Skip to main content
BetaServer tools are currently in beta. The API and behavior may change.
The 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:
  1. parameters.model on the tool definition, if set.
  2. The model from the outer API request, as a fallback.
Unlike the advisor tool, the delegating model does not choose its worker per call; the worker is fixed by the tool definition. The subagent tool itself can never be the worker model.

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 the task_description.

Parameters

Pass an optional parameters 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:
On failure the result has status: "error" with a message; the calling model continues without the outcome:

Worker tools

When you pass tools, 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.
The subagent can inherit the function tools you define at the top level of the request by setting either of the following parameters:
  • inherit_functions: true gives the worker every function tool in the request’s top-level tools list.
  • inherited_function_names allows 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 when inherit_functions is true (everything is already inherited), and a listed name that matches no top-level function tool is rejected with a 400.

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:subagent item with status: "in_progress". It carries call_id (the id of the tool call that spawned the worker) plus the task_name and task_description, which are both generated and visible to the model.
  • The subagent’s pending calls, projected as standard function_call output items that additionally carry two attribution fields:
A suspended response looks like this in the Responses API:
Execute subagent function calls exactly like ordinary function calls, but ensure that your client does not drop the extra fields added for replay bookkeeping. The delegating model may also call your functions directly in the same turn; those items carry no subagent_id.

Replaying to resume the worker

To preserve subagent state when returning the output of function_call items, you must send the conversation back:
  1. The openrouter:subagent item, verbatim.
  2. Every projected function_call item exactly as returned, with subagent_id and subagent_items intact, in the order you received them.
  3. One function_call_output item per projected call, matched by call_id. (No change from non-subagent function_call_output.)
  4. The same tools array. The openrouter:subagent entry that spawned the worker must still be present, and the order of openrouter:subagent entries must stay stable across requests — instance identity is positional.
OpenRouter detects the answered calls and resumes each suspended worker with your results injected. A worker that finishes produces a completed 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:
A resumed worker may also call a function tool again, in which case it suspends again — the loop supports multiple rounds. A suspend-again response carries the round’s new projected calls only; the suspended 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

With stream: true, the suspension surfaces through the standard Responses SSE events with one contract worth knowing:
  • The suspended openrouter:subagent item’s response.output_item.added event is deferred until the spawning tool call’s arguments finish streaming, and arrives fully enriched — it already carries call_id, task_name, task_description, and name/instance_name when set — so you can rebuild your replay history from per-item events alone. A suspended item never receives a response.output_item.done event in that response.
  • Each projected function_call item streams normally. Its response.output_item.added event carries subagent_id for early attribution; the potentially large subagent_items transcript rides only the response.output_item.done event and the final response.completed snapshot.
  • On a later round, a worker that completes is announced as a new item (fresh id, same call_id) with a normal response.output_item.added and response.output_item.done pair.

Failure handling

A failed worker never fails the response. In every failure case below, the affected worker degrades to a status: "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_id or the task echo, its projected calls or their subagent_items were not replayed, a projected call has no function_call_output, or the spawning openrouter:subagent entry was dropped from tools.
One exception: a replayed 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 tools array (and rejects the subagent tool name as the worker model).
  • Each inner subagent call carries an x-openrouter-subagent-depth header; the subagent tool is stripped from any sub-call, so a worker can never re-enter the subagent.
Task executions are also capped per request to bound cost and latency.