a2aproject / a2aproject/A2A

Proposal: Distributed Tracing Semantic Conventions for A2A

Aberta
#2,103 2 comentários 0 reações 0 responsáveis Ver no GitHub
Linguagem predominante
Shell
Estrelas
25.7k
Forks
2.6k
Merge médio
3d 6h
PRs com merge (30d)
16

Descrição

### Abstract

When Agent A delegates a task to Agent B via A2A, the trace breaks. The Python SDK creates spans locally (via `@trace_class`) but there's no standard way to propagate W3C Trace Context between agents. Each delegation starts a fresh, disconnected trace. This makes it impossible to see a full delegation chain in Jaeger, Grafana, or any OTel-compatible backend.

This proposal defines how trace context flows between A2A agents and what the resulting spans should look like (names, attributes, parent-child relationships), so that instrumentation libraries and SDKs converge on the same conventions.

### Motivation

I've been working with OpenTelemetry GenAI semantic conventions and running multi-agent systems in production. Three things keep coming up:

**Traces disconnect at delegation boundaries.** The `a2a-python` SDK traces request handlers on the server side, but when a client calls `message/send` to another agent, there's no mechanism to inject `traceparent` into the request and extract it on the other end. You get two separate traces instead of one connected tree. Every team I've seen solves this differently.

**Everyone invents their own attribute names.** The Traceability Extension sample uses `TraceRecord`/`TraceStep` with custom fields. Third-party libraries like traceAI use `a2a.task_id`. The CoSAI/OASIS ws2-defenders effort uses `task.id`. The Python SDK's built-in telemetry doesn't tag spans with task or agent identifiers at all. When you switch tools or vendors, your dashboards break because nothing agrees on what to call things.

**No guidance on span structure.** Should `message/send` produce one CLIENT span on the caller and one SERVER span on the receiver (like HTTP)? What about streaming via `tasks/sendSubscribe`? When an agent delegates to a sub-agent, is that a child span or a link? People make reasonable but incompatible choices here.

### Relationship to Existing Work

The Traceability Extension sample in a2a-samples demonstrates call-chain recording using a custom JSON format. It's useful for debugging but doesn't integrate with OTel backends. Issue #2026 proposes W3C header propagation specifically for A2A-to-MCP cross-protocol bridging. This proposal complements both by defining the semantic conventions that give propagated traces consistent meaning across implementations.

The OTel GenAI semantic conventions already define `gen_ai.agent.name`, `gen_ai.operation.name`, and span patterns like `invoke_agent {name}`. This proposal follows those same patterns for A2A-specific operations rather than inventing a parallel naming scheme.

### Proposed Scope

Narrowly scoped to tracing only. No metrics, cost propagation, or log correlation in v1.

**Context propagation.** Trace context (W3C `traceparent` and `tracestate`) travels in message metadata under the extension's URI key:

```json
{
"metadata": {
"": {
"traceparent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
"tracestate": "a2a=weather-agent"
}
}
}
```

No baggage in v1. Baggage propagates to all downstream services in plaintext, which creates a data leakage vector in multi-tenant agent deployments.

**Span naming.** Following the OTel GenAI `{operation} {target}` pattern:

| Operation | Span Name | Kind |
|-----------|-----------|------|
| Client sends message | `invoke_agent {agent_name}` | CLIENT |
| Client gets task | `get_task {task_id}` | CLIENT |
| Client cancels task | `cancel_task {task_id}` | CLIENT |
| Server processes message | `process_message` | SERVER |
| Server delegates to sub-agent | `invoke_agent {agent_name}` | CLIENT |

**Semantic attributes.** Reusing OTel GenAI conventions where they exist, adding only what's A2A-specific:

| Attribute | Source | Description |
|-----------|--------|-------------|
| `gen_ai.agent.name` | OTel GenAI (existing) | Name of the target agent |
| `gen_ai.operation.name` | OTel GenAI (existing) | Method name, e.g. `message/send` |
| `a2a.task.id` | New | A2A task identifier |
| `a2a.task.state` | New | Terminal task state |
| `a2a.method` | New | JSON-RPC method name |

Three new attributes total. Everything else reuses what OTel already defines.

**Activation.** Standard `A2A-Extensions` header negotiation. Agents that support the extension extract `traceparent` from metadata and create child spans under the propagated context. Agents that don't support it simply ignore the metadata.

### Deliverables

1. Semantic conventions document covering attribute names, span structures, and propagation rules
2. Python reference implementation as a `ClientCallInterceptor` on the client side and middleware on the server side
3. End-to-end example showing a correlated trace across a two-agent delegation

Happy to start with a reference implementation and iterate based on maintainer feedback.

Guia de contribuição

Abrir o guia de contribuição

Avaliação

Esta issue ainda não foi avaliada.

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.