Skip to content

[opentelemetry-instrumentation-genai-bedrock] Add instrumentation for InvokeModel and InvokeModelWithResponseStream - #514

Open
DylanRussell wants to merge 21 commits into
mainfrom
DylanRussell/add_bedrock_instrumentation_3
Open

[opentelemetry-instrumentation-genai-bedrock] Add instrumentation for InvokeModel and InvokeModelWithResponseStream#514
DylanRussell wants to merge 21 commits into
mainfrom
DylanRussell/add_bedrock_instrumentation_3

Conversation

@DylanRussell

@DylanRussell DylanRussell commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Description

Adds instrumentation for InvokeModel and InvokeModelWithResponseStream

Add support for bedrock specific sem convs: Add aws.bedrock.guardrail.id, add gen_ai.prompt.variable.<key>, add gen_ai.output.type.

  • New feature (non-breaking change which adds functionality)

How has this been tested?

Unit tests

Checklist

  • Followed the style guidelines of this project
  • Changelog updated if the change requires an entry
  • Unit tests added
  • Documentation updated

Copilot AI lite review requested due to automatic review settings August 31, 2026 18:41
@DylanRussell
DylanRussell requested a review from a team as a code owner August 31, 2026 18:41
@DylanRussell
DylanRussell changed the base branch from main to DylanRussell/add_bedrock_instrumentation_2 August 31, 2026 18:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Amazon Bedrock Runtime (boto3/botocore) operation-level GenAI instrumentation to the existing opentelemetry-instrumentation-genai-bedrock package, including span/attribute extraction for InvokeModel and InvokeModelWithResponseStream plus corresponding tests and conformance wiring.

Changes:

  • Patch botocore.client.BaseClient._make_api_call to instrument Bedrock Converse* and InvokeModel* operations, including stream wrappers for streaming responses.
  • Add Bedrock-specific request/response/stream-chunk extractors mapping provider payloads into opentelemetry-util-genai invocation types.
  • Add unit + VCR-backed tests and conformance scenarios; wire a Bedrock conformance tox env.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tox.ini Adds Bedrock conformance env and adjusts Bedrock test commands; introduces global passenv patterns.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/test_invoke_model.py New unit tests for invoke_model request/response extraction and span attributes.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/test_invoke_model_stream.py New unit tests for streaming InvokeModelWithResponseStream wrapper behavior and error paths.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/test_converse.py New VCR-backed tests for converse instrumentation, content capture, tool calls, and errors.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/test_converse_stream.py New VCR-backed tests for converse_stream instrumentation, early close, and error paths.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/test_conformance.py Adds conformance test runner that executes Bedrock scenarios with weaver live-check.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/test_completion_hook.py Adds tests validating completion-hook wiring behavior for Bedrock.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/requirements.oldest.txt Updates oldest test requirements (editable util-genai note).
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/requirements.latest.txt Keeps latest test requirements aligned with editable workspace installs.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/conftest.py Adds boto3 Bedrock client fixture, VCR config/scrubbing, env setup, and content-capture fixtures.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/conformance/tool_calling.py Adds tool-calling conformance scenario for Bedrock chat.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/conformance/inference.py Adds non-streaming inference conformance scenario for Bedrock chat.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/conformance/inference_streaming.py Adds streaming inference conformance scenario and validates gen_ai.request.stream=true.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/conformance/init.py Marks conformance scenario package.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/cassettes/test_converse_with_invalid_model.yaml VCR cassette for Converse error case.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/cassettes/test_converse_with_content.yaml VCR cassette for Converse success with content capture.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/cassettes/test_converse_tool_call_with_content.yaml VCR cassette for Converse tool call flow (content).
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/cassettes/test_converse_tool_call_no_content.yaml VCR cassette for Converse tool call flow (no content).
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/cassettes/test_converse_stream_with_invalid_model.yaml VCR cassette for ConverseStream error case.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/cassettes/test_converse_stream_with_content.yaml VCR cassette for ConverseStream success with content capture.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/cassettes/test_converse_stream_with_content_tool_call.yaml VCR cassette for ConverseStream tool call flow (content).
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/cassettes/test_converse_stream_no_content.yaml VCR cassette for ConverseStream success (no content).
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/cassettes/test_converse_stream_handles_event_stream_error.yaml VCR cassette used for stream error-path test coverage.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/cassettes/test_converse_stream_close_before_consumption.yaml VCR cassette used to validate early stream close handling.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/cassettes/test_converse_stream_caller_side_error.yaml VCR cassette used for caller-side exception path coverage.
instrumentation/opentelemetry-instrumentation-genai-bedrock/tests/cassettes/test_converse_no_content.yaml VCR cassette for Converse success (no content).
instrumentation/opentelemetry-instrumentation-genai-bedrock/src/opentelemetry/instrumentation/genai/bedrock/stream.py Adds SyncStreamWrapper subclasses for ConverseStream and InvokeModelWithResponseStream.
instrumentation/opentelemetry-instrumentation-genai-bedrock/src/opentelemetry/instrumentation/genai/bedrock/patch.py Adds BaseClient._make_api_call wrapper and handlers for Converse/InvokeModel paths.
instrumentation/opentelemetry-instrumentation-genai-bedrock/src/opentelemetry/instrumentation/genai/bedrock/extractors.py Adds request/response extraction + finish-reason mapping for Bedrock payload formats.
instrumentation/opentelemetry-instrumentation-genai-bedrock/src/opentelemetry/instrumentation/genai/bedrock/init.py Wires patch/unpatch into BedrockInstrumentor.
instrumentation/opentelemetry-instrumentation-genai-bedrock/README.rst Documents supported Bedrock operations and basic usage.
instrumentation/opentelemetry-instrumentation-genai-bedrock/pyproject.toml Updates util-genai dependency floor for Bedrock instrumentation.
instrumentation/opentelemetry-instrumentation-genai-bedrock/examples/zero-code/main.py Updates zero-code example to use converse.
instrumentation/opentelemetry-instrumentation-genai-bedrock/examples/manual/main.py Updates manual example to use converse.
instrumentation/opentelemetry-instrumentation-genai-bedrock/examples/manual/custom_hook.py Adds custom completion-hook example for Bedrock.
instrumentation/opentelemetry-instrumentation-genai-bedrock/.changelog/488.added Adds a changelog fragment describing the feature addition.
Suppressed comments (2)

