Skip to content

Server-side built-in tools

Enable the provider’s code-execution built-in, prompt 'Compute 12345 * 6789 using code', and confirm the answer 83810205 appears in the response — using one tool descriptor that works on any supporting provider.

Some tools run entirely on the provider’s servers — the model writes code, the provider’s sandbox executes it, and the result flows back to the model automatically, all without your server being involved. Common built-ins:

  • Code interpreter / code execution — the model writes Python, the sandbox runs it, the model sees stdout/result.
  • Web search / grounding — the model queries a search index provider-side, results are injected into context.
  • File search — the model searches a provider-managed vector store.
  • Image generation — the model generates an image provider-side, result returned as a media part.

The challenge: each provider uses a completely different object shape to declare these tools. You cannot write one tool entry that works across providers.

import { complete } from '@combycode/llm-sdk';
const { text } = await complete({
model: process.env.LLM_MODEL!,
apiKey: process.env.LLM_API_KEY,
prompt: 'Compute 12345 * 6789 using code and tell me the result.',
tools: [{ type: 'code_interpreter' }],
maxTokens: 1024,
});
console.log(text); // includes "83810205"

No execute function — there is nothing to execute client-side. The { type: 'code_interpreter' } object is a BuiltinTool (from llm/types/tools.ts). The SDK maps it to the provider’s native shape before sending the request.

You can pass both defineTool tools and built-in tools in the same tools array. The model will call whichever is appropriate for the task:

import { complete, defineTool } from '@combycode/llm-sdk';
const getDbRecord = defineTool({
name: 'get_db_record',
description: 'Look up a record by ID from the database.',
params: { id: 'string' },
execute: async ({ id }) => {
return JSON.stringify({ id, name: 'Widget', price: 9.99 });
},
});
const { text } = await complete({
model: process.env.LLM_MODEL!,
apiKey: process.env.LLM_API_KEY,
prompt: 'Look up record abc-123 and compute its price in euros (rate: 0.92).',
tools: [
getDbRecord, // client-side: your server executes this
{ type: 'code_interpreter' }, // server-side: provider executes this
],
maxTokens: 1024,
});

When the model calls get_db_record, the SDK invokes your execute function. When it uses code execution, nothing happens client-side — the provider handles it.

Step 3 — Use web search for grounded answers

Section titled “Step 3 — Use web search for grounded answers”
import { complete } from '@combycode/llm-sdk';
const { text } = await complete({
model: process.env.LLM_MODEL!,
apiKey: process.env.LLM_API_KEY,
prompt: 'What are the latest developments in fusion energy research?',
tools: [{ type: 'web_search' }],
maxTokens: 1024,
});
console.log(text); // answer grounded in current web results

The provider performs the search, injects results into context, and the model synthesises a grounded answer. For a dedicated web search scenario with citations see Web search.

Some built-in tools accept configuration via an optional params field on the descriptor:

// OpenAI file search: point at a specific vector store
tools: [{ type: 'file_search', params: { vector_store_ids: ['vs_abc123'] } }]
// OpenAI code interpreter: attach files for the sandbox to use
tools: [{ type: 'code_interpreter', params: { file_ids: ['file-xyz'] } }]

Provider-specific params that have no cross-provider equivalent are passed through in params. Check provider docs for the exact keys.

Built-in tool types (BuiltinTool.type):

TypeWhat it doesProvider support
'code_interpreter'Run Python in a sandboxed environmentOpenAI, Google, Anthropic (via computer_*)
'web_search'Search the web and inject grounded resultsOpenAI, Google (native), Anthropic (Brave/Tavily via params)
'file_search'Search a provider-managed vector storeOpenAI (requires vector store setup)
'image_generation'Generate images provider-sideOpenAI (gpt-image-1)
'mcp'Model Context Protocol external serverOpenAI (remote MCP)

Client-side vs server-side — the key distinction:

Client-side tools (defineTool)Server-side built-ins (BuiltinTool)
Who executesYour execute function on your serverProvider’s infrastructure
execute function requiredYesNo (no-op internally)
Network round-tripYes (your server)No (provider-internal)
Customizable logicFullyOnly via params configuration
Result visible in responsetext + message historyEmbedded in text
Works offlineYes (local execution)No

Provider-native shape mapping:

ORXA maps { type: 'code_interpreter' } to:

  • Anthropic: { type: 'computer_20250124', name: 'computer', display_width_px: ..., ... } (or bash/text-editor variants depending on the request context)
  • OpenAI: { type: 'code_interpreter' } (same shape)
  • Google: { codeExecution: {} }

This mapping is transparent — you never write the provider-native shape.

BuiltinTool type definition:

interface BuiltinTool {
type: 'image_generation' | 'web_search' | 'code_interpreter' | 'file_search' | 'mcp';
params?: Record<string, unknown>;
}

params is a pass-through — values are merged into the provider’s native tool entry before sending.

import { complete } from '@combycode/llm-sdk';

// Builtin (server-side) tools now pass straight through complete() — no executor
// needed. The SDK maps `code_interpreter` to each provider's code-execution tool.
const t0 = performance.now();
const { text } = await complete({
  model: process.env.LLM_MODEL!,
  apiKey: process.env.LLM_API_KEY,
  prompt: 'Compute 12345*6789 using code and tell me the result.',
  tools: [{ type: 'code_interpreter' }],
  maxTokens: 1024,
});

console.log(JSON.stringify({ result: text.trim(), ms: Math.round(performance.now() - t0) }));

The structural difference: Anthropic’s built-in tool types are named computer_20250124, bash_20250124, and text_editor_20250124 with required width/height/action fields. OpenAI uses code_interpreter (no extra fields). Google uses { codeExecution: {} }. ORXA exposes one generic type name, maps it per-provider before sending, and handles the built-in tool’s result (code output, search snippets) without any client-side processing.

Not every provider supports every built-in. file_search is OpenAI-only. image_generation requires specific model support. If you pass an unsupported built-in to a provider that does not implement it, the request will fail at the provider with an API error. Test your model/provider pair before deploying.

Built-in tools can add cost. Code interpreter and file search calls have per-call or per-query pricing on top of the base token cost. Check provider pricing pages for current rates.

Built-in results appear inline in text. Unlike client tools that produce a discrete tool result message, built-in tools’ outputs are often embedded in the model’s final text reply. There is no separate structured result field.

execute is never called for built-ins. Internally, ORXA wraps BuiltinTool as an AgentTool with a no-op execute: async () => ''. If the provider somehow routes the call back to the client (misconfigured provider), the no-op fires and the model receives an empty result.

Next steps:

  • Web search — dedicated web search example with citation handling
  • MCP tools — connect external tool servers via Model Context Protocol
  • Single tool call — client-side tools with defineTool