[A2A] RemoteA2aAgent(use_legacy=False): extension header written to state['http_kwargs'], ignored by a2a-sdk 1.x transports
Les mainteneurs répondent en général sous 5 jours
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 2/5
- Temps estimé
- 1-3 heures
- Accessibilité débutants
- 84/100
Piste de recherche
Commencez dans google/adk/a2a/agent/interceptors/new_integration_extension.py:43-51 et comparez sa mise à jour du contexte avec le comportement du transport de a2a-sdk 1.x décrit dans l’issue. Préservez les paramètres de service existants et placez l’en-tête A2A-Extensions à l’endroit où les transports HTTP et gRPC le lisent, puis exécutez la reproduction in-process fournie et confirmez que le serveur capture l’en-tête.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Describe the Bug
With RemoteA2aAgent(use_legacy=False), ADK installs a request interceptor that is supposed to negotiate the new A2A-ADK integration extension (the one documented as the a2a-extension / v2 A2aAgentExecutor). The interceptor (google/adk/a2a/agent/interceptors/new_integration_extension.py:43-51, same code on main @ eb1a002 and on 2.7.1–2.10.0) writes the A2A-Extensions header into:
params.client_call_context.state['http_kwargs']
But on a2a-sdk 1.x, HTTP transports build outbound headers exclusively from ClientCallContext.service_parameters (a2a/client/transports/http_helpers.py:46-47 in 1.1.2):
if context and context.service_parameters:
http_kwargs['headers'] = context.service_parameters.copy()
Nothing in a2a-sdk 1.x reads client_call_context.state['http_kwargs'], so the extension header never reaches the server. The server therefore keeps running the legacy executor even though the client asked for the new integration. (The gRPC transport likewise reads service_parameters, a2a/client/transports/grpc.py:304-305.)
For reference, a2a-sdk 1.x's own auth interceptor writes Authorization into context.service_parameters (a2a/client/auth/interceptor.py:47-84), which is the convention downstream users follow too.
Steps to Reproduce
Self-contained, in-process, no network or credentials:
import asyncio
import httpx
from google.adk.a2a.utils.agent_to_a2a import to_a2a
from google.adk.agents import LlmAgent
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
from google.adk.models.base_llm import BaseLlm
from google.adk.models.llm_response import LlmResponse
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types
CAPTURED: dict[str, str] = {}
class CaptureMiddleware:
def __init__(self, app):
self.app = app
async def __call__(self, scope, receive, send):
if scope["type"] == "http":
headers = {k.decode().lower(): v.decode() for k, v in scope["headers"]}
if "a2a-extensions" in headers:
CAPTURED[headers["a2a-extensions"]] = headers["a2a-extensions"]
await self.app(scope, receive, send)
class Scripted(BaseLlm):
async def generate_content_async(self, req, stream=False):
yield LlmResponse(content=types.Content(role="model", parts=[types.Part(text="ok")]))
async def main():
server = to_a2a(LlmAgent(name="remote", model=Scripted(model="x"), instruction="x"))
async with server.router.lifespan_context(server):
remote = RemoteA2aAgent(
name="remote",
agent_card="http://localhost:8000/.well-known/agent-card.json",
use_legacy=False,
httpx_client=httpx.AsyncClient(
transport=httpx.ASGITransport(app=CaptureMiddleware(server))
),
)
runner = Runner(
app_name="caller",
agent=remote,
session_service=InMemorySessionService(),
auto_create_session=True,
)
async for _ in runner.run_async(
user_id="u", session_id="s",
new_message=types.Content(role="user", parts=[types.Part(text="hi")]),
):
pass
print("A2A-Extensions seen by server:", CAPTURED or "NOT RECEIVED")
asyncio.run(main())
Observed Behavior
A2A-Extensions seen by server: NOT RECEIVED
Adding a custom request_interceptors entry that puts the header into params.client_call_context.service_parameters instead makes the server receive it, which confirms the interceptor pipeline runs and the failure is specifically the state['http_kwargs'] write target.
Expected Behavior
RemoteA2aAgent(use_legacy=False) causes the A2A-Extensions: https://google.github.io/adk-docs/a2a/a2a-extension/ header to actually reach the remote server on a2a-sdk 1.x.
Environment Details
- google-adk: 2.7.1 (pinned in my project); the interceptor source hasn't been updated since
- a2a-sdk: 1.1.2, 1.1.5 also affected
- Python: 3.14
- OS: macOS 15
Impact / Suggested direction
Impact is silent: no error, the server just keeps legacy behavior. This specifically blocks use_legacy=False from doing anything on the 1.x client stack, and it masks verification of the v2-executor bugs tracked in #7247 / #6343 (their suggested workaround of activating the v2 path via use_legacy=False is a no-op on a2a-sdk 1.x).
Suggested fix: in new_integration_extension.py, write the header into params.client_call_context.service_parameters (initializing ClientCallContext if absent) and merge with any existing mapping.
- Langage dominant
- Python
- Étoiles
- 21.6k
- Forks
- 4k
- Merge moyen
- 12 h 6 min
- PR mergées (30 j)
- 4
Préparer son environnement
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de google/adk-python
-
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
google/adk-python#7341 · 2 réactions ·
Les mainteneurs répondent en général sous 5 jours
-
GoogleOidcVerifier treats string "false" as a verified email claimPeut-être pris @surajksharma07 l’a pris il y a 1 jour. Ouvertecore
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
google/adk-python#7289 · 5 commentaires · 1 personne assignée ·
Les mainteneurs répondent en général sous 5 jours
-
RestApiTool raises uncaught KeyError when a required path param is omittedPeut-être pris @llalitkumarrr l’a pris il y a 1 jour. Ouverterequest clarification tools
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
google/adk-python#7282 · 3 commentaires · 1 personne assignée ·
Les mainteneurs répondent en général sous 5 jours
-
CredentialsManager should also extract scopes when populating auth schemesPeut-être pris @sanketpatil06 l’a pris il y a 4 jours. Ouvertecore needs review
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
google/adk-python#7266 · 2 commentaires · 1 personne assignée ·
Les mainteneurs répondent en général sous 5 jours
-
OAuth2 Discovery method fails because FastMCP with GoogleProvider (OAuth) returns issuerUrl with trailing slashPeut-être pris @sanketpatil06 l’a pris il y a 4 jours. Ouvertemcp
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
google/adk-python#7265 · 3 commentaires · 1 personne assignée ·
Les mainteneurs répondent en général sous 5 jours
Toutes les issues de google/adk-python
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
PedestrianDynamics/pyFDS-Evac#343 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 88/100
theskumar/python-dotenv#708 ·
-
Difficulté 1/5 Moins d'une heure Accessibilité débutants 88/100
Les mainteneurs répondent en général sous 2 jours
-
Docs Timedelta
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
pandas-dev/pandas#69919 ·
Les mainteneurs répondent en général sous 1 jour
-
API documentation
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
zephyrproject-rtos/west#1009 · 2 commentaires ·
Les mainteneurs répondent en général sous 3 jours