본문으로 건너뛰기

@tanstack/ai-svelte

TanStack AI를 위한 Svelte 5 바인딩으로, Svelte runes를 사용해 헤드리스 클라이언트용 반응형 팩토리 함수를 제공합니다.

설치

npm install @tanstack/ai-svelte

createChat(options)

완전한 타입 안전성을 갖춘 Svelte 5 채팅 상태 관리용 팩토리 함수입니다.

import { createChat, fetchServerSentEvents } from "@tanstack/ai-svelte";
import {
createChatClientOptions,
type InferChatMessages,
} from "@tanstack/ai-client";
import { toolDefinition } from "@tanstack/ai";
import { z } from "zod";

const updateUIDef = toolDefinition({
name: "updateUI",
description: "Update the UI with a notification",
inputSchema: z.object({
message: z.string(),
}),
outputSchema: z.object({ success: z.boolean() }),
});

// In <script> block
let notification = "";

const updateUI = updateUIDef.client((input) => {
notification = input.message;
return { success: true };
});

const tools = [updateUI];

const chatOptions = createChatClientOptions({
connection: fetchServerSentEvents("/api/chat"),
tools,
});

// Fully typed messages!
type ChatMessages = InferChatMessages<typeof chatOptions>;

const chat = createChat(chatOptions);
// Access: chat.messages, chat.sendMessage, chat.isLoading, chat.error

옵션

@tanstack/ai-clientChatClientOptions를 확장합니다(내부 상태 콜백 제외).

  • connection - Connection adapter (필수)
  • tools? - 클라이언트 도구 구현 배열(.client() 메서드 포함)
  • initialMessages? - 초기 메시지 배열
  • threadId? - 이 채팅의 유일한 식별자입니다. 영속성이 켜져 있으면 필요합니다. 생략하면 마운트 후 생성됩니다.
  • forwardedProps? - AG-UI RunAgentInput.forwardedProps 필드에서 서버로 전달되는 클라이언트 제어 JSON입니다(예: { provider: 'openai', model: 'gpt-5.5' }).
  • body? - 더 이상 권장되지 않습니다. 대신 forwardedProps를 사용합니다. 이전 버전과의 호환성을 위해 계속 작동하며, 전송 시 값이 forwardedProps에 병합됩니다.
  • byok? - defineByok의 선택적 BYOK 키링입니다. 전송할 때마다 클라이언트가 확인된 provider를 준비하고 x-byok-* 요청 헤더를 추가합니다. 키는 body에 절대 포함되지 않습니다.
  • byokProvider? - 이 채팅의 provider slug를 반환하는 선택적 함수입니다. slug를 반환하면 해당 키만 준비해 전송합니다. 그렇지 않으면 forwardedProps, body, 호출별 sendMessage body의 병합된 provider를 사용합니다. 나중에 지정된 소스가 우선합니다. slug가 확인되지 않으면 저장된 모든 키를 첨부하는 대신 전송에서 오류가 발생합니다.
  • context? - 클라이언트 도구 구현에 전달되는 타입이 지정된 클라이언트 로컬 런타임 컨텍스트입니다. 이 값은 서버로 직렬화되지 않습니다.
  • live? - 라이브 구독 모드를 활성화합니다(생성 시 구독).
  • onResponse? - 응답을 받을 때 호출되는 콜백
  • onChunk? - 스트림 청크를 받을 때 호출되는 콜백
  • onFinish? - 응답이 완료될 때 호출되는 콜백
  • onError? - 오류가 발생할 때 호출되는 콜백
  • onInterruptStateChange? - 인터럽트 상태가 변경될 때 호출되는 콜백입니다. 컨텍스트 소스는 복원된 상태의 경우 hydrate, 스트리밍 또는 클라이언트가 시작한 업데이트의 경우 live입니다.
  • onCustomEvent? - 사용자 지정 스트림 이벤트용 콜백
  • streamProcessor? - 스트림 처리 구성

참고: 클라이언트 도구는 이제 자동으로 실행되므로 onToolCall 콜백이 필요하지 않습니다.

반환값

import type {
UIMessage,
MultimodalContent,
ChatClientState,
ConnectionStatus,
SendMessageOptions,
} from "@tanstack/ai-client";
import type { ModelMessage } from "@tanstack/ai";

interface CreateChatReturn<TContext = unknown> {
readonly messages: UIMessage[];
sendMessage: (
content: string | MultimodalContent,
options?: SendMessageOptions,
) => Promise<void>;
append: (message: ModelMessage | UIMessage) => Promise<void>;
addToolResult: (result: {
toolCallId: string;
tool: string;
output: any;
state?: "output-available" | "output-error";
errorText?: string;
}) => Promise<void>;
addToolApprovalResponse: (response: {
id: string;
approved: boolean;
}) => Promise<void>;
reload: () => Promise<void>;
stop: () => void;
readonly isLoading: boolean;
readonly error: Error | undefined;
readonly status: ChatClientState;
readonly isSubscribed: boolean;
readonly connectionStatus: ConnectionStatus;
readonly sessionGenerating: boolean;
setMessages: (messages: UIMessage[]) => void;
clear: () => void;
/** @deprecated Use `updateForwardedProps` instead. */
updateBody: (body: Record<string, any>) => void;
updateForwardedProps: (forwardedProps: Record<string, any>) => void;
updateContext: (context: TContext) => void;
}

