Agent Discovery

Discover available agent capabilities and schemas at runtime for dynamic orchestration

Agent Discovery

Discover available agent capabilities and schemas at runtime for dynamic orchestration

Discover available agents, reasoners, and skills at runtime with their input/output schemas. Perfect for building AI orchestrators that select tools dynamically, generate LLM tool catalogs, or implement intelligent routing based on available capabilities.

Quick Start

Discover all available capabilities:

curl http://localhost:8080/api/v1/discovery/capabilities

Response:

{
  "discovered_at": "2025-11-23T10:30:00Z",
  "total_agents": 5,
  "total_reasoners": 23,
  "total_skills": 45,
  "capabilities": [
    {
      "agent_id": "research-agent",
      "base_url": "http://research-agent:8080",
      "version": "2.3.1",
      "health_status": "active",
      "reasoners": [
        {
          "id": "deep_research",
          "description": "Performs comprehensive research using multiple sources",
          "tags": ["research", "ml", "synthesis"],
          "invocation_target": "research-agent.deep_research"
        }
      ],
      "skills": [
        {
          "id": "web_search",
          "description": "Search the web using multiple engines",
          "tags": ["web", "search"],
          "invocation_target": "research-agent.skill:web_search"
        }
      ]
    }
  ]
}

Endpoint

Wildcard Pattern Matching

Use wildcards to filter capabilities flexibly:

  • *abc* - Contains "abc" anywhere
  • abc* - Starts with "abc"
  • *abc - Ends with "abc"
  • abc - Exact match (no wildcards)

Examples:

# Find all research-related reasoners
curl 'http://localhost:8080/api/v1/discovery/capabilities?reasoner=*research*'

# Find reasoners starting with "deep_"
curl 'http://localhost:8080/api/v1/discovery/capabilities?reasoner=deep_*'

# Find ML-related capabilities
curl 'http://localhost:8080/api/v1/discovery/capabilities?tags=ml*'

# Find web skills
curl 'http://localhost:8080/api/v1/discovery/capabilities?skill=web_*'

Response Formats

JSON Format (Default)

Standard JSON response with full capability details:

curl 'http://localhost:8080/api/v1/discovery/capabilities?format=json'

XML Format

XML format optimized for LLM context injection:

curl 'http://localhost:8080/api/v1/discovery/capabilities?format=xml'
<?xml version="1.0" encoding="UTF-8"?>
<discovery discovered_at="2025-11-23T10:30:00Z">
  <summary total_agents="5" total_reasoners="23" total_skills="45"/>
  <capabilities>
    <agent id="research-agent" base_url="http://research-agent:8080">
      <reasoners>
        <reasoner id="deep_research" target="research-agent.deep_research">
          <description>Comprehensive research</description>
          <tags>
            <tag>research</tag>
            <tag>ml</tag>
          </tags>
        </reasoner>
      </reasoners>
    </agent>
  </capabilities>
</discovery>

Compact Format

Minimal response for bandwidth-constrained scenarios:

curl 'http://localhost:8080/api/v1/discovery/capabilities?format=compact'
{
  "discovered_at": "2025-11-23T10:30:00Z",
  "reasoners": [
    {
      "id": "deep_research",
      "agent_id": "research-agent",
      "target": "research-agent.deep_research",
      "tags": ["research", "ml"]
    }
  ],
  "skills": [
    {
      "id": "web_search",
      "agent_id": "research-agent",
      "target": "research-agent.skill:web_search",
      "tags": ["web", "search"]
    }
  ]
}

Examples

# Discover all capabilities with schemascurl 'http://localhost:8080/api/v1/discovery/capabilities?include_input_schema=true&include_output_schema=true'# Find research capabilities with ML tagscurl 'http://localhost:8080/api/v1/discovery/capabilities?reasoner=*research*&tags=ml,nlp'# Get compact format for specific agentcurl 'http://localhost:8080/api/v1/discovery/capabilities?agent=research-agent&format=compact'# XML format for LLM contextcurl 'http://localhost:8080/api/v1/discovery/capabilities?format=xml&include_descriptions=true'

Schema Discovery

Include input and output schemas to validate requests at runtime:

curl 'http://localhost:8080/api/v1/discovery/capabilities?agent=research-agent&include_input_schema=true&include_output_schema=true'

Response with schemas:

{
  "capabilities": [
    {
      "agent_id": "research-agent",
      "reasoners": [
        {
          "id": "deep_research",
          "description": "Comprehensive research using multiple sources",
          "tags": ["research", "ml"],
          "input_schema": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "Research query or topic"
              },
              "depth": {
                "type": "integer",
                "minimum": 1,
                "maximum": 5,
                "default": 3,
                "description": "Research depth level"
              }
            },
            "required": ["query"]
          },
          "output_schema": {
            "type": "object",
            "properties": {
              "findings": {
                "type": "array",
                "items": {"type": "object"}
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              }
            }
          },
          "invocation_target": "research-agent.deep_research"
        }
      ]
    }
  ]
}

Use Cases

AI Orchestrator Pattern

Build AI systems that select tools at runtime:

// Step 1: Discover available tools
const tools = await fetch(
  'http://localhost:8080/api/v1/discovery/capabilities?include_input_schema=true'
).then(r => r.json());

// Step 2: Let AI select appropriate tool
const selectedTool = await aiModel.selectTool(userQuery, tools);

// Step 3: Execute selected tool
const result = await fetch(
  `http://localhost:8080/api/v1/execute/${selectedTool.invocation_target}`,
  {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({input: userInput})
  }
).then(r => r.json());

Dynamic Tool Registry for LLMs

Generate LLM function definitions from discovered capabilities:

import requests

# Discover all capabilities with schemas
capabilities = requests.get(
    'http://localhost:8080/api/v1/discovery/capabilities',
    params={
        'include_input_schema': 'true',
        'include_descriptions': 'true'
    }
).json()

# Convert to OpenAI function definitions
openai_tools = []
for agent_cap in capabilities['capabilities']:
    for reasoner in agent_cap['reasoners']:
        openai_tools.append({
            'type': 'function',
            'function': {
                'name': reasoner['id'],
                'description': reasoner['description'],
                'parameters': reasoner['input_schema']
            }
        })

# Use with OpenAI
response = openai.chat.completions.create(
    model='gpt-4',
    messages=[{'role': 'user', 'content': user_query}],
    tools=openai_tools
)

Health-Based Routing

Route to healthy agents only:

curl 'http://localhost:8080/api/v1/discovery/capabilities?health_status=active&tags=search'

Response Fields

FieldTypeDescription
discovered_atstringDiscovery timestamp (ISO 8601)
total_agentsnumberTotal number of agents discovered
total_reasonersnumberTotal number of reasoners across all agents
total_skillsnumberTotal number of skills across all agents
paginationobjectPagination metadata (limit, offset, has_more)
capabilitiesarrayArray of agent capability objects

Agent Capability Object

FieldTypeDescription
agent_idstringUnique agent identifier
base_urlstringAgent's HTTP endpoint
versionstringAgent version
health_statusstringHealth status: active, inactive, degraded, unknown
deployment_typestringDeployment type: long_running, serverless
last_heartbeatstringLast heartbeat timestamp
reasonersarrayArray of reasoner capability objects
skillsarrayArray of skill capability objects

Reasoner/Skill Capability Object

FieldTypeDescription
idstringReasoner/skill identifier
descriptionstringHuman-readable description (if include_descriptions=true)
tagsarrayArray of tag strings
input_schemaobjectJSON Schema for input (if include_input_schema=true)
output_schemaobjectJSON Schema for output (if include_output_schema=true)
examplesarrayUsage examples (if include_examples=true)
invocation_targetstringTarget string for execution (format: agent_id.function_name)

Best Practices

Cache Discovery Results

Discovery results change infrequently—cache them:

let capabilitiesCache = null;
let cacheTime = null;
const CACHE_TTL = 30000; // 30 seconds

async function getCapabilities() {
  const now = Date.now();

  if (capabilitiesCache && (now - cacheTime) < CACHE_TTL) {
    return capabilitiesCache;
  }

  const response = await fetch(
    'http://localhost:8080/api/v1/discovery/capabilities'
  );
  capabilitiesCache = await response.json();
  cacheTime = now;

  return capabilitiesCache;
}

Use Compact Format for Bandwidth

Use compact format when you only need targets and tags:

curl 'http://localhost:8080/api/v1/discovery/capabilities?format=compact'

Filter Aggressively

Request only what you need and combine filters in a single request:

# Bad: Retrieve everything
curl 'http://localhost:8080/api/v1/discovery/capabilities'

# Bad: Multiple separate requests
curl 'http://localhost:8080/api/v1/discovery/capabilities?tags=research'
curl 'http://localhost:8080/api/v1/discovery/capabilities?health_status=active'

# Good: Combine filters in one request (efficient server-side evaluation)
curl 'http://localhost:8080/api/v1/discovery/capabilities?tags=research&health_status=active&include_input_schema=true'

Use XML for LLM System Prompts

XML format is easier for LLMs to parse in system prompts:

xml_capabilities = requests.get(
    'http://localhost:8080/api/v1/discovery/capabilities',
    params={'format': 'xml', 'include_descriptions': 'true'}
).text

system_prompt = f"""
You have access to these capabilities:

{xml_capabilities}

Select and use the appropriate capability for the user's request.
"""

Performance Considerations

Caching:

  • Discovery results are cached for 30 seconds on the server
  • Cache hit rate typically >95%
  • Response time: <50ms (p50), <100ms (p95)

Filtering:

  • All filtering happens in-memory after cache lookup
  • Wildcard matching adds ~5-10ms overhead
  • Schema inclusion adds ~10-20ms per agent

Best Performance:

  • Use specific filters to reduce response size
  • Omit schemas if not needed (include_input_schema=false)
  • Use compact format for minimal payloads
  • Cache results on client side (30-60 seconds)

Observability

The Discovery API automatically exposes Prometheus metrics for monitoring:

# Request metrics
agentfield_discovery_requests_total{format="json|xml|compact",status="success|error"}
agentfield_discovery_request_duration_seconds{format="json|xml|compact"}

# Cache metrics
agentfield_discovery_cache_hits_total
agentfield_discovery_cache_misses_total

# Usage metrics
agentfield_discovery_filter_usage_total{filter_type="reasoner|skill|tag|agent"}

Scrape these metrics at /metrics on the control plane to track discovery usage, cache efficiency, and performance.

Debug Logging: Enable debug-level logs to see cache hit/miss information and filter execution details for slow queries.

Troubleshooting