BetaServer tools are currently in beta. The API and behavior may change.
openrouter:subagent server tool lets a model delegate self-contained tasks to a smaller, cheaper, faster worker model mid-generation. When your model has a piece of work that doesn’t need its full capability (summarizing a document, extracting structured data, drafting boilerplate, reformatting text), it invokes the tool with a task_name and a task_description. The worker model executes the task and returns its result as the tool’s outcome, and your model continues, integrating the result.
The worker can be any OpenRouter model, and it can optionally run as a sub-agent with its own tools (for example openrouter:web_search). Each task is independent: the worker sees only the task description (not the parent conversation) and keeps no memory between tasks.
Quick start
Choosing the worker model
The worker model is resolved with the following precedence:parameters.modelon the tool definition, if set.- The model from the outer API request, as a fallback.
When does the model invoke it?
The tool’s description steers the model to delegate focused sub-tasks that don’t need its full capability, and to skip delegation for work that is faster to do directly than to describe. Because the worker has no access to the parent conversation, the model is instructed to include all relevant context and the expected output format in thetask_description.
Parameters
Pass an optionalparameters object on the tool entry:
Tool-call arguments
When invoking the tool, the model passes:What the tool returns
On success the tool result contains the outcome text, the task name, and the model that produced it:status: "error" with a message; the calling model continues without the outcome:
Worker tools
When you passtools, the worker runs as an agentic sub-agent over them before producing its outcome. For example, giving the worker openrouter:web_search lets it ground its result in fresh sources. The worker’s tool use happens inside the tool call; only its final text is returned to your model.
Nested tools must be OpenRouter server tools (for example openrouter:web_search or openrouter:web_fetch). Client function tools ({ "type": "function" }) placed directly in the nested tools array are rejected with a 400. See Inheriting Client Function Tools.
Inheriting Client Function Tools
ExperimentalClient function inheritance and the suspension/replay contract below are experimental and subject to change without notice. They are supported on the Responses API (
/api/v1/responses) only; requests on other APIs that set inherit_functions or inherited_function_names are rejected with a 400.inherit_functions: truegives the worker every function tool in the request’s top-leveltoolslist.inherited_function_namesallows you to define an array of names. Each tool with a matching name is copied fully into the worker’s tools. The list is ignored wheninherit_functionsistrue(everything is already inherited), and a listed name that matches no top-level function tool is rejected with a400.
What happens when a subagent calls a local tool
When the subagent calls an inherited client tool, its run pauses and the response’s turn ends (it is possible for the subagent to also call multiple tools in parallel). The response output contains:- The spawning
openrouter:subagentitem withstatus: "in_progress". It carriescall_id(the id of the tool call that spawned the worker) plus thetask_nameandtask_description, which are both generated and visible to the model. - The subagent’s pending calls, projected as standard
function_calloutput items that additionally carry two attribution fields:
A suspended response looks like this in the Responses API:
subagent_id.
Replaying to resume the worker
To preserve subagent state when returning the output offunction_call items, you must send the conversation back:
- The
openrouter:subagentitem, verbatim. - Every projected
function_callitem exactly as returned, withsubagent_idandsubagent_itemsintact, in the order you received them. - One
function_call_outputitem per projected call, matched bycall_id. (No change from non-subagentfunction_call_output.) - The same
toolsarray. Theopenrouter:subagententry that spawned the worker must still be present, and the order ofopenrouter:subagententries must stay stable across requests — instance identity is positional.
openrouter:subagent item — a new item with a fresh id but the same call_id — carrying its outcome, and the delegating model continues with the outcome text in its context:
openrouter:subagent item is announced once and is not restated, so keep the copy you already have. On each subsequent replay, include the full history — the suspended item, every projected call from every round with its function_call_output — plus the new round’s calls and outputs. While any worker is still working, the delegating model does not resume: it continues only once all of its workers have settled.
The cost of resumed worker runs folds into the usage reported on the request that resumed them, the same way live worker runs fold into their own request’s usage.
Streaming
Withstream: true, the suspension surfaces through the standard Responses SSE events with one contract worth knowing:
- The suspended
openrouter:subagentitem’sresponse.output_item.addedevent is deferred until the spawning tool call’s arguments finish streaming, and arrives fully enriched — it already carriescall_id,task_name,task_description, andname/instance_namewhen set — so you can rebuild your replay history from per-item events alone. A suspended item never receives aresponse.output_item.doneevent in that response. - Each projected
function_callitem streams normally. Itsresponse.output_item.addedevent carriessubagent_idfor early attribution; the potentially largesubagent_itemstranscript rides only theresponse.output_item.doneevent and the finalresponse.completedsnapshot. - On a later round, a worker that completes is announced as a new item (fresh
id, samecall_id) with a normalresponse.output_item.addedandresponse.output_item.donepair.
Failure handling
A failed worker never fails the response. In every failure case below, the affected worker degrades to astatus: "error" tool result; the delegating model sees the error and continues:
- The suspension cannot be delivered (for example, the worker’s transcript cannot be serialized for replay).
- A replayed worker cannot be resumed — its item is missing
call_idor the task echo, its projected calls or theirsubagent_itemswere not replayed, a projected call has nofunction_call_output, or the spawningopenrouter:subagententry was dropped fromtools.
function_call with an invalid or mismatched subagent_id (i.e. there is no corresponding openrouter:subagent item) is rejected with a 400.
Recursion protection
The subagent tool cannot invoke itself. Two guards enforce this:- A self-reference check rejects a subagent entry inside the subagent’s own
toolsarray (and rejects the subagent tool name as the workermodel). - Each inner subagent call carries an
x-openrouter-subagent-depthheader; the subagent tool is stripped from any sub-call, so a worker can never re-enter the subagent.
Related
- Advisor server tool. Consult a stronger model for guidance
- Fusion server tool. Multi-model deliberation
- Web Search server tool