Build a reusable assistant profile
Section: DOC-MA-profiles-prompts#create-and-version-agent-profiles.
Build one nutrition-coach profile, use it in a conversation, then change its response style without copying a prompt into every send. The finished recipe gives you a stored profile, a conversation explicitly using it and a recorded version you can inspect when behavior changes.
Use a single profile first. Add a picker or shared fragments only when your application needs multiple assistants.
Before you start
Section: DOC-MA-profiles-prompts#start-here.
You need a provisioned project, a backend secret key for profile management, a model accepted by your account, and the user-scoped credentials used for conversation calls. Replace YOUR_MODEL_ID with an allowed model.
Profile management takes the secret key on its own: no X-On-Behalf-Of or end-user JWT. Conversation calls need the user-scoped authentication pair. The public profile API uses the default project; X-Project-Id does not create or select a separate customer project.
Choose an unused profileId for the recipe. The example uses nutrition_coach; do not overwrite a shared profile just to try it.
Follow the profile through its first reply
Section: DOC-MA-profiles-prompts#get-started.
- Create the profile below and retain its ID and assigned version.
- Read it back to confirm the prompt and model you stored.
- Select it explicitly when creating a conversation, then send one representative question and inspect the reply.
- Make a controlled update and compare a later turn with the earlier one.
The create/read/use steps are the main recipe. The sections after the first reply cover changing, restoring, selecting and importing profiles.
Step 1: Save the assistant instructions
Section: DOC-MA-profiles-prompts#create-a-profile.
The example creates an enabled profile with a concise response style. Replace the model placeholder before sending. The returned version is the starting point for later comparisons.
The model and every fallback in models must be allowed for your account. Otherwise create and update return 403, with a message carrying model_access/MODEL_NOT_ALLOWED and the refused ID, and nothing is stored. An update is judged on every model it sends, including ones outside its update mask. See model errors.
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",
"description": "Food, meals and macros.",
"whenToUse": "Use when the user asks about food, meals, or macros.",
"keywords": [
"nutrition",
"food",
"macros"
],
"enabled": true,
"generationConfig": {
"model": "YOUR_MODEL_ID",
"systemPrompt": "You are a nutrition coach. Be concise and practical.",
"temperature": 0.4
}
}
}'
Reference: Create an agent profile · Request fields.
Response: the stored record, echoed back with version: 1.
{
"profile": {
"profileId": "nutrition_coach",
"name": "Nutrition Coach",
"description": "Food, meals and macros.",
"whenToUse": "Use when the user asks about food, meals, or macros.",
"keywords": [
"nutrition",
"food",
"macros"
],
"enabled": true,
"generationConfig": {
"model": "YOUR_MODEL_ID",
"systemPrompt": "You are a nutrition coach. Be concise and practical.",
"temperature": 0.4
},
"version": 1
}
}
Reference: Create an agent profile · Response fields.
Step 2: Confirm what you saved
Section: DOC-MA-profiles-prompts#read-a-profile.
Read the new profile and compare its generationConfig.systemPrompt, model and version with your intended setup. Do this before attaching it to the first conversation; a profile ID alone does not tell you which instructions are stored.
curl -X POST https://api.travila.ai/api/v1/agent-profiles/get \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"profileId": "nutrition_coach"
}'
Reference: Get an agent profile · Request fields.
Response: {"profile": {...}} — the full record.
Pass version to read a specific immutable version instead of the latest:
{
"profileId": "nutrition_coach",
"version": 3
}
Reference: Get an agent profile · Request fields.
For this first run, use the version returned by creation. The version-3 request above illustrates a later inspection; it only works after that version exists.
Step 3: Use the profile and inspect the reply
Section: DOC-MA-profiles-prompts#how-it-works.
Create a thread with activeProfileId set to nutrition_coach, using the user-scoped credentials from conversation configuration. Retain the returned thread ID as conversationKey.
Send one representative question with the normal generation flow, retain its runId, and read the correlated outcome. For an existing conversation, use setActiveProfileId on the send instead. Selecting a profile persists for later turns; an empty value does not clear the selection.
Finished result: the profile exists at the version you recorded, the conversation explicitly selects it, and the accepted run has a correlated reply or a visible unsuccessful outcome. Inspect the resolved generation context when diagnosing a reply; creating a profile is not itself a test of model behavior.
Recipe: change the response style without replacing the profile
Section: DOC-MA-profiles-prompts#update-a-profile.
Read the current profile first, then lower its temperature for a controlled comparison. Use a leaf mask to change that setting while keeping the existing prompt and model. Each successful update appends a new immutable version.
curl -X POST https://api.travila.ai/api/v1/agent-profiles/update \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"profileId": "nutrition_coach",
"profile": {
"generationConfig": {
"temperature": 0.2
}
},
"updateMask": "generationConfig.temperature"
}'
Reference: Update an agent profile · Request fields.
Response: {"profile": {...}} with the new version.
After updating, retain the new version and send a later turn on an unpinned conversation. Compare the actual response and usage with your earlier turn; a lower temperature reduces variation in some models but does not guarantee deterministic output. If the change is unsuitable, use the version-recovery recipe below.
Recipe: investigate a change and restore earlier content
Section: DOC-MA-profiles-prompts#version-history.
If replies change after an edit, list versions, read the earlier snapshot and compare the stored prompt and configuration before making another update. The example history represents a profile that has already been edited.
curl -X POST https://api.travila.ai/api/v1/agent-profiles/versions \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"profileId": "nutrition_coach"
}'
Reference: List a profile's versions · Request fields.
Response: newest first, one entry per successful mutation.
{
"versions": [
{
"version": 3,
"createdAt": "2026-08-14T10:22:41Z"
},
{
"version": 2,
"createdAt": "2026-07-02T16:04:09Z"
},
{
"version": 1,
"createdAt": "2026-06-19T09:11:55Z"
}
]
}
Reference: List a profile's versions · Response fields.
Pair a version number with get to read the saved profile snapshot.
Investigating a past turn also requires its fragment-set version, resolved variables,
generation configuration and any context added during the turn. Changes to prompt
processing and model behavior can also affect the result. A saved profile does not guarantee exact reproduction of a model response. A profile that never
existed returns an empty list rather than an error.
After restoring through a new update, read the new version back and test a later turn. Historical fragments, supplied variables and model behavior still need separate inspection; restoring profile content alone cannot reproduce every old reply.
Variant: let the user choose an assistant
Section: DOC-MA-profiles-prompts#read-the-selection-library.
Once more than one profile exists, populate a picker from the library. After the user chooses, pass that profile ID through the conversation selection step above. Do not send full prompts and tool configuration merely to display a list of choices.
Use the returned selection metadata for the picker, then explicitly select the chosen profile for the conversation.
curl -X POST https://api.travila.ai/api/v1/agent-profiles/library \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{}'
Reference: Get the profile library · Request fields.
Response:
{
"library": {
"profiles": [
{
"profileId": "nutrition_coach",
"name": "Nutrition Coach",
"description": "Food, meals and macros.",
"whenToUse": "Use when the user asks about food, meals, or macros.",
"keywords": [
"nutrition",
"food",
"macros"
],
"enabled": true
}
],
"defaultProfileId": "generalist"
}
}
Reference: Get the profile library · Response fields.
A conversation does not automatically select a profile when none is active; explicitly select the customer’s chosen enabled profile.
Write a useful choice description
Section: DOC-MA-profiles-prompts#writing-whentouse.
whenToUse describes when the profile fits a turn. Your selection interface or
application policy can use this metadata; the field itself does not enable an
automatic router. Write a concrete selection instruction:
- Good:
Use when the user asks about food, meals, macros, or logging what they ate. - Poor:
The nutrition profile.
Use description to explain the profile in a picker and keywords to support your own search or selection logic. Together with
profileId, name and enabled, these are the fields returned by
the library.
Variant: inventory profiles before a shared change
Section: DOC-MA-profiles-prompts#list-profiles.
Use full profile records when reviewing dependencies or planning a shared change. Read every page needed for the inventory and include disabled profiles when they matter. Use the selection library for an ordinary picker.
curl -X POST https://api.travila.ai/api/v1/agent-profiles/list \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"page": 1,
"pageSize": 25
}'
Reference: List agent profiles · Request fields.
Response:
{
"profiles": [
{
"profileId": "nutrition_coach",
"name": "Nutrition Coach",
"version": 3
}
],
"totalCount": 1,
"hasMore": false
}
Reference: List agent profiles · Response fields.
Retire an assistant without stranding its conversations
Section: DOC-MA-profiles-prompts#delete-a-profile.
Before disabling or deleting a profile, identify conversations that still select it and move them to enabled replacements. Direct sends cannot use a disabled profile; queued messages have the different fallback behavior described in configuration. Retirement is separate from the response-style test above.
For reversible retirement, send this body to agent-profiles/update with your management credentials. It disables selection without deleting the profile or its version history:
{
"profileId": "nutrition_coach",
"profile": {
"enabled": false
},
"updateMask": "enabled"
}
Reference: Update an agent profile · Request fields.
For permanent removal, use the delete request below instead. Deletion removes version history and does not check for remaining references:
curl -X POST https://api.travila.ai/api/v1/agent-profiles/delete \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"profileId": "nutrition_coach"
}'
Reference: Delete an agent profile · Request fields.
Response: {} on success.
Re-enable a disabled profile through another masked update when it should be selectable again. Deletion removes its saved versions, so choose the reversible path when you may need to restore it.
Variant: migrate an existing prompt library
Section: DOC-MA-profiles-prompts#import-an-existing-prompt-library.
If your prompts already live in a file-based library — personas plus shared blocks they
@include — convert the whole thing in one call rather than hand-porting each one.
curl -X POST https://api.travila.ai/api/v1/agent-profiles/import \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"templates": [
{
"profileId": "nutrition_coach",
"name": "Nutrition Coach",
"whenToUse": "Use when the user asks about food, meals, or macros.",
"keywords": [
"nutrition"
],
"sourceDsl": "@include _shared/safety.txt\n\nYou are a nutrition coach for {{user_name}}.",
"generationConfig": {
"model": "YOUR_MODEL_ID"
}
}
],
"fragments": [
{
"fragmentId": "safety",
"name": "Safety rules",
"path": "_shared/safety.txt",
"sourceDsl": "Never give medical advice."
}
],
"emitFragments": true
}'
Reference: Import a prompt library · Request fields.
Response:
{
"profiles": [
{
"profileId": "nutrition_coach",
"version": 1
}
],
"fragments": [
{
"fragmentId": "safety",
"name": "Safety rules"
}
]
}
Reference: Import a prompt library · Response fields.
Inspect the imported profiles and fragments, supply any required variables explicitly, then run the same first-reply recipe. Import success confirms stored configuration; it does not prove the resulting prompt produced the intended answer.
Flatten or fragments
Section: DOC-MA-profiles-prompts#flatten-or-fragments.
emitFragments | What happens | Choose it when |
|---|---|---|
false (default) | Each @include is resolved inline into that profile's system prompt. No fragment rows are written. | You want profiles self-contained and are happy editing shared text in several places. |
true | Shared blocks become fragment rows, referenced with {{template "id" .}}. | You want one edit to reach every profile. Every block referenced by an @include must be supplied in the same call. |
Related
Section: DOC-MA-profiles-prompts#related.
- Prompt Fragments — the shared blocks profiles compose
- Conversation Configuration — selecting a profile for a conversation
- Agent tools — the tool bundle a profile carries
- Evals — scoring what a profile produced
Document ID: DOC-MA-profiles-prompts. Section identities and revisions.