a2aclient

package
v1.0.0-alpha Latest Latest
Warning

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

Go to latest
Published: Feb 23, 2026 License: Apache-2.0 Imports: 23 Imported by: 19

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{...}),
	WithCallInterceptors(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, WithCallInterceptors(&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 := WithCallInterceptors(&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 AttachServiceParams

func AttachServiceParams(ctx context.Context, params ServiceParams) context.Context

AttachServiceParams creates a new context with service parameters attached to it. These parameters will be passed to the Transport, where implementation is responsible for serializing them according to the protocol binding. CallInterceptor-s will be able to modify params before they are passed to the Transport.

func AttachSessionID

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

AttachSessionID 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 AttachSessionID 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, any, error)

Before implements the CallInterceptor interface. It retrieves credentials for the current session and security requirements, and attaches the appropriate authorization parameters (e.g. Bearer token or API Key) to the request's ServiceParams.

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.
	// If either the result (2nd return value) or the error (3rd return value) is non nil,
	// the network request will not be made and the value will be returned to the caller.
	Before(ctx context.Context, req *Request) (context.Context, any, error)

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

CallInterceptor can be attached to a 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 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, req *a2a.CancelTaskRequest) (*a2a.Task, error)

CancelTask implements the 'CancelTask' protocol method.

func (*Client) CreateTaskPushConfig

func (c *Client) CreateTaskPushConfig(ctx context.Context, req *a2a.CreateTaskPushConfigRequest) (*a2a.TaskPushConfig, error)

CreateTaskPushConfig implements the `CreateTaskPushNotificationConfig` protocol method.

func (*Client) DeleteTaskPushConfig

func (c *Client) DeleteTaskPushConfig(ctx context.Context, req *a2a.DeleteTaskPushConfigRequest) error

DeleteTaskPushConfig implements the `DeleteTaskPushNotificationConfig` protocol method.

func (*Client) Destroy

func (c *Client) Destroy() error

Destroy cleans up resources associated with the client.

func (*Client) GetExtendedAgentCard

func (c *Client) GetExtendedAgentCard(ctx context.Context, req *a2a.GetExtendedAgentCardRequest) (*a2a.AgentCard, error)

GetExtendedAgentCard implements the `GetExtendedAgentCard` protocol method.

func (*Client) GetTask

func (c *Client) GetTask(ctx context.Context, req *a2a.GetTaskRequest) (*a2a.Task, error)

GetTask implements the 'GetTask' protocol method.

func (*Client) GetTaskPushConfig

func (c *Client) GetTaskPushConfig(ctx context.Context, req *a2a.GetTaskPushConfigRequest) (*a2a.TaskPushConfig, error)

GetTaskPushConfig implements the `GetTaskPushNotificationConfig` protocol method.

func (*Client) ListTaskPushConfigs

func (c *Client) ListTaskPushConfigs(ctx context.Context, req *a2a.ListTaskPushConfigRequest) ([]*a2a.TaskPushConfig, error)

ListTaskPushConfigs implements the `ListTaskPushNotificationConfig` protocol method.

func (*Client) ListTasks added in v0.3.7

func (c *Client) ListTasks(ctx context.Context, req *a2a.ListTasksRequest) (*a2a.ListTasksResponse, error)

ListTasks implements the 'ListTasks' protocol method.

func (*Client) SendMessage

func (c *Client) SendMessage(ctx context.Context, req *a2a.SendMessageRequest) (a2a.SendMessageResult, error)

SendMessage implements the 'SendMessage' protocol method (non-streaming).

func (*Client) SendStreamingMessage

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

SendStreamingMessage implements the 'SendStreamingMessage' protocol method (streaming).

func (*Client) SubscribeToTask

func (c *Client) SubscribeToTask(ctx context.Context, req *a2a.SubscribeToTaskRequest) iter.Seq2[a2a.Event, error]

SubscribeToTask implements the `SubscribeToTask` protocol method.

func (*Client) UpdateCard

func (c *Client) UpdateCard(card *a2a.AgentCard) error

UpdateCard updates the agent card used by the client.

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 retrieves the credential for the given session ID and security scheme name.
	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 WithCallInterceptors

func WithCallInterceptors(interceptors ...CallInterceptor) FactoryOption

WithCallInterceptors attaches call interceptors to created [Client]s.

func WithCompatTransport

func WithCompatTransport(version a2a.ProtocolVersion, protocol a2a.TransportProtocol, factory TransportFactory) FactoryOption

WithCompatTransport uses the provided factory during connection establishment for the specified transport binding and protocol version.

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 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 WithRESTTransport

func WithRESTTransport(client *http.Client) FactoryOption

WithRESTTransport returns a Client factory option that enables REST transport support.

func WithTransport

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

WithTransport uses the provided factory during connection establishment for the specified transport binding.

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

Get retrieves the credential for the given session ID and security scheme name.

func (*InMemoryCredentialsStore) Set

Set stores the credential for the given session ID and security scheme name.

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

After implements the CallInterceptor.

func (PassthroughInterceptor) Before

Before implements the CallInterceptor.

type RESTTransport

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

RESTTransport implemetns Transport using RESTful HTTP API.

func (*RESTTransport) CancelTask

func (t *RESTTransport) CancelTask(ctx context.Context, params ServiceParams, req *a2a.CancelTaskRequest) (*a2a.Task, error)

CancelTask implements a2a.Transport.

func (*RESTTransport) CreateTaskPushConfig

func (t *RESTTransport) CreateTaskPushConfig(ctx context.Context, params ServiceParams, req *a2a.CreateTaskPushConfigRequest) (*a2a.TaskPushConfig, error)

CreateTaskPushConfig implements a2a.Transport.

func (*RESTTransport) DeleteTaskPushConfig

func (t *RESTTransport) DeleteTaskPushConfig(ctx context.Context, params ServiceParams, req *a2a.DeleteTaskPushConfigRequest) error

DeleteTaskPushConfig implements a2a.Transport.

func (*RESTTransport) Destroy

func (t *RESTTransport) Destroy() error

Destroy implements a2a.Transport.

func (*RESTTransport) GetExtendedAgentCard

func (t *RESTTransport) GetExtendedAgentCard(ctx context.Context, params ServiceParams, req *a2a.GetExtendedAgentCardRequest) (*a2a.AgentCard, error)

GetExtendedAgentCard implements a2a.Transport.

func (*RESTTransport) GetTask

func (t *RESTTransport) GetTask(ctx context.Context, params ServiceParams, req *a2a.GetTaskRequest) (*a2a.Task, error)

GetTask implements a2a.Transport.

func (*RESTTransport) GetTaskPushConfig

func (t *RESTTransport) GetTaskPushConfig(ctx context.Context, params ServiceParams, req *a2a.GetTaskPushConfigRequest) (*a2a.TaskPushConfig, error)

GetTaskPushConfig implements a2a.Transport.

func (*RESTTransport) ListTaskPushConfigs

func (t *RESTTransport) ListTaskPushConfigs(ctx context.Context, params ServiceParams, req *a2a.ListTaskPushConfigRequest) ([]*a2a.TaskPushConfig, error)

ListTaskPushConfigs implements a2a.Transport.

func (*RESTTransport) ListTasks

ListTasks implements a2a.Transport.

func (*RESTTransport) SendMessage

SendMessage implements a2a.Transport.

func (*RESTTransport) SendStreamingMessage

func (t *RESTTransport) SendStreamingMessage(ctx context.Context, params ServiceParams, req *a2a.SendMessageRequest) iter.Seq2[a2a.Event, error]

SendStreamingMessage implements a2a.Transport.

func (*RESTTransport) SubscribeToTask

func (t *RESTTransport) SubscribeToTask(ctx context.Context, params ServiceParams, req *a2a.SubscribeToTaskRequest) iter.Seq2[a2a.Event, error]

SubscribeToTask implements a2a.Transport.

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
	// ServiceParams holds horizontally applicable context or parameters with case-insensitive keys.
	// The transmission mechanism for these service parameter key-value pairs is defined by the specific protocol binding
	ServiceParams ServiceParams
	// 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
	// ServiceParams holds horizontally applicable context or parameters with case-insensitive keys.
	// The transmission mechanism for these service parameter key-value pairs is defined by the specific protocol binding
	ServiceParams ServiceParams
	// 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 ServiceParams

type ServiceParams map[string][]string

ServiceParams holds horizontally applicable context or parameters with case-insensitive keys. The transmission mechanism for these service parameter key-value pairs is defined by the specific protocol binding. In jsonrpc it is passed as HTTP headers, in gRPC it becomes a part of context.Context. Custom protocol implementations can use ServiceParams to access this data and perform the operations necessary for attaching it to the request.

func (ServiceParams) Append

func (m ServiceParams) Append(key string, vals ...string)

Append appends the provided values to the list of values associated with the key. Duplicates values will not be added. Key matching is case-insensitive.

func (ServiceParams) Get

func (m ServiceParams) Get(key string) []string

Get performs case-insensitive lookup or the provided key. Returns nil if value is not present.

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 'GetTask' protocol method.
	GetTask(context.Context, ServiceParams, *a2a.GetTaskRequest) (*a2a.Task, error)

	// ListTasks calls the 'ListTasks' protocol method.
	ListTasks(context.Context, ServiceParams, *a2a.ListTasksRequest) (*a2a.ListTasksResponse, error)

	// CancelTask calls the 'CancelTask' protocol method.
	CancelTask(context.Context, ServiceParams, *a2a.CancelTaskRequest) (*a2a.Task, error)

	// SendMessage calls the 'SendMessage' protocol method (non-streaming).
	SendMessage(context.Context, ServiceParams, *a2a.SendMessageRequest) (a2a.SendMessageResult, error)

	// SubscribeToTask calls the `SubscribeToTask` protocol method.
	SubscribeToTask(context.Context, ServiceParams, *a2a.SubscribeToTaskRequest) iter.Seq2[a2a.Event, error]

	// SendStreamingMessage calls the 'SendStreamingMessage' protocol method (streaming).
	SendStreamingMessage(context.Context, ServiceParams, *a2a.SendMessageRequest) iter.Seq2[a2a.Event, error]

	// GetTaskPushConfig calls the `GetTaskPushNotificationConfig` protocol method.
	GetTaskPushConfig(context.Context, ServiceParams, *a2a.GetTaskPushConfigRequest) (*a2a.TaskPushConfig, error)

	// ListTaskPushConfigs calls the `ListTaskPushNotificationConfig` protocol method.
	ListTaskPushConfigs(context.Context, ServiceParams, *a2a.ListTaskPushConfigRequest) ([]*a2a.TaskPushConfig, error)

	// CreateTaskPushConfig calls the `CreateTaskPushNotificationConfig` protocol method.
	CreateTaskPushConfig(context.Context, ServiceParams, *a2a.CreateTaskPushConfigRequest) (*a2a.TaskPushConfig, error)

	// DeleteTaskPushConfig calls the `DeleteTaskPushNotificationConfig` protocol method.
	DeleteTaskPushConfig(context.Context, ServiceParams, *a2a.DeleteTaskPushConfigRequest) error

	// GetExtendedAgentCard calls the 'GetExtendedAgentCard' protocol method.
	GetExtendedAgentCard(context.Context, ServiceParams, *a2a.GetExtendedAgentCardRequest) (*a2a.AgentCard, error)

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

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

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))

func NewRESTTransport

func NewRESTTransport(tURL string, client *http.Client) Transport

NewRESTTransport creates a new REST Transport for A2A protocol and communication By default, an HTTP client with 5-second timeout is used. For production deployments, provide a client with appropriate timeout, retry policy, and connection pooling configured for your requirements.

type TransportFactory

type TransportFactory interface {
	// Create creates an A2A protocol connection to the provided URL.
	Create(ctx context.Context, card *a2a.AgentCard, iface *a2a.AgentInterface) (Transport, error)
}

TransportFactory creates an A2A protocol connection to the provided URL.

type TransportFactoryFn

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

TransportFactoryFn implements TransportFactory.

func (TransportFactoryFn) Create

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

Create implements TransportFactory interface.

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