Skip to content

fix(anthropic): prevent response object corruption in beta API instrumentation#3278

Open
galkleinman wants to merge 3 commits intomainfrom
gk/fix-anthropic-async
Open

fix(anthropic): prevent response object corruption in beta API instrumentation#3278
galkleinman wants to merge 3 commits intomainfrom
gk/fix-anthropic-async

Conversation

@galkleinman
Copy link
Copy Markdown
Contributor

@galkleinman galkleinman commented Aug 14, 2025

Important

Fixes response handling and adds tests for Anthropic beta API instrumentation to prevent corruption and ensure concurrency.

  • Instrumentation:
    • Added support for Beta Messages (sync and async) in __init__.py.
    • Improved response handling in span_utils.py to prevent corruption and ensure coroutine-aware processing.
    • Enhanced extraction of response attributes for metrics in utils.py.
  • Bug Fixes:
    • Fixed async/sync response handling to avoid hangs in span_utils.py.
    • Improved parsing of multi-block content for accurate spans and metadata in span_utils.py.
  • Tests:
    • Re-enabled Bedrock raw-response tests in test_bedrock_with_raw_response.py.
    • Added tests for beta API concurrency and response integrity in test_beta_api_interference.py.

This description was created by Ellipsis for 5931306. You can customize this summary. It will automatically update as commits are pushed.


Summary by CodeRabbit

  • New Features

    • Added instrumentation coverage for Beta Messages (sync and async) across Anthropic and Bedrock beta APIs.
  • Bug Fixes

    • Improved coroutine-aware response handling to avoid hangs and skipped processing.
    • More robust extraction of response attributes for metrics, including token usage.
    • Enhanced parsing of multi-block content (text, tool calls, thinking) for accurate spans and metadata.
  • Tests

    • Re-enabled Bedrock raw-response tests and added tests for beta API concurrency, response integrity, and method-preservation.

…mentation

This fixes an issue where the Anthropic beta API instrumentation was causing
LangGraph agents using Claude on Bedrock to get stuck. The root cause was that
the instrumentation was directly accessing response.__dict__ which could corrupt
the response object's internal state for certain object types like Pydantic
models or proxy objects used by LangGraph.

The fix ensures that response data extraction creates safe copies of object
attributes rather than modifying or directly accessing the original response
objects. This preserves the response object's integrity while still allowing
the instrumentation to collect necessary metrics and token usage data.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 14, 2025

Walkthrough

Adds beta API instrumentation wrappers for Anthropic and Bedrock (sync + async), refactors response handling to be coroutine-aware and object/dict-agnostic, adds a safe metrics extractor, un-skips Bedrock tests, and introduces tests validating beta concurrency and response integrity.

Changes

Cohort / File(s) Summary
Beta instrumentation wrappers
packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/__init__.py
Adds WRAPPED_METHODS and WRAPPED_AMETHODS entries for anthropic.resources.beta.messages.messages.Messages / AsyncMessages and anthropic.lib.bedrock._beta_messages.Messages / AsyncMessages for create and stream (span_name anthropic.chat).
Span completion & response handling
packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/span_utils.py
Removes reliance on an external extraction helper; adds coroutine detection/awaiting in async flows and warnings for coroutine responses in sync flows; normalizes access via getattr/dict fallbacks; iterates content items and handles text, thinking, and tool_use blocks; updates async/sync completion and attribute setters; adds inspect and logging usage.
Response utilities & metrics extraction
packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/utils.py
Adds _safe_extract_attributes_for_metrics(response) and updates _aextract_response_data / _extract_response_data to coerce/normalize responses into dict-like structures (via parse()/model_dump()/dict or safe __dict__ copy) with improved logging.
Un-skipped Bedrock tests
packages/opentelemetry-instrumentation-anthropic/tests/test_bedrock_with_raw_response.py
Removes pytest.mark.skip decorators from three async Bedrock tests, enabling their execution without changing test logic.
New beta interference tests
packages/opentelemetry-instrumentation-anthropic/tests/test_beta_api_interference.py
Adds fixture for AsyncAnthropicBedrock and async tests: concurrency / timeout check for beta calls, response corruption check for tool_use content items, and a placeholder for method-signature-preservation test.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant Client as AsyncAnthropicBedrock
  participant Instrumentation as OTel Wrapper
  participant API as Beta Messages / Bedrock
  participant SpanUtils as span_utils
  participant Exporter as OTel Exporter

  User->>Client: beta.Messages.create(...) / stream(...)
  Client->>Instrumentation: invoked (wrapped)
  Instrumentation->>API: forward call
  API-->>Instrumentation: response (object or coroutine)
  Instrumentation->>SpanUtils: set_response_attributes / set_span_completions (await if coroutine)
  SpanUtils-->>Instrumentation: attributes/completions set
  Instrumentation-->>Client: return original or safely-wrapped response
  Instrumentation->>Exporter: export span
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Suggested reviewers

  • nirga
  • doronkopit5

Poem

I twitch my ears at beta’s dawn,
Wrappers hop in, spans are drawn.
Coroutines wait, tool_calls sing,
Text and thinking—everything!
Tests awake; metrics nibble near. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0d9e58c and 5931306.

📒 Files selected for processing (1)
  • packages/opentelemetry-instrumentation-anthropic/tests/test_bedrock_with_raw_response.py (0 hunks)
💤 Files with no reviewable changes (1)
  • packages/opentelemetry-instrumentation-anthropic/tests/test_bedrock_with_raw_response.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build Packages (3.11)
  • GitHub Check: Lint
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch gk/fix-anthropic-async

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@ellipsis-dev ellipsis-dev Bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed everything up to 974db37 in 2 minutes and 25 seconds. Click for details.
  • Reviewed 818 lines of code in 5 files
  • Skipped 0 files when reviewing.
  • Skipped posting 6 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/__init__.py:98
  • Draft comment:
    Uncommenting the Beta API methods here (for both sync and async) activates instrumentation for the Bedrock SDK. Ensure this change is intentional for production use or gated by a feature flag if still experimental.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 0% vs. threshold = 50% The comment violates several rules: 1. It asks to "ensure this change is intentional" which is a form of asking for confirmation 2. It suggests using a feature flag which is speculative ("if still experimental") 3. The uncommented code appears to be a deliberate change, and we should assume the author knows what they're doing 4. The comment doesn't point out any actual problems or bugs The comment does correctly identify that this enables new functionality for Bedrock SDK. Maybe there are legitimate production readiness concerns? While the concern about production readiness might be valid, the comment doesn't provide evidence of actual issues. We should trust that the author has considered the implications of enabling these methods. The comment should be deleted as it primarily asks for confirmation and makes speculative suggestions without identifying concrete issues.
2. packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/span_utils.py:190
  • Draft comment:
    Switching from dictionary lookups (e.g. response.get) to using getattr helps preserve the original response object. Consider adding a check to support dict responses (i.e. using response.get) if that case might occur in practice.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.
3. packages/opentelemetry-instrumentation-anthropic/tests/test_beta_api_interference.py:147
  • Draft comment:
    The test 'test_beta_api_method_signature_preservation' currently has a placeholder 'pass'. It would be beneficial to either implement this test to verify that beta API method signatures are preserved or remove the placeholder to avoid false positives in coverage.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% This is a new file being added, so the placeholder test is part of the changes. Having an unimplemented test with just 'pass' could be problematic as it suggests missing test coverage for an important feature (signature preservation). However, the test file already has two substantial test implementations for other aspects. The author may have intentionally left this as a TODO for future work. I might be too focused on the technical merit of having complete test coverage, when I should be considering whether this comment actually helps improve the code in a meaningful way. The author likely knows this test is unimplemented. While test coverage is important, commenting on an obviously unimplemented test doesn't provide actionable value. The author is clearly aware it's a placeholder since they added the explanatory comments. The comment should be deleted as it merely points out something obvious to the author and doesn't provide actionable guidance for improving the code.
4. packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/span_utils.py:206
  • Draft comment:
    Typo: In the comment, "Antrhopic" should be corrected to "Anthropic".
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 0% vs. threshold = 50% The rules say not to make purely informative comments and to only comment if there is clearly a code change required. While this is a real typo, fixing a typo in a comment is not a functional change and doesn't affect the code's behavior. The comment is accurate but not important enough to warrant inclusion based on the rules. The typo does appear in multiple places in the code, so it's not just an isolated issue. Could fixing documentation/comments be considered important for maintainability? While documentation quality is important, the rules explicitly state not to make purely informative comments. This typo doesn't impact code functionality or readability significantly. Delete this comment as it only addresses a minor typo in documentation and doesn't require any functional code changes.
5. packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/span_utils.py:320
  • Draft comment:
    Typographical error: the comment says "Antrhopic"; it should be "Anthropic".
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 0% vs. threshold = 50% The rules say not to make purely informative comments and to only comment if there is clearly a code change required. While this is a real typo, fixing a typo in a comment is not a functional change and doesn't affect the code's behavior. The comment is more informative than actionable. The typo does appear twice in the codebase, so it's not just an isolated issue. And having correct spelling in comments could be considered a code quality issue. However, the rules explicitly state not to make purely informative comments and to only comment when there is clearly a code change required. A typo in a comment doesn't require a code change - it's purely cosmetic. Based on the rules, we should delete this comment since it is purely informative and doesn't require an actual code change.
6. packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/utils.py:149
  • Draft comment:
    Typographical note: The async function is named _aextract_response_data. Given the docstring refers to an async version of _extract_response_data, it might be clearer if the function name were _async_extract_response_data (or similar) to avoid potential confusion.
  • Reason this comment was not posted:
    Comment was on unchanged code.

Workflow ID: wflow_0iWEU8F0oNglOpdA

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Re-enables instrumentation for all beta API methods in both regular
Anthropic SDK and Bedrock SDK, including streaming methods. Now that
the response corruption issue has been fixed, all beta API methods
can be safely instrumented without interfering with LangGraph agents.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/opentelemetry-instrumentation-anthropic/tests/test_beta_api_interference.py (1)

147-154: Complete the method signature preservation test.

The placeholder test should be implemented to verify that wrapped methods preserve their original signatures.

Would you like me to help implement this test to verify that the beta API method signatures are preserved after instrumentation? This would ensure compatibility with tools like LangGraph that may depend on specific method signatures.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 50be41d and 974db37.

📒 Files selected for processing (5)
  • packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/__init__.py (2 hunks)
  • packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/span_utils.py (5 hunks)
  • packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/utils.py (6 hunks)
  • packages/opentelemetry-instrumentation-anthropic/tests/test_bedrock_with_raw_response.py (3 hunks)
  • packages/opentelemetry-instrumentation-anthropic/tests/test_beta_api_interference.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.py: Python code must conform to Flake8 linting rules
Do not hardcode API keys in source code; read them from environment variables or a secure vault

Files:

  • packages/opentelemetry-instrumentation-anthropic/tests/test_bedrock_with_raw_response.py
  • packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/__init__.py
  • packages/opentelemetry-instrumentation-anthropic/tests/test_beta_api_interference.py
  • packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/utils.py
  • packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/span_utils.py
🧬 Code Graph Analysis (1)
packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/span_utils.py (2)
packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py (1)
  • SpanAttributes (64-257)
packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/utils.py (2)
  • set_span_attribute (20-24)
  • dont_throw (33-61)
🔇 Additional comments (15)
packages/opentelemetry-instrumentation-anthropic/tests/test_bedrock_with_raw_response.py (3)

28-28: LGTM! Tests re-enabled for better coverage.

Good to see these Bedrock tests re-enabled now that the instrumentation properly handles raw responses and beta API calls.


83-83: Consistent test re-enablement.

This regular Bedrock test is correctly re-enabled alongside the raw response tests.


132-132: Beta API raw response test enabled.

