New:Microsoft Teams Notifications Are Now Available in Socket.Learn more →
Get Started

@aibind/sveltekit

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@aibind/sveltekit

AI SDK bindings for SvelteKit — streaming, structured output, agents, server handlers, and remote functions

Source
npmnpm
Version
0.2.0
Version published
Weekly downloads
0
Maintainers
1
Weekly downloads
 
Created
Source

@aibind/sveltekit

AI SDK bindings for SvelteKit. Reactive Svelte 5 classes, server handlers, remote functions, and agents — all wired up with sensible defaults.

Features

🤏 Tiny — Ships only what you use. Tree-shakes per entry point. 🐇 Simple — Three classes: Stream, StructuredStream, Agent. Instantiate and .send(). 🧙‍♀️ Elegant — Svelte 5 runes ($state) on every field. No stores, no boilerplate. 🗃️ Highly customizable — Custom endpoints, custom fetch, per-request system overrides, named model registries. ⚛️ Reactive — Text, loading, error, done — all reactive. Just bind and go. 🔌 Batteries included — Server handler, remote functions, and default endpoints out of the box.

Install

npm install @aibind/sveltekit ai svelte

Peer dependencies: svelte ^5.53, ai ^6.0, @sveltejs/kit ^2.53.

Schema Libraries

StructuredStream works with any Standard Schema-compatible library. Install one:

# Zod (v4 recommended — has built-in JSON Schema support)
npm install zod

# Valibot (requires JSON Schema converter)
npm install valibot @valibot/to-json-schema

# ArkType (built-in JSON Schema via .toJsonSchema())
npm install arktype

Quick Start

1. Add the stream handler

// src/hooks.server.ts
import { createStreamHandler } from "@aibind/sveltekit/server";
import { anthropic } from "@ai-sdk/anthropic";

export const handle = createStreamHandler({
  model: anthropic("claude-sonnet-4-20250514"),
});

This handles /api/__aibind__/stream and /api/__aibind__/structured automatically.

2. Stream in a component

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

  const stream = new Stream({
    system: 'You are a helpful assistant.'
  });

  let prompt = $state('');
</script>

<form onsubmit={(e) => { e.preventDefault(); stream.send(prompt); }}>
  <input bind:value={prompt} />
  <button disabled={stream.loading}>Send</button>
</form>

