> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anonalabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat

> An OpenAI-compatible chat endpoint that automatically recalls and stores memory.

`POST /v1/chat/completions` is an OpenAI-compatible chat endpoint with memory built in.
On every request Anona retrieves the most relevant memories from the space, injects them
into the prompt, and stores the exchange back, so the conversation stays grounded in
what came before without any extra calls.

Point an existing OpenAI-compatible client at the Anona base URL and pick a space.

```python theme={null}
from openai import OpenAI

client = OpenAI(
    api_key="anona_live_YOUR_KEY",
    base_url="https://api.anonalabs.com/v1",
    default_headers={"X-Anona-Space-Id": "support-bot"},
)
```

## Request

```bash theme={null}
POST https://api.anonalabs.com/v1/chat/completions
Authorization: Bearer anona_live_...
Content-Type: application/json
```

```json theme={null}
{
  "model": "gpt-4o-mini",
  "space_id": "support-bot",
  "messages": [
    { "role": "user", "content": "What plan did I say I was on?" }
  ],
  "memory_limit": 5,
  "temperature": 0.7,
  "max_tokens": 512
}
```

| Field            | Type    | Default            | Description                                                                                                                                                                                                       |
| ---------------- | ------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `messages`       | array   | required           | Standard chat messages, each with `role` and `content`.                                                                                                                                                           |
| `model`          | string  | deployment default | Optional. Omit it to use whatever model this deployment serves; that is the recommended default. Naming a model the deployment does not serve returns `400 invalid_model`, and the message names the one it does. |
| `stream`         | boolean | `false`            | Stream the reply as server-sent events. See [Streaming](#streaming).                                                                                                                                              |
| `stream_options` | object  | none               | Streaming only. `{"include_usage": true}` appends the final usage chunk, exactly as on OpenAI. Omit it and no usage chunk is sent.                                                                                |
| `max_tokens`     | integer | none               | Optional.                                                                                                                                                                                                         |
| `temperature`    | float   | none               | Optional.                                                                                                                                                                                                         |

Fields Anona does not model (`top_p`, `n`, `stop`, `presence_penalty` and the rest of
the OpenAI request) are forwarded to the provider unchanged.

## Memory tunables

Every knob can be set in the body **or** as a header. The header form exists so a stock
client can set them once in `default_headers` and leave every call site alone; when both
are present, the body wins.

| Body field            | Header                  | Type             | Default     | Description                                                                                                                                                                                                                                                                                                    |
| --------------------- | ----------------------- | ---------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `space_id`            | `X-Anona-Space-Id`      | string           | `"default"` | Which space to recall from and store into. Omit it and the turn lands in a space literally named `default`, created on the first proxied turn if it does not exist yet, so a space you never created appears in your space list and in the dashboard. Set it once in `default_headers` to keep products apart. |
| `user_id`             | `X-Anona-User-Id`       | string           | none        | Scope the turn to one end user: it recalls only that user's memories and stores the turn under them. One space, many users. See [Scoping](/api-reference/retrieve#scoping-within-a-space).                                                                                                                     |
| `agent_id`            | `X-Anona-Agent-Id`      | string           | none        | Scope the turn to one agent.                                                                                                                                                                                                                                                                                   |
| `session_id`          | `X-Anona-Session-Id`    | string           | none        | Scope the turn to one conversation or run.                                                                                                                                                                                                                                                                     |
| `memory_limit`        | `X-Anona-Memory-Limit`  | integer, 1 to 20 | `5`         | How many memories to inject.                                                                                                                                                                                                                                                                                   |
| `memory_token_budget` | `X-Anona-Memory-Tokens` | integer          | none        | Approximate token cap for the injected block. Whole memories are dropped, lowest-ranked first, until it fits; the text is never truncated mid-sentence. The count is an estimate, not a tokenizer.                                                                                                             |
| `auto_record`         | `X-Anona-Auto-Record`   | boolean          | `true`      | Store this turn back into the space. Set `false` for read-only turns, such as evaluating against a space without polluting it.                                                                                                                                                                                 |
| `memory`              | `X-Anona-Memory`        | boolean          | `true`      | Set `false` to skip recall and injection entirely for one call.                                                                                                                                                                                                                                                |

A header that cannot be parsed returns `400 invalid_tunable` naming the header.

### Space defaults

The same knobs can be stored on the space, so they apply to every proxied call
without touching a call site. Resolution is per field, in this order:

```
request body  →  request header  →  space default  →  platform default
```

| Method   | Path                                  | Description                                                                      |
| -------- | ------------------------------------- | -------------------------------------------------------------------------------- |
| `GET`    | `/v1/spaces/{space_id}/chat-settings` | The space's stored defaults. An unconfigured space returns all nulls, not a 404. |
| `PUT`    | `/v1/spaces/{space_id}/chat-settings` | Replace them. A field left out of the body is **cleared**, not kept.             |
| `DELETE` | `/v1/spaces/{space_id}/chat-settings` | Remove every override. Idempotent.                                               |

```bash theme={null}
curl -X PUT https://api.anonalabs.com/v1/spaces/support-bot/chat-settings \
  -H "Authorization: Bearer anona_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"memory_limit": 12, "auto_record": false}'
```

```json theme={null}
{
  "space_id": "support-bot",
  "memory_limit": 12,
  "memory_token_budget": null,
  "auto_record": false,
  "memory": null
}
```

`space_id` is not a settable default: it is the key the defaults are stored
under. A `null` means *unset*, not "off": that field falls through to the
platform default, so a space can configure one knob and inherit the rest.

These endpoints are free, cost no credits, and remain available when an
organization has run out of credits, because configuration should never be the thing
you cannot change.

## Response

OpenAI-shaped, plus two Anona fields.

```json theme={null}
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "model": "gpt-4o-mini",
  "choices": [ { "index": 0, "message": { "role": "assistant", "content": "..." } } ],
  "usage": { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 },
  "memories_injected": 3,
  "space_id": "support-bot"
}
```

| Field               | Description                                            |
| ------------------- | ------------------------------------------------------ |
| `memories_injected` | How many memories were pulled into this turn's prompt. |
| `space_id`          | The space the turn was recalled from and stored into.  |

The same two values are also returned as the `X-Anona-Memories-Injected` and
`X-Anona-Space-Id` response headers, which is how you read them on a stream.

The user turn and the assistant reply are both stored back into `space_id`
automatically, unless `auto_record` is `false`.

## Streaming

Send `"stream": true` and the reply arrives as server-sent events in the standard
OpenAI chunk format, terminated by `data: [DONE]`.

```python theme={null}
stream = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "What plan am I on?"}],
    stream=True,
)
for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")
```

Memory recall happens before the model is called, so injection is unaffected by
streaming. The first chunk carries the `memories_injected` and `space_id` fields
alongside the usual chunk payload, and both are on the response headers from the start.

The turn is recorded and billed after the last token, using the token counts from the
final chunk. If the connection drops mid-stream, whatever the model already produced is
still recorded and still billed, from an estimate of the text that was sent, since the
counts travel in a chunk that never arrived.

Token counts reach *you* only if you ask for them, as on OpenAI: set
`"stream_options": {"include_usage": true}` and the stream ends with a usage chunk.
Billing does not depend on it.

<Note>
  Errors raised before the first token (an unavailable model, an unreachable provider)
  come back as a normal JSON error with a real status code. Once the stream has started
  the status is already sent, so a later failure ends the stream early instead.
</Note>

## Other request shapes

| Shape                   | Endpoint                                    |
| ----------------------- | ------------------------------------------- |
| OpenAI Chat Completions | `/v1/chat/completions` (this page)          |
| OpenAI Responses        | [`/v1/responses`](/api-reference/responses) |
| Anthropic Messages      | [`/v1/messages`](/api-reference/messages)   |

All three run the identical memory wrapper and accept the same tunables.

<Note>
  You never supply an LLM key. Anona runs the model for you, `model` is a hint, and
  billing is metered in Anona credits rather than by the underlying provider.
</Note>
