# Agents

> What an agent is, how to author and configure one, and how a conversation with it fits together from your server to your user's device.

An **agent** is a character you write once and your users talk to many times, by text or by voice. You describe who it is, where the conversation happens, how it speaks, what it is trying to do and what it must not do. The API holds every conversation, so each turn carries only the new message. The reply streams back as text and, if the agent speaks, as audio.

```bash title="curl"
curl https://api.lumavox.ai/v1/agents \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Mira",
    "personality": "A patient travel guide who has lived in Lisbon for twenty years.",
    "environment": "A chat on a travel booking site.",
    "tone": "Warm and brief. Two or three sentences unless asked for more.",
    "goal": "Help the traveller plan their first three days.",
    "guardrails": "Never quote prices or make bookings.",
    "first_message": "Olá! Is this your first time in Lisbon?",
    "voice_enabled": true,
    "voice_config": { "voice_id": "default" }
  }'
```

```json title="Response — 201 (abridged)"
{
  "id": "0193b1e2-6c1d-7a4e-9f20-5d8a3c2b1e07",
  "name": "Mira",
  "model": "gemini-3.1-flash-lite",
  "version": 1,
  "voice_enabled": true,
  "first_message": "Olá! Is this your first time in Lisbon?",
  "first_message_generated": false,
  "thinking_level": null,
  "created_at": "2026-10-24T09:14:03.000Z",
  "updated_at": "2026-10-24T09:14:03.000Z"
}
```

