Skip to content

Tools

Tools let an Agent take actions – fetch data, call external APIs, execute code, or even use a computer. The JavaScript/TypeScript SDK supports six categories:

  1. Hosted OpenAI tools – run alongside the model on OpenAI servers. (web search, file search, code interpreter, image generation)
  2. Local built-in tools – run in your environment. (computer use, shell, apply_patch)
  3. Function tools – wrap any local function with a JSON schema so the LLM can call it.
  4. Agents as tools – expose an entire Agent as a callable tool.
  5. MCP servers – attach a Model Context Protocol server (local or remote).
  6. Experimental: Codex tool – wrap the Codex SDK as a function tool to run workspace-aware tasks.

The rest of this guide first covers each tool category, then summarizes cross-cutting tool selection and prompting guidance.

When you use the OpenAIResponsesModel you can add the following built‑in tools:

ToolType stringPurpose
Web search'web_search'Internet search.
File / retrieval search'file_search'Query vector stores hosted on OpenAI.
Code Interpreter'code_interpreter'Run code in a sandboxed environment.
Image generation'image_generation'Generate images based on text.
Hosted tools
import {
Agent,
codeInterpreterTool,
fileSearchTool,
imageGenerationTool,
webSearchTool,
} from '@openai/agents';
const agent = new Agent({
name: 'Travel assistant',
tools: [
webSearchTool({ searchContextSize: 'medium' }),
fileSearchTool('VS_ID', { maxNumResults: 3 }),
codeInterpreterTool(),
imageGenerationTool({ size: '1024x1024' }),
],
});

The SDK provides helper functions that return hosted tool definitions:

Helper functionNotes
webSearchTool(options?)JS-friendly options such as searchContextSize, userLocation, and filters.allowedDomains.
fileSearchTool(ids, options?)Accepts one or more vector store IDs as the first argument, plus options like maxNumResults and filters.
codeInterpreterTool(options?)Defaults to an auto-managed container when no container is provided.
imageGenerationTool(options?)Supports image generation configuration such as size, quality, background, and output format.

These helpers map JavaScript/TypeScript-friendly option names to the underlying OpenAI Responses API tool payloads. Refer to the official OpenAI documentation for the full tool schemas and advanced options like ranking options or semantic filters.


Local built-in tools run in your own environment and require you to supply implementations:

  • Computer use – implement the Computer interface and pass it to computerTool().
  • Shell – either provide a local Shell implementation, or configure a hosted container environment.
  • Apply patch – implement the Editor interface and pass it to applyPatchTool().

Computer and apply-patch tools execute locally and are not hosted by OpenAI. Shell tools can run locally or in hosted container environments, depending on shellTool() configuration. The tool calls are still requested by the model’s responses, but your application controls how those calls are executed.

Local built-in tools
import {
Agent,
applyPatchTool,
computerTool,
shellTool,
Computer,
Editor,
Shell,
} from '@openai/agents';
const computer: Computer = {
environment: 'browser',
dimensions: [1024, 768],
screenshot: async () => '',
click: async () => {},
doubleClick: async () => {},
scroll: async () => {},
type: async () => {},
wait: async () => {},
move: async () => {},
keypress: async () => {},
drag: async () => {},
};
const shell: Shell = {
run: async () => ({
output: [
{
stdout: '',
stderr: '',
outcome: { type: 'exit', exitCode: 0 },
},
],
}),
};
const editor: Editor = {
createFile: async () => ({ status: 'completed' }),
updateFile: async () => ({ status: 'completed' }),
deleteFile: async () => ({ status: 'completed' }),
};
const agent = new Agent({
name: 'Local tools agent',
tools: [
computerTool({ computer }),
shellTool({ shell, needsApproval: true }),
applyPatchTool({ editor, needsApproval: true }),
],
});
void agent;

For hosted shell environments, configure shellTool({ environment }) with either:

  • type: 'container_auto' to create a managed container for the run (supports network policy, memory limit, and skills).
  • type: 'container_reference' to reuse an existing container by containerId.

See examples/tools/container-shell-skill-ref.ts and examples/tools/container-shell-inline-skill.ts for end-to-end usage.


You can turn any function into a tool with the tool() helper.

Function tool with Zod parameters
import { tool } from '@openai/agents';
import { z } from 'zod';
const getWeatherTool = tool({
name: 'get_weather',
description: 'Get the weather for a given city',
parameters: z.object({ city: z.string() }),
async execute({ city }) {
return `The weather in ${city} is sunny.`;
},
});
FieldRequiredDescription
nameNoDefaults to the function name (e.g., get_weather).
descriptionYesClear, human-readable description shown to the LLM.
parametersYesEither a Zod schema or a raw JSON schema object. Zod parameters automatically enable strict mode.
strictNoWhen true (default), the SDK returns a model error if the arguments don’t validate. Set to false for fuzzy matching.
executeYes(args, context, details) => string | unknown | Promise<...> – your business logic. Non-string outputs are serialized for the model. context is optional RunContext; details includes metadata like toolCall, resumeState, and signal.
errorFunctionNoCustom handler (context, error) => string for transforming internal errors into a user-visible string.
timeoutMsNoPer-call timeout in milliseconds. Must be greater than 0 and less than or equal to 2147483647.
timeoutBehaviorNoTimeout mode: error_as_result (default) returns a model-visible timeout message, and raise_exception throws ToolTimeoutError.
timeoutErrorFunctionNoCustom handler (context, timeoutError) => string for timeout output when timeoutBehavior is error_as_result.
needsApprovalNoRequire human approval before execution. See the human-in-the-loop guide.
isEnabledNoConditionally expose the tool per run; accepts a boolean or predicate.
inputGuardrailsNoGuardrails that run before the tool executes; can reject or throw. See Guardrails.
outputGuardrailsNoGuardrails that run after the tool executes; can reject or throw. See Guardrails.

Use timeoutMs to bound each function tool invocation.

  • timeoutBehavior: 'error_as_result' (default) returns Tool '<name>' timed out after <timeoutMs>ms. to the model.
  • timeoutBehavior: 'raise_exception' throws ToolTimeoutError, which you can catch as part of run exceptions.
  • timeoutErrorFunction lets you customize timeout text in error_as_result mode.
  • Timeouts abort details.signal, so long-running tools can stop promptly when they listen for cancellation.

If you invoke a function tool directly, use invokeFunctionTool to enforce the same timeout behavior as normal agent runs.

If you need the model to guess invalid or partial input you can disable strict mode when using raw JSON schema:

Non-strict JSON schema tools
import { tool } from '@openai/agents';
interface LooseToolInput {
text: string;
}
const looseTool = tool({
description: 'Echo input; be forgiving about typos',
strict: false,
parameters: {
type: 'object',
properties: { text: { type: 'string' } },
required: ['text'],
additionalProperties: true,
},
execute: async (input) => {
// because strict is false we need to do our own verification
if (typeof input !== 'object' || input === null || !('text' in input)) {
return 'Invalid input. Please try again';
}
return (input as LooseToolInput).text;
},
});

Sometimes you want an Agent to assist another Agent without fully handing off the conversation. Use agent.asTool():

Agents as tools
import { Agent } from '@openai/agents';
const summarizer = new Agent({
name: 'Summarizer',
instructions: 'Generate a concise summary of the supplied text.',
});
const summarizerTool = summarizer.asTool({
toolName: 'summarize_text',
toolDescription: 'Generate a concise summary of the supplied text.',
});
const mainAgent = new Agent({
name: 'Research assistant',
tools: [summarizerTool],
});

Under the hood the SDK:

  • Creates a function tool with a single input parameter.
  • Runs the sub‑agent with that input when the tool is called.
  • Returns either the last message or the output extracted by customOutputExtractor.

When you run an agent as a tool, Agents SDK creates a runner with the default settings and run the agent with it within the function execution. If you want to provide any properties of runConfig or runOptions, you can pass them to the asTool() method to customize the runner’s behavior.

You can also set needsApproval and isEnabled on the agent tool via asTool() options to integrate with human‑in‑the‑loop flows and conditional tool availability.

Advanced structured-input options for agent.asTool():

  • inputBuilder: maps structured tool args to the nested agent input payload.
  • includeInputSchema: includes the input JSON schema in the nested run for stronger schema-aware behavior.
  • resumeState: controls context reconciliation strategy when resuming nested serialized RunState.

Agent tools can stream all nested run events back to your app. Choose the hook style that fits how you construct the tool:

Streaming agent tools
import { Agent } from '@openai/agents';
const billingAgent = new Agent({
name: 'Billing Agent',
instructions: 'Answer billing questions and compute simple charges.',
});
const billingTool = billingAgent.asTool({
toolName: 'billing_agent',
toolDescription: 'Handles customer billing questions.',
// onStream: simplest catch-all when you define the tool inline.
onStream: (event) => {
console.log(`[onStream] ${event.event.type}`, event);
},
});
// on(eventName) lets you subscribe selectively (or use '*' for all).
billingTool.on('run_item_stream_event', (event) => {
console.log('[on run_item_stream_event]', event);
});
billingTool.on('raw_model_stream_event', (event) => {
console.log('[on raw_model_stream_event]', event);
});
const orchestrator = new Agent({
name: 'Support Orchestrator',
instructions: 'Delegate billing questions to the billing agent tool.',
tools: [billingTool],
});
  • Event types match RunStreamEvent['type']: raw_model_stream_event, run_item_stream_event, agent_updated_stream_event.
  • onStream is the simplest “catch-all” and works well when you declare the tool inline (tools: [agent.asTool({ onStream })]). Use it if you do not need per-event routing.
  • on(eventName, handler) lets you subscribe selectively (or with '*') and is best when you need finer-grained handling or want to attach listeners after creation.
  • If you provide either onStream or any on(...) handler, the agent-as-tool will run in streaming mode automatically; without them it stays on the non-streaming path.
  • Handlers are invoked in parallel so a slow onStream callback will not block on(...) handlers (and vice versa).
  • toolCallId is provided when the tool was invoked via a model tool call; direct invoke() calls or provider quirks may omit it.

You can expose tools via Model Context Protocol (MCP) servers and attach them to an agent. For instance, you can use MCPServerStdio to spawn and connect to the stdio MCP server:

Local MCP server
import { Agent, MCPServerStdio } from '@openai/agents';
const server = new MCPServerStdio({
fullCommand: 'npx -y @modelcontextprotocol/server-filesystem ./sample_files',
});
await server.connect();
const agent = new Agent({
name: 'Assistant',
mcpServers: [server],
});

See filesystem-example.ts for a complete example. Also, if you’re looking for a comprehensitve guide for MCP server tool integration, refer to MCP guide for details. When managing multiple servers (or partial failures), use connectMcpServers and the lifecycle guidance in the MCP guide.


@openai/agents-extensions/experimental/codex provides codexTool(), a function tool that routes model tool calls to the Codex SDK so the agent can run workspace-scoped tasks (shell, file edits, MCP tools) autonomously. This surface is experimental and may change.

Install dependencies first:

Terminal window
npm install @openai/agents-extensions @openai/codex-sdk

Quick start:

Experimental Codex tool
import { Agent } from '@openai/agents';
import { codexTool } from '@openai/agents-extensions/experimental/codex';
export const codexAgent = new Agent({
name: 'Codex Agent',
instructions:
'Use the codex tool to inspect the workspace and answer the question. When skill names, which usually start with `$`, are mentioned, you must rely on the codex tool to use the skill and answer the question.',
tools: [
codexTool({
sandboxMode: 'workspace-write',
workingDirectory: '/path/to/repo',
defaultThreadOptions: {
model: 'gpt-5.2-codex',
networkAccessEnabled: true,
webSearchEnabled: false,
},
}),
],
});

What to know:

  • Auth: supply CODEX_API_KEY (preferred) or OPENAI_API_KEY, or pass codexOptions.apiKey.
  • Inputs: strict schema—inputs must contain at least one { type: 'text', text } or { type: 'local_image', path }.
  • Safety: pair sandboxMode with workingDirectory; set skipGitRepoCheck if the directory is not a Git repo.
  • Threading: useRunContextThreadId: true reads/stores the latest thread id in runContext.context, which is useful for cross-turn reuse in your app state.
  • Thread ID precedence: tool call threadId (if your schema includes it) takes priority, then run-context thread id, then codexTool({ threadId }).
  • Run context key: defaults to codexThreadId for name: 'codex', or codexThreadId_<suffix> for names like name: 'engineer' (codex_engineer after normalization).
  • Mutable context requirement: when useRunContextThreadId is enabled, pass a mutable object or Map as run(..., { context }).
  • Naming: tool names are normalized into the codex namespace (engineer becomes codex_engineer), and duplicate Codex tool names in an agent are rejected.
  • Streaming: onStream mirrors Codex events (reasoning, command execution, MCP tool calls, file changes, web search) so you can log or trace progress.
  • Outputs: tool result includes response, usage, and threadId, and Codex token usage is recorded in RunContext.
  • Structure: outputSchema can be a descriptor, JSON schema object, or Zod object. For JSON object schemas, additionalProperties must be false.

Run-context thread reuse example:

Codex run-context thread reuse
import { Agent, run } from '@openai/agents';
import { codexTool } from '@openai/agents-extensions/experimental/codex';
// Derived from codexTool({ name: 'engineer' }) when runContextThreadIdKey is omitted.
type ExampleContext = {
codexThreadId_engineer?: string;
};
const agent = new Agent<ExampleContext>({
name: 'Codex assistant',
instructions: 'Use the codex tool for workspace tasks.',
tools: [
codexTool({
// `name` is optional for a single Codex tool.
// We set it so the run-context key is tool-specific and to avoid collisions when adding more Codex tools.
name: 'engineer',
// Reuse the same Codex thread across runs that share this context object.
useRunContextThreadId: true,
sandboxMode: 'workspace-write',
workingDirectory: '/path/to/repo',
defaultThreadOptions: {
model: 'gpt-5.2-codex',
approvalPolicy: 'never',
},
}),
],
});
// The default key for useRunContextThreadId with name=engineer is codexThreadId_engineer.
const context: ExampleContext = {};
// First turn creates (or resumes) a Codex thread and stores the thread ID in context.
await run(agent, 'Inspect src/tool.ts and summarize it.', { context });
// Second turn reuses the same thread because it shares the same context object.
await run(agent, 'Now list refactoring opportunities.', { context });
const threadId = context.codexThreadId_engineer;
void threadId;

Refer to the Agents guide for controlling when and how a model must use tools (modelSettings.toolChoice, toolUseBehavior, etc.).


  • Short, explicit descriptions – describe what the tool does and when to use it.
  • Validate inputs – use Zod schemas for strict JSON validation where possible.
  • Avoid side‑effects in error handlerserrorFunction should return a helpful string, not throw.
  • One responsibility per tool – small, composable tools lead to better model reasoning.

  • Learn about forcing tool use.
  • Add guardrails to validate tool inputs or outputs.
  • Dive into the TypeDoc reference for tool() and the various hosted tool types.