The beta API test is appropriately re-enabled, providing coverage for the new beta Messages instrumentation.

packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/__init__.py (2)

97-103: LGTM! Beta API instrumentation for Bedrock SDK enabled.

The addition of synchronous Bedrock beta Messages instrumentation correctly extends the coverage to this new API variant.


138-144: Consistent async beta API instrumentation added.

The async counterpart is properly configured to match the synchronous wrapper.

packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/utils.py (3)

64-147: Well-designed safe attribute extraction for metrics.

The _safe_extract_attributes_for_metrics function is thoughtfully implemented with proper defensive programming:

  • Handles various response types (None, dict, Pydantic models)
  • Safely extracts only the necessary metrics attributes
  • Avoids side effects from direct __dict__ access on proxy objects
  • Includes proper error handling and fallbacks

This approach prevents the response object corruption issue mentioned in the PR title.


168-191: Improved async response data extraction.

The enhancements to _aextract_response_data properly:

  • Ensure dict-like outputs by converting parsed responses
  • Create safe copies to avoid modifying original objects
  • Include proper error handling and logging

212-234: Consistent sync response data extraction.

The sync version mirrors the async improvements appropriately, maintaining consistency in the response handling approach.

packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/span_utils.py (5)

174-184: Excellent coroutine-aware response handling.

The addition of coroutine detection and proper awaiting prevents potential issues with async response objects. The error handling with logging ensures debugging visibility.


185-281: Robust attribute-based access preserves response structure.

The refactored approach using getattr instead of extracting the entire response object is a significant improvement:

  • Preserves the original response object structure
  • Prevents side effects from dict extraction on proxy objects
  • Handles both object-like and dict-like responses gracefully
  • Properly processes thinking blocks and tool_use blocks

This directly addresses the response object corruption issue mentioned in the PR title.


289-298: Appropriate sync context coroutine handling.

The sync version correctly detects and logs when a coroutine is received, preventing silent failures.


402-412: Consistent coroutine handling in async response attributes.

The async response attribute setter properly handles coroutines with appropriate error handling.


447-456: Appropriate sync context protection.

The sync version correctly prevents processing of coroutines with proper warning logs.

packages/opentelemetry-instrumentation-anthropic/tests/test_beta_api_interference.py (2)

25-86: Comprehensive test for concurrent beta API calls.

This test effectively validates that the instrumentation doesn't cause hangs or interference with multiple concurrent beta API calls, which is crucial for LangGraph integration.


88-145: Good test for response object integrity.

The test properly verifies that the instrumentation preserves response object structure and identity, which is critical for preventing the corruption issue.

Copy link
Copy Markdown
Contributor

@ellipsis-dev ellipsis-dev Bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed 0d9e58c in 1 minute and 12 seconds. Click for details.
  • Reviewed 108 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 2 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/__init__.py:81
  • Draft comment:
    Uncommented beta API methods for regular Anthropic SDK and Bedrock. The dictionary format and field names are consistent with other entries, ensuring these endpoints are properly instrumented.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative, describing what was done without providing any actionable feedback or suggestions. It doesn't ask for confirmation or suggest improvements.
2. packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/__init__.py:122
  • Draft comment:
    Uncommented beta API async methods for both regular SDK and Bedrock. This change mirrors the synchronous configuration and should help prevent response object issues in beta implementations.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative, explaining what the change does and its intended benefit. It doesn't provide a suggestion, ask for confirmation, or point out a potential issue.

Workflow ID: wflow_07aOA4sZlk1Ba43R

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 974db37 and 0d9e58c.

📒 Files selected for processing (1)
  • packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/__init__.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.py: Python code must conform to Flake8 linting rules
Do not hardcode API keys in source code; read them from environment variables or a secure vault

Files:

  • packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/__init__.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build Packages (3.11)
  • GitHub Check: Lint

Comment on lines +84 to 110
# Beta API methods (regular Anthropic SDK)
{
"package": "anthropic.resources.beta.messages.messages",
"object": "Messages",
"method": "create",
"span_name": "anthropic.chat",
},
{
"package": "anthropic.resources.beta.messages.messages",
"object": "Messages",
"method": "stream",
"span_name": "anthropic.chat",
},
# Beta API methods (Bedrock SDK)
{
"package": "anthropic.lib.bedrock._beta_messages",
"object": "Messages",
"method": "create",
"span_name": "anthropic.chat",
},
{
"package": "anthropic.lib.bedrock._beta_messages",
"object": "Messages",
"method": "stream",
"span_name": "anthropic.chat",
},
]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add Beta AsyncMessages.stream to sync wrappers (async context manager semantics).

For non-beta, AsyncMessages.stream is wrapped via the sync wrapper because it returns an async context manager (used with "async with") and is not awaitable. The Beta API exposes the same semantics, so Beta AsyncMessages.stream should also be wrapped with the sync wrapper (WRAPPED_METHODS), mirroring the non-beta approach. This avoids awaiting a non-awaitable object in the async wrapper.

Apply this diff to include Beta AsyncMessages.stream entries in WRAPPED_METHODS:

@@
     # Beta API methods (regular Anthropic SDK)
     {
         "package": "anthropic.resources.beta.messages.messages",
         "object": "Messages",
         "method": "create",
         "span_name": "anthropic.chat",
     },
     {
         "package": "anthropic.resources.beta.messages.messages",
         "object": "Messages",
         "method": "stream",
         "span_name": "anthropic.chat",
     },
+    # Beta API async stream is an async context manager; wrap with sync wrapper (see non-beta)
+    {
+        "package": "anthropic.resources.beta.messages.messages",
+        "object": "AsyncMessages",
+        "method": "stream",
+        "span_name": "anthropic.chat",
+    },
     # Beta API methods (Bedrock SDK)
     {
         "package": "anthropic.lib.bedrock._beta_messages",
         "object": "Messages",
         "method": "create",
         "span_name": "anthropic.chat",
     },
     {
         "package": "anthropic.lib.bedrock._beta_messages",
         "object": "Messages",
         "method": "stream",
         "span_name": "anthropic.chat",
     },
+    {
+        "package": "anthropic.lib.bedrock._beta_messages",
+        "object": "AsyncMessages",
+        "method": "stream",
+        "span_name": "anthropic.chat",
+    },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Beta API methods (regular Anthropic SDK)
{
"package": "anthropic.resources.beta.messages.messages",
"object": "Messages",
"method": "create",
"span_name": "anthropic.chat",
},
{
"package": "anthropic.resources.beta.messages.messages",
"object": "Messages",
"method": "stream",
"span_name": "anthropic.chat",
},
# Beta API methods (Bedrock SDK)
{
"package": "anthropic.lib.bedrock._beta_messages",
"object": "Messages",
"method": "create",
"span_name": "anthropic.chat",
},
{
"package": "anthropic.lib.bedrock._beta_messages",
"object": "Messages",
"method": "stream",
"span_name": "anthropic.chat",
},
]
# Beta API methods (regular Anthropic SDK)
{
"package": "anthropic.resources.beta.messages.messages",
"object": "Messages",
"method": "create",
"span_name": "anthropic.chat",
},
{
"package": "anthropic.resources.beta.messages.messages",
"object": "Messages",
"method": "stream",
"span_name": "anthropic.chat",
},
# Beta API async stream is an async context manager; wrap with sync wrapper (see non-beta)
{
"package": "anthropic.resources.beta.messages.messages",
"object": "AsyncMessages",
"method": "stream",
"span_name": "anthropic.chat",
},
# Beta API methods (Bedrock SDK)
{
"package": "anthropic.lib.bedrock._beta_messages",
"object": "Messages",
"method": "create",
"span_name": "anthropic.chat",
},
{
"package": "anthropic.lib.bedrock._beta_messages",
"object": "Messages",
"method": "stream",
"span_name": "anthropic.chat",
},
{
"package": "anthropic.lib.bedrock._beta_messages",
"object": "AsyncMessages",
"method": "stream",
"span_name": "anthropic.chat",
},
]
🤖 Prompt for AI Agents
In
packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/__init__.py
around lines 84-110, the WRAPPED_METHODS list is missing Beta
AsyncMessages.stream entries so the Beta async context-manager stream is
currently not wrapped by the sync wrapper and may be awaited incorrectly; add
entries mirroring the non-beta async stream entries for the Beta API (both the
beta messages package and the bedrock _beta_messages package) pointing to
AsyncMessages.stream so the sync wrapper treats the returned async context
manager correctly.