{#if stream.text}
  <p>{stream.text}</p>
{/if}

Entry Points

@aibind/sveltekit — Client Classes

import { Stream, StructuredStream, defineModels } from "@aibind/sveltekit";

defineModels(models)

Define named AI models for type-safe model selection across client and server.

// src/lib/models.server.ts
import { defineModels } from "@aibind/sveltekit";
import { anthropic } from "@ai-sdk/anthropic";

export const models = defineModels({
  default: anthropic("claude-sonnet-4-20250514"),
  fast: anthropic("claude-haiku-20250514"),
});

export type Models = typeof models.$infer; // 'default' | 'fast'

Pass models to the server handler:

// src/hooks.server.ts
import { createStreamHandler } from "@aibind/sveltekit/server";
import { models } from "$lib/models.server";

export const handle = createStreamHandler({ models });

new Stream(options?)

Reactive streaming text. All properties are Svelte 5 $state fields. Endpoint defaults to /api/__aibind__/stream.

const stream = new Stream({
  model: "fast", // optional model key
  system: "You are a poet.",
  endpoint: "/api/custom/stream", // override default
  fetch: customFetch, // optional custom fetch
  onFinish: (text) => console.log(text),
  onError: (err) => console.error(err),
});

stream.send("Write a haiku");
stream.send("Now a limerick", { system: "Override system prompt" });
stream.text; // reactive accumulated text
stream.loading; // true while streaming
stream.error; // Error | null
stream.done; // true when complete
stream.abort(); // cancel in-flight request
stream.retry(); // re-send last prompt

new StructuredStream(options)

Streams JSON and parses partial objects as they arrive. Validates the final result with any Standard Schema-compatible library. Endpoint defaults to /api/__aibind__/structured.

import { StructuredStream } from "@aibind/sveltekit";
import { z } from "zod";

const analysis = new StructuredStream({
  schema: z.object({
    sentiment: z.enum(["positive", "negative", "neutral"]),
    score: z.number(),
    topics: z.array(z.string()),
  }),
  system: "Analyze sentiment. Return JSON matching the schema.",
});

analysis.send("I love this product!");
analysis.partial; // Partial<T> — updates as JSON streams in
analysis.data; // T | null — fully validated after completion
analysis.raw; // raw JSON string

@aibind/sveltekit/server — Stream Handler

import { createStreamHandler, ServerAgent } from "@aibind/sveltekit/server";

createStreamHandler(config)

SvelteKit handle hook that serves streaming endpoints.

// Single model
export const handle = createStreamHandler({
  model: anthropic("claude-sonnet-4-20250514"),
  prefix: "/api/__aibind__", // default
});

// Multi-model
export const handle = createStreamHandler({ models });

Handles two routes:

  • POST {prefix}/stream — text streaming
  • POST {prefix}/structured — JSON streaming

ServerAgent

Server-side agent with tools, system prompt, and multi-step tool loops.

import { ServerAgent } from "@aibind/sveltekit/server";
import { tool, stepCountIs } from "ai";
import { z } from "zod";

const agent = new ServerAgent({
  model: anthropic("claude-sonnet-4-20250514"),
  system: "You are a helpful assistant with access to tools.",
  tools: {
    get_weather: tool({
      description: "Get weather for a city",
      inputSchema: z.object({ city: z.string() }),
      execute: async ({ city }) => ({
        city,
        temperature: "72°F",
        condition: "sunny",
      }),
    }),
  },
  stopWhen: stepCountIs(5),
});

// In a SvelteKit endpoint:
export async function POST({ request }) {
  const { messages } = await request.json();
  const lastMessage = messages[messages.length - 1];
  const result = agent.stream(lastMessage.content, {
    messages: messages.slice(0, -1),
  });
  return result.toTextStreamResponse();
}

@aibind/sveltekit/remote — SvelteKit Remote Functions

import { AIRemote } from "@aibind/sveltekit/remote";

Requires @sveltejs/kit ^2.53.

new AIRemote(model)

Wraps SvelteKit's remote functions with AI SDK.

// src/lib/ai.server.ts
import { AIRemote } from "@aibind/sveltekit/remote";

export const ai = new AIRemote(anthropic("claude-sonnet-4-20250514"));
ai.query(schema, promptFn) — Text response
// src/routes/api/summarize.remote.ts
import { ai } from "$lib/ai.server";
import { z } from "zod";

export const summarize = ai.query(
  z.string(),
  (text) => `Summarize this: ${text}`,
);
ai.structuredQuery({ input, output, prompt }) — Typed response
export const analyze = ai.structuredQuery({
  input: z.string(),
  output: z.object({
    sentiment: z.enum(["positive", "negative", "neutral"]),
    confidence: z.number(),
  }),
  prompt: (text) => `Analyze: ${text}`,
  system: "Return JSON matching the output schema.",
});
ai.command(schema, handler) — Mutations
export const generatePost = ai.command(
  z.object({ topic: z.string() }),
  async (input, { model }) => {
    const result = await generateText({
      model,
      prompt: `Write about ${input.topic}`,
    });
    await db.posts.create({ content: result.text });
    return { id: post.id };
  },
);

@aibind/sveltekit/agent — Client Agent

import { Agent } from "@aibind/sveltekit/agent";

new Agent(options?)

Reactive agent state. Endpoint defaults to /api/__aibind__/agent.

<script lang="ts">
  import { Agent } from '@aibind/sveltekit/agent';

  const agent = new Agent();

  let prompt = $state('');
</script>

<form onsubmit={(e) => { e.preventDefault(); agent.send(prompt); prompt = ''; }}>
  <input bind:value={prompt} />
  <button disabled={agent.status === 'running'}>Send</button>
</form>

{#each agent.messages as message (message.id)}
  <div class={message.role}>{message.content}</div>
{/each}

{#if agent.status === 'running'}
  <button onclick={() => agent.stop()}>Stop</button>
{/if}

Reactive properties:

  • messages — array of { id, role, content, type } messages
  • status — 'idle' | 'running' | 'awaiting-approval' | 'error'
  • error — Error | null
  • pendingApproval — { id, toolName, args } | null

Methods:

  • send(prompt) — send a message, streams response incrementally
  • stop() — abort the current request
  • approve(id) / deny(id) — respond to tool approval requests

@aibind/sveltekit/markdown — Streaming Markdown

import { StreamMarkdown } from "@aibind/sveltekit/markdown";

Renders streaming markdown with recovery for unterminated syntax. Uses @aibind/markdown under the hood.

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

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

<StreamMarkdown text={stream.text} streaming={stream.loading} />

Props:

  • text — markdown string to render
  • streaming — when true, applies markdown recovery (closes unterminated bold, code blocks, etc.)
  • class — optional CSS class

@aibind/sveltekit/history — Branching Conversation History

import {
  ReactiveChatHistory,
  ReactiveMessageTree,
  ChatHistory,
  MessageTree,
} from "@aibind/sveltekit/history";

Tree-structured conversation history with branching support. Edit messages, regenerate responses, and navigate alternatives (ChatGPT-style).

<script lang="ts">
  import { ReactiveChatHistory } from '@aibind/sveltekit/history';

  const chat = new ReactiveChatHistory<{ role: string; content: string }>();
  chat.append({ role: 'user', content: 'Hello' });
  chat.append({ role: 'assistant', content: 'Hi!' });
</script>

{#each chat.messages as msg, i}
  <div>{msg.role}: {msg.content}</div>
  {#if chat.hasAlternatives(chat.nodeIds[i])}
    <button onclick={() => chat.prevAlternative(chat.nodeIds[i])}>←</button>
    {chat.alternativeIndex(chat.nodeIds[i]) + 1}/{chat.alternativeCount(chat.nodeIds[i])}
    <button onclick={() => chat.nextAlternative(chat.nodeIds[i])}>→</button>
  {/if}
{/each}

See @aibind/core README for full API documentation.

Requirements

  • Svelte 5.53+
  • SvelteKit 2.53+
  • AI SDK 6.0+
  • Node.js 20+

License

MIT

Keywords

svelte

FAQs

Package last updated on 04 Mar 2026

Related posts