deepAgent
Orchestrates a hierarchical multi-agent workflow. It takes a subgraph of connected subagent, tool, agentInput, and agentOutput nodes — compiled at runtime by DeepAgentCompiler — and executes the resulting agent. The main agent can invoke subagents via a task() tool call.
Cost tracking middleware wraps every LLM call and records per-call token and cost data. Execution runs in streaming mode (astream_events) or non-streaming mode (ainvoke).
Every run is bounded by five tunable ceilings on tool calls, subagent delegations, concurrency, and tool-calling rounds — see Agent Run Budgets.
Parameters
| Param | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Model identifier for the main agent (e.g. gpt-4o-mini) |
system_prompt | string | Yes | System prompt for the main agent |
messages | object[] | Yes | Conversation messages, each with role and content keys |
session_id | string? | No (default: null) | Multi-turn memory handle, threaded in from the agentInput node (e.g. {{ @agentInput.session_id }}). Lets the agent resume the same conversation across turns |
user_prompt | string? | No (default: null) | The current turn's user prompt, threaded in from the agentInput node (e.g. {{ @agentInput.user_prompt }}) |
response_format | object? | No (default: null) | JSON schema for structured output. When provided, the agent returns a structured_response key |
streaming | boolean | No (default: true) | When true, executes via astream_events and tracks call counts |
sandbox | boolean | No (default: false) | Opt this agent into the persistent code-execution sandbox (execute + file tools, filesystem persists across turns). Session mode only, and requires the sandbox backend to be enabled in the environment |
on_degraded | string | No (default: disclose) | Policy applied when a tool source fails to load or a subagent fails at runtime. disclose answers with an explicit caveat naming what was unavailable; refuse declines substantive sourced answers on topics that depend on it |
system_prompt is fixed once the workflow is saved, but a caller can extend it
for a single run: instructions on
POST /agent/{id}/responses
is appended after it, for that turn only, on this node only. Write the agent's
durable behaviour here and leave per-turn facts to the caller.
Run budgets
Five ceilings bound what one run may spend. Defaults are permissive — see Agent Run Budgets for how a breach behaves and how to tune them.
| Param | Type | Required | Description |
|---|---|---|---|
max_tool_calls | integer | No (default: 200) | Ceiling on total tool calls for the whole run — every agent, every tool, including task() calls themselves. Once reached, further tool calls are refused and the model must answer with what it has |
max_subagent_calls | integer | No (default: 50) | Ceiling on total task() delegations for the run. Once reached, only task() is refused; ordinary tool calls continue unless max_tool_calls is also spent |
max_concurrent_subagents | integer | No (default: 5) | Maximum task() invocations running at once. Excess calls queue (bounded — a call that waits too long is surfaced to the model as a degradation, never left hanging) |
max_tool_rounds | integer | No (default: 332) | Tool-calling rounds the main agent may complete before it must answer. Not graph steps — the LangGraph recursion_limit is derived from this and the agent's actual middleware stack |
subagent_max_tool_rounds | integer | No (default: 100) | Tool-calling rounds each compiled subagent may complete before it must answer, derived the same way |
Output
All fields returned by the compiled agent, plus a metadata field:
| Field | Type | Description |
|---|---|---|
metadata | object | Execution metadata (see below) |
| (any agent fields) | any | All fields returned by the compiled agent |
metadata object:
| Field | Type | Description |
|---|---|---|
total_cost | float | Total API cost in USD |
execution_time_seconds | float | Wall-clock time |
tool_calls_made | integer | Number of tool calls made |
subagent_calls_made | integer | Number of subagent calls made |
total_input_tokens | integer | Total input tokens consumed |
total_output_tokens | integer | Total output tokens produced |
llm_calls | object[] | Per-call breakdown with model, provider, context, tokens, and cost |
Example
{
"id": "deepAgentNode",
"type": "deepAgent",
"data": {
"label": "Deep Agent",
"isExecuted": false,
"handles": ["inputs", "outputs"],
"schema": {},
"params": {
"model": { "value": "{{ @agentInput.model }}", "isExpression": true, "isAttachedToInputNode": false },
"system_prompt": { "value": "{{ @agentInput.system_prompt }}", "isExpression": true, "isAttachedToInputNode": false },
"messages": { "value": "{{ @agentInput.messages }}", "isExpression": true, "isAttachedToInputNode": false },
"streaming": { "value": true, "isExpression": false, "isAttachedToInputNode": false }
},
"inputs": [], "outputs": [], "errors": []
},
"position": { "x": 300, "y": 0 },
"isSelected": false,
"isDragging": false
}
Subagents are connected to deepAgent via agent edges. Tools are connected via tool edges. These edges do not affect execution order — they are used by DeepAgentCompiler to wire the agent hierarchy.