Sockudo
Server

AI Transport providers

Stream model output from Vercel AI SDK, OpenAI, Anthropic, OpenAI-compatible APIs, and custom providers through Sockudo AI Transport.

Sockudo AI Transport is provider-neutral. Sockudo carries ordered, durable run state; your agent chooses how to call the model and converts provider output into AI SDK UI message chunks.

The JavaScript SDK has two integration families:

IntegrationImportBest for
Vercel AI SDK transport@sockudo/ai-transport/vercelApps already using ai, streamText, useChat, Vue, React, or Svelte AI SDK UI primitives.
Direct provider adapters@sockudo/ai-transport/providersWorkers that call OpenAI, Anthropic, OpenAI-compatible HTTP/SSE endpoints, or local model servers directly.
Core codec transport@sockudo/ai-transportCustom model protocols, custom UI projections, or non-Vercel message shapes.

Credits

Sockudo AI Transport is heavily inspired by Ably AI Transport, and Ably's public AI Transport docs and SDK were the main product inspiration for this layer. The Sockudo implementation maps those ideas onto Sockudo Protocol V2, durable history, versioned messages, presence, push, and the @sockudo/client SDK in this monorepo.

Sockudo AI Transport is community-built and community-maintained. It is not an Ably product and is not supported by Ably.

Provider flow

The provider never needs to know about connection recovery, rewind, history cursors, branch trees, presence, or multi-device fanout. It streams chunks. Sockudo makes those chunks durable and observable.

Vercel AI SDK

Use Vercel AI SDK when you want provider packages, tool calling, and UI message streams to stay in the ai ecosystem.

// server/api/chat.post.ts
import { streamText, toUIMessageStream } from "ai";
import { createAgentSession } from "@sockudo/ai-transport/vercel";
import { realtimeClient } from "../utils/sockudo";

export default defineEventHandler(async (event) => {
  const body = await readBody(event);

  const session = createAgentSession({
    client: realtimeClient(),
    channelName: body.channelName,
  });

  const run = session.createRun({
    runId: body.runId,
    invocationId: body.invocationId,
    inputEventId: body.inputEventId,
    clientId: body.clientId,
    onCancel(request) {
      return (
        request.filter.all === true ||
        request.matchedRunIds.includes(body.runId)
      );
    },
  });

  event.waitUntil?.(
    (async () => {
      await run.start();
      const result = streamText({
        model: "openai/gpt-5-mini",
        instructions: "You are a concise incident-room assistant.",
        prompt:
          body.messages
            .at(-1)
            ?.parts?.map((part) => part.text ?? "")
            .join("") ?? "",
        abortSignal: run.abortSignal,
      });
      await run.streamResponse(toUIMessageStream({ stream: result.stream }));
      await run.end("complete");
      session.close();
    })(),
  );

  setResponseStatus(event, 202);
});

The frontend can use the Vercel-compatible transport in React, Vue, or Svelte.

import { useChat } from "@ai-sdk/vue";
import { provideChatTransport } from "@sockudo/ai-transport/vercel/vue";

const provider = provideChatTransport({
  api: "/api/chat",
  channelName: "private-ai:user-42:sess-01J",
  client: sockudoClient,
  clientId: "user-42",
});

const { sendMessage } = useChat({
  id: "private-ai:user-42:sess-01J",
  transport: provider.chatTransport.value,
});

await sendMessage({ text: "Summarize the last deploy failure." });

AI SDK 7 feature coverage

AI SDK 7 does not require a separate Sockudo server mode. The compatibility surface is the AI SDK UI message stream: Sockudo persists ordered UI chunks, run lifecycle events, approval responses, and metadata, while the app runtime keeps provider calls, tool execution, and agent-local state.

