a2aclient

package
v0.3.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 14, 2026 License: Apache-2.0 Imports: 23 Imported by: 6

Documentation

Overview

Package a2aclient provides a transport-agnostic A2A client implementation. Under the hood it handles transport protocol negotiation and connection establishment.

A Client can be configured with CallInterceptor middleware and custom transports. If a client is created in multiple places, a Factory can be used to share the common configuration options:

factory := NewFactory(
	WithConfig(&a2aclient.Config{...}),
	WithInterceptors(loggingInterceptor),
	WithGRPCTransport(customGRPCOptions)
)

A client can be created from an a2a.AgentCard or a list of known a2a.AgentInterface descriptions using either package-level functions or Factory methods.

client, err := factory.CreateFromEndpoints(ctx, []a2a.AgentInterface{{URL: url, Transport: a2a.TransportProtocolGRPC}})

// or

card, err :=  agentcard.DefaultResolved.Resolve(ctx, url)
if err != nil {
	log.Fatalf("Failed to resolve an AgentCard: %v", err)
}
client, err := a2aclient.NewFromCard(ctx, card, WithInterceptors(&customInterceptor{}))

An AuthInterceptor provides a basic support for attaching credentials listed as security requirements in agent card to requests. Credentials retrieval logic is application specific and is not handled by the package.

// client setup
store :=  a2aclient.InMemoryCredentialsStore()
interceptors := WithInterceptors(&a2aclient.AuthInterceptor{Service: store})
client, err := a2aclient.NewFromCard(ctx, card, interceptors)

// session setup
sessionID := newSessionID()
store.Set(sessionID, a2a.SecuritySchemeName("..."), credential)
sessionCtx := a2aclient.WithSessionID(ctx, sessionID)

// credentials will be automatically attached to requests if listed as security requirements
resp, err := client.SendMessage(sessionCtx, params)

Index

Constants

This section is empty.

Variables

View Source
var ErrCredentialNotFound = errors.New("credential not found")

ErrCredentialNotFound is returned by CredentialsService if a credential for the provided (sessionId, scheme) pair was not found.

Functions

func WithSessionID

func WithSessionID(ctx context.Context, sid SessionID) context.Context

WithSessionID allows callers to attach a session identifier to the request. CallInterceptor can access this identifier using SessionIDFrom.

Types

type AuthCredential

type AuthCredential string

AuthCredential represents a security-scheme specific credential (eg. a JWT token).

type AuthInterceptor

type AuthInterceptor struct {
	PassthroughInterceptor
	Service CredentialsService
}

AuthInterceptor implements CallInterceptor. It uses SessionID provided using WithSessionID to lookup credentials and attach them according to the security scheme specified in the agent card. Credentials fetching is delegated to CredentialsService.

func (*AuthInterceptor) Before

func (ai *AuthInterceptor) Before(ctx context.Context, req *Request) (context.Context, error)

type CallInterceptor

type CallInterceptor interface {
	// Before allows to observe, modify or reject a Request.
	// A new context.Context can be returned to pass information to After.
	Before(ctx context.Context, req *Request) (context.Context, error)

	// After allows to observe, modify or reject a Response.
	After(ctx context.Context, resp *Response) error
}

CallInterceptor can be attached to an Client. If multiple interceptors are added:

  • Before will be executed in the order of attachment sequentially.
  • After will be executed in the reverse order sequentially.

type CallMeta

type CallMeta map[string][]string

CallMeta holds things like auth headers and signatures. In jsonrpc it is passed as HTTP headers, in gRPC it becomes a part of context.Context. Custom protocol implementations can use CallMetaFrom to access this data and perform the operations necessary for attaching it to the request.

func CallMetaFrom

func CallMetaFrom(ctx context.Context) (CallMeta, bool)

CallMetaFrom allows Transport implementations to access CallMeta after all the interceptors were applied.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client represents a transport-agnostic implementation of A2A client. The actual call is delegated to a specific Transport implementation. CallInterceptor-s are applied before and after every protocol call.

func NewFromCard

func NewFromCard(ctx context.Context, card *a2a.AgentCard, opts ...FactoryOption) (*Client, error)

NewFromCard is a client Client constructor method which takes an a2a.AgentCard as input. It is equivalent to Factory.CreateFromCard method.

func NewFromEndpoints

func NewFromEndpoints(ctx context.Context, endpoints []a2a.AgentInterface, opts ...FactoryOption) (*Client, error)

NewFromEndpoints is a Client constructor method which takes known a2a.AgentInterface descriptions as input. It is equivalent to Factory.CreateFromEndpoints method.

func (*Client) AddCallInterceptor

func (c *Client) AddCallInterceptor(ci CallInterceptor)

AddCallInterceptor allows to attach a CallInterceptor to the client after creation.

func (*Client) CancelTask

func (c *Client) CancelTask(ctx context.Context, id *a2a.TaskIDParams) (*a2a.Task, error)

func (*Client) DeleteTaskPushConfig

func (c *Client) DeleteTaskPushConfig(ctx context.Context, params *a2a.DeleteTaskPushConfigParams) error

func (*Client) Destroy

func (c *Client) Destroy() error

func (*Client) GetAgentCard

func (c *Client) GetAgentCard(ctx context.Context) (*a2a.AgentCard, error)

func (*Client) GetTask

func (c *Client) GetTask(ctx context.Context, query *a2a.TaskQueryParams) (*a2a.Task, error)

func (*Client) GetTaskPushConfig

func (c *Client) GetTaskPushConfig(ctx context.Context, params *a2a.GetTaskPushConfigParams) (*a2a.TaskPushConfig, error)

func (*Client) ListTaskPushConfig

func (c *Client) ListTaskPushConfig(ctx context.Context, params *a2a.ListTaskPushConfigParams) ([]*a2a.TaskPushConfig, error)

func (*Client) ResubscribeToTask

func (c *Client) ResubscribeToTask(ctx context.Context, id *a2a.TaskIDParams) iter.Seq2[a2a.Event, error]

func (*Client) SendMessage

func (c *Client) SendMessage(ctx context.Context, message *a2a.MessageSendParams) (a2a.SendMessageResult, error)

func (*Client) SendStreamingMessage

func (c *Client) SendStreamingMessage(ctx context.Context, message *a2a.MessageSendParams) iter.Seq2[a2a.Event, error]

func (*Client) SetTaskPushConfig

func (c *Client) SetTaskPushConfig(ctx context.Context, params *a2a.TaskPushConfig) (*a2a.TaskPushConfig, error)

type Config

type Config struct {
	// PushConfig specifies the default push notification configuration to apply for every Task.
	PushConfig *a2a.PushConfig
	// AcceptedOutputModes are MIME types passed with every Client message and might be used by an agent
	// to decide on the result format.
	// For example, an Agent might declare a skill with OutputModes: ["application/json", "image/png"]
	// and a Client that doesn't support images will pass AcceptedOutputModes: ["application/json"]
	// to get a result in the desired format.
	AcceptedOutputModes []string
	// PreferredTransports is used for selecting the most appropriate communication protocol.
	// The first transport from the list which is also supported by the server is going to be used
	// to establish a connection. If no preference is provided the server ordering will be used.
	// If there's no overlap in supported Transport Factory will return an error on Client
	// creation attempt.
	PreferredTransports []a2a.TransportProtocol
	// Whether client prefers to poll for task updates instead of blocking until a terminal state is reached.
	// If set to true, non-streaming send message result might be a Message or a Task in any (including non-terminal) state.
	// Callers are responsible for running the polling loop. This configuration does not apply to streaming requests.
	Polling bool
}

Config exposes options for customizing Client behavior.

type CredentialsService

type CredentialsService interface {
	Get(ctx context.Context, sid SessionID, scheme a2a.SecuritySchemeName) (AuthCredential, error)
}

CredentialsService is used by AuthInterceptor for resolving credentials.

type Factory

type Factory struct {
	// contains filtered or unexported fields
}

Factory provides an API for creating a Client compatible with requested transports. Factory is immutable, but the configuration can be extended using WithAdditionalOptions call.

func NewFactory

func NewFactory(options ...FactoryOption) *Factory

NewFactory creates a new Factory applying the provided configurations.

func WithAdditionalOptions

func WithAdditionalOptions(f *Factory, opts ...FactoryOption) *Factory

WithAdditionalOptions creates a new Factory with the additionally provided options.

func (*Factory) CreateFromCard

func (f *Factory) CreateFromCard(ctx context.Context, card *a2a.AgentCard) (*Client, error)

CreateFromCard returns a Client configured to communicate with the agent described by the provided a2a.AgentCard or fails if we couldn't establish a compatible transport. Config.PreferredTransports field is used to determine the order of connection attempts.

If PreferredTransports were not provided, we start from the PreferredTransport specified in the AgentCard and proceed in the order specified by the AdditionalInterfaces.

The method fails if we couldn't establish a compatible transport.

func (*Factory) CreateFromEndpoints

func (f *Factory) CreateFromEndpoints(ctx context.Context, endpoints []a2a.AgentInterface) (*Client, error)

CreateFromEndpoints returns a Client configured to communicate with one of the provided endpoints. Config.PreferredTransports field is used to determine the order of connection attempts.

If PreferredTransports were not provided, we attempt to establish a connection using the provided endpoint order.

The method fails if we couldn't establish a compatible transport.

type FactoryOption

type FactoryOption interface {
	// contains filtered or unexported methods
}

FactoryOption represents a configuration for creating a Client.

func WithConfig

func WithConfig(c Config) FactoryOption

WithConfig configures Client with the provided Config.

func WithDefaultsDisabled

func WithDefaultsDisabled() FactoryOption

WithDefaultsDisabled attaches call interceptors to clients created by the factory.

func WithGRPCTransport

func WithGRPCTransport(opts ...grpc.DialOption) FactoryOption

WithGRPCTransport create a gRPC transport implementation which will use the provided [grpc.DialOption]s during connection establishment.

func WithInterceptors

func WithInterceptors(interceptors ...CallInterceptor) FactoryOption

WithInterceptors attaches call interceptors to created [Client]s.

func WithJSONRPCTransport

func WithJSONRPCTransport(client *http.Client) FactoryOption

WithJSONRPCTransport returns a Client factory option that enables JSON-RPC transport support. When applied, the client will use JSON-RPC 2.0 over HTTP for all A2A protocol communication as defined in the A2A specification §7.

func WithTransport

func WithTransport(protocol a2a.TransportProtocol, factory TransportFactory) FactoryOption

WithTransport uses the provided factory during connection establishment for the specified protocol.

type InMemoryCredentialsStore

type InMemoryCredentialsStore struct {
	// contains filtered or unexported fields
}

InMemoryCredentialsStore implements CredentialsService.

func NewInMemoryCredentialsStore

func NewInMemoryCredentialsStore() *InMemoryCredentialsStore

NewInMemoryCredentialsStore initializes an in-memory implementation of CredentialsService.

func (*InMemoryCredentialsStore) Get

func (*InMemoryCredentialsStore) Set

type JSONRPCOption

type JSONRPCOption func(*jsonrpcTransport)

JSONRPCOption configures optional parameters for the JSONRPC transport. Options are applied during NewJSONRPCTransport initialization.

type PassthroughInterceptor

type PassthroughInterceptor struct{}

PassthroughInterceptor can be used by CallInterceptor implementers who don't need all methods. The struct can be embedded for providing a no-op implementation.

func (PassthroughInterceptor) After

func (PassthroughInterceptor) Before

type Request

type Request struct {
	// Method is the name of the method invoked on the A2A-server.
	Method string
	// BaseURL is the URL of the agent interface to which the Client is connected.
	BaseURL string
	// CallMeta holds request metadata like auth headers and signatures.
	Meta CallMeta
	// Card is the AgentCard of the agent the client is connected to. Might be nil if Client was
	// created directly from server URL and extended AgentCard was never fetched.
	Card *a2a.AgentCard
	// Payload is the request payload. It is nil if the method does not take any parameters. Otherwise, it is one of a2a package core types otherwise.
	Payload any
}

Request represents a transport-agnostic request to be sent to A2A server.

type Response

type Response struct {
	// Method is the name of the method invoked on the A2A-server.
	Method string
	// BaseURL is the URL of the agent interface to which the Client is connected.
	BaseURL string
	// Err is the error response. It is nil for successful invocations.
	Err error
	// CallMeta holds request metadata like auth headers and signatures.
	Meta CallMeta
	// Card is the AgentCard of the agent the client is connected to. Might be nil if Client was
	// created directly from server URL and extended AgentCard was never fetched.
	Card *a2a.AgentCard
	// Payload is the response. It is nil if method doesn't return anything or Err was returned. Otherwise, it is one of a2a package core types otherwise.
	Payload any
}

Response represents a transport-agnostic result received from A2A server.

type SessionCredentials

type SessionCredentials map[a2a.SecuritySchemeName]AuthCredential

SessionCredentials is a map of scheme names to auth credentials.

type SessionID

type SessionID string

SessionID is a client-generated identifier used for scoping auth credentials.

func SessionIDFrom

func SessionIDFrom(ctx context.Context) (SessionID, bool)

SessionIDFrom allows to get a previously attached session identifier from Context.

type Transport

type Transport interface {
	// GetTask calls the 'tasks/get' protocol method.
	GetTask(ctx context.Context, query *a2a.TaskQueryParams) (*a2a.Task, error)

	// CancelTask calls the 'tasks/cancel' protocol method.
	CancelTask(ctx context.Context, id *a2a.TaskIDParams) (*a2a.Task, error)

	// SendMessage calls the 'message/send' protocol method (non-streaming).
	SendMessage(ctx context.Context, message *a2a.MessageSendParams) (a2a.SendMessageResult, error)

	// ResubscribeToTask calls the `tasks/resubscribe` protocol method.
	ResubscribeToTask(ctx context.Context, id *a2a.TaskIDParams) iter.Seq2[a2a.Event, error]

	// SendStreamingMessage calls the 'message/stream' protocol method (streaming).
	SendStreamingMessage(ctx context.Context, message *a2a.MessageSendParams) iter.Seq2[a2a.Event, error]

	// GetTaskPushNotificationConfig calls the `tasks/pushNotificationConfig/get` protocol method.
	GetTaskPushConfig(ctx context.Context, params *a2a.GetTaskPushConfigParams) (*a2a.TaskPushConfig, error)

	// ListTaskPushNotificationConfig calls the `tasks/pushNotificationConfig/list` protocol method.
	ListTaskPushConfig(ctx context.Context, params *a2a.ListTaskPushConfigParams) ([]*a2a.TaskPushConfig, error)

	// SetTaskPushConfig calls the `tasks/pushNotificationConfig/set` protocol method.
	SetTaskPushConfig(ctx context.Context, params *a2a.TaskPushConfig) (*a2a.TaskPushConfig, error)

	// DeleteTaskPushNotificationConfig calls the `tasks/pushNotificationConfig/delete` protocol method.
	DeleteTaskPushConfig(ctx context.Context, params *a2a.DeleteTaskPushConfigParams) error

	// GetAgentCard resolves the AgentCard.
	// If extended card is supported calls the 'agent/getAuthenticatedExtendedCard' protocol method.
	GetAgentCard(ctx context.Context) (*a2a.AgentCard, error)

	// Clean up resources associated with the transport (eg. close a gRPC channel).
	Destroy() error
}

A2AClient defines a transport-agnostic interface for making A2A requests. Transport implementations are a translation layer between a2a core types and wire formats.

func NewGRPCTransport

func NewGRPCTransport(conn *grpc.ClientConn) Transport

NewGRPCTransport exposes a method for direct A2A gRPC protocol handler.

func NewGRPCTransportFromClient added in v0.3.3

func NewGRPCTransportFromClient(client a2apb.A2AServiceClient) Transport

NewGRPCTransportFromClient creates a gRPC transport where the connection is managed externally and encapsulated in the service client. The transport's Destroy method is a no-op.

func NewJSONRPCTransport

func NewJSONRPCTransport(url string, client *http.Client) Transport

NewJSONRPCTransport creates a new JSON-RPC transport for A2A protocol communication. By default, an HTTP client will use a 3-minute timeout. For production deployments, provide a client with appropriate timeout, retry policy, and connection pooling configured for your requirements.

To create an A2A client with custom HTTP client use WithJSONRPCTransport option:

httpClient := &http.Client{Timeout: 5 * time.Minute}
client := NewFromCard(ctx, card, WithJSONRPCTransport(httpClient))

type TransportFactory

type TransportFactory interface {
	Create(ctx context.Context, url string, card *a2a.AgentCard) (Transport, error)
}

TransportFactory creates an A2A protocol connection to the provided URL.

type TransportFactoryFn

type TransportFactoryFn func(ctx context.Context, url string, card *a2a.AgentCard) (Transport, error)

TransportFactoryFn implements TransportFactory.

func (TransportFactoryFn) Create

func (fn TransportFactoryFn) Create(ctx context.Context, url string, card *a2a.AgentCard) (Transport, error)

Directories

Path Synopsis
Package agentcard provides utilities for fetching public a2a.AgentCard.
Package agentcard provides utilities for fetching public a2a.AgentCard.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL