# `Impact.Bedrock`

Span helpers for AWS Bedrock Converse-style API calls.

Use these when you need to manually instrument Bedrock calls that don't go
through `Req` (and therefore can't be auto-instrumented by
`Impact.Instrumentation.Bedrock`). Typical case: apps using the
`:aws_elixir` (`AWS.BedrockRuntime`) or `:ex_aws_bedrock` clients.

## High-level usage — `with_call/4`

Wraps the entire LLM call in a `bedrock_call` span. Sets request-side
attributes upfront, response-side attributes after the closure returns,
and latency on every code path:

    Impact.Bedrock.with_call(model, body, [conversation_id: agent_id], fn ->
      case AWS.BedrockRuntime.converse(client, model.arn, body, opts) do
        {:ok, response, _metadata} -> {:ok, response}
        {:error, reason} -> {:error, reason}
      end
    end)

Returns whatever the closure returned, unchanged.

## Result classification

The closure can return any of these shapes; `with_call/4` interprets them as
follows:

| Return value | Attribute set | Latency stamped |
|---|---|---|
| `{:ok, response}` | `attrs_for_response/2` | yes |
| `{:ok, response, _meta}` (3-tuple aws-elixir form) | `attrs_for_response/2` | yes |
| `{:error, reason}` | `attrs_for_error/2` | yes |
| anything else (e.g. `{:snooze, n}`) | `aws.bedrock.latency_ms` only | yes |

## Manual control — `attrs_for_request/3` / `attrs_for_response/2` / `attrs_for_error/2`

Build attribute maps directly when you need to drive the trace block
yourself (multi-attempt retries, snooze handling with per-attempt timing,
etc):

    request_attrs = Impact.Bedrock.attrs_for_request(model, body, conversation_id: agent_id)

    Impact.trace [type: :llm, name: "bedrock_call", attributes: request_attrs] do
      start_ms = System.monotonic_time(:millisecond)
      # ... your call ...
      Impact.set_attributes(Impact.Bedrock.attrs_for_response(response, latency))
    end

## Attribute keys

Request-side (`attrs_for_request/3`):

  * `gen_ai.system = "aws.bedrock"`
  * `gen_ai.provider.name = "aws"`
  * `gen_ai.operation.name = "chat"`
  * `gen_ai.request.model` — model name (from `model.name` or ARN)
  * `gen_ai.input.messages` — JSON-encoded request `messages`
  * `gen_ai.system_instructions` — extracted system text
  * `gen_ai.conversation.id` — opt `:conversation_id`
  * `gen_ai.model.id` — opt `:model_id`
  * `aws.bedrock.model.arn` — from `model.arn`
  * `aws.bedrock.inference_config` — JSON-encoded `inferenceConfig`
  * `aws.bedrock.tool_config` — JSON-encoded `toolConfig`

Response-side (`attrs_for_response/2`):

  * `gen_ai.response.id`
  * `gen_ai.response.finish_reasons` — list with `stopReason`
  * `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`
  * `gen_ai.output.messages` — JSON-encoded assistant message
  * `gen_ai.output.text` — extracted plain text
  * `gen_ai.response.tool_calls.count` — number of `toolUse` blocks
  * `aws.bedrock.latency_ms`

Error-side (`attrs_for_error/2`):

  * `error.message` — `inspect(reason)`
  * `aws.bedrock.latency_ms`

For tool / function call spans, see `Impact.Tool`.

# `attrs_for_error`

```elixir
@spec attrs_for_error(any(), integer()) :: map()
```

Build error-side attributes for a failed `bedrock_call`.

# `attrs_for_request`

```elixir
@spec attrs_for_request(map(), map(), keyword()) :: map()
```

Build request-side attributes for a `bedrock_call` span.

## Options

  * `:conversation_id` — value for `gen_ai.conversation.id`
  * `:model_id` — value for `gen_ai.model.id` (internal model identifier
    distinct from the human-readable model name)

# `attrs_for_response`

```elixir
@spec attrs_for_response(map(), integer()) :: map()
```

Build response-side attributes for a successful `bedrock_call`.

# `with_call`

```elixir
@spec with_call(map(), map(), keyword(), (-&gt; any())) :: any()
```

Wrap a Bedrock-style API call in a `bedrock_call` LLM span. Handles request
attrs, response/error attrs, and latency on every code path.

## Options (forwarded to `attrs_for_request/3`)

  * `:conversation_id` — value for `gen_ai.conversation.id`
  * `:model_id` — value for `gen_ai.model.id`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
