Skip to content

feat(agent): allow declarative agents to call agents in other clusters#2130

Draft
tjorourke wants to merge 1 commit into
kagent-dev:mainfrom
tjorourke:fix/1853-cross-cluster-declarative-a2a
Draft

feat(agent): allow declarative agents to call agents in other clusters#2130
tjorourke wants to merge 1 commit into
kagent-dev:mainfrom
tjorourke:fix/1853-cross-cluster-declarative-a2a

Conversation

@tjorourke

@tjorourke tjorourke commented Jul 1, 2026

Copy link
Copy Markdown

What this fixes

Cross-cluster agent-to-agent (A2A) already works for BYO agents — the BYO container makes the A2A call to the remote agent itself, so nothing is resolved. It does not work for declarative agents.

A declarative agent-as-tool (tools[].type: Agent) is resolved by the controller with a lookup in its own cluster's API. An agent in another cluster isn't there, so the referencing agent never starts:

Agent.kagent.dev "remote-agent" not found

Tracking issue: solo-io/kagent-enterprise#1853 (Telefonica).

The fix

Let an Agent tool reference carry an optional url (and description). When a url is set, the agent calls that remote A2A endpoint directly — e.g. an agent in another cluster reached over an east-west gateway — instead of resolving a local Agent CR. Declarative agents get the same cross-cluster reach BYO already has. Name-based references are unchanged.

tools:
  - type: Agent
    agent:
      name: remote-agent
      url: http://remote-agent.kagent.svc.cluster.local:8080   # remote A2A endpoint
      description: Remote specialist in the peer cluster

Under the hood this reuses the exact RemoteAgentConfig the local path already builds (Url = toolAgentURL(agent)); it just lets you supply the URL instead of deriving it from a local CR.

Backward compatibility

Purely additive — safe:

  • url/description are optional; nothing removed, renamed, or retyped; name stays required.
  • Applying the new CRD is a schema widening — existing name-based Agent objects validate and behave identically. No storage-version change.
  • CRD + controller should ship together: old CRD + new controller ⇒ url is pruned and the feature no-ops (no break); new CRD + old controller ⇒ url stored but ignored. Neither breaks existing agents.

Files

  • go/api/v1alpha2/agent_types.gourl/description on TypedReference
  • go/core/internal/controller/translator/agent/compiler.go — URL fast-path at both resolution sites
  • go/core/internal/controller/translator/agent/remote_url_agent_tool_test.go — new unit test
  • CRDs regenerated with controller-gen (make manifests) + synced to the Helm chart (make controller-manifests)

Testing Proof

$ go test ./core/internal/controller/translator/agent/
ok  github.com/kagent-dev/kagent/go/core/internal/controller/translator/agent  0.237s

gofmt -l clean · go vet clean · deepcopy unchanged. A full end-to-end two-cluster (east↔west over an east-west gateway) live run is being captured and will be added here.

Live end-to-end proof — cross-cluster declarative A2A (patched OSS kagent v0.9.11)

Two kind clusters, Solo Istio ambient federation + east-west gateway, patched controller on both:

east controller image: docker.io/library/kagent-controller:fix1853
west controller image: docker.io/library/kagent-controller:fix1853

Declarative agents Ready on both clusters (west = remote specialist, east = orchestrator that references it cross-cluster via url):

# WEST
NAME           TYPE          RUNTIME   READY   ACCEPTED
remote-agent   Declarative   python    True    True
# EAST
NAME                  TYPE          RUNTIME   READY   ACCEPTED
orchestrator-remote   Declarative   python    True    True

The east orchestrator's cross-cluster tool reference (the new field):

{
    "agent": {
        "description": "Remote specialist in the WEST cluster (cross-cluster A2A)",
        "name": "remote-agent",
        "url": "http://remote-agent.kagent:8080"
    },
    "type": "Agent"
}

Accepted condition (was ReconcileFailed: Agent.kagent.dev "remote-agent" not found before the fix):

Accepted=True (Reconciled)
Ready=True (DeploymentReady)

Live A2A call — invoking the EAST orchestrator; it delegates over A2A to the WEST agent and returns its answer:

$ curl -s .../api/a2a/kagent/orchestrator-remote/ -d {message: "who and where are you?"}

**I am the remote-agent in the WEST cluster.**
I'm a remote specialist running in the WEST cluster, ready to assist you with tasks and questions from this location.

The reply comes from the WEST cluster's agent — proving a declarative EAST agent successfully used a declarative WEST agent over A2A across clusters.

What may be a better approach here (maybe another PR in future?)

The ideal long-term UX is the controller auto-deriving the federated URL from a name+cluster reference (so users don't hand-type it), but that needs the controller to know cross-cluster topology. The explicit url is the pragmatic MVP that works with any mesh/gateway today.

Checklist

  • Conventional commit + DCO sign-off
  • Unit tests + full translator package green
  • controller-gen codegen + Helm CRD sync
  • Backward compatible (additive optional fields)
  • Docs update on kagent.dev (separate repo)
  • End-to-end live proof (in progress)

@github-actions github-actions Bot added the enhancement New feature or request label Jul 1, 2026
@tjorourke tjorourke changed the title feat(agent): support cross-cluster A2A via remote agent tool URL feat(agent): allow declarative agents to call agents in other clusters Jul 1, 2026
@tjorourke tjorourke force-pushed the fix/1853-cross-cluster-declarative-a2a branch from 4a4a1a1 to bf7ff59 Compare July 1, 2026 15:40
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Jul 1, 2026
Cross-cluster agent-to-agent (A2A) already works for BYO agents: the BYO
container makes the A2A call to the remote agent itself, so nothing needs to be
resolved. It does NOT work for declarative agents.

A declarative agent-as-tool (tools[].type: Agent) is resolved by the controller
with a lookup in its OWN cluster's API. An agent in another cluster isn't there,
so the referencing agent never starts:

    Agent.kagent.dev "remote-agent" not found

Fix: let an Agent tool reference carry an optional `url` (and `description`).
When a url is set, the agent calls that remote A2A endpoint directly — e.g. an
agent in another cluster reached over an east-west gateway — instead of
resolving a local Agent CR. This gives declarative agents the same cross-cluster
reach BYO already has. Name-based references are unchanged.

    tools:
      - type: Agent
        agent:
          name: remote-agent
          url: http://remote-agent.kagent.svc.cluster.local:8080

Fixes: solo-io/kagent-enterprise#1853
Signed-off-by: Thomas O'Rourke <tom.orourke@solo.io>
@tjorourke tjorourke force-pushed the fix/1853-cross-cluster-declarative-a2a branch from bf7ff59 to 0ac7433 Compare July 1, 2026 15:44
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Jul 1, 2026
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