Comment on lines +125 to 151
# Beta API async methods (regular Anthropic SDK)
{
"package": "anthropic.resources.beta.messages.messages",
"object": "AsyncMessages",
"method": "create",
"span_name": "anthropic.chat",
},
{
"package": "anthropic.resources.beta.messages.messages",
"object": "AsyncMessages",
"method": "stream",
"span_name": "anthropic.chat",
},
# Beta API async methods (Bedrock SDK)
{
"package": "anthropic.lib.bedrock._beta_messages",
"object": "AsyncMessages",
"method": "create",
"span_name": "anthropic.chat",
},
{
"package": "anthropic.lib.bedrock._beta_messages",
"object": "AsyncMessages",
"method": "stream",
"span_name": "anthropic.chat",
},
]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Bug: Wrapping Beta AsyncMessages.stream in async wrapper will await a non-awaitable context manager.

AsyncMessages.stream returns an async context manager (used with "async with"), not an awaitable. Wrapping it in WRAPPED_AMETHODS leads to awaiting a non-awaitable object in _awrap, which will raise a TypeError at runtime. Mirror the non-beta handling: remove these from WRAPPED_AMETHODS and wrap them via the sync wrapper (see prior comment).

Apply this diff to remove Beta AsyncMessages.stream entries from WRAPPED_AMETHODS:

@@
     # Beta API async methods (regular Anthropic SDK)
     {
         "package": "anthropic.resources.beta.messages.messages",
         "object": "AsyncMessages",
         "method": "create",
         "span_name": "anthropic.chat",
     },
-    {
-        "package": "anthropic.resources.beta.messages.messages",
-        "object": "AsyncMessages",
-        "method": "stream",
-        "span_name": "anthropic.chat",
-    },
@@
     # Beta API async methods (Bedrock SDK)
     {
         "package": "anthropic.lib.bedrock._beta_messages",
         "object": "AsyncMessages",
         "method": "create",
         "span_name": "anthropic.chat",
     },
-    {
-        "package": "anthropic.lib.bedrock._beta_messages",
-        "object": "AsyncMessages",
-        "method": "stream",
-        "span_name": "anthropic.chat",
-    },

Run this quick check to confirm stream usage patterns in tests (expect "async with ...messages.stream(" occurrences):


🏁 Script executed:

#!/bin/bash
# Verify AsyncMessages.stream is used as an async context manager (not awaited)
rg -n -A2 -i $'async with .*\\.messages\\.stream\\(' tests || true
rg -n -A2 -i $'await .*\\.messages\\.stream\\(' tests || true

Length of output: 214


To verify stream usage across the repo, let's search everywhere (not just a missing tests/ folder):

This will confirm whether stream is ever awaited or only used in async with. If it’s never awaited, we should remove it from WRAPPED_AMETHODS as proposed.


🏁 Script executed:

#!/bin/bash
# Verify AsyncMessages.stream is used as an async context manager (not awaited)
rg -n -A2 -i 'async with .*messages\.stream\(' .
rg -n -A2 -i 'await .*messages\.stream\(' .

Length of output: 1124


Remove Beta AsyncMessages.stream from async wrapper
Tests confirm that AsyncMessages.stream is only ever used as an async context manager (async with … .stream(…)) and is never awaited. Wrapping it in the async‐await wrapper will attempt to await a non‐awaitable, causing a TypeError at runtime.

Please update WRAPPED_AMETHODS in
packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/__init__.py
to remove the two "method": "stream" entries under both the regular and Bedrock Beta sections, for example:

@@ -128,11 +128,6 @@ WRAPPED_AMETHODS = [
     # Beta API async methods (regular Anthropic SDK)
     {
         "package": "anthropic.resources.beta.messages.messages",
         "object": "AsyncMessages",
         "method": "create",
         "span_name": "anthropic.chat",
     },
-    {
-        "package": "anthropic.resources.beta.messages.messages",
-        "object": "AsyncMessages",
-        "method": "stream",
-        "span_name": "anthropic.chat",
-    },
@@ -134,11 +129,6 @@ WRAPPED_AMETHODS = [
     # Beta API async methods (Bedrock SDK)
     {
         "package": "anthropic.lib.bedrock._beta_messages",
         "object": "AsyncMessages",
         "method": "create",
         "span_name": "anthropic.chat",
     },
-    {
-        "package": "anthropic.lib.bedrock._beta_messages",
-        "object": "AsyncMessages",
-        "method": "stream",
-        "span_name": "anthropic.chat",
-    },
 ]

After removal, if you need to instrument stream, mirror the non-Beta handling by wrapping it via the sync wrapper.

Tagging as since this change is necessary to prevent runtime errors.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Beta API async methods (regular Anthropic SDK)
{
"package": "anthropic.resources.beta.messages.messages",
"object": "AsyncMessages",
"method": "create",
"span_name": "anthropic.chat",
},
{
"package": "anthropic.resources.beta.messages.messages",
"object": "AsyncMessages",
"method": "stream",
"span_name": "anthropic.chat",
},
# Beta API async methods (Bedrock SDK)
{
"package": "anthropic.lib.bedrock._beta_messages",
"object": "AsyncMessages",
"method": "create",
"span_name": "anthropic.chat",
},
{
"package": "anthropic.lib.bedrock._beta_messages",
"object": "AsyncMessages",
"method": "stream",
"span_name": "anthropic.chat",
},
]
# Beta API async methods (regular Anthropic SDK)
{
"package": "anthropic.resources.beta.messages.messages",
"object": "AsyncMessages",
"method": "create",
"span_name": "anthropic.chat",
},
# Beta API async methods (Bedrock SDK)
{
"package": "anthropic.lib.bedrock._beta_messages",
"object": "AsyncMessages",
"method": "create",
"span_name": "anthropic.chat",
},
]
🤖 Prompt for AI Agents
In
packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/__init__.py
around lines 125 to 151, the Beta async mapping includes two entries with
"method": "stream" which are only used as async context managers and not
awaitable; remove the two {"object": "AsyncMessages", "method": "stream",
"span_name": "anthropic.chat"} entries (one in the regular Beta section and one
in the Bedrock Beta section) so the async wrapper will not attempt to await a
non-awaitable, and if you need to instrument stream leave or add it under the
non-Beta/sync wrapper handling instead.

Copy link
Copy Markdown
Contributor

@ellipsis-dev ellipsis-dev Bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed 5931306 in 1 minute and 8 seconds. Click for details.
  • Reviewed 28 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 3 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/opentelemetry-instrumentation-anthropic/tests/test_bedrock_with_raw_response.py:25
  • Draft comment:
    Removed commented-out @pytest.mark.skip decorator to re-enable the async test. Confirm that these tests should run actively.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
2. packages/opentelemetry-instrumentation-anthropic/tests/test_bedrock_with_raw_response.py:80
  • Draft comment:
    Removed commented-out @pytest.mark.skip decorator for the regular create test. Ensure that the test shouldn’t be skipped.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
3. packages/opentelemetry-instrumentation-anthropic/tests/test_bedrock_with_raw_response.py:129
  • Draft comment:
    Removed commented-out @pytest.mark.skip decorator for the beta test. Make sure the beta API tests are now intended to be executed.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None

Workflow ID: wflow_pw1QnWwkzfbexGuL

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

import inspect

response = _extract_response_data(response)
# If we get a coroutine, we cannot process it in sync context
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.

so it just won't work for coroutines, no?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants