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

# Dynamic Variables

> Mustache-style variable system: syntax, precedence chain, sensitive variables, context tokens, and per-message overrides.

## Overview

Dynamic variables allow prompt templates to be personalized at runtime using data from multiple sources. Variables use Mustache-style `{{variable_name}}` syntax and are resolved from a priority-ordered chain of sources before any prompt is rendered.

## Variable Syntax

```
Hi {{user_name}}! Welcome to {{bot_name}}.
Your current plan is {{plan_tier}}.
```

* Variable names are case-sensitive
* Unresolved variables are replaced with an empty string
* Unresolved variables are logged as warnings for debugging
* Nested/escaped braces are handled gracefully

## Sources and Precedence

Variables are merged from **highest to lowest priority** (higher priority overwrites lower for the same key):

| Priority | Source                          | Set By                                                 | Example                                |
| -------- | ------------------------------- | ------------------------------------------------------ | -------------------------------------- |
| 1        | Per-message overrides           | API body `variables` on subsequent messages            | Updating page context mid-conversation |
| 2        | Server-set sensitive variables  | `POST .../variables` endpoint or signed context token  | User PII, account IDs, internal tier   |
| 3        | Client-set invocation variables | Query params, widget config, API body on first message | User name, plan tier, referral source  |
| 4        | Agent-level defaults            | Bot's `prompt_variables` configuration                 | Default greeting name, brand name      |
| 5        | System defaults                 | Platform-wide `default_variables` in platform\_config  | Generic fallbacks                      |

## Passing Variables

<Tabs>
  <Tab title="Chat Request">
    Include `variables` in the chat request body:

    ```json theme={null}
    POST /bots/:id/chat
    {
      "message": "Hello",
      "variables": { "user_name": "John", "plan": "pro" },
      "conversationId": "...",
      "stream": false
    }
    ```

    * **First request** (no `conversationId`): variables stored as `initial_variables` and `variables`
    * **Subsequent requests**: new variables merged into `variables` (existing keys overwritten)
  </Tab>

  <Tab title="Conversation Creation">
    ```json theme={null}
    POST /bots/:id/conversations
    {
      "variables": { "user_name": "John", "plan": "pro" },
      "context_token": "eyJ..."
    }
    ```
  </Tab>

  <Tab title="Direct Link">
    Pass non-sensitive variables via query params using the `var_` prefix:

    ```
    /chat/bot-id?var_user_name=John&var_plan=pro
    ```

    Frontend strips the `var_` prefix and passes variables to the first chat request.
  </Tab>

  <Tab title="Web Widget">
    ```html theme={null}
    <script
      data-bot-id="abc"
      data-variables='{"user_name":"John","plan":"pro"}'
      data-context-token="eyJ..."
      src="https://widget.brainstormer.ai/embed.js">
    </script>
    ```

    * `data-variables`: non-sensitive client variables (exposed in HTML source)
    * `data-context-token`: signed JWT from host backend (for sensitive vars)
  </Tab>
</Tabs>

## Sensitive Variables

Sensitive variables are server-set and **never returned** in any client-facing API response. They are stored encrypted in `conversation_variables.sensitive_variables` using AES-256-GCM.

### Setting via POST Endpoint

Call from your backend before or during the conversation:

```json theme={null}
POST /bots/:id/conversations/:conversationId/variables
{
  "sensitive": true,
  "variables": { "account_id": "12345", "internal_tier": "enterprise" }
}
```

### Setting via Signed Context Token

Generate a signed JWT from your backend:

```json theme={null}
POST /bots/:id/context-token
{
  "variables": { "user_name": "John", "account_id": "12345" },
  "sensitive_keys": ["account_id"],
  "expires_in": 3600
}
```

Response: `{ "token": "eyJ..." }`

* Frontend receives opaque token, passes as `context_token` in conversation create or chat request
* Bot service decodes JWT server-side, extracts variables
* Keys listed in `sensitive_keys` are stored encrypted; others stored as regular variables
* Token has expiry -- validated before use

<Tip>
  **Use case:** Host backend pre-generates context for an embedded widget session. The frontend never sees the sensitive values, only the opaque token.
</Tip>

## Resolution Flow

```mermaid theme={null}
graph TD
    A[Collect variables from all sources] --> B[Merge by precedence]
    B --> C[Store/update in conversation_variables]
    C --> D["Load merged variables<br/>(sensitive + regular)"]
    D --> E["Replace {{variable_name}} occurrences"]
    E --> F{Unresolved variables?}
    F -->|Yes| G["Replace with empty string<br/>Log warning"]
    F -->|No| H[Return rendered prompt]
    G --> H
```

## Prompt Rendering Engine

Shared utility in `packages/shared/src/prompt-renderer.ts`:

```typescript theme={null}
interface RenderResult {
  rendered: string;
  unresolvedVariables: string[];
}

function renderPrompt(
  template: string,
  variables: Record<string, string>
): RenderResult;
```

* Pure function, no side effects
* Used by bot service for all prompt types
* Handles nested/escaped braces gracefully
* Returns list of unresolved variables for logging

## Per-Message Variable Overrides

Variables can be updated mid-conversation by including `variables` in any chat request:

```json theme={null}
POST /bots/:id/chat
{
  "message": "Now show me the enterprise options",
  "conversationId": "existing-conv-id",
  "variables": { "current_page": "pricing", "plan": "enterprise" }
}
```

New variables are merged into the existing `conversation_variables.variables` record, enabling dynamic context updates as the conversation progresses.

## Security Considerations

<Warning>
  Follow these security rules for all variable handling.
</Warning>

* **Never expose sensitive variable keys** in client-side code or HTML. Use signed context tokens.
* **Prompt injection:** Malicious variable values could attempt to override LLM behavior. Variables should be clearly delimited (e.g., wrapped in quotes or XML tags) when inserted into LLM prompts.
* **Context token expiry:** Always set a reasonable `expires_in` (e.g., 3600 seconds). Expired tokens are rejected.
* **Sensitive variables:** Encrypted at rest, never returned in GET responses, only accessible server-side during prompt rendering.
* **Query param variables:** Only use for non-sensitive data -- query params are logged and visible in browser history.
