Skip to content

[Feat]: A2AClient should propagate trace context? #168

Description

@jerry-junjie-xu

Is your feature request related to a problem? Please describe.

A2A py sdk provides OpenTelemetry util lib #and key classes/functions are intrumented.

However, the trace context is not propagated across agent boundries by default.

Describe the solution you'd like

A2AClient propagates trace context.

Describe alternatives you've considered

We can get trace context propagated manually, when we have control over the coding calling A2AClient:

headers = {}
inject(headers)
async for response in client.send_message_streaming(request, http_kwargs={"headers": headers}):
    ...

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Activity

  1. self-assigned this
    on Nov 5, 2025
  2. DhanashreePetare commented on Dec 16, 2025

    @DhanashreePetare

    Greetings @jerry-junjie-xu ..I am interested to work on the issue. Can You please assign this to me. ThankYou

  3. jerry-junjie-xu commented on Dec 17, 2025

    @jerry-junjie-xu
    Author

    Hi @DhanashreePetare,

    I don't seem to have the permission to reassign issues.

  4. mtsmyassin commented on Apr 17, 2026

    @mtsmyassin

    Implementation sketch

    The cleanest way to propagate trace context is via OpenTelemetry's standard HTTP instrumentation, injecting W3C traceparent / tracestate headers into every outgoing A2AClient request.

    Client-side

    # src/a2a/client/trace_context.py
    from opentelemetry import propagate
    from opentelemetry.trace import get_current_span
    
    
    def inject_trace_context(headers: dict[str, str]) -> dict[str, str]:
        """Inject W3C trace context into outgoing headers."""
        propagate.inject(headers)
        return headers

    Then wire it into the existing transports. For JsonRpcTransport (httpx-based):

    # Before making the HTTP call
    request_headers = dict(self._headers) if self._headers else {}
    inject_trace_context(request_headers)
    response = await self._http_client.post(
        self._url, json=payload, headers=request_headers,
    )

    For GrpcTransport, use the gRPC OTel instrumentation package which handles this automatically:

    from opentelemetry.instrumentation.grpc import GrpcAioInstrumentorClient
    GrpcAioInstrumentorClient().instrument()

    Make OTel a soft dependency

    To avoid forcing the dep on every user, guard the import:

    try:
        from opentelemetry import propagate
        _OTEL_AVAILABLE = True
    except ImportError:
        _OTEL_AVAILABLE = False
    
    def inject_trace_context(headers: dict[str, str]) -> dict[str, str]:
        if _OTEL_AVAILABLE:
            propagate.inject(headers)
        return headers

    And expose it through an otel extra:

    # pyproject.toml
    [project.optional-dependencies]
    otel = ["opentelemetry-api>=1.25", "opentelemetry-instrumentation>=0.46b0"]

    Server-side (pairs with #828

    On the server, the reverse: extract context from incoming headers so spans created inside the agent become children of the client span:

    from opentelemetry import propagate
    
    ctx = propagate.extract(dict(request.headers))
    with tracer.start_as_current_span("agent.execute", context=ctx):
        ...

    Combined effect

    Client calls message/send → span A is active → traceparent header injected → server extracts → agent.execute span B is a child of A → any downstream tools/LLM calls from the agent are grandchildren of A. End-to-end distributed trace across agent boundaries, which is particularly valuable for multi-agent workflows.

    I can submit a PR implementing this for the JSON-RPC transport first, then extend to REST / gRPC in follow-ups. Worth noting the telemetry.py utilities already use OTel internally, so the dependency story is already partially in place.

  5. sokoliva commented on Apr 21, 2026

    @sokoliva
    Member

    A2AClient was removed.

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

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions