Skip to content

adcp/a2aclient: Go A2A buyer client with context retention #70

@bokelley

Description

@bokelley

Why

Port of adcontextprotocol/adcp-client-python#251 to Go. That PR added auto-retention of contextId and taskId across multi-turn A2A calls on the Python side. Without a Go equivalent, Go buyers can't speak A2A — half of AdCP's transport surface — and we can't run Go-side conformance against A2A agents.

Depends on a Go A2A server to test against (see #69). Can test against Python reference agents in the interim.

What

New package adcp/a2aclient mirroring the Python ADCPClient A2A adapter's API shape so the two stay legible together.

API

c := a2aclient.New(cfg,
    a2aclient.WithContextID("resume-or-self-named"), // seed for resume across restarts
)

resp, err := c.SendMessage(ctx, msg)  // auto-injects contextId + pending taskId

c.ContextID()        // current, server-authoritative
c.PendingTaskID()    // empty when last response was terminal
c.ResetContext()     // clear
c.ResetContext("id") // clear + seed

Retention rules

  • Auto-adopt whatever contextId the server returns (supports ADK-style rewriting transparently).
  • Retain taskId only while last response status ∈ {submitted, working, input-required, auth-required}.
  • Clear taskId on terminal states.
  • Default on — document the "one Client per conversation" rule on the type; last-write-wins under concurrent use.

Error behavior

  • WithContextID / ResetContext(id) on a non-A2A-configured client return a typed error (symmetric writes).
  • ContextID() / PendingTaskID() return empty strings when unset (lenient reads; safe in generic code).

Tests

  • Unit: auto-retain, inject, reset, server rebinding, taskId retention in each non-terminal state, taskId clearing on terminal states.
  • Integration: real A2A server (Go if reference: A2A transport alongside MCP on reference agents #69 lands; Python reference otherwise). Prove contextId persists across sends and HITL input-required → resume path works.

Scope

  • Sync message/send + tasks/get to start. Streaming added later.
  • A2A transport only; MCP gets its own client story.

Non-goals

  • Full buyer SDK (discovery, signing abstractions) — this is the transport adapter.
  • Backwards compat — net-new package.

Sequence

  1. Reference-agent A2A transport (reference: A2A transport alongside MCP on reference agents #69) lands first to give us a Go server to test against.
  2. Client implementation.
  3. Conformance test running the same scenario over MCP (existing) and A2A (this package).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions