# Agent node

The **Agent** node is the brain of Systalink Agent Builder. It calls an LLM with your instructions, reasons over the current input, optionally invokes tools, and emits text or structured JSON that downstream nodes can consume.

Every non-trivial workflow has at least one Agent. It is the only node that can decide *what to do next* with free-form input — every other Core node is a deterministic primitive.

---

## Overview

An Agent node takes:

- **Instructions** (your system prompt)
- **A user message** (built from `input`, the previous node's output, and optionally the chat history)
- **Tools** (optional — web search, MCP, file search, code interpreter, shell, image generation, function)
- **Output format** (text or JSON with a schema)

…and produces:

- `outputs.<node-id>.raw` — the model's text response
- `outputs.<node-id>.parsed` — parsed JSON (when **Output format** is JSON)

The runtime uses the OpenAI **Responses API** with `parallel_tool_calls: false` and follows function-call loops until the model returns a final answer.

---

## Model

Configurable from the node panel. Available models:

| Value | Notes |
| --- | --- |
| `gpt-5.5` | Highest quality, slower, most expensive |
| `gpt-5.4` | Strong general reasoning |
| `gpt-5.4-mini` | Default — fast and cheap |
| `gpt-5.4-mini-2026-03-17` | Pinned legacy build |
| `gpt-5.3` / `gpt-5.2` / `gpt-5.1` | Older snapshots |

You can also set **Reasoning effort** to `low`, `medium`, or `high`. Higher values let the model think longer before responding — useful for multi-step tool use or hard structured outputs, but they add latency and cost.

> Start with `gpt-5.4-mini` and `reasoning: low`. Bump only when evals show you need it.

---

## System prompt (Instructions)

The **Instructions** textarea is sent as the `instructions` field of the Responses API call. Write it like a job description: who the agent is, what it must do, what it must avoid, and what format the output should take.

Placeholders are interpolated at run time from the workflow context:

| Placeholder | Resolves to |
| --- | --- |
| `{input}` | The current input (chat message, webhook payload, or previous output) |
| `{event.body.<field>}` | A field from the triggering event (webhook body, schedule payload) |
| `{event.headers.<name>}` | A header from the triggering event |
| `{outputs.<node-id>.raw}` | The raw text output of an upstream node |
| `{outputs.<node-id>.parsed.<field>}` | A specific field from an upstream JSON output |
| `{state.<key>}` | A workflow state variable set by a Set State node |

Example:

```
You are a support triage agent for {state.tenant_name}.

The customer wrote:
{input}

Their previous ticket category was: {outputs.classify-1.parsed.classification}

Respond in the customer's language. Be concise (2-3 sentences).
```

---

## User message

The user message is built automatically from the runtime context — you usually do not write it. The order of precedence is:

1. The current chat message (when triggered from the chat preview)
2. The webhook or event payload
3. The output of the upstream node (`last_output`)

When **Include chat history** is on, the full conversation transcript is prepended so the agent has multi-turn context.

If no input is available and **Allow image input** is on, the runtime sends `"Analyze the provided image input and respond to the user."` so the model still has a prompt anchor.

---

## Output format

Two modes, selected from the **Output format** dropdown.

### Text

The model's free-form text is written to `outputs.<node-id>.raw` and to `last_output`. Use this for chat replies, summaries, or anything a human will read.

### JSON (structured output)

Selecting **JSON** opens a schema modal where you define the response shape. The runtime serializes it into a JSON Schema and forces the model to return strict structured output via the Responses API `text.format = json_schema` parameter.

Each property has:

- **Name** — the JSON key
- **Type** — `str`, `num`, `bool`, `enum`, `obj`, or `arr`
- **Description** — guides the model
- **Required** — toggle
- **Enum values** — only for `enum` types

The parsed result is exposed as `outputs.<node-id>.parsed`. Downstream nodes — especially **If/Else** and **Classify** — can reference fields directly:

```
{outputs.agent-1.parsed.intent}
{outputs.agent-1.parsed.confidence}
```

> **Prefer JSON whenever the next node needs to make a decision.** Free-text parsing is brittle; structured output is contractual.

---

## Include chat history

Toggle that controls `contextMode`:

- **On (default)** — `contextMode: "conversation"`. The full chat transcript is sent in the user message. Use this for chatbots, conversational copilots, anything multi-turn.
- **Off** — `contextMode: "input"`. Only the current input is sent. Use this for one-shot tasks: classifying a webhook payload, extracting fields from a document, processing a single record.

Turning chat history off makes runs cheaper, more deterministic, and easier to debug.

---

## Allow image input

When on, the runtime collects any image attachments from the current chat message or workflow input and forwards them to the model as `input_image` content items. The active model must support vision.

Use this for:

- Screenshot triage
- Receipt or invoice OCR
- Visual quality checks

If no text input is present, the runtime injects a fallback instruction so the model knows to describe or act on the image.

---

## Tools

Tools let the agent call out to the world. They are hosted by OpenAI, run in our sandbox, or invoked as local function-style tools that the model calls and your workflow handles.

Add tools from the **+** button next to the Tools row. Each tool produces a chip you can click to reconfigure.

| Tool | Hosted by | Use it for |
| --- | --- | --- |
| [Web search](/docs/tool-web-search) | OpenAI | Fresh information, current events, public docs |
| [File search](/docs/tool-file-search) | Systalink | Querying workflow documents, chat attachments, sandbox files |
| [MCP](/docs/tool-mcp) | Remote | Calling any [Model Context Protocol](https://modelcontextprotocol.io) server |
| [Code interpreter](/docs/tool-code-interpreter) | Systalink sandbox | Math, data wrangling, generating files |
| [Shell](/docs/tool-shell) | Systalink sandbox | Running CLI commands inside the sandbox |
| [Image generation](/docs/tool-image-generation) | OpenAI | Producing images from prompts (`gpt-image-1`) |
| [Function](/docs/tool-function) | Local | Custom function-style tool with a JSON schema you define |

Each tool needs a clear **Description**. The model uses the description (plus your instructions) to decide *when* to call the tool — vague descriptions lead to over-calling or no-calling.

> The runtime enforces `parallel_tool_calls: false`. The agent calls one tool at a time and waits for the result before proceeding. This makes traces easy to read.

---

## Output (downstream contract)

After execution, the Agent node writes:

```json
{
  "outputs": {
    "<node-id>": {
      "raw": "...",
      "parsed": { ... }
    }
  },
  "last_output": "...",
  "last_output_parsed": { ... }
}
```

Any downstream node — including another Agent — can reference these via placeholders.

---

## Best practices

**Write a focused system prompt.** One job per agent. Tell the model who it is, what it must produce, what it must avoid, and the output format. Resist the urge to cram unrelated tasks into a single agent — chain two agents instead.

**Prefer structured output for downstream nodes.** If the next node is `If/Else`, `Classify`, or another Agent that needs specific fields, switch to **JSON** mode and define a schema. Free-text parsing is a recipe for production bugs.

**Use tools sparingly.** Each tool adds latency, cost, and a way for the model to be wrong. Give the agent the minimum tool set it needs. If the agent never needs web search, do not enable it.

**Test with the chat preview before publishing.** Open the right-hand chat panel in the workflow editor and trigger your workflow with realistic inputs. Watch the tool-call trace, inspect the JSON, then iterate. Cheaper than learning in production.

**Pick the smallest model that works.** Start with `gpt-5.4-mini` and `reasoning: low`. Only escalate to a bigger model when you have an eval that proves it matters.

**Pin the model in production.** Use the date-pinned variant (e.g. `gpt-5.4-mini-2026-03-17`) once your prompt is tuned, so silent model upgrades cannot regress your behavior.

---

*Source: https://agentbuilder.systalink.sn/docs/node-agent — human documentation.*
*Other language: [/docs-md/fr/node-agent.md](/docs-md/fr/node-agent.md).*
*Machine-readable index: [/llms.txt](/llms.txt).*
