Async Tool Handle
also known as Async HandleId Pattern, Job-Handle Tool, Deferred Tool Result
Have a slow tool return a job handle immediately and expose a separate poll tool for the result, so the agent loop never blocks past a tool-call timeout.
Context
An agent reaches a tool that wraps slow work: a video render, a long database query, a third-party API that takes a minute to answer, or a batch job. The transport that carries the tool call enforces a short response deadline. Model Context Protocol clients, for instance, commonly abort a tool call after a few seconds and surface a timeout error to the agent.
Problem
A tool that waits for its slow work to finish before returning will breach the transport deadline, and the agent receives a timeout instead of a result. From the model's side the call simply failed, so it retries, fires the slow job again, or abandons the task. Meanwhile the agent loop is frozen on a single call and cannot make progress on anything else. Holding a synchronous connection open for the whole duration is fragile and wastes the turn.
Forces
- The transport caps how long one tool call may take, but the underlying work legitimately takes far longer than that cap.
- Returning fast keeps the loop responsive, yet the result still has to reach the agent once the work completes.
- Polling too eagerly burns turns and tokens on empty status checks; polling too lazily leaves the result stale.
- The handle must outlive the call that created it, so the slow work needs somewhere durable to run and store its outcome.
Example
An agent is asked to generate a marketing video. The render takes ninety seconds, but the tool transport aborts any call after seven. So the render tool returns a job id straight away, the agent moves on to drafting the caption, and a minute later it calls the poll tool with that job id, gets back the finished video, and attaches it. The slow render never blocked the loop and never tripped the timeout.
Diagram
Solution
Therefore:
Model the slow operation as two tools instead of one. The start tool validates the request, hands the work to a background worker or queue, and returns a job handle immediately, well inside the transport deadline. The background worker runs the job to completion and writes its status and result into a store keyed by the handle. A separate poll tool takes the handle and returns one of running, done with the result, or failed with an error. The agent calls the start tool, keeps working on other steps, and calls the poll tool when it needs the answer, treating a running reply as a signal to wait or do something else. Because the handle is durable, the result survives even if the agent run pauses or restarts between starting the job and collecting it.
What this pattern forbids. A slow tool must not block until its work finishes; the start tool may only return a handle, and the result is read solely through a separate poll call against that handle.
And the patterns that stand alongside it, or against it —
- alternative-toBlocking Sync Calls in Agent Loop✕— Anti-pattern: run synchronous, blocking I/O inside the agent loop or HTTP handler, capping concurrency at the number of OS threads.
- complementsAgent Resumption★★— Persist agent execution state so a long-running run survives restarts, deploys, or user disconnects.
- complementsInterruptible Agent Execution★— Treat pause, resume, and cancel as a first-class control surface on every long-running agent so users can halt expensive or off-track trajectories mid-task while state is preserved for resumption.
- complementsActor-Model Agents★— Implement each agent as an independent actor with its own mailbox, processing asynchronous messages one at a time and never sharing mutable state with peers.
Neighbourhood
Click any neighbour to follow the language. Scroll to zoom, drag to pan.