fix(bedrock): streaming fallback to Converse API + image base64 decode + bearer token routing - #34742
Conversation
…e + bearer token routing Three fixes for the Bedrock Claude path: 1. Streaming fallback: When AnthropicBedrock SDK raises 'Unexpected event order' (SDK misparses Bedrock error events as message_start), auto-switch to native Converse API for the rest of the session instead of failing after 3 retries. 2. Image base64 decode (NousResearch#33317): data URL payloads were passed as base64 strings to source.bytes, but boto3 re-encodes at the wire layer. Now decoded to raw bytes before passing to Converse API. 3. Bearer token routing (NousResearch#28156): Users with AWS_BEARER_TOKEN_BEDROCK are now routed through Converse API regardless of model, since the AnthropicBedrock SDK only supports SigV4 signing. 3 new tests. 121 bedrock_adapter tests passing.
|
Significant overlap with existing open PRs:
This PR bundles all three fixes together. Consider whether to merge this or the individual PRs. |
|
For anyone tracking bearer-token Bedrock support: the two PRs that look closest to a complete fix are #24507 (main-loop Converse routing + Relative to this PR: the routing here omits the token promotion that #24507 carries (which matters for cron jobs / subagents that don't inherit the interactive session's env), and the base64 image-decode fix is also included in #28085. The streaming-overload → Converse fallback in this PR is independently useful for SigV4 hosts. |
|
Update — the aux vision gap noted in my comment above is now resolved by #28085's second commit ( |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for consolidating the Bedrock reports. The image and bearer-routing premises are both still present on current main, but this bundle needs a focused salvage rather than a direct application.
Problems
agent/bedrock_adapter.py:91-101creates boto3 clients without promotingAWS_BEARER_TOKEN_BEDROCKto boto3'sAWS_BEARER_TOKEN. This PR routes bearer users to Converse but does not provide that token to the new client path; related PR #24507 contains the missing promotion.- The new fallback changes
agent.api_modepermanently from a string-matchedRuntimeError. Currentagent/agent_init.py:895-915initializes_bedrock_guardrail_configonly when Converse is selected at startup, so this transition would lose configured guardrails. - No test exercises the new conversation-loop fallback; the added tests cover only conversion and provider resolution.
base64.b64decode(data)is non-strict and the fallback still sends arbitrary bytes for malformed input.
Suggested changes
- Add guarded bearer-token promotion in the boto3 client factory with regression coverage.
- Use a tested Converse-transition helper that preserves Bedrock runtime state, including guardrails, and restrict fallback to a confirmed retryable stream failure.
- Strictly validate data URLs and skip malformed image blocks; add a live-path fallback regression test.
Automated hermes-sweeper review.
| # results in double-encoding and Bedrock rejects it with | ||
| # "Failed to sanitize image". Ref: #33317. | ||
| import base64 | ||
| try: |
There was a problem hiding this comment.
base64.b64decode() defaults to non-strict parsing, so malformed payloads can silently decode to junk; the exception fallback then still sends arbitrary bytes to Bedrock. Use validate=True and omit an invalid image block rather than forwarding it.
Three fixes for the Bedrock Claude path that share a common theme: the AnthropicBedrock SDK doesn't handle all Bedrock scenarios correctly, and the native Converse API path is the reliable fallback.
1. Streaming fallback (new)
When the AnthropicBedrock SDK's stream accumulator receives a Bedrock error event (throttling, overload, 5xx) before
message_start, it raisesRuntimeError: Unexpected event orderand discards the actual error payload. After 3 retries the session dies.Fix: detect this specific RuntimeError in the conversation loop and auto-switch
api_modefromanthropic_messagestobedrock_conversefor the rest of the session. The Converse API handles these error events gracefully via boto3's native error handling.2. Image base64 decode (fixes #33317)
_convert_content_to_converse()passed the base64 string directly assource.bytes. boto3 re-encodes at the wire layer, resulting in double-encoding. Bedrock rejects with "Failed to sanitize image".Fix:
base64.b64decode(data)before passing tosource.bytes.3. Bearer token routing (fixes #28156 part 1)
Users with
AWS_BEARER_TOKEN_BEDROCKwere routed through the AnthropicBedrock SDK (which only supports SigV4 signing), causingRuntimeError: could not resolve credentials from session.Fix: check for bearer token env var in the dual-path routing logic. If present, always use
bedrock_converseregardless of model.Files
agent/conversation_loop.py-- streaming fallback handleragent/bedrock_adapter.py-- base64 decode fixhermes_cli/runtime_provider.py-- bearer token routingtests/agent/test_bedrock_adapter.py-- 3 new testsTesting
121 bedrock_adapter tests passing (Python 3.11 + 3.14).
Ref: #33317, #28156, #14737