The working copy and the published snapshot
The working copy lives in the agent’sagent_config row. Every field in the
editor writes there — prompt, model, voice, turn detection, call flow, and the
rest. It has no version number.
Publishing copies the working copy into an immutable, numbered snapshot.
agentVersions.status reports the relationship between the two:
The console renders these as two tags:
Live: v<n> or Never published, and
Unpublished changes or Up to date. An agent with no published
snapshot cannot be reached by callers at all — there is nothing for a call to
resolve to.
Publishing: what gets snapshotted and when callers see it
agentVersions.publish takes { orgId, agentId, note? }. It snapshots the
entire working copy definition, not a field selection and not a diff — the
snapshot is self-contained, which is what makes restoring one later a complete
operation. The optional note is free text; the console’s input caps it at 500
characters and sends nothing when it is left empty.
The response drives what the screen says:
The Publish button is only rendered while
status.unpublished is true.
When the working copy matches the live snapshot there is nothing to publish and
the control is not offered.
After either mutation the console refetches both status and list, so the
history and the live tag update together.
Rollback: republishing an older definition
agentVersions.rollback takes { orgId, agentId, versionId }. Note that it
identifies the target by the history row’s id, not by its version number.
Rollback does not move the version pointer backwards and does not reopen an
old number for writing. It republishes the older definition as a new
snapshot at the next version number. The response carries both numbers:
rolled_back_to— the version whose definition was restored.version_number— the new version that now holds it.
Rolled back to v<a>, published as v<b>. Version
numbers only ever move forward, so the history stays a straight append-only
log and you can roll back a rollback.
In the history list, Restore only appears on rows whose status is not
published. There is no point restoring the snapshot that is already live.
A rollback can also come back with ready: false, for the same reason a
publish can.
Reading the change list
status.changed and each history row’s changed array contain raw field
names. The console maps them to the labels an operator recognises from the
editor:
Any field name without a mapping is shown verbatim. On the live-status card the
list reads
Changed since v<n>: …; on a history row it reads Changed: … for
that snapshot.
Reading the side-by-side diff
The change list tells you which fields moved. Compare on a history row tells you how. The console serialises both definitions to indented JSON and runs a line-level longest-common-subsequence diff, then renders two columns:- Left, red-tinted — lines present in the selected snapshot’s
definitionand absent from the comparison target (deletions). - Right, green-tinted — lines present only in the target (additions).
- Untinted lines are common to both. A greyed-out cell means that side has no line at that position.
status.live, so a comparison is always “this snapshot
versus what the console reports as current”. The header line above the diff
reads No differences. or <n> changed lines.
Line-level diffing is the reason this view beats the field list for prose
changes: a reworded system prompt shows up as one field name in changed, but
as the specific sentences that moved in the diff.
Publishing an agent that cannot run yet: missing provider credentials
Publishing validates that a snapshot exists and is well-formed. It does not require that every provider the snapshot names has usable credentials in your org. Those are two separate concerns, and TeleQuick lets the publish succeed so you are not blocked from versioning a configuration you are still wiring up. When the snapshot references a provider with no credential,publish and
rollback return ready: false together with missing_providers. The console
treats this as an error condition even though the mutation succeeded, and shows:
missing_providers is empty the provider list is omitted from the message.
The version is live either way: the pointer has moved, the history row exists,
and incoming calls will resolve to it and fail on the missing credential. Add
the credential for each named provider to clear the condition — the snapshot
itself does not need to be republished for the credential to take effect.
ready: false is reported for both mutations, so a rollback to an older
snapshot that names a provider you have since removed lands in the same state.
Calls already in progress when you publish
Publishing swaps which snapshot is live. Be precise about what the screen tells you and what it does not:publishreturns the newversion_number,unchanged,readyandmissing_providers. It returns no information about calls in progress, and the console does not display any.statusreports which snapshot is live and whether the working copy has drifted from it. It is a statement about the agent’s configuration, not about any particular call.
Published v<n>. Callers are getting it now. confirms that the
pointer moved — not that any specific connected call has been re-read. To
confirm end-to-end behaviour of a new version, place a fresh call after
publishing rather than inferring it from a call that was already up.
This is also the failure mode the screen was built to replace. Previously a
save wrote the row and a toast told the operator the agent was “still answering
with the old config” — a state, surfaced once, with no way to act on it. Now
that state is the Unpublished changes tag, and the action is the Publish
button next to it.
The agentVersions API
All four procedures takeorgId and agentId.
Notes on
list: rows are the history, newest first as rendered. status is
published for the live row and something else for every other row — the
console keys the Live tag and the availability of Restore off that
single value. published_at is preferred over created_at for the displayed
timestamp. definition is the full snapshot, which is what makes client-side
diffing possible without a second round trip. The console requests
limit: 30.