Skip to content

feat(core): build the A2A handler in core instead of exposing it to extensions - #2578

Draft
jjamroga wants to merge 1 commit into
kagent-dev:mainfrom
jjamroga:core-builds-a2a-handler
Draft

feat(core): build the A2A handler in core instead of exposing it to extensions#2578
jjamroga wants to merge 1 commit into
kagent-dev:mainfrom
jjamroga:core-builds-a2a-handler

Conversation

@jjamroga

Copy link
Copy Markdown
Collaborator

The A2A gateway should not be injectable. It is a core component, not a policy
decision, and the only parts of it an extension should influence are the ones it
already supplies through pluggable interfaces: Authenticator and Authorizer.

Today ExtensionConfig.A2AHandler inverts that — the one gRPC service that reaches
agent runtimes gets whatever auth the embedder assembles for it, separately from the
authenticator and authorizer it hands core for every other method. Everything
a2agateway.New needs is already in scope in Start, so build it there and drop the
field.

Existing deployments are unaffected. build-controller builds controller-v2, which
sets A2AHandler on grpcserver.Config directly and never reads ExtensionConfig,
and the config that drives the gateway — A2A_GATEWAY_URL and
controller.a2aGatewayUrl — is unchanged. Only embedders of app.Start need a code
change.

Breaking changes

  • ExtensionConfig.A2AHandler removed — core builds the handler from the
    authenticator and authorizer embedders already supply.
  • -a2a-base-url-a2a-gateway-url — different endpoints. a2a-base-url named
    the HTTP server on :8083 and has been dead config since chore: remove legacy ACP and controller runtime #2565; the gateway URL is
    published in agent cards as the agent's gRPC interface and must address :8084.
    The new flag matches the A2A_GATEWAY_URL env var and controller.a2aGatewayUrl
    chart value already in use, so deployments need no change.
  • -substrate-atenet-router-url defaults to DefaultAtenetRouterURL instead of
    "", which never meant "substrate absent". NewRuntimeDialer rejects an empty value
    at startup.

A stale A2A_BASE_URL env var is silently ignored, but a stale -a2a-base-url
argument is a hard startup failure, since flag rejects unknown flags. The chart
configures by env, not args.

Testing

go build, go vet, go test clean. Chart suite 268/272 — the 4 failures are
kagent-tools subchart tests that fail identically on a clean checkout. Verified end to
end in kind with Substrate against a downstream embedder of app.Start:
CreateAgentInstance, SendMessage, DeleteAgentInstance all OK, agent reached
through the gateway and atenet router, no auth errors.

🤖 Generated with Claude Code

@github-actions github-actions Bot added the enhancement New feature or request label Aug 26, 2026
…xtensions

The A2A gateway should not be injectable. It is a core component, not a
policy decision, and the only parts of it an extension should influence are
the ones it already supplies through pluggable interfaces: Authenticator and
Authorizer.

ExtensionConfig.A2AHandler inverts that: the one gRPC service that reaches
agent runtimes gets whatever auth the embedder assembles for it, separately
from the authenticator and authorizer it hands core for every other method.
Every input a2agateway.New needs is already in scope in Start -- the db
client, the instance workflow, the gateway URL, and the extension's own
authenticator and authorizer -- so build the handler here and drop the field.

Replaces -a2a-base-url with -a2a-gateway-url. The two described different
endpoints: a2a-base-url named the HTTP A2A server on :8083 and has been
dead config since kagent-dev#2565 removed the legacy ACP runtime, while the gateway
URL is published in agent cards as the agent's gRPC interface and so must
address the gRPC listener on :8084. The flag now matches the
A2A_GATEWAY_URL env var and controller.a2aGatewayUrl chart value that
core/cmd/controller-v2 and the chart already carry, and the dead
a2aBaseUrl value, helper and configmap key are removed.

Substrate is a required component. Start already dials ate-api
unconditionally and exits when that fails, so -substrate-atenet-router-url
now carries DefaultAtenetRouterURL as its actual default rather than
treating "" as a sentinel meaning "use the default". An empty value is
rejected where it is used: NewRuntimeDialer returns "atenet router URL
must include a host", which is fatal at startup.

Existing deployments are unaffected. build-controller builds
core/cmd/controller-v2, which sets A2AHandler on grpcserver.Config directly
and never reads ExtensionConfig, and the config that drives the gateway is
unchanged. Only embedders of app.Start need a code change.

Signed-off-by: Jonathan Jamroga <jjamroga@gmail.com>
@jjamroga
jjamroga force-pushed the core-builds-a2a-handler branch from af343c5 to 87f7fae Compare August 26, 2026 16:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant