# Agents

Agents are AI assistants that can chat with users and execute tools.

## Defining Agents

```hcl
agent "assistant" {
  model       = models.anthropic.claude_sonnet_4
  personality = "Friendly, helpful, and concise"
  tools       = [
    builtins.http.get,
    tools.weather
  ]
}
```

## Attributes

| Attribute | Type | Description |
|-----------|------|-------------|
| `model` | reference | Model reference (e.g., `models.anthropic.claude_sonnet_4`) |
| `personality` | string | Personality traits for the agent — also serves as the agent's description when commanders pick which agent to delegate to |
| `tools` | list | Tools available to the agent (optional) |
| `reasoning` | string | Native reasoning level: `"low"`, `"medium"`, or `"high"` (optional) |

## Tools

Agents can use three types of tools:

### Built-in Tools

```hcl
tools = [
  builtins.http.get,       # HTTP GET
  builtins.http.post,      # HTTP POST
  builtins.http.put,       # HTTP PUT
  builtins.http.patch,     # HTTP PATCH
  builtins.http.delete,    # HTTP DELETE
]
```

### Custom Tools

Reference tools defined in `tool` blocks:

```hcl
tools = [
  tools.weather,
  tools.create_todo
]
```

### External Plugin Tools

Reference tools from loaded plugins:

```hcl
tools = [
  plugins.slack.send_message,
  plugins.github.create_issue
]
```

### MCP Server Tools

Reference tools from a declared `mcp "name"` server through the `mcp.<name>.*` namespace. Use `.all` to expose every tool the server provides:

```hcl
tools = [
  mcp.filesystem.read_text_file,   # single tool
  mcp.remote_api.all,              # every tool from that server
]
```

See [MCP Tools](/config/mcp_tools) for how to declare consumer-side MCP servers.

## Mission-Scoped Agents

Agents can be defined inside a `mission` block, making them available only to that mission. This is useful for specialized agents that don't make sense as global definitions.

```hcl
mission "research" {
  commander { model = models.anthropic.claude_sonnet_4 }

  agent "specialist" {
    model       = models.anthropic.claude_opus_4
    personality = "Deep domain expert"
    tools       = [plugins.shell.exec]
  }

  agents = [agents.global_helper, agents.specialist]

  task "gather" {
    objective = "Research the topic"
    # No agents attribute — task inherits the mission's list,
    # so both `global_helper` and `specialist` are available.
  }

  task "deep_dive" {
    objective = "Run the specialized analysis"
    agents    = [agents.specialist]  # Restrict this task to one agent.
  }
}
```

Mission-scoped agents use the same syntax and attributes as global agents. They must be listed in the mission's `agents = [...]` to be available — once listed there, every task in the mission can use them automatically. A task only needs its own `agents = [...]` attribute when you want to restrict that task to a different subset.

**Rules:**
- A scoped agent name must not conflict with any global agent name
- Two different missions can each define an agent with the same name (they are independently scoped)
- Multiple scoped agents per mission are supported

## Example: Specialized Agents

```hcl
agent "coder" {
  model       = models.anthropic.claude_sonnet_4
  personality = "Precise and methodical"
  tools       = [builtins.http.get]
}

agent "researcher" {
  model       = models.openai.gpt_4o
  personality = "Curious and thorough"
  tools       = [builtins.http.get]
}

agent "writer" {
  model       = models.anthropic.claude_sonnet_4
  personality = "Creative and articulate"
  tools       = []  # No tools, just conversation
}
```

## Built-in Tools

All agents automatically have access to result tools for handling large data:

| Tool | Purpose |
|------|---------|
| `result_info` | Get type/size of a stored large result |
| `result_items` | Get items from a large array |
| `result_get` | Navigate large objects with dot paths |
| `result_keys` | Get keys of a large object |
| `result_chunk` | Get chunks of large text |

When a tool returns a result larger than the configured threshold (default: ~16,000 tokens), it's automatically stored and a sample is shown. The agent can use these tools to access the full data without overwhelming context.

In mission context, `result_to_dataset` is also available to promote arrays to datasets.

## Tool Response Limits

You can configure the maximum token count for tool call responses before they're truncated and stored for paged access:

```hcl
agent "data_processor" {
  model = models.anthropic.claude_sonnet_4
  tools = [builtins.http.get]

  tool_response {
    max_tokens = 32000  # override the default 16,000 token limit
  }
}
```

| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| `max_tokens` | number | `16000` | Approximate max token count before a tool response is truncated/sampled. Hard maximum: `64000`. |

When a response exceeds `max_tokens`, it's stored in memory and the LLM receives a preview with metadata. The agent can then use `result_*` tools to access the full data.

The same setting is available on the mission commander:

```hcl
mission "example" {
  commander {
    model = models.anthropic.claude_sonnet_4
    tool_response {
      max_tokens = 32000
    }
  }
}
```

## Reasoning

Use the optional `reasoning` attribute to enable native provider reasoning ("extended thinking" on Anthropic, `reasoning_effort` on OpenAI, `thinking_config` on Gemini). Valid values: `"low"`, `"medium"`, `"high"`.

```hcl
agent "researcher" {
  model       = models.anthropic.claude_opus_4_7
  personality = "Methodical analyst"
  reasoning   = "high"
  tools       = [builtins.http.get]
}
```

The same attribute is available on the mission commander:

```hcl
mission "complex_orchestration" {
  commander {
    model     = models.anthropic.claude_sonnet_4_6
    reasoning = "medium"
  }
  agents = [agents.researcher]
  task "investigate" { objective = "Find the root cause" }
}
```

**Per-provider behaviour:**

| Provider | Reasoning-capable models | Reasoning events streamed? |
|----------|--------------------------|----------------------------|
| Anthropic | Claude 4 family (`claude-opus-4*`, `claude-sonnet-4*`, `claude-haiku-4*`) | **Yes** — thinking blocks streamed as `agent_reasoning_*` events |
| OpenAI | `o3*`, `o4*`, `gpt-5*` | **Yes** — reasoning summaries streamed via the Responses API (`/v1/responses`) |
| Gemini | Gemini 2.5+ and 3.x | **Yes** — thought parts streamed as `agent_reasoning_*` events |
| Ollama / OpenAI-compat proxies | Not auto-detected | No — Squadron can't tell which user-named local models support reasoning |

**Models that don't support native reasoning silently ignore the `reasoning` attribute** and log a warning at agent startup. They produce direct answers with no reasoning step; there is no chain-of-thought fallback.

**OpenAI / Ollama use the Responses API.** Squadron talks to OpenAI and OpenAI-compatible servers (Ollama, vLLM, LiteLLM) over `/v1/responses`, not the legacy `/v1/chat/completions`. The Responses API is what surfaces reasoning summaries on o-series and gpt-5 models. Ollama supports `/v1/responses` since v0.13.3 — older versions will need to be upgraded.

**Token budgets** (for providers that accept a budget): `low` ≈ 2 048 tokens, `medium` ≈ 8 192, `high` ≈ 24 576. For Anthropic, the provider clamps `max_tokens` upward when needed so the budget fits.
