Skip to content
Build
BuildCoordination

Service Discovery

Find agents, reasoners, and skills at runtime through the control plane discovery API, and publish selected capabilities through ARD when they need to be discoverable outside the deployment.

Runtime service discovery — agents find each other

Find every agent, reasoner, and skill in your fleet -- at runtime, not at deploy time.

Hard-coded service addresses break the moment you scale past a handful of agents. AgentField's discovery API lets any agent query the control plane for live capabilities, filtered by tags, health status, or name patterns. Build orchestrators that discover what is available, introspect input schemas, and dynamically decide which agents to call -- all without a single hardcoded address.

For capabilities that should be discoverable outside this control plane, AgentField also supports external agent discovery through Agentic Resource Discovery (ARD). Treat it as the outside-network extension of this model: AgentField-to-AgentField communication stays simple through app.call("node.function"); ARD decides what selected capabilities other systems can find, import, and possibly call after explicit approval.

@app.reasoner(tags=["orchestrator"])
async def dynamic_router(question: str) -> dict:
    # 1. Discover active agents with input schemas — zero hardcoded addresses
    caps = app.discover(
        tags=["public"],
        health_status="active",
        include_input_schema=True,
        format="json",
    )
    print(f"{caps.json.total_agents} agents online, {len(caps.json.capabilities)} capabilities")

    # 2. Feed discovered capabilities + schemas into an LLM — it picks the best agent
    result = await app.ai(
        system=(
            "You are a routing agent. Pick the best tool for the user's question.\n"
            "Available capabilities:\n" + caps.raw
        ),
        user=question,
        tools="discover",  # built-in: turns discovered capabilities into callable tools
    )

    # 3. The LLM chose an agent and called it — no static routing table needed
    return result

# New agents register at startup → the router discovers them automatically.
# No config changes, no redeployment, no service mesh.
agent.reasoner('dynamicRouter', async (ctx) => {
  // 1. Discover active agents with input schemas — zero hardcoded addresses
  const caps = await agent.discover({
    tags: ['public'],
    healthStatus: 'active',
    includeInputSchema: true,
    format: 'json',
  });
  console.log(`${caps.json?.totalAgents} agents online`);

  // 2. Feed discovered capabilities + schemas into an LLM — it picks the best agent
  const result = await ctx.ai(ctx.input.question, {
    system: `You are a routing agent. Pick the best tool.\nAvailable:\n${caps.raw}`,
  });

  // 3. The LLM chose an agent and called it — no static routing table needed
  return result;
});

// New agents register at startup → the router discovers them automatically.
a.RegisterReasoner("dynamic_router", func(ctx context.Context, input map[string]any) (any, error) {
    // 1. Discover active agents with input schemas — zero hardcoded addresses
    caps, err := a.Discover(ctx,
        agent.WithTags([]string{"public"}),
        agent.WithHealthStatus("active"),
        agent.WithDiscoveryInputSchema(true),
        agent.WithFormat("json"),
    )
    if err != nil {
        return nil, err
    }
    fmt.Printf("%d agents online, %d capabilities\n",
        caps.JSON.TotalAgents, len(caps.JSON.Capabilities))

    // 2. Use compact format in LLM context for dynamic tool selection
    // 3. Route to the best agent based on discovered capabilities
    return map[string]any{
        "available_agents": caps.JSON.TotalAgents,
        "capabilities":     caps.JSON.Capabilities,
    }, nil
})

// New agents register at startup → the router discovers them automatically.

What just happened

  • The agent queried the live control plane registry instead of relying on hardcoded targets
  • Discovery results included enough metadata to drive dynamic routing decisions
  • New active agents could appear in routing immediately after registration

Internal discovery vs ARD

SurfaceScopePrimary use
app.call("node.function")Inside one AgentField control planeMake inter-agent communication feel like a native backend call, with routing and execution context handled by AgentField.
app.discover() / /api/v1/discovery/capabilitiesInside one AgentField control planeRoute to healthy local agents, reasoners, and skills.
/.well-known/ai-catalog.jsonPublic catalog for selected entriesLet external agents, registries, and partner systems discover published capabilities.
/api/v1/ard/searchPublic ARD registry search when enabledLet an outside client search your published catalog.
Discovery -> ImportsYour control planeRecord external ARD entries without making them callable yet.
external.* callable bindingYour control planeRoute app.call() to an imported external resource after approval.

The important product boundary: global ARD enablement does not publish or invoke anything by itself. Publishing is per reasoner or skill; external invocation is per imported binding.

Example discovery summary:

{
  "discovered_at": "2026-03-23T12:00:00Z",
  "total_agents": 2,
  "total_reasoners": 2,
  "total_skills": 0,
  "pagination": { "limit": 100, "offset": 0, "has_more": false },
  "capabilities": [
    {
      "agent_id": "weather-agent",
      "base_url": "http://weather-agent:9000",
      "version": "1.0.0",
      "health_status": "active",
      "deployment_type": "sidecar",
      "last_heartbeat": "2026-03-23T12:00:00Z",
      "reasoners": [
        { "id": "forecast", "tags": ["public", "weather"], "invocation_target": "weather-agent:forecast" }
      ],
      "skills": []
    },
    {
      "agent_id": "translator",
      "base_url": "http://translator:9000",
      "version": "1.0.0",
      "health_status": "active",
      "deployment_type": "sidecar",
      "last_heartbeat": "2026-03-23T12:00:00Z",
      "reasoners": [
        { "id": "translate", "tags": ["public", "translation"], "invocation_target": "translator:translate" }
      ],
      "skills": []
    }
  ]
}