ctx.discover()

Discover capabilities of agents registered with the control plane

The ctx.discover() method queries the Agentfield control plane to find available agents and their capabilities, enabling dynamic agent orchestration.

Basic Usage

agent.reasoner('find_agents', async (ctx) => {
  const result = await ctx.discover();

  return {
    totalAgents: result.json?.totalAgents,
    capabilities: result.json?.capabilities
  };
});

Discovery Options

Prop

Type

Response Format

JSON Format (Default)

const result = await ctx.discover({ format: 'json' });

interface DiscoveryResponse {
  discoveredAt: string;
  totalAgents: number;
  totalReasoners: number;
  totalSkills: number;
  pagination: {
    limit: number;
    offset: number;
    hasMore: boolean;
  };
  capabilities: AgentCapability[];
}

interface AgentCapability {
  agentId: string;
  baseUrl: string;
  version: string;
  healthStatus: string;
  deploymentType?: string;
  lastHeartbeat?: string;
  reasoners: ReasonerCapability[];
  skills: SkillCapability[];
}

Compact Format

const result = await ctx.discover({ format: 'compact' });
// result.compact contains a condensed representation

XML Format

const result = await ctx.discover({ format: 'xml' });
// result.xml contains XML string

Examples

Filter by Tags

agent.reasoner('find_analyzers', async (ctx) => {
  const result = await ctx.discover({
    tags: ['analysis', 'nlp'],
    includeDescriptions: true
  });

  return result.json?.capabilities.map(agent => ({
    id: agent.agentId,
    reasoners: agent.reasoners.map(r => ({
      name: r.name,
      description: r.description
    }))
  }));
});

Find Specific Capability

agent.reasoner('find_sentiment_analyzer', async (ctx) => {
  const result = await ctx.discover({
    reasoner: 'analyze_sentiment',
    healthStatus: 'healthy'
  });

  if (result.json?.capabilities.length === 0) {
    throw new Error('No sentiment analyzer available');
  }

  // Use the first available agent
  const agent = result.json.capabilities[0];
  return await ctx.call(`${agent.agentId}.analyze_sentiment`, ctx.input);
});

Dynamic Routing

agent.reasoner('smart_route', async (ctx) => {
  const { taskType, data } = ctx.input;

  // Find agents that can handle this task type
  const result = await ctx.discover({
    tags: [taskType],
    healthStatus: 'healthy',
    includeInputSchema: true
  });

  const available = result.json?.capabilities || [];

  if (available.length === 0) {
    throw new Error(`No agents available for task: ${taskType}`);
  }

  // Pick best agent (e.g., by version, load, etc.)
  const target = available[0];
  const reasoner = target.reasoners[0];

  return await ctx.call(`${target.agentId}.${reasoner.name}`, data);
});

Agent-Level Discovery

// Outside of a reasoner context
const result = await agent.discover({
  tags: ['database'],
  limit: 10
});

console.log(`Found ${result.json?.totalAgents} database agents`);

With Pagination

agent.reasoner('list_all_agents', async (ctx) => {
  const allAgents = [];
  let offset = 0;
  const limit = 50;

  while (true) {
    const result = await ctx.discover({ limit, offset });
    const capabilities = result.json?.capabilities || [];

    allAgents.push(...capabilities);

    if (!result.json?.pagination.hasMore) break;
    offset += limit;
  }

  return { totalAgents: allAgents.length, agents: allAgents };
});

Use Cases

Service Mesh Pattern

agent.reasoner('orchestrate', async (ctx) => {
  // Discover available services
  const services = await ctx.discover({
    tags: ['microservice'],
    healthStatus: 'healthy'
  });

  // Build service map
  const serviceMap = new Map();
  for (const svc of services.json?.capabilities || []) {
    for (const reasoner of svc.reasoners) {
      serviceMap.set(reasoner.name, svc.agentId);
    }
  }

  // Route to appropriate service
  const { operation, data } = ctx.input;
  const targetAgent = serviceMap.get(operation);

  if (!targetAgent) {
    throw new Error(`Unknown operation: ${operation}`);
  }

  return await ctx.call(`${targetAgent}.${operation}`, data);
});

Health-Aware Load Balancing

agent.reasoner('load_balance', async (ctx) => {
  const { operation, data } = ctx.input;

  // Find all healthy instances
  const result = await ctx.discover({
    reasoner: operation,
    healthStatus: 'healthy'
  });

  const instances = result.json?.capabilities || [];

  if (instances.length === 0) {
    throw new Error(`No healthy instances for: ${operation}`);
  }

  // Random selection (simple load balancing)
  const target = instances[Math.floor(Math.random() * instances.length)];

  return await ctx.call(`${target.agentId}.${operation}`, data);
});