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
- 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):Passing Variables
- Chat Request
- Conversation Creation
- Direct Link (not implemented)
- Web Widget (not implemented)
Include
variables in the chat request body:- First request (no
conversationId): variables stored asinitial_variablesandvariables - Subsequent requests: new variables merged into
variables(existing keys overwritten)
Sensitive Variables (not implemented)
Design only — not implemented (C-210). The
conversation_variables.sensitive_variables column and its decryption on read exist, but neither write path below was built: there is no POST .../variables endpoint and no context-token issuer or verifier. The design is kept for the planned verified-variables work.conversation_variables.sensitive_variables using AES-256-GCM.
Setting via POST Endpoint (not implemented)
Design: call from your backend before or during the conversation:Setting via Signed Context Token (not implemented)
Design: generate a signed JWT from your backend:{ "token": "eyJ..." }
- Frontend receives opaque token, passes as
context_tokenin conversation create or chat request - Bot service decodes JWT server-side, extracts variables
- Keys listed in
sensitive_keysare stored encrypted; others stored as regular variables - Token has expiry — validated before use
Resolution Flow
Prompt Rendering Engine
Shared utility inpackages/shared/src/prompt-renderer.ts:
- 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 includingvariables in any chat request:
conversation_variables.variables record, enabling dynamic context updates as the conversation progresses.
Security Considerations
- Never expose sensitive variable keys in client-side code or HTML. (The intended remedy, signed context tokens, is not implemented — C-210. Until it is, there is no safe channel for sensitive values: keep them out of variables.)
- Variables are not verified: a value arrives as the visitor or API caller sent it. Never use one to decide anything that must be trusted, such as a customer tier that unlocks behaviour.
- 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 (design, not implemented): a token should carry a reasonable
expires_in(e.g., 3600 seconds) and be rejected once expired. - Sensitive variables (design, write path not implemented): encrypted at rest, never returned in GET responses, only accessible server-side during prompt rendering.
- Query param variables (not implemented): Only use for non-sensitive data — query params are logged and visible in browser history.

