Repository navigation
Conversation
Assisted-by: GitHub Copilot CLI Signed-off-by: 1fanwang <1fannnw@gmail.com>
Assisted-by: GitHub Copilot CLI Signed-off-by: 1fanwang <1fannnw@gmail.com>
Pull request dashboard statusWaiting on the author · refreshed 2026-10-23 22:10 UTC Respond to 1 review item (e.g. link a commit, explain why not, ask a follow-up):
Status above doesn't look right?
|
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Finalization mutates caller-visible SDK data and drops captured partial text when callers abandon text_stream.
Review effort: Balanced
Findings: 2
Open (3)
What changed in this PR
Updates Anthropic streaming telemetry for #824 to distinguish abandoned responses from completed ones.
Changes:
- Tracks partial content, marks incomplete responses, and omits unknown output-token counts.
- Adds sync and async early-exit regression tests and a changelog entry.
| File | Description |
|---|---|
| instrumentation/opentelemetry-instrumentation-genai-anthropic/tests/test_sync_messages.py | Tests synchronous early exits during tool calls. |
| instrumentation/opentelemetry-instrumentation-genai-anthropic/tests/test_async_messages.py | Tests asynchronous early exits during tool calls. |
| instrumentation/opentelemetry-instrumentation-genai-anthropic/src/opentelemetry/instrumentation/genai/anthropic/wrappers.py | Tracks partial responses and adjusts finalization. |
| instrumentation/opentelemetry-instrumentation-genai-anthropic/.changelog/838.fixed | Documents the early-exit correction. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Assisted-by: GitHub Copilot CLI Signed-off-by: 1fanwang <1fannnw@gmail.com>
Assisted-by: GitHub Copilot CLI (Auto) Signed-off-by: 1fanwang <1fannnw@gmail.com>
Assisted-by: GitHub Copilot CLI (Auto) Signed-off-by: 1fanwang <1fannnw@gmail.com>
This comment has been minimized.
This comment has been minimized.
Assisted-by: GitHub Copilot CLI (Auto) Signed-off-by: 1fanwang <1fannnw@gmail.com>
Keep token corrections in telemetry, recover partial snapshot text, and skip content buffering when capture is disabled. Assisted-by: GitHub Copilot CLI (gpt-6-astra) Signed-off-by: 1fanwang <1fannnw@gmail.com>
| ) | ||
|
|
||
|
|
||
| def _partial_tool_use_stream_sse_body() -> bytes: |
There was a problem hiding this comment.
Please use recorded SDK calls for these regressions instead of transport mocks. Extend the existing test_sync_messages_stream_closed_early_by_caller and test_sync_messages_stream_interrupted_mid_iteration in this file, with matching async coverage.
| # text_stream bypasses our event tracking, but the snapshot has | ||
| # the received text. Tool snapshots may still hold placeholder input. | ||
| for index, block in enumerate(self._self_message.content): | ||
| if block.type == "text": |
There was a problem hiding this comment.
Breaking after the first text chunk of an extended-thinking response now drops the preceding reasoning. text_stream bypasses event tracking, and this fallback only copies text from the SDK snapshot. Preserve thinking blocks too.
| if block.type == "text": | |
| if block.type in ("text", "thinking"): |
Regression test for tests/test_sync_messages.py, using its existing imports and fixtures. This needs a real streaming cassette and matching async coverage. It has not been run; the expected failure is an empty recorded reasoning list despite nonempty reasoning in the SDK snapshot.
@pytest.mark.vcr()
def test_sync_messages_text_stream_early_exit_preserves_thinking(
span_exporter, anthropic_client, instrument_with_content
):
with anthropic_client.messages.stream(
model="claude-sonnet-4-20250514",
max_tokens=16000,
thinking={"type": "enabled", "budget_tokens": 10000},
messages=[
{"role": "user", "content": "What is 17*19? Think first."}
],
) as stream:
text = next(stream.text_stream)
snapshot = stream.current_message_snapshot
reasoning = [
{"type": "reasoning", "content": block.thinking}
for block in snapshot.content
if block.type == "thinking"
]
assert reasoning
assert all(part["content"] for part in reasoning)
assert text
assert snapshot.stop_reason is None
spans = span_exporter.get_finished_spans()
assert len(spans) == 1
span = spans[0]
output = _load_span_messages(
span, GenAIAttributes.GEN_AI_OUTPUT_MESSAGES
)
assert len(output) == 1
assert [
part for part in output[0]["parts"]
if part["type"] == "reasoning"
] == reasoning
assert output[0]["finish_reason"] == "error"Keep the SDK token counts and exercise early close and interruption against existing sync and async recordings. Assisted-by: GitHub Copilot CLI (gpt-6-astra) Signed-off-by: 1fanwang <1fannnw@gmail.com>
Keep upstream failure and cancellation cases alongside snapshot-preservation and disabled-capture assertions. Assisted-by: GitHub Copilot CLI (gpt-6-astra) Signed-off-by: 1fanwang <1fannnw@gmail.com>
Keep both import sets in the Anthropic stream wrappers. Upstream moved request capture to the stream manager entry, which does not overlap the early exit finalization. Assisted-by: GitHub Copilot CLI (claude-sonnet-5.5) Signed-off-by: 1fanwang <1fannnw@gmail.com>
|
Hi @1fanwang — just a friendly reminder that this pull request is waiting on you. The dashboard status comment has the open items and is kept current.
|
Assisted-by: GitHub Copilot CLI (Auto) Signed-off-by: 1fanwang <1fannnw@gmail.com>
Keep partial-stream state compatible with beta SDK blocks and cover sync/async early thinking exits. Assisted-by: GitHub Copilot CLI (Auto) Signed-off-by: 1fanwang <1fannnw@gmail.com>
Assisted-by: GitHub Copilot CLI (Auto) Signed-off-by: 1fanwang <1fannnw@gmail.com>
Assisted-by: GitHub Copilot CLI (GPT-6 Astra) Signed-off-by: 1fanwang <1fannnw@gmail.com>