React/Vue와의 주요 차이점:

  • create* 명명 -- 훅이 아닌 팩토리 함수입니다. 어떤 라이프사이클 바깥에서도 호출합니다.
  • 반응형 getter -- 상태 속성(messages, isLoading, error, status, isSubscribed, connectionStatus, sessionGenerating)은 getter를 통한 Svelte 5 $state입니다. 직접 액세스합니다(예: chat.messages, chat.messages.value가 아님).
  • 자동 정리 없음 -- React/Vue/Solid와 달리 createChat은 자동으로 dispose하지 않습니다. 컴포넌트가 언마운트될 때(예: onDestroy 또는 $effect 반환문에서) chat.stop()을 수동으로 호출합니다.
  • updateForwardedProps() -- AG-UI forwardedProps를 동적으로 업데이트합니다(예: 모델 선택). Vue에서는 forwardedProps 옵션 변경 사항이 watch를 통해 동기화되지만, Svelte에서는 이 메서드를 명시적으로 호출합니다. 기존 updateBody()도 사용할 수 있지만 더 이상 권장되지 않습니다.
  • .svelte.ts 파일 -- 소스 파일은 Svelte 5 rune을 지원하기 위해 .svelte.ts 확장자를 사용합니다.

createByok(client)

Svelte 5에서 ByokClient 스냅샷을 구독합니다. 컴포넌트 초기화 중 호출합니다.

import { createByok } from "@tanstack/ai-svelte";
import { byok } from "./byok";

const byokState = createByok(byok);

객체를 유지합니다. byokState.snapshot은 반응형 getter(status, locked, prompt)입니다. snapshot을 구조 분해하면 첫 번째 값으로 고정됩니다. 마크업 또는 $derived에서 읽습니다. 자체 UI에서 byok.update(provider, value)를 호출해 키를 저장합니다. Bring Your Own Key를 참조하세요.

연결 어댑터

편의를 위해 @tanstack/ai-client에서 다시 내보냅니다.

import {
fetchServerSentEvents,
fetchHttpStream,
stream,
type ConnectionAdapter,
} from "@tanstack/ai-svelte";

예시: 기본 채팅

<script lang="ts">
import { createChat, fetchServerSentEvents } from "@tanstack/ai-svelte";

let input = $state("");

const chat = createChat({
connection: fetchServerSentEvents("/api/chat"),
});

const handleSubmit = (e: Event) => {
e.preventDefault();
if (input.trim() && !chat.isLoading) {
chat.sendMessage(input);
input = "";
}
};
</script>

<div>
<div>
{#each chat.messages as message (message.id)}
<div>
<strong>{message.role}:</strong>
{#each message.parts as part, idx}
{#if part.type === "thinking"}
<div class="text-sm text-gray-500 italic">
Thinking: {part.content}
</div>
{:else if part.type === "text"}
<span>{part.content}</span>
{/if}
{/each}
</div>
{/each}
</div>
<form onsubmit={handleSubmit}>
<input bind:value={input} disabled={chat.isLoading} />
<button type="submit" disabled={chat.isLoading}>Send</button>
</form>
</div>

예시: 도구 승인

<script lang="ts">
import { createChat, fetchServerSentEvents } from "@tanstack/ai-svelte";

const chat = createChat({
connection: fetchServerSentEvents("/api/chat"),
});
</script>

<div>
{#each chat.messages as message (message.id)}
{#each message.parts as part}
{#if part.type === "tool-call" && part.state === "approval-requested" && part.approval}
<div>
<p>Approve: {part.name}</p>
<button
onclick={() =>
chat.addToolApprovalResponse({
id: part.approval.id,
approved: true,
})}
>
Approve
</button>
<button
onclick={() =>
chat.addToolApprovalResponse({
id: part.approval.id,
approved: false,
})}
>
Deny
</button>
</div>
{/if}
{/each}
{/each}
</div>

예시: 타입 안전성을 갖춘 클라이언트 도구

<script lang="ts">
import { createChat, fetchServerSentEvents } from "@tanstack/ai-svelte";
import {
createChatClientOptions,
type InferChatMessages,
} from "@tanstack/ai-client";
import { updateUIDef, saveToStorageDef } from "./tool-definitions";

let notification = $state(null);

// Create client implementations
const updateUI = updateUIDef.client((input) => {
// input is fully typed!
notification = { message: input.message, type: input.type };
return { success: true };
});

const saveToStorage = saveToStorageDef.client((input) => {
localStorage.setItem(input.key, input.value);
return { saved: true };
});

// Create typed tools array (no 'as const' needed!)
const tools = [updateUI, saveToStorage];

const chat = createChat({
connection: fetchServerSentEvents("/api/chat"),
tools, // Automatic execution, full type safety
});
</script>

<div>
{#each chat.messages as message (message.id)}
{#each message.parts as part}
{#if part.type === "tool-call" && part.name === "updateUI"}
<div>Tool executed: {part.name}</div>
{/if}
{/each}
{/each}
</div>

생성 함수

이미지, 음성, 전사, 요약, 동영상과 같은 일회성 생성 작업을 위한 팩토리 함수입니다. 모두 동일한 패턴을 따릅니다. connection 또는 fetcher를 제공하고 generate()를 호출한 다음 반응형 상태를 읽습니다.

createGeneration(options)

사용자 지정 생성 타입을 위한 기본 팩토리입니다. 아래의 모든 특수화된 함수는 이를 기반으로 합니다.

import { createGeneration, fetchServerSentEvents } from "@tanstack/ai-svelte";

const gen = createGeneration({
connection: fetchServerSentEvents("/api/generate/custom"),
});

// gen.generate({ prompt: 'Hello' })
// gen.result, gen.isLoading, gen.error, gen.status

옵션: connection?, fetcher?, threadId?, body?, onResult?, onError?, onProgress?, onChunk?

반환값: generate, result, isLoading, error, status, stop, reset, runId, updateBody -- 모든 상태 속성은 반응형 getter입니다.

createGenerateImage(options)

이미지 생성 팩토리입니다. generate()ImageGenerateInput을 받고 결과는 ImageGenerationResult입니다.

createGenerateSpeech(options)

텍스트 음성 변환 팩토리입니다. generate()SpeechGenerateInput을 받고 결과는 TTSResult입니다.

createTranscription(options)

오디오 전사 팩토리입니다. generate()TranscriptionGenerateInput을 받고 결과는 TranscriptionResult입니다.

createSummarize(options)

텍스트 요약 팩토리입니다. generate()SummarizeGenerateInput을 받고 결과는 SummarizationResult입니다.

createGenerateVideo(options)

작업 폴링을 지원하는 동영상 생성 팩토리입니다. 추가로 jobIdvideoStatus 반응형 getter를 반환합니다. onJobCreated?onStatusUpdate? 콜백도 추가로 받습니다.

어떤 생성 함수에도 자동 정리는 포함되지 않습니다. 완료되면 .stop()을 수동으로 호출합니다.

createChatClientOptions(options)

타입이 지정된 채팅 옵션을 생성하는 헬퍼입니다(@tanstack/ai-client에서 다시 내보냄).

import {
createChatClientOptions,
fetchServerSentEvents,
type InferChatMessages,
} from "@tanstack/ai-client";
import { tool1, tool2 } from "./tools";

// Create typed tools array (no 'as const' needed!)
const tools = [tool1, tool2];

const chatOptions = createChatClientOptions({
connection: fetchServerSentEvents("/api/chat"),
tools,
});

type Messages = InferChatMessages<typeof chatOptions>;

타입

@tanstack/ai-client에서 다시 내보냅니다.

  • UIMessage<TTools> - 도구 타입 매개변수가 있는 메시지 타입
  • MessagePart<TTools> - 도구 타입 매개변수가 있는 메시지 파트
  • TextPart - 텍스트 콘텐츠 파트
  • ThinkingPart - 사고 콘텐츠 파트
  • ToolCallPart<TTools> - 도구 호출 파트(판별된 유니온)
  • ToolResultPart - 도구 결과 파트
  • ChatClientOptions<TTools, TContext> - 타입이 지정된 클라이언트 런타임 컨텍스트가 있는 채팅 클라이언트 옵션
  • ConnectionAdapter - 연결 어댑터 인터페이스
  • InferChatMessages<T> - 옵션에서 메시지 타입 추출
  • ChatRequestBody - 요청 본문 타입
  • GenerationClientState - 생성 라이프사이클 상태
  • ImageGenerateInput - 이미지 생성 입력 타입
  • SpeechGenerateInput - 음성 생성 입력 타입
  • TranscriptionGenerateInput - 전사 입력 타입
  • SummarizeGenerateInput - 요약 입력 타입
  • VideoGenerateInput - 동영상 생성 입력 타입
  • VideoGenerateResult - 동영상 생성 결과 타입
  • VideoStatusInfo - 동영상 작업 상태 정보

@tanstack/ai에서 다시 내보냅니다.

  • toolDefinition() - 아이소모픽 도구 정의 생성
  • ToolDefinitionInstance - 도구 정의 타입
  • ClientTool - 클라이언트 도구 타입
  • ServerTool - 서버 도구 타입

다음 단계