# Agent Versioning

> Manage agent versions, promote configurations, and roll back changes with PromptRails' immutable versioning system.

Source: https://0.0.0.0:8080/docs/agent-versioning

PromptRails uses an immutable versioning system for agents. Every configuration change creates a new version, and you can promote any version to be the current active configuration. This enables safe iteration, A/B testing, and instant rollbacks.

## How Versioning Works

Each agent has one or more **versions**. A version captures the complete execution configuration at a point in time:

- Configuration object (system prompt, model, temperature, tools, etc.)
- Input and output schemas
- Linked prompt versions (with roles and sort order)
- Version identifier (e.g., `v1`, `v2`, `v3`)
- 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.

### Current Version

Exactly one version per agent is marked as `is_current = true`. 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.

## Creating a Version

Config is a **typed discriminated union by agent type** —
`SimpleAgentConfig`, `ChainAgentConfig`, `MultiAgentConfig`,
`WorkflowAgentConfig`, or `CompositeAgentConfig`. The SDK injects the
`type` discriminator automatically and catches schema mismatches (like
`prompt_version_id` → `prompt_id`) at compile time instead of runtime.

**Python SDK**

```python
from promptrails import SimpleAgentConfig

version = client.agents.create_version(
    agent_id="your-agent-id",
    version="1.0.0",
    config=SimpleAgentConfig(
        prompt_id="your-prompt-id",
        temperature=0.7,
        max_tokens=1024,
        approval_required=False,
    ),
    input_schema={
        "type": "object",
        "properties": {
            "message": {"type": "string"}
        },
        "required": ["message"]
    },
    message="Initial version",
)

print(f"Version created: {version.version}")
```

**JavaScript SDK**

```typescript
import { SimpleAgentConfig } from '@promptrails/sdk'

const simple: SimpleAgentConfig = {
  type: 'simple',
  prompt_id: 'your-prompt-id',
  temperature: 0.7,
  max_tokens: 1024,
  approval_required: false,
}

const version = await client.agents.createVersion('your-agent-id', {
  version: '1.0.0',
  config: simple,
  input_schema: {
    type: 'object',
    properties: {
      message: { type: 'string' },
    },
    required: ['message'],
  },
  message: 'Initial version',
})

console.log(`Version created: ${version.data.version}`)
```

**Go SDK**

```go
simple := promptrails.SimpleAgentConfig{
    PromptID:    "your-prompt-id",
    Temperature: &temperature,
    MaxTokens:   1024,
}

version, err := client.Agents.CreateVersion(ctx, "your-agent-id", &promptrails.CreateVersionParams{
    Version: "1.0.0",
    Config:  simple,
    Message: "Initial version",
})
```

For chain, multi-agent, workflow, and composite configs see the
[Linked Prompts](#linked-prompts) section below.

## Promoting a Version

Promoting a version sets it as the current active configuration for the agent. The previously current version is demoted automatically.

**Python SDK**

```python
client.agents.promote_version(
    agent_id="your-agent-id",
    version_id="version-id-to-promote"
)
```

**JavaScript SDK**

```typescript
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:

```python
versions = client.agents.list_versions(agent_id="your-agent-id")

for v in versions["data"]:
    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:

```python
# 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["data"][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.

## 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., `v1`, `v2`)                 |
| `config`        | JSON      | Complete execution configuration                 |
| `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                     |
| `prompts`       | array     | Linked prompt versions with roles and sort order |

## Linked Prompts

Chain, multi-agent, workflow, and composite configs reference prompts
through a `PromptLink`:

| Field        | Description                                                                                                           |
| ------------ | --------------------------------------------------------------------------------------------------------------------- |
| `prompt_id`  | The prompt to use. Execution **auto-follows the prompt's current version** — you don't pin a specific prompt version. |
| `role`       | The role of the prompt in the agent (e.g., `main`, `writer`, `critic`)                                                |
| `sort_order` | Execution order for chain-type agents                                                                                 |

Auto-follow means promoting a new prompt version instantly changes the
behaviour of every agent linked to that prompt — no agent version bump
required. If you want deterministic, pinned behaviour, cut a new prompt
(rather than a new version) and switch the agent to link to it.

### Chain example

```python
from promptrails import ChainAgentConfig, PromptLink

chain = ChainAgentConfig(
    prompt_ids=[
        PromptLink(prompt_id="researcher-prompt-id", role="research", sort_order=0),
        PromptLink(prompt_id="writer-prompt-id",     role="write",    sort_order=1),
    ],
)

client.agents.create_version(agent_id="your-agent-id", version="1.0.0", config=chain)
```

> **Breaking change (SDK v0.3).** The old opaque
> `config: Dict[str, Any]` / `Record<string, unknown>` /
> `map[string]any` is gone. The config JSON key
> `prompt_ids[].prompt_version_id` was renamed to
> `prompt_ids[].prompt_id`. Typed SDK callers don't need to touch
> anything — the SDK emits the right shape.

## 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
- **Coordinate prompt and agent versions** -- when updating prompts, create a new agent version that links to the new prompt versions
