# Agents and versions

> How an agent's configuration is drafted, published as immutable versions, compared and rolled back — and how every answer can be traced to the exact settings that produced it.

An **agent** is a configured assistant. It has a name, a slug, a description and one **configuration document**: identity and dialect, instructions, knowledge, tools, guardrails, handoff, business hours, conversation, model, variables, overrides, fallback and widget settings. Every field is listed in the [settings reference](/docs/en/concepts/settings/).

- `GET /v1/agents/{agent}` always returns the **complete** configuration with every default filled in. No setting is hidden.
- Unknown fields are rejected, so a typo never passes silently.
- The configuration's JSON Schema is served at `GET /v1/agents/config_schema`, with English and Arabic titles and descriptions for every field.
- `{agent}` in a URL is the agent ID (`agt_…`) or its slug (`store-assistant`). Slugs match `^[a-z0-9][a-z0-9-]{0,62}$`.

## Drafts and versions

Every agent has one editable **draft** and a list of immutable, numbered **versions**:

```text
create ──► v1 (published automatically)
            │
  PATCH the draft … PATCH the draft
            │
  publish ──► v2 ──► publish ──► v3
                        │
  restore v1 into the draft, then publish ──► v4 (same settings as v1)
```

- **Creating an agent publishes version 1 immediately**, so your first API call works without an extra step.
- Editing never changes a published version. Your changes stay in the draft until you publish.
- The agent object shows `published_version` and `has_unpublished_changes`, so you always know whether the draft differs from what is live.

## Edit the draft

`PATCH /v1/agents/{agent}` edits the draft. It needs the draft's current etag in `If-Match`, so two people (or two scripts) can never overwrite each other's changes:

```bash
ETAG=$(curl -s https://api.k-agent.kerneltics.com/v1/agents/store-assistant \
  -H "Authorization: Bearer $KAGENT_API_KEY" | jq -r .draft.etag)

curl -X PATCH https://api.k-agent.kerneltics.com/v1/agents/store-assistant \
  -H "Authorization: Bearer $KAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "If-Match: $ETAG" \
  -d '{
    "config": {
      "identity": { "enabled": true, "bot_name": "Nada assistant", "dialect": "saudi" },
      "conversation": { "history_limit": 20 }
    }
  }'
```

