Configuration
What shapes a generation: the model and sampling parameters, the agent profile in effect, conversation-level settings, and how history is kept within the context window.
Generation Config
Control how the AI generates responses by updating the default generation config.
curl -X POST https://api.travila.ai/api/v1/llm/update-default-generation-config \
-H "X-API-Key: sk_your_key_here" \
-H "X-On-Behalf-Of: user_123" \
-H "Content-Type: application/json" \
-d '{
"conversationKey": "support-chat-001",
"defaultGenerationConfig": {
"model": "anthropic/claude-sonnet-5",
"temperature": 0.7,
"maxOutputTokens": 2048,
"topP": 0.9
}
}'
The four fields above are the ones most conversations need:
| Field | Description | Default |
|---|---|---|
model | Model to generate with — see Available Models | Platform default |
temperature | Randomness (0.0 = deterministic, 2.0 = creative) | 1.0 |
maxOutputTokens | Maximum tokens in the response | Model default |
topP | Nucleus sampling threshold | 1.0 |
GenerationConfig carries far more than these four — model fallback lists and routing
filters, provider preferences and price ceilings, reasoning options, tool definitions and
execution policy, response format, plugins, timeouts, and more.
Browse the complete schema, field by field, on
Update Default Generation Config
in the API reference — expand generationConfig to see every field with its type and
constraints.
Available Models
Set model — or the models fallback list — to a model from the platform allowlist. The
canonical list, with the exact rejection error and the rule for OpenRouter variant
suffixes, lives in
Model Routing → Allowed models.
The platform accepts a curated set, not the full OpenRouter catalog: requesting
anything outside it fails immediately with MODEL_INVALID. See
Model Routing & Pre-Filter for capability-based filtering
within that set.
Reasoning
Models that support chain-of-thought reasoning (e.g., google/gemini-3.1-pro-preview, anthropic/claude-sonnet-5) can expose their internal thinking process. Configure reasoning via the reasoning_options field on the generation config:
curl -X POST https://api.travila.ai/api/v1/llm/update-default-generation-config \
-H "X-API-Key: sk_your_key_here" \
-H "X-On-Behalf-Of: user_123" \
-H "Content-Type: application/json" \
-d '{
"conversationKey": "support-chat-001",
"defaultGenerationConfig": {
"model": "google/gemini-3.1-pro-preview",
"reasoning_options": {
"effort": "EFFORT_MEDIUM",
"includeReasoningHistory": true
}
}
}'
| Field | Description | Default |
|---|---|---|
effort | How much reasoning the model should perform. Values: EFFORT_NONE, EFFORT_MINIMAL, EFFORT_LOW, EFFORT_MEDIUM, EFFORT_HIGH, EFFORT_XHIGH | EFFORT_UNSPECIFIED (provider default) |
maxTokens | Maximum tokens the model may use for reasoning | Model default |
exclude | If true, reasoning content is not included in the response | false |
includeReasoningHistory | Include reasoning from previous turns in multi-turn requests for provider continuity | true |
When reasoning is enabled, assistant messages may contain content parts with type: CONTENT_PART_TYPE_REASONING alongside the normal CONTENT_PART_TYPE_TEXT parts. The reasoning parts contain the model's internal thinking process.
Agent Profiles
An agent profile is a saved, versioned bundle of agent configuration — system prompt, model, tools — that you point a conversation at instead of assembling the same generation config on every call.
Two separate things, on two different APIs:
- Managing profiles — create, edit, version, delete — is the Agent Profile APIs, or the admin console.
- Selecting one for a conversation is the LLM APIs, covered below.
Profiles are tenant configuration, not per-user data, so the Agent Profile APIs take a
secret key on its own — no X-On-Behalf-Of, no end-user JWT. That is the opposite of
every call on this page, where a bare sk_… key returns
401 authenticated user_id is required.
Create one, then point conversations at it by id:
curl -X POST https://api.travila.ai/api/v1/agent-profiles/create \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"profile": {
"profileId": "nutrition_coach",
"name": "Nutrition Coach",
"whenToUse": "Use when the user asks about food, meals, or macros.",
"enabled": true,
"generationConfig": {
"model": "google/gemini-3.6-flash",
"systemPrompt": "You are a nutrition coach. Be concise and practical."
}
}
}'
Set the profile when the thread is created:
{
"title": "Nutrition check-in",
"activeProfileId": "nutrition_coach"
}
Or switch profiles mid-conversation. setActiveProfileId on
send-message or
send-message-sync applies to that turn and
every turn after it, until you set a different one:
{
"conversationKey": "thread_abc",
"userMessage": { "role": "ROLE_USER", "content": [{"type": "CONTENT_PART_TYPE_TEXT", "content": "..."}] },
"setActiveProfileId": "profile_escalation"
}
A profile's mcpServers replaces the conversation's MCP server list rather than
merging with it — including when the profile's list is empty. If a profile is active and
defines no MCP servers, the conversation has none for that turn.
Conversation Settings
Update the conversation's system prompt, interrupt policy, and other settings.
curl -X POST https://api.travila.ai/api/v1/llm/update-settings \
-H "X-API-Key: sk_your_key_here" \
-H "X-On-Behalf-Of: user_123" \
-H "Content-Type: application/json" \
-d '{
"conversationKey": "support-chat-001",
"settings": {
"system_prompt": "You are a helpful customer support agent for Acme Corp.",
"interruptPolicy": "QUEUE"
}
}'
System Prompt
The systemPrompt is prepended to every LLM request for this conversation. Use it to set the AI's persona, rules, and context.
Interrupt Policy
Controls what happens when a user sends a new message while a generation run is already in progress:
| Policy | Behavior |
|---|---|
QUEUE | Queue the new message and process it after the current run completes |
INTERRUPT | Cancel the current run and start a new one with the latest message |
Context Management
For long conversations, the message history can exceed the model's context window.
Context management settings control what happens then. Pick a strategy, then configure
the matching sub-object.
| Strategy | Config field | Behaviour |
|---|---|---|
CONTEXT_STRATEGY_COMPACTION | compactionConfig | Summarize older messages, keeping the recent ones verbatim |
CONTEXT_STRATEGY_WINDOWING | windowingConfig | Drop everything beyond the most recent N messages |
CONTEXT_STRATEGY_NONE | — | Do nothing; the turn fails if it exceeds the window |
curl -X POST https://api.travila.ai/api/v1/llm/update-context-management-settings \
-H "X-API-Key: sk_your_key_here" \
-H "X-On-Behalf-Of: user_123" \
-H "Content-Type: application/json" \
-d '{
"conversationKey": "support-chat-001",
"contextManagementSettings": {
"strategy": "CONTEXT_STRATEGY_COMPACTION",
"compactionConfig": {
"mode": "COMPACTION_MODE_ASYNC",
"threshold": {"percentage": 80},
"preserveRecent": 10
}
}
}'
threshold takes one of tokenCount (an absolute limit) or percentage (of the
model's context window). preserveRecent is how many recent messages stay verbatim.
COMPACTION_MODE_ASYNC compacts out of band so the turn is not delayed;
COMPACTION_MODE_SYNC blocks the turn until compaction finishes.
Windowing is the cheaper option when losing old context is acceptable:
{
"conversationKey": "support-chat-001",
"contextManagementSettings": {
"strategy": "CONTEXT_STRATEGY_WINDOWING",
"windowingConfig": {"maxMessages": 50}
}
}
selectiveExclusionConfig composes with either strategy, and is the cheapest win of the
three — dropping tool results and images from context often saves more tokens than
summarizing prose does:
{
"conversationKey": "support-chat-001",
"contextManagementSettings": {
"strategy": "CONTEXT_STRATEGY_COMPACTION",
"selectiveExclusionConfig": {
"excludeToolResults": true,
"excludeImages": true,
"excludeReasoning": true
}
}
}
Compacting on Demand
Compaction normally fires on the configured threshold. Trigger it yourself when you know a long conversation is about to resume — at app launch, say — so the user does not pay the latency mid-turn.
curl -X POST https://api.travila.ai/api/v1/llm/compact-conversation \
-H "X-API-Key: sk_your_key_here" \
-H "X-On-Behalf-Of: user_123" \
-H "Content-Type: application/json" \
-d '{"conversationKey": "support-chat-001"}'
Response:
{
"compactionId": "cmp_a1b2c3d4",
"tokensBefore": 48211,
"tokensAfter": 12004,
"tokensSaved": 36207,
"durationMs": "4120",
"status": "COMPACTION_STATUS_COMPLETED"
}
status is COMPACTION_STATUS_PENDING when the conversation is configured for
COMPACTION_MODE_ASYNC — the token counts are then the pre-compaction figures, and the
result lands later. durationMs is a 64-bit integer, so it arrives as a string.
Prompt Variables
A profile's system prompt can carry {{.variable}} placeholders declared in its
variableSpecs. Prompt variables are where the values come from — set on the
conversation, re-rendered into the prompt on every subsequent turn, so a value you
set once stays current without resending it.
curl -X POST https://api.travila.ai/api/v1/llm/update-prompt-variables \
-H "X-API-Key: sk_your_key_here" \
-H "X-On-Behalf-Of: user_123" \
-H "Content-Type: application/json" \
-d '{
"conversationKey": "support-chat-001",
"variables": {
"userName": "Jane",
"planTier": "pro"
}
}'
Response: {"settings": {...}} — the merged conversation settings.
This is a merge, not a replace: variables you do not send keep their current values.
Pass updateMask to restrict the write to named variables:
{
"conversationKey": "support-chat-001",
"variables": {"planTier": "enterprise"},
"updateMask": "planTier"
}
Because rendering happens per turn, updating a variable mid-conversation changes the prompt for the next turn — this is the late-binding hook for anything that drifts during a session (a plan upgrade, a changed goal, the user's current screen).