Turn protocol v1
Turn protocol v1
Ordered assistant content
Use ordered assistant content when one canonical assistant message must combine streamed prose with portable application components. Create one encoder per assistant turn and yield each encoded value as a normal AgentsKit text chunk:
import { createAssistantContentEncoder } from '@agentskit/chat/protocol'
const content = createAssistantContentEncoder()
yield { type: 'text', content: content.encode({ kind: 'text', text: answerChunk }) }
yield { type: 'text', content: content.encode({ kind: 'component', frame: sourceListFrame }) }
Never concatenate raw model output into the envelope. encode validates and JSON-escapes every record. The first call writes the agentskit.chat.content/1 prefix; later calls continue the same envelope. decodeAssistantContent returns completed ordered parts and marks an incomplete trailing record with complete: false, allowing renderers to hide partial transport bytes. Total content is limited to 256 KiB, 512 records, and 16 KiB per input text record; component frames retain their existing props and semantic-fallback limits.
Existing plain-text messages and single ComponentRenderFrame messages remain valid. See ADR-0021.
The v1 protocol identifier is agentskit.chat.turn; every event carries version 1, stable event/session/turn ids, a non-negative sequence, and an ISO timestamp.
Events
| Event | Direction | Payload |
|---|---|---|
client.turn.submit | client → application | non-blank input |
server.turn.snapshot | application → client | canonical message wire records, AgentsKit status, token usage, optional safe diagnostic and lifecycle lineage |
server.turn.diagnostic | application → client | versioned code, safe message, retryability |
Snapshots are complete projections, not deltas. Streaming sends successive snapshots with stable message ids and increasing sequence numbers.
Optional lineage records submit, retry, edit, or regenerate plus parent turn/source message identities. createSnapshotEvent creates the canonical projection from AgentsKit messages. createTurnSnapshotCursor(sessionId) applies only newer snapshots from the expected session, making reconnect, duplicate delivery, and stale delivery inert without implementing another lifecycle reducer.
Message records are validated by validateMemoryRecord from the published @agentskit/core/memory-validation subpath. The protocol package owns only the application envelope and must not reproduce AgentsKit message, content-part, tool-call, or memory schemas.
Decode safely
import { decodeTurnEvent } from '@agentskit/chat/protocol'
const result = decodeTurnEvent(untrustedInput)
if (!result.ok) {
// Do not mutate state.
report(result.diagnostic)
return
}
apply(result.event)
The decoder returns PROTOCOL_UNSUPPORTED_VERSION, PROTOCOL_UNKNOWN_EVENT, or PROTOCOL_INVALID_PAYLOAD. It never returns raw Zod issues or copies the rejected payload into the diagnostic.
Component frames and interactions
The sibling agentskit.chat.component v1 envelope carries custom application render frames and semantic interaction events. A render frame contains componentKey, instanceId, unknown props for validation by the closed application manifest, and a required semantic fallback. A selection event preserves the component and instance identities plus the selected choiceId.
Envelope decoding validates structure only. @agentskit/chat then verifies registration and the component-specific props schema. Unknown types, versions, components, invalid props, and invalid JSON are inert typed diagnostics.
Compatibility
- Optional additive fields are allowed within v1 and ignored by older decoders.
- Unknown event kinds and versions are inert.
- Removing or renaming required fields, changing meaning, or changing lifecycle semantics requires v2, migration fixtures, and a new ADR.
- Versions are never silently coerced.
StreamChunk and AgentEvent remain upstream AgentsKit adapter/observer contracts and are not wire events.
Application sessions
Persistent application metadata uses the separate agentskit.chat.session v1 envelope. decodeSessionSnapshot validates current snapshots and explicitly migrates the supported v0 shape. It contains session/definition identity, definition revision, cursor, deterministic decisions, and confirmation bindings; canonical messages are excluded and remain in AgentsKit ChatMemory.