Text Stream

Docs

Raw streaming sends text chunks as soon as they are generated. This demo reads a response body stream and appends each chunk to the page, without event names or reconnect metadata. Use it when you only need text to appear quickly and the browser doesn't need typed events. If you need event names, completion events, or browser-managed reconnects, see SSE streaming.

Prompt
What are AI agents and how do they work?
Anthropic/Claude Opus 4.8
Ready
Output will appear here as text streams in...
Reference Code
import { Hono } from "hono";
import { AIGatewayClient } from "@agentuity/aigateway";
import { getAIGatewayStreamDeltaText } from "@agentuity/aigateway";

const app = new Hono();
const gateway = new AIGatewayClient();
const encoder = new TextEncoder();
// Default model in the live demo; any gateway model id works here.
const MODEL = "anthropic/claude-opus-4-8";

app.post("/api/stream", async (c) => {
  const body: unknown = await c.req.json();
  const prompt =
    typeof body === "object" && body !== null && "prompt" in body
      ? String(body.prompt)
      : "Write a short note about AI agents.";

  const result = await gateway.streamRequest({
    path: "/",
    body: {
      model: MODEL,
      stream: true,
      messages: [{ role: "user", content: prompt }],
    },
  });

  const textStream = new ReadableStream<Uint8Array>({
    async start(controller) {
      for await (const chunk of readGatewayText(result.stream)) {
        controller.enqueue(encoder.encode(chunk));
      }
      controller.close();
    },
  });

  return new Response(textStream, {
    headers: { "content-type": "text/plain; charset=utf-8" },
  });
});

// For named SSE events and an explicit "done" frame, see the SSE Stream demo.

// streamRequest() returns the provider's raw SSE bytes. Split frames on
// blank lines; the SDK decodes each provider's delta shape to plain text.
async function* readGatewayText(stream: ReadableStream<Uint8Array>) {
  const reader = stream.getReader();
  const decoder = new TextDecoder();
  let buffer = "";

  try {
    for (;;) {
      const { value, done } = await reader.read();
      if (done) break;

      buffer += decoder.decode(value, { stream: true });
      const frames = buffer.split(/\r?\n\r?\n/);
      buffer = frames.pop() ?? "";

      for (const frame of frames) {
        const text = frameText(frame);
        if (text) yield text;
      }
    }

    buffer += decoder.decode();
    const text = frameText(buffer);
    if (text) yield text;
  } finally {
    reader.releaseLock();
  }
}

function frameText(frame: string): string {
  const data = frame
    .split(/\r?\n/)
    .filter((line) => line.startsWith("data:"))
    .map((line) => line.slice(5).trimStart())
    .join("\n")
    .trim();

  if (!data || data === "[DONE]") return "";

  try {
    return getAIGatewayStreamDeltaText(JSON.parse(data));
  } catch {
    return "";
  }
}

export default app;
Ready
Output will appear here...