AI Transport overview
How Sockudo maps AI Transport sessions onto existing V2 realtime, history, recovery, push, and presence primitives.
AI Transport is a Protocol V2 convention layer. It does not replace Sockudo's realtime protocol or create AI-only storage. A session is a channel, every run is normal channel traffic, and the server supplies durable, ordered, recoverable primitives that SDKs reduce into UI state.
Sockudo AI Transport is heavily inspired by Ably AI Transport.
Ably's public AI Transport docs and SDK were the main product inspiration; Sockudo adapts that
model to Protocol V2, versioned messages, durable history, presence, push, and the local
@sockudo/client SDK.
Sockudo AI Transport is community-built and community-maintained. It is not an Ably product and is not supported by Ably.
Enable it with the ai-transport Cargo feature and runtime config:
[ai_transport]
enabled = true
[[ai_transport.channels]]
prefix = "private-ai-"End-to-end model
A normal Protocol V2 channel that carries every run event, message mutation, presence update, and recovery cursor.
The durable channel is the source of truth. HTTP streaming can start a run, but the answer is no longer tied to that HTTP response. A browser refresh, mobile handoff, tab close, or temporary network loss can recover from the same channel history.
The nine primitives
| Primitive | Sockudo subsystem |
|---|---|
| Session | One channel, usually private or presence, for a user/agent conversation. |
| Input | ai-input channel event from a verified user-capable connection or trusted server. |
| Output | ai-output mutable message created and appended by the agent/server side. |
| Run lifecycle | ai-run-start, ai-run-suspend, ai-run-resume, ai-run-end, and ai-cancel events with bounded extras.ai.transport headers. |
| Mutable state | Existing versioned messages: create, update, delete, append, summary. |
| Replay | Durable history, rewind, until_attach, and hot-to-durable recovery. |
| Identity | V2 capability tokens, signed channel auth, and server app-key HTTP auth. |
| Agent state | Presence channels plus V2 sockudo:presence_update. |
| Notifications | Existing push device/channel-subscription pipeline and optional [[push_rules]]. |
Run lifecycle
- 01Input creates the run
The client publishes ai-input create; Sockudo persists the input before agent work starts.
Client -> Sockudo -> Store - 02Agent opens output state
The worker emits ai-run-start and creates the ai-output mutable message for this run.
Agent -> Sockudo - 03Provider stream becomes append operations
Every token, tool delta, reasoning chunk, or metadata update is encoded as message.append.
append loop - 04Live clients receive rolled-up fanout
Sockudo can compact append bursts for WebSocket egress while preserving each original mutation internally.
Sockudo -> Client - 05Run closes into durable history
The agent emits ai-run-end complete; the final aggregate is visible to history, rewind, and recovery.
Agent -> Sockudo -> Store
ai-output is a normal mutable message. Streaming text, reasoning, tool input, tool output, and
source metadata are encoded as append/update operations by the SDK codec. Late joiners read the
aggregated visible state, while conformance, history, webhooks, and push can still observe the
original operation log.
What already exists
These features are not new AI-only subsystems:
MessageActionandVersionStorefor mutable messages.HistoryStore, rewind, and two-tier recovery.- Presence and presence-history.
- Annotation publish/delete/summary projection.
- Push providers, device registrations, channel subscriptions, publish status, queues, retries, feedback, and scheduler.
- Protocol V2 capability tokens and revocation.
- V1 isolation: V1 clients keep Pusher-compatible output.
What ai-transport adds
The feature adds validation and operational conventions:
- well-known AI event names
- bounded
extras.ai.transportandextras.ai.codec - anti-spoof checks for
*-client-idheaders - stream lifecycle tracking and active-stream limits
- append rollup as WebSocket egress optimization
- orphan stream cancellation
- conformance, benchmark, load, and chaos suites
The formal wire reference is AI Transport wire protocol. The provider integration guide is AI Transport providers.
AI SDK agents and durability
Sockudo durability and AI SDK agent durability solve different recovery problems. Use both when you run long-lived agents.
| Layer | Owns | Recovers from |
|---|---|---|
| Sockudo AI Transport | Published user inputs, assistant output chunks, approval responses, run lifecycle, and cursors. | Browser refresh, mobile handoff, reconnect, late join, transcript replay, and audit workflows. |
AI SDK WorkflowAgent or agent store | Pending agent steps, sleeps, retries, tool execution state, model-local context, and checkpoints. | Worker crash, deployment restart, long-running wait states, and agent workflow resume. |
| Model provider runtime | Provider-native realtime sessions, reasoning controls, uploaded files, and provider tool context. | Provider-specific retries, session resume, or media reconnect semantics. |
Sockudo history is intentionally not a workflow checkpoint store. Persist the AI SDK workflow run id
or agent checkpoint id in run metadata, then correlate it with channelName, runId, and
invocationId. When a workflow resumes, it can reload its own checkpoint and continue appending to
the same Sockudo session channel; clients recover the visible transcript from Sockudo.
Minimal server route
import { streamText, toUIMessageStream } from "ai";
import { createAgentSession } from "@sockudo/ai-transport/vercel";
export async function runAgent({ body, sockudo }) {
const session = createAgentSession({
client: sockudo,
channelName: body.channelName,
});
const run = session.createRun({
runId: body.runId,
invocationId: body.invocationId,
inputEventId: body.inputEventId,
clientId: body.clientId,
});
await run.start();
const result = streamText({
model: "openai/gpt-5-mini",
instructions: "You are a concise incident-room assistant.",
prompt: body.prompt,
abortSignal: run.abortSignal,
});
await run.streamResponse(toUIMessageStream({ stream: result.stream }));
await run.end("complete");
session.close();
}Minimal client
import Sockudo from "@sockudo/client";
import { useChat } from "@ai-sdk/vue";
import { provideChatTransport } from "@sockudo/ai-transport/vercel/vue";
const client = new Sockudo("app-key", {
wsHost: "realtime.example.com",
forceTLS: true,
protocolVersion: 2,
channelAuthorization: { endpoint: "/api/sockudo/channel-auth" },
});
const channelName = "private-ai:user-42:sess-01J";
const provider = provideChatTransport({
api: "/api/chat",
channelName,
client,
clientId: "user-42",
});
const { sendMessage } = useChat({
id: channelName,
transport: provider.chatTransport.value,
});
await sendMessage({ text: "Investigate the last failed deploy." });Session channel model
Use channel names that encode tenant/user/session ownership in your backend, for example:
private-ai:tenant-7:user-42:sess-01J...
presence-ai:tenant-7:sess-01J...Clients should never assert client_id or tenant identity in message bodies. Derive channel access
from signed auth or capability-token claims, then scope subscribe, publish, history,
message_append_own, and related capabilities to the exact channel or a narrow wildcard.
Compatibility
AI Transport is V2-only. V1 connections can still coexist on the same server, but they do not see V2 extras, mutable-message fields, recovery frames, annotations, or AI validation semantics.