@tanstack/ai-svelte 0.15.1 → 0.16.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,7 +1,11 @@
1
1
  import { ChatClient } from '@tanstack/ai-client'
2
2
  import { createChatDevtoolsBridge } from '@tanstack/ai-client/devtools'
3
+ import { onMount } from 'svelte'
3
4
  import type {
4
5
  ChatClientState,
6
+ ChatInterrupt,
7
+ ChatInterruptState,
8
+ ChatResumeState,
5
9
  ConnectionStatus,
6
10
  InferredClientContext,
7
11
  QueuedMessage,
@@ -12,6 +16,7 @@ import type {
12
16
  AnyClientTool,
13
17
  InferSchemaType,
14
18
  ModelMessage,
19
+ RunAgentResumeItem,
15
20
  SchemaInput,
16
21
  StreamChunk,
17
22
  } from '@tanstack/ai'
@@ -23,6 +28,9 @@ import type {
23
28
  UIMessage,
24
29
  } from './types'
25
30
 
31
+ const EMPTY_INTERRUPTS = Object.freeze([])
32
+ const EMPTY_INTERRUPT_ERRORS = Object.freeze([])
33
+
26
34
  /**
27
35
  * Creates a reactive chat instance for Svelte 5.
28
36
  *
@@ -60,11 +68,6 @@ export function createChat<
60
68
  >(
61
69
  options: CreateChatOptions<TTools, TSchema, TContext>,
62
70
  ): CreateChatReturn<TTools, TSchema, TContext> {
63
- // Generate a unique ID for this chat instance
64
- const clientId =
65
- options.id ||
66
- `chat-${Date.now()}-${Math.random().toString(36).substring(7)}`
67
-
68
71
  // Create reactive state using Svelte 5 runes
69
72
  let messages = $state<Array<UIMessage<TTools>>>(options.initialMessages || [])
70
73
  let isLoading = $state(false)
@@ -74,6 +77,13 @@ export function createChat<
74
77
  let connectionStatus = $state<ConnectionStatus>('disconnected')
75
78
  let sessionGenerating = $state(false)
76
79
  let queue = $state<Array<QueuedMessage>>([])
80
+ let runId = $state<string | null>(null)
81
+ let interruptState = $state.raw<ChatInterruptState<TTools>>({
82
+ interrupts: EMPTY_INTERRUPTS,
83
+ pendingInterrupts: EMPTY_INTERRUPTS,
84
+ interruptErrors: EMPTY_INTERRUPT_ERRORS,
85
+ resuming: false,
86
+ })
77
87
 
78
88
  // Structured-output `partial` / `final` are derived from `messages` —
79
89
  // specifically from the structured-output part on the latest assistant
@@ -96,16 +106,21 @@ export function createChat<
96
106
  ? { connection: options.connection }
97
107
  : { fetcher: options.fetcher }
98
108
 
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.
99
112
  const client = new ChatClient<TTools, TContext>({
100
113
  devtoolsBridgeFactory: createChatDevtoolsBridge,
101
114
  ...transport,
102
- id: clientId,
103
115
  ...(options.initialMessages !== undefined && {
104
116
  initialMessages: options.initialMessages,
105
117
  }),
106
118
  ...(options.persistence !== undefined && {
107
119
  persistence: options.persistence,
108
120
  }),
121
+ ...(options.initialResumeSnapshot !== undefined && {
122
+ initialResumeSnapshot: options.initialResumeSnapshot,
123
+ }),
109
124
  ...(options.body !== undefined && { body: options.body }),
110
125
  ...(options.threadId !== undefined && { threadId: options.threadId }),
111
126
  ...(options.forwardedProps !== undefined && {
@@ -140,6 +155,7 @@ export function createChat<
140
155
  },
141
156
  onLoadingChange: (newIsLoading: boolean) => {
142
157
  isLoading = newIsLoading
158
+ syncResumeState()
143
159
  },
144
160
  onStatusChange: (newStatus: ChatClientState) => {
145
161
  status = newStatus
@@ -160,9 +176,22 @@ export function createChat<
160
176
  onQueueChange: (nextQueue: Array<QueuedMessage>) => {
161
177
  queue = nextQueue
162
178
  },
179
+ onRunIdChange: (nextRunId) => {
180
+ runId = nextRunId
181
+ },
182
+ onInterruptStateChange: (nextInterruptState) => {
183
+ interruptState = nextInterruptState
184
+ options.onInterruptStateChange?.(nextInterruptState)
185
+ },
163
186
  })
164
187
 
188
+ function syncResumeState() {
189
+ runId = client.getCurrentRunId()
190
+ interruptState = client.getInterruptState()
191
+ }
192
+
165
193
  messages = client.getMessages()
194
+ interruptState = client.getInterruptState()
166
195
 
167
196
  if (options.live) {
168
197
  client.subscribe()
@@ -170,27 +199,64 @@ export function createChat<
170
199
 
171
200
  client.mountDevtools()
172
201
 
173
- // Note: Cleanup is handled by calling stop() directly when needed.
174
- // Unlike React/Vue/Solid, Svelte 5 runes like $effect can only be used
175
- // during component initialization, so we don't add automatic cleanup here.
176
- // Users should call chat.stop() in their component's cleanup if needed.
202
+ if (typeof window !== 'undefined') {
203
+ try {
204
+ onMount(() => {
205
+ // Delivery-durability resume is transparent: the resumable SSE
206
+ // connection adapter reattaches via the browser's native
207
+ // Last-Event-ID on reconnect. We only seed interrupt (state) resume.
208
+ syncResumeState()
209
+ client.attach()
210
+ // ONLY THE VIEW ON SCREEN HOLDS A STREAM. `onMount`'s returned function
211
+ // runs when the component is destroyed, which is the one automatic
212
+ // teardown Svelte gives us here — and it is enough, because a connection
213
+ // is all that must go. A page can own many chats and a browser allows
214
+ // only ~6 connections per origin, so one long-lived stream per chat
215
+ // starves every other request once a few views have been open.
216
+ //
217
+ // `detach` keeps the transcript and the resume pointer, so re-entering
218
+ // the view picks the run back up from the durable log.
219
+ return () => {
220
+ client.detach()
221
+ }
222
+ })
223
+ } catch {
224
+ // Svelte lifecycle hooks are only valid during component initialization.
225
+ }
226
+ }
227
+
228
+ // Note: `dispose()` remains manual — it releases devtools and marks the client
229
+ // dead, which only the owner can decide. The CONNECTION is released
230
+ // automatically by the `onMount` teardown above.
177
231
 
178
232
  // Define methods
179
233
  const sendMessage = async (
180
234
  content: string | MultimodalContent,
181
235
  sendOptions?: SendMessageOptions,
182
236
  ) => {
183
- await client.sendMessage(content, undefined, sendOptions)
237
+ try {
238
+ await client.sendMessage(content, undefined, sendOptions)
239
+ } finally {
240
+ syncResumeState()
241
+ }
184
242
  }
185
243
 
186
244
  const cancelQueued = (id: string) => client.cancelQueued(id)
187
245
 
188
246
  const append = async (message: ModelMessage | UIMessage<TTools>) => {
189
- await client.append(message)
247
+ try {
248
+ await client.append(message)
249
+ } finally {
250
+ syncResumeState()
251
+ }
190
252
  }
191
253
 
192
254
  const reload = async () => {
193
- await client.reload()
255
+ try {
256
+ await client.reload()
257
+ } finally {
258
+ syncResumeState()
259
+ }
194
260
  }
195
261
 
196
262
  const stop = () => {
@@ -203,6 +269,7 @@ export function createChat<
203
269
 
204
270
  const clear = () => {
205
271
  client.clear()
272
+ syncResumeState()
206
273
  }
207
274
 
208
275
  const setMessages = (newMessages: Array<UIMessage<TTools>>) => {
@@ -224,8 +291,41 @@ export function createChat<
224
291
  approved: boolean
225
292
  }) => {
226
293
  await client.addToolApprovalResponse(response)
294
+ syncResumeState()
227
295
  }
228
296
 
297
+ const resumeInterrupts = async (
298
+ resumeItems: Array<RunAgentResumeItem>,
299
+ state?: ChatResumeState,
300
+ ) => {
301
+ const result = await client.resumeInterrupts(resumeItems, state)
302
+ syncResumeState()
303
+ return result
304
+ }
305
+
306
+ const resolveInterrupts = (
307
+ resolution: boolean | ((interrupt: ChatInterrupt<TTools>) => undefined),
308
+ ) => {
309
+ if (typeof resolution === 'boolean') {
310
+ client.resolveInterrupts(resolution)
311
+ } else {
312
+ client.resolveInterrupts(resolution)
313
+ }
314
+ }
315
+
316
+ const cancelInterrupts = () => {
317
+ client.cancelInterrupts()
318
+ }
319
+
320
+ const retryInterrupts = () => {
321
+ client.retryInterrupts()
322
+ }
323
+
324
+ const resumeInterruptsUnsafe = (
325
+ resumeItems: Array<RunAgentResumeItem>,
326
+ state?: ChatResumeState,
327
+ ) => client.resumeInterruptsUnsafe(resumeItems, state)
328
+
229
329
  /**
230
330
  * @deprecated Use `updateForwardedProps` instead.
231
331
  * Both populate the same wire payload.
@@ -282,7 +382,7 @@ export function createChat<
282
382
 
283
383
  // Return the chat interface with reactive getters
284
384
  // Using getters allows Svelte to track reactivity without needing $ prefix
285
- // eslint-disable-next-line no-restricted-syntax -- rune return shape diverges from generic CreateChatReturn<TTools, TSchema, TContext> due to TSchema conditional partial/final fields; TS can't structurally narrow.
385
+ // oxlint-disable-next-line eslint-js/no-restricted-syntax -- rune return shape diverges from generic CreateChatReturn<TTools, TSchema, TContext> due to TSchema conditional partial/final fields; TS can't structurally narrow.
286
386
  return {
287
387
  get messages() {
288
388
  return messages
@@ -308,6 +408,21 @@ export function createChat<
308
408
  get queue() {
309
409
  return queue
310
410
  },
411
+ get runId() {
412
+ return runId
413
+ },
414
+ get interrupts() {
415
+ return interruptState.interrupts
416
+ },
417
+ get pendingInterrupts() {
418
+ return interruptState.interrupts
419
+ },
420
+ get interruptErrors() {
421
+ return interruptState.interruptErrors
422
+ },
423
+ get resuming() {
424
+ return interruptState.resuming
425
+ },
311
426
  get partial() {
312
427
  return partial
313
428
  },
@@ -324,6 +439,11 @@ export function createChat<
324
439
  clear,
325
440
  addToolResult,
326
441
  addToolApprovalResponse,
442
+ resolveInterrupts,
443
+ cancelInterrupts,
444
+ retryInterrupts,
445
+ resumeInterruptsUnsafe,
446
+ resumeInterrupts,
327
447
  updateBody,
328
448
  updateForwardedProps,
329
449
  updateContext,
@@ -1,4 +1,9 @@
1
1
  import { createGeneration } from './create-generation.svelte'
2
+ import { reconstructAudioResult } from '@tanstack/ai-client'
3
+ import type {
4
+ CreateGenerationOptions,
5
+ CreateGenerationReturn,
6
+ } from './create-generation.svelte'
2
7
  import type { AudioGenerationResult, StreamChunk } from '@tanstack/ai'
3
8
  import type {
4
9
  AIDevtoolsDisplayOptions,
@@ -6,6 +11,7 @@ import type {
6
11
  ConnectConnectionAdapter,
7
12
  GenerationClientState,
8
13
  GenerationFetcher,
14
+ GenerationPersistenceOptions,
9
15
  InferGenerationOutputFromReturn,
10
16
  } from '@tanstack/ai-client'
11
17
 
@@ -14,12 +20,19 @@ import type {
14
20
  *
15
21
  * @template TOutput - The output type after optional transform (defaults to AudioGenerationResult)
16
22
  */
17
- export interface CreateGenerateAudioOptions<TOutput = AudioGenerationResult> {
23
+ export interface CreateGenerateAudioOptions<
24
+ TOutput = AudioGenerationResult,
25
+ > extends Pick<
26
+ CreateGenerationOptions<AudioGenerateInput, AudioGenerationResult, TOutput>,
27
+ 'persistence' | 'threadId' | 'hydrateGeneration' | 'joinRun'
28
+ > {
18
29
  /** Connect-based adapter for streaming transport (SSE, HTTP stream, custom) */
19
30
  connection?: ConnectConnectionAdapter
20
31
  /** Direct async function for audio generation */
21
32
  fetcher?: GenerationFetcher<AudioGenerateInput, AudioGenerationResult>
22
- /** Unique identifier for this generation instance */
33
+ /**
34
+ * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
35
+ */
23
36
  id?: string
24
37
  /** Additional body parameters to send with connect-based adapter requests */
25
38
  body?: Record<string, any>
@@ -46,7 +59,9 @@ export interface CreateGenerateAudioOptions<TOutput = AudioGenerationResult> {
46
59
  *
47
60
  * @template TOutput - The output type (after optional transform)
48
61
  */
49
- export interface CreateGenerateAudioReturn<TOutput = AudioGenerationResult> {
62
+ export interface CreateGenerateAudioReturn<
63
+ TOutput = AudioGenerationResult,
64
+ > extends Omit<CreateGenerationReturn<TOutput>, 'generate'> {
50
65
  /** The generation result containing audio, or null */
51
66
  readonly result: TOutput | null
52
67
  /** Whether generation is in progress */
@@ -57,12 +72,6 @@ export interface CreateGenerateAudioReturn<TOutput = AudioGenerationResult> {
57
72
  readonly status: GenerationClientState
58
73
  /** Trigger audio generation */
59
74
  generate: (input: AudioGenerateInput) => Promise<void>
60
- /** Abort the current generation */
61
- stop: () => void
62
- /** Clear result, error, and return to idle */
63
- reset: () => void
64
- /** Update additional body parameters */
65
- updateBody: (body: Record<string, any>) => void
66
75
  }
67
76
 
68
77
  /**
@@ -92,9 +101,12 @@ export interface CreateGenerateAudioReturn<TOutput = AudioGenerationResult> {
92
101
  * ```
93
102
  */
94
103
  export function createGenerateAudio<TTransformed = void>(
95
- options: Omit<CreateGenerateAudioOptions, 'onResult'> & {
104
+ options: Omit<
105
+ CreateGenerateAudioOptions,
106
+ 'onResult' | 'persistence' | 'threadId' | 'id'
107
+ > & {
96
108
  onResult?: (result: AudioGenerationResult) => TTransformed
97
- },
109
+ } & GenerationPersistenceOptions,
98
110
  ): CreateGenerateAudioReturn<
99
111
  InferGenerationOutputFromReturn<AudioGenerationResult, TTransformed>
100
112
  > {
@@ -111,6 +123,7 @@ export function createGenerateAudio<TTransformed = void>(
111
123
  >({
112
124
  ...options,
113
125
  devtools,
126
+ reconstructResult: reconstructAudioResult,
114
127
  })
115
128
 
116
129
  return {
@@ -126,9 +139,13 @@ export function createGenerateAudio<TTransformed = void>(
126
139
  get status() {
127
140
  return gen.status
128
141
  },
129
- generate: gen.generate as (input: AudioGenerateInput) => Promise<void>,
142
+ generate: gen.generate,
130
143
  stop: gen.stop,
131
144
  reset: gen.reset,
132
145
  updateBody: gen.updateBody,
146
+ dispose: gen.dispose,
147
+ get runId() {
148
+ return gen.runId
149
+ },
133
150
  }
134
151
  }
@@ -1,10 +1,16 @@
1
1
  import { createGeneration } from './create-generation.svelte'
2
+ import { reconstructImageResult } from '@tanstack/ai-client'
3
+ import type {
4
+ CreateGenerationOptions,
5
+ CreateGenerationReturn,
6
+ } from './create-generation.svelte'
2
7
  import type { ImageGenerationResult, StreamChunk } from '@tanstack/ai'
3
8
  import type {
4
9
  AIDevtoolsDisplayOptions,
5
10
  ConnectConnectionAdapter,
6
11
  GenerationClientState,
7
12
  GenerationFetcher,
13
+ GenerationPersistenceOptions,
8
14
  ImageGenerateInput,
9
15
  InferGenerationOutputFromReturn,
10
16
  } from '@tanstack/ai-client'
@@ -14,12 +20,19 @@ import type {
14
20
  *
15
21
  * @template TOutput - The output type after optional transform (defaults to ImageGenerationResult)
16
22
  */
17
- export interface CreateGenerateImageOptions<TOutput = ImageGenerationResult> {
23
+ export interface CreateGenerateImageOptions<
24
+ TOutput = ImageGenerationResult,
25
+ > extends Pick<
26
+ CreateGenerationOptions<ImageGenerateInput, ImageGenerationResult, TOutput>,
27
+ 'persistence' | 'threadId' | 'hydrateGeneration' | 'joinRun'
28
+ > {
18
29
  /** Connect-based adapter for streaming transport (SSE, HTTP stream, custom) */
19
30
  connection?: ConnectConnectionAdapter
20
31
  /** Direct async function for image generation */
21
32
  fetcher?: GenerationFetcher<ImageGenerateInput, ImageGenerationResult>
22
- /** Unique identifier for this generation instance */
33
+ /**
34
+ * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
35
+ */
23
36
  id?: string
24
37
  /** Additional body parameters to send with connect-based adapter requests */
25
38
  body?: Record<string, any>
@@ -46,7 +59,9 @@ export interface CreateGenerateImageOptions<TOutput = ImageGenerationResult> {
46
59
  *
47
60
  * @template TOutput - The output type (after optional transform)
48
61
  */
49
- export interface CreateGenerateImageReturn<TOutput = ImageGenerationResult> {
62
+ export interface CreateGenerateImageReturn<
63
+ TOutput = ImageGenerationResult,
64
+ > extends Omit<CreateGenerationReturn<TOutput>, 'generate'> {
50
65
  /** The generation result containing images, or null */
51
66
  readonly result: TOutput | null
52
67
  /** Whether generation is in progress */
@@ -57,12 +72,6 @@ export interface CreateGenerateImageReturn<TOutput = ImageGenerationResult> {
57
72
  readonly status: GenerationClientState
58
73
  /** Trigger image generation */
59
74
  generate: (input: ImageGenerateInput) => Promise<void>
60
- /** Abort the current generation */
61
- stop: () => void
62
- /** Clear result, error, and return to idle */
63
- reset: () => void
64
- /** Update additional body parameters */
65
- updateBody: (body: Record<string, any>) => void
66
75
  }
67
76
 
68
77
  /**
@@ -101,9 +110,12 @@ export interface CreateGenerateImageReturn<TOutput = ImageGenerationResult> {
101
110
  * ```
102
111
  */
103
112
  export function createGenerateImage<TTransformed = void>(
104
- options: Omit<CreateGenerateImageOptions, 'onResult'> & {
113
+ options: Omit<
114
+ CreateGenerateImageOptions,
115
+ 'onResult' | 'persistence' | 'threadId' | 'id'
116
+ > & {
105
117
  onResult?: (result: ImageGenerationResult) => TTransformed
106
- },
118
+ } & GenerationPersistenceOptions,
107
119
  ): CreateGenerateImageReturn<
108
120
  InferGenerationOutputFromReturn<ImageGenerationResult, TTransformed>
109
121
  > {
@@ -120,6 +132,7 @@ export function createGenerateImage<TTransformed = void>(
120
132
  >({
121
133
  ...options,
122
134
  devtools,
135
+ reconstructResult: reconstructImageResult,
123
136
  })
124
137
 
125
138
  return {
@@ -135,9 +148,13 @@ export function createGenerateImage<TTransformed = void>(
135
148
  get status() {
136
149
  return gen.status
137
150
  },
138
- generate: gen.generate as (input: ImageGenerateInput) => Promise<void>,
151
+ generate: gen.generate,
139
152
  stop: gen.stop,
140
153
  reset: gen.reset,
141
154
  updateBody: gen.updateBody,
155
+ dispose: gen.dispose,
156
+ get runId() {
157
+ return gen.runId
158
+ },
142
159
  }
143
160
  }
@@ -1,10 +1,16 @@
1
1
  import { createGeneration } from './create-generation.svelte'
2
+ import { reconstructSpeechResult } from '@tanstack/ai-client'
3
+ import type {
4
+ CreateGenerationOptions,
5
+ CreateGenerationReturn,
6
+ } from './create-generation.svelte'
2
7
  import type { StreamChunk, TTSResult } from '@tanstack/ai'
3
8
  import type {
4
9
  AIDevtoolsDisplayOptions,
5
10
  ConnectConnectionAdapter,
6
11
  GenerationClientState,
7
12
  GenerationFetcher,
13
+ GenerationPersistenceOptions,
8
14
  InferGenerationOutputFromReturn,
9
15
  SpeechGenerateInput,
10
16
  } from '@tanstack/ai-client'
@@ -14,12 +20,17 @@ import type {
14
20
  *
15
21
  * @template TOutput - The output type after optional transform (defaults to TTSResult)
16
22
  */
17
- export interface CreateGenerateSpeechOptions<TOutput = TTSResult> {
23
+ export interface CreateGenerateSpeechOptions<TOutput = TTSResult> extends Pick<
24
+ CreateGenerationOptions<SpeechGenerateInput, TTSResult, TOutput>,
25
+ 'persistence' | 'threadId' | 'hydrateGeneration' | 'joinRun'
26
+ > {
18
27
  /** Connect-based adapter for streaming transport (SSE, HTTP stream, custom) */
19
28
  connection?: ConnectConnectionAdapter
20
29
  /** Direct async function for speech generation */
21
30
  fetcher?: GenerationFetcher<SpeechGenerateInput, TTSResult>
22
- /** Unique identifier for this generation instance */
31
+ /**
32
+ * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
33
+ */
23
34
  id?: string
24
35
  /** Additional body parameters to send with connect-based adapter requests */
25
36
  body?: Record<string, any>
@@ -46,7 +57,10 @@ export interface CreateGenerateSpeechOptions<TOutput = TTSResult> {
46
57
  *
47
58
  * @template TOutput - The output type (after optional transform)
48
59
  */
49
- export interface CreateGenerateSpeechReturn<TOutput = TTSResult> {
60
+ export interface CreateGenerateSpeechReturn<TOutput = TTSResult> extends Omit<
61
+ CreateGenerationReturn<TOutput>,
62
+ 'generate'
63
+ > {
50
64
  /** The TTS result containing audio data, or null */
51
65
  readonly result: TOutput | null
52
66
  /** Whether generation is in progress */
@@ -57,12 +71,6 @@ export interface CreateGenerateSpeechReturn<TOutput = TTSResult> {
57
71
  readonly status: GenerationClientState
58
72
  /** Trigger speech generation */
59
73
  generate: (input: SpeechGenerateInput) => Promise<void>
60
- /** Abort the current generation */
61
- stop: () => void
62
- /** Clear result, error, and return to idle */
63
- reset: () => void
64
- /** Update additional body parameters */
65
- updateBody: (body: Record<string, any>) => void
66
74
  }
67
75
 
68
76
  /**
@@ -92,9 +100,12 @@ export interface CreateGenerateSpeechReturn<TOutput = TTSResult> {
92
100
  * ```
93
101
  */
94
102
  export function createGenerateSpeech<TTransformed = void>(
95
- options: Omit<CreateGenerateSpeechOptions, 'onResult'> & {
103
+ options: Omit<
104
+ CreateGenerateSpeechOptions,
105
+ 'onResult' | 'persistence' | 'threadId' | 'id'
106
+ > & {
96
107
  onResult?: (result: TTSResult) => TTransformed
97
- },
108
+ } & GenerationPersistenceOptions,
98
109
  ): CreateGenerateSpeechReturn<
99
110
  InferGenerationOutputFromReturn<TTSResult, TTransformed>
100
111
  > {
@@ -107,6 +118,7 @@ export function createGenerateSpeech<TTransformed = void>(
107
118
  const gen = createGeneration<SpeechGenerateInput, TTSResult, TTransformed>({
108
119
  ...options,
109
120
  devtools,
121
+ reconstructResult: reconstructSpeechResult,
110
122
  })
111
123
 
112
124
  return {
@@ -122,9 +134,13 @@ export function createGenerateSpeech<TTransformed = void>(
122
134
  get status() {
123
135
  return gen.status
124
136
  },
125
- generate: gen.generate as (input: SpeechGenerateInput) => Promise<void>,
137
+ generate: gen.generate,
126
138
  stop: gen.stop,
127
139
  reset: gen.reset,
128
140
  updateBody: gen.updateBody,
141
+ dispose: gen.dispose,
142
+ get runId() {
143
+ return gen.runId
144
+ },
129
145
  }
130
146
  }