Async Tool Dispatch
Tools marked with async: true return immediately with a taskId instead of blocking the agent loop. The tool executes in the background; the agent can check its result later using the built-in tool_poll tool.
How it works
- Agent calls an async tool
- A row is inserted into the
tool_taskstable withstatus: 'running' - The tool returns
{ taskId, status: "running" }instantly - Execution continues in the background
- The agent calls
tool_poll({ taskId })to retrieve the result when needed
Declaring an async tool
typescript
export const myTool: ToolDefinition = {
name: 'heavy_analysis',
description: 'Run a long analysis job',
async: true, // marks this tool as async
parameters: z.object({
dataset: z.string(),
}),
execute: async ({ dataset }, ctx) => {
// This runs in the background after the immediate return
return await runAnalysis(dataset)
},
}Immediate response shape
typescript
// What the agent receives immediately
{
taskId: "550e8400-e29b-41d4-a716-446655440000",
status: "running",
toolName: "heavy_analysis"
}tool_tasks table schema
sql
CREATE TABLE tool_tasks (
id UUID PRIMARY KEY,
session_id TEXT NOT NULL,
tool_name TEXT NOT NULL,
params JSONB,
status TEXT NOT NULL, -- 'running' | 'done' | 'error'
result JSONB,
error_message TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
); Use async dispatch for tools that take more than 2-3 seconds. Short tools (search, read file) should stay synchronous — async adds round-trip overhead from tool_poll calls.