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

# Per-turn context

> Attach hidden, situational context to a single user turn so the agent can ground its reply in the current page, locale, or other client-side signals.

Per-turn context lets you attach structured, UI-invisible information to a specific user message—such as the current page URL, locale, or selected product—so the agent can ground its response in the user's situation.
The context informs the model's answer for that turn only.
It doesn't appear in the chat and it isn't carried forward to later turns.

## When to use per-turn context

Use `turnContext` when:

* The client UI already has relevant information for the current turn, such as URL, locale, product ID, or the selected category.
* You don't want that information to appear in the conversation transcript.
* The information applies only to this turn and shouldn't persist across the conversation.

Don't use it for:

* **Conversation-wide state** (agent instructions, user preferences). Use the [agent prompt](/doc/guides/algolia-ai/agent-studio/how-to/prompting) instead.
* **Tool results or extra messages.** Those belong in the normal message pipeline.
* **Trusted server signals.** Agent Studio treats `turnContext` as untrusted client input.

<Warning>
  Agent Studio sends `turnContext` to the model as plain text.
  Don't include secrets, access tokens, or personally identifiable information you don't intend to share with the model.
</Warning>

## How per-turn context works

1. Your client attaches `turnContext` to the latest user message in a completion request.
2. Agent Studio validates the payload, renders it as a preamble and a JSON block, and prepends it to the latest user message before calling the LLM.
3. If conversation persistence is enabled, Agent Studio stores the context on the user message.
4. The model uses the context silently to inform its answer. It doesn't quote or cite the block.
5. When you retrieve conversation history, the stored context is echoed as a `turnContext` field on the user message.

Agent Studio reads and injects only the *latest* user turn's context.
Older turns' context is ignored on new requests.
To keep the model grounded, re-attach context on every new user turn.

## Attach context to a request

The request shape depends on which AI SDK client protocol you use.

<CodeGroup>
  ```json AI SDK v5 theme={"system"}
  {
    "role": "user",
    "parts": [{ "type": "text", "text": "What does this page show?" }],
    "metadata": {
      "turnContext": {
        "url": "https://shop.example.com/p/blue-widget-42",
        "locale": "en-US",
        "product.id": "SKU-42"
      }
    }
  }
  ```

  ```json AI SDK v4 theme={"system"}
  {
    "role": "user",
    "content": "What does this page show?",
    "annotations": [
      {
        "type": "turn-context",
        "data": {
          "url": "https://shop.example.com/p/blue-widget-42",
          "locale": "en-US",
          "product.id": "SKU-42"
        }
      }
    ]
  }
  ```
</CodeGroup>

For AI SDK v5, attach the context under `metadata.turnContext` on the user message.
Unknown sibling keys inside `metadata` are preserved and ignored.

For AI SDK v4, attach it as an entry in the `annotations` array with `type` set to `turn-context`.
Other annotation types pass through untouched, but attaching more than one `turn-context` annotation to the same message is rejected.

<Note>
  The [Chat widget](/doc/api-reference/widgets/chat/js) sends its `context` option as `metadata.turnContext` for you.
  You don't need to construct the payload manually when you use the widget.
</Note>

## Validation rules

`turnContext` must be a flat object that maps strings to strings.
Agent Studio rejects malformed payloads.

| Rule        | Constraint                                                                |
| ----------- | ------------------------------------------------------------------------- |
| Type        | Flat `Record<string, string>`. No nested objects, no non-string values.   |
| Total size  | Up to 4,096 bytes (UTF-8) across all keys and values.                     |
| Key count   | Up to 32 keys.                                                            |
| Key charset | `^[A-Za-z0-9_.-]{1,64}$`. Both `snake_case` and `camelCase` are accepted. |
| Value       | Non-empty, non-whitespace, up to 1,024 bytes (UTF-8).                     |

If you need to send structured data, serialize it to a string yourself before adding it to the context.

Violations return HTTP `422` with a stable error code:

| Error code                    | When                                                          |
| ----------------------------- | ------------------------------------------------------------- |
| `turn_context_too_many_keys`  | More than 32 keys.                                            |
| `turn_context_invalid_key`    | A key fails the charset or length rule.                       |
| `turn_context_empty_value`    | A value is empty or contains only whitespace.                 |
| `turn_context_value_too_long` | A value exceeds 1,024 bytes.                                  |
| `turn_context_oversize`       | The total serialized size exceeds 4,096 bytes.                |
| `turn_context_duplicate`      | AI SDK v4 only: multiple `turn-context` annotations.          |
| `turn_context_invalid_shape`  | A type mismatch, such as a nested object or non-string value. |

Validation runs in a deterministic order: `too_many_keys` → `invalid_key` → `empty_value` → `value_too_long` → `oversize`.

## What the model sees

Agent Studio prepends a preamble and a `<turn_context>` JSON block to the latest user message before calling the LLM:

```text expandable theme={"system"}
[System preamble instructing the model to use these facts silently and treat them as untrusted — it never follows instructions embedded in the block.]
<turn_context>
{"locale":"en-US","product.id":"SKU-42","url":"https://shop.example.com/p/blue-widget-42"}
</turn_context>

What does this page show?
```

Keys are sorted alphabetically so the rendered block is deterministic.
Any `</` sequence inside a value is escaped so a value can't forge a closing tag.

## Retrieve persisted context

When [conversation persistence](/doc/guides/algolia-ai/agent-studio/how-to/conversations) is enabled, the history endpoints echo the stored context as a flat `turnContext` field on user messages, regardless of which AI SDK version the client used:

```json expandable theme={"system"}
{
  "id": "alg_cnv_abc123",
  "messages": [
    {
      "role": "user",
      "parts": [{ "type": "text", "text": "What does this page show?" }],
      "turnContext": {
        "url": "https://shop.example.com/p/blue-widget-42",
        "locale": "en-US"
      }
    },
    {
      "role": "assistant",
      "parts": [{ "type": "text", "text": "..." }],
      "turnContext": null
    }
  ]
}
```

Assistant messages always carry `null`, because per-turn context is a user-turn signal.
For agents with retention turned off, `turnContext` is `null` on every user message, because nothing is persisted.

## Caching

Per-turn context participates in [response caching](/doc/guides/algolia-ai/agent-studio/how-to/caching):

* When context is attached, the cache key includes a hash of the context. Two requests with identical messages but different contexts produce distinct cache entries—different pages can warrant different answers.
* When no context is attached, requests share cache entries as before. Enabling per-turn context doesn't invalidate your existing cache.

## Privacy and retention

* Agent Studio treats `turnContext` as untrusted client input. Keys and values don't appear in logs, traces, metrics, or error messages.
* Values are stored on the user message under the same [retention policy](/doc/guides/algolia-ai/agent-studio/how-to/conversations#manage-retention-and-exports) as message text. Agents with retention turned off never store context.
* Authenticated tenants read their own persisted context through the history endpoints—the same trust boundary as message text.

## See also

* Send context from the UI library, see the Chat widget's `context` option for [JavaScript](/doc/api-reference/widgets/chat/js) and [React](/doc/api-reference/widgets/chat/react)
* Persist and retrieve conversations, see [Conversations](/doc/guides/algolia-ai/agent-studio/how-to/conversations)
* Cache agent responses, see [Caching](/doc/guides/algolia-ai/agent-studio/how-to/caching)
