---
question: Does an agent remember earlier messages in the same thread?
kind: task
via_web: available
via_cli: available
via_python: available
via_api: available
via_config: na
ref_web: Chat
ref_cli: abi chat
ref_python: Agent.invoke
ref_api: POST /agents/{agent_name}/completion
prereq: A project with at least one agent. Nexus and the REST API also need ABI running, with `abi dev up` or `abi stack start` (see the [Quickstart](/user-guide/get-started/quickstart#4-start-it)).
next:
  - /capabilities/build/agents/test-an-agent
  - /capabilities/build/agents/enable-in-a-workspace
  - /capabilities/build/agents/edit-prompt-and-model
---

# Chat with an agent

Every agent the engine loads can be reached from the Nexus chat, from `abi chat` in a terminal, from Python with `invoke`, and from its REST route. A conversation is a thread: the agent remembers the earlier messages of the same thread.

## Web UI

### Turn the agent on

In the workspace, open Settings › Agents and check **Enabled** on the agent's row. The chat only offers enabled agents. See [Enable in a workspace](/user-guide/build/agents/enable-in-a-workspace).

### Start a conversation

Open **Chat** in the sidebar and click **New Chat** (Ctrl+I), or use File › New Chat.

### Pick the agent

Open the agent picker in the message box. With **Auto** on, the message goes to the workspace's default agent. Picking an agent turns **Auto** off: the default agent is under **Agents**, the others under **Custom**. An agent that can run several models lists them under its name; pick one.

![Chat with the agent picker open](/abi/Screenshot_Agent_Picker.png)

*The agent picker in the message box: Auto, the default agent under Agents, and the workspace's other agents under Custom.*

### Send a message

Type in **Send a message...** and press Enter. Shift+Enter adds a line. The answer streams in, and the tools the agent calls show as it calls them.

:::tip Skills
Type `/skills` to list the workspace's skills, and `/<slug>` to run one. See [Skills](/user-guide/build/skills/overview).
:::

## CLI

### Open a chat

From the project root:

```bash
abi chat                          # the default agent
abi chat my_module ReviewerAgent  # <module> <agent class name>
```

With no arguments it opens `default_agent` from `config.yaml`. Otherwise it loads that one module, whose entry is under `modules:`, and the agent whose class name you give; `abi agent list` prints both columns. A name that matches no class ends the command without a chat. `abi chat` serves the engine itself when none runs, and is a client of the running one otherwise: see [`abi chat`](/user-guide/reference/cli#abi-chat).

### Talk to it

Type a message and press Enter. Three commands are built in:

```text
/?               list the commands
/reset           start a new thread
/bye or /exit    quit
```

The conversation is also written to `storage/datastore/interfaces/terminal_agent/<timestamp>.txt`.

## Python

### Build the agent

`New()` asks the engine's model registry for its chat model, so load the engine first. `abi run script` loads it, then runs your file:

```python title="scripts/ask_reviewer.py"
from my_module.agents.ReviewerAgent import ReviewerAgent

agent = ReviewerAgent.New()
```

### Send messages

```python title="scripts/ask_reviewer.py"
print(agent.invoke("Summarize the open review comments."))
print(agent.invoke("Now group them by author."))  # same thread: it remembers the first message

agent.reset()  # start a new thread
```

`invoke(prompt)` returns the final answer as a string. `stream(prompt)` yields the agent's updates as it works.

### Run it

```bash
abi run script scripts/ask_reviewer.py
```

To load the engine in your own process instead, do what `abi chat` does:

```python
from naas_abi_core.engine.Engine import Engine

engine = Engine()
engine.load(module_names=["my_module"])
```

In a NATS project where an engine already serves the kernel services, set `ABI_ENGINE_ROLE=auto` first, as the CLI does. The default role, `serve`, fails to start next to a serving engine.

## REST API

### Call the agent's route

The API exposes every agent the engine loads:

```http
POST /agents/{agent_name}/completion
POST /agents/{agent_name}/stream-completion
```

`{agent_name}` is the agent's `name`, with characters other than letters, digits, `_` and `-` replaced by `_` (`Ontology Engineer` becomes `Ontology_Engineer`).

```bash
curl -X POST "http://localhost:9879/agents/Reviewer/completion" \
  -H "Authorization: Bearer $ABI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "Summarize the open review comments.", "thread_id": 1}'
```

The body is `prompt` and `thread_id`; send the same `thread_id` to continue a conversation. `completion` returns the answer. `stream-completion` sends it as server-sent events. Auth is `ABI_API_KEY`, as `Authorization: Bearer` or `?token=`. Port 9879 is the Docker stack's; under `abi dev up`, `abi dev ports` prints the API's. The shipped agents' routes are on [Agents](/api/processes/agents).

### Or go through Nexus

The Nexus chat calls `POST /api/chat/stream`, and `POST /api/chat/complete` returns the whole answer. Both take a Nexus session. The body holds `workspace_id`, `message` and `agent`, the agent's id from `GET /api/agents/?workspace_id=<id>`. With `stream`, an agent that is off in that workspace, or not in it, is replaced by the workspace's default agent. Agents of [remote modules](/user-guide/build/sdk/build-a-remote-module) have no engine route: reach them this way.

## Config

Not applicable. `config.yaml` sends no message: it names the default agent and [which agents a workspace offers](/user-guide/build/agents/enable-in-a-workspace?via=config).
