@tanstack/ai-client 0.18.4 → 0.18.5

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.
Files changed (48) hide show
  1. package/package.json +3 -3
  2. package/dist/esm/chat-client.d.ts +0 -264
  3. package/dist/esm/chat-client.js +0 -1097
  4. package/dist/esm/chat-client.js.map +0 -1
  5. package/dist/esm/client-persistor.d.ts +0 -86
  6. package/dist/esm/client-persistor.js +0 -243
  7. package/dist/esm/client-persistor.js.map +0 -1
  8. package/dist/esm/connection-adapters.d.ts +0 -203
  9. package/dist/esm/connection-adapters.js +0 -611
  10. package/dist/esm/connection-adapters.js.map +0 -1
  11. package/dist/esm/devtools-noop.d.ts +0 -63
  12. package/dist/esm/devtools-noop.js +0 -141
  13. package/dist/esm/devtools-noop.js.map +0 -1
  14. package/dist/esm/devtools.d.ts +0 -276
  15. package/dist/esm/devtools.js +0 -1178
  16. package/dist/esm/devtools.js.map +0 -1
  17. package/dist/esm/events.d.ts +0 -129
  18. package/dist/esm/events.js +0 -227
  19. package/dist/esm/events.js.map +0 -1
  20. package/dist/esm/generation-client.d.ts +0 -99
  21. package/dist/esm/generation-client.js +0 -325
  22. package/dist/esm/generation-client.js.map +0 -1
  23. package/dist/esm/generation-types.d.ts +0 -242
  24. package/dist/esm/generation-types.js +0 -14
  25. package/dist/esm/generation-types.js.map +0 -1
  26. package/dist/esm/index.d.ts +0 -16
  27. package/dist/esm/index.js +0 -44
  28. package/dist/esm/index.js.map +0 -1
  29. package/dist/esm/realtime-client.d.ts +0 -98
  30. package/dist/esm/realtime-client.js +0 -403
  31. package/dist/esm/realtime-client.js.map +0 -1
  32. package/dist/esm/realtime-types.d.ts +0 -78
  33. package/dist/esm/response-stream.d.ts +0 -7
  34. package/dist/esm/response-stream.js +0 -32
  35. package/dist/esm/response-stream.js.map +0 -1
  36. package/dist/esm/sse-parser.d.ts +0 -8
  37. package/dist/esm/sse-parser.js +0 -52
  38. package/dist/esm/sse-parser.js.map +0 -1
  39. package/dist/esm/sse-utils.d.ts +0 -1
  40. package/dist/esm/sse-utils.js +0 -11
  41. package/dist/esm/sse-utils.js.map +0 -1
  42. package/dist/esm/tool-types.d.ts +0 -20
  43. package/dist/esm/types.d.ts +0 -419
  44. package/dist/esm/types.js +0 -11
  45. package/dist/esm/types.js.map +0 -1
  46. package/dist/esm/video-generation-client.d.ts +0 -110
  47. package/dist/esm/video-generation-client.js +0 -382
  48. package/dist/esm/video-generation-client.js.map +0 -1
