@tanstack/ai-svelte 0.16.3 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import type { InferredClientContext } from '@tanstack/ai-client';
2
- import type { AnyClientTool, SchemaInput } from '@tanstack/ai';
2
+ import type { AnyClientTool, InterruptDefinition, SchemaInput } from '@tanstack/ai';
3
3
  import type { CreateChatOptions, CreateChatReturn } from './types';
4
4
  /**
5
5
  * Creates a reactive chat instance for Svelte 5.
@@ -31,4 +31,4 @@ import type { CreateChatOptions, CreateChatReturn } from './types';
31
31
  * </div>
32
32
  * ```
33
33
  */
34
- export declare function createChat<const TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>>(options: CreateChatOptions<TTools, TSchema, TContext>): CreateChatReturn<TTools, TSchema, TContext>;
34
+ export declare function createChat<const TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, const TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []>(options: CreateChatOptions<TTools, TSchema, TContext, TInterrupts>): CreateChatReturn<TTools, TSchema, TContext, TInterrupts>;
@@ -63,23 +63,27 @@ export function createChat(options) {
63
63
  const transport = options.connection
64
64
  ? { connection: options.connection }
65
65
  : { fetcher: options.fetcher };
66
- // The hook's identity is its `threadId`, which ChatClient also uses as the
67
- // persistence key — no separate `id`. When no `threadId` is given the client
68
- // generates one, so an ephemeral chat still works but is not restored on reload.
66
+ // The hook's identity is its `threadId`. When no `threadId` is given the
67
+ // client mints one after mount, so an ephemeral chat still works but is not
68
+ // restored on reload.
69
69
  const client = new ChatClient({
70
70
  devtoolsBridgeFactory: createChatDevtoolsBridge,
71
71
  ...transport,
72
72
  ...(options.initialMessages !== undefined && {
73
73
  initialMessages: options.initialMessages,
74
74
  }),
75
- ...(options.persistence !== undefined && {
76
- persistence: options.persistence,
77
- }),
75
+ ...(typeof options.threadId === 'string' && options.persistence
76
+ ? {
77
+ persistence: options.persistence,
78
+ threadId: options.threadId,
79
+ }
80
+ : {
81
+ ...(options.threadId !== undefined && { threadId: options.threadId }),
82
+ }),
78
83
  ...(options.initialResumeSnapshot !== undefined && {
79
84
  initialResumeSnapshot: options.initialResumeSnapshot,
80
85
  }),
81
86
  ...(options.body !== undefined && { body: options.body }),
82
- ...(options.threadId !== undefined && { threadId: options.threadId }),
83
87
  ...(options.forwardedProps !== undefined && {
84
88
  forwardedProps: options.forwardedProps,
85
89
  }),
@@ -101,6 +105,9 @@ export function createChat(options) {
101
105
  options.onError?.(err);
102
106
  },
103
107
  tools: options.tools,
108
+ ...(options.interrupts !== undefined && {
109
+ interrupts: options.interrupts,
110
+ }),
104
111
  ...(options.onCustomEvent !== undefined && {
105
112
  onCustomEvent: options.onCustomEvent,
106
113
  }),
@@ -136,9 +143,9 @@ export function createChat(options) {
136
143
  onRunIdChange: (nextRunId) => {
137
144
  runId = nextRunId;
138
145
  },
139
- onInterruptStateChange: (nextInterruptState) => {
146
+ onInterruptStateChange: (nextInterruptState, context) => {
140
147
  interruptState = nextInterruptState;
141
- options.onInterruptStateChange?.(nextInterruptState);
148
+ options.onInterruptStateChange?.(nextInterruptState, context);
142
149
  },
143
150
  });
144
151
  function syncResumeState() {
@@ -11,10 +11,6 @@ export interface CreateGenerateAudioOptions<TOutput = AudioGenerationResult> ext
11
11
  connection?: ConnectConnectionAdapter;
12
12
  /** Direct async function for audio generation */
13
13
  fetcher?: GenerationFetcher<AudioGenerateInput, AudioGenerationResult>;
14
- /**
15
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
16
- */
17
- id?: string;
18
14
  /** Additional body parameters to send with connect-based adapter requests */
19
15
  body?: Record<string, any>;
20
16
  /** Display options for TanStack AI Devtools. */
@@ -77,6 +73,6 @@ export interface CreateGenerateAudioReturn<TOutput = AudioGenerationResult> exte
77
73
  * </div>
78
74
  * ```
79
75
  */
80
- export declare function createGenerateAudio<TTransformed = void>(options: Omit<CreateGenerateAudioOptions, 'onResult' | 'persistence' | 'threadId' | 'id'> & {
76
+ export declare function createGenerateAudio<TTransformed = void>(options: Omit<CreateGenerateAudioOptions, 'onResult' | 'persistence' | 'threadId'> & {
81
77
  onResult?: (result: AudioGenerationResult) => TTransformed;
82
78
  } & GenerationPersistenceOptions): CreateGenerateAudioReturn<InferGenerationOutputFromReturn<AudioGenerationResult, TTransformed>>;
@@ -11,10 +11,6 @@ export interface CreateGenerateImageOptions<TOutput = ImageGenerationResult> ext
11
11
  connection?: ConnectConnectionAdapter;
12
12
  /** Direct async function for image generation */
13
13
  fetcher?: GenerationFetcher<ImageGenerateInput, ImageGenerationResult>;
14
- /**
15
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
16
- */
17
- id?: string;
18
14
  /** Additional body parameters to send with connect-based adapter requests */
19
15
  body?: Record<string, any>;
20
16
  /** Display options for TanStack AI Devtools. */
@@ -86,6 +82,6 @@ export interface CreateGenerateImageReturn<TOutput = ImageGenerationResult> exte
86
82
  * </div>
87
83
  * ```
88
84
  */
89
- export declare function createGenerateImage<TTransformed = void>(options: Omit<CreateGenerateImageOptions, 'onResult' | 'persistence' | 'threadId' | 'id'> & {
85
+ export declare function createGenerateImage<TTransformed = void>(options: Omit<CreateGenerateImageOptions, 'onResult' | 'persistence' | 'threadId'> & {
90
86
  onResult?: (result: ImageGenerationResult) => TTransformed;
91
87
  } & GenerationPersistenceOptions): CreateGenerateImageReturn<InferGenerationOutputFromReturn<ImageGenerationResult, TTransformed>>;
@@ -11,10 +11,6 @@ export interface CreateGenerateSpeechOptions<TOutput = TTSResult> extends Pick<C
11
11
  connection?: ConnectConnectionAdapter;
12
12
  /** Direct async function for speech generation */
13
13
  fetcher?: GenerationFetcher<SpeechGenerateInput, TTSResult>;
14
- /**
15
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
16
- */
17
- id?: string;
18
14
  /** Additional body parameters to send with connect-based adapter requests */
19
15
  body?: Record<string, any>;
20
16
  /** Display options for TanStack AI Devtools. */
@@ -77,6 +73,6 @@ export interface CreateGenerateSpeechReturn<TOutput = TTSResult> extends Omit<Cr
77
73
  * </div>
78
74
  * ```
79
75
  */
80
- export declare function createGenerateSpeech<TTransformed = void>(options: Omit<CreateGenerateSpeechOptions, 'onResult' | 'persistence' | 'threadId' | 'id'> & {
76
+ export declare function createGenerateSpeech<TTransformed = void>(options: Omit<CreateGenerateSpeechOptions, 'onResult' | 'persistence' | 'threadId'> & {
81
77
  onResult?: (result: TTSResult) => TTransformed;
82
78
  } & GenerationPersistenceOptions): CreateGenerateSpeechReturn<InferGenerationOutputFromReturn<TTSResult, TTransformed>>;
@@ -10,10 +10,6 @@ export interface CreateGenerateVideoOptions<TOutput = VideoGenerateResult> {
10
10
  connection?: ConnectConnectionAdapter;
11
11
  /** Direct async function that returns a completed video result */
12
12
  fetcher?: GenerationFetcher<VideoGenerateInput, VideoGenerateResult>;
13
- /**
14
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
15
- */
16
- id?: string;
17
13
  /** Additional body parameters to send with connect-based adapter requests */
18
14
  body?: Record<string, any>;
19
15
  /** Display options for TanStack AI Devtools. */
@@ -37,8 +33,8 @@ export interface CreateGenerateVideoOptions<TOutput = VideoGenerateResult> {
37
33
  * id on the wire, which the protocol requires.
38
34
  *
39
35
  * **Required whenever `persistence` is set** — an app that cannot name the
40
- * scope has nothing to restore to. Optional for ephemeral generations, where
41
- * it falls back to `id` purely to satisfy the wire.
36
+ * scope has nothing to restore to. Optional for ephemeral generations. If
37
+ * omitted, the client mints a wire id after mount.
42
38
  */
43
39
  threadId?: string;
44
40
  /**
@@ -140,6 +136,6 @@ export interface CreateGenerateVideoReturn<TOutput = VideoGenerateResult> {
140
136
  * </div>
141
137
  * ```
142
138
  */
143
- export declare function createGenerateVideo<TTransformed = void>(options: Omit<CreateGenerateVideoOptions, 'onResult' | 'persistence' | 'threadId' | 'id'> & {
139
+ export declare function createGenerateVideo<TTransformed = void>(options: Omit<CreateGenerateVideoOptions, 'onResult' | 'persistence' | 'threadId'> & {
144
140
  onResult?: (result: VideoGenerateResult) => TTransformed;
145
141
  } & GenerationPersistenceOptions): CreateGenerateVideoReturn<InferGenerationOutputFromReturn<VideoGenerateResult, TTransformed>>;
@@ -34,7 +34,6 @@ import { createVideoDevtoolsBridge } from '@tanstack/ai-client/devtools';
34
34
  // parameter is typed as `VideoGenerateResult` and `result` narrows to the
35
35
  // transform's return. See issue #848.
36
36
  export function createGenerateVideo(options) {
37
- const fallbackId = `video-${Date.now()}-${Math.random().toString(36).substring(7)}`;
38
37
  // Create reactive state using Svelte 5 runes
39
38
  let result = $state(null);
40
39
  let jobId = $state(null);
@@ -48,15 +47,18 @@ export function createGenerateVideo(options) {
48
47
  // is declared `body?: Record<string, any>` (absent vs. present) under
49
48
  // `exactOptionalPropertyTypes`. The optional caller `options.body` may be
50
49
  // undefined, in which case we want the key to be absent on the target.
51
- // Identity: pass `threadId` alone when set (never also pass deprecated `id`).
52
50
  const baseOptions = {
53
51
  body: options.body,
54
- ...(options.threadId !== undefined
55
- ? { threadId: options.threadId }
56
- : { id: options.id ?? fallbackId }),
57
- ...(options.persistence !== undefined && {
58
- persistence: options.persistence,
59
- }),
52
+ ...(typeof options.threadId === 'string' && options.persistence
53
+ ? {
54
+ persistence: options.persistence,
55
+ threadId: options.threadId,
56
+ }
57
+ : {
58
+ ...(options.threadId !== undefined && {
59
+ threadId: options.threadId,
60
+ }),
61
+ }),
60
62
  ...(options.hydrateGeneration !== undefined && {
61
63
  hydrateGeneration: options.hydrateGeneration,
62
64
  }),
@@ -14,10 +14,6 @@ export interface CreateGenerationOptions<TInput, TResult, TOutput = TResult> {
14
14
  connection?: ConnectConnectionAdapter;
15
15
  /** Direct async function for one-shot generation (no streaming protocol needed) */
16
16
  fetcher?: GenerationFetcher<TInput, TResult>;
17
- /**
18
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
19
- */
20
- id?: string;
21
17
  /** Additional body parameters to send with connect-based adapter requests */
22
18
  body?: Record<string, any>;
23
19
  /** Display options for TanStack AI Devtools. */
@@ -41,8 +37,8 @@ export interface CreateGenerationOptions<TInput, TResult, TOutput = TResult> {
41
37
  * id on the wire, which the protocol requires.
42
38
  *
43
39
  * **Required whenever `persistence` is set** — an app that cannot name the
44
- * scope has nothing to restore to. Optional for ephemeral generations, where
45
- * it falls back to `id` purely to satisfy the wire.
40
+ * scope has nothing to restore to. Optional for ephemeral generations. If
41
+ * omitted, the client mints a wire id after mount.
46
42
  */
47
43
  threadId?: string;
48
44
  /**
@@ -144,6 +140,6 @@ export interface CreateGenerationReturn<TOutput, TInput extends Record<string, a
144
140
  * </div>
145
141
  * ```
146
142
  */
147
- export declare function createGeneration<TInput extends Record<string, any>, TResult, TTransformed = void>(options: Omit<CreateGenerationOptions<TInput, TResult>, 'onResult' | 'persistence' | 'threadId' | 'id'> & {
143
+ export declare function createGeneration<TInput extends Record<string, any>, TResult, TTransformed = void>(options: Omit<CreateGenerationOptions<TInput, TResult>, 'onResult' | 'persistence' | 'threadId'> & {
148
144
  onResult?: (result: TResult) => TTransformed;
149
145
  } & GenerationPersistenceOptions): CreateGenerationReturn<InferGenerationOutputFromReturn<TResult, TTransformed>, TInput>;
@@ -38,7 +38,6 @@ import { createGenerationDevtoolsBridge } from '@tanstack/ai-client/devtools';
38
38
  // default, leaving the parameter `any` — a hard error under `strict`. See
39
39
  // issue #848.
40
40
  export function createGeneration(options) {
41
- const fallbackId = `gen-${Date.now()}-${Math.random().toString(36).substring(7)}`;
42
41
  // Create reactive state using Svelte 5 runes
43
42
  let result = $state(null);
44
43
  let isLoading = $state(false);
@@ -51,15 +50,8 @@ export function createGeneration(options) {
51
50
  // `exactOptionalPropertyTypes`. Assigning `undefined` directly would be
52
51
  // rejected — the optional caller `options.body` may be undefined, in which
53
52
  // case we want the key to be absent.
54
- // Identity: pass `threadId` alone when set (never also pass deprecated `id`).
55
53
  const clientOptions = {
56
54
  body: options.body,
57
- ...(options.threadId !== undefined
58
- ? { threadId: options.threadId }
59
- : { id: options.id ?? fallbackId }),
60
- ...(options.persistence !== undefined && {
61
- persistence: options.persistence,
62
- }),
63
55
  ...(options.hydrateGeneration !== undefined && {
64
56
  hydrateGeneration: options.hydrateGeneration,
65
57
  }),
@@ -115,16 +107,28 @@ export function createGeneration(options) {
115
107
  runId = rs?.runId ?? null;
116
108
  },
117
109
  };
110
+ const persistenceProps = typeof options.threadId === 'string' && options.persistence
111
+ ? {
112
+ persistence: options.persistence,
113
+ threadId: options.threadId,
114
+ }
115
+ : {
116
+ ...(options.threadId !== undefined && {
117
+ threadId: options.threadId,
118
+ }),
119
+ };
118
120
  let client;
119
121
  if (options.connection) {
120
122
  client = new GenerationClient({
121
123
  ...clientOptions,
124
+ ...persistenceProps,
122
125
  connection: options.connection,
123
126
  });
124
127
  }
125
128
  else if (options.fetcher) {
126
129
  client = new GenerationClient({
127
130
  ...clientOptions,
131
+ ...persistenceProps,
128
132
  fetcher: options.fetcher,
129
133
  });
130
134
  }
@@ -11,10 +11,6 @@ export interface CreateSummarizeOptions<TOutput = SummarizationResult> extends P
11
11
  connection?: ConnectConnectionAdapter;
12
12
  /** Direct async function for summarization */
13
13
  fetcher?: GenerationFetcher<SummarizeGenerateInput, SummarizationResult>;
14
- /**
15
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
16
- */
17
- id?: string;
18
14
  /** Additional body parameters to send with connect-based adapter requests */
19
15
  body?: Record<string, any>;
20
16
  /** Display options for TanStack AI Devtools. */
@@ -81,6 +77,6 @@ export interface CreateSummarizeReturn<TOutput = SummarizationResult> extends Om
81
77
  * </div>
82
78
  * ```
83
79
  */
84
- export declare function createSummarize<TTransformed = void>(options: Omit<CreateSummarizeOptions, 'onResult' | 'persistence' | 'threadId' | 'id'> & {
80
+ export declare function createSummarize<TTransformed = void>(options: Omit<CreateSummarizeOptions, 'onResult' | 'persistence' | 'threadId'> & {
85
81
  onResult?: (result: SummarizationResult) => TTransformed;
86
82
  } & GenerationPersistenceOptions): CreateSummarizeReturn<InferGenerationOutputFromReturn<SummarizationResult, TTransformed>>;
@@ -11,10 +11,6 @@ export interface CreateTranscriptionOptions<TOutput = TranscriptionResult> exten
11
11
  connection?: ConnectConnectionAdapter;
12
12
  /** Direct async function for transcription */
13
13
  fetcher?: GenerationFetcher<TranscriptionGenerateInput, TranscriptionResult>;
14
- /**
15
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
16
- */
17
- id?: string;
18
14
  /** Additional body parameters to send with connect-based adapter requests */
19
15
  body?: Record<string, any>;
20
16
  /** Display options for TanStack AI Devtools. */
@@ -86,6 +82,6 @@ export interface CreateTranscriptionReturn<TOutput = TranscriptionResult> extend
86
82
  * </div>
87
83
  * ```
88
84
  */
89
- export declare function createTranscription<TTransformed = void>(options: Omit<CreateTranscriptionOptions, 'onResult' | 'persistence' | 'threadId' | 'id'> & {
85
+ export declare function createTranscription<TTransformed = void>(options: Omit<CreateTranscriptionOptions, 'onResult' | 'persistence' | 'threadId'> & {
90
86
  onResult?: (result: TranscriptionResult) => TTransformed;
91
87
  } & GenerationPersistenceOptions): CreateTranscriptionReturn<InferGenerationOutputFromReturn<TranscriptionResult, TTransformed>>;
package/dist/index.d.ts CHANGED
@@ -16,4 +16,4 @@ export { createGenerateVideo } from './create-generate-video.svelte';
16
16
  export type { CreateGenerateVideoOptions, CreateGenerateVideoReturn, } from './create-generate-video.svelte';
17
17
  export { createAudioRecorder } from './create-audio-recorder.svelte';
18
18
  export type { CreateAudioRecorderOptions, CreateAudioRecorderReturn, } from './create-audio-recorder.svelte';
19
- export { fetchServerSentEvents, localStoragePersistence, sessionStoragePersistence, indexedDBPersistence, StorageUnavailableError, type ChatClientPersistence, type ChatPersistedState, type ChatPersistenceOption, type ChatStorageAdapter, type WebStoragePersistenceOptions, type IndexedDBPersistenceOptions, fetchHttpStream, xhrServerSentEvents, xhrHttpStream, stream, rpcStream, createChatClientOptions, clientTools, type ConnectionAdapter, type ConnectConnectionAdapter, type SubscribeConnectionAdapter, type RunAgentInputContext, type FetchConnectionOptions, type XhrConnectionOptions, type InferChatMessages, type GenerationClientState, type ImageGenerateInput, type AudioGenerateInput, type SpeechGenerateInput, type TranscriptionGenerateInput, type SummarizeGenerateInput, type VideoGenerateInput, type VideoGenerateResult, type VideoStatusInfo, } from '@tanstack/ai-client';
19
+ export { fetchServerSentEvents, localStoragePersistence, sessionStoragePersistence, indexedDBPersistence, StorageUnavailableError, type ChatClientPersistence, type ChatPersistedState, type ChatPersistenceOption, type ChatStorageAdapter, type WebStoragePersistenceOptions, type IndexedDBPersistenceOptions, fetchHttpStream, xhrServerSentEvents, xhrHttpStream, stream, rpcStream, webSocket, createChatClientOptions, clientTools, type ConnectionAdapter, type ConnectConnectionAdapter, type SubscribeConnectionAdapter, type RunAgentInputContext, type FetchConnectionOptions, type XhrConnectionOptions, type WebSocketConnectionOptions, type InferChatMessages, type GenerationClientState, type ImageGenerateInput, type AudioGenerateInput, type SpeechGenerateInput, type TranscriptionGenerateInput, type SummarizeGenerateInput, type VideoGenerateInput, type VideoGenerateResult, type VideoStatusInfo, } from '@tanstack/ai-client';
package/dist/index.js CHANGED
@@ -9,4 +9,4 @@ export { createSummarize } from './create-summarize.svelte';
9
9
  export { createGenerateVideo } from './create-generate-video.svelte';
10
10
  export { createAudioRecorder } from './create-audio-recorder.svelte';
11
11
  // Re-export from ai-client for convenience
12
- export { fetchServerSentEvents, localStoragePersistence, sessionStoragePersistence, indexedDBPersistence, StorageUnavailableError, fetchHttpStream, xhrServerSentEvents, xhrHttpStream, stream, rpcStream, createChatClientOptions, clientTools, } from '@tanstack/ai-client';
12
+ export { fetchServerSentEvents, localStoragePersistence, sessionStoragePersistence, indexedDBPersistence, StorageUnavailableError, fetchHttpStream, xhrServerSentEvents, xhrHttpStream, stream, rpcStream, webSocket, createChatClientOptions, clientTools, } from '@tanstack/ai-client';
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { AnyClientTool, InferSchemaType, ModelMessage, RunAgentResumeItem, SchemaInput } from '@tanstack/ai';
2
- import type { AIDevtoolsDisplayOptions, BoundInterrupts, ChatClientOptions, ChatClientState, ChatInterrupt, ChatInterruptState, ChatRequestBody, ChatResumeState, ClientContextOptionFromTools, ConnectionStatus, DistributedOmit, InferredClientContext, MultimodalContent, QueueConfig, QueueOption, QueueStrategy, QueuedMessage, SendMessageOptions, UIMessage, WhenBusy } from '@tanstack/ai-client';
1
+ import type { AnyClientTool, InterruptDefinition, InferSchemaType, ModelMessage, RunAgentResumeItem, SchemaInput } from '@tanstack/ai';
2
+ import type { AIDevtoolsDisplayOptions, BoundInterrupts, ChatClientOptions, ChatClientState, ResolvableChatInterrupt, ChatInterruptState, ChatRequestBody, ChatResumeState, ClientContextOptionFromTools, ConnectionStatus, DistributedOmit, InferredClientContext, MultimodalContent, QueueConfig, QueueOption, QueueStrategy, QueuedMessage, SendMessageOptions, UIMessage, WhenBusy } from '@tanstack/ai-client';
3
3
  export type { ChatRequestBody, MultimodalContent, QueueConfig, QueuedMessage, QueueOption, QueueStrategy, SendMessageOptions, UIMessage, WhenBusy, };
4
4
  /**
5
5
  * Recursive partial — every property and every nested array element is
@@ -30,7 +30,7 @@ export type DeepPartial<T> = T extends ReadonlyArray<infer U> ? Array<DeepPartia
30
30
  * Note: Connection and body changes will recreate the ChatClient instance.
31
31
  * To update these options, remount the component or use a key prop.
32
32
  */
33
- export type CreateChatOptions<TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>> = DistributedOmit<ChatClientOptions<TTools, TContext>, 'onMessagesChange' | 'onLoadingChange' | 'onErrorChange' | 'onStatusChange' | 'onSubscriptionChange' | 'onConnectionStatusChange' | 'onSessionGeneratingChange' | 'onQueueChange' | 'onResumeStateChange' | 'onRunIdChange' | 'context' | 'devtools' | 'id'> & {
33
+ export type CreateChatOptions<TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> = DistributedOmit<ChatClientOptions<TTools, TContext, TInterrupts>, 'onMessagesChange' | 'onLoadingChange' | 'onErrorChange' | 'onStatusChange' | 'onSubscriptionChange' | 'onConnectionStatusChange' | 'onSessionGeneratingChange' | 'onQueueChange' | 'onResumeStateChange' | 'onRunIdChange' | 'context' | 'devtools'> & {
34
34
  live?: boolean;
35
35
  /** Display options for TanStack AI Devtools. */
36
36
  devtools?: AIDevtoolsDisplayOptions;
@@ -45,7 +45,7 @@ export type CreateChatOptions<TTools extends ReadonlyArray<AnyClientTool> = any,
45
45
  * typed `partial` / `final` reactive getters; otherwise the return is
46
46
  * unchanged.
47
47
  */
48
- export type CreateChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = unknown> = BaseCreateChatReturn<TTools, TSchema extends SchemaInput ? InferSchemaType<TSchema> : unknown, TContext> & (TSchema extends SchemaInput ? {
48
+ export type CreateChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = unknown, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> = BaseCreateChatReturn<TTools, TSchema extends SchemaInput ? InferSchemaType<TSchema> : unknown, TContext, TInterrupts> & (TSchema extends SchemaInput ? {
49
49
  /**
50
50
  * Live progressively-parsed structured output (reactive getter).
51
51
  * Derived from the latest assistant message's structured-output part.
@@ -58,7 +58,7 @@ export type CreateChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any,
58
58
  */
59
59
  readonly final: InferSchemaType<TSchema> | null;
60
60
  } : Record<never, never>);
61
- interface BaseCreateChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any, TData = unknown, TContext = unknown> {
61
+ interface BaseCreateChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any, TData = unknown, TContext = unknown, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> {
62
62
  /**
63
63
  * Current messages in the conversation (reactive getter). When
64
64
  * `outputSchema` is supplied, `messages[i].parts.find(p => p.type ===
@@ -112,14 +112,14 @@ interface BaseCreateChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any
112
112
  * it, correlate a log line).
113
113
  */
114
114
  readonly runId: string | null;
115
- readonly interrupts: BoundInterrupts<TTools>;
115
+ readonly interrupts: BoundInterrupts<TTools, TInterrupts>;
116
116
  /** @deprecated Use `interrupts`. */
117
- readonly pendingInterrupts: BoundInterrupts<TTools>;
118
- readonly interruptErrors: ChatInterruptState<TTools>['interruptErrors'];
117
+ readonly pendingInterrupts: BoundInterrupts<TTools, TInterrupts>;
118
+ readonly interruptErrors: ChatInterruptState<TTools, TInterrupts>['interruptErrors'];
119
119
  readonly resuming: boolean;
120
120
  resolveInterrupts: {
121
121
  (approved: boolean): void;
122
- (resolver: (interrupt: ChatInterrupt<TTools>) => undefined): void;
122
+ (resolver: (interrupt: ResolvableChatInterrupt<TTools, TInterrupts>) => undefined): void;
123
123
  };
124
124
  cancelInterrupts: () => void;
125
125
  retryInterrupts: () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai-svelte",
3
- "version": "0.16.3",
3
+ "version": "0.18.1",
4
4
  "description": "Svelte 5 bindings for TanStack AI streaming chat, structured outputs, and media generation.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -46,24 +46,24 @@
46
46
  "media-generation"
47
47
  ],
48
48
  "dependencies": {
49
- "@tanstack/ai-client": "^0.23.3"
49
+ "@tanstack/ai-client": "^0.25.1"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "svelte": "^5.0.0",
53
- "@tanstack/ai": "^0.45.0"
53
+ "@tanstack/ai": "^0.47.1"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@standard-schema/spec": "^1.1.0",
57
57
  "@sveltejs/package": "^2.3.10",
58
- "@sveltejs/vite-plugin-svelte": "^5.1.1",
58
+ "@sveltejs/vite-plugin-svelte": "^7.3.0",
59
59
  "@types/node": "^24.10.1",
60
60
  "@vitest/coverage-v8": "4.1.10",
61
61
  "jsdom": "^27.4.0",
62
- "svelte": "^5.20.0",
62
+ "svelte": "^5.56.9",
63
63
  "svelte-check": "^4.2.0",
64
64
  "typescript": "5.9.3",
65
65
  "vite": "^8.2.1",
66
- "@tanstack/ai": "0.45.0"
66
+ "@tanstack/ai": "0.47.1"
67
67
  },
68
68
  "scripts": {
69
69
  "clean": "rm -rf ./dist",
@@ -3,7 +3,7 @@ import { createChatDevtoolsBridge } from '@tanstack/ai-client/devtools'
3
3
  import { onMount } from 'svelte'
4
4
  import type {
5
5
  ChatClientState,
6
- ChatInterrupt,
6
+ ResolvableChatInterrupt,
7
7
  ChatInterruptState,
8
8
  ChatResumeState,
9
9
  ConnectionStatus,
@@ -14,6 +14,7 @@ import type {
14
14
  } from '@tanstack/ai-client'
15
15
  import type {
16
16
  AnyClientTool,
17
+ InterruptDefinition,
17
18
  InferSchemaType,
18
19
  ModelMessage,
19
20
  RunAgentResumeItem,
@@ -65,9 +66,12 @@ export function createChat<
65
66
  const TTools extends ReadonlyArray<AnyClientTool> = any,
66
67
  TSchema extends SchemaInput | undefined = undefined,
67
68
  TContext = InferredClientContext<TTools>,
69
+ const TInterrupts extends ReadonlyArray<
70
+ InterruptDefinition<any, any, any, any>
71
+ > = readonly [],
68
72
  >(
69
- options: CreateChatOptions<TTools, TSchema, TContext>,
70
- ): CreateChatReturn<TTools, TSchema, TContext> {
73
+ options: CreateChatOptions<TTools, TSchema, TContext, TInterrupts>,
74
+ ): CreateChatReturn<TTools, TSchema, TContext, TInterrupts> {
71
75
  // Create reactive state using Svelte 5 runes
72
76
  let messages = $state<Array<UIMessage<TTools>>>(options.initialMessages || [])
73
77
  let isLoading = $state(false)
@@ -78,7 +82,7 @@ export function createChat<
78
82
  let sessionGenerating = $state(false)
79
83
  let queue = $state<Array<QueuedMessage>>([])
80
84
  let runId = $state<string | null>(null)
81
- let interruptState = $state.raw<ChatInterruptState<TTools>>({
85
+ let interruptState = $state.raw<ChatInterruptState<TTools, TInterrupts>>({
82
86
  interrupts: EMPTY_INTERRUPTS,
83
87
  pendingInterrupts: EMPTY_INTERRUPTS,
84
88
  interruptErrors: EMPTY_INTERRUPT_ERRORS,
@@ -106,23 +110,27 @@ export function createChat<
106
110
  ? { connection: options.connection }
107
111
  : { fetcher: options.fetcher }
108
112
 
109
- // The hook's identity is its `threadId`, which ChatClient also uses as the
110
- // persistence key — no separate `id`. When no `threadId` is given the client
111
- // generates one, so an ephemeral chat still works but is not restored on reload.
112
- const client = new ChatClient<TTools, TContext>({
113
+ // The hook's identity is its `threadId`. When no `threadId` is given the
114
+ // client mints one after mount, so an ephemeral chat still works but is not
115
+ // restored on reload.
116
+ const client = new ChatClient<TTools, TContext, TInterrupts>({
113
117
  devtoolsBridgeFactory: createChatDevtoolsBridge,
114
118
  ...transport,
115
119
  ...(options.initialMessages !== undefined && {
116
120
  initialMessages: options.initialMessages,
117
121
  }),
118
- ...(options.persistence !== undefined && {
119
- persistence: options.persistence,
120
- }),
122
+ ...(typeof options.threadId === 'string' && options.persistence
123
+ ? {
124
+ persistence: options.persistence,
125
+ threadId: options.threadId,
126
+ }
127
+ : {
128
+ ...(options.threadId !== undefined && { threadId: options.threadId }),
129
+ }),
121
130
  ...(options.initialResumeSnapshot !== undefined && {
122
131
  initialResumeSnapshot: options.initialResumeSnapshot,
123
132
  }),
124
133
  ...(options.body !== undefined && { body: options.body }),
125
- ...(options.threadId !== undefined && { threadId: options.threadId }),
126
134
  ...(options.forwardedProps !== undefined && {
127
135
  forwardedProps: options.forwardedProps,
128
136
  }),
@@ -144,6 +152,9 @@ export function createChat<
144
152
  options.onError?.(err)
145
153
  },
146
154
  tools: options.tools,
155
+ ...(options.interrupts !== undefined && {
156
+ interrupts: options.interrupts,
157
+ }),
147
158
  ...(options.onCustomEvent !== undefined && {
148
159
  onCustomEvent: options.onCustomEvent,
149
160
  }),
@@ -179,9 +190,9 @@ export function createChat<
179
190
  onRunIdChange: (nextRunId) => {
180
191
  runId = nextRunId
181
192
  },
182
- onInterruptStateChange: (nextInterruptState) => {
193
+ onInterruptStateChange: (nextInterruptState, context) => {
183
194
  interruptState = nextInterruptState
184
- options.onInterruptStateChange?.(nextInterruptState)
195
+ options.onInterruptStateChange?.(nextInterruptState, context)
185
196
  },
186
197
  })
187
198
 
@@ -304,7 +315,11 @@ export function createChat<
304
315
  }
305
316
 
306
317
  const resolveInterrupts = (
307
- resolution: boolean | ((interrupt: ChatInterrupt<TTools>) => undefined),
318
+ resolution:
319
+ | boolean
320
+ | ((
321
+ interrupt: ResolvableChatInterrupt<TTools, TInterrupts>,
322
+ ) => undefined),
308
323
  ) => {
309
324
  if (typeof resolution === 'boolean') {
310
325
  client.resolveInterrupts(resolution)
@@ -447,5 +462,5 @@ export function createChat<
447
462
  updateBody,
448
463
  updateForwardedProps,
449
464
  updateContext,
450
- } as unknown as CreateChatReturn<TTools, TSchema, TContext>
465
+ } as unknown as CreateChatReturn<TTools, TSchema, TContext, TInterrupts>
451
466
  }
@@ -30,10 +30,6 @@ export interface CreateGenerateAudioOptions<
30
30
  connection?: ConnectConnectionAdapter
31
31
  /** Direct async function for audio generation */
32
32
  fetcher?: GenerationFetcher<AudioGenerateInput, AudioGenerationResult>
33
- /**
34
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
35
- */
36
- id?: string
37
33
  /** Additional body parameters to send with connect-based adapter requests */
38
34
  body?: Record<string, any>
39
35
  /** Display options for TanStack AI Devtools. */
@@ -103,7 +99,7 @@ export interface CreateGenerateAudioReturn<
103
99
  export function createGenerateAudio<TTransformed = void>(
104
100
  options: Omit<
105
101
  CreateGenerateAudioOptions,
106
- 'onResult' | 'persistence' | 'threadId' | 'id'
102
+ 'onResult' | 'persistence' | 'threadId'
107
103
  > & {
108
104
  onResult?: (result: AudioGenerationResult) => TTransformed
109
105
  } & GenerationPersistenceOptions,
@@ -30,10 +30,6 @@ export interface CreateGenerateImageOptions<
30
30
  connection?: ConnectConnectionAdapter
31
31
  /** Direct async function for image generation */
32
32
  fetcher?: GenerationFetcher<ImageGenerateInput, ImageGenerationResult>
33
- /**
34
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
35
- */
36
- id?: string
37
33
  /** Additional body parameters to send with connect-based adapter requests */
38
34
  body?: Record<string, any>
39
35
  /** Display options for TanStack AI Devtools. */
@@ -112,7 +108,7 @@ export interface CreateGenerateImageReturn<
112
108
  export function createGenerateImage<TTransformed = void>(
113
109
  options: Omit<
114
110
  CreateGenerateImageOptions,
115
- 'onResult' | 'persistence' | 'threadId' | 'id'
111
+ 'onResult' | 'persistence' | 'threadId'
116
112
  > & {
117
113
  onResult?: (result: ImageGenerationResult) => TTransformed
118
114
  } & GenerationPersistenceOptions,
@@ -28,10 +28,6 @@ export interface CreateGenerateSpeechOptions<TOutput = TTSResult> extends Pick<
28
28
  connection?: ConnectConnectionAdapter
29
29
  /** Direct async function for speech generation */
30
30
  fetcher?: GenerationFetcher<SpeechGenerateInput, TTSResult>
31
- /**
32
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
33
- */
34
- id?: string
35
31
  /** Additional body parameters to send with connect-based adapter requests */
36
32
  body?: Record<string, any>
37
33
  /** Display options for TanStack AI Devtools. */
@@ -102,7 +98,7 @@ export interface CreateGenerateSpeechReturn<TOutput = TTSResult> extends Omit<
102
98
  export function createGenerateSpeech<TTransformed = void>(
103
99
  options: Omit<
104
100
  CreateGenerateSpeechOptions,
105
- 'onResult' | 'persistence' | 'threadId' | 'id'
101
+ 'onResult' | 'persistence' | 'threadId'
106
102
  > & {
107
103
  onResult?: (result: TTSResult) => TTransformed
108
104
  } & GenerationPersistenceOptions,
@@ -23,10 +23,6 @@ export interface CreateGenerateVideoOptions<TOutput = VideoGenerateResult> {
23
23
  connection?: ConnectConnectionAdapter
24
24
  /** Direct async function that returns a completed video result */
25
25
  fetcher?: GenerationFetcher<VideoGenerateInput, VideoGenerateResult>
26
- /**
27
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
28
- */
29
- id?: string
30
26
  /** Additional body parameters to send with connect-based adapter requests */
31
27
  body?: Record<string, any>
32
28
  /** Display options for TanStack AI Devtools. */
@@ -50,8 +46,8 @@ export interface CreateGenerateVideoOptions<TOutput = VideoGenerateResult> {
50
46
  * id on the wire, which the protocol requires.
51
47
  *
52
48
  * **Required whenever `persistence` is set** — an app that cannot name the
53
- * scope has nothing to restore to. Optional for ephemeral generations, where
54
- * it falls back to `id` purely to satisfy the wire.
49
+ * scope has nothing to restore to. Optional for ephemeral generations. If
50
+ * omitted, the client mints a wire id after mount.
55
51
  */
56
52
  threadId?: string
57
53
  /**
@@ -161,7 +157,7 @@ export interface CreateGenerateVideoReturn<TOutput = VideoGenerateResult> {
161
157
  export function createGenerateVideo<TTransformed = void>(
162
158
  options: Omit<
163
159
  CreateGenerateVideoOptions,
164
- 'onResult' | 'persistence' | 'threadId' | 'id'
160
+ 'onResult' | 'persistence' | 'threadId'
165
161
  > & {
166
162
  onResult?: (result: VideoGenerateResult) => TTransformed
167
163
  } & GenerationPersistenceOptions,
@@ -172,7 +168,6 @@ export function createGenerateVideo<TTransformed = void>(
172
168
  VideoGenerateResult,
173
169
  TTransformed
174
170
  >
175
- const fallbackId = `video-${Date.now()}-${Math.random().toString(36).substring(7)}`
176
171
 
177
172
  // Create reactive state using Svelte 5 runes
178
173
  let result = $state<TOutput | null>(null)
@@ -188,15 +183,18 @@ export function createGenerateVideo<TTransformed = void>(
188
183
  // is declared `body?: Record<string, any>` (absent vs. present) under
189
184
  // `exactOptionalPropertyTypes`. The optional caller `options.body` may be
190
185
  // undefined, in which case we want the key to be absent on the target.
191
- // Identity: pass `threadId` alone when set (never also pass deprecated `id`).
192
186
  const baseOptions = {
193
187
  body: options.body,
194
- ...(options.threadId !== undefined
195
- ? { threadId: options.threadId }
196
- : { id: options.id ?? fallbackId }),
197
- ...(options.persistence !== undefined && {
198
- persistence: options.persistence,
199
- }),
188
+ ...(typeof options.threadId === 'string' && options.persistence
189
+ ? {
190
+ persistence: options.persistence,
191
+ threadId: options.threadId,
192
+ }
193
+ : {
194
+ ...(options.threadId !== undefined && {
195
+ threadId: options.threadId,
196
+ }),
197
+ }),
200
198
  ...(options.hydrateGeneration !== undefined && {
201
199
  hydrateGeneration: options.hydrateGeneration,
202
200
  }),
@@ -26,10 +26,6 @@ export interface CreateGenerationOptions<TInput, TResult, TOutput = TResult> {
26
26
  connection?: ConnectConnectionAdapter
27
27
  /** Direct async function for one-shot generation (no streaming protocol needed) */
28
28
  fetcher?: GenerationFetcher<TInput, TResult>
29
- /**
30
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
31
- */
32
- id?: string
33
29
  /** Additional body parameters to send with connect-based adapter requests */
34
30
  body?: Record<string, any>
35
31
  /** Display options for TanStack AI Devtools. */
@@ -53,8 +49,8 @@ export interface CreateGenerationOptions<TInput, TResult, TOutput = TResult> {
53
49
  * id on the wire, which the protocol requires.
54
50
  *
55
51
  * **Required whenever `persistence` is set** — an app that cannot name the
56
- * scope has nothing to restore to. Optional for ephemeral generations, where
57
- * it falls back to `id` purely to satisfy the wire.
52
+ * scope has nothing to restore to. Optional for ephemeral generations. If
53
+ * omitted, the client mints a wire id after mount.
58
54
  */
59
55
  threadId?: string
60
56
  /**
@@ -174,7 +170,7 @@ export function createGeneration<
174
170
  >(
175
171
  options: Omit<
176
172
  CreateGenerationOptions<TInput, TResult>,
177
- 'onResult' | 'persistence' | 'threadId' | 'id'
173
+ 'onResult' | 'persistence' | 'threadId'
178
174
  > & {
179
175
  onResult?: (result: TResult) => TTransformed
180
176
  } & GenerationPersistenceOptions,
@@ -183,8 +179,6 @@ export function createGeneration<
183
179
  TInput
184
180
  > {
185
181
  type TOutput = InferGenerationOutputFromReturn<TResult, TTransformed>
186
- const fallbackId = `gen-${Date.now()}-${Math.random().toString(36).substring(7)}`
187
-
188
182
  // Create reactive state using Svelte 5 runes
189
183
  let result = $state<TOutput | null>(null)
190
184
  let isLoading = $state(false)
@@ -198,15 +192,11 @@ export function createGeneration<
198
192
  // `exactOptionalPropertyTypes`. Assigning `undefined` directly would be
199
193
  // rejected — the optional caller `options.body` may be undefined, in which
200
194
  // case we want the key to be absent.
201
- // Identity: pass `threadId` alone when set (never also pass deprecated `id`).
202
- const clientOptions: GenerationClientOptions<TInput, TResult, TOutput> = {
195
+ const clientOptions: Omit<
196
+ GenerationClientOptions<TInput, TResult, TOutput>,
197
+ 'persistence' | 'threadId'
198
+ > = {
203
199
  body: options.body,
204
- ...(options.threadId !== undefined
205
- ? { threadId: options.threadId }
206
- : { id: options.id ?? fallbackId }),
207
- ...(options.persistence !== undefined && {
208
- persistence: options.persistence,
209
- }),
210
200
  ...(options.hydrateGeneration !== undefined && {
211
201
  hydrateGeneration: options.hydrateGeneration,
212
202
  }),
@@ -257,16 +247,30 @@ export function createGeneration<
257
247
  },
258
248
  }
259
249
 
250
+ const persistenceProps =
251
+ typeof options.threadId === 'string' && options.persistence
252
+ ? {
253
+ persistence: options.persistence,
254
+ threadId: options.threadId,
255
+ }
256
+ : {
257
+ ...(options.threadId !== undefined && {
258
+ threadId: options.threadId,
259
+ }),
260
+ }
261
+
260
262
  let client: GenerationClient<TInput, TResult, TOutput>
261
263
 
262
264
  if (options.connection) {
263
265
  client = new GenerationClient<TInput, TResult, TOutput>({
264
266
  ...clientOptions,
267
+ ...persistenceProps,
265
268
  connection: options.connection,
266
269
  })
267
270
  } else if (options.fetcher) {
268
271
  client = new GenerationClient<TInput, TResult, TOutput>({
269
272
  ...clientOptions,
273
+ ...persistenceProps,
270
274
  fetcher: options.fetcher,
271
275
  })
272
276
  } else {
@@ -30,10 +30,6 @@ export interface CreateSummarizeOptions<
30
30
  connection?: ConnectConnectionAdapter
31
31
  /** Direct async function for summarization */
32
32
  fetcher?: GenerationFetcher<SummarizeGenerateInput, SummarizationResult>
33
- /**
34
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
35
- */
36
- id?: string
37
33
  /** Additional body parameters to send with connect-based adapter requests */
38
34
  body?: Record<string, any>
39
35
  /** Display options for TanStack AI Devtools. */
@@ -107,7 +103,7 @@ export interface CreateSummarizeReturn<
107
103
  export function createSummarize<TTransformed = void>(
108
104
  options: Omit<
109
105
  CreateSummarizeOptions,
110
- 'onResult' | 'persistence' | 'threadId' | 'id'
106
+ 'onResult' | 'persistence' | 'threadId'
111
107
  > & {
112
108
  onResult?: (result: SummarizationResult) => TTransformed
113
109
  } & GenerationPersistenceOptions,
@@ -34,10 +34,6 @@ export interface CreateTranscriptionOptions<
34
34
  connection?: ConnectConnectionAdapter
35
35
  /** Direct async function for transcription */
36
36
  fetcher?: GenerationFetcher<TranscriptionGenerateInput, TranscriptionResult>
37
- /**
38
- * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
39
- */
40
- id?: string
41
37
  /** Additional body parameters to send with connect-based adapter requests */
42
38
  body?: Record<string, any>
43
39
  /** Display options for TanStack AI Devtools. */
@@ -116,7 +112,7 @@ export interface CreateTranscriptionReturn<
116
112
  export function createTranscription<TTransformed = void>(
117
113
  options: Omit<
118
114
  CreateTranscriptionOptions,
119
- 'onResult' | 'persistence' | 'threadId' | 'id'
115
+ 'onResult' | 'persistence' | 'threadId'
120
116
  > & {
121
117
  onResult?: (result: TranscriptionResult) => TTransformed
122
118
  } & GenerationPersistenceOptions,
package/src/index.ts CHANGED
@@ -80,6 +80,7 @@ export {
80
80
  xhrHttpStream,
81
81
  stream,
82
82
  rpcStream,
83
+ webSocket,
83
84
  createChatClientOptions,
84
85
  clientTools,
85
86
  type ConnectionAdapter,
@@ -88,6 +89,7 @@ export {
88
89
  type RunAgentInputContext,
89
90
  type FetchConnectionOptions,
90
91
  type XhrConnectionOptions,
92
+ type WebSocketConnectionOptions,
91
93
  type InferChatMessages,
92
94
  type GenerationClientState,
93
95
  type ImageGenerateInput,
package/src/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type {
2
2
  AnyClientTool,
3
+ InterruptDefinition,
3
4
  InferSchemaType,
4
5
  ModelMessage,
5
6
  RunAgentResumeItem,
@@ -10,7 +11,7 @@ import type {
10
11
  BoundInterrupts,
11
12
  ChatClientOptions,
12
13
  ChatClientState,
13
- ChatInterrupt,
14
+ ResolvableChatInterrupt,
14
15
  ChatInterruptState,
15
16
  ChatRequestBody,
16
17
  ChatResumeState,
@@ -78,8 +79,10 @@ export type CreateChatOptions<
78
79
  TTools extends ReadonlyArray<AnyClientTool> = any,
79
80
  TSchema extends SchemaInput | undefined = undefined,
80
81
  TContext = InferredClientContext<TTools>,
82
+ TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> =
83
+ readonly [],
81
84
  > = DistributedOmit<
82
- ChatClientOptions<TTools, TContext>,
85
+ ChatClientOptions<TTools, TContext, TInterrupts>,
83
86
  | 'onMessagesChange'
84
87
  | 'onLoadingChange'
85
88
  | 'onErrorChange'
@@ -92,10 +95,6 @@ export type CreateChatOptions<
92
95
  | 'onRunIdChange'
93
96
  | 'context'
94
97
  | 'devtools'
95
- // `id` is not a hook option: the hook's identity is its `threadId`, which is
96
- // also the persistence key. Persist across reloads by passing a stable
97
- // `threadId`; there is no separate id to set.
98
- | 'id'
99
98
  > & {
100
99
  live?: boolean
101
100
  /** Display options for TanStack AI Devtools. */
@@ -116,10 +115,13 @@ export type CreateChatReturn<
116
115
  TTools extends ReadonlyArray<AnyClientTool> = any,
117
116
  TSchema extends SchemaInput | undefined = undefined,
118
117
  TContext = unknown,
118
+ TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> =
119
+ readonly [],
119
120
  > = BaseCreateChatReturn<
120
121
  TTools,
121
122
  TSchema extends SchemaInput ? InferSchemaType<TSchema> : unknown,
122
- TContext
123
+ TContext,
124
+ TInterrupts
123
125
  > &
124
126
  (TSchema extends SchemaInput
125
127
  ? {
@@ -141,6 +143,8 @@ interface BaseCreateChatReturn<
141
143
  TTools extends ReadonlyArray<AnyClientTool> = any,
142
144
  TData = unknown,
143
145
  TContext = unknown,
146
+ TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> =
147
+ readonly [],
144
148
  > {
145
149
  /**
146
150
  * Current messages in the conversation (reactive getter). When
@@ -205,14 +209,21 @@ interface BaseCreateChatReturn<
205
209
  * it, correlate a log line).
206
210
  */
207
211
  readonly runId: string | null
208
- readonly interrupts: BoundInterrupts<TTools>
212
+ readonly interrupts: BoundInterrupts<TTools, TInterrupts>
209
213
  /** @deprecated Use `interrupts`. */
210
- readonly pendingInterrupts: BoundInterrupts<TTools>
211
- readonly interruptErrors: ChatInterruptState<TTools>['interruptErrors']
214
+ readonly pendingInterrupts: BoundInterrupts<TTools, TInterrupts>
215
+ readonly interruptErrors: ChatInterruptState<
216
+ TTools,
217
+ TInterrupts
218
+ >['interruptErrors']
212
219
  readonly resuming: boolean
213
220
  resolveInterrupts: {
214
221
  (approved: boolean): void
215
- (resolver: (interrupt: ChatInterrupt<TTools>) => undefined): void
222
+ (
223
+ resolver: (
224
+ interrupt: ResolvableChatInterrupt<TTools, TInterrupts>,
225
+ ) => undefined,
226
+ ): void
216
227
  }
217
228
  cancelInterrupts: () => void
218
229
  retryInterrupts: () => void