@tanstack/ai-client 0.34.0 → 0.35.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.
- package/dist/esm/chat-client.d.ts +15 -0
- package/dist/esm/chat-client.js +39 -2
- package/dist/esm/chat-client.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/web-mcp-tools.d.ts +60 -0
- package/dist/esm/web-mcp-tools.js +92 -1
- package/dist/esm/web-mcp-tools.js.map +1 -1
- package/package.json +3 -3
- package/src/chat-client.ts +59 -2
- package/src/index.ts +8 -1
- package/src/web-mcp-tools.ts +181 -0
|
@@ -143,6 +143,8 @@ export declare class ChatClient<TTools extends ReadonlyArray<AnyClientTool> = an
|
|
|
143
143
|
private readonly activeRunIds;
|
|
144
144
|
/** Latched by `dispose()`; stops any late async callback starting new work. */
|
|
145
145
|
private disposed;
|
|
146
|
+
/** The error a failed mount hydration set, cleared by the next successful one. */
|
|
147
|
+
private hydrationError;
|
|
146
148
|
/** Whether a view is currently watching. See `attach` / `detach`. */
|
|
147
149
|
private tailing;
|
|
148
150
|
/** Constructor inputs `attach()` needs on every re-attach, not just the first. */
|
|
@@ -219,6 +221,19 @@ export declare class ChatClient<TTools extends ReadonlyArray<AnyClientTool> = an
|
|
|
219
221
|
* send that starts first owns the client (hydration then backs off).
|
|
220
222
|
*/
|
|
221
223
|
private hydrateFromServer;
|
|
224
|
+
/**
|
|
225
|
+
* Surface a mount-hydration failure (`persistence: true`) on the observable
|
|
226
|
+
* fields, mirroring `GenerationClient.failHydration`, so "this thread failed
|
|
227
|
+
* to load" is distinguishable from "this thread has no messages" and the app
|
|
228
|
+
* can show an error / offer a retry. A genuine miss — the server having no
|
|
229
|
+
* record for a fresh thread — resolves normally and never reaches here; only a
|
|
230
|
+
* thrown transport / authorize-gate error does.
|
|
231
|
+
*
|
|
232
|
+
* Skipped when the view unmounted (`!tailing`) or a `sendMessage` took
|
|
233
|
+
* ownership while the hydrate GET was in flight, so a live run's state always
|
|
234
|
+
* wins over a stale mount-time failure — same guard as the success path above.
|
|
235
|
+
*/
|
|
236
|
+
private failHydration;
|
|
222
237
|
mountDevtools(): void;
|
|
223
238
|
private ensureThreadId;
|
|
224
239
|
/**
|
package/dist/esm/chat-client.js
CHANGED
|
@@ -138,10 +138,16 @@ var REJOIN_CONNECT_DEADLINE_MS = 2e3;
|
|
|
138
138
|
var REJOIN_REBUILD_TRIGGERS = /* @__PURE__ */ new Set([
|
|
139
139
|
"TEXT_MESSAGE_START",
|
|
140
140
|
"TEXT_MESSAGE_CONTENT",
|
|
141
|
+
"REASONING_MESSAGE_CONTENT",
|
|
141
142
|
"TOOL_CALL_START",
|
|
142
143
|
"MESSAGES_SNAPSHOT",
|
|
143
144
|
"SUBAGENT_STARTED"
|
|
144
145
|
]);
|
|
146
|
+
function rebuildsAssistantMessage(chunk) {
|
|
147
|
+
if (chunk.type === "REASONING_ENCRYPTED_VALUE") return chunk.subtype === "message" && typeof chunk.encryptedValue === "string" && chunk.encryptedValue.length > 0;
|
|
148
|
+
if (chunk.type === "STEP_FINISHED") return "signature" in chunk && Boolean(chunk.signature);
|
|
149
|
+
return REJOIN_REBUILD_TRIGGERS.has(chunk.type);
|
|
150
|
+
}
|
|
145
151
|
/** Every subagent card in the messages, nested cards included. */
|
|
146
152
|
function collectSubagentParts(messages) {
|
|
147
153
|
const cards = [];
|
|
@@ -258,6 +264,8 @@ var ChatClient = class {
|
|
|
258
264
|
activeRunIds = /* @__PURE__ */ new Set();
|
|
259
265
|
/** Latched by `dispose()`; stops any late async callback starting new work. */
|
|
260
266
|
disposed = false;
|
|
267
|
+
/** The error a failed mount hydration set, cleared by the next successful one. */
|
|
268
|
+
hydrationError;
|
|
261
269
|
/** Whether a view is currently watching. See `attach` / `detach`. */
|
|
262
270
|
tailing = false;
|
|
263
271
|
/** Constructor inputs `attach()` needs on every re-attach, not just the first. */
|
|
@@ -556,12 +564,18 @@ var ChatClient = class {
|
|
|
556
564
|
const generation = this.historyGeneration;
|
|
557
565
|
try {
|
|
558
566
|
result = await hydrate(this.threadId, hydrateOptions);
|
|
559
|
-
} catch {
|
|
567
|
+
} catch (cause) {
|
|
568
|
+
if (generation === this.historyGeneration) this.failHydration(cause);
|
|
560
569
|
return;
|
|
561
570
|
}
|
|
562
571
|
if (generation !== this.historyGeneration) return;
|
|
563
572
|
if (this.disposed || !this.tailing) return;
|
|
564
573
|
if (this.isLoading || this.abortController) return;
|
|
574
|
+
if (this.hydrationError && this.error === this.hydrationError) {
|
|
575
|
+
this.setError(void 0);
|
|
576
|
+
this.setStatus("ready");
|
|
577
|
+
}
|
|
578
|
+
this.hydrationError = void 0;
|
|
565
579
|
this.applyHydrationPage(result.page);
|
|
566
580
|
if (result.messages.length > 0) {
|
|
567
581
|
const windowMessages = normalizeMessagesDates(result.messages);
|
|
@@ -578,6 +592,29 @@ var ChatClient = class {
|
|
|
578
592
|
else if (result.activeRun?.runId) this.maybeRejoinInFlight(result.activeRun.runId);
|
|
579
593
|
})();
|
|
580
594
|
}
|
|
595
|
+
/**
|
|
596
|
+
* Surface a mount-hydration failure (`persistence: true`) on the observable
|
|
597
|
+
* fields, mirroring `GenerationClient.failHydration`, so "this thread failed
|
|
598
|
+
* to load" is distinguishable from "this thread has no messages" and the app
|
|
599
|
+
* can show an error / offer a retry. A genuine miss — the server having no
|
|
600
|
+
* record for a fresh thread — resolves normally and never reaches here; only a
|
|
601
|
+
* thrown transport / authorize-gate error does.
|
|
602
|
+
*
|
|
603
|
+
* Skipped when the view unmounted (`!tailing`) or a `sendMessage` took
|
|
604
|
+
* ownership while the hydrate GET was in flight, so a live run's state always
|
|
605
|
+
* wins over a stale mount-time failure — same guard as the success path above.
|
|
606
|
+
*/
|
|
607
|
+
failHydration(cause) {
|
|
608
|
+
if (this.disposed || !this.tailing) return;
|
|
609
|
+
if (this.isLoading || this.abortController) return;
|
|
610
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
611
|
+
if (error instanceof ByokMissingError) this.byok?.request(error.provider, "missing");
|
|
612
|
+
if (error instanceof ByokBlockedError && error.reason === "locked") this.byok?.request(error.provider, "locked");
|
|
613
|
+
this.hydrationError = error;
|
|
614
|
+
this.setStatus("error");
|
|
615
|
+
this.setError(error);
|
|
616
|
+
this.callbacksRef.current.onError(error);
|
|
617
|
+
}
|
|
581
618
|
mountDevtools() {
|
|
582
619
|
this.ensureThreadId();
|
|
583
620
|
if (this.devtoolsMounted) return;
|
|
@@ -1033,7 +1070,7 @@ var ChatClient = class {
|
|
|
1033
1070
|
attached = true;
|
|
1034
1071
|
clearTimeout(connectTimer);
|
|
1035
1072
|
}
|
|
1036
|
-
if (!rebuilt &&
|
|
1073
|
+
if (!rebuilt && rebuildsAssistantMessage(chunk)) {
|
|
1037
1074
|
rebuilt = true;
|
|
1038
1075
|
this.dropTrailingInFlightAssistant();
|
|
1039
1076
|
}
|