@tanstack/ai-client 0.23.2 → 0.24.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.
- package/README.md +10 -1
- package/dist/esm/chat-client.d.ts +6 -8
- package/dist/esm/chat-client.js +32 -18
- package/dist/esm/chat-client.js.map +1 -1
- package/dist/esm/connection-adapters.d.ts +49 -0
- package/dist/esm/connection-adapters.js +266 -26
- package/dist/esm/connection-adapters.js.map +1 -1
- package/dist/esm/devtools.d.ts +0 -1
- package/dist/esm/devtools.js +11 -14
- package/dist/esm/devtools.js.map +1 -1
- package/dist/esm/generation-client.d.ts +5 -11
- package/dist/esm/generation-client.js +18 -6
- package/dist/esm/generation-client.js.map +1 -1
- package/dist/esm/generation-types.d.ts +15 -45
- package/dist/esm/generation-types.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/types.d.ts +27 -36
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/video-generation-client.d.ts +5 -11
- package/dist/esm/video-generation-client.js +18 -6
- package/dist/esm/video-generation-client.js.map +1 -1
- package/package.json +5 -5
- package/src/chat-client.ts +52 -37
- package/src/connection-adapters.ts +491 -45
- package/src/devtools.ts +6 -22
- package/src/generation-client.ts +36 -24
- package/src/generation-types.ts +15 -47
- package/src/index.ts +3 -0
- package/src/types.ts +34 -39
- package/src/video-generation-client.ts +33 -20
package/README.md
CHANGED
|
@@ -36,6 +36,14 @@
|
|
|
36
36
|
</a>
|
|
37
37
|
</div>
|
|
38
38
|
|
|
39
|
+
<br />
|
|
40
|
+
|
|
41
|
+
<div align="center">
|
|
42
|
+
<a href="https://tanstack.com/blog/tanstack-open-source-awards-2026">
|
|
43
|
+
<img src="https://raw.githubusercontent.com/TanStack/ai/16826d81cade868956df240d6239a671e689193c/media/js-open-source-award-2026-ai-project-of-the-year.svg" alt="Winner of the 2026 JavaScript Open Source Award for AI Project of the Year" width="250" />
|
|
44
|
+
</a>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
39
47
|
# TanStack AI
|
|
40
48
|
|
|
41
49
|
Type-safe, provider-agnostic TypeScript SDK for building streaming chat,
|
|
@@ -191,7 +199,7 @@ Learn more in the
|
|
|
191
199
|
build low-latency realtime voice experiences.
|
|
192
200
|
- [Code Mode](https://tanstack.com/ai/latest/docs/code-mode/code-mode) - let
|
|
193
201
|
models write and execute TypeScript inside a secure isolate.
|
|
194
|
-
- [Code Mode with
|
|
202
|
+
- [Code Mode with Snippets](https://tanstack.com/ai/latest/docs/code-mode/code-mode-with-snippets) -
|
|
195
203
|
give Code Mode reusable runtime capabilities.
|
|
196
204
|
|
|
197
205
|
## Providers
|
|
@@ -208,6 +216,7 @@ Official adapters include:
|
|
|
208
216
|
| [`@tanstack/ai-grok`](https://tanstack.com/ai/latest/docs/adapters/grok) | xAI Grok chat, images, and realtime |
|
|
209
217
|
| [`@tanstack/ai-groq`](https://tanstack.com/ai/latest/docs/adapters/groq) | Groq low-latency inference |
|
|
210
218
|
| [`@tanstack/ai-elevenlabs`](https://tanstack.com/ai/latest/docs/adapters/elevenlabs) | ElevenLabs realtime voice, speech, transcription, music, and sound effects |
|
|
219
|
+
| [`@tanstack/ai-byteplus`](https://tanstack.com/ai/latest/docs/adapters/byteplus) | BytePlus Seed chat, Seedance video, Seedream image, and Seed Speech TTS/ASR |
|
|
211
220
|
| [`@tanstack/ai-fal`](https://tanstack.com/ai/latest/docs/adapters/fal) | fal.ai image, video, audio, speech, and transcription models |
|
|
212
221
|
|
|
213
222
|
The adapter system is tree-shakeable by activity. Import `openaiText` for chat,
|
|
@@ -46,8 +46,8 @@ export declare function normalizeQueueOption(option: QueueOption | undefined): N
|
|
|
46
46
|
export declare class ChatClient<TTools extends ReadonlyArray<AnyClientTool> = any, TContext = unknown> {
|
|
47
47
|
private readonly processor;
|
|
48
48
|
private connection;
|
|
49
|
-
private
|
|
50
|
-
private
|
|
49
|
+
private uniqueId;
|
|
50
|
+
private threadId;
|
|
51
51
|
private readonly persistor?;
|
|
52
52
|
private readonly clearedStreamTracker;
|
|
53
53
|
private currentRunId;
|
|
@@ -190,6 +190,7 @@ export declare class ChatClient<TTools extends ReadonlyArray<AnyClientTool> = an
|
|
|
190
190
|
*/
|
|
191
191
|
private hydrateFromServer;
|
|
192
192
|
mountDevtools(): void;
|
|
193
|
+
private ensureThreadId;
|
|
193
194
|
/**
|
|
194
195
|
* Drain a runId-less RUN_ERROR that belongs to a cleared run the client is
|
|
195
196
|
* still tracking. The persistor owns the cleared-run bookkeeping; the client
|
|
@@ -352,12 +353,9 @@ export declare class ChatClient<TTools extends ReadonlyArray<AnyClientTool> = an
|
|
|
352
353
|
* ```
|
|
353
354
|
*/
|
|
354
355
|
sendMessage(content: string | MultimodalContent, body?: Record<string, any>, sendOptions?: SendMessageOptions): Promise<void>;
|
|
355
|
-
/**
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
* continued do not block a later turn once the resume stream has cleared
|
|
359
|
-
* resume state.
|
|
360
|
-
*/
|
|
356
|
+
/** True while interrupt descriptors still own continuation. */
|
|
357
|
+
private hasPendingInterrupts;
|
|
358
|
+
/** True while an interrupt batch owns the next user turn. */
|
|
361
359
|
private hasBlockingInterrupts;
|
|
362
360
|
/** True while a stream is active, a send is claiming the client, or the queue is draining. */
|
|
363
361
|
private isSendBusy;
|
package/dist/esm/chat-client.js
CHANGED
|
@@ -197,13 +197,15 @@ var ChatClient = class {
|
|
|
197
197
|
devtoolsMounted = false;
|
|
198
198
|
callbacksRef;
|
|
199
199
|
constructor(options) {
|
|
200
|
-
this.threadId = options.threadId ||
|
|
201
|
-
this.uniqueId =
|
|
200
|
+
this.threadId = options.threadId || "";
|
|
201
|
+
this.uniqueId = this.threadId;
|
|
202
202
|
let cachesMessages = true;
|
|
203
|
-
if (options.persistence === true)
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
203
|
+
if (options.persistence === true) {
|
|
204
|
+
if (!options.threadId) throw new Error("[TanStack AI] persistence needs a stable `threadId` to key on. Pass a threadId from your app (for example support-42).");
|
|
205
|
+
cachesMessages = false;
|
|
206
|
+
} else if (options.persistence) {
|
|
207
|
+
if (!options.threadId) throw new Error("[TanStack AI] persistence needs a stable `threadId` to key on. Pass a threadId from your app (for example support-42).");
|
|
208
|
+
this.persistor = new ChatPersistor(options.persistence, options.threadId, (messages) => this.processor.setMessages(messages), (snapshot) => this.applyPersistedResume(snapshot));
|
|
207
209
|
}
|
|
208
210
|
this.bodyOption = options.body || {};
|
|
209
211
|
this.forwardedPropsOption = options.forwardedProps || {};
|
|
@@ -367,6 +369,7 @@ var ChatClient = class {
|
|
|
367
369
|
*/
|
|
368
370
|
attach() {
|
|
369
371
|
if (this.disposed || this.tailing) return;
|
|
372
|
+
this.ensureThreadId();
|
|
370
373
|
this.tailing = true;
|
|
371
374
|
if (this.rejoinRunId) this.maybeRejoinInFlight(this.rejoinRunId);
|
|
372
375
|
if (!this.cachesMessages && this.connection.hydrate) this.hydrateFromServer();
|
|
@@ -474,10 +477,16 @@ var ChatClient = class {
|
|
|
474
477
|
})();
|
|
475
478
|
}
|
|
476
479
|
mountDevtools() {
|
|
480
|
+
this.ensureThreadId();
|
|
477
481
|
if (this.devtoolsMounted) return;
|
|
478
482
|
this.devtoolsMounted = true;
|
|
479
483
|
this.devtoolsBridge.mountWithTools(this.processor.getMessages().length);
|
|
480
484
|
}
|
|
485
|
+
ensureThreadId() {
|
|
486
|
+
if (!this.threadId) this.threadId = this.generateUniqueId("thread");
|
|
487
|
+
this.uniqueId = this.threadId;
|
|
488
|
+
return this.threadId;
|
|
489
|
+
}
|
|
481
490
|
/**
|
|
482
491
|
* Drain a runId-less RUN_ERROR that belongs to a cleared run the client is
|
|
483
492
|
* still tracking. The persistor owns the cleared-run bookkeeping; the client
|
|
@@ -732,10 +741,17 @@ var ChatClient = class {
|
|
|
732
741
|
this.events.errorChanged(error?.message || null);
|
|
733
742
|
}
|
|
734
743
|
buildDevtoolsBridgeOptions(devtools) {
|
|
744
|
+
const client = this;
|
|
735
745
|
return {
|
|
736
|
-
hookId
|
|
737
|
-
|
|
738
|
-
|
|
746
|
+
get hookId() {
|
|
747
|
+
return client.uniqueId;
|
|
748
|
+
},
|
|
749
|
+
get clientId() {
|
|
750
|
+
return client.uniqueId;
|
|
751
|
+
},
|
|
752
|
+
get threadId() {
|
|
753
|
+
return client.threadId;
|
|
754
|
+
},
|
|
739
755
|
metadata: {
|
|
740
756
|
hookName: devtools?.hookName ?? "useChat",
|
|
741
757
|
outputKind: devtools?.outputKind ?? "chat",
|
|
@@ -1038,16 +1054,13 @@ var ChatClient = class {
|
|
|
1038
1054
|
this.sendInFlight = false;
|
|
1039
1055
|
}
|
|
1040
1056
|
}
|
|
1041
|
-
/**
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
*/
|
|
1057
|
+
/** True while interrupt descriptors still own continuation. */
|
|
1058
|
+
hasPendingInterrupts() {
|
|
1059
|
+
return this.interruptManager.getDescriptors().length > 0;
|
|
1060
|
+
}
|
|
1061
|
+
/** True while an interrupt batch owns the next user turn. */
|
|
1047
1062
|
hasBlockingInterrupts() {
|
|
1048
|
-
|
|
1049
|
-
if (this.activeInterruptSubmission) return true;
|
|
1050
|
-
return this.interruptManager.getInterrupts().some((item) => item.status === "pending" || item.status === "validating" || item.status === "error" || item.status === "staged");
|
|
1063
|
+
return this.activeInterruptSubmission !== void 0 || this.hasPendingInterrupts();
|
|
1051
1064
|
}
|
|
1052
1065
|
/** True while a stream is active, a send is claiming the client, or the queue is draining. */
|
|
1053
1066
|
isSendBusy() {
|
|
@@ -1445,6 +1458,7 @@ var ChatClient = class {
|
|
|
1445
1458
|
* Check if we should continue the flow and do so if needed
|
|
1446
1459
|
*/
|
|
1447
1460
|
async checkForContinuation() {
|
|
1461
|
+
if (this.hasPendingInterrupts()) return;
|
|
1448
1462
|
if (this.continuationPending || this.isLoading) {
|
|
1449
1463
|
this.continuationSkipped = true;
|
|
1450
1464
|
return;
|