Skip to content

fix(agent): shape partial-stream stub to match active api_mode - #46003

Closed
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:fix/anthropic-stream-stub-api-mode
Closed

liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:fix/anthropic-stream-stub-api-mode

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes the partial-stream recovery stub for anthropic_messages mode. When a malformed Anthropic stream (non-contiguous content_block indices) crashes stream.get_final_message() with IndexError, the recovery stub now returns an Anthropic-shaped response (content list) instead of an OpenAI-shaped one (choices list). Previously the stub always used OpenAI shape, which AnthropicTransport.validate_response() rejected, causing 10 useless retries in the conversation loop.

Related Issue

Fixes #45908

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • agent/chat_completion_helpers.py: In the partial-stream stub creation path, check agent.api_mode. When "anthropic_messages", return an Anthropic-shaped stub with content=[SimpleNamespace(type="text", text=...)] and stop_reason="max_tokens" instead of the OpenAI-shaped choices=[...] stub. This ensures AnthropicTransport.validate_response() accepts the stub on the first try.
  • run_agent.py: Extend _is_provider_stream_parse_error() to also classify IndexError as a stream parse error for anthropic_messages mode. Non-contiguous content_block indices from upstream proxies cause the SDK accumulator to raise IndexError — this is an upstream protocol violation that should follow the same retry path as malformed event-stream frames.
  • tests/agent/test_anthropic_stream_stub_shape.py: 8 regression tests covering: Anthropic stub has content list, passes validate_response, normalizes correctly, chat_completions stub unchanged, IndexError classified as parse error, mode-gated behavior, existing ValueError classification preserved.

How to Test

  1. pytest tests/agent/test_anthropic_stream_stub_shape.py -xvs — all 8 tests pass
  2. pytest tests/run_agent/test_partial_stream_finish_reason.py -xvs — all 9 existing tests pass (no regression)
  3. To manually verify: configure an Anthropic-compatible proxy that sends non-contiguous content_block indices, send a message that triggers multi-block streaming (thinking + text), observe that the agent recovers gracefully instead of retrying 10 times with "response.content invalid" errors.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Code Intelligence

  • Analyzed: agent/chat_completion_helpers.py::interruptible_streaming_api_call (stub creation path), run_agent.py::_is_provider_stream_parse_error (error classification)
  • Blast radius: LOW — changes are in error recovery paths only; normal streaming is unaffected
  • Related patterns: PARTIAL_STREAM_STUB_ID (stub identification), AnthropicTransport.validate_response() (validator), _STOP_REASON_MAP (stop_reason → finish_reason mapping)

When a malformed Anthropic stream (non-contiguous content_block
indices) crashes stream.get_final_message() with IndexError, the
partial-stream recovery stub now returns an Anthropic-shaped response
(content list) for anthropic_messages mode instead of always returning
an OpenAI-shaped one (choices list).

Previously AnthropicTransport.validate_response() rejected the stub
because it checks response.content, which the OpenAI stub lacks —
causing 10 useless retries in the conversation loop.

Also extend _is_provider_stream_parse_error() to classify IndexError
as a stream parse error for anthropic_messages mode, enabling the
transient-retry path for upstream protocol violations.

Fixes NousResearch#45908
@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists duplicate This issue or pull request already exists labels Jun 14, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

Duplicate of #45919 — same fix for #45908 (Anthropic-shaped partial-stream recovery stub in anthropic_messages mode, agent/chat_completion_helpers.py). #45919 is the earliest open PR in the cluster (#45920 closed, #45922 also open).

@liuhao1024 liuhao1024 closed this Jun 14, 2026
@liuhao1024

Copy link
Copy Markdown
Contributor Author

Closing as duplicate of #45919 by @LeonSGP43, which implements the same fix for #45908 (Anthropic-shaped partial-stream recovery stub). That PR extracts a cleaner helper function with complete field coverage. It was opened earlier today and has passing CI.

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

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

anthropic_messages: malformed upstream stream (non-contiguous content_block index) crashes with IndexError and retries 10x

2 participants