instrumentation/opentelemetry-instrumentation-genai-bedrock/src/opentelemetry/instrumentation/genai/bedrock/extractors.py:574

  • int(...) conversion for output_tokens from the response payload is unguarded and can raise, which would cause the instrumentation wrapper to fail the SDK call.
        if invocation.output_tokens is None:
            out_tok = usage.get("output_tokens") or usage.get("outputTokens")
            if out_tok is not None:
                invocation.output_tokens = int(out_tok)

instrumentation/opentelemetry-instrumentation-genai-bedrock/src/opentelemetry/instrumentation/genai/bedrock/extractors.py:584

  • cacheReadInputTokens/cacheWriteInputTokens payload parsing uses unguarded int(...) conversions; if these values are absent or non-integer the instrumentation will raise and fail the request.
        cache_read = usage.get("cache_read_input_tokens") or usage.get(
            "cacheReadInputTokens"
        )
        if cache_read is not None:
            invocation.cache_read_input_tokens = int(cache_read)
        cache_write = usage.get("cache_creation_input_tokens") or usage.get(
            "cacheWriteInputTokens"
        )
        if cache_write is not None:
            invocation.cache_creation_input_tokens = int(cache_write)

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Aug 31, 2026

Copy link
Copy Markdown

Pull request dashboard status

Waiting on the author · refreshed 2026-09-02 21:15 UTC

Respond to 2 review items (e.g. link a commit, explain why not, ask a follow-up):

  • Inline threads: 1, 2
Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Should this be with reviewers? Comment /dashboard route:reviewers to route it to them.
  • Anything wrong — including the routing? Report it with what you expected; it helps us improve the dashboard.

@DylanRussell
DylanRussell force-pushed the DylanRussell/add_bedrock_instrumentation_3 branch 2 times, most recently from d083b66 to ef86be9 Compare August 31, 2026 20:27
@DylanRussell
DylanRussell force-pushed the DylanRussell/add_bedrock_instrumentation_3 branch 2 times, most recently from f01d3c7 to fc5990a Compare September 1, 2026 13:52
@DylanRussell
DylanRussell force-pushed the DylanRussell/add_bedrock_instrumentation_3 branch 2 times, most recently from 5322535 to 756332f Compare September 1, 2026 14:11
Base automatically changed from DylanRussell/add_bedrock_instrumentation_2 to main September 1, 2026 21:35
@lmolkova
lmolkova force-pushed the DylanRussell/add_bedrock_instrumentation_3 branch from a5bddf7 to 289a944 Compare September 1, 2026 21:35
…ool calling

- Restore .changelog/488.added fragment from main
- Gate stream content accumulation behind capture_content in BedrockInvokeModelStreamWrapper
- Support Anthropic tool_use and tool_result content blocks in extract_content_block
- Support streamed tool use in BedrockInvokeModelStreamWrapper
- Add unit and end-to-end integration tests using Stubber for InvokeModel streaming
…mptVariables

- Extract guardrail identifier in Converse and InvokeModel as aws.bedrock.guardrail.id
- Extract outputConfig textFormat in Converse as gen_ai.output.type
- Extract promptVariables in Converse as gen_ai.prompt.variable.<key> when content capture is enabled
- Add unit and integration tests

FinishReason = Literal[
"content_filter", "error", "length", "stop", "tool_calls", "compaction"
"content_filter", "error", "length", "stop", "tool_call", "compaction"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change breaks OpenAI instrumentation when choices have tool calls (OutputMessage expects FinishReason, but OpenAI returns "tool_calls"). Please update OpenAI to map "tool_calls" to "tool_call".

)
)
else:
if self._self_accumulated_reasoning:

@lmolkova lmolkova Sep 2, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self._self_accumulated_reasoning is never populated in _process_chunk, did you want to populate reasoning part with it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants