Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.3.6"
".": "0.3.7"
}
17 changes: 15 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
# Changelog

<<<<<<< HEAD
=======
## [0.3.7](https://github.com/a2aproject/a2a-go/compare/v0.3.6...v0.3.7) (2026-02-20)


### Features

* implement tasks/list RPC ([#210](https://github.com/a2aproject/a2a-go/issues/210)) ([6e04698](https://github.com/a2aproject/a2a-go/commit/6e04698e63d4cb7d67a2aed700babd9bd6664b51))
* retry cancelations ([#222](https://github.com/a2aproject/a2a-go/issues/222)) ([3057474](https://github.com/a2aproject/a2a-go/commit/30574743207ae68a96588fc81926ad7de3d9887e))


### Bug Fixes

* handle internal error: tck failure ([#186](https://github.com/a2aproject/a2a-go/issues/186)) ([b55fbfd](https://github.com/a2aproject/a2a-go/commit/b55fbfd6417fb48a89dd838611f35a6899d17e12))
* **sse:** support data: prefix without space ([#188](https://github.com/a2aproject/a2a-go/issues/188)) ([6657a6d](https://github.com/a2aproject/a2a-go/commit/6657a6dc3b6872d425f03d6f340b7c1a82c55810)), closes [#162](https://github.com/a2aproject/a2a-go/issues/162)


## [0.3.6](https://github.com/a2aproject/a2a-go/compare/v0.3.5...v0.3.6) (2026-01-30)


Expand Down
3 changes: 3 additions & 0 deletions a2a/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ var (

// ErrUnauthorized indicates that the caller does not have permission to execute the specified operation.
ErrUnauthorized = errors.New("permission denied")

// ErrConcurrentTaskModification indicates that optimistic concurrency control failed during task update attempt.
ErrConcurrentTaskModification = errors.New("concurrent task modification")
)

// Error provides control over the message and details returned to clients.
Expand Down
3 changes: 1 addition & 2 deletions a2aclient/agentcard/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ A [Resolver] can be created with a custom [http.Client] or a package-level Defau
resolver := agentcard.NewResolver(customClient)
card, err := resolver.Resolve(ctx, baseURL)

By default the request is sent for a well-known card location, but custom
this can be configured by providing [ResolveOption]s.
By default the request is sent for a well-known card location, but this can be customized by providing [ResolveOption]s.

card, err := resolver.Resolve(
ctx,
Expand Down
2 changes: 1 addition & 1 deletion a2aclient/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ using either package-level functions or [Factory] methods.

// or

card, err := agentcard.DefaultResolved.Resolve(ctx, url)
card, err := agentcard.DefaultResolver.Resolve(ctx, url)
if err != nil {
log.Fatalf("Failed to resolve an AgentCard: %v", err)
}
Expand Down
5 changes: 5 additions & 0 deletions a2aclient/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ func createTransport(ctx context.Context, candidates []transportCandidate, card
if len(failures) > 0 {
log.Info(ctx, "some transports failed to connect", "failures", failures)
}

if selected.endpoint.Tenant != "" {
transport = &tenantTransportDecorator{base: transport, tenant: selected.endpoint.Tenant}
}

return transport, selected, nil
}

Expand Down
24 changes: 24 additions & 0 deletions a2aclient/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,27 @@ func TestFactory_TransportSelection(t *testing.T) {
})
}
}

func TestFactory_Tenant(t *testing.T) {
ctx := t.Context()
factory := NewFactory(WithTransport(a2a.TransportProtocolJSONRPC, TransportFactoryFn(func(ctx context.Context, card *a2a.AgentCard, iface *a2a.AgentInterface) (Transport, error) {
return unimplementedTransport{}, nil
})))
iface := a2a.NewAgentInterface("https://agent.com", a2a.TransportProtocolJSONRPC)
iface.Tenant = "my-tenant"

client, err := factory.CreateFromEndpoints(ctx, []*a2a.AgentInterface{iface})
if err != nil {
t.Fatalf("CreateFromEndpoints() error = %v, want nil", err)
}
decorator, ok := client.transport.(*tenantTransportDecorator)
if !ok {
t.Fatalf("client.transport type = %T, want *tenantTransportDecorator", client.transport)
}
if decorator.tenant != "my-tenant" {
t.Errorf("decorator.tenant = %q, want %q", decorator.tenant, "my-tenant")
}
if _, ok := decorator.base.(unimplementedTransport); !ok {
t.Errorf("decorator.base type = %T, want unimplementedTransport", decorator.base)
}
}
28 changes: 28 additions & 0 deletions a2aclient/jsonrpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -644,3 +644,31 @@ func TestJSONRPCTransport_ErrorDetails(t *testing.T) {
t.Errorf("got wrong details (+got,-want) diff = %s", diff)
}
}

func TestJSONRPCTransport_Tenant(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
req := mustDecodeJSONRPC(t, r, "ListTasks")
params, ok := req.Params.(map[string]any)
if !ok {
t.Fatalf("expected map[string]any params, got %T", req.Params)
}
if params["tenant"] != "my-tenant" {
t.Errorf("expected tenant my-tenant, got %v", params["tenant"])
}

resp := newResponse(req, json.RawMessage(`{"tasks":[]}`))
_ = json.NewEncoder(w).Encode(resp)
}))
defer server.Close()

iface := a2a.NewAgentInterface(server.URL, a2a.TransportProtocolJSONRPC)
iface.Tenant = "my-tenant"
transport := NewJSONRPCTransport(iface.URL, nil)
// Apply decorator manually as we are bypassing the factory
transport = &tenantTransportDecorator{base: transport, tenant: iface.Tenant}

_, err := transport.ListTasks(t.Context(), ServiceParams{}, &a2a.ListTasksRequest{})
if err != nil {
t.Fatalf("ListTasks failed: %v", err)
}
}
Loading