AI SDK capabilitySockudo behavior
Reasoning controlsPass model options through streamText; Sockudo carries emitted reasoning text and reasoning-file chunks.
Tool context and runtime contextKeep context on the trusted worker. Publish only safe derived metadata, never provider secrets or raw tool credentials.
Provider file and skill uploadsLet the provider own uploads and references. Sockudo can carry file, source, reasoning-file, or custom chunks that point at externally stored assets.
MCP Apps and custom UI partsPreserve custom chunks and provider metadata. Rendering app iframes or custom widgets remains a client responsibility.
Tool approvalsPersist approval requests and responses as normal run state. The app still owns approval policy, signature checks, and tool execution authorization.
WorkflowAgent and HarnessAgent outputStream their UI-message output through toUIMessageStream. Use the workflow store for agent checkpoints and Sockudo for transcript/reconnect history.
Realtime voiceKeep low-latency audio on the provider's realtime channel. Mirror transcripts, tool calls, approvals, and final state through Sockudo.
Video generationStore generated media outside Sockudo and publish progress, asset URLs, thumbnails, or final file parts through the AI session channel.
Telemetry and lifecycle callbacksCorrelate AI SDK spans with channelName, runId, and invocationId. Sockudo metrics continue to describe transport, history, and fanout health.

Direct provider support

The @sockudo/ai-transport/providers entry point supports these built-in adapters:

Provider pathFunctionNotes
OpenAI-compatible HTTP/SSEstreamOpenAICompatibleTextUses Chat Completions-compatible /chat/completions streaming.
OpenAI-compatible reusable providercreateOpenAICompatibleProviderGood for named provider registries.
OpenAI SDK Chat CompletionsstreamOpenAIChatCompletion / createOpenAISdkProviderUses a structural subset of the official OpenAI SDK.
OpenAI SDK ResponsesstreamOpenAIResponse / createOpenAISdkProvider({ mode: "responses" })Maps output text and tool argument deltas to UI chunks.
Anthropic SDK MessagesstreamAnthropicMessage / createAnthropicSdkProviderMaps text, thinking, tool use, and finish reasons.

OpenAI-compatible presets are:

NameDefault base URL
openaihttps://api.openai.com/v1
openrouterhttps://openrouter.ai/api/v1
groqhttps://api.groq.com/openai/v1
togetheraihttps://api.together.xyz/v1
fireworkshttps://api.fireworks.ai/inference/v1
deepseekhttps://api.deepseek.com
perplexityhttps://api.perplexity.ai
mistralhttps://api.mistral.ai/v1
xaihttps://api.x.ai/v1
ollamahttp://127.0.0.1:11434/v1
lmstudiohttp://127.0.0.1:1234/v1

Local providers such as Ollama and LM Studio may omit apiKey when the local server does not require one.

OpenAI-compatible HTTP example

import {
  createOpenAICompatibleProvider,
  runDirectLlm,
} from "@sockudo/ai-transport/providers";

const provider = createOpenAICompatibleProvider({
  provider: "groq",
  apiKey: process.env.GROQ_API_KEY,
  model: "llama-3.3-70b-versatile",
});

await runDirectLlm(run, provider, {
  prompt: "Write a remediation plan for a Redis fanout incident.",
  maxOutputTokens: 800,
});

OpenAI SDK examples

import OpenAI from "openai";
import {
  createOpenAISdkProvider,
  runDirectLlm,
} from "@sockudo/ai-transport/providers";

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

const chatProvider = createOpenAISdkProvider({
  client: openai,
  mode: "chat",
  model: "gpt-4.1-mini",
});

await runDirectLlm(run, chatProvider, {
  messages: [
    { role: "system", content: "Answer as a production engineer." },
    { role: "user", content: "Why did reconnect recovery fail?" },
  ],
});
const responsesProvider = createOpenAISdkProvider({
  client: openai,
  mode: "responses",
  model: "gpt-5-mini",
});

await runDirectLlm(run, responsesProvider, {
  prompt: "Explain the latest channel history page in plain English.",
  body: {
    reasoning: { effort: "low" },
  },
});

Anthropic SDK example

import Anthropic from "@anthropic-ai/sdk";
import {
  createAnthropicSdkProvider,
  runDirectLlm,
} from "@sockudo/ai-transport/providers";

const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });

const provider = createAnthropicSdkProvider({
  client: anthropic,
  model: "claude-sonnet-4-5",
  system: "Be concise and include risk levels.",
});

await runDirectLlm(run, provider, {
  prompt: "Audit this failed push notification delivery chain.",
});

Provider registry

Use a registry when the UI lets a user or tenant select a model provider.

import {
  createAnthropicSdkProvider,
  createDirectLlmProviderRegistry,
  createOpenAICompatibleProvider,
} from "@sockudo/ai-transport/providers";

const providers = createDirectLlmProviderRegistry({
  groq: createOpenAICompatibleProvider({
    provider: "groq",
    apiKey: process.env.GROQ_API_KEY,
    model: "llama-3.3-70b-versatile",
  }),
  local: createOpenAICompatibleProvider({
    provider: "ollama",
    model: "llama3.2",
  }),
  anthropic: createAnthropicSdkProvider({
    client: anthropic,
    model: "claude-sonnet-4-5",
  }),
});

const stream = await providers.streamText("local", {
  prompt: "Return a JSON incident summary.",
});

Custom provider

Any provider that returns ReadableStream<VercelOutput> can participate.

import type { DirectLlmProvider } from "@sockudo/ai-transport/providers";

const provider: DirectLlmProvider = {
  async streamText(request) {
    const words = (request.prompt ?? "").split(/\s+/);

    return new ReadableStream({
      start(controller) {
        controller.enqueue({ type: "start" });
        controller.enqueue({ type: "text-start", id: "answer" });
        for (const word of words) {
          controller.enqueue({
            type: "text-delta",
            id: "answer",
            delta: `${word} `,
          });
        }
        controller.enqueue({ type: "text-end", id: "answer" });
        controller.enqueue({ type: "finish", finishReason: "stop" });
        controller.close();
      },
    });
  },
};

Tool calling and human approval

Tool calls are just streamed UI message chunks. The transport persists every tool-input delta and the final tool state, so a user can approve from another tab or after a reconnect.

For AI SDK 7 approval flows, treat the request and response as part of the transcript:

  1. The agent streams a tool-approval-request chunk with a stable approval id and tool call id.
  2. Sockudo stores that request on the ai-output mutable message and fans it out to every attached client.
  3. The client records an approval response on the assistant tool part. The Vercel chat transport diffs the optimistic message overlay and publishes a tool-approval-response input.
  4. The worker verifies the response, runs or denies the tool, then appends tool-result, tool-result-error, or output-denied state.

Use channel auth and V2 capabilities to decide who can approve. If the provider supplies approval signatures or automatic-approval markers, keep them with the approval chunk so the worker can verify them before executing the tool. Do not treat a client-rendered button click as sufficient authority by itself.

Realtime voice and generated media

AI SDK realtime voice sessions are optimized for provider-native WebSocket or WebRTC media paths. Sockudo should not proxy high-rate PCM frames, microphone buffers, or generated video bytes through mutable-message appends. Use Sockudo as the durable control and transcript plane:

  • publish session start, model, voice, and participant metadata
  • append transcript deltas, final transcript text, tool calls, and approval state
  • fan out presence for the user, agent, and handoff devices
  • publish push notifications or completion events when the media job finishes
  • store recordings, uploaded files, thumbnails, and generated videos in object storage, then publish references as file, source, or custom chunks

This keeps reconnect, rewind, audit, and multi-device UI recovery in Sockudo without putting latency-sensitive media on the same path as durable chat history.

Choosing an integration

You haveUse
Vercel AI SDK streamText already wired@sockudo/ai-transport/vercel
A provider with OpenAI-compatible SSEcreateOpenAICompatibleProvider
Official OpenAI SDKcreateOpenAISdkProvider
Official Anthropic SDKcreateAnthropicSdkProvider
A custom internal model gatewayDirectLlmProvider
A non-Vercel UI modelCore codec API from @sockudo/ai-transport
AI SDK agent or workflow outputConvert to UI message chunks, then stream through the Vercel transport
Realtime voice or generated videoProvider media path plus Sockudo transcript/control events

Keep provider API keys server-side. Browser clients should only receive Sockudo public app keys, private/presence auth responses, and short-lived Protocol V2 capability tokens.

On this page