Description
Stopping an Anthropic stream could report unfinished tool arguments as a complete call. This marks partial text and tool output incomplete and preserves the latest provider token count, including zero, without changing SDK responses.
Fixes #824.
A response without a stop event or stop reason is incomplete. The wrapper keeps unfinished tool-argument JSON as text and takes token counts from the SDK's accumulated response.
Known gaps: Streaming-thinking and tool recordings remain unavailable. Thinking coverage uses local HTTP/SSE rather than a provider recording.
Type of change
How has this been tested?
Testing Done
Anthropic 0.51.0 and 1.13.0 produced identical results.
The tool-call input uses a synthetic local HTTP server, not a provider recording.
Before:
After:
The usage replay uses unchanged provider recordings.
Before:
After:
No live provider calls. Save all three sources below in /tmp. Run from this checkout with its tox environments:
Reproducer source: compare_stream_repros.py
Reproducer source: repro_early_exit.py
Reproducer source: repro_recorded_stream.py
Early thinking exit:
Anthropic SDK 1.12.0 received a local HTTP/SSE stream with a thinking block followed by text. The observation below uses the committed local-server fixtures and an in-memory span exporter. No provider request was made; the package has no recorded streaming-thinking cassette.
Save the source below as thinking-sse-observation.py in the Anthropic package directory of the 4e4beb5 checkout. Keep the package's installed dependencies and test fixtures from that checkout while comparing the two wrapper versions.
At 227ea28, the process exited 1:
git show 4e4beb5d4a0639cbe610eeee32292754216f5fdc:instrumentation/opentelemetry-instrumentation-genai-anthropic/src/opentelemetry/instrumentation/genai/anthropic/wrappers.py > src/opentelemetry/instrumentation/genai/anthropic/wrappers.py env -u ANTHROPIC_API_KEY ../../.tox/py314-test-instrumentation-genai-anthropic-latest/bin/python thinking-sse-observation.pyAt 4e4beb5, the process exited 0:
Reproducer source: thinking-sse-observation.py
Checklist
See CONTRIBUTING.md
for the style guide, changelog guidance, and more.
Documentation changes are not applicable.