Tools

July 29, 2026 · View on GitHub

Local tools — tool()

tool() wraps an async function. Pass a Zod schema or a plain JSON Schema object for inputSchema. The function runs locally as a Conductor worker that the runtime polls; the runtime registers and polls it automatically on run() / serve().

const getWeather = tool(
  async (args: { city: string }) => {
    return { city: args.city, tempC: 21, conditions: 'sunny' };
  },
  {
    name: 'get_weather',
    description: 'Get the current weather for a city.',
    inputSchema: {
      type: 'object',
      properties: { city: { type: 'string', description: 'City name' } },
      required: ['city'],
    },
  },
);

const agent = new Agent({
  name: 'weather_agent',
  model: 'anthropic/claude-sonnet-4-6',
  instructions: 'Answer weather questions using the tool.',
  tools: [getWeather],
});

tool() options: name, description, inputSchema, outputSchema?, approvalRequired?, timeoutSeconds?, external?, credentials?, guardrails?, maxCalls?, retryCount?, retryDelaySeconds?, retryPolicy?.

The tool function receives an optional second argument, the ToolContext (sessionId, executionId, agentName, metadata, dependencies, and a mutable state). See Stateful agents.

No per-run mutable capture. A tool() handler is registered once and its Conductor worker is reused across concurrent runs and (for framework-spawned agents) concurrent process-local executors — never re-created per run. Don't close over per-run mutable state in the handler itself (a module-level counter, an array pushed to across calls, a captured let reassigned mid-run); two runs executing the same tool concurrently would corrupt each other's state. Everything a handler needs that varies per run belongs in ToolContext (state for durable per-execution data, dependencies for injected collaborators) or in the function's own arguments — never in a closure variable mutated across invocations. Tool and agent factories otherwise take plain data (JSON-serializable configs), so building one is always safe to repeat.

Tool discovery — @Tool / toolsFrom

Decorate methods on a class and extract them, bound to the instance:

import { Tool, toolsFrom } from '@io-orkes/conductor-javascript/agents';

class MathTools {
  @Tool({ description: 'Add two numbers.', inputSchema: {
    type: 'object', properties: { a: { type: 'number' }, b: { type: 'number' } }, required: ['a', 'b'],
  }})
  async add(args: { a: number; b: number }) { return { sum: args.a + args.b }; }
}

const tools = toolsFrom(new MathTools());     // ToolFunction[]
new Agent({ name: 'calc', model, tools });

Built-in tools

These return a ToolDef that runs server-side (no local worker). Add them to tools: [...].

BuilderTool typePurpose
httpTool({ name, description, url, method?, headers?, inputSchema?, credentials? })httpCall an HTTP endpoint.
mcpTool({ serverUrl, name?, description?, headers?, toolNames?, maxTools?, credentials? })mcpExpose an MCP server's tools.
apiTool({ url, name?, description?, headers?, toolNames?, maxTools?, credentials? })apiExpose an OpenAPI/API as tools.
agentTool(agent, { name?, description?, retryCount?, retryDelaySeconds?, optional? })agent_toolCall another Agent as a tool (sub-agent).
humanTool({ name, description, inputSchema? })humanPause for human input (HITL).
imageTool({ name, description, llmProvider, model, style?, size? })generate_imageGenerate images.
audioTool({ name, description, llmProvider, model, voice?, speed?, format? })generate_audioText-to-speech.
videoTool({ name, description, llmProvider, model, duration?, resolution?, fps?, ... })generate_videoGenerate video.
pdfTool({ name?, description?, pageSize?, theme?, fontSize? })generate_pdfRender markdown to PDF.
waitForMessageTool({ name, description, batchSize?, blocking? })pull_workflow_messagesDequeue messages from the workflow message queue.
searchTool({ name, description, vectorDb, index, embeddingModelProvider, embeddingModel, namespace?, maxResults? })rag_searchRAG vector search.
indexTool({ name, description, vectorDb, index, embeddingModelProvider, embeddingModel, namespace?, chunkSize?, chunkOverlap? })rag_indexRAG index/ingest.
import { httpTool, mcpTool } from '@io-orkes/conductor-javascript/agents';

const agent = new Agent({
  name: 'researcher',
  model: 'anthropic/claude-sonnet-4-6',
  tools: [
    httpTool({
      name: 'get_user',
      description: 'Fetch a user by id.',
      url: 'https://api.example.com/users/{id}',
      method: 'GET',
    }),
    mcpTool({ serverUrl: 'https://mcp.example.com/sse', toolNames: ['search'] }),
  ],
});

waitForMessageTool — workflow message queue

waitForMessageTool lets a running agent dequeue messages pushed into its workflow message queue (Conductor PULL_WORKFLOW_MESSAGES). No worker is needed — the server handles it. In blocking mode (default) the task stays in progress until a message arrives. For plain (non-agent) workflows, use the pullWorkflowMessages task builder instead — see workflow-message-queue.md.

import { waitForMessageTool } from '@io-orkes/conductor-javascript/agents';

const agent = new Agent({
  name: 'inbox_agent',
  model: 'anthropic/claude-sonnet-4-6',
  instructions: 'When asked to wait, call wait_for_message and process what arrives.',
  tools: [waitForMessageTool({
    name: 'wait_for_message',
    description: 'Wait for the next inbound message.',
    batchSize: 1,       // up to 100; default 1
    blocking: true,     // default true
  })],
});

agentTool — agent as a tool

import { agentTool } from '@io-orkes/conductor-javascript/agents';

const translator = new Agent({ name: 'translator', model, instructions: 'Translate to French.' });

const orchestrator = new Agent({
  name: 'orchestrator',
  model,
  instructions: 'Use the translator tool when asked to translate.',
  tools: [agentTool(translator, { description: 'Translate text to French.' })],
});

Next steps

See multi-agent for composing agents as tools via agentTool, guardrails for tool-level validation, and the tool reference for the complete option and type list.