Agent Versioning
Ship agent changes safely by saving versions with their model config, budget, and tools, promoting the right one, and rolling back when behavior gets worse.
Agent Versioning
PromptRails keeps agent versions immutable. Instead of editing production behavior in place, you create a new version, test it, and promote it when it is ready. If the change misbehaves, promote an older version back to current.
How Versioning Works
Each agent has one or more versions. A version captures the complete runtime configuration at a point in time:
- A
configobject carrying the agent-kind payload —prompt_id(for anagent) ornodes(for aworkflow). model_config— the model and sampling settings (model_id,fallback_model_id,temperature,top_p,top_k,max_tokens).run_budget,approval_policy, andcache_timeout.- The attached
tools,sub_agents, andguardrails. - Input and output schemas.
- Version identifier (e.g.,
1.0.0) and version message (release notes).
Versions are immutable once created. To change an agent’s behavior, you create a new version rather than modifying an existing one.
Model config lives on the agent version. In API v2 a prompt version is pure content (system prompt, user prompt, input schema). The model, sampling, budget, approval policy, cache TTL, and tool/sub-agent/guardrail attachments all live on the agent version. This is what makes a prompt safely shareable across multiple agents.
Current Version
Exactly one version per agent is marked as is_current. When an agent is executed without specifying a version, the current version is used. The current version is what API consumers and chat sessions interact with by default.
An agent version is a draft while it is not current. Promoting that version with promote_version publishes it by making it current; creating a version with set_current=True performs creation and publication in one call. There is no separate publish endpoint. Here, draft describes a non-current agent version, not the draft status of the parent agent resource.
Creating a Version
When you create a version from an SDK, config is built with the helper that matches the agent kind — PromptAgentConfig for an agent or WorkflowAgentConfig for a workflow. The helper injects the type discriminator automatically. Model config, budget, approval policy, and attachments are passed alongside config, not inside it.
Leave set_current false to create a draft for testing, or set it to true to create and publish the version immediately.
Technical detailsCreate, promote, and roll back versions with SDKs
Python SDK
from promptrails import (
PromptAgentConfig,
ModelConfig,
RunBudget,
ApprovalPolicy,
ToolAttachment,
)
version = client.agents.create_version(
agent_id="your-agent-id",
version="1.0.0",
config=PromptAgentConfig(prompt_id="your-prompt-id"),
model_config=ModelConfig(model_id="llm-model-id", temperature=0.7, max_tokens=1024),
run_budget=RunBudget(max_cost=2.0, max_tool_calls=20),
approval_policy=ApprovalPolicy(mode="admins"),
cache_timeout=300,
tools=[ToolAttachment(mcp_tool_id="tool-id", requires_approval=True)],
input_schema={
"type": "object",
"properties": {"message": {"type": "string"}},
"required": ["message"],
},
set_current=True,
message="Initial version",
)
print(f"Version created: {version.version}")JavaScript SDK
import type { PromptAgentConfig, ModelConfig, RunBudget } from '@promptrails/sdk'
const config: PromptAgentConfig = { type: 'agent', prompt_id: 'your-prompt-id' }
const model_config: ModelConfig = { model_id: 'llm-model-id', temperature: 0.7, max_tokens: 1024 }
const run_budget: RunBudget = { max_cost: 2.0, max_tool_calls: 20 }
const version = await client.agents.createVersion('your-agent-id', {
version: '1.0.0',
config,
model_config,
run_budget,
approval_policy: { mode: 'admins' },
cache_timeout: 300,
tools: [{ mcp_tool_id: 'tool-id', requires_approval: true }],
input_schema: {
type: 'object',
properties: { message: { type: 'string' } },
required: ['message'],
},
set_current: true,
message: 'Initial version',
})
console.log(`Version created: ${version.version}`)Go SDK
temp := 0.7
maxCost := 2.0
version, err := client.Agents.CreateVersion(ctx, "your-agent-id", &promptrails.CreateVersionParams{
Version: "1.0.0",
Config: promptrails.PromptAgentConfig{PromptID: "your-prompt-id"},
ModelConfig: &promptrails.ModelConfig{ModelID: "llm-model-id", Temperature: &temp},
RunBudget: &promptrails.RunBudget{MaxCost: &maxCost},
Tools: []promptrails.ToolAttachment{{MCPToolID: "tool-id", RequiresApproval: true}},
SetCurrent: true,
Message: "Initial version",
})See Workflow configs below for the WorkflowAgentConfig shape.
Promoting a Version
Promoting a version is the publish action: it sets the version as the current active configuration for the agent. The previously current version is demoted automatically.
Python SDK
client.agents.promote_version(
agent_id="your-agent-id",
version_id="version-id-to-promote",
)JavaScript SDK
await client.agents.promoteVersion('your-agent-id', 'version-id-to-promote')After promotion, all new executions (unless a specific version is requested) will use the newly promoted version.
Version History
List all versions of an agent to review the change history:
versions = client.agents.list_versions(agent_id="your-agent-id")
for v in versions:
current = " (current)" if v.is_current else ""
print(f"{v.version}{current} - {v.message} - {v.created_at}")Rolling Back
To roll back to a previous version, simply promote it:
# List versions to find the one to roll back to
versions = client.agents.list_versions(agent_id="your-agent-id")
# Promote the previous version
previous_version = versions[1] # second most recent
client.agents.promote_version(
agent_id="your-agent-id",
version_id=previous_version.id,
)
print(f"Rolled back to {previous_version.version}")Rollbacks are instant because versions are immutable — there is no rebuild or redeployment step.
Technical detailsVersion payload details
Version Content
Each version includes:
| Field | Type | Description |
|---|---|---|
id | KSUID | Unique version identifier |
agent_id | KSUID | Parent agent ID |
version | string | Version label (e.g., 1.0.0) |
config | JSON | Agent-kind payload (prompt_id for agent, nodes for workflow) |
model_config | JSON | Model + sampling (model_id, temperature, max_tokens, …) |
run_budget | JSON | Execution-tree budget (max_cost, max_tool_calls, …) |
approval_policy | JSON | Who may approve/deny gated calls (mode, member_ids) |
cache_timeout | integer | Response cache TTL in seconds (0 = disabled) |
tools | array | Attached MCP tools with per-tool policy |
sub_agents | array | Attached delegate/handoff sub-agents |
guardrails | array | Input/output guardrail attachments |
input_schema | JSON | Input validation schema |
output_schema | JSON | Output structure schema |
is_current | boolean | Whether this is the active version |
message | string | Version message / release notes |
created_at | timestamp | When the version was created |
Model Config
model_config owns the model and sampling. Every field is optional; unset sampling inherits the provider/model default.
| Field | Description |
|---|---|
model_id | Primary LLM model |
fallback_model_id | Model used if the primary fails or is unavailable |
temperature | Sampling temperature |
top_p | Nucleus sampling |
top_k | Top-k sampling |
max_tokens | Maximum tokens in the response |
Run Budget
run_budget bounds the whole execution tree, enforced at the root. Every field is optional.
| Field | Description |
|---|---|
max_cost | Maximum total USD cost across the tree |
max_total_tokens | Maximum total tokens across the tree |
max_tool_calls | Maximum tool calls across the tree |
max_children | Maximum sub-agent/child executions |
max_depth | Maximum delegation depth |
Tool and Sub-agent Attachments
Tools and sub-agents are attached to the version, each with its own policy:
ToolAttachment—mcp_tool_id,requires_approval,no_retry,sort_order.SubAgentAttachment—agent_id,alias,description,mode(delegate|handoff),context_mode(task|window),requires_approval,sort_order.
An agent with sub-agents attached is a supervisor: delegate mode runs a sub-agent as a tool and returns to the supervisor, while handoff transfers the conversation to the sub-agent.
Prompt Pinning
An agent draft links to a prompt by prompt_id and follows that prompt’s current version while you iterate. Calling promote_version publishes the draft by making it current and stamps the resolved prompt_version_id on the link. Creating the version with set_current=True performs the same pinning immediately. From then on, that version keeps its pinned prompt even if it is later replaced as current, so promoting a newer prompt version does not silently change production runs.
To release a prompt change, promote the intended prompt version, test it through an agent draft or playground, then promote that agent version to current. The new release pins the prompt version it resolved when it became current.
Workflow configs
A workflow agent’s config is a typed DAG. Nodes can run prompts, tools, data sources, conditions, routers, loops, approvals, other agents, or media generation, and depends_on defines their ordering:
from promptrails import WorkflowAgentConfig, WorkflowNode
workflow = WorkflowAgentConfig(
nodes=[
WorkflowNode(id="research", prompt_id="researcher-prompt-id"),
WorkflowNode(id="write", prompt_id="writer-prompt-id", depends_on=["research"]),
],
)
client.agents.create_version(
agent_id="your-agent-id",
version="1.0.0",
config=workflow,
model_config=ModelConfig(model_id="llm-model-id"),
set_current=True,
)Nodes can also generate media by setting node_type="media" with media_provider, media_type, media_model, and media_config.
Best Practices
- Always include a version message describing what changed and why
- Test new versions by executing them directly (by version ID) before promoting
- Keep previous versions as they serve as an audit trail and enable instant rollbacks
- Use input/output schemas to catch breaking changes early
- Set a run budget so a misbehaving version can’t run away on cost, tokens, or delegation depth
- Coordinate prompt and agent versions — promote the intended prompt, test it through a draft, then promote the agent version to current so it pins the prompt