- The body accepts `name`, `slug`, `description`, `config`, `ai_paused` and `actions_paused`.
- `config` is a **JSON merge patch** ([RFC 7396](https://www.rfc-editor.org/rfc/rfc7396)) applied to the draft: objects merge, arrays are replaced as a whole, and `null` resets a field to its default. The merged result is validated as a whole.
- A missing `If-Match` returns `428 if_match_required`. A stale one returns `412 etag_mismatch`: fetch the agent again and re-apply your change.
- Validation errors return `422` with `param` set to a JSON pointer such as `/tools/max_tool_rounds`.

## Publish

```bash
curl https://api.k-agent.kerneltics.com/v1/agents/store-assistant/publish \
  -H "Authorization: Bearer $KAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"note": "Saudi dialect and a longer history window"}'
```

Publishing creates version N+1 from the draft. A version is immutable and records:

- the full configuration and a `config_hash` — `sha256:` plus the SHA-256 of the configuration's canonical JSON, so identical settings always produce the same hash;
- a **copy of every HTTP tool definition** the agent uses. Editing a tool later does not change published versions: publish again to pick up the new definition.
- your note, who published it and when.

Knowledge sources are **not** copied: they are live across all versions, so updating your price list takes effect without a new version.

## Roll back

A rollback is a restore followed by a publish:

```bash
# Copy version 1 into the draft…
curl -X POST https://api.k-agent.kerneltics.com/v1/agents/store-assistant/versions/1/restore \
  -H "Authorization: Bearer $KAGENT_API_KEY"

# …then publish it as a new version.
curl https://api.k-agent.kerneltics.com/v1/agents/store-assistant/publish \
  -H "Authorization: Bearer $KAGENT_API_KEY" -H "Content-Type: application/json" \
  -d '{"note": "Roll back to version 1"}'
```

History is never rewritten: the restored settings become a new, higher version.

## Compare versions

`GET /v1/agents/{agent}/diff?from=<n|draft>&to=<n|draft>` lists every changed field:

```bash
curl "https://api.k-agent.kerneltics.com/v1/agents/store-assistant/diff?from=1&to=draft" \
  -H "Authorization: Bearer $KAGENT_API_KEY"
```

```json
{
  "changes": [
    { "path": "/identity/dialect", "kind": "changed", "before": "match", "after": "saudi" },
    { "path": "/conversation/history_limit", "kind": "changed", "before": 12, "after": 20 }
  ]
}
```

`GET /v1/agents/{agent}/versions` lists the versions and `GET /v1/agents/{agent}/versions/{n}` returns one.

## Which version answers a call

1. `version: "draft"` runs **only in playground sessions** (the dashboard's test panel, or `channel: "playground"`), for dashboard users with the editor role or secret keys with `agents:write`. Anywhere else it returns `422 draft_not_allowed`.
2. A session created with `version_policy: "pinned"` and a `version` keeps using that version.
3. Everything else uses the **latest published version**.

Sessions on the default `latest` policy switch to a new version at their next segment boundary — the next message after an idle gap, or the next message after you publish. See [segments](/docs/en/concepts/sessions/#history-and-segments).

## Every answer is traceable

Each run records `agent.version`, `config_hash` and `snapshot_hash` (the hash of the exact prompt and tool list that were frozen for the conversation). You can always prove which settings produced a given answer. `GET /v1/runs/{run}/steps` shows the model calls and tool calls of that run.

## Pause switches

Two top-level switches act immediately, without a new version or `If-Match`:

| Field | Effect |
|---|---|
| `ai_paused` | Stops AI replies at once. API calls return `409 agent_not_ready` with the blocker `ai_paused`, and widget visitors see a short notice instead of an answer. |
| `actions_paused` | Tools with side effects (`create_ticket`, action HTTP tools, client tools) are removed; answering and handing off keep working. |

Both changes are written to the audit log.

```bash
curl -X PATCH https://api.k-agent.kerneltics.com/v1/agents/store-assistant \
  -H "Authorization: Bearer $KAGENT_API_KEY" -H "Content-Type: application/json" \
  -d '{"actions_paused": true}'
```

## Readiness

The agent object carries `readiness: {ready, blockers}`. While `ready` is false, API calls return `409 agent_not_ready` with the blockers, instead of a confusing half-answer:

| Blocker | Meaning |
|---|---|
| `no_model_credential` | No API key is connected for the agent's AI provider. |
| `credential_invalid` | The provider rejected the connected API key. |
| `model_not_allowed_on_plan` | The agent's model isn't available on your plan. |
| `quota_exhausted` | This month's AI conversation quota is used up. |
| `ai_paused` | AI replies are paused for this agent. |
| `provider_unavailable` | The AI provider is currently unavailable. |
| `knowledge_sync_failing` | A knowledge source is failing to sync. |

Configuration problems are never retried or handed off as if the provider had failed — they are reported so you can fix them.

## Templates, export and the prompt X-ray

- `GET /v1/agent_templates` lists four starter agents — customer support, sales questions, booking assistant and internal FAQ — each with complete, localized settings. Create from one with `POST /v1/agents {"name": "…", "template": "<template id>"}`.
- `GET /v1/agents/{agent}/export` returns the configuration as JSON, with secrets referenced by name only. `POST /v1/agents/import` creates an agent from such a file. Use them to keep agents in Git or copy them between projects.
- `POST /v1/agents/{agent}/prompt_preview` is the **prompt X-ray**: the assembled prompt as blocks, each with its source, version, token estimate and whether it is part of the cacheable prefix. Platform rules are shown too — nothing is hidden.

## Endpoints

| Method and path | Purpose |
|---|---|
| `POST /v1/agents` | Create an agent (from scratch or a `template`); publishes v1 |
| `GET /v1/agents` | List agents |
| `GET /v1/agents/{agent}` | Get an agent with its complete draft configuration |
| `PATCH /v1/agents/{agent}` | Edit the draft (`If-Match`), or toggle the pause switches |
| `DELETE /v1/agents/{agent}` | Archive the agent |
| `POST /v1/agents/{agent}/publish` | Publish the draft as a new version |
| `GET /v1/agents/{agent}/versions` | List versions |
| `GET /v1/agents/{agent}/versions/{n}` | Get one version |
| `POST /v1/agents/{agent}/versions/{n}/restore` | Copy a version into the draft |
| `GET /v1/agents/{agent}/diff` | Compare two versions or the draft |
| `GET /v1/agents/{agent}/export`, `POST /v1/agents/import` | Export and import |
| `POST /v1/agents/{agent}/prompt_preview` | Prompt X-ray |
| `GET /v1/agents/config_schema` | JSON Schema of the configuration |
| `GET /v1/agent_templates` | Starter templates |
