@tanstack/ai-react 0.18.1 → 0.19.0

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 (49) hide show
  1. package/README.md +15 -1
  2. package/dist/esm/index.d.ts +1 -1
  3. package/dist/esm/index.js +2 -23
  4. package/dist/esm/mcp-app-resource.js +45 -45
  5. package/dist/esm/mcp-app-resource.js.map +1 -1
  6. package/dist/esm/mcp-apps.js +1 -4
  7. package/dist/esm/types.d.ts +29 -3
  8. package/dist/esm/use-audio-recorder.js +41 -46
  9. package/dist/esm/use-audio-recorder.js.map +1 -1
  10. package/dist/esm/use-chat.js +330 -275
  11. package/dist/esm/use-chat.js.map +1 -1
  12. package/dist/esm/use-generate-audio.d.ts +50 -4
  13. package/dist/esm/use-generate-audio.js +47 -23
  14. package/dist/esm/use-generate-audio.js.map +1 -1
  15. package/dist/esm/use-generate-image.d.ts +50 -4
  16. package/dist/esm/use-generate-image.js +49 -23
  17. package/dist/esm/use-generate-image.js.map +1 -1
  18. package/dist/esm/use-generate-speech.d.ts +50 -4
  19. package/dist/esm/use-generate-speech.js +43 -23
  20. package/dist/esm/use-generate-speech.js.map +1 -1
  21. package/dist/esm/use-generate-video.d.ts +50 -4
  22. package/dist/esm/use-generate-video.js +141 -103
  23. package/dist/esm/use-generate-video.js.map +1 -1
  24. package/dist/esm/use-generation.d.ts +59 -6
  25. package/dist/esm/use-generation.js +113 -90
  26. package/dist/esm/use-generation.js.map +1 -1
  27. package/dist/esm/use-mcp-app-bridge.js +46 -23
  28. package/dist/esm/use-mcp-app-bridge.js.map +1 -1
  29. package/dist/esm/use-realtime-chat.js +185 -185
  30. package/dist/esm/use-realtime-chat.js.map +1 -1
  31. package/dist/esm/use-summarize.d.ts +50 -4
  32. package/dist/esm/use-summarize.js +46 -23
  33. package/dist/esm/use-summarize.js.map +1 -1
  34. package/dist/esm/use-transcription.d.ts +50 -4
  35. package/dist/esm/use-transcription.js +51 -20
  36. package/dist/esm/use-transcription.js.map +1 -1
  37. package/package.json +7 -7
  38. package/src/index.ts +10 -0
  39. package/src/types.ts +44 -0
  40. package/src/use-chat.ts +221 -35
  41. package/src/use-generate-audio.ts +64 -17
  42. package/src/use-generate-image.ts +64 -17
  43. package/src/use-generate-speech.ts +64 -17
  44. package/src/use-generate-video.ts +99 -18
  45. package/src/use-generation.ts +112 -18
  46. package/src/use-summarize.ts +64 -17
  47. package/src/use-transcription.ts +60 -18
  48. package/dist/esm/index.js.map +0 -1
  49. package/dist/esm/mcp-apps.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { StreamChunk, TranscriptionResult } from '@tanstack/ai';
2
- import { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher, InferGenerationOutputFromReturn, TranscriptionGenerateInput } from '@tanstack/ai-client';
2
+ import { AIDevtoolsDisplayOptions, ConnectConnectionAdapter, GenerationClientState, GenerationFetcher, GenerationPersistenceOptions, InferGenerationOutputFromReturn, TranscriptionGenerateInput } from '@tanstack/ai-client';
3
3
  /**
4
4
  * Options for the useTranscription hook.
5
5
  *
@@ -10,12 +10,51 @@ export interface UseTranscriptionOptions<TOutput = TranscriptionResult> {
10
10
  connection?: ConnectConnectionAdapter;
11
11
  /** Direct async function for transcription */
12
12
  fetcher?: GenerationFetcher<TranscriptionGenerateInput, TranscriptionResult>;
