mirror of
https://github.com/tiennm99/litellm.git
synced 2026-07-12 13:05:11 +00:00
250d8d2a96
* fix(a2a): forward agent_extra_headers through completion bridge
A2A agents backed by a custom_llm_provider (e.g. langgraph,
bedrock_agentcore) silently dropped any per-request headers rewritten
from the inbound `x-a2a-{agent}-*` convention or admin-configured
`extra_headers`. The headers were correctly extracted in
`a2a_endpoints.py` but never passed into
`_send_message_via_completion_bridge` or the bridge handler, so the
upstream HTTP request reached the agent backend without them.
Thread `agent_extra_headers` through:
- asend_message / asend_message_streaming -> bridge call sites
- _send_message_via_completion_bridge
- A2ACompletionBridgeHandler.handle_non_streaming / handle_streaming
- Inject as `extra_headers` into the underlying litellm.acompletion()
call, and forward to provider configs via kwargs (their **kwargs
signature absorbs it harmlessly today).
* fix(a2a): forward agent_extra_headers through bridge convenience wrappers
Address greptile review on PR #28277:
- handle_a2a_completion / handle_a2a_completion_streaming (the public,
exported convenience wrappers) now accept agent_extra_headers and
forward it to the underlying class methods. Without this, callers
going through the public API would still silently drop per-request
headers — the exact regression this PR fixes for the class-method
path.
- Add the missing agent_extra_headers entry to the handle_streaming
docstring for parity with handle_non_streaming.
Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
* fix(a2a/bedrock): forward agent_extra_headers to AgentCore HTTP request
Address greptile follow-up on PR #28277:
BedrockAgentCoreA2AConfig was absorbing agent_extra_headers via **kwargs
but never propagating to the underlying HTTP POST, so x-a2a-{agent}-*
rewrites and admin extra_headers were silently dropped on the
bedrock_agentcore path that bypasses the completion bridge.
Thread the parameter through the full Bedrock AgentCore stack:
- config.handle_non_streaming / handle_streaming pull
agent_extra_headers from kwargs and pass to the handler.
- handler.handle_non_streaming / handle_streaming accept it and forward
to the transformation layer.
- transformation.get_url_and_signed_request merges agent_extra_headers
into the headers dict BEFORE signing, so SigV4 covers them in the
signature. JWT/Bearer path: AgentCore signer always overwrites
Authorization with api_key, so use api_key (not agent_extra_headers)
to override the bearer token.
Also fix a pre-existing test assertion that was already broken by the
parent commit ab70ff6 (test_provider_config_receives_litellm_params
didn't include agent_extra_headers in the expected call).
Tests:
- TestTransformation::test_agent_extra_headers_merged_into_signed_headers_jwt
- TestTransformation::test_agent_extra_headers_signed_for_sigv4
- TestNonStreaming::test_agent_extra_headers_forwarded_on_outbound_post
Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
* fix(a2a/bedrock): drop reserved AWS headers from agent_extra_headers
Per veria-ai security review on PR #28277:
agent_extra_headers carries values rewritten from the client-controlled
x-a2a-{agent}-* convention, so the unconditional 'headers.update(agent_extra_headers)'
in BedrockAgentCoreA2ATransformation.get_url_and_signed_request let any
caller with access to an agent overwrite headers the proxy sets from
trusted server-side config -- most notably
X-Amzn-Bedrock-AgentCore-Runtime-User-Id, which AWS treats as the runtime
identity. Because the merge happened before SigV4 signing, the spoofed
value would also be bound into a valid signature.
Strip reserved AWS/AgentCore headers (authorization, host,
x-amzn-bedrock-agentcore-runtime-*, x-amz-*) from agent_extra_headers
before merging and log a warning when any are dropped. Legitimate
per-request headers (e.g. x-mcp-token, x-tenant) still pass through.
Adds two tests covering both the JWT path (verifies the spoof does not
land on the outbound headers) and the SigV4 path (verifies the signer
never sees the spoofed values).
Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
* fix(a2a): annotate completion_params dict for mypy
The dict literal initializing completion_params had heterogeneous value
types (str, list, bool), so mypy inferred the value type as a narrow
union that did not accept dict[str, str] when assigning extra_headers.
Annotate completion_params as Dict[str, Any] in both the non-streaming
and streaming bridge handlers so the agent_extra_headers merge
type-checks cleanly.
Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
* fix(a2a/pydantic_ai): forward agent_extra_headers to upstream HTTP request
* fix(a2a/bridge): admin litellm_params.extra_headers win over caller-rewritten headers
agent_extra_headers contains both admin static_headers and caller-derived
dynamic headers (from the x-a2a-{agent}-* rewrite). Merging it last would
let a caller replace headers that the proxy was configured to send upstream
via litellm_params.extra_headers. Flip the merge order so admin-configured
headers take precedence on conflict.
* fix(a2a/headers): merge_agent_headers compares case-insensitively
HTTP header names are case-insensitive, but the previous merge was a
case-sensitive dict update. That meant an admin-configured
static_headers['Authorization'] (capital A) did not strip a
caller-rewritten x-a2a-{agent}-authorization (lowercase, from the
inbound header normalization in a2a_endpoints) - both ended up on the
outbound request to pydantic_ai / langgraph / etc.
Restore the documented 'static wins on conflict' invariant by comparing
case-insensitively when overlaying static_headers. Static side's casing
is preserved on the output.
* fix(a2a/bridge): merge configured extra_headers case-insensitively over caller headers
A caller-rewritten lowercase header (e.g. authorization from the
x-a2a-{agent}-* convention) could ride alongside an admin-configured
case-variant key in litellm_params.extra_headers, sending duplicate
Authorization headers upstream. The bridge now reuses
merge_agent_headers so configured headers win case-insensitively, in
both the non-streaming and streaming paths. merge_agent_headers moved
to litellm.interactions.agents.utils (re-exported from the proxy utils)
so the SDK-level bridge does not import from litellm.proxy.
https://claude.ai/code/session_017cBvda8Y4CLo8wspB2kfSV
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>