Tools

Batchable Tools

Tools that set batchable: true can implement an executeBatch() method. When multiple calls to the same batchable tool appear in a single round, the runtime routes them through executeBatch() instead of executing each call in parallel — enabling a single API request, database query, or I/O operation to handle all calls at once.

Declaring a batchable tool

typescript
export const lookupTool: ToolDefinition<{ id: string }, { name: string }> = {
  name: 'lookup_user',
  description: 'Look up a user by ID',
  batchable: true,
  parameters: z.object({ id: z.string() }),

  // Called when only one invocation exists in a round
  execute: async ({ id }) => {
    return await db.users.findOne(id)
  },

  // Called when multiple invocations exist in a round
  executeBatch: async (params) => {
    const ids = params.map(p => p.id)
    const users = await db.users.findMany(ids)
    return params.map(p => users.find(u => u.id === p.id) ?? null)
  },
}

Routing logic

The runtime calls executeBatch() only when all tool calls in a round target the same batchable tool. Mixed rounds (some batchable, some not) fall through to standard parallel execution.

Return shape

executeBatch() must return an array with the same length and order as the input params array. Index 0 of the result maps to params[0], etc.

Batchable tools are ideal for any I/O that supports multi-record requests: database lookups by ID, embedding API calls, external API calls with array endpoints. A single SQL IN (...) query is far cheaper than N individual lookups.