Robutler

Agent Capabilities

Capabilities enable discovery and interoperability between agents, clients, and models. WebAgents uses the UAMP unified capabilities format.

Unified Format

All capability declarations (model, client, agent) use the same structure:

import type { Capabilities } from 'webagents';

// Model capabilities
const modelCaps: Capabilities = {
  id: 'gpt-4o',
  provider: 'openai',
  modalities: ['text', 'image'],
  supports_streaming: true,
  context_window: 128_000,
};

// Client capabilities
const clientCaps: Capabilities = {
  id: 'web-app',
  provider: 'robutler',
  modalities: ['text', 'image', 'audio'],
  widgets: ['chart', 'form'],
  extensions: { supports_html: true },
};

// Agent capabilities
const agentCaps: Capabilities = {
  id: 'my-agent',
  provider: 'webagents',
  modalities: ['text', 'image'],
  provides: ['web_search', 'chart', 'tts'],
  endpoints: ['/api/search'],
};

The provides Field

Decorators support a provides field to declare the capability they provide.

Tools

@tool({ provides: 'web_search', description: 'Search the web for information' })
async searchWeb(params: { query: string }): Promise<string> { return ''; }

@tool({ provides: 'chart', description: 'Render data as a chart widget' })
async renderChart(params: { data: string }): Promise<string> { return ''; }

@tool({ provides: 'tts', description: 'Convert text to speech audio' })
async textToSpeech(params: { text: string }): Promise<Uint8Array> { return new Uint8Array(); }

Handoffs

@handoff({ name: 'gpt4', description: 'GPT-4 with extended thinking' })
async *gpt4Handoff(events) {
  yield { type: 'response.delta', delta: '...' } as const;
}

@handoff({ name: 'vision', description: 'Vision model for image analysis' })
async *visionHandoff(events) {
  yield { type: 'response.delta', delta: '...' } as const;
}

The TypeScript @handoff decorator does not currently accept a provides field; capabilities for handoffs are inferred from the skill's class name and subscribes / produces. Track this in the parity matrix.

HTTP Endpoints

@http({ path: '/export/pdf', method: 'POST', description: 'Export data as PDF' })
async exportPdf(req: Request): Promise<Response> { return new Response('pdf'); }

@http({ path: '/api/search', method: 'GET', description: 'Search API endpoint' })
async searchApi(req: Request): Promise<Response> { return Response.json({}); }

WebSockets

@websocket({ path: '/stream' })
realtimeStream(ws: WebSocket): void {
  ws.onmessage = () => ws.send('chunk');
}

Widgets

// @widget is Python-only today. Return a <widget> envelope from a regular @tool:
@tool({ description: 'Interactive chart widget', provides: 'chart' })
async chartWidget(params: { data: string }): Promise<string> {
  return `<widget kind="webagents" id="chart"><div>${params.data}</div></widget>`;
}

Capability Aggregation

The agent automatically aggregates all provides values from:

  • Tools (@tool)
  • Handoffs (@handoff)
  • HTTP endpoints (@http)
  • WebSockets (@websocket)
  • Widgets (@widget, Python only)

These are exposed via the Capabilities.provides field.

Querying Capabilities

Agents expose capabilities through the /capabilities endpoint:

curl http://localhost:8000/my-agent/capabilities

Response:

{
  "id": "my-agent",
  "provider": "webagents",
  "modalities": ["text", "image"],
  "provides": ["web_search", "chart", "tts", "pdf_export"],
  "endpoints": ["/api/search", "/export/pdf"],
  "widgets": ["chart"],
  "supports_streaming": true
}

Client Capabilities

Clients announce their capabilities when creating a session:

import type { SessionCreateEvent, Capabilities } from 'webagents';

const event: SessionCreateEvent = {
  type: 'session.create',
  event_id: 'evt_1',
  session: { client_id: 'web-app' },
  client_capabilities: {
    id: 'web-app',
    provider: 'robutler',
    modalities: ['text', 'image', 'audio'],
    widgets: ['chart', 'form'],
    extensions: { supports_html: true },
  },
};

This enables agents to adapt their responses based on client capabilities.

UAMP Types

Import capability types from webagents/uamp:

import type {
  Capabilities,        // Unified capabilities (model, client, agent)
  ImageCapabilities,   // Detailed image support
  AudioCapabilities,   // Detailed audio support
  FileCapabilities,    // Detailed file support
  ToolCapabilities,    // Tool calling support
} from 'webagents';

Best Practices

  1. Use descriptive provides values — make capabilities discoverable.
  2. Match client capabilities — adapt output to what the client can render.
  3. Aggregate from skills — let skills declare their capabilities.
  4. Query before calling — check agent capabilities before making requests.

On this page