@tanstack/ai-client 0.12.0 → 0.14.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/dist/esm/chat-client.d.ts +16 -2
- package/dist/esm/chat-client.js +197 -31
- package/dist/esm/chat-client.js.map +1 -1
- package/dist/esm/connection-adapters.d.ts +21 -1
- package/dist/esm/connection-adapters.js +262 -68
- package/dist/esm/connection-adapters.js.map +1 -1
- package/dist/esm/devtools-noop.d.ts +60 -0
- package/dist/esm/devtools-noop.js +135 -0
- package/dist/esm/devtools-noop.js.map +1 -0
- package/dist/esm/devtools.d.ts +276 -0
- package/dist/esm/devtools.js +1178 -0
- package/dist/esm/devtools.js.map +1 -0
- package/dist/esm/events.d.ts +51 -8
- package/dist/esm/events.js +65 -20
- package/dist/esm/events.js.map +1 -1
- package/dist/esm/generation-client.d.ts +14 -0
- package/dist/esm/generation-client.js +135 -5
- package/dist/esm/generation-client.js.map +1 -1
- package/dist/esm/generation-types.d.ts +16 -2
- package/dist/esm/generation-types.js.map +1 -1
- package/dist/esm/index.d.ts +6 -4
- package/dist/esm/index.js +9 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/realtime-client.d.ts +1 -1
- package/dist/esm/realtime-client.js +1 -1
- package/dist/esm/realtime-client.js.map +1 -1
- package/dist/esm/realtime-types.d.ts +1 -1
- package/dist/esm/response-stream.d.ts +7 -0
- package/dist/esm/response-stream.js +32 -0
- package/dist/esm/response-stream.js.map +1 -0
- package/dist/esm/sse-parser.d.ts +1 -1
- package/dist/esm/sse-parser.js +5 -6
- package/dist/esm/sse-parser.js.map +1 -1
- package/dist/esm/sse-utils.d.ts +1 -0
- package/dist/esm/sse-utils.js +11 -0
- package/dist/esm/sse-utils.js.map +1 -0
- package/dist/esm/tool-types.d.ts +1 -1
- package/dist/esm/types.d.ts +23 -5
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/video-generation-client.d.ts +15 -0
- package/dist/esm/video-generation-client.js +147 -8
- package/dist/esm/video-generation-client.js.map +1 -1
- package/package.json +7 -3
- package/src/chat-client.ts +250 -33
- package/src/connection-adapters.ts +360 -68
- package/src/devtools-noop.ts +205 -0
- package/src/devtools.ts +1866 -0
- package/src/events.ts +143 -12
- package/src/generation-client.ts +177 -10
- package/src/generation-types.ts +24 -5
- package/src/index.ts +16 -3
- package/src/realtime-client.ts +2 -2
- package/src/realtime-types.ts +1 -1
- package/src/response-stream.ts +42 -0
- package/src/sse-parser.ts +9 -7
- package/src/sse-utils.ts +8 -0
- package/src/tool-types.ts +1 -1
- package/src/types.ts +31 -4
- package/src/video-generation-client.ts +187 -12
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnyClientTool, ModelMessage, StreamChunk } from '@tanstack/ai';
|
|
1
|
+
import { AnyClientTool, ModelMessage, StreamChunk } from '@tanstack/ai/client';
|
|
2
2
|
import { ConnectionAdapter } from './connection-adapters.js';
|
|
3
3
|
import { ChatClientOptions, ChatClientState, ChatFetcher, ConnectionStatus, MultimodalContent, UIMessage } from './types.js';
|
|
4
4
|
export declare class ChatClient {
|
|
@@ -15,8 +15,15 @@ export declare class ChatClient {
|
|
|
15
15
|
private status;
|
|
16
16
|
private connectionStatus;
|
|
17
17
|
private abortController;
|
|
18
|
-
private readonly events;
|
|
19
18
|
private readonly clientToolsRef;
|
|
19
|
+
private readonly devtoolsBridge;
|
|
20
|
+
/**
|
|
21
|
+
* Alias for `this.events`. The bridge installs an
|
|
22
|
+
* emitter that auto-attaches run/thread context and auto-emits a
|
|
23
|
+
* snapshot after every event, so chat-client only ever calls
|
|
24
|
+
* `this.events.X(...)` exactly like it did before devtools landed.
|
|
25
|
+
*/
|
|
26
|
+
private readonly events;
|
|
20
27
|
private currentStreamId;
|
|
21
28
|
private currentMessageId;
|
|
22
29
|
private readonly postStreamActions;
|
|
@@ -30,8 +37,10 @@ export declare class ChatClient {
|
|
|
30
37
|
private draining;
|
|
31
38
|
private sessionGenerating;
|
|
32
39
|
private readonly activeRunIds;
|
|
40
|
+
private devtoolsMounted;
|
|
33
41
|
private readonly callbacksRef;
|
|
34
42
|
constructor(options: ChatClientOptions);
|
|
43
|
+
mountDevtools(): void;
|
|
35
44
|
private generateUniqueId;
|
|
36
45
|
private setIsLoading;
|
|
37
46
|
private setStatus;
|
|
@@ -40,6 +49,9 @@ export declare class ChatClient {
|
|
|
40
49
|
private setSessionGenerating;
|
|
41
50
|
private resetSessionGenerating;
|
|
42
51
|
private setError;
|
|
52
|
+
private buildDevtoolsBridgeOptions;
|
|
53
|
+
private getDevtoolsSnapshot;
|
|
54
|
+
private findMessageIdForToolCall;
|
|
43
55
|
private abortSubscriptionLoop;
|
|
44
56
|
private resolveProcessing;
|
|
45
57
|
private cancelInFlightStream;
|
|
@@ -149,6 +161,7 @@ export declare class ChatClient {
|
|
|
149
161
|
state?: 'output-available' | 'output-error';
|
|
150
162
|
errorText?: string;
|
|
151
163
|
}): Promise<void>;
|
|
164
|
+
private addToolResultInternal;
|
|
152
165
|
/**
|
|
153
166
|
* Respond to a tool approval request
|
|
154
167
|
*/
|
|
@@ -230,4 +243,5 @@ export declare class ChatClient {
|
|
|
230
243
|
toolCallId?: string;
|
|
231
244
|
}) => void;
|
|
232
245
|
}): void;
|
|
246
|
+
dispose(): void;
|
|
233
247
|
}
|
package/dist/esm/chat-client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { StreamProcessor, normalizeToUIMessage, generateMessageId, convertSchemaToJsonSchema } from "@tanstack/ai";
|
|
2
|
-
import {
|
|
1
|
+
import { StreamProcessor, normalizeToUIMessage, generateMessageId, convertSchemaToJsonSchema } from "@tanstack/ai/client";
|
|
2
|
+
import { createNoOpChatDevtoolsBridge } from "./devtools-noop.js";
|
|
3
3
|
import { normalizeConnectionAdapter, fetcherToConnectionAdapter } from "./connection-adapters.js";
|
|
4
4
|
function resolveTransport(transport) {
|
|
5
5
|
const { connection, fetcher } = transport;
|
|
@@ -30,8 +30,15 @@ class ChatClient {
|
|
|
30
30
|
status = "ready";
|
|
31
31
|
connectionStatus = "disconnected";
|
|
32
32
|
abortController = null;
|
|
33
|
-
events;
|
|
34
33
|
clientToolsRef;
|
|
34
|
+
devtoolsBridge;
|
|
35
|
+
/**
|
|
36
|
+
* Alias for `this.events`. The bridge installs an
|
|
37
|
+
* emitter that auto-attaches run/thread context and auto-emits a
|
|
38
|
+
* snapshot after every event, so chat-client only ever calls
|
|
39
|
+
* `this.events.X(...)` exactly like it did before devtools landed.
|
|
40
|
+
*/
|
|
41
|
+
events;
|
|
35
42
|
currentStreamId = null;
|
|
36
43
|
currentMessageId = null;
|
|
37
44
|
postStreamActions = [];
|
|
@@ -49,6 +56,7 @@ class ChatClient {
|
|
|
49
56
|
draining = false;
|
|
50
57
|
sessionGenerating = false;
|
|
51
58
|
activeRunIds = /* @__PURE__ */ new Set();
|
|
59
|
+
devtoolsMounted = false;
|
|
52
60
|
callbacksRef;
|
|
53
61
|
constructor(options) {
|
|
54
62
|
this.uniqueId = options.id || this.generateUniqueId("chat");
|
|
@@ -56,13 +64,14 @@ class ChatClient {
|
|
|
56
64
|
this.bodyOption = options.body || {};
|
|
57
65
|
this.forwardedPropsOption = options.forwardedProps || {};
|
|
58
66
|
this.connection = normalizeConnectionAdapter(resolveTransport(options));
|
|
59
|
-
this.events = new DefaultChatClientEventEmitter(this.uniqueId);
|
|
60
67
|
this.clientToolsRef = { current: /* @__PURE__ */ new Map() };
|
|
61
68
|
if (options.tools) {
|
|
62
69
|
for (const tool of options.tools) {
|
|
63
70
|
this.clientToolsRef.current.set(tool.name, tool);
|
|
64
71
|
}
|
|
65
72
|
}
|
|
73
|
+
this.devtoolsBridge = (options.devtoolsBridgeFactory ?? createNoOpChatDevtoolsBridge)(this.buildDevtoolsBridgeOptions(options.devtools));
|
|
74
|
+
this.events = this.devtoolsBridge.events;
|
|
66
75
|
this.callbacksRef = {
|
|
67
76
|
current: {
|
|
68
77
|
onResponse: options.onResponse || (() => {
|
|
@@ -134,10 +143,30 @@ class ChatClient {
|
|
|
134
143
|
this.events.thinkingUpdated(
|
|
135
144
|
this.currentStreamId,
|
|
136
145
|
messageId,
|
|
137
|
-
content
|
|
146
|
+
content,
|
|
147
|
+
void 0
|
|
138
148
|
);
|
|
139
149
|
}
|
|
140
150
|
},
|
|
151
|
+
onStructuredOutputChange: (args) => {
|
|
152
|
+
const streamId = this.devtoolsBridge.resolveStreamId();
|
|
153
|
+
const eventName = args.phase === "start" ? "structured-output:started" : args.phase === "complete" ? "structured-output:completed" : args.phase === "error" ? "structured-output:errored" : "structured-output:updated";
|
|
154
|
+
this.currentMessageId = args.messageId;
|
|
155
|
+
this.events.structuredOutputChanged(
|
|
156
|
+
eventName,
|
|
157
|
+
streamId,
|
|
158
|
+
args.messageId,
|
|
159
|
+
{
|
|
160
|
+
status: args.status,
|
|
161
|
+
raw: args.raw,
|
|
162
|
+
...args.partial !== void 0 ? { partial: args.partial } : {},
|
|
163
|
+
...args.data !== void 0 ? { data: args.data } : {},
|
|
164
|
+
...args.reasoning !== void 0 ? { reasoning: args.reasoning } : {},
|
|
165
|
+
...args.errorMessage !== void 0 ? { errorMessage: args.errorMessage } : {},
|
|
166
|
+
...args.delta !== void 0 ? { delta: args.delta } : {}
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
},
|
|
141
170
|
onToolCallStateChange: (messageId, toolCallId, state, args) => {
|
|
142
171
|
const messages = this.processor.getMessages();
|
|
143
172
|
const message = messages.find((m) => m.id === messageId);
|
|
@@ -160,23 +189,30 @@ class ChatClient {
|
|
|
160
189
|
const clientTool = this.clientToolsRef.current.get(args.toolName);
|
|
161
190
|
const executeFunc = clientTool?.execute;
|
|
162
191
|
if (executeFunc) {
|
|
192
|
+
const runEventContext = this.devtoolsBridge.getCurrentRunEventContext();
|
|
163
193
|
const executionPromise = (async () => {
|
|
164
194
|
try {
|
|
165
195
|
const output = await executeFunc(args.input);
|
|
166
|
-
await this.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
196
|
+
await this.addToolResultInternal(
|
|
197
|
+
{
|
|
198
|
+
toolCallId: args.toolCallId,
|
|
199
|
+
tool: args.toolName,
|
|
200
|
+
output,
|
|
201
|
+
state: "output-available"
|
|
202
|
+
},
|
|
203
|
+
runEventContext
|
|
204
|
+
);
|
|
172
205
|
} catch (error) {
|
|
173
|
-
await this.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
206
|
+
await this.addToolResultInternal(
|
|
207
|
+
{
|
|
208
|
+
toolCallId: args.toolCallId,
|
|
209
|
+
tool: args.toolName,
|
|
210
|
+
output: null,
|
|
211
|
+
state: "output-error",
|
|
212
|
+
errorText: error.message
|
|
213
|
+
},
|
|
214
|
+
runEventContext
|
|
215
|
+
);
|
|
180
216
|
} finally {
|
|
181
217
|
this.pendingToolExecutions.delete(args.toolCallId);
|
|
182
218
|
}
|
|
@@ -185,23 +221,29 @@ class ChatClient {
|
|
|
185
221
|
}
|
|
186
222
|
},
|
|
187
223
|
onApprovalRequest: (args) => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
224
|
+
const streamId = this.devtoolsBridge.resolveStreamId();
|
|
225
|
+
const messageIdForApproval = this.findMessageIdForToolCall(args.toolCallId) ?? this.currentMessageId ?? "";
|
|
226
|
+
this.events.approvalRequested(
|
|
227
|
+
streamId,
|
|
228
|
+
messageIdForApproval,
|
|
229
|
+
args.toolCallId,
|
|
230
|
+
args.toolName,
|
|
231
|
+
args.input,
|
|
232
|
+
args.approvalId
|
|
233
|
+
);
|
|
198
234
|
},
|
|
199
235
|
onCustomEvent: (eventType, data, context) => {
|
|
200
236
|
this.callbacksRef.current.onCustomEvent(eventType, data, context);
|
|
201
237
|
}
|
|
202
238
|
}
|
|
203
239
|
});
|
|
204
|
-
|
|
240
|
+
}
|
|
241
|
+
mountDevtools() {
|
|
242
|
+
if (this.devtoolsMounted) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
this.devtoolsMounted = true;
|
|
246
|
+
this.devtoolsBridge.mountWithTools(this.processor.getMessages().length);
|
|
205
247
|
}
|
|
206
248
|
generateUniqueId(prefix) {
|
|
207
249
|
return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
|
@@ -214,19 +256,23 @@ class ChatClient {
|
|
|
214
256
|
setStatus(status) {
|
|
215
257
|
this.status = status;
|
|
216
258
|
this.callbacksRef.current.onStatusChange(status);
|
|
259
|
+
this.devtoolsBridge.emitSnapshot();
|
|
217
260
|
}
|
|
218
261
|
setIsSubscribed(isSubscribed) {
|
|
219
262
|
this.isSubscribed = isSubscribed;
|
|
220
263
|
this.callbacksRef.current.onSubscriptionChange(isSubscribed);
|
|
264
|
+
this.devtoolsBridge.emitSnapshot();
|
|
221
265
|
}
|
|
222
266
|
setConnectionStatus(status) {
|
|
223
267
|
this.connectionStatus = status;
|
|
224
268
|
this.callbacksRef.current.onConnectionStatusChange(status);
|
|
269
|
+
this.devtoolsBridge.emitSnapshot();
|
|
225
270
|
}
|
|
226
271
|
setSessionGenerating(isGenerating) {
|
|
227
272
|
if (this.sessionGenerating === isGenerating) return;
|
|
228
273
|
this.sessionGenerating = isGenerating;
|
|
229
274
|
this.callbacksRef.current.onSessionGeneratingChange(isGenerating);
|
|
275
|
+
this.devtoolsBridge.emitSnapshot();
|
|
230
276
|
}
|
|
231
277
|
resetSessionGenerating() {
|
|
232
278
|
this.activeRunIds.clear();
|
|
@@ -237,6 +283,51 @@ class ChatClient {
|
|
|
237
283
|
this.callbacksRef.current.onErrorChange(error);
|
|
238
284
|
this.events.errorChanged(error?.message || null);
|
|
239
285
|
}
|
|
286
|
+
buildDevtoolsBridgeOptions(devtools) {
|
|
287
|
+
return {
|
|
288
|
+
hookId: this.uniqueId,
|
|
289
|
+
clientId: this.uniqueId,
|
|
290
|
+
threadId: this.threadId,
|
|
291
|
+
metadata: {
|
|
292
|
+
hookName: devtools?.hookName ?? "useChat",
|
|
293
|
+
outputKind: devtools?.outputKind ?? "chat",
|
|
294
|
+
...devtools?.framework ? { framework: devtools.framework } : {},
|
|
295
|
+
...devtools?.name ? { name: devtools.name } : {}
|
|
296
|
+
},
|
|
297
|
+
getSnapshot: () => this.getDevtoolsSnapshot(),
|
|
298
|
+
getTools: () => this.clientToolsRef.current.values(),
|
|
299
|
+
getMessages: () => this.processor.getMessages(),
|
|
300
|
+
setMessages: (messages) => {
|
|
301
|
+
this.processor.setMessages(messages);
|
|
302
|
+
},
|
|
303
|
+
addToolResult: (toolCallId, output, errorText) => {
|
|
304
|
+
this.processor.addToolResult(toolCallId, output, errorText);
|
|
305
|
+
},
|
|
306
|
+
generateId: (prefix) => this.generateUniqueId(prefix)
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
getDevtoolsSnapshot() {
|
|
310
|
+
return {
|
|
311
|
+
messages: this.processor.getMessages(),
|
|
312
|
+
status: this.status,
|
|
313
|
+
isLoading: this.isLoading,
|
|
314
|
+
isSubscribed: this.isSubscribed,
|
|
315
|
+
connectionStatus: this.connectionStatus,
|
|
316
|
+
sessionGenerating: this.sessionGenerating,
|
|
317
|
+
activeRunIds: Array.from(this.activeRunIds),
|
|
318
|
+
...this.error ? { error: this.error.message } : {}
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
findMessageIdForToolCall(toolCallId) {
|
|
322
|
+
const messages = this.processor.getMessages();
|
|
323
|
+
for (const message of messages) {
|
|
324
|
+
const match = message.parts.find(
|
|
325
|
+
(part) => part.type === "tool-call" && part.id === toolCallId
|
|
326
|
+
);
|
|
327
|
+
if (match) return message.id;
|
|
328
|
+
}
|
|
329
|
+
return void 0;
|
|
330
|
+
}
|
|
240
331
|
abortSubscriptionLoop() {
|
|
241
332
|
this.subscriptionAbortController?.abort();
|
|
242
333
|
this.subscriptionAbortController = null;
|
|
@@ -306,11 +397,12 @@ class ChatClient {
|
|
|
306
397
|
this.setConnectionStatus("connected");
|
|
307
398
|
}
|
|
308
399
|
this.callbacksRef.current.onChunk(chunk);
|
|
309
|
-
this.processor.processChunk(chunk);
|
|
310
400
|
if (chunk.type === "RUN_STARTED") {
|
|
311
401
|
this.activeRunIds.add(chunk.runId);
|
|
312
402
|
this.setSessionGenerating(true);
|
|
313
403
|
}
|
|
404
|
+
this.devtoolsBridge.observeChunk(chunk);
|
|
405
|
+
this.processor.processChunk(chunk);
|
|
314
406
|
if (chunk.type === "RUN_FINISHED" || chunk.type === "RUN_ERROR") {
|
|
315
407
|
const runId = "runId" in chunk && typeof chunk.runId === "string" ? chunk.runId : void 0;
|
|
316
408
|
if (runId) {
|
|
@@ -386,6 +478,7 @@ class ChatClient {
|
|
|
386
478
|
* ```
|
|
387
479
|
*/
|
|
388
480
|
async sendMessage(content, body) {
|
|
481
|
+
this.mountDevtools();
|
|
389
482
|
const emptyMessage = typeof content === "string" && !content.trim();
|
|
390
483
|
if (emptyMessage || this.isLoading) {
|
|
391
484
|
return;
|
|
@@ -413,6 +506,7 @@ class ChatClient {
|
|
|
413
506
|
* Append a message and stream the response
|
|
414
507
|
*/
|
|
415
508
|
async append(message) {
|
|
509
|
+
this.mountDevtools();
|
|
416
510
|
const normalizedMessage = normalizeToUIMessage(message, generateMessageId);
|
|
417
511
|
if (normalizedMessage.role === "system") {
|
|
418
512
|
return;
|
|
@@ -421,6 +515,7 @@ class ChatClient {
|
|
|
421
515
|
this.events.messageAppended(uiMessage);
|
|
422
516
|
const messages = this.processor.getMessages();
|
|
423
517
|
this.processor.setMessages([...messages, uiMessage]);
|
|
518
|
+
this.devtoolsBridge.emitSnapshot();
|
|
424
519
|
if (this.isLoading) {
|
|
425
520
|
this.queuePostStreamAction(async () => {
|
|
426
521
|
await this.streamResponse();
|
|
@@ -446,6 +541,8 @@ class ChatClient {
|
|
|
446
541
|
const signal = this.abortController.signal;
|
|
447
542
|
this.pendingToolExecutions.clear();
|
|
448
543
|
let streamCompletedSuccessfully = false;
|
|
544
|
+
let activeDevtoolsRunId = null;
|
|
545
|
+
let runTerminalEventEmitted = false;
|
|
449
546
|
try {
|
|
450
547
|
const messages = this.processor.getMessages();
|
|
451
548
|
await this.callbacksRef.current.onResponse();
|
|
@@ -459,6 +556,7 @@ class ChatClient {
|
|
|
459
556
|
};
|
|
460
557
|
this.pendingMessageBody = void 0;
|
|
461
558
|
this.currentStreamId = this.generateUniqueId("stream");
|
|
559
|
+
this.devtoolsBridge.setCurrentStreamId(this.currentStreamId);
|
|
462
560
|
this.currentMessageId = null;
|
|
463
561
|
this.processor.prepareAssistantMessage();
|
|
464
562
|
this.ensureSubscription();
|
|
@@ -475,12 +573,34 @@ class ChatClient {
|
|
|
475
573
|
),
|
|
476
574
|
forwardedProps: { ...mergedBody }
|
|
477
575
|
};
|
|
576
|
+
this.devtoolsBridge.beginRun(runContext.runId, this.threadId);
|
|
577
|
+
activeDevtoolsRunId = runContext.runId;
|
|
578
|
+
this.devtoolsBridge.emitRunLifecycle(
|
|
579
|
+
"run:created",
|
|
580
|
+
runContext.runId,
|
|
581
|
+
"created"
|
|
582
|
+
);
|
|
583
|
+
this.devtoolsBridge.emitRunLifecycle(
|
|
584
|
+
"run:started",
|
|
585
|
+
runContext.runId,
|
|
586
|
+
"started"
|
|
587
|
+
);
|
|
588
|
+
this.devtoolsBridge.emitSnapshot();
|
|
478
589
|
await this.connection.send(messages, mergedBody, signal, runContext);
|
|
479
590
|
await processingComplete;
|
|
480
591
|
if (generation !== this.streamGeneration) {
|
|
481
592
|
return false;
|
|
482
593
|
}
|
|
483
594
|
if (this.status === "error") {
|
|
595
|
+
if (activeDevtoolsRunId) {
|
|
596
|
+
this.devtoolsBridge.emitRunLifecycle(
|
|
597
|
+
"run:errored",
|
|
598
|
+
activeDevtoolsRunId,
|
|
599
|
+
"errored",
|
|
600
|
+
this.error ? { error: this.error.message } : {}
|
|
601
|
+
);
|
|
602
|
+
runTerminalEventEmitted = true;
|
|
603
|
+
}
|
|
484
604
|
return false;
|
|
485
605
|
}
|
|
486
606
|
if (this.pendingToolExecutions.size > 0) {
|
|
@@ -491,19 +611,52 @@ class ChatClient {
|
|
|
491
611
|
} catch (err) {
|
|
492
612
|
if (err instanceof Error) {
|
|
493
613
|
if (err.name === "AbortError") {
|
|
614
|
+
if (activeDevtoolsRunId) {
|
|
615
|
+
this.devtoolsBridge.emitRunLifecycle(
|
|
616
|
+
"run:cancelled",
|
|
617
|
+
activeDevtoolsRunId,
|
|
618
|
+
"cancelled"
|
|
619
|
+
);
|
|
620
|
+
runTerminalEventEmitted = true;
|
|
621
|
+
}
|
|
494
622
|
return false;
|
|
495
623
|
}
|
|
496
624
|
if (generation === this.streamGeneration) {
|
|
497
625
|
this.reportStreamError(err);
|
|
626
|
+
if (activeDevtoolsRunId) {
|
|
627
|
+
this.devtoolsBridge.emitRunLifecycle(
|
|
628
|
+
"run:errored",
|
|
629
|
+
activeDevtoolsRunId,
|
|
630
|
+
"errored",
|
|
631
|
+
{ error: err.message }
|
|
632
|
+
);
|
|
633
|
+
runTerminalEventEmitted = true;
|
|
634
|
+
}
|
|
498
635
|
}
|
|
499
636
|
}
|
|
500
637
|
} finally {
|
|
501
638
|
if (generation === this.streamGeneration) {
|
|
502
639
|
this.currentStreamId = null;
|
|
640
|
+
this.devtoolsBridge.setCurrentStreamId(null);
|
|
503
641
|
this.currentMessageId = null;
|
|
504
642
|
this.abortController = null;
|
|
505
643
|
this.setIsLoading(false);
|
|
506
644
|
this.pendingMessageBody = void 0;
|
|
645
|
+
if (activeDevtoolsRunId && !runTerminalEventEmitted) {
|
|
646
|
+
if (streamCompletedSuccessfully) {
|
|
647
|
+
this.devtoolsBridge.emitRunLifecycle(
|
|
648
|
+
"run:completed",
|
|
649
|
+
activeDevtoolsRunId,
|
|
650
|
+
"completed"
|
|
651
|
+
);
|
|
652
|
+
} else if (signal.aborted) {
|
|
653
|
+
this.devtoolsBridge.emitRunLifecycle(
|
|
654
|
+
"run:cancelled",
|
|
655
|
+
activeDevtoolsRunId,
|
|
656
|
+
"cancelled"
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
507
660
|
await this.drainPostStreamActions();
|
|
508
661
|
if (streamCompletedSuccessfully) {
|
|
509
662
|
const messages = this.processor.getMessages();
|
|
@@ -565,6 +718,7 @@ class ChatClient {
|
|
|
565
718
|
}
|
|
566
719
|
this.events.reloaded(lastUserMessageIndex);
|
|
567
720
|
this.processor.removeMessagesAfter(lastUserMessageIndex);
|
|
721
|
+
this.devtoolsBridge.emitSnapshot();
|
|
568
722
|
await this.streamResponse();
|
|
569
723
|
}
|
|
570
724
|
/**
|
|
@@ -586,11 +740,15 @@ class ChatClient {
|
|
|
586
740
|
* Add the result of a client-side tool execution
|
|
587
741
|
*/
|
|
588
742
|
async addToolResult(result) {
|
|
743
|
+
await this.addToolResultInternal(result);
|
|
744
|
+
}
|
|
745
|
+
async addToolResultInternal(result, context) {
|
|
589
746
|
this.events.toolResultAdded(
|
|
590
747
|
result.toolCallId,
|
|
591
748
|
result.tool,
|
|
592
749
|
result.output,
|
|
593
|
-
result.state || "output-available"
|
|
750
|
+
result.state || "output-available",
|
|
751
|
+
context
|
|
594
752
|
);
|
|
595
753
|
this.processor.addToolResult(
|
|
596
754
|
result.toolCallId,
|
|
@@ -626,6 +784,7 @@ class ChatClient {
|
|
|
626
784
|
);
|
|
627
785
|
}
|
|
628
786
|
this.processor.addToolApprovalResponse(response.id, response.approved);
|
|
787
|
+
this.devtoolsBridge.emitSnapshot();
|
|
629
788
|
if (this.isLoading) {
|
|
630
789
|
this.queuePostStreamAction(() => this.checkForContinuation());
|
|
631
790
|
return;
|
|
@@ -743,6 +902,7 @@ class ChatClient {
|
|
|
743
902
|
*/
|
|
744
903
|
setMessagesManually(messages) {
|
|
745
904
|
this.processor.setMessages(messages);
|
|
905
|
+
this.devtoolsBridge.emitSnapshot();
|
|
746
906
|
}
|
|
747
907
|
/**
|
|
748
908
|
* Update options refs (for use in React hooks to avoid recreating client)
|
|
@@ -782,6 +942,7 @@ class ChatClient {
|
|
|
782
942
|
for (const tool of options.tools) {
|
|
783
943
|
this.clientToolsRef.current.set(tool.name, tool);
|
|
784
944
|
}
|
|
945
|
+
this.devtoolsBridge.notifyToolsChanged();
|
|
785
946
|
}
|
|
786
947
|
if (options.onResponse !== void 0) {
|
|
787
948
|
this.callbacksRef.current.onResponse = options.onResponse;
|
|
@@ -808,6 +969,11 @@ class ChatClient {
|
|
|
808
969
|
this.callbacksRef.current.onCustomEvent = options.onCustomEvent;
|
|
809
970
|
}
|
|
810
971
|
}
|
|
972
|
+
dispose() {
|
|
973
|
+
this.unsubscribe();
|
|
974
|
+
this.devtoolsBridge.dispose();
|
|
975
|
+
this.devtoolsMounted = false;
|
|
976
|
+
}
|
|
811
977
|
}
|
|
812
978
|
export {
|
|
813
979
|
ChatClient
|