Skip to content

Input & output nodes

Every agent begins at an input node and ends at an output node. The input node carries whatever you pass to a run into the graph; the output node's value is what the run returns. Both are boundary nodes — they mark the edges of the graph and perform no work of their own. A fresh graph in the editor already contains one of each, wired together, so it passes validation and runs (echoing its input) from the start.

graph LR
  IN([input]) --> OUT([output])

The input node

The single entry point of the agent. The value you pass when you run the agent appears on its out port, ready for downstream nodes to read with $in. It is a boundary node and is never skipped — it has no inbound edges, so it always runs first.

Ports

Port Direction Required Description
out out Carries the entire run input to whatever is wired downstream.

An input node has no in-ports.

Configuration

Field Type Default Description
modality enum text The expected shape of the input: text, audio, image, video, json, or file.
schema JSON Schema null An optional description of the input's structure.

Both fields are declarative. They document what the agent expects and help the editor and triggers map an incoming payload — they are not enforced at run time. The value on out is exactly what was passed in.

Behavior notes

  • The whole input lands on out. Downstream nodes read it with the bare $in token (the default in-port). To pull a field out of a structured input, drill into it — $in.in.<field> — from a node that reads it. See Referencing inputs.
  • Composing several inputs. The input node has a single out port; it does not split values for you. When an agent needs to combine several upstream values — say a document and a question — you give the consuming node (typically an llm) more than one named in-port and wire a separate edge into each. That node then addresses them distinctly as $in.<port>. This is how multi-input agents work: a run input like {"path": "...", "question": "..."} fans out to nodes whose named ports each pick up their piece.
  • Triggers live here, not as nodes. When you select the input node, the inspector shows a read-only Triggers panel listing how this agent can be invoked (schedule, webhook, token). Triggers are added after saving the agent, not as graph nodes — see Triggers and webhooks.

Example

An input node feeding two downstream readers that each take a slice of a structured input:

graph LR
  IN([input]) --> A[tool: read file]
  IN --> B[tool: carry question]
  A --> LLM[llm]
  B --> LLM
  LLM --> OUT([output])
{
  "id": "n_in",
  "type": "input",
  "kind": "boundary",
  "config": { "modality": "json" },
  "ports": { "in": [], "out": [{ "id": "out" }] }
}

Works well with


The output node

The exit point. Whatever value reaches its in port is the run's canonical output — the value returned by the run and stored against it. It is a boundary node and performs no side effect; it just marks where the answer comes from.

Ports

Port Direction Required Description
in in yes The value that becomes the run's output.

An output node has no out-ports.

Configuration

Field Type Default Description
modality enum text The shape of the result: text, audio, image, or json.
schema JSON Schema null An optional description of the output's structure.

For an audio or image result the value is a reference to a produced artifact, not the raw bytes — see Audio & images.

Behavior notes

The output node has two rules worth knowing, because both surface as loud failures rather than silent surprises:

  • Exactly one in-port. An output node is a single-value consumer: it takes the value from one in-port. Declaring more than one in-port is a validation error — the editor will not let you save it, because which value is "the output" would be ambiguous.
  • At most one output may run per run. A graph is allowed to contain several output nodes — for example, a happy-path output and a refusal output on the two branches of a guardrail. But no more than one may actually execute in a single run. If two output nodes both go live, the run fails with a clear message: a second output node executed — the run output would be ambiguous. Route exclusive branches (with a router or a guardrail) so that exactly one output is reachable.
  • Empty output is honest. If the output node's in-port is fed only by a branch that was not taken — for example an upstream tool bound its err port and its success path was skipped — the run does not report a green empty success. It carries an honest error note explaining the upstream cause.

Example

A guardrail that routes to one of two outputs — a valid two-output pattern, because only one is ever live:

graph LR
  IN([input]) --> G{guardrail}
  G -->|pass| LLM[llm]
  LLM --> OUT([output: answer])
  G -->|block| REFUSE([output: refusal])
{
  "id": "n_out",
  "type": "output",
  "kind": "boundary",
  "config": { "modality": "text" },
  "ports": { "in": [{ "id": "in" }], "out": [] }
}

Works well with