@@ -1,20 +0,0 @@
1
- import { AnyClientTool, InferToolInput, InferToolOutput } from '@tanstack/ai/client';
2
- /**
3
- * Extract all tool names from a tools array as a union type
4
- */
5
- export type ExtractToolNames<TTools extends ReadonlyArray<AnyClientTool>> = TTools[number]['name'];
6
- /**
7
- * Find a tool by name in the tools array
8
- */
9
- type FindTool<TTools extends ReadonlyArray<AnyClientTool>, TName extends string> = Extract<TTools[number], {
10
- name: TName;
11
- }>;
12
- /**
13
- * Extract the input type for a specific tool by name
14
- */
15
- export type ExtractToolInput<TTools extends ReadonlyArray<AnyClientTool>, TName extends string> = TName extends ExtractToolNames<TTools> ? InferToolInput<FindTool<TTools, TName>> : any;
16
- /**
17
- * Extract the output type for a specific tool by name
18
- */
19
- export type ExtractToolOutput<TTools extends ReadonlyArray<AnyClientTool>, TName extends string> = TName extends ExtractToolNames<TTools> ? InferToolOutput<FindTool<TTools, TName>> : any;
20
- export {};
@@ -1,419 +0,0 @@
1
- import { AnyClientTool, AudioPart, ChunkStrategy, ContentPart, DocumentPart, ImagePart, InferToolInput, InferToolOutput, ModelMessage, StreamChunk, StructuredOutputPart, VideoPart } from '@tanstack/ai/client';
2
- import { ConnectionAdapter } from './connection-adapters.js';
3
- import { AIDevtoolsClientMetadata } from './devtools.js';
4
- import { ChatDevtoolsBridgeFactory } from './devtools-noop.js';
5
- export type { StructuredOutputPart } from '@tanstack/ai/client';
6
- /**
7
- * `messages` is the full UIMessage history (not a delta). `data` is the
8
- * merged body — `ChatClientOptions.body` plus any per-call data passed to
9
- * `sendMessage(...)`. `threadId` / `runId` are the AG-UI correlation ids
10
- * the chat client uses to track this turn — forward them to your server
11
- * if it needs to correlate requests.
12
- */
13
- export interface ChatFetcherInput {
14
- messages: Array<UIMessage>;
15
- data?: Record<string, unknown>;
16
- threadId: string;
17
- runId: string;
18
- }
19
- export interface ChatFetcherOptions {
20
- /** Fires when `stop()` is called or the request is superseded. */
21
- signal: AbortSignal;
22
- }
23
- /**
24
- * Direct function that performs a chat request. Mirrors
25
- * `GenerationFetcher`. Returns either a `Response` (SSE body parsed by the
26
- * chat client) or an `AsyncIterable<StreamChunk>` (yielded directly). May
27
- * return the value synchronously, as a `Promise`, or as an async generator
28
- * (`async function*`) — the chat client awaits whichever shape is returned.
29
- *
30
- * @example
31
- * ```ts
32
- * useChat({
33
- * fetcher: ({ messages }, { signal }) =>
34
- * chatFn({ data: { messages }, signal }),
35
- * })
36
- * ```
37
- */
38
- export type ChatFetcher = (input: ChatFetcherInput, options: ChatFetcherOptions) => Response | AsyncIterable<StreamChunk> | Promise<Response | AsyncIterable<StreamChunk>>;
39
- /**
40
- * Distributive `Omit` — applies `Omit<O, K>` per branch of a union so
41
- * discriminated unions survive omission. Plain `Omit` collapses unions
42
- * into a single object shape, which would erase the `ChatTransport` XOR
43
- * when framework hooks omit React-managed callbacks from
44
- * `ChatClientOptions`.
45
- */
46
- export type DistributedOmit<TObject, TKeys extends keyof any> = TObject extends unknown ? Omit<TObject, TKeys> : never;
47
- /**
48
- * Discriminated union enforcing that exactly one of `connection` or
49
- * `fetcher` is provided. Mirrors `GenerationTransport`.
50
- */
51
- export type ChatTransport = {
52
- connection: ConnectionAdapter;
53
- fetcher?: never;
54
- } | {
55
- fetcher: ChatFetcher;
56
- connection?: never;
57
- };
58
- /**
59
- * Tool call states - track the lifecycle of a tool call
60
- */
61
- export type ToolCallState = 'awaiting-input' | 'input-streaming' | 'input-complete' | 'approval-requested' | 'approval-responded' | 'complete' | 'error';
62
- /**
63
- * Tool result states - track the lifecycle of a tool result
64
- */
65
- export type ToolResultState = 'streaming' | 'complete' | 'error';
66
- /**
67
- * ChatClient state - track the lifecycle of a chat
68
- */
69
- export type ChatClientState = 'ready' | 'submitted' | 'streaming' | 'error';
70
- /**
71
- * Connection lifecycle state for the subscription loop.
72
- */
73
- export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'error';
74
- /**
75
- * Multimodal content input for sending messages with rich media.
76
- * Allows sending text, images, audio, video, and documents to the LLM.
77
- *
78
- * @example
79
- * ```ts
80
- * // Send an image with a question
81
- * client.sendMessage({
82
- * content: [
83
- * { type: 'text', content: 'What is in this image?' },
84
- * { type: 'image', source: { type: 'url', value: 'https://example.com/photo.jpg' } }
85
- * ],
86
- * id: 'custom-message-id' // optional
87
- * })
88
- * ```
89
- */
90
- export interface MultimodalContent {
91
- /**
92
- * The content of the message.
93
- * Can be a simple string or an array of content parts for multimodal messages.
94
- */
95
- content: string | Array<ContentPart>;
96
- /**
97
- * Optional custom ID for the message.
98
- * If not provided, a unique ID will be generated.
99
- */
100
- id?: string;
101
- }
102
- /**
103
- * Message parts - building blocks of UIMessage
104
- */
105
- export interface TextPart {
106
- type: 'text';
107
- content: string;
108
- }
109
- /**
110
- * Helper type that creates a tool-call part for a specific tool.
111
- * This is a conditional type to enable proper distribution over union types,
112
- * creating a discriminated union where `name` is the discriminant.
113
- */
114
- type ToolCallPartForTool<T> = T extends AnyClientTool ? {
115
- type: 'tool-call';
116
- id: string;
117
- name: T['name'];
118
- arguments: string;
119
- /** Parsed tool input (typed from inputSchema) */
120
- input?: InferToolInput<T>;
121
- state: ToolCallState;
122
- /** Approval metadata if tool requires user approval */
123
- approval?: {
124
- id: string;
125
- needsApproval: boolean;
126
- approved?: boolean;
127
- };
128
- /** Tool execution output (for client tools or after approval) */
129
- output?: InferToolOutput<T>;
130
- } : never;
131
- /**
132
- * Fallback tool-call part type when tools are not typed
133
- */
134
- type UntypedToolCallPart = {
135
- type: 'tool-call';
136
- id: string;
137
- name: string;
138
- arguments: string;
139
- input?: any;
140
- state: ToolCallState;
141
- approval?: {
142
- id: string;
143
- needsApproval: boolean;
144
- approved?: boolean;
145
- };
146
- output?: any;
147
- };
148
- /**
149
- * Tool call part that creates a proper discriminated union.
150
- * When TTools is typed, checking `part.name === 'toolName'` will narrow
151
- * `part.output` to the correct type for that tool.
152
- *
153
- * The discriminant is `name`, so code like:
154
- * ```ts
155
- * if (part.name === 'recommendGuitar') {
156
- * // part.output is now typed to the recommendGuitar tool's output
157
- * }
158
- * ```
159
- */
160
- export type ToolCallPart<TTools extends ReadonlyArray<AnyClientTool> = any> = [
161
- TTools
162
- ] extends [never] ? UntypedToolCallPart : unknown extends TTools ? UntypedToolCallPart : TTools extends ReadonlyArray<infer Tool> ? Tool extends AnyClientTool ? ToolCallPartForTool<Tool> : UntypedToolCallPart : UntypedToolCallPart;
163
- export interface ToolResultPart {
164
- type: 'tool-result';
165
- toolCallId: string;
166
- content: string | Array<ContentPart>;
167
- state: ToolResultState;
168
- error?: string;
169
- }
170
- export interface ThinkingPart {
171
- type: 'thinking';
172
- content: string;
173
- }
174
- export type MessagePart<TTools extends ReadonlyArray<AnyClientTool> = any, TData = unknown> = TextPart | ImagePart | AudioPart | VideoPart | DocumentPart | ToolCallPart<TTools> | ToolResultPart | ThinkingPart | StructuredOutputPart<TData>;
175
- /**
176
- * UIMessage - Domain-specific message format optimized for building chat UIs
177
- * Contains parts that can be text, tool calls, or tool results.
178
- *
179
- * `TTools` narrows the tool-call/result part types based on the registered
180
- * tools. `TData` is the schema-inferred type for any `structured-output` part
181
- * on the message — defaulted to `unknown` so untyped consumers (the core
182
- * stream processor, the wire converter) don't need to thread a schema generic
183
- * everywhere; the hook layer (`useChat({ outputSchema })`) substitutes it on
184
- * the public return so `m.parts.find(p => p.type === 'structured-output').data`
185
- * is typed without manual casts.
186
- */
187
- export interface UIMessage<TTools extends ReadonlyArray<AnyClientTool> = any, TData = unknown> {
188
- id: string;
189
- role: 'system' | 'user' | 'assistant';
190
- parts: Array<MessagePart<TTools, TData>>;
191
- createdAt?: Date;
192
- }
193
- export interface ChatClientPersistence<TTools extends ReadonlyArray<AnyClientTool> = any> {
194
- getItem: (id: string) => Array<UIMessage<TTools>> | null | undefined | Promise<Array<UIMessage<TTools>> | null | undefined>;
195
- setItem: (id: string, messages: Array<UIMessage<TTools>>) => void | Promise<void>;
196
- removeItem: (id: string) => void | Promise<void>;
197
- }
198
- type IsUnknown<T> = unknown extends T ? [T] extends [unknown] ? true : false : false;
199
- type KnownContext<T> = IsUnknown<T> extends true ? never : T;
200
- type MergeContext<TLeft, TRight> = [TLeft] extends [never] ? TRight : [TRight] extends [never] ? TLeft : TLeft & TRight;
201
- type UnionToIntersection<T> = [T] extends [never] ? never : (T extends unknown ? (value: T) => void : never) extends (value: infer TIntersection) => void ? TIntersection : never;
202
- type DefinedContext<T> = Exclude<T, undefined>;
203
- type ContextFromExecute<T> = T extends (...args: any) => any ? NonNullable<Parameters<T>[1]> extends {
204
- context: infer TContext;
205
- } ? KnownContext<TContext> : never : never;
206
- type ContextFromClientTool<T> = T extends AnyClientTool ? T extends {
207
- execute?: infer TExecute;
208
- } ? ContextFromExecute<TExecute> : never : never;
209
- type RequiredContextFromClientToolUnion<T> = T extends unknown ? undefined extends ContextFromClientTool<T> ? never : ContextFromClientTool<T> : never;
210
- type ContextFromClientToolUnion<T> = [
211
- UnionToIntersection<DefinedContext<ContextFromClientTool<T>>>
212
- ] extends [never] ? never : [RequiredContextFromClientToolUnion<T>] extends [never] ? UnionToIntersection<DefinedContext<ContextFromClientTool<T>>> | undefined : UnionToIntersection<DefinedContext<ContextFromClientTool<T>>>;
213
- type ContextFromClientTools<TTools> = IsUnknown<TTools> extends true ? never : TTools extends readonly [infer THead, ...infer TTail] ? MergeContext<ContextFromClientTool<THead>, ContextFromClientTools<TTail>> : TTools extends ReadonlyArray<infer TItem> ? ContextFromClientToolUnion<TItem> : never;
214
- export type InferredClientContext<TTools> = [
215
- ContextFromClientTools<TTools>
216
- ] extends [never] ? unknown : ContextFromClientTools<TTools>;
217
- export type ClientContextOptionFromTools<TTools, TContext> = [
218
- ContextFromClientTools<TTools>
219
- ] extends [never] ? {
220
- context?: TContext;
221
- } : undefined extends ContextFromClientTools<TTools> ? {
222
- context?: TContext & ContextFromClientTools<TTools>;
223
- } : {
224
- context: TContext & ContextFromClientTools<TTools>;
225
- };
226
- /**
227
- * Base options for `ChatClient`, excluding the transport (`connection` or
228
- * `fetcher`) which is supplied separately via `ChatTransport` so the XOR
229
- * is preserved when composing the final `ChatClientOptions` type.
230
- */
231
- export interface ChatClientBaseOptions<TTools extends ReadonlyArray<AnyClientTool> = any, TContext = unknown> {
232
- /**
233
- * Initial messages to populate the chat
234
- */
235
- initialMessages?: Array<UIMessage<TTools>>;
236
- /**
237
- * Optional persistence adapter for chat messages.
238
- */
239
- persistence?: ChatClientPersistence<TTools>;
240
- /**
241
- * Unique identifier for this chat instance
242
- * Used for managing multiple chats
243
- */
244
- id?: string;
245
- /**
246
- * Thread ID to use for this chat session. Persists across sends within
247
- * the session. If omitted, a unique thread ID is generated.
248
- */
249
- threadId?: string;
250
- /**
251
- * Arbitrary client-controlled JSON forwarded to the server in the
252
- * AG-UI `RunAgentInput.forwardedProps` field. Use this for per-session
253
- * options like provider/model selection or feature flags that the
254
- * server endpoint should read.
255
- *
256
- * Replaces the legacy `body` option. If both are provided,
257
- * `forwardedProps` wins on key collision.
258
- */
259
- forwardedProps?: Record<string, any>;
260
- /**
261
- * @deprecated Use `forwardedProps` instead. `body` continues to work
262
- * unchanged — its values are merged into the AG-UI
263
- * `RunAgentInput.forwardedProps` field on the wire and are also
264
- * mirrored under the legacy `data` field for servers that have not
265
- * migrated yet. Will be removed in a future major release.
266
- */
267
- body?: Record<string, any>;
268
- /**
269
- * Client-local runtime context passed to client tool implementations.
270
- *
271
- * This value is not serialized to the server. Use `forwardedProps` for
272
- * explicit client-to-server handoff of serializable values.
273
- */
274
- context?: TContext;
275
- /**
276
- * Callback when a response is received
277
- */
278
- onResponse?: (response?: Response) => void | Promise<void>;
279
- /**
280
- * Callback when a stream chunk is received
281
- */
282
- onChunk?: (chunk: StreamChunk) => void;
283
- /**
284
- * Callback when the response is finished
285
- */
286
- onFinish?: (message: UIMessage<TTools>) => void;
287
- /**
288
- * Callback when an error occurs
289
- */
290
- onError?: (error: Error) => void;
291
- /**
292
- * Callback when messages change
293
- */
294
- onMessagesChange?: (messages: Array<UIMessage<TTools>>) => void;
295
- /**
296
- * Callback when loading state changes
297
- */
298
- onLoadingChange?: (isLoading: boolean) => void;
299
- /**
300
- * Callback when error state changes
301
- */
302
- onErrorChange?: (error: Error | undefined) => void;
303
- /**
304
- * Callback when chat status changes
305
- */
306
- onStatusChange?: (status: ChatClientState) => void;
307
- /**
308
- * Callback when subscription lifecycle changes.
309
- * This is independent from request lifecycle (`isLoading`, `status`).
310
- */
311
- onSubscriptionChange?: (isSubscribed: boolean) => void;
312
- /**
313
- * Callback when connection lifecycle changes.
314
- */
315
- onConnectionStatusChange?: (status: ConnectionStatus) => void;
316
- /**
317
- * Callback when session generation activity changes.
318
- * Derived from stream run events (RUN_STARTED / RUN_FINISHED / RUN_ERROR).
319
- * Unlike `onLoadingChange` (request-local), this reflects shared generation
320
- * activity visible to all subscribers (e.g. across tabs/devices).
321
- */
322
- onSessionGeneratingChange?: (isGenerating: boolean) => void;
323
- /**
324
- * Callback when a custom event is received from a server-side tool.
325
- * Custom events are emitted by tools using `context.emitCustomEvent()` during execution.
326
- *
327
- * @param eventType - The name of the custom event
328
- * @param data - The event payload data
329
- * @param context - Additional context including the toolCallId that emitted the event
330
- */
331
- onCustomEvent?: (eventType: string, data: unknown, context: {
332
- toolCallId?: string;
333
- }) => void;
334
- /**
335
- * Client-side tools with execution logic
336
- * When provided, tools with execute functions will be called automatically
337
- */
338
- tools?: TTools;
339
- /**
340
- * Devtools hook metadata for this client instance.
341
- */
342
- devtools?: Partial<AIDevtoolsClientMetadata>;
343
- /**
344
- * Factory that constructs the devtools bridge. Default is a no-op
345
- * factory, which keeps `@tanstack/ai-client/devtools` (the heavy
346
- * bridge implementation) out of the main entry's bundle. Frameworks
347
- * that need live devtools should pass the real factory from
348
- * `@tanstack/ai-client/devtools`.
349
- */
350
- devtoolsBridgeFactory?: ChatDevtoolsBridgeFactory;
351
- /**
352
- * Stream processing options (optional)
353
- * Configure chunking strategy
354
- */
355
- streamProcessor?: {
356
- /**
357
- * Strategy for when to emit text updates
358
- * Defaults to ImmediateStrategy (every chunk)
359
- */
360
- chunkStrategy?: ChunkStrategy;
361
- };
362
- }
363
- /**
364
- * Options for `ChatClient`. Exactly one of `connection` or `fetcher` must be
365
- * provided — the type-level XOR is enforced via `ChatTransport`.
366
- */
367
- export type ChatClientOptions<TTools extends ReadonlyArray<AnyClientTool> = any, TContext = InferredClientContext<TTools>> = DistributedOmit<ChatClientBaseOptions<TTools, TContext>, 'context'> & ClientContextOptionFromTools<TTools, TContext> & ChatTransport;
368
- export interface ChatRequestBody {
369
- messages: Array<ModelMessage>;
370
- data?: Record<string, any>;
371
- }
372
- /**
373
- * Create a typed array of client tools with proper type inference.
374
- * This eliminates the need for `as const` when defining tool arrays.
375
- *
376
- * @example
377
- * ```ts
378
- * const tools = clientTools(
379
- * myTool1.client(() => result1),
380
- * myTool2.client(() => result2),
381
- * )
382
- *
383
- * // tools is now properly typed as a tuple with literal tool names
384
- * // This enables type narrowing when checking part.name === 'toolName'
385
- * ```
386
- */
387
- export declare function clientTools<const T extends Array<AnyClientTool>>(...tools: T): T;
388
- /**
389
- * Helper to create typed chat client options
390
- * Use this to get proper type inference for messages
391
- *
392
- * @example
393
- * ```ts
394
- * const tools = clientTools(myTool1, myTool2)
395
- *
396
- * const chatOptions = createChatClientOptions({
397
- * connection: fetchServerSentEvents('/api/chat'),
398
- * tools,
399
- * })
400
- *
401
- * type MyMessages = InferChatMessages<typeof chatOptions>
402
- * ```
403
- */
404
- export declare function createChatClientOptions<const TTools extends ReadonlyArray<AnyClientTool>, TContext = InferredClientContext<TTools>>(options: ChatClientOptions<TTools, TContext>): ChatClientOptions<TTools, TContext>;
405
- /**
406
- * Extract the message type from chat options
407
- *
408
- * @example
409
- * ```ts
410
- * const chatOptions = createChatClientOptions({
411
- * connection: fetchServerSentEvents('/api/chat'),
412
- * tools: [myTool1, myTool2],
413
- * })
414
- *
415
- * type MyMessages = InferChatMessages<typeof chatOptions>
416
- * // MyMessages is now Array<UIMessage<[typeof myTool1, typeof myTool2]>>
417
- * ```
418
- */
419
- export type InferChatMessages<T> = T extends ChatClientOptions<infer TTools, any> ? Array<UIMessage<TTools>> : never;
package/dist/esm/types.js DELETED
@@ -1,11 +0,0 @@
1
- function clientTools(...tools) {
2
- return tools;
3
- }
4
- function createChatClientOptions(options) {
5
- return options;
6
- }
7
- export {
8
- clientTools,
9
- createChatClientOptions
10
- };
11
- //# sourceMappingURL=types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sources":["../../src/types.ts"],"sourcesContent":["import type {\n AnyClientTool,\n AudioPart,\n ChunkStrategy,\n ContentPart,\n DocumentPart,\n ImagePart,\n InferToolInput,\n InferToolOutput,\n ModelMessage,\n StreamChunk,\n StructuredOutputPart,\n VideoPart,\n} from '@tanstack/ai/client'\nimport type { ConnectionAdapter } from './connection-adapters'\nimport type { AIDevtoolsClientMetadata } from './devtools'\nimport type { ChatDevtoolsBridgeFactory } from './devtools-noop'\n\nexport type { StructuredOutputPart } from '@tanstack/ai/client'\n\n/**\n * `messages` is the full UIMessage history (not a delta). `data` is the\n * merged body — `ChatClientOptions.body` plus any per-call data passed to\n * `sendMessage(...)`. `threadId` / `runId` are the AG-UI correlation ids\n * the chat client uses to track this turn — forward them to your server\n * if it needs to correlate requests.\n */\nexport interface ChatFetcherInput {\n messages: Array<UIMessage>\n data?: Record<string, unknown>\n threadId: string\n runId: string\n}\n\nexport interface ChatFetcherOptions {\n /** Fires when `stop()` is called or the request is superseded. */\n signal: AbortSignal\n}\n\n/**\n * Direct function that performs a chat request. Mirrors\n * `GenerationFetcher`. Returns either a `Response` (SSE body parsed by the\n * chat client) or an `AsyncIterable<StreamChunk>` (yielded directly). May\n * return the value synchronously, as a `Promise`, or as an async generator\n * (`async function*`) — the chat client awaits whichever shape is returned.\n *\n * @example\n * ```ts\n * useChat({\n * fetcher: ({ messages }, { signal }) =>\n * chatFn({ data: { messages }, signal }),\n * })\n * ```\n */\nexport type ChatFetcher = (\n input: ChatFetcherInput,\n options: ChatFetcherOptions,\n) =>\n | Response\n | AsyncIterable<StreamChunk>\n | Promise<Response | AsyncIterable<StreamChunk>>\n\n/**\n * Distributive `Omit` — applies `Omit<O, K>` per branch of a union so\n * discriminated unions survive omission. Plain `Omit` collapses unions\n * into a single object shape, which would erase the `ChatTransport` XOR\n * when framework hooks omit React-managed callbacks from\n * `ChatClientOptions`.\n */\nexport type DistributedOmit<\n TObject,\n TKeys extends keyof any,\n> = TObject extends unknown ? Omit<TObject, TKeys> : never\n\n/**\n * Discriminated union enforcing that exactly one of `connection` or\n * `fetcher` is provided. Mirrors `GenerationTransport`.\n */\nexport type ChatTransport =\n | { connection: ConnectionAdapter; fetcher?: never }\n | { fetcher: ChatFetcher; connection?: never }\n\n/**\n * Tool call states - track the lifecycle of a tool call\n */\nexport type ToolCallState =\n | 'awaiting-input' // Received start but no arguments yet\n | 'input-streaming' // Partial arguments received\n | 'input-complete' // All arguments received\n | 'approval-requested' // Waiting for user approval\n | 'approval-responded' // User has approved/denied\n | 'complete' // Result is complete\n | 'error' // Tool execution failed (terminal)\n\n/**\n * Tool result states - track the lifecycle of a tool result\n */\nexport type ToolResultState =\n | 'streaming' // Placeholder for future streamed output\n | 'complete' // Result is complete\n | 'error' // Error occurred\n\n/**\n * ChatClient state - track the lifecycle of a chat\n */\nexport type ChatClientState = 'ready' | 'submitted' | 'streaming' | 'error'\n\n/**\n * Connection lifecycle state for the subscription loop.\n */\nexport type ConnectionStatus =\n | 'disconnected'\n | 'connecting'\n | 'connected'\n | 'error'\n\n/**\n * Multimodal content input for sending messages with rich media.\n * Allows sending text, images, audio, video, and documents to the LLM.\n *\n * @example\n * ```ts\n * // Send an image with a question\n * client.sendMessage({\n * content: [\n * { type: 'text', content: 'What is in this image?' },\n * { type: 'image', source: { type: 'url', value: 'https://example.com/photo.jpg' } }\n * ],\n * id: 'custom-message-id' // optional\n * })\n * ```\n */\nexport interface MultimodalContent {\n /**\n * The content of the message.\n * Can be a simple string or an array of content parts for multimodal messages.\n */\n content: string | Array<ContentPart>\n /**\n * Optional custom ID for the message.\n * If not provided, a unique ID will be generated.\n */\n id?: string\n}\n\n/**\n * Message parts - building blocks of UIMessage\n */\nexport interface TextPart {\n type: 'text'\n content: string\n}\n\n/**\n * Helper type that creates a tool-call part for a specific tool.\n * This is a conditional type to enable proper distribution over union types,\n * creating a discriminated union where `name` is the discriminant.\n */\ntype ToolCallPartForTool<T> = T extends AnyClientTool\n ? {\n type: 'tool-call'\n id: string\n name: T['name']\n arguments: string // JSON string (may be incomplete)\n /** Parsed tool input (typed from inputSchema) */\n input?: InferToolInput<T>\n state: ToolCallState\n /** Approval metadata if tool requires user approval */\n approval?: {\n id: string // Unique approval ID\n needsApproval: boolean // Always true if present\n approved?: boolean // User's decision (undefined until responded)\n }\n /** Tool execution output (for client tools or after approval) */\n output?: InferToolOutput<T>\n }\n : never\n\n/**\n * Fallback tool-call part type when tools are not typed\n */\ntype UntypedToolCallPart = {\n type: 'tool-call'\n id: string\n name: string\n arguments: string\n input?: any\n state: ToolCallState\n approval?: {\n id: string\n needsApproval: boolean\n approved?: boolean\n }\n output?: any\n}\n\n/**\n * Tool call part that creates a proper discriminated union.\n * When TTools is typed, checking `part.name === 'toolName'` will narrow\n * `part.output` to the correct type for that tool.\n *\n * The discriminant is `name`, so code like:\n * ```ts\n * if (part.name === 'recommendGuitar') {\n * // part.output is now typed to the recommendGuitar tool's output\n * }\n * ```\n */\nexport type ToolCallPart<TTools extends ReadonlyArray<AnyClientTool> = any> =\n // Check if we have a concrete tools array (not 'any' or 'never')\n [TTools] extends [never]\n ? UntypedToolCallPart\n : unknown extends TTools\n ? UntypedToolCallPart\n : TTools extends ReadonlyArray<infer Tool>\n ? Tool extends AnyClientTool\n ? ToolCallPartForTool<Tool>\n : UntypedToolCallPart\n : UntypedToolCallPart\n\nexport interface ToolResultPart {\n type: 'tool-result'\n toolCallId: string\n content: string | Array<ContentPart>\n state: ToolResultState\n error?: string // Error message if state is \"error\"\n}\n\nexport interface ThinkingPart {\n type: 'thinking'\n content: string\n}\n\nexport type MessagePart<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TData = unknown,\n> =\n | TextPart\n | ImagePart\n | AudioPart\n | VideoPart\n | DocumentPart\n | ToolCallPart<TTools>\n | ToolResultPart\n | ThinkingPart\n | StructuredOutputPart<TData>\n\n/**\n * UIMessage - Domain-specific message format optimized for building chat UIs\n * Contains parts that can be text, tool calls, or tool results.\n *\n * `TTools` narrows the tool-call/result part types based on the registered\n * tools. `TData` is the schema-inferred type for any `structured-output` part\n * on the message — defaulted to `unknown` so untyped consumers (the core\n * stream processor, the wire converter) don't need to thread a schema generic\n * everywhere; the hook layer (`useChat({ outputSchema })`) substitutes it on\n * the public return so `m.parts.find(p => p.type === 'structured-output').data`\n * is typed without manual casts.\n */\nexport interface UIMessage<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TData = unknown,\n> {\n id: string\n role: 'system' | 'user' | 'assistant'\n parts: Array<MessagePart<TTools, TData>>\n createdAt?: Date\n}\n\nexport interface ChatClientPersistence<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n> {\n getItem: (\n id: string,\n ) =>\n | Array<UIMessage<TTools>>\n | null\n | undefined\n | Promise<Array<UIMessage<TTools>> | null | undefined>\n setItem: (\n id: string,\n messages: Array<UIMessage<TTools>>,\n ) => void | Promise<void>\n removeItem: (id: string) => void | Promise<void>\n}\n\ntype IsUnknown<T> = unknown extends T\n ? [T] extends [unknown]\n ? true\n : false\n : false\n\ntype KnownContext<T> = IsUnknown<T> extends true ? never : T\n\ntype MergeContext<TLeft, TRight> = [TLeft] extends [never]\n ? TRight\n : [TRight] extends [never]\n ? TLeft\n : TLeft & TRight\n\ntype UnionToIntersection<T> = [T] extends [never]\n ? never\n : (T extends unknown ? (value: T) => void : never) extends (\n value: infer TIntersection,\n ) => void\n ? TIntersection\n : never\n\ntype DefinedContext<T> = Exclude<T, undefined>\n\ntype ContextFromExecute<T> = T extends (...args: any) => any\n ? NonNullable<Parameters<T>[1]> extends { context: infer TContext }\n ? KnownContext<TContext>\n : never\n : never\n\ntype ContextFromClientTool<T> = T extends AnyClientTool\n ? T extends { execute?: infer TExecute }\n ? ContextFromExecute<TExecute>\n : never\n : never\n\ntype RequiredContextFromClientToolUnion<T> = T extends unknown\n ? undefined extends ContextFromClientTool<T>\n ? never\n : ContextFromClientTool<T>\n : never\n\ntype ContextFromClientToolUnion<T> = [\n UnionToIntersection<DefinedContext<ContextFromClientTool<T>>>,\n] extends [never]\n ? never\n : [RequiredContextFromClientToolUnion<T>] extends [never]\n ? UnionToIntersection<DefinedContext<ContextFromClientTool<T>>> | undefined\n : UnionToIntersection<DefinedContext<ContextFromClientTool<T>>>\n\ntype ContextFromClientTools<TTools> =\n IsUnknown<TTools> extends true\n ? never\n : TTools extends readonly [infer THead, ...infer TTail]\n ? MergeContext<\n ContextFromClientTool<THead>,\n ContextFromClientTools<TTail>\n >\n : TTools extends ReadonlyArray<infer TItem>\n ? ContextFromClientToolUnion<TItem>\n : never\n\nexport type InferredClientContext<TTools> = [\n ContextFromClientTools<TTools>,\n] extends [never]\n ? unknown\n : ContextFromClientTools<TTools>\n\nexport type ClientContextOptionFromTools<TTools, TContext> = [\n ContextFromClientTools<TTools>,\n] extends [never]\n ? { context?: TContext }\n : undefined extends ContextFromClientTools<TTools>\n ? { context?: TContext & ContextFromClientTools<TTools> }\n : { context: TContext & ContextFromClientTools<TTools> }\n\n/**\n * Base options for `ChatClient`, excluding the transport (`connection` or\n * `fetcher`) which is supplied separately via `ChatTransport` so the XOR\n * is preserved when composing the final `ChatClientOptions` type.\n */\nexport interface ChatClientBaseOptions<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TContext = unknown,\n> {\n /**\n * Initial messages to populate the chat\n */\n initialMessages?: Array<UIMessage<TTools>>\n\n /**\n * Optional persistence adapter for chat messages.\n */\n persistence?: ChatClientPersistence<TTools>\n\n /**\n * Unique identifier for this chat instance\n * Used for managing multiple chats\n */\n id?: string\n\n /**\n * Thread ID to use for this chat session. Persists across sends within\n * the session. If omitted, a unique thread ID is generated.\n */\n threadId?: string\n\n /**\n * Arbitrary client-controlled JSON forwarded to the server in the\n * AG-UI `RunAgentInput.forwardedProps` field. Use this for per-session\n * options like provider/model selection or feature flags that the\n * server endpoint should read.\n *\n * Replaces the legacy `body` option. If both are provided,\n * `forwardedProps` wins on key collision.\n */\n forwardedProps?: Record<string, any>\n\n /**\n * @deprecated Use `forwardedProps` instead. `body` continues to work\n * unchanged — its values are merged into the AG-UI\n * `RunAgentInput.forwardedProps` field on the wire and are also\n * mirrored under the legacy `data` field for servers that have not\n * migrated yet. Will be removed in a future major release.\n */\n body?: Record<string, any>\n\n /**\n * Client-local runtime context passed to client tool implementations.\n *\n * This value is not serialized to the server. Use `forwardedProps` for\n * explicit client-to-server handoff of serializable values.\n */\n context?: TContext\n\n /**\n * Callback when a response is received\n */\n onResponse?: (response?: Response) => void | Promise<void>\n\n /**\n * Callback when a stream chunk is received\n */\n onChunk?: (chunk: StreamChunk) => void\n\n /**\n * Callback when the response is finished\n */\n onFinish?: (message: UIMessage<TTools>) => void\n\n /**\n * Callback when an error occurs\n */\n onError?: (error: Error) => void\n\n /**\n * Callback when messages change\n */\n onMessagesChange?: (messages: Array<UIMessage<TTools>>) => void\n\n /**\n * Callback when loading state changes\n */\n onLoadingChange?: (isLoading: boolean) => void\n\n /**\n * Callback when error state changes\n */\n onErrorChange?: (error: Error | undefined) => void\n\n /**\n * Callback when chat status changes\n */\n onStatusChange?: (status: ChatClientState) => void\n\n /**\n * Callback when subscription lifecycle changes.\n * This is independent from request lifecycle (`isLoading`, `status`).\n */\n onSubscriptionChange?: (isSubscribed: boolean) => void\n\n /**\n * Callback when connection lifecycle changes.\n */\n onConnectionStatusChange?: (status: ConnectionStatus) => void\n\n /**\n * Callback when session generation activity changes.\n * Derived from stream run events (RUN_STARTED / RUN_FINISHED / RUN_ERROR).\n * Unlike `onLoadingChange` (request-local), this reflects shared generation\n * activity visible to all subscribers (e.g. across tabs/devices).\n */\n onSessionGeneratingChange?: (isGenerating: boolean) => void\n\n /**\n * Callback when a custom event is received from a server-side tool.\n * Custom events are emitted by tools using `context.emitCustomEvent()` during execution.\n *\n * @param eventType - The name of the custom event\n * @param data - The event payload data\n * @param context - Additional context including the toolCallId that emitted the event\n */\n onCustomEvent?: (\n eventType: string,\n data: unknown,\n context: { toolCallId?: string },\n ) => void\n\n /**\n * Client-side tools with execution logic\n * When provided, tools with execute functions will be called automatically\n */\n tools?: TTools\n\n /**\n * Devtools hook metadata for this client instance.\n */\n devtools?: Partial<AIDevtoolsClientMetadata>\n\n /**\n * Factory that constructs the devtools bridge. Default is a no-op\n * factory, which keeps `@tanstack/ai-client/devtools` (the heavy\n * bridge implementation) out of the main entry's bundle. Frameworks\n * that need live devtools should pass the real factory from\n * `@tanstack/ai-client/devtools`.\n */\n devtoolsBridgeFactory?: ChatDevtoolsBridgeFactory\n\n /**\n * Stream processing options (optional)\n * Configure chunking strategy\n */\n streamProcessor?: {\n /**\n * Strategy for when to emit text updates\n * Defaults to ImmediateStrategy (every chunk)\n */\n chunkStrategy?: ChunkStrategy\n }\n}\n\n/**\n * Options for `ChatClient`. Exactly one of `connection` or `fetcher` must be\n * provided — the type-level XOR is enforced via `ChatTransport`.\n */\nexport type ChatClientOptions<\n TTools extends ReadonlyArray<AnyClientTool> = any,\n TContext = InferredClientContext<TTools>,\n> = DistributedOmit<ChatClientBaseOptions<TTools, TContext>, 'context'> &\n ClientContextOptionFromTools<TTools, TContext> &\n ChatTransport\n\nexport interface ChatRequestBody {\n messages: Array<ModelMessage>\n data?: Record<string, any>\n}\n\n/**\n * Create a typed array of client tools with proper type inference.\n * This eliminates the need for `as const` when defining tool arrays.\n *\n * @example\n * ```ts\n * const tools = clientTools(\n * myTool1.client(() => result1),\n * myTool2.client(() => result2),\n * )\n *\n * // tools is now properly typed as a tuple with literal tool names\n * // This enables type narrowing when checking part.name === 'toolName'\n * ```\n */\nexport function clientTools<const T extends Array<AnyClientTool>>(\n ...tools: T\n): T {\n return tools\n}\n\n/**\n * Helper to create typed chat client options\n * Use this to get proper type inference for messages\n *\n * @example\n * ```ts\n * const tools = clientTools(myTool1, myTool2)\n *\n * const chatOptions = createChatClientOptions({\n * connection: fetchServerSentEvents('/api/chat'),\n * tools,\n * })\n *\n * type MyMessages = InferChatMessages<typeof chatOptions>\n * ```\n */\nexport function createChatClientOptions<\n const TTools extends ReadonlyArray<AnyClientTool>,\n TContext = InferredClientContext<TTools>,\n>(\n options: ChatClientOptions<TTools, TContext>,\n): ChatClientOptions<TTools, TContext> {\n return options\n}\n\n/**\n * Extract the message type from chat options\n *\n * @example\n * ```ts\n * const chatOptions = createChatClientOptions({\n * connection: fetchServerSentEvents('/api/chat'),\n * tools: [myTool1, myTool2],\n * })\n *\n * type MyMessages = InferChatMessages<typeof chatOptions>\n * // MyMessages is now Array<UIMessage<[typeof myTool1, typeof myTool2]>>\n * ```\n */\nexport type InferChatMessages<T> =\n T extends ChatClientOptions<infer TTools, any>\n ? Array<UIMessage<TTools>>\n : never\n"],"names":[],"mappings":"AA8iBO,SAAS,eACX,OACA;AACH,SAAO;AACT;AAkBO,SAAS,wBAId,SACqC;AACrC,SAAO;AACT;"}
@@ -1,110 +0,0 @@
1
- import { ConnectConnectionAdapter } from './connection-adapters.js';
2
- import { GenerationClientState, GenerationFetcher, VideoGenerateInput, VideoGenerateResult, VideoGenerationClientOptions, VideoStatusInfo } from './generation-types.js';
3
- /**
4
- * A specialized client for job-based video generation.
5
- *
6
- * Video generation is asynchronous: a job is created, then polled for status
7
- * until completion. This client handles the full lifecycle.
8
- *
9
- * Supports two transport modes:
10
- * - **ConnectConnectionAdapter** — Server handles the polling loop internally and
11
- * streams status updates via CUSTOM events.
12
- * - **Fetcher** — Direct async function that returns a completed
13
- * `VideoGenerateResult`.
14
- *
15
- * @example
16
- * ```typescript
17
- * // With streaming connection adapter (server-driven polling)
18
- * const client = new VideoGenerationClient({
19
- * connection: fetchServerSentEvents('/api/generate/video'),
20
- * onResultChange: setResult,
21
- * onVideoStatusChange: setVideoStatus,
22
- * })
23
- *
24
- * // With fetcher (direct result)
25
- * const client = new VideoGenerationClient({
26
- * fetcher: async (input) => {
27
- * const res = await fetch('/api/video/generate', {
28
- * method: 'POST',
29
- * body: JSON.stringify(input),
30
- * })
31
- * return res.json() // { jobId, status: 'completed', url, expiresAt }
32
- * },
33
- * })
34
- *
35
- * await client.generate({ prompt: 'A flying car over a city' })
36
- * ```
37
- */
38
- export declare class VideoGenerationClient<TOutput = VideoGenerateResult> {
39
- private readonly connection;
40
- private readonly fetcher;
41
- private readonly uniqueId;
42
- private readonly devtoolsMetadata;
43
- private readonly devtoolsBridge;
44
- private readonly threadId;
45
- private body;
46
- private result;
47
- private input;
48
- private progress;
49
- private jobId;
50
- private videoStatus;
51
- private isLoading;
52
- private error;
53
- private status;
54
- private abortController;
55
- private readonly callbacksRef;
56
- private devtoolsMounted;
57
- constructor(options: VideoGenerationClientOptions<TOutput> & ({
58
- connection: ConnectConnectionAdapter;
59
- fetcher?: never;
60
- } | {
61
- fetcher: GenerationFetcher<VideoGenerateInput, VideoGenerateResult>;
62
- connection?: never;
63
- }));
64
- private buildDevtoolsBridgeOptions;
65
- mountDevtools(): void;
66
- /**
67
- * Trigger video generation.
68
- * Only one generation can be in-flight at a time.
69
- */
70
- generate(input: VideoGenerateInput): Promise<void>;
71
- /**
72
- * Direct fetcher mode: call fetcher and set result.
73
- */
74
- private generateWithFetcher;
75
- /**
76
- * Process a stream of AG-UI events from the streaming connection adapter.
77
- * The server handles the polling loop and streams status updates.
78
- */
79
- private processStream;
80
- /**
81
- * Abort any in-flight generation or polling.
82
- */
83
- stop(): void;
84
- /**
85
- * Clear all state and return to idle.
86
- */
87
- reset(): void;
88
- /**
89
- * Update options without recreating the client.
90
- */
91
- updateOptions(options: Partial<Pick<VideoGenerationClientOptions<TOutput>, 'body' | 'onResult' | 'onError' | 'onProgress' | 'onChunk' | 'onJobCreated' | 'onStatusUpdate'>>): void;
92
- dispose(): void;
93
- getResult(): TOutput | null;
94
- getJobId(): string | null;
95
- getVideoStatus(): VideoStatusInfo | null;
96
- getIsLoading(): boolean;
97
- getError(): Error | undefined;
98
- getStatus(): GenerationClientState;
99
- private setResult;
100
- private setJobId;
101
- private setVideoStatus;
102
- private setIsLoading;
103
- private setError;
104
- private setStatus;
105
- private setProgress;
106
- private createCompletedVideoStatus;
107
- private createDevtoolsMetadata;
108
- private generateUniqueId;
109
- private createRunContext;
110
- }