Skip to content

Streaming ​

aibind's streaming API sends a prompt to your server and streams back text in real-time.

How It Works ​

  1. Client sends a POST to your endpoint with { prompt, model?, system? }
  2. Server resolves the model and calls streamText() from the AI SDK
  3. Response streams back as raw text chunks
  4. Client accumulates text and updates reactive state

Client API ​

Each framework has its own reactive wrapper, but the returned API surface is the same.

svelte
<script lang="ts">
  import { Stream } from "@aibind/sveltekit";

  const stream = new Stream({
    model: "fast",
    system: "You are a helpful assistant.",
  });
</script>

<button onclick={() => stream.send("Hello!")}>Send</button>
<p>{stream.text}</p>
<p>Loading: {stream.loading}, Done: {stream.done}</p>
tsx
"use client";

import { useStream } from "@aibind/nextjs";

function Chat() {
  const { text, loading, send, abort, retry } = useStream({
    model: "fast",
    system: "You are a helpful assistant.",
  });

  return (
    <div>
      <button onClick={() => send("Hello!")}>Send</button>
      <p>{text}</p>
    </div>
  );
}
vue
<script setup lang="ts">
import { useStream } from "@aibind/nuxt";

const { text, loading, send, abort, retry } = useStream({
  model: "fast",
  system: "You are a helpful assistant.",
});
</script>

<template>
  <button @click="send('Hello!')">Send</button>
  <p>{{ text }}</p>
  <p>Loading: {{ loading }}, Done: {{ done }}</p>
</template>
tsx
import { useStream } from "@aibind/solidstart";

function Chat() {
  const { text, loading, send, abort, retry } = useStream({
    model: "fast",
    system: "You are a helpful assistant.",
  });

  return (
    <div>
      <button onClick={() => send("Hello!")}>Send</button>
      <p>{text()}</p>
      <p>
        Loading: {loading()}, Done: {done()}
      </p>
    </div>
  );
}
tsx
import { useStream } from "@aibind/tanstack-start";

function Chat() {
  const { text, loading, send, abort, retry } = useStream({
    model: "fast",
    system: "You are a helpful assistant.",
  });

  return (
    <div>
      <button onClick={() => send("Hello!")}>Send</button>
      <p>{text}</p>
    </div>
  );
}

Returned State ​

PropertyTypeDescription
textstringAccumulated streamed text
loadingbooleanWhether a stream is in progress
donebooleanWhether the stream finished
errorError | nullAny error that occurred
statusStreamStatus'idle' | 'streaming' | 'stopped' | 'resuming'
streamIdstring | nullID for durable stream operations
canResumebooleanWhether the stream supports resume
modelM | undefinedCurrent persistent model
setModel(m: M) => voidChange persistent model for all future sends

Methods ​

MethodDescription
send(prompt, opts?)Start streaming with the given prompt
abort()Cancel the current stream
retry()Re-send the last prompt
stop()Stop and save stream for later resume
resume()Resume a stopped stream
speak()Pipe stream to Web Speech API; returns cleanup function
broadcast(name)Sync stream state to other tabs via BroadcastChannel
destroy()Remove event listeners (call when controller is done)

Options ​

OptionTypeDescription
modelstringNamed model key (from defineModels)
systemstringSystem prompt
endpointstringCustom endpoint (fullstack packages default to /__aibind__/stream)
fetchtypeof fetchCustom fetch function
onFinish(text: string) => voidCalled when stream completes
onError(error: Error) => voidCalled on error
sessionIdstringEnable server-side conversation history (see Conversation Store)
autoResumebooleanAuto-suspend on tab hide, auto-resume on tab focus (requires durable streams)

stream.speak() ​

Pipe the streaming response into the browser's SpeechSynthesis API. Audio playback starts after the first complete sentence — no waiting for the full response to finish. Returns a cleanup function.

ts
const stream = new Stream({ endpoint: "..." });
const stopSpeaking = stream.speak();

stream.send("Explain the water cycle");
// sentences play back as they arrive

stopSpeaking(); // cancel at any time

No-op in non-browser environments. Zero dependencies — uses window.speechSynthesis.

Tab-switch Auto-resume ​

Set autoResume: true to automatically suspend the stream when the tab becomes hidden and resume when it regains focus — backed by the existing durable stream infrastructure.

ts
const stream = new Stream({ endpoint: "...", autoResume: true });

Requires resumable: true on the server handler. Call stream.destroy() when the controller is no longer needed to remove the visibilitychange listener.

Reactivity by Framework ​

The API is identical — only the access pattern differs:

FrameworkAccess patternExample
SvelteDirect propertystream.text
ReactDirect valuetext (from hook)
Vue.valuetext.value
SolidFunction calltext()

Server Handler ​

The server handler is created once and handles all routing:

ts
import { createStreamHandler } from "@aibind/sveltekit/server";
import { models } from "./models.server";

export const handle = createStreamHandler({ models });

It automatically routes /__aibind__/stream and /__aibind__/structured requests.

Released under the MIT License.