Pre-alpha documentation
Call an A2A agent without guessing the outcome.
Freeze an A2A 1.0 Agent Card and egress interface, use every HTTP+JSON or JSON-RPC/SSE operation, and bind outbound sends to PostgreSQL durability.
One operation surface, two bindings
| Area | Operations | Transport result |
|---|---|---|
| Message | Send, streaming send | Task/message or bounded SSE |
| Task | Get, list, cancel, subscribe | Bounded snapshots/pages or SSE |
| Push config | Create, get, list, delete | Secret-redacted bounded contracts |
| Card | Authenticated extended card | Revalidated Agent Card |
Every request sends A2A-Version: 1.0. The client checks
response media, JSON-RPC version and ID, exclusive result/error presence,
exact response unions, duplicate JSON keys, resource identity,
blocking-send lifecycle, task-page filters/order, SSE event lifecycle,
artifact append continuity, idle time, event count, and byte ceilings. It
never follows redirects or retries a request.
Freeze discovery before execution
- Use verified HTTPS; literal loopback HTTP is an explicit test/sidecar boundary.
- Fetch one bounded public Agent Card and optionally verify its RFC 8785 digest.
- Select the first supported 1.0 interface in server preference order.
- Require its binding and URL to match a local egress pin exactly.
- Validate extension, tenant, and a complete anonymous or single-scheme bearer-compatible security choice.
let client = A2aClient::discover(
A2aAgentCardEndpoint::https(
"https://partner.example/.well-known/agent-card.json",
)?,
vec![A2aClientInterfacePin::https(
"https://partner.example/a2a",
A2aBinding::HttpJson,
)?],
A2aAgentCardTrust::TlsServerIdentity,
A2aClientSecurity::bearer("oidc", Arc::new(token_provider))?,
vec![],
A2aClientOptions::default(),
).await?; A production bearer provider resolves a short-lived credential for every exact operation, remote routing tenant, task, and scope. Durable sends also expose local tenant, run, invocation, and physical-attempt identity. The implemented profile covers HTTP Bearer, OAuth 2.0, and OpenID Connect token use; unsupported or multi-scheme requirements fail closed. Tokens, response bodies, and remote text never enter public errors or debug output.
The extended card is authenticated and revalidated, but returned as data. It never mutates this immutable client or silently changes egress/security pins; adopting it requires a reviewed, newly constructed binding.
Make PostgreSQL the dispatch authority
Agent Cards do not carry skill argument/result JSON Schemas, and A2A 1.0
has no send field that routes to a skill. The selected skill therefore
freezes media and security evidence; a trusted local registry validates
input and the standard one-key {"message": ...} or {"task": ...} output.
let recovery = A2aRemoteAgentRecovery::operator_attested_context_task_history(
4,
64,
DurationMillis::new(1_000)?,
)?;
let remote = A2aRemoteAgent::bind_with_recovery(
descriptor,
client,
"answer",
A2aRemoteAgentDelivery::AtMostOnce,
recovery,
schemas,
)?;
let mut tools = ToolProviderRegistryBuilder::new();
tools.register(Arc::new(remote))?;
let tools = tools.build();
The invocation ledger commits executing before the one network
send. A valid response is schema-checked before commit. Any uncertain outcome
after possible dispatch becomes Unknown + ReconcileFirst;
ordinary recovery does not send again.
The adapter sets returnImmediately: true. A returned Task
commits message submission plus its durable handle—not remote terminal
completion. Waiting for completion is a separately authorized,
application-owned get_task or subscribe_to_task workflow.
Do not invent message-ID idempotency
| Mode | Descriptor truth | Message identity |
|---|---|---|
AtMostOnce | Non-idempotent write; unsupported key | Physical attempt ID |
MessageIdDeduplicated | Idempotent write; required key | Stable invocation key |
A2A itself does not require receivers to deduplicate messageId. The second mode is safe only when operators prove durable remote
deduplication across the full local ledger-retention and disaster-recovery
window.
Recover only from attested remote facts
| Mode | Required deployment evidence | Action |
|---|---|---|
Disabled | None | Remain fail-closed for manual reconciliation |
ContextTaskHistory | Preserved client context, complete stable task pagination, retained original message ID | Bounded ListTasks scan; never resend |
MessageIdReplay | Durable message-ID deduplication across the complete recovery window | Replay the exact request identity; deduplicated delivery only |
Enabled modes require a matching descriptor status-query claim and a
bounded polling interval. Context recovery adds a one-way opaque ID to the
original message, scans at most 16 pages of 100 tasks with at most 256
history messages, and accepts exactly one match whose role, context, and
payload equal the original message. No match becomes Pending;
duplicate identities, ambiguous matches, same-ID payload substitution, or
exhausted scan bounds fail closed.
The provider-native Agent commits authoritative evidence atomically. A
pending probe becomes a durable SafeAfter node retry under a later
lease, with the original physical attempt and business-call count unchanged.
Bound every exchange
- 15-second discovery, 60-second unary/stream-establishment, and 60-second stream-idle defaults.
- 16 MiB request and 2 MiB unary-response transport defaults.
- 512 KiB line, 2 MiB event, 64 MiB total, and 4,096-event SSE defaults.
- Task pages follow A2A's 100-item maximum, inclusive timestamp filtering, and newest-first ordering; push-config pages have a local 256-item ceiling.
Before production, independently restrict DNS/proxy egress, review every card change, use attempt-scoped workload credentials, align local ledger retention with remote deduplication, alert on Unknown outcomes, and test accepted-request/lost-response, cancellation races, malformed streams, database failover, and restore.
Read the evidence, then the limits
Real loopback tests execute all eleven operations over both bindings and
exercise strict discovery, authorization, errors, streams, and lost
responses. They also prove context/history recovery without resend and
exact replay under an explicit deduplication attestation, including
rejection of same-ID payload substitution. A separate provider-neutral
real PostgreSQL test proves Unknown → Pending → durable retry → Committed with one business call across two probes.
Use the complete production guide and reproduction commands. The official TCK evidence applies to the separate Server profile; Client live-peer and recovery-attestation qualification, gRPC, stable API review, and a complete production release remain separate gates.