The agent comes back with every field it has, `null` for each setting you left unset. The full shape is in the [agents reference](https://docs.lumavox.ai/reference/agents.md).

`GET /v1/agents` lists your agents, newest first, each with `sessions`, `turns` and `last_used_at` beside its settings. They come in one page, with `next_cursor` always `null` ([Conventions](https://docs.lumavox.ai/conventions.md#lists-and-pages)). `GET /v1/agents/{agent_id}` reads one.

## Who the agent is

Five prose fields describe the character. They are joined into one system instruction in a fixed order. A field you leave empty is left out entirely rather than sent blank.

| Field | What it holds |
|---|---|
| `personality` | Who the agent is: character, background, quirks. |
| `environment` | The setting the conversation takes place in. |
| `tone` | How it speaks: register, pacing, how much it says. |
| `goal` | What it is trying to achieve in the conversation. |
| `guardrails` | What it must not do or discuss. |

`name` is for you and your dashboards. It is never sent to the model.

## The opening line

`first_message` is what the agent says first. With `first_message_generated` on, the same field is a *direction* instead, such as "say hello and catch up with them". The model then writes the line fresh each time and can use what it remembers about the person. A scripted line costs nothing. A generated one is a billed model call.

Either way, the opening line is the agent's **first turn on the WebSocket**. It streams and is spoken like every other reply. Opening a session does not produce it.

The agent does not greet twice. A conversation continued within a quiet period gets no fresh opening line, and the socket's `ready` frame says which will happen (see [The WebSocket](https://docs.lumavox.ai/agents/websocket.md)). The quiet period is `resume_greeting_after_minutes` in your [organisation's defaults](#organisation-wide-defaults), else the platform's `agents.greeting.resume_after_minutes` ([Limits](https://docs.lumavox.ai/limits.md)).

`first_message_generated` needs a `first_message` to act on. Turning it on with the text empty is a 422.

## Switches

| Field | What it does |
|---|---|
| `voice_enabled` | Replies come back as audio as well as text. A client can override it for one turn with `speech` on the message. |
| `voice_config` | The voice: `voice_id` from `GET /v1/voices`, `model` (`eleven_flash_v2_5`, the default, or `eleven_multilingual_v2`), `sample_rate` (8000, 16000, 22050, 24000 or 44100; 24000 when unset) and `provider_options` (stability, similarity, style, speed). `eleven_v3` is refused with 422 on a speaking agent: it cannot stream over the socket. |
| `emotion_enabled` | Each reply reports how the agent feels. The mood arrives as a `mood` event and is stored on the message. It costs about six output tokens per turn. |
| `relation_enabled` | The agent keeps a standing relationship with each person (warmth, trust, how well they know each other) across every conversation. Read it with `GET /v1/agent/relations`. |
| `knowledge_enabled` | Whether the agent may use the [knowledge](https://docs.lumavox.ai/agents/knowledge.md) assigned to it. **On by default.** Turning it off hides the entries without unassigning them. |
| `stt_config` | How a spoken turn is transcribed: `language` (detected per turn when unset), `sample_rate` of the PCM your client sends, `model` and `mark_spoken`. A client can override the first three per recording. |
| `model`, `thinking_level`, `thinking_summaries`, `max_output_tokens` | The Gemini model and how it thinks. The default model is the platform's `agents.model` ([Limits](https://docs.lumavox.ai/limits.md)). |
| `stream_chunk_schedule` | How a streamed reply is cut into pieces for speech, smallest first, for example `[60, 160, 250]`. The first number decides how much text must arrive before the agent starts talking. Below about 50 characters, speech starts sooner but can stutter. |

The compaction and memory fields (`compact_threshold_tokens`, `extract_facts_on_compact`, `facts_enabled`, `facts_scope`, `max_facts` and the instructions) are covered in [Conversations and memory](https://docs.lumavox.ai/agents/conversations.md).

## Edit or delete an agent

`PATCH /v1/agents/{agent_id}` is a partial update. Fields you omit are left alone, and an explicit `null` clears one.

```bash title="curl"
curl -X PATCH https://api.lumavox.ai/v1/agents/$AGENT_ID \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "tone": "Playful, and a little more talkative.", "expected_version": 1 }'
```

- **The whole agent is checked on every save.** A `thinking_level` the model refuses, a generated opening with no direction, or a speech schedule out of order is a 422 naming the problem, whichever field you changed.
- **Send `expected_version`** (the `version` you last read) to be refused with 409 if somebody else saved the agent since. Nothing is written in that case.
- **Conversations already open pick up the change within about a minute**, from their next turn. There is nothing to reopen. That also means somebody mid-conversation is now talking to the edited agent.

`DELETE /v1/agents/{agent_id}` deletes the agent and every conversation with it, and answers **204** with no body. It cannot be undone.

Your plan caps how many agents your organisation holds. Creating one past the cap is a 409.

## Organisation-wide defaults

`GET /v1/agents/settings` returns what every agent falls back to when it sets nothing of its own. The chain is the agent, then your organisation, then the built-in default. The built-in text comes back alongside each field, so you can show what leaving it empty means.

`PUT /v1/agents/settings` changes them. It needs `agent:write`. Omitted fields are left alone, and `null` returns one to the built-in default.

| Field | What it sets |
|---|---|
| `default_emotion_instruction`, `default_relation_instruction`, `default_fact_instruction`, `default_compact_instruction` | The instructions agents use when they set none of their own. |
| `default_stream_chunk_schedule` | The speech chunk schedule for agents that set none. |
| `resume_greeting_after_minutes` | How long a conversation must be quiet before the agent greets the person again. `0` means always greet. 15 when unset. |
| `resume_max_age_days` | How old a person's last conversation may be and still be continued rather than replaced. `0` means never continue. 7 when unset. |

The response also lists `moods`: every mood label the API accepts. If you override the mood instruction, name these labels. The API strips a first line shaped `mood: <label> <intensity>` and records a mood only for a label it knows, so an instruction asking for any other shape leaves the line in the reply.

A change reaches open conversations within about a minute, as an edit to an agent does. `resume_greeting_after_minutes` is read when a socket connects, so it applies from the next connection.

## Scopes

| Scope | Lets an API key |
|---|---|
| `agent` | List and read agents and the defaults, manage [end users](https://docs.lumavox.ai/agents/end-users.md), read and search knowledge, read [tools](https://docs.lumavox.ai/agents/tools.md). |
| `agent:write` | Create, edit and delete agents, set the defaults, write knowledge and tools. |
| `tokens` | Mint, list and revoke [ephemeral keys](https://docs.lumavox.ai/agents/end-users.md#ephemeral-keys). |

**An API key cannot talk to an agent.** Conversations run only on an end user's ephemeral key: an API key gets 403 on `/v1/agent/*` and close code `4002` on the socket.

## How a conversation fits together

1. **Your server finds or creates the person.** `POST /v1/end-users` with your own `external_id` returns the same end user every time. See [End users and their keys](https://docs.lumavox.ai/agents/end-users.md).
2. **Your server mints an ephemeral key for them.** `POST /v1/ephemeral-keys` with the end user and a `credit_limit_micros`. Hand only the token to their device. Your API key never leaves your server.
3. **The device opens a session.** `POST /v1/agent/sessions` with the token continues the person's recent conversation with this agent, or starts a new one. See [Conversations and memory](https://docs.lumavox.ai/agents/conversations.md).
4. **The device connects to the socket** at `wss://api.lumavox.ai/v1/agent/stream?session_id=…`, with the subprotocol `ino.v2` and an `auth` frame first. See [The WebSocket](https://docs.lumavox.ai/agents/websocket.md).
5. **The person talks.** Typed or spoken turns go up; text, audio, mood and usage come back as the reply is written.
6. **Memory happens after the reply.** Facts about the person and the relationship carry into every later conversation with any of your agents — unless an agent remembers nothing, or keeps what it learns to itself.

## Next

- [End users and their keys](https://docs.lumavox.ai/agents/end-users.md)
- [Conversations and memory](https://docs.lumavox.ai/agents/conversations.md)
- [The WebSocket](https://docs.lumavox.ai/agents/websocket.md)
- [Knowledge](https://docs.lumavox.ai/agents/knowledge.md)
- [Tools](https://docs.lumavox.ai/agents/tools.md)
- [Agents reference](https://docs.lumavox.ai/reference/agents.md)
