Skip to main content
The agent node runs a language model that can call integration tools and loop until it reaches a final answer, all inside a single workflow step. Where the LLM node makes exactly one model call, the agent node binds a set of tools to the model and repeatedly lets the model decide whether to call a tool or finish — a manual tool-calling loop bounded by max_iterations. Use it when a step needs to gather information or act through tools before answering — for example “find the three most relevant GitHub issues and summarize them” or “search the web, then draft a reply.” When you want deterministic control over a single tool call instead, use the tool node; when you want generation with no tools, use the LLM node.
The agent node is the in-workflow agentic step. It is distinct from the standalone Assistant, which is a workflow-independent agentic chat. They share the same idea — a model that loops over tools — but the agent node runs as one node in a compiled workflow graph and writes its result into run state, while the Assistant is its own chat surface.
The result of the loop is written into run state under the node’s own id, the same convention every node follows. To pass data into the agent’s prompt and tools, use {{node_id.field}} references — the same reference system documented in variables & references and the workflow engine.

What the node does

When the engine compiles your workflow, the agent node is turned into a single async step (workflow engine). At run time the node:
  1. Initializes the model from llm and binds the configured tools to it (so the model can emit tool calls). If tools is empty, the model runs with no tools bound — effectively a one-shot LLM call inside the loop.
  2. Resolves system_prompt against the current run state, replacing every {{...}} token with its resolved value.
  3. Builds the user message from the first of these that is set: prompt_template (deprecated), then input_mapping, then input_keys (deprecated), then the run-state input field. The agent’s user message must not be empty (see errors).
  4. Enters the tool loop, up to max_iterations times:
    • Calls the model with the running message list.
    • Records token usage for billing (managed usage only — see credit impact).
    • If the model returns no tool calls, the loop ends and the model’s content becomes the result.
    • If the model returns tool calls, the node executes each one, appends the tool result as a tool message, and loops again.
  5. Writes the final content into run state under the node’s id.

The manual tool loop

The agent node runs its own loop rather than delegating to a framework agent executor. Each iteration is one model call plus zero or more tool executions:
1

Model call

The model is invoked with the current message list (system message, the user message, and any tool messages from previous iterations). Token usage is recorded after every call.
2

Tool-call check

If the response contains no tool calls, the loop stops and the response content is the node’s result. If it contains tool calls, each call is executed in turn.
3

Tool execution

For each tool call, the node looks up the bound tool by name, merges in any parameter_defaults for that tool (only when the model did not already supply that argument), and invokes the tool. The tool’s output is appended to the message list as a tool message so the model sees it on the next turn. A tool that raises is caught: the error text is appended as the tool message (prefixed Error:) so the model can react, rather than failing the node.
4

Loop or finish

The loop repeats from the model call until the model returns no tool calls, or until max_iterations is reached.
If the model’s final content looks like a JSON object (it starts with {), the node parses it into an object; otherwise the content is stored as a string.

Stop conditions

The loop ends on exactly one of these:
  • The model returns no tool calls. This is the normal finish: the model’s content becomes the result.
  • max_iterations is reached. The loop stops even if the model still wanted to call a tool. The result is the content of the last message in the conversation — which may be a partial answer or a tool result rather than a clean final response. Size max_iterations to the task (see the field reference below).
Reaching max_iterations is not an error — the node still returns and the run continues. But the returned value may be incomplete because the model was mid-task. If your downstream logic depends on a finished answer, raise max_iterations, simplify the task, or validate the output with a guardrails node.

Configuration (AgentNodeConfig)

These fields live on the node’s agent_config. In the builder you set them through the detail panel; over the API they appear inside the node definition (the builder also accepts a wrapped {config: {...}} form, which the backend normalizes to agent_config).
LLMConfig object
required
The model the agent reasons with and calls tools through. Required. See the llm object below for its fields. This selects both the provider (managed or BYOK) and the specific model. The model must support tool calling for tools to be useful.
ToolDefinition[]
default:"[]"
The integration tools available to the agent. Optional; defaults to an empty list. Each entry is a ToolDefinition identifying an integration and action. The agent decides when and how to call them. With no tools, the node behaves like a single LLM call wrapped in the loop. See using integration tools and the tool node for the same ToolDefinition shape.
string
required
The system message that sets the agent’s role, goal, and how it should use its tools. Required — unlike the LLM node, the agent node requires a system prompt. Supports {{node_id.field}} and {{input}} references. Write it to tell the model what tools it has and when to stop.
string
The human message — the actual task. Optional. Supports {{node_id.field}} and {{input}} references. The agent builds its user message from the first source that is set, in this order: prompt_template (deprecated), input_mapping, input_keys (deprecated), then the run-state input field. Provide a user_prompt or an input_mapping so the agent has a task; an empty user message raises an error.
object
default:"{}"
A map of named inputs resolved from run state with {{node_id.field}} references. Optional. When the agent has no prompt_template, the resolved mapping becomes the user message: a single entry is passed as its value; multiple entries are formatted as key: value lines. None and empty-string values are skipped during resolution. Use this to feed structured upstream data into the agent.
integer
default:"10"
The maximum number of model calls in the tool loop. Optional; defaults to 10. Each model call is one iteration; a turn that triggers tool calls and loops counts as one iteration. The loop stops when the model returns no tool calls or when this limit is hit. Higher values let the agent take more steps but cost more (every iteration is a billable model call for managed models).
These fields exist on AgentNodeConfig for backward compatibility and are normalized away or ignored. Author new workflows without them.
string
deprecated
Deprecated. Use user_prompt instead. If prompt_template is set and user_prompt is not, the backend copies prompt_template into user_prompt automatically. When present, prompt_template takes priority as the agent’s user message.
string[]
deprecated
Deprecated. Use input_mapping (or {{node_id.field}} references in user_prompt) instead of listing state keys. When used, the listed state values are concatenated with spaces into the user message.
string
deprecated
Deprecated. Output is always stored under the node id. This field is ignored for routing.

The llm object

The llm field is an LLMConfig. It is required and identifies the provider, the model, and (optionally) which stored credential to use. It is the same object the LLM node uses.
string
required
The provider integration on the wire. Required. Use modulexai for ModuleX-managed models (billed in credits). For BYOK, use the provider integration name — for example anthropic, openai, gemini, or xai. See LLM providers and managed vs BYOK.
string
required
The underlying provider id. Required. For example anthropic, openai, gemini, xai, or — for managed routing — openrouter. Each model in a provider catalog declares its own provider_id; match it for the model you pick.
string
required
The standardized model id, for example claude-sonnet-4.6, claude-haiku-4.5, or gpt-5.4-mini. Required. ModuleX maps this id to the provider’s served model. Pick a model that supports tool calling. Models marked deprecated or in maintenance are automatically routed to their replacement for managed integrations. Browse available ids on each provider page.
number
default:"0.4"
Sampling temperature passed to the model. Optional; defaults to 0.4. Lower values make the agent’s decisions more deterministic; higher values make them more varied.
string
A specific stored credential to use for the model calls. Optional. If omitted, ModuleX resolves a credential for the integration in the current organization. Required in practice for BYOK providers (you must have connected your own key). See managing credentials.

The tool objects

Each entry in tools is a ToolDefinition. The same shape is used by the tool node, with one key difference: the agent node uses parameter_defaults only and ignores parameter_overrides. The agent chooses arguments autonomously; defaults fill in only what the model did not supply. If you need to force exact argument values, use a tool node instead.
string
required
The integration the tool belongs to, for example tavily or github. Required. See the integrations overview and the catalog.
string
required
The action/tool within the integration, for example web_search or create_issue. Required.
string
A specific stored credential to use for this tool. Optional. If omitted, ModuleX resolves a credential for the integration in the current organization. See managing credentials.
object
Default argument values for the tool, applied only when the model does not supply that argument. Optional. Supports {{node_id.field}} references, which are resolved against run state before the tool is called. This is the only parameter mechanism the agent node honors.
object
deprecated
Ignored by the agent node. Optional and present only because the ToolDefinition shape is shared with the tool node, which does honor overrides. To force argument values in a workflow, use a tool node.

Retry configuration

The agent node is retry-wrapped at the node level. You can attach a retry_config to the node definition itself (not inside agent_config) to control how a failed node execution is retried. If you omit it, the engine applies its default retry policy (2 retries). Errors are only retried when their type is in retry_on_error_types.
integer
default:"3"
Total attempts including the first. Range 1–10. 1 means no retry; 3 means the initial attempt plus 2 retries.
number
default:"1.0"
Seconds to wait before the first retry. Range 0.1–60.
number
default:"2.0"
Multiplier applied to the delay between successive retries (exponential backoff). Range 1–5.
string[]
Exception type names that trigger a retry. Errors not in this list fail immediately. A credit-exhaustion stop is not retried.
Retry applies to the whole node execution, not to a single tool call inside the loop. A tool that raises mid-loop is caught and reported back to the model as a tool message (prefixed Error:) instead of failing the node — so a single bad tool call does not trigger a node-level retry. See error handling & retries.

Inputs and outputs

Inputs

The agent node has no fixed input fields. It reads whatever you reference in system_prompt, user_prompt/input_mapping, and each tool’s parameter_defaults from run state:
  • {{node_id}} — the entire output of an upstream node (typed value: string, object, or array).
  • {{node_id.field}} — a nested value via dot/bracket path, for example {{search_1.results[0].url}}. An out-of-range index or missing key resolves to nothing.
  • {{input}} — the run’s top-level input field.
A reference that is the entire string keeps its native type; a reference embedded inside other text is string-substituted (objects/arrays are JSON-encoded). During input_mapping resolution, None and empty-string values are skipped. See variables & references for the full resolution model.

Outputs

The node writes one value into run state under its id:
string | object
The agent’s final content.
Downstream nodes read this with {{node_id}} (whole value) or {{node_id.field}} (a field of a parsed object).
Intermediate tool calls and tool results live only inside the agent’s loop; they are not written to run state as separate fields. Only the final content is stored under the node id. If a downstream step needs a specific tool result deterministically, run that tool as a separate tool node instead.

Streaming

An agent node streams at the node level over SSE, like other workflow nodes. The model’s per-iteration tool calls and tool results are not streamed as separate run events; you receive one node_update when the node finishes its loop, carrying the node’s final output. On the wire this event is flat and uses the keys node and output — for example {type, node, output} — not the typed model field names. The run then continues to the next node and ends with a done event.
The realtime wire dicts differ from the typed event models: the node_update frame uses node and output, and done carries only a message. Parse each SSE frame as JSON and switch on its type field — there is no SSE event: line. Details on SSE run streaming.

Human-in-the-loop

The agent node itself does not pause for human input — it runs its tool loop to completion (or to max_iterations) and returns. To add a human approval or input step around an agent in a workflow, use a separate interrupt node, which pauses the run with a structured question and resumes after a person responds. The typical pattern is: agent node produces a draft, interrupt node asks “approve this?”, then a tool node acts on the approved result.
HITL inside the agentic loop — where the model itself can ask the user a question or request a credential mid-task — is a feature of the standalone Assistant, not the in-workflow agent node. For pause/resume semantics in workflows, see the interrupt node and human-in-the-loop resume.

Managed vs BYOK

The llm.integration_name you choose decides who runs the model and how it is billed. Tool execution itself is not a model cost — the model billing follows the same rules as the LLM node:

Managed (modulexai)

Set integration_name to modulexai. The model calls run through ModuleX-provisioned providers and are billed in credits by input/output tokens — once per iteration. No provider key of your own is required. See ModuleX-managed models.

BYOK (your own key)

Set integration_name to the provider (for example anthropic, openai, gemini, xai) and connect your own credential. Model usage is billed directly by that provider with no ModuleX markup and is not charged in credits (token usage is recorded for analytics only). See LLM providers and managing credentials.

Credit impact

There is no fixed per-node credit charge for an agent node. Charging is metered per model call, and the agent makes one model call per loop iteration:
  • Managed (modulexai) — each iteration’s model call records token usage and charges credits for input and output tokens. An agent that loops N times incurs N billable model calls, so a higher max_iterations (or a task that takes many tool steps) costs more. ModuleX measures usage in credits (the managed-usage billing unit).
  • BYOK — token usage is recorded for analytics, but no credits are charged; you pay your provider directly.
  • Tools the agent calls — an integration tool may have its own cost depending on the provider, but tool execution is not metered as ModuleX managed-model credits here. A managed-knowledge retrieval reached through a knowledge node is billed separately; see credits & metering.
Workflow runs go through the usage gate, which admits the run before it starts. The gate is best-effort once a run is executing: a billing problem mid-run surfaces as a node error rather than crashing the run silently. If an organization runs out of credits mid-run, the node’s error event carries a stable reason token (credit_exhausted) so clients can detect a budget stop deterministically. See usage gating & limits and credits & metering.
Workflow run, Composer, Assistant, and managed-knowledge surfaces are gated by the billing admission gate, which can return a DenialEnvelope as 402 / 403 / 429. The flat envelope shape is {code, layer, key, current, limit, reason}. See errors & status codes and usage gating.

Errors

The agent node surfaces failures through the run’s node-error event after node-level retries are exhausted. Common cases:
If an agent node has no agent_config, compilation fails with a configuration error (Agent node <id> missing agent_config). Ensure llm, system_prompt, and (usually) tools are set.
If none of prompt_template, input_mapping, input_keys, or the run-state input field resolves to non-empty text, the node raises with a message like Agent node '<id>' has empty input. Please provide prompt_template or input_mapping in agent_config. Provide a user_prompt or an input_mapping so the agent has a task.
A tool that throws is not a node failure: the node catches the exception and appends an error tool message (prefixed Error:) so the model can adjust on the next iteration. The node still returns a result. If a tool consistently fails and the model cannot recover, the agent may return a partial or apologetic answer — validate downstream, or move the call to a dedicated tool node where a failure surfaces as a node error.
Timeouts, connection failures, and HTTP errors from the model provider are retried per retry_config (defaults: TimeoutError, ConnectionError, HTTPError). When retries are exhausted, the node emits a node_error event with error_type, error_message, the attempt count, and recoverable: false, then the run fails. See error handling & retries.
If a managed model call cannot be billed because credits are exhausted, the node’s node_error event includes a stable reason token, credit_exhausted, so a client can match it without parsing free text. Resolve by topping up the wallet or upgrading your plan.
This is not raised as an error — the node returns the last message content (see stop conditions). If you need to treat an unfinished agent as a failure, check the output downstream with a conditional node or a guardrails node.
For the full taxonomy of error-envelope shapes and which surface emits each, see errors & status codes.

Full example

A research agent that searches the web and reads GitHub issues, then writes a short brief. The first tab shows the agent node definition as it appears in a workflow over the API; the next tabs run the workflow end to end with the SDKs.
Every request authenticates with Authorization: Bearer mx_live_… plus X-Organization-ID. See authentication and the run-a-workflow guide. To stream the run instead of waiting for the final state, see SSE run streaming and streaming & HITL in the SDKs.
The agent’s output shape depends on the model and your prompt. Asking for JSON in system_prompt makes the result parse into an object (so {{research_1.summary}} resolves), but it is not guaranteed — the model may return prose. Validate the shape with a guardrails node when downstream logic depends on it.

LLM node

Generate once with no tools, including structured JSON output.

Tool node

Call a single integration tool deterministically, with parameter overrides.

Interrupt node

Pause a run to ask a person for approval or input, then resume.

Assistant

The standalone agentic chat — agentic loop with HITL, no workflow required.

Variables & references

How {{node_id.field}} references resolve against run state.

Node types overview

All nine node types and how each writes its result into run state.