13
- /** Unique identifier for this generation instance */
13
+ /**
14
+ * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).
15
+ */
14
16
  id?: string;
15
17
  /** Additional body parameters to send with connect-based adapter requests */
16
18
  body?: Record<string, any>;
17
19
  /** Display options for TanStack AI Devtools. */
18
20
  devtools?: AIDevtoolsDisplayOptions;
21
+ /**
22
+ * How this generation persists across reloads.
23
+ * - Omit / `false`: ephemeral, in-memory only.
24
+ * - `true`: server-driven — on mount the client hydrates the last generation
25
+ * for its `threadId` from the server (needs a connection with a
26
+ * `hydrateGeneration` handler) and repaints it; it never auto-starts a run.
27
+ */
28
+ persistence?: boolean;
29
+ /**
30
+ * The **scope** this generation belongs to: a stable, app-chosen name for the
31
+ * slot successive runs fill — not a link to a chat conversation.
32
+ *
33
+ * The hook starts empty and produces many runs over its life; each gets its
34
+ * own `runId`, but all belong to one scope. Persistence keys on this, so
35
+ * derive it from your own domain and keep it identical across reloads (e.g.
36
+ * `` `video-${videoId}-start-frame` ``). It is also sent as the AG-UI thread
37
+ * id on the wire, which the protocol requires.
38
+ *
39
+ * **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.
42
+ */
43
+ threadId?: string;
44
+ /**
45
+ * Server-driven hydration handler for `persistence: true` when the
46
+ * connection doesn't carry one (e.g. alongside `fetcher`, or a `stream()` /
47
+ * `rpcStream()` adapter built without handlers) — typically a one-line
48
+ * server-function call. The connection's own handler takes precedence.
49
+ */
50
+ hydrateGeneration?: ConnectConnectionAdapter['hydrateGeneration'];
51
+ /**
52
+ * Re-attach handler that replays a run still generating to completion on
53
+ * mount, when the connection doesn't carry one. Without it, a restored
54
+ * `running` snapshot surfaces as an (interrupted) error. The connection's
55
+ * own handler takes precedence.
56
+ */
57
+ joinRun?: ConnectConnectionAdapter['joinRun'];
19
58
  /**
20
59
  * Callback when transcription is complete. Can optionally return a transformed value.
21
60
  *
@@ -51,6 +90,13 @@ export interface UseTranscriptionReturn<TOutput = TranscriptionResult> {
51
90
  stop: () => void;
52
91
  /** Clear result, error, and return to idle */
53
92
  reset: () => void;
93
+ /**
94
+ * The id of the generation job currently running, or `null` when nothing is in
95
+ * flight. Each call to `generate` is one job with its own id. Pass it to your
96
+ * own endpoint to cancel or poll the provider job — `stop()` only aborts the
97
+ * local stream, it does not stop work already running on the provider.
98
+ */
99
+ runId: string | null;
54
100
  }
55
101
  /**
56
102
  * React hook for transcribing audio to text using AI models.
@@ -86,6 +132,6 @@ export interface UseTranscriptionReturn<TOutput = TranscriptionResult> {
86
132
  * }
87
133
  * ```
88
134
  */
89
- export declare function useTranscription<TTransformed = void>(options: Omit<UseTranscriptionOptions, 'onResult'> & {
135
+ export declare function useTranscription<TTransformed = void>(options: Omit<UseTranscriptionOptions, 'onResult' | 'persistence' | 'threadId' | 'id'> & {
90
136
  onResult?: (result: TranscriptionResult) => TTransformed;
91
- }): UseTranscriptionReturn<InferGenerationOutputFromReturn<TranscriptionResult, TTransformed>>;
137
+ } & GenerationPersistenceOptions): UseTranscriptionReturn<InferGenerationOutputFromReturn<TranscriptionResult, TTransformed>>;
@@ -1,23 +1,54 @@
1
1
  import { useGeneration } from "./use-generation.js";
2
+ import { reconstructTranscriptionResult } from "@tanstack/ai-client";
3
+ //#region src/use-transcription.ts
4
+ /**
5
+ * React hook for transcribing audio to text using AI models.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { useTranscription } from '@tanstack/ai-react'
10
+ * import { fetchServerSentEvents } from '@tanstack/ai-client'
11
+ *
12
+ * function Transcriber() {
13
+ * const { generate, result, isLoading } = useTranscription({
14
+ * connection: fetchServerSentEvents('/api/transcribe'),
15
+ * })
16
+ *
17
+ * const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => {
18
+ * const file = e.target.files?.[0]
19
+ * if (file) {
20
+ * const reader = new FileReader()
21
+ * reader.onload = () => {
22
+ * generate({ audio: reader.result as string, language: 'en' })
23
+ * }
24
+ * reader.readAsDataURL(file)
25
+ * }
26
+ * }
27
+ *
28
+ * return (
29
+ * <div>
30
+ * <input type="file" accept="audio/*" onChange={handleFile} />
31
+ * {isLoading && <p>Transcribing...</p>}
32
+ * {result && <p>{result.text}</p>}
33
+ * </div>
34
+ * )
35
+ * }
36
+ * ```
37
+ */
2
38
  function useTranscription(options) {
3
- const devtools = {
4
- ...options.devtools,
5
- framework: "react",
6
- hookName: "useTranscription",
7
- outputKind: "text"
8
- };
9
- const { generate, result, isLoading, error, status, stop, reset } = useGeneration({ ...options, devtools });
10
- return {
11
- generate,
12
- result,
13
- isLoading,
14
- error,
15
- status,
16
- stop,
17
- reset
18
- };
39
+ const devtools = {
40
+ ...options.devtools,
41
+ framework: "react",
42
+ hookName: "useTranscription",
43
+ outputKind: "text"
44
+ };
45
+ return useGeneration({
46
+ ...options,
47
+ devtools,
48
+ reconstructResult: reconstructTranscriptionResult
49
+ });
19
50
  }
20
- export {
21
- useTranscription
22
- };
23
- //# sourceMappingURL=use-transcription.js.map
51
+ //#endregion
52
+ export { useTranscription };
53
+
54
+ //# sourceMappingURL=use-transcription.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-transcription.js","sources":["../../src/use-transcription.ts"],"sourcesContent":["import { useGeneration } from './use-generation'\nimport type { StreamChunk, TranscriptionResult } from '@tanstack/ai'\nimport type {\n AIDevtoolsDisplayOptions,\n ConnectConnectionAdapter,\n GenerationClientState,\n GenerationFetcher,\n InferGenerationOutputFromReturn,\n TranscriptionGenerateInput,\n} from '@tanstack/ai-client'\n\n/**\n * Options for the useTranscription hook.\n *\n * @template TOutput - The output type after optional transform (defaults to TranscriptionResult)\n */\nexport interface UseTranscriptionOptions<TOutput = TranscriptionResult> {\n /** Connect-based adapter for streaming transport (SSE, HTTP stream, custom) */\n connection?: ConnectConnectionAdapter\n /** Direct async function for transcription */\n fetcher?: GenerationFetcher<TranscriptionGenerateInput, TranscriptionResult>\n /** Unique identifier for this generation instance */\n id?: string\n /** Additional body parameters to send with connect-based adapter requests */\n body?: Record<string, any>\n /** Display options for TanStack AI Devtools. */\n devtools?: AIDevtoolsDisplayOptions\n /**\n * Callback when transcription is complete. Can optionally return a transformed value.\n *\n * - Return a non-null value to transform and store it as the result\n * - Return `null` to keep the previous result unchanged\n * - Return nothing (`void`) to store the raw result as-is\n */\n onResult?: (result: TranscriptionResult) => TOutput | null | void\n /** Callback when an error occurs */\n onError?: (error: Error) => void\n /** Callback when progress is reported (0-100) */\n onProgress?: (progress: number, message?: string) => void\n /** Callback for each stream chunk (connect-based adapter mode only) */\n onChunk?: (chunk: StreamChunk) => void\n}\n\n/**\n * Return type for the useTranscription hook.\n *\n * @template TOutput - The output type (after optional transform)\n */\nexport interface UseTranscriptionReturn<TOutput = TranscriptionResult> {\n /** Trigger transcription */\n generate: (input: TranscriptionGenerateInput) => Promise<void>\n /** The transcription result, or null */\n result: TOutput | null\n /** Whether transcription is in progress */\n isLoading: boolean\n /** Current error, if any */\n error: Error | undefined\n /** Current state of the generation */\n status: GenerationClientState\n /** Abort the current transcription */\n stop: () => void\n /** Clear result, error, and return to idle */\n reset: () => void\n}\n\n/**\n * React hook for transcribing audio to text using AI models.\n *\n * @example\n * ```tsx\n * import { useTranscription } from '@tanstack/ai-react'\n * import { fetchServerSentEvents } from '@tanstack/ai-client'\n *\n * function Transcriber() {\n * const { generate, result, isLoading } = useTranscription({\n * connection: fetchServerSentEvents('/api/transcribe'),\n * })\n *\n * const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => {\n * const file = e.target.files?.[0]\n * if (file) {\n * const reader = new FileReader()\n * reader.onload = () => {\n * generate({ audio: reader.result as string, language: 'en' })\n * }\n * reader.readAsDataURL(file)\n * }\n * }\n *\n * return (\n * <div>\n * <input type=\"file\" accept=\"audio/*\" onChange={handleFile} />\n * {isLoading && <p>Transcribing...</p>}\n * {result && <p>{result.text}</p>}\n * </div>\n * )\n * }\n * ```\n */\nexport function useTranscription<TTransformed = void>(\n options: Omit<UseTranscriptionOptions, 'onResult'> & {\n onResult?: (result: TranscriptionResult) => TTransformed\n },\n): UseTranscriptionReturn<\n InferGenerationOutputFromReturn<TranscriptionResult, TTransformed>\n> {\n const devtools = {\n ...options.devtools,\n framework: 'react',\n hookName: 'useTranscription',\n outputKind: 'text' as const,\n }\n const { generate, result, isLoading, error, status, stop, reset } =\n useGeneration<\n TranscriptionGenerateInput,\n TranscriptionResult,\n TTransformed\n >({ ...options, devtools })\n\n return {\n generate: generate as (input: TranscriptionGenerateInput) => Promise<void>,\n result,\n isLoading,\n error,\n status,\n stop,\n reset,\n }\n}\n"],"names":[],"mappings":";AAmGO,SAAS,iBACd,SAKA;AACA,QAAM,WAAW;AAAA,IACf,GAAG,QAAQ;AAAA,IACX,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY;AAAA,EAAA;AAEd,QAAM,EAAE,UAAU,QAAQ,WAAW,OAAO,QAAQ,MAAM,MAAA,IACxD,cAIE,EAAE,GAAG,SAAS,UAAU;AAE5B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;"}
1
+ {"version":3,"file":"use-transcription.js","names":[],"sources":["../../src/use-transcription.ts"],"sourcesContent":["import { useGeneration } from './use-generation'\nimport { reconstructTranscriptionResult } from '@tanstack/ai-client'\nimport type { StreamChunk, TranscriptionResult } from '@tanstack/ai'\nimport type {\n AIDevtoolsDisplayOptions,\n ConnectConnectionAdapter,\n GenerationClientState,\n GenerationFetcher,\n GenerationPersistenceOptions,\n InferGenerationOutputFromReturn,\n TranscriptionGenerateInput,\n} from '@tanstack/ai-client'\n\n/**\n * Options for the useTranscription hook.\n *\n * @template TOutput - The output type after optional transform (defaults to TranscriptionResult)\n */\nexport interface UseTranscriptionOptions<TOutput = TranscriptionResult> {\n /** Connect-based adapter for streaming transport (SSE, HTTP stream, custom) */\n connection?: ConnectConnectionAdapter\n /** Direct async function for transcription */\n fetcher?: GenerationFetcher<TranscriptionGenerateInput, TranscriptionResult>\n /**\n * @deprecated Prefer `threadId`. Only allowed when `threadId` is omitted (see `GenerationPersistenceOptions`).\n */\n id?: string\n /** Additional body parameters to send with connect-based adapter requests */\n body?: Record<string, any>\n /** Display options for TanStack AI Devtools. */\n devtools?: AIDevtoolsDisplayOptions\n /**\n * How this generation persists across reloads.\n * - Omit / `false`: ephemeral, in-memory only.\n * - `true`: server-driven — on mount the client hydrates the last generation\n * for its `threadId` from the server (needs a connection with a\n * `hydrateGeneration` handler) and repaints it; it never auto-starts a run.\n */\n persistence?: boolean\n /**\n * The **scope** this generation belongs to: a stable, app-chosen name for the\n * slot successive runs fill — not a link to a chat conversation.\n *\n * The hook starts empty and produces many runs over its life; each gets its\n * own `runId`, but all belong to one scope. Persistence keys on this, so\n * derive it from your own domain and keep it identical across reloads (e.g.\n * `` `video-${videoId}-start-frame` ``). It is also sent as the AG-UI thread\n * id on the wire, which the protocol requires.\n *\n * **Required whenever `persistence` is set** — an app that cannot name the\n * scope has nothing to restore to. Optional for ephemeral generations, where\n * it falls back to `id` purely to satisfy the wire.\n */\n threadId?: string\n /**\n * Server-driven hydration handler for `persistence: true` when the\n * connection doesn't carry one (e.g. alongside `fetcher`, or a `stream()` /\n * `rpcStream()` adapter built without handlers) — typically a one-line\n * server-function call. The connection's own handler takes precedence.\n */\n hydrateGeneration?: ConnectConnectionAdapter['hydrateGeneration']\n /**\n * Re-attach handler that replays a run still generating to completion on\n * mount, when the connection doesn't carry one. Without it, a restored\n * `running` snapshot surfaces as an (interrupted) error. The connection's\n * own handler takes precedence.\n */\n joinRun?: ConnectConnectionAdapter['joinRun']\n /**\n * Callback when transcription is complete. Can optionally return a transformed value.\n *\n * - Return a non-null value to transform and store it as the result\n * - Return `null` to keep the previous result unchanged\n * - Return nothing (`void`) to store the raw result as-is\n */\n onResult?: (result: TranscriptionResult) => TOutput | null | void\n /** Callback when an error occurs */\n onError?: (error: Error) => void\n /** Callback when progress is reported (0-100) */\n onProgress?: (progress: number, message?: string) => void\n /** Callback for each stream chunk (connect-based adapter mode only) */\n onChunk?: (chunk: StreamChunk) => void\n}\n\n/**\n * Return type for the useTranscription hook.\n *\n * @template TOutput - The output type (after optional transform)\n */\nexport interface UseTranscriptionReturn<TOutput = TranscriptionResult> {\n /** Trigger transcription */\n generate: (input: TranscriptionGenerateInput) => Promise<void>\n /** The transcription result, or null */\n result: TOutput | null\n /** Whether transcription is in progress */\n isLoading: boolean\n /** Current error, if any */\n error: Error | undefined\n /** Current state of the generation */\n status: GenerationClientState\n /** Abort the current transcription */\n stop: () => void\n /** Clear result, error, and return to idle */\n reset: () => void\n /**\n * The id of the generation job currently running, or `null` when nothing is in\n * flight. Each call to `generate` is one job with its own id. Pass it to your\n * own endpoint to cancel or poll the provider job — `stop()` only aborts the\n * local stream, it does not stop work already running on the provider.\n */\n runId: string | null\n}\n\n/**\n * React hook for transcribing audio to text using AI models.\n *\n * @example\n * ```tsx\n * import { useTranscription } from '@tanstack/ai-react'\n * import { fetchServerSentEvents } from '@tanstack/ai-client'\n *\n * function Transcriber() {\n * const { generate, result, isLoading } = useTranscription({\n * connection: fetchServerSentEvents('/api/transcribe'),\n * })\n *\n * const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => {\n * const file = e.target.files?.[0]\n * if (file) {\n * const reader = new FileReader()\n * reader.onload = () => {\n * generate({ audio: reader.result as string, language: 'en' })\n * }\n * reader.readAsDataURL(file)\n * }\n * }\n *\n * return (\n * <div>\n * <input type=\"file\" accept=\"audio/*\" onChange={handleFile} />\n * {isLoading && <p>Transcribing...</p>}\n * {result && <p>{result.text}</p>}\n * </div>\n * )\n * }\n * ```\n */\nexport function useTranscription<TTransformed = void>(\n options: Omit<\n UseTranscriptionOptions,\n 'onResult' | 'persistence' | 'threadId' | 'id'\n > & {\n onResult?: (result: TranscriptionResult) => TTransformed\n } & GenerationPersistenceOptions,\n): UseTranscriptionReturn<\n InferGenerationOutputFromReturn<TranscriptionResult, TTransformed>\n> {\n const devtools = {\n ...options.devtools,\n framework: 'react',\n hookName: 'useTranscription',\n outputKind: 'text' as const,\n }\n const generation = useGeneration<\n TranscriptionGenerateInput,\n TranscriptionResult,\n TTransformed\n >({ ...options, devtools, reconstructResult: reconstructTranscriptionResult })\n\n return generation\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmJA,SAAgB,iBACd,SAQA;CACA,MAAM,WAAW;EACf,GAAG,QAAQ;EACX,WAAW;EACX,UAAU;EACV,YAAY;CACd;CAOA,OANmB,cAIjB;EAAE,GAAG;EAAS;EAAU,mBAAmB;CAA+B,CAErE;AACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai-react",
3
- "version": "0.18.1",
3
+ "version": "0.19.0",
4
4
  "description": "React hooks for TanStack AI streaming chat, realtime voice, structured outputs, and media generation.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -49,13 +49,13 @@
49
49
  "media-generation"
50
50
  ],
51
51
  "dependencies": {
52
- "@tanstack/ai-client": "0.22.1"
52
+ "@tanstack/ai-client": "0.23.0"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@mcp-ui/client": "^7",
56
56
  "@types/react": ">=18.0.0",
57
57
  "react": ">=18.0.0",
58
- "@tanstack/ai": "^0.42.0"
58
+ "@tanstack/ai": "^0.43.0"
59
59
  },
60
60
  "peerDependenciesMeta": {
61
61
  "@mcp-ui/client": {
@@ -70,13 +70,13 @@
70
70
  "@vitest/coverage-v8": "4.0.14",
71
71
  "jsdom": "^27.2.0",
72
72
  "react": "^19.2.3",
73
- "vite": "^7.3.3",
74
- "@tanstack/ai": "0.42.0"
73
+ "vite": "^8.1.4",
74
+ "@tanstack/ai": "0.43.0"
75
75
  },
76
76
  "scripts": {
77
77
  "clean": "premove ./build ./dist",
78
- "lint:fix": "eslint ./src --fix",
79
- "test:eslint": "eslint ./src",
78
+ "lint:fix": "oxlint src --type-aware --fix",
79
+ "test:oxlint": "oxlint src --type-aware",
80
80
  "test:lib": "vitest run",
81
81
  "test:lib:dev": "pnpm test:lib --watch",
82
82
  "test:types": "tsc",
package/src/index.ts CHANGED
@@ -69,6 +69,16 @@ export type {
69
69
  // Re-export from ai-client for convenience
70
70
  export {
71
71
  fetchServerSentEvents,
72
+ localStoragePersistence,
73
+ sessionStoragePersistence,
74
+ indexedDBPersistence,
75
+ StorageUnavailableError,
76
+ type ChatClientPersistence,
77
+ type ChatPersistedState,
78
+ type ChatPersistenceOption,
79
+ type ChatStorageAdapter,
80
+ type WebStoragePersistenceOptions,
81
+ type IndexedDBPersistenceOptions,
72
82
  fetchHttpStream,
73
83
  xhrServerSentEvents,
74
84
  xhrHttpStream,
package/src/types.ts CHANGED
@@ -2,13 +2,18 @@ import type {
2
2
  AnyClientTool,
3
3
  InferSchemaType,
4
4
  ModelMessage,
5
+ RunAgentResumeItem,
5
6
  SchemaInput,
6
7
  } from '@tanstack/ai/client'
7
8
  import type {
8
9
  AIDevtoolsDisplayOptions,
10
+ BoundInterrupts,
9
11
  ChatClientOptions,
10
12
  ChatClientState,
13
+ ChatInterrupt,
14
+ ChatInterruptState,
11
15
  ChatRequestBody,
16
+ ChatResumeState,
12
17
  ClientContextOptionFromTools,
13
18
  ConnectionStatus,
14
19
  DistributedOmit,
@@ -88,8 +93,14 @@ export type UseChatOptions<
88
93
  | 'onConnectionStatusChange'
89
94
  | 'onSessionGeneratingChange'
90
95
  | 'onQueueChange'
96
+ | 'onResumeStateChange'
97
+ | 'onRunIdChange'
91
98
  | 'context'
92
99
  | 'devtools'
100
+ // `id` is not a hook option: the hook's identity is its `threadId`, which is
101
+ // also the persistence key. Persist across reloads by passing a stable
102
+ // `threadId`; there is no separate id to set.
103
+ | 'id'
93
104
  > & {
94
105
  /** Display options for TanStack AI Devtools. */
95
106
  devtools?: AIDevtoolsDisplayOptions
@@ -195,6 +206,39 @@ interface BaseUseChatReturn<
195
206
  approved: boolean
196
207
  }) => Promise<void>
197
208
 
209
+ /**
210
+ * The id of the run this client has in flight — one it started or rejoined —
211
+ * or `null` when there is none (including while a run sits paused on an
212
+ * interrupt, waiting on approval).
213
+ *
214
+ * A run is one turn of the conversation, so this changes from turn to turn. A
215
+ * whole tool loop stays inside one run, while resuming after an interrupt
216
+ * continues the turn under a new id — so one user message can produce several
217
+ * run ids. Use it to talk to your own server about that run (cancel it, poll
218
+ * it, correlate a log line).
219
+ */
220
+ runId: string | null
221
+ interrupts: BoundInterrupts<TTools>
222
+ /** @deprecated Use `interrupts`. */
223
+ pendingInterrupts: BoundInterrupts<TTools>
224
+ interruptErrors: ChatInterruptState<TTools>['interruptErrors']
225
+ resuming: boolean
226
+ resolveInterrupts: {
227
+ (approved: boolean): void
228
+ (resolver: (interrupt: ChatInterrupt<TTools>) => undefined): void
229
+ }
230
+ cancelInterrupts: () => void
231
+ retryInterrupts: () => void
232
+ resumeInterruptsUnsafe: (
233
+ resume: Array<RunAgentResumeItem>,
234
+ state?: ChatResumeState,
235
+ ) => Promise<boolean>
236
+ /** @deprecated Use bound interrupt methods or `resumeInterruptsUnsafe`. */
237
+ resumeInterrupts: (
238
+ resume: Array<RunAgentResumeItem>,
239
+ state?: ChatResumeState,
240
+ ) => Promise<boolean>
241
+
198
242
  /**
199
243
  * Reload the last assistant message
200
244
  */