Dynamic Prompts¶
Dynamic Prompts is an advanced integration pattern. Tuor can store and version the system prompts your models use. Pulling the active prompt at runtime — instead of hard-coding it — means every prompt change automatically applies to new traces, and every trace is permanently linked to the exact prompt version that produced it.
How it works¶
- You store your prompt in Tuor and fetch the active version at runtime.
- Your model runs with that prompt content.
- You ingest the trace with the prompt version ID stamped in
trace_config. - Tuor accumulates enough reviewed traces to suggest a refinement.
- You review and accept the suggestion — it becomes the new active version.
- Your service picks it up on the next fetch.
sequenceDiagram
participant App as Your App
participant Tuor as Tuor API
participant Model as Your Model
App->>Tuor: GET /v1/projects/{id}/prompts
Tuor-->>App: { active: { id, content, version } }
App->>Model: Run with active.content
Model-->>App: model_output
App->>Tuor: POST /v1/traces/ (trace_config.prompt_version_id = active.id)
Fetch the active prompt¶
Response
{
"active": {
"id": "prm_abc123",
"project_id": "proj_abc123",
"version": 3,
"content": "You are a financial assistant. Extract the following fields...",
"source": "manual",
"is_active": true,
"created_at": "2026-05-20T10:00:00Z",
"created_by": "user_1abc"
},
"history": [...]
}
active is null if no prompt has been saved yet for the project. The objects above are abbreviated — each prompt also carries org_id, parent_id, rationale, and lineage_event_ids.
Ingest traces linked to the prompt¶
Stamp prompt_version_id in trace_config on every ingest call. Tuor echoes it back in webhook payloads and exports so you can trace any output back to the exact prompt that produced it.
curl -X POST "https://api.tuor.dev/v1/traces/" \
-H "X-API-Key: $TUOR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "proj_abc123",
"model_input": { "content": "Extract net income from the attached statement." },
"model_output": { "net_income": 250000 },
"trace_config": {
"model": "gpt-4o",
"prompt_version_id": "prm_abc123",
"internal_run_id": "run_01j2abcde"
}
}'
Cache the active prompt¶
The active prompt ID only changes when a new version is saved. Fetching it once at startup — or on a short TTL — is sufficient. There is no need to fetch it per-request.
Python
import os
import httpx
TUOR_API_KEY = os.environ["TUOR_API_KEY"]
PROJECT_ID = "proj_abc123"
def fetch_active_prompt() -> dict:
resp = httpx.get(
f"https://api.tuor.dev/v1/projects/{PROJECT_ID}/prompts",
headers={"X-API-Key": TUOR_API_KEY},
timeout=5,
)
resp.raise_for_status()
return resp.json()["active"]
# Cache at startup
prompt = fetch_active_prompt()
def run_and_trace(user_input: str) -> dict:
model_output = call_your_model(prompt["content"], user_input)
httpx.post(
"https://api.tuor.dev/v1/traces/",
headers={"X-API-Key": TUOR_API_KEY, "Content-Type": "application/json"},
json={
"project_id": PROJECT_ID,
"model_input": {"content": user_input},
"model_output": model_output,
"trace_config": {
"model": "gpt-4o",
"prompt_version_id": prompt["id"],
},
},
)
return model_output
TypeScript
const TUOR_API_KEY = process.env.TUOR_API_KEY!;
const PROJECT_ID = "proj_abc123";
async function fetchActivePrompt() {
const res = await fetch(
`https://api.tuor.dev/v1/projects/${PROJECT_ID}/prompts`,
{ headers: { "X-API-Key": TUOR_API_KEY } }
);
const data = await res.json();
return data.active;
}
// Cache at startup
const prompt = await fetchActivePrompt();
async function runAndTrace(userInput: string) {
const modelOutput = await callYourModel(prompt.content, userInput);
await fetch("https://api.tuor.dev/v1/traces/", {
method: "POST",
headers: {
"X-API-Key": TUOR_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
project_id: PROJECT_ID,
model_input: { content: userInput },
model_output: modelOutput,
trace_config: {
model: "gpt-4o",
prompt_version_id: prompt.id,
},
}),
});
return modelOutput;
}
Save a new prompt version¶
When you want to update the prompt manually, POST a new version. It becomes active immediately and all subsequent fetches will return it.
curl -X POST "https://api.tuor.dev/v1/projects/proj_abc123/prompts" \
-H "X-API-Key: $TUOR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "content": "You are a financial assistant. Extract the following fields with strict ISO formatting..." }'
Prompt content is capped at 16 KB. The previous active version is retained in history and linked traces are unaffected.
Prompt refinement¶
Once a project has accumulated at least 10 reviewed traces since the current active version, Tuor can suggest a revised prompt based on what reviewers actually corrected. See the Integration API for the /refine and /accept-refinement endpoints.