@meshagent/meshagent-agents 0.47.1 → 0.49.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/CHANGELOG.md +18 -0
- package/README.md +28 -5
- package/dist/browser/agent-messages.d.ts +1448 -107
- package/dist/browser/agent-messages.js +345 -193
- package/dist/browser/chat-client.d.ts +93 -33
- package/dist/browser/chat-client.js +483 -206
- package/dist/browser/images-dataset.d.ts +1 -1
- package/dist/browser/index.d.ts +2 -0
- package/dist/browser/index.js +8 -0
- package/dist/browser/thread-storage.d.ts +1 -1
- package/dist/esm/agent-messages.d.ts +1448 -107
- package/dist/esm/agent-messages.js +340 -189
- package/dist/esm/chat-client.d.ts +93 -33
- package/dist/esm/chat-client.js +478 -206
- package/dist/esm/images-dataset.d.ts +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/thread-storage.d.ts +1 -1
- package/dist/node/agent-messages.d.ts +1448 -107
- package/dist/node/agent-messages.js +345 -193
- package/dist/node/chat-client.d.ts +93 -33
- package/dist/node/chat-client.js +483 -206
- package/dist/node/images-dataset.d.ts +1 -1
- package/dist/node/index.d.ts +2 -0
- package/dist/node/index.js +8 -0
- package/dist/node/thread-storage.d.ts +1 -1
- package/package.json +7 -3
package/dist/node/chat-client.js
CHANGED
|
@@ -1,19 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ChatThreadSession = exports.MessagingChatClient = exports.BaseMessagingChatClient = exports.ThreadListSubscribe = exports.ThreadSubscribe = exports.messagingChatThreadListSubscribeType = exports.messagingChatThreadSubscribeType = exports.BaseChatClient = exports.ChatThreadStartResult = exports.ChatThreadSessionLoadState = exports.ChatThreadSessionLoadPhase = exports.PendingAgentInput = exports.AgentMessageEvent = void 0;
|
|
6
|
+
exports.ChatThreadSession = exports.MessagingChatClient = exports.WebSocketChatClient = exports.BaseMessagingChatClient = exports.ThreadListSubscribe = exports.ThreadSubscribe = exports.messagingChatThreadListSubscribeType = exports.messagingChatThreadSubscribeType = exports.BaseChatClient = exports.PendingThreadStartCandidate = exports.ChatThreadStartResult = exports.ChatThreadSessionLoadState = exports.ChatThreadSessionLoadPhase = exports.PendingAgentInput = exports.AgentMessageEvent = void 0;
|
|
4
7
|
const meshagent_1 = require("@meshagent/meshagent");
|
|
8
|
+
const msgpack_1 = require("@msgpack/msgpack");
|
|
9
|
+
const isomorphic_ws_1 = __importDefault(require("isomorphic-ws"));
|
|
5
10
|
const uuid_1 = require("uuid");
|
|
6
11
|
const agent_messages_js_1 = require("./agent-messages.js");
|
|
7
12
|
const change_emitter_js_1 = require("./change-emitter.js");
|
|
8
13
|
class AgentMessageEvent {
|
|
9
14
|
constructor({ message, createdAt, attachment }) {
|
|
10
|
-
this.
|
|
11
|
-
this.
|
|
15
|
+
this.listeners = new Set();
|
|
16
|
+
this.messageValue = message;
|
|
17
|
+
this.createdAt = createdAt ?? message.createdAtUtc ?? new Date();
|
|
12
18
|
this.attachment = attachment;
|
|
13
19
|
}
|
|
20
|
+
get message() {
|
|
21
|
+
return this.messageValue;
|
|
22
|
+
}
|
|
14
23
|
get payload() {
|
|
15
24
|
return { ...this.message.toJson(), created_at: this.createdAt.toISOString() };
|
|
16
25
|
}
|
|
26
|
+
addEventListener(listener) {
|
|
27
|
+
this.listeners.add(listener);
|
|
28
|
+
}
|
|
29
|
+
removeEventListener(listener) {
|
|
30
|
+
this.listeners.delete(listener);
|
|
31
|
+
}
|
|
32
|
+
replaceMessage(message) {
|
|
33
|
+
this.messageValue = message;
|
|
34
|
+
for (const listener of [...this.listeners]) {
|
|
35
|
+
listener();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
17
38
|
}
|
|
18
39
|
exports.AgentMessageEvent = AgentMessageEvent;
|
|
19
40
|
function agentRoomMessageFromEvent(event) {
|
|
@@ -99,6 +120,13 @@ class ChatThreadStartResult {
|
|
|
99
120
|
}
|
|
100
121
|
}
|
|
101
122
|
exports.ChatThreadStartResult = ChatThreadStartResult;
|
|
123
|
+
class PendingThreadStartCandidate {
|
|
124
|
+
constructor({ messageId, senderName }) {
|
|
125
|
+
this.messageId = messageId;
|
|
126
|
+
this.senderName = senderName;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.PendingThreadStartCandidate = PendingThreadStartCandidate;
|
|
102
130
|
class EventQueue {
|
|
103
131
|
constructor() {
|
|
104
132
|
this.subscribers = new Set();
|
|
@@ -151,12 +179,15 @@ class EventQueue {
|
|
|
151
179
|
}
|
|
152
180
|
}
|
|
153
181
|
class BaseChatClient extends change_emitter_js_1.ChangeEmitter {
|
|
154
|
-
constructor() {
|
|
155
|
-
super(
|
|
182
|
+
constructor({ threadCreatedPendingStartMatcher, deduplicateClientToolRequests = false, } = {}) {
|
|
183
|
+
super();
|
|
156
184
|
this.sessionsByPath = new Map();
|
|
157
185
|
this.pendingStartRequests = new Map();
|
|
158
186
|
this.pendingSessionEventsByPath = new Map();
|
|
159
187
|
this.eventQueue = new EventQueue();
|
|
188
|
+
this.claimedClientToolRequests = new Set();
|
|
189
|
+
this.threadCreatedPendingStartMatcher = threadCreatedPendingStartMatcher;
|
|
190
|
+
this.deduplicateClientToolRequests = deduplicateClientToolRequests;
|
|
160
191
|
}
|
|
161
192
|
get events() {
|
|
162
193
|
return this.eventQueue.stream;
|
|
@@ -178,14 +209,41 @@ class BaseChatClient extends change_emitter_js_1.ChangeEmitter {
|
|
|
178
209
|
localParticipantId() {
|
|
179
210
|
return undefined;
|
|
180
211
|
}
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
|
|
212
|
+
clientToolRequestKey(threadPath, requestId) {
|
|
213
|
+
const normalizedThreadPath = threadPath.trim();
|
|
214
|
+
const normalizedRequestId = requestId.trim();
|
|
215
|
+
if (normalizedThreadPath === "" || normalizedRequestId === "") {
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
return `${normalizedThreadPath}\n${normalizedRequestId}`;
|
|
219
|
+
}
|
|
220
|
+
claimClientToolRequest(threadPath, requestId) {
|
|
221
|
+
if (!this.deduplicateClientToolRequests) {
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
const key = this.clientToolRequestKey(threadPath, requestId);
|
|
225
|
+
if (key == null) {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
if (this.claimedClientToolRequests.has(key)) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
this.claimedClientToolRequests.add(key);
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
finishClientToolRequest(threadPath, requestId, { responseSent }) {
|
|
235
|
+
if (!this.deduplicateClientToolRequests || responseSent) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const key = this.clientToolRequestKey(threadPath, requestId);
|
|
239
|
+
if (key != null) {
|
|
240
|
+
this.claimedClientToolRequests.delete(key);
|
|
241
|
+
}
|
|
184
242
|
}
|
|
185
243
|
cleanParticipantName(value) {
|
|
186
244
|
return nonEmptyTrimmed(value);
|
|
187
245
|
}
|
|
188
|
-
openThread(threadPath, { load = true, sinceTurn, reloadIfOpen = false,
|
|
246
|
+
openThread(threadPath, { load = true, sinceTurn, reloadIfOpen = false, } = {}) {
|
|
189
247
|
const normalized = threadPath.trim();
|
|
190
248
|
if (normalized === "") {
|
|
191
249
|
throw new TypeError("thread path cannot be empty");
|
|
@@ -197,11 +255,8 @@ class BaseChatClient extends change_emitter_js_1.ChangeEmitter {
|
|
|
197
255
|
}
|
|
198
256
|
return existing;
|
|
199
257
|
}
|
|
200
|
-
const created =
|
|
258
|
+
const created = ChatThreadSession.create({ client: this, threadPath: normalized });
|
|
201
259
|
this.sessionsByPath.set(normalized, created);
|
|
202
|
-
if (drainPendingEvents) {
|
|
203
|
-
this.drainPendingSessionEvents(normalized, created);
|
|
204
|
-
}
|
|
205
260
|
this.openSession(created, { load, sinceTurn });
|
|
206
261
|
this.notifyListeners();
|
|
207
262
|
return created;
|
|
@@ -211,7 +266,7 @@ class BaseChatClient extends change_emitter_js_1.ChangeEmitter {
|
|
|
211
266
|
this.notifyListeners();
|
|
212
267
|
});
|
|
213
268
|
}
|
|
214
|
-
async startThread({ messageId, message, attachments, name, backend, provider, model, voice, outputModalities, realtimeProtocol, senderName, clientToolkits,
|
|
269
|
+
async startThread({ messageId, message, attachments, name, backend, provider, model, voice, outputModalities, realtimeProtocol, senderName, clientToolkits, omitContent = false, }) {
|
|
215
270
|
const resolvedMessageId = messageId == null || messageId.trim() === "" ? (0, uuid_1.v4)() : messageId.trim();
|
|
216
271
|
const resolvedSenderName = this.cleanParticipantName(senderName) ?? this.localParticipantName();
|
|
217
272
|
const payload = new agent_messages_js_1.StartThread({
|
|
@@ -226,10 +281,9 @@ class BaseChatClient extends change_emitter_js_1.ChangeEmitter {
|
|
|
226
281
|
realtimeProtocol: nonEmptyTrimmed(realtimeProtocol),
|
|
227
282
|
senderName: resolvedSenderName,
|
|
228
283
|
clientToolkits: clientToolkits != null && clientToolkits.length > 0 ? clientToolkits : undefined,
|
|
229
|
-
toolChoice: toolChoice?.toJson(),
|
|
230
284
|
});
|
|
231
285
|
const completer = new meshagent_1.Completer();
|
|
232
|
-
this.pendingStartRequests.set(resolvedMessageId, completer);
|
|
286
|
+
this.pendingStartRequests.set(resolvedMessageId, { request: payload, completer });
|
|
233
287
|
try {
|
|
234
288
|
await this.sendAgentMessage(payload);
|
|
235
289
|
const response = await completer.fut;
|
|
@@ -239,18 +293,18 @@ class BaseChatClient extends change_emitter_js_1.ChangeEmitter {
|
|
|
239
293
|
if (threadPath === "") {
|
|
240
294
|
throw new Error("Agent did not return a thread_id for the new thread.");
|
|
241
295
|
}
|
|
242
|
-
const session = this.openThread(threadPath, { load: false
|
|
296
|
+
const session = this.openThread(threadPath, { load: false });
|
|
243
297
|
if (!omitContent) {
|
|
244
298
|
session.addAgentMessage(new AgentMessageEvent({
|
|
245
299
|
message: this.resolvedStartThreadMessage({ payload, threadPath }),
|
|
246
|
-
createdAt:
|
|
300
|
+
createdAt: payload.createdAtUtc,
|
|
247
301
|
}));
|
|
248
302
|
}
|
|
249
303
|
this.drainPendingSessionEvents(threadPath, session);
|
|
250
304
|
return new ChatThreadStartResult({
|
|
251
305
|
session,
|
|
252
306
|
threadPath,
|
|
253
|
-
realtimeConnection: response
|
|
307
|
+
realtimeConnection: response instanceof agent_messages_js_1.ThreadStarted && response.realtimeConnection != null
|
|
254
308
|
? response.realtimeConnection.toJson()
|
|
255
309
|
: undefined,
|
|
256
310
|
});
|
|
@@ -274,6 +328,7 @@ class BaseChatClient extends change_emitter_js_1.ChangeEmitter {
|
|
|
274
328
|
mcp: payload.mcp,
|
|
275
329
|
clientToolkits: payload.clientToolkits,
|
|
276
330
|
toolkits: payload.toolkits,
|
|
331
|
+
toolChoice: payload.toolChoice,
|
|
277
332
|
});
|
|
278
333
|
}
|
|
279
334
|
drainPendingSessionEvents(threadPath, session) {
|
|
@@ -287,9 +342,13 @@ class BaseChatClient extends change_emitter_js_1.ChangeEmitter {
|
|
|
287
342
|
}
|
|
288
343
|
}
|
|
289
344
|
handleAgentMessage(message, { createdAt, attachment } = {}) {
|
|
290
|
-
if (message instanceof agent_messages_js_1.AgentClientToolCallRequested
|
|
291
|
-
|
|
292
|
-
|
|
345
|
+
if (message instanceof agent_messages_js_1.AgentClientToolCallRequested) {
|
|
346
|
+
const targetParticipantId = message.targetParticipantId?.trim();
|
|
347
|
+
if (targetParticipantId != null &&
|
|
348
|
+
targetParticipantId !== "" &&
|
|
349
|
+
targetParticipantId !== this.localParticipantId()) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
293
352
|
}
|
|
294
353
|
if (message.type === agent_messages_js_1.agentConnectionStatusType) {
|
|
295
354
|
this._connectionStatus = message;
|
|
@@ -300,10 +359,13 @@ class BaseChatClient extends change_emitter_js_1.ChangeEmitter {
|
|
|
300
359
|
sourceMessageId != null &&
|
|
301
360
|
sourceMessageId.trim() !== "") {
|
|
302
361
|
const pending = this.pendingStartRequests.get(sourceMessageId.trim());
|
|
303
|
-
if (pending != null && !pending.completed) {
|
|
304
|
-
pending.complete(message);
|
|
362
|
+
if (pending != null && !pending.completer.completed) {
|
|
363
|
+
pending.completer.complete(message);
|
|
305
364
|
}
|
|
306
365
|
}
|
|
366
|
+
if (message instanceof agent_messages_js_1.ThreadCreated) {
|
|
367
|
+
this.acknowledgePendingStartFromThreadCreated(message);
|
|
368
|
+
}
|
|
307
369
|
const threadPath = "threadId" in message ? String(message.threadId).trim() : "";
|
|
308
370
|
if (threadPath === "") {
|
|
309
371
|
this.notifyListeners();
|
|
@@ -321,6 +383,40 @@ class BaseChatClient extends change_emitter_js_1.ChangeEmitter {
|
|
|
321
383
|
}
|
|
322
384
|
this.notifyListeners();
|
|
323
385
|
}
|
|
386
|
+
acknowledgePendingStartFromThreadCreated(message) {
|
|
387
|
+
const matcher = this.threadCreatedPendingStartMatcher;
|
|
388
|
+
const threadPath = String(message.thread?.path ?? "").trim();
|
|
389
|
+
if (matcher == null || threadPath === "") {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const candidates = [...this.pendingStartRequests.entries()]
|
|
393
|
+
.filter(([, pending]) => !pending.completer.completed)
|
|
394
|
+
.map(([messageId, pending]) => new PendingThreadStartCandidate({
|
|
395
|
+
messageId,
|
|
396
|
+
senderName: pending.request.senderName,
|
|
397
|
+
}));
|
|
398
|
+
if (candidates.length === 0) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
let matchedMessageId;
|
|
402
|
+
try {
|
|
403
|
+
matchedMessageId = matcher(message, candidates)?.trim();
|
|
404
|
+
}
|
|
405
|
+
catch {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (matchedMessageId == null || matchedMessageId === "") {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
const pending = this.pendingStartRequests.get(matchedMessageId);
|
|
412
|
+
if (pending == null || pending.completer.completed) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
pending.completer.complete(new agent_messages_js_1.ThreadStarted({
|
|
416
|
+
sourceMessageId: matchedMessageId,
|
|
417
|
+
threadId: threadPath,
|
|
418
|
+
}));
|
|
419
|
+
}
|
|
324
420
|
emitConnectionStatus({ status, message, reason, retryDelay, }) {
|
|
325
421
|
const event = new agent_messages_js_1.AgentConnectionStatus({
|
|
326
422
|
status,
|
|
@@ -377,9 +473,17 @@ class ThreadListSubscribe {
|
|
|
377
473
|
}
|
|
378
474
|
}
|
|
379
475
|
exports.ThreadListSubscribe = ThreadListSubscribe;
|
|
476
|
+
function participantWaitAbortedError(reason) {
|
|
477
|
+
if (reason instanceof Error) {
|
|
478
|
+
return reason;
|
|
479
|
+
}
|
|
480
|
+
const error = new Error("Agent participant wait was cancelled.");
|
|
481
|
+
error.name = "AbortError";
|
|
482
|
+
return error;
|
|
483
|
+
}
|
|
380
484
|
class BaseMessagingChatClient extends BaseChatClient {
|
|
381
|
-
constructor({ room, agentName }) {
|
|
382
|
-
super();
|
|
485
|
+
constructor({ room, agentName, threadCreatedPendingStartMatcher, deduplicateClientToolRequests = true, }) {
|
|
486
|
+
super({ threadCreatedPendingStartMatcher, deduplicateClientToolRequests });
|
|
383
487
|
this.pendingParticipantWaits = new Map();
|
|
384
488
|
this.started = false;
|
|
385
489
|
this.hasConnected = false;
|
|
@@ -476,7 +580,7 @@ class BaseMessagingChatClient extends BaseChatClient {
|
|
|
476
580
|
this.attachMessagingListeners();
|
|
477
581
|
this.room.messaging.start();
|
|
478
582
|
this.startRoomStatusListener();
|
|
479
|
-
|
|
583
|
+
this.room.messaging.enable();
|
|
480
584
|
this.waitingForParticipant = true;
|
|
481
585
|
this.onMessagingChanged();
|
|
482
586
|
}
|
|
@@ -527,7 +631,13 @@ class BaseMessagingChatClient extends BaseChatClient {
|
|
|
527
631
|
}
|
|
528
632
|
return null;
|
|
529
633
|
}
|
|
530
|
-
async waitForAgentParticipant({ waitKey } = {}) {
|
|
634
|
+
async waitForAgentParticipant({ waitKey, signal, timeoutMs, } = {}) {
|
|
635
|
+
if (signal?.aborted) {
|
|
636
|
+
throw participantWaitAbortedError(signal.reason);
|
|
637
|
+
}
|
|
638
|
+
if (timeoutMs != null && (!Number.isFinite(timeoutMs) || timeoutMs < 0)) {
|
|
639
|
+
throw new RangeError("Agent participant wait timeout must be a non-negative finite number.");
|
|
640
|
+
}
|
|
531
641
|
const existing = this.agentParticipant();
|
|
532
642
|
if (existing != null) {
|
|
533
643
|
return existing;
|
|
@@ -535,12 +645,34 @@ class BaseMessagingChatClient extends BaseChatClient {
|
|
|
535
645
|
const key = waitKey == null || waitKey.trim() === "" ? (0, uuid_1.v4)() : waitKey.trim();
|
|
536
646
|
const completer = new meshagent_1.Completer();
|
|
537
647
|
this.pendingParticipantWaits.set(key, completer);
|
|
648
|
+
const handleAbort = () => {
|
|
649
|
+
if (!completer.completed) {
|
|
650
|
+
completer.completeError(participantWaitAbortedError(signal?.reason));
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
signal?.addEventListener("abort", handleAbort, { once: true });
|
|
654
|
+
if (signal?.aborted) {
|
|
655
|
+
handleAbort();
|
|
656
|
+
}
|
|
657
|
+
const timeout = timeoutMs == null
|
|
658
|
+
? undefined
|
|
659
|
+
: setTimeout(() => {
|
|
660
|
+
if (!completer.completed) {
|
|
661
|
+
completer.completeError(new Error(`Agent messaging participant was not available within ${timeoutMs}ms.`));
|
|
662
|
+
}
|
|
663
|
+
}, timeoutMs);
|
|
538
664
|
this.onMessagingChanged();
|
|
539
665
|
try {
|
|
540
666
|
return await completer.fut;
|
|
541
667
|
}
|
|
542
668
|
finally {
|
|
543
|
-
|
|
669
|
+
signal?.removeEventListener("abort", handleAbort);
|
|
670
|
+
if (timeout != null) {
|
|
671
|
+
clearTimeout(timeout);
|
|
672
|
+
}
|
|
673
|
+
if (this.pendingParticipantWaits.get(key) === completer) {
|
|
674
|
+
this.pendingParticipantWaits.delete(key);
|
|
675
|
+
}
|
|
544
676
|
}
|
|
545
677
|
}
|
|
546
678
|
async sendAgentMessage(message, { attachment } = {}) {
|
|
@@ -595,6 +727,255 @@ class BaseMessagingChatClient extends BaseChatClient {
|
|
|
595
727
|
}
|
|
596
728
|
}
|
|
597
729
|
exports.BaseMessagingChatClient = BaseMessagingChatClient;
|
|
730
|
+
class WebSocketChatClient extends BaseChatClient {
|
|
731
|
+
constructor({ url, token, participantName, protocols = ["meshagent-msgpack"], reconnect = true, reconnectInitialDelay = 1000, reconnectMaxDelay = 10000, }) {
|
|
732
|
+
super({ deduplicateClientToolRequests: true });
|
|
733
|
+
this.started = false;
|
|
734
|
+
this.stopping = false;
|
|
735
|
+
this.connecting = false;
|
|
736
|
+
this.reconnectAttempts = 0;
|
|
737
|
+
this.onMessage = (event) => {
|
|
738
|
+
try {
|
|
739
|
+
const bytes = webSocketMessageBytes(event.data);
|
|
740
|
+
if (bytes == null) {
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
const decoded = (0, msgpack_1.decode)(bytes);
|
|
744
|
+
if (!isJsonMap(decoded)) {
|
|
745
|
+
throw new Error("chat websocket received a non-object message");
|
|
746
|
+
}
|
|
747
|
+
const message = agent_messages_js_1.AgentMessage.fromJson(decoded);
|
|
748
|
+
if (message instanceof agent_messages_js_1.AgentConnectionStatus) {
|
|
749
|
+
const participantId = message.participantId?.trim();
|
|
750
|
+
if (participantId != null && participantId !== "") {
|
|
751
|
+
this.assignedParticipantId = participantId;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
this.handleAgentMessage(message);
|
|
755
|
+
}
|
|
756
|
+
catch (error) {
|
|
757
|
+
this.receiveError = error;
|
|
758
|
+
this.emitConnectionStatus({
|
|
759
|
+
status: "disconnected",
|
|
760
|
+
message: "Chat websocket message could not be decoded",
|
|
761
|
+
reason: describeError(error),
|
|
762
|
+
});
|
|
763
|
+
this.webSocket?.close(1003);
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
this.onSocketError = (event) => {
|
|
767
|
+
this.receiveError = event.error ?? new Error("chat websocket error");
|
|
768
|
+
};
|
|
769
|
+
this.onSocketClose = (event) => {
|
|
770
|
+
const webSocket = this.webSocket;
|
|
771
|
+
if (webSocket == null) {
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
this.closeCode = event.code;
|
|
775
|
+
this.closeReason = event.reason;
|
|
776
|
+
this.detachSocketListeners(webSocket);
|
|
777
|
+
this.webSocket = undefined;
|
|
778
|
+
this.assignedParticipantId = undefined;
|
|
779
|
+
if (this.stopping || !this.started) {
|
|
780
|
+
this.notifyListeners();
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
const reason = event.reason !== "" ? `code=${event.code}: ${event.reason}` : `code=${event.code}`;
|
|
784
|
+
if (this.reconnect) {
|
|
785
|
+
this.scheduleReconnect({ reason });
|
|
786
|
+
}
|
|
787
|
+
else {
|
|
788
|
+
this.emitConnectionStatus({
|
|
789
|
+
status: "disconnected",
|
|
790
|
+
message: "Chat websocket disconnected",
|
|
791
|
+
reason,
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
this.notifyListeners();
|
|
795
|
+
};
|
|
796
|
+
this.url = url;
|
|
797
|
+
this.token = token;
|
|
798
|
+
this.participantName = participantName;
|
|
799
|
+
this.protocols = protocols;
|
|
800
|
+
this.reconnect = reconnect;
|
|
801
|
+
this.reconnectInitialDelay = reconnectInitialDelay;
|
|
802
|
+
this.reconnectMaxDelay = reconnectMaxDelay;
|
|
803
|
+
}
|
|
804
|
+
get isConnected() {
|
|
805
|
+
return this.webSocket != null && this.webSocket.readyState === isomorphic_ws_1.default.OPEN;
|
|
806
|
+
}
|
|
807
|
+
localParticipantName() {
|
|
808
|
+
return this.cleanParticipantName(this.participantName);
|
|
809
|
+
}
|
|
810
|
+
localParticipantId() {
|
|
811
|
+
return this.assignedParticipantId;
|
|
812
|
+
}
|
|
813
|
+
async start() {
|
|
814
|
+
this.started = true;
|
|
815
|
+
this.stopping = false;
|
|
816
|
+
if (this.webSocket != null || this.connecting) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
await this.connect({ isReconnect: false });
|
|
820
|
+
}
|
|
821
|
+
async connect({ isReconnect }) {
|
|
822
|
+
if (this.webSocket != null || this.connecting || !this.started || this.stopping) {
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
this.connecting = true;
|
|
826
|
+
const webSocket = new isomorphic_ws_1.default(this.url.toString(), this.resolvedProtocols());
|
|
827
|
+
this.webSocket = webSocket;
|
|
828
|
+
this.assignedParticipantId = undefined;
|
|
829
|
+
webSocket.binaryType = "arraybuffer";
|
|
830
|
+
try {
|
|
831
|
+
await new Promise((resolve, reject) => {
|
|
832
|
+
const onOpen = () => {
|
|
833
|
+
cleanup();
|
|
834
|
+
resolve();
|
|
835
|
+
};
|
|
836
|
+
const onError = (event) => {
|
|
837
|
+
cleanup();
|
|
838
|
+
reject(event.error ?? new Error("chat websocket connection failed"));
|
|
839
|
+
};
|
|
840
|
+
const cleanup = () => {
|
|
841
|
+
webSocket.removeEventListener("open", onOpen);
|
|
842
|
+
webSocket.removeEventListener("error", onError);
|
|
843
|
+
};
|
|
844
|
+
webSocket.addEventListener("open", onOpen);
|
|
845
|
+
webSocket.addEventListener("error", onError);
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
catch (error) {
|
|
849
|
+
if (this.webSocket === webSocket) {
|
|
850
|
+
this.webSocket = undefined;
|
|
851
|
+
}
|
|
852
|
+
this.receiveError = error;
|
|
853
|
+
this.connecting = false;
|
|
854
|
+
if (isReconnect && this.reconnect && !this.stopping) {
|
|
855
|
+
this.scheduleReconnect({ reason: describeError(error) });
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
this.emitConnectionStatus({
|
|
859
|
+
status: "disconnected",
|
|
860
|
+
message: "Chat websocket connection failed",
|
|
861
|
+
reason: describeError(error),
|
|
862
|
+
});
|
|
863
|
+
throw error;
|
|
864
|
+
}
|
|
865
|
+
webSocket.addEventListener("message", this.onMessage);
|
|
866
|
+
webSocket.addEventListener("error", this.onSocketError);
|
|
867
|
+
webSocket.addEventListener("close", this.onSocketClose);
|
|
868
|
+
this.connecting = false;
|
|
869
|
+
this.receiveError = undefined;
|
|
870
|
+
this.closeCode = undefined;
|
|
871
|
+
this.closeReason = undefined;
|
|
872
|
+
const status = isReconnect ? "reconnected" : "connected";
|
|
873
|
+
this.emitConnectionStatus({
|
|
874
|
+
status,
|
|
875
|
+
message: isReconnect ? "Chat websocket reconnected" : "Chat websocket connected",
|
|
876
|
+
});
|
|
877
|
+
if (isReconnect) {
|
|
878
|
+
await this.reopenOpenSessions();
|
|
879
|
+
}
|
|
880
|
+
this.reconnectAttempts = 0;
|
|
881
|
+
this.notifyListeners();
|
|
882
|
+
}
|
|
883
|
+
async stop() {
|
|
884
|
+
this.started = false;
|
|
885
|
+
this.stopping = true;
|
|
886
|
+
if (this.reconnectTimer != null) {
|
|
887
|
+
clearTimeout(this.reconnectTimer);
|
|
888
|
+
this.reconnectTimer = undefined;
|
|
889
|
+
}
|
|
890
|
+
const webSocket = this.webSocket;
|
|
891
|
+
this.webSocket = undefined;
|
|
892
|
+
this.assignedParticipantId = undefined;
|
|
893
|
+
if (webSocket != null) {
|
|
894
|
+
this.detachSocketListeners(webSocket);
|
|
895
|
+
webSocket.close(1000);
|
|
896
|
+
}
|
|
897
|
+
this.emitConnectionStatus({
|
|
898
|
+
status: "disconnected",
|
|
899
|
+
message: "Chat websocket disconnected",
|
|
900
|
+
reason: "client_stopped",
|
|
901
|
+
});
|
|
902
|
+
this.stopping = false;
|
|
903
|
+
this.notifyListeners();
|
|
904
|
+
}
|
|
905
|
+
async sendAgentMessage(message, { attachment } = {}) {
|
|
906
|
+
if (attachment != null) {
|
|
907
|
+
throw new Error("WebSocketChatClient does not support binary attachments yet.");
|
|
908
|
+
}
|
|
909
|
+
const webSocket = this.webSocket;
|
|
910
|
+
if (webSocket == null || webSocket.readyState !== isomorphic_ws_1.default.OPEN) {
|
|
911
|
+
throw new Error(this.closedMessage());
|
|
912
|
+
}
|
|
913
|
+
webSocket.send((0, msgpack_1.encode)(message.toJson()));
|
|
914
|
+
}
|
|
915
|
+
detachSocketListeners(webSocket) {
|
|
916
|
+
webSocket.removeEventListener("message", this.onMessage);
|
|
917
|
+
webSocket.removeEventListener("error", this.onSocketError);
|
|
918
|
+
webSocket.removeEventListener("close", this.onSocketClose);
|
|
919
|
+
}
|
|
920
|
+
scheduleReconnect({ reason }) {
|
|
921
|
+
if (this.reconnectTimer != null || this.stopping || !this.started) {
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
const retryDelay = this.nextReconnectDelay();
|
|
925
|
+
this.emitConnectionStatus({
|
|
926
|
+
status: "reconnecting",
|
|
927
|
+
message: "Chat websocket disconnected; reconnecting",
|
|
928
|
+
reason,
|
|
929
|
+
retryDelay,
|
|
930
|
+
});
|
|
931
|
+
this.reconnectTimer = setTimeout(() => {
|
|
932
|
+
this.reconnectTimer = undefined;
|
|
933
|
+
void this.connect({ isReconnect: true });
|
|
934
|
+
}, retryDelay);
|
|
935
|
+
}
|
|
936
|
+
nextReconnectDelay() {
|
|
937
|
+
const initialDelay = Math.max(1, this.reconnectInitialDelay);
|
|
938
|
+
const maxDelay = Math.max(initialDelay, this.reconnectMaxDelay);
|
|
939
|
+
const factor = 2 ** Math.min(this.reconnectAttempts, 6);
|
|
940
|
+
this.reconnectAttempts += 1;
|
|
941
|
+
return Math.min(initialDelay * factor, maxDelay);
|
|
942
|
+
}
|
|
943
|
+
async reopenOpenSessions() {
|
|
944
|
+
for (const session of this.sessions) {
|
|
945
|
+
if (!session.isOpen) {
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
await session.open({ load: true, sinceTurn: session.lastCompletedTurnId });
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
resolvedProtocols() {
|
|
952
|
+
const resolved = [];
|
|
953
|
+
for (const protocol of this.protocols) {
|
|
954
|
+
const normalized = protocol.trim();
|
|
955
|
+
if (normalized !== "" && !resolved.includes(normalized)) {
|
|
956
|
+
resolved.push(normalized);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
const normalizedToken = this.token.trim();
|
|
960
|
+
if (normalizedToken !== "") {
|
|
961
|
+
resolved.push(`meshagent-agent.${normalizedToken}`);
|
|
962
|
+
}
|
|
963
|
+
return resolved;
|
|
964
|
+
}
|
|
965
|
+
closedMessage() {
|
|
966
|
+
if (this.receiveError != null) {
|
|
967
|
+
return `chat websocket is closed: ${describeError(this.receiveError)}`;
|
|
968
|
+
}
|
|
969
|
+
if (this.closeCode != null) {
|
|
970
|
+
return `chat websocket is closed (code=${this.closeCode})`;
|
|
971
|
+
}
|
|
972
|
+
if (this.closeReason != null && this.closeReason.trim() !== "") {
|
|
973
|
+
return `chat websocket is closed: ${this.closeReason}`;
|
|
974
|
+
}
|
|
975
|
+
return "chat websocket is closed";
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
exports.WebSocketChatClient = WebSocketChatClient;
|
|
598
979
|
class MessagingChatClient extends BaseMessagingChatClient {
|
|
599
980
|
constructor() {
|
|
600
981
|
super(...arguments);
|
|
@@ -658,7 +1039,7 @@ class MessagingChatClient extends BaseMessagingChatClient {
|
|
|
658
1039
|
await super.sendAgentMessage(message, { attachment });
|
|
659
1040
|
return;
|
|
660
1041
|
}
|
|
661
|
-
if (message
|
|
1042
|
+
if (message instanceof agent_messages_js_1.OpenThread) {
|
|
662
1043
|
const previous = this.threadSubscriptions.get(message.threadId);
|
|
663
1044
|
if (previous != null) {
|
|
664
1045
|
await previous.close();
|
|
@@ -674,7 +1055,7 @@ class MessagingChatClient extends BaseMessagingChatClient {
|
|
|
674
1055
|
this.trackStream(subscription);
|
|
675
1056
|
return;
|
|
676
1057
|
}
|
|
677
|
-
if (message
|
|
1058
|
+
if (message instanceof agent_messages_js_1.CloseThread) {
|
|
678
1059
|
const subscription = this.threadSubscriptions.get(message.threadId);
|
|
679
1060
|
if (subscription != null) {
|
|
680
1061
|
this.threadSubscriptions.delete(message.threadId);
|
|
@@ -682,7 +1063,7 @@ class MessagingChatClient extends BaseMessagingChatClient {
|
|
|
682
1063
|
return;
|
|
683
1064
|
}
|
|
684
1065
|
}
|
|
685
|
-
if (message
|
|
1066
|
+
if (message instanceof agent_messages_js_1.WatchThreads) {
|
|
686
1067
|
await this.threadListSubscription?.close();
|
|
687
1068
|
const stream = await this.room.messaging.stream({
|
|
688
1069
|
to: participant,
|
|
@@ -695,7 +1076,7 @@ class MessagingChatClient extends BaseMessagingChatClient {
|
|
|
695
1076
|
this.trackStream(subscription);
|
|
696
1077
|
return;
|
|
697
1078
|
}
|
|
698
|
-
if (message
|
|
1079
|
+
if (message instanceof agent_messages_js_1.UnwatchThreads && this.threadListSubscription != null) {
|
|
699
1080
|
const subscription = this.threadListSubscription;
|
|
700
1081
|
this.threadListSubscription = undefined;
|
|
701
1082
|
await subscription.close();
|
|
@@ -734,6 +1115,9 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
734
1115
|
this.client = client;
|
|
735
1116
|
this.threadPath = threadPath;
|
|
736
1117
|
}
|
|
1118
|
+
static create({ client, threadPath }) {
|
|
1119
|
+
return new ChatThreadSession({ client, threadPath });
|
|
1120
|
+
}
|
|
737
1121
|
get messages() {
|
|
738
1122
|
return [...this._messages];
|
|
739
1123
|
}
|
|
@@ -752,18 +1136,6 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
752
1136
|
get lastCompletedTurnId() {
|
|
753
1137
|
return this.lastCompletedTurnIdValue;
|
|
754
1138
|
}
|
|
755
|
-
get activeTurnId() {
|
|
756
|
-
return this.activeTurnIdValue;
|
|
757
|
-
}
|
|
758
|
-
get threadStatus() {
|
|
759
|
-
return this.threadStatusValue;
|
|
760
|
-
}
|
|
761
|
-
get currentModel() {
|
|
762
|
-
return this.currentModelValue;
|
|
763
|
-
}
|
|
764
|
-
get modelsResponse() {
|
|
765
|
-
return this.modelsResponseValue;
|
|
766
|
-
}
|
|
767
1139
|
async open({ load = true, sinceTurn } = {}) {
|
|
768
1140
|
if (this.openState) {
|
|
769
1141
|
if (load) {
|
|
@@ -778,7 +1150,6 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
778
1150
|
}
|
|
779
1151
|
catch (error) {
|
|
780
1152
|
this.setLoadState(this.failedLoadState(error));
|
|
781
|
-
throw error;
|
|
782
1153
|
}
|
|
783
1154
|
}
|
|
784
1155
|
return;
|
|
@@ -797,7 +1168,6 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
797
1168
|
}
|
|
798
1169
|
catch (error) {
|
|
799
1170
|
this.setLoadState(this.failedLoadState(error));
|
|
800
|
-
throw error;
|
|
801
1171
|
}
|
|
802
1172
|
}
|
|
803
1173
|
resetReplayState() {
|
|
@@ -844,16 +1214,20 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
844
1214
|
response,
|
|
845
1215
|
}));
|
|
846
1216
|
}
|
|
847
|
-
|
|
1217
|
+
claimClientToolCall(requestId) {
|
|
1218
|
+
return this.client.claimClientToolRequest(this.threadPath, requestId);
|
|
1219
|
+
}
|
|
1220
|
+
finishClientToolCall(requestId, { responseSent }) {
|
|
1221
|
+
this.client.finishClientToolRequest(this.threadPath, requestId, { responseSent });
|
|
1222
|
+
}
|
|
1223
|
+
injectMessages(messages) {
|
|
1224
|
+
return this.client.sendAgentMessage(new agent_messages_js_1.InjectMessages({
|
|
1225
|
+
threadId: this.threadPath,
|
|
1226
|
+
messages: [...messages],
|
|
1227
|
+
}));
|
|
1228
|
+
}
|
|
1229
|
+
async sendText({ messageId, text, attachments, steer = false, turnId, backend, provider, model, voice, outputModalities, senderName, clientToolkits, }) {
|
|
848
1230
|
const resolvedMessageId = messageId == null || messageId.trim() === "" ? (0, uuid_1.v4)() : messageId.trim();
|
|
849
|
-
const currentModel = this.currentModelValue;
|
|
850
|
-
const resolvedBackend = nonEmptyTrimmed(backend) ?? currentModel?.backend;
|
|
851
|
-
const resolvedProvider = nonEmptyTrimmed(provider) ?? currentModel?.provider;
|
|
852
|
-
const resolvedModel = nonEmptyTrimmed(model) ?? currentModel?.model;
|
|
853
|
-
const resolvedVoice = nonEmptyTrimmed(voice) ?? currentModel?.voice;
|
|
854
|
-
const resolvedOutputModalities = outputModalities != null && outputModalities.length > 0
|
|
855
|
-
? outputModalities
|
|
856
|
-
: currentModel?.outputModalities;
|
|
857
1231
|
const payload = steer
|
|
858
1232
|
? new agent_messages_js_1.TurnSteer({
|
|
859
1233
|
threadId: this.threadPath,
|
|
@@ -867,13 +1241,12 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
867
1241
|
messageId: resolvedMessageId,
|
|
868
1242
|
senderName: nonEmptyTrimmed(senderName),
|
|
869
1243
|
content: (0, agent_messages_js_1.agentInputContent)({ text, attachments }),
|
|
870
|
-
backend:
|
|
871
|
-
provider:
|
|
872
|
-
model:
|
|
873
|
-
voice:
|
|
874
|
-
outputModalities:
|
|
1244
|
+
backend: nonEmptyTrimmed(backend),
|
|
1245
|
+
provider: nonEmptyTrimmed(provider),
|
|
1246
|
+
model: nonEmptyTrimmed(model),
|
|
1247
|
+
voice: nonEmptyTrimmed(voice),
|
|
1248
|
+
outputModalities: outputModalities != null && outputModalities.length > 0 ? outputModalities : undefined,
|
|
875
1249
|
clientToolkits: clientToolkits != null && clientToolkits.length > 0 ? clientToolkits : undefined,
|
|
876
|
-
toolChoice: toolChoice?.toJson(),
|
|
877
1250
|
});
|
|
878
1251
|
this.localAgentMessageIds.add(resolvedMessageId);
|
|
879
1252
|
this.pendingLocalInputMessageIds.add(resolvedMessageId);
|
|
@@ -892,10 +1265,10 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
892
1265
|
await this.client.sendAgentMessage(new agent_messages_js_1.AgentRealtimeAudioChunk({
|
|
893
1266
|
threadId: this.threadPath,
|
|
894
1267
|
messageId: (0, uuid_1.v4)(),
|
|
895
|
-
format,
|
|
1268
|
+
format: new agent_messages_js_1.AgentAudioFormat(format),
|
|
896
1269
|
}), { attachment: chunk });
|
|
897
1270
|
}
|
|
898
|
-
async commitRealtimeAudio({ turnId, provider, model, voice, outputModalities, }) {
|
|
1271
|
+
async commitRealtimeAudio({ turnId, backend, provider, model, voice, outputModalities, }) {
|
|
899
1272
|
const messageId = (0, uuid_1.v4)();
|
|
900
1273
|
await this.client.sendAgentMessage(new agent_messages_js_1.AgentRealtimeAudioCommit({
|
|
901
1274
|
threadId: this.threadPath,
|
|
@@ -906,6 +1279,7 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
906
1279
|
threadId: this.threadPath,
|
|
907
1280
|
messageId: (0, uuid_1.v4)(),
|
|
908
1281
|
turnId,
|
|
1282
|
+
backend: nonEmptyTrimmed(backend),
|
|
909
1283
|
provider: nonEmptyTrimmed(provider),
|
|
910
1284
|
model: nonEmptyTrimmed(model),
|
|
911
1285
|
voice: nonEmptyTrimmed(voice),
|
|
@@ -934,56 +1308,9 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
934
1308
|
const turnId = normalizedString(threadMessageValue(message, "turnId"));
|
|
935
1309
|
if (turnId != null) {
|
|
936
1310
|
this.lastCompletedTurnIdValue = turnId;
|
|
937
|
-
if (this.activeTurnIdValue === turnId) {
|
|
938
|
-
this.activeTurnIdValue = undefined;
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
const statusTurnId = normalizedString(this.threadStatusValue?.turnId);
|
|
942
|
-
if (statusTurnId == null || statusTurnId === turnId) {
|
|
943
|
-
this.threadStatusValue = undefined;
|
|
944
1311
|
}
|
|
945
|
-
return;
|
|
946
|
-
}
|
|
947
|
-
if (message.type === agent_messages_js_1.agentTurnStartAcceptedType || message.type === agent_messages_js_1.agentTurnStartedType) {
|
|
948
|
-
const turnId = normalizedString(threadMessageValue(message, "turnId"));
|
|
949
|
-
if (turnId != null) {
|
|
950
|
-
this.activeTurnIdValue = turnId;
|
|
951
|
-
}
|
|
952
|
-
if (message.type === agent_messages_js_1.agentTurnStartedType) {
|
|
953
|
-
const statusTurnId = normalizedString(this.threadStatusValue?.turnId);
|
|
954
|
-
if (statusTurnId == null || statusTurnId === turnId) {
|
|
955
|
-
this.threadStatusValue = undefined;
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
return;
|
|
959
|
-
}
|
|
960
|
-
if (message.type === agent_messages_js_1.agentThreadStatusType && message instanceof agent_messages_js_1.AgentThreadStatus) {
|
|
961
|
-
const mode = normalizedString(message.mode);
|
|
962
|
-
const status = normalizedString(message.status);
|
|
963
|
-
const turnId = normalizedString(message.turnId);
|
|
964
|
-
if (status == null) {
|
|
965
|
-
this.threadStatusValue = undefined;
|
|
966
|
-
if (turnId != null && this.activeTurnIdValue === turnId) {
|
|
967
|
-
this.activeTurnIdValue = undefined;
|
|
968
|
-
}
|
|
969
|
-
return;
|
|
970
|
-
}
|
|
971
|
-
this.threadStatusValue = message;
|
|
972
|
-
if (mode === "steerable" && turnId != null) {
|
|
973
|
-
this.activeTurnIdValue = turnId;
|
|
974
|
-
}
|
|
975
|
-
return;
|
|
976
1312
|
}
|
|
977
|
-
if (message.type === agent_messages_js_1.
|
|
978
|
-
this.currentModelValue = message;
|
|
979
|
-
return;
|
|
980
|
-
}
|
|
981
|
-
if (message.type === agent_messages_js_1.agentModelsResponseType && message instanceof agent_messages_js_1.ModelsResponse) {
|
|
982
|
-
this.modelsResponseValue = message;
|
|
983
|
-
this.applyActiveModel(message);
|
|
984
|
-
return;
|
|
985
|
-
}
|
|
986
|
-
if (message.type === agent_messages_js_1.agentThreadLoadedType) {
|
|
1313
|
+
else if (message.type === agent_messages_js_1.agentThreadLoadedType) {
|
|
987
1314
|
this.setLoadState(new ChatThreadSessionLoadState({
|
|
988
1315
|
phase: ChatThreadSessionLoadPhase.Loaded,
|
|
989
1316
|
startedAt: this.loadStateValue.startedAt,
|
|
@@ -1061,45 +1388,21 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
1061
1388
|
}
|
|
1062
1389
|
appendRenderableMessage(event) {
|
|
1063
1390
|
const message = event.message;
|
|
1064
|
-
if (message
|
|
1065
|
-
if (message.error != null) {
|
|
1066
|
-
this.appendMessage(event);
|
|
1067
|
-
}
|
|
1068
|
-
return;
|
|
1069
|
-
}
|
|
1070
|
-
if (message.type === agent_messages_js_1.agentToolCallEndedType) {
|
|
1071
|
-
const itemId = message.error == null ? undefined : normalizedString(message.itemId);
|
|
1072
|
-
if (itemId != null) {
|
|
1073
|
-
this.upsertItemMessage(`tool_call:${itemId}`, event);
|
|
1074
|
-
}
|
|
1075
|
-
else if (message.error != null) {
|
|
1076
|
-
this.appendMessage(event);
|
|
1077
|
-
}
|
|
1078
|
-
return;
|
|
1079
|
-
}
|
|
1080
|
-
if (message.type === agent_messages_js_1.agentToolCallPendingType || message.type === agent_messages_js_1.agentToolCallInProgressType || message.type === agent_messages_js_1.agentToolCallStartedType) {
|
|
1081
|
-
const itemId = normalizedString(message.itemId);
|
|
1082
|
-
if (itemId != null) {
|
|
1083
|
-
this.upsertItemMessage(`tool_call:${itemId}`, event);
|
|
1084
|
-
}
|
|
1085
|
-
return;
|
|
1086
|
-
}
|
|
1087
|
-
if (message.type === agent_messages_js_1.agentSecretRequestedType) {
|
|
1391
|
+
if (message instanceof agent_messages_js_1.TurnEnded) {
|
|
1088
1392
|
this.appendMessage(event);
|
|
1089
1393
|
return;
|
|
1090
1394
|
}
|
|
1091
|
-
if (message.
|
|
1092
|
-
|
|
1093
|
-
return;
|
|
1094
|
-
}
|
|
1095
|
-
if (message.type === agent_messages_js_1.agentThreadStartType || message.type === agent_messages_js_1.agentTurnStartType || message.type === agent_messages_js_1.agentTurnSteerType) {
|
|
1096
|
-
if (agentInputText(message.content).trim() !== "") {
|
|
1395
|
+
if (message instanceof agent_messages_js_1.StartThread || message instanceof agent_messages_js_1.TurnStart || message instanceof agent_messages_js_1.TurnSteer) {
|
|
1396
|
+
if (agentInputText(messageValue(message, "content")).trim() !== "") {
|
|
1097
1397
|
this.appendMessage(event);
|
|
1398
|
+
const messageId = normalizedString(message.messageId);
|
|
1399
|
+
if (messageId != null)
|
|
1400
|
+
this.pendingLocalInputMessageIds.add(messageId);
|
|
1098
1401
|
}
|
|
1099
1402
|
return;
|
|
1100
1403
|
}
|
|
1101
|
-
if (message
|
|
1102
|
-
const sourceMessageId = normalizedString(
|
|
1404
|
+
if (message instanceof agent_messages_js_1.TurnStartAccepted) {
|
|
1405
|
+
const sourceMessageId = normalizedString(message.sourceMessageId);
|
|
1103
1406
|
if (sourceMessageId != null && this.localAgentMessageIds.has(sourceMessageId)) {
|
|
1104
1407
|
this.pendingLocalInputMessageIds.delete(sourceMessageId);
|
|
1105
1408
|
return;
|
|
@@ -1107,36 +1410,21 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
1107
1410
|
if (agentInputText(message.content).trim() !== "") {
|
|
1108
1411
|
this.appendMessage(event, { beforePendingLocalInputs: true });
|
|
1109
1412
|
}
|
|
1110
|
-
else {
|
|
1111
|
-
this.appendMessage(event);
|
|
1112
|
-
}
|
|
1113
|
-
return;
|
|
1114
|
-
}
|
|
1115
|
-
if (message.type === agent_messages_js_1.agentTurnStartedType ||
|
|
1116
|
-
message.type === agent_messages_js_1.agentTurnSteeredType ||
|
|
1117
|
-
message.type === agent_messages_js_1.agentTurnStartRejectedType ||
|
|
1118
|
-
message.type === agent_messages_js_1.agentTurnSteerRejectedType ||
|
|
1119
|
-
message.type === agent_messages_js_1.agentTurnInterruptAcceptedType ||
|
|
1120
|
-
message.type === agent_messages_js_1.agentTurnInterruptedType) {
|
|
1121
|
-
this.appendMessage(event);
|
|
1122
1413
|
return;
|
|
1123
1414
|
}
|
|
1124
1415
|
if (isMergeableDelta(message)) {
|
|
1125
1416
|
this.appendOrMergeDelta(event);
|
|
1126
1417
|
return;
|
|
1127
1418
|
}
|
|
1128
|
-
if (message
|
|
1129
|
-
|
|
1130
|
-
if (itemId != null) {
|
|
1131
|
-
this.upsertItemMessage(`image_generation:${itemId}`, event);
|
|
1132
|
-
}
|
|
1419
|
+
if (message instanceof agent_messages_js_1.AgentImageGenerationPartial || message instanceof agent_messages_js_1.AgentImageGenerationCompleted) {
|
|
1420
|
+
this.appendMessage(event);
|
|
1133
1421
|
return;
|
|
1134
1422
|
}
|
|
1135
|
-
if (message
|
|
1423
|
+
if (message instanceof agent_messages_js_1.AgentClientToolCallRequested) {
|
|
1136
1424
|
this.appendMessage(event);
|
|
1137
1425
|
return;
|
|
1138
1426
|
}
|
|
1139
|
-
if (message instanceof agent_messages_js_1.
|
|
1427
|
+
if (message instanceof agent_messages_js_1.AgentConnectionStatus || message instanceof agent_messages_js_1.AgentThreadMessage) {
|
|
1140
1428
|
this.appendMessage(event);
|
|
1141
1429
|
}
|
|
1142
1430
|
}
|
|
@@ -1156,15 +1444,6 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
1156
1444
|
this.messageIndexes.set(normalizedMessageId, this._messages.length);
|
|
1157
1445
|
this._messages.push(event);
|
|
1158
1446
|
}
|
|
1159
|
-
upsertItemMessage(key, event) {
|
|
1160
|
-
const existingIndex = this.messageIndexes.get(key);
|
|
1161
|
-
if (existingIndex == null) {
|
|
1162
|
-
this.messageIndexes.set(key, this._messages.length);
|
|
1163
|
-
this._messages.push(event);
|
|
1164
|
-
return;
|
|
1165
|
-
}
|
|
1166
|
-
this._messages[existingIndex] = event;
|
|
1167
|
-
}
|
|
1168
1447
|
appendOrMergeDelta(event) {
|
|
1169
1448
|
const message = event.message;
|
|
1170
1449
|
const normalizedMessageId = normalizedString(message.messageId);
|
|
@@ -1174,7 +1453,7 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
1174
1453
|
}
|
|
1175
1454
|
this.mergedDeltaMessageIds.add(normalizedMessageId);
|
|
1176
1455
|
}
|
|
1177
|
-
const itemId = normalizedString(message
|
|
1456
|
+
const itemId = normalizedString(messageValue(message, "itemId"));
|
|
1178
1457
|
if (itemId == null) {
|
|
1179
1458
|
return;
|
|
1180
1459
|
}
|
|
@@ -1188,7 +1467,7 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
1188
1467
|
const existing = this._messages[existingIndex].message;
|
|
1189
1468
|
const merged = mergeDeltaMessage(existing, message);
|
|
1190
1469
|
if (merged != null) {
|
|
1191
|
-
this._messages[existingIndex]
|
|
1470
|
+
this._messages[existingIndex].replaceMessage(merged);
|
|
1192
1471
|
}
|
|
1193
1472
|
}
|
|
1194
1473
|
indexMessagesFrom(start) {
|
|
@@ -1199,29 +1478,6 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
1199
1478
|
}
|
|
1200
1479
|
}
|
|
1201
1480
|
}
|
|
1202
|
-
applyActiveModel(response) {
|
|
1203
|
-
for (const provider of response.providers) {
|
|
1204
|
-
for (const model of provider.models) {
|
|
1205
|
-
if (!model.active) {
|
|
1206
|
-
continue;
|
|
1207
|
-
}
|
|
1208
|
-
this.currentModelValue = new agent_messages_js_1.AgentModelChanged({
|
|
1209
|
-
threadId: this.threadPath,
|
|
1210
|
-
sourceMessageId: response.sourceMessageId,
|
|
1211
|
-
backend: provider.backend,
|
|
1212
|
-
provider: provider.name,
|
|
1213
|
-
model: model.name,
|
|
1214
|
-
voice: model.defaultOutputVoice,
|
|
1215
|
-
inputFormat: model.inputFormat,
|
|
1216
|
-
outputFormat: model.outputFormat,
|
|
1217
|
-
turnDetection: model.turnDetection,
|
|
1218
|
-
realtimeProtocols: model.realtimeProtocols,
|
|
1219
|
-
outputModalities: model.modalities.length > 0 ? [model.modalities[0]] : ["text"],
|
|
1220
|
-
});
|
|
1221
|
-
return;
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
1481
|
markClosed({ notify = true } = {}) {
|
|
1226
1482
|
this.openState = false;
|
|
1227
1483
|
this.loadStateValue = new ChatThreadSessionLoadState({
|
|
@@ -1281,12 +1537,33 @@ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
|
|
|
1281
1537
|
}
|
|
1282
1538
|
}
|
|
1283
1539
|
exports.ChatThreadSession = ChatThreadSession;
|
|
1540
|
+
function webSocketMessageBytes(value) {
|
|
1541
|
+
if (value instanceof Uint8Array) {
|
|
1542
|
+
return value;
|
|
1543
|
+
}
|
|
1544
|
+
if (value instanceof ArrayBuffer) {
|
|
1545
|
+
return new Uint8Array(value);
|
|
1546
|
+
}
|
|
1547
|
+
if (ArrayBuffer.isView(value)) {
|
|
1548
|
+
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
1549
|
+
}
|
|
1550
|
+
return undefined;
|
|
1551
|
+
}
|
|
1552
|
+
function isJsonMap(value) {
|
|
1553
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1554
|
+
}
|
|
1555
|
+
function describeError(error) {
|
|
1556
|
+
return error instanceof Error ? error.message : String(error);
|
|
1557
|
+
}
|
|
1284
1558
|
function sourceMessageIdFor(message) {
|
|
1285
1559
|
const value = "sourceMessageId" in message ? message.sourceMessageId : undefined;
|
|
1286
1560
|
return typeof value === "string" ? value : undefined;
|
|
1287
1561
|
}
|
|
1562
|
+
function messageValue(message, key) {
|
|
1563
|
+
return message[key];
|
|
1564
|
+
}
|
|
1288
1565
|
function threadMessageValue(message, key) {
|
|
1289
|
-
const value = message
|
|
1566
|
+
const value = messageValue(message, key);
|
|
1290
1567
|
return typeof value === "string" ? value : undefined;
|
|
1291
1568
|
}
|
|
1292
1569
|
function agentInputText(content) {
|
|
@@ -1314,7 +1591,7 @@ function isMergeableDelta(message) {
|
|
|
1314
1591
|
}
|
|
1315
1592
|
function messageIndexKey(message) {
|
|
1316
1593
|
if (isMergeableDelta(message)) {
|
|
1317
|
-
const itemId = normalizedString(message
|
|
1594
|
+
const itemId = normalizedString(messageValue(message, "itemId"));
|
|
1318
1595
|
return itemId == null ? undefined : `${message.type}:${itemId}`;
|
|
1319
1596
|
}
|
|
1320
1597
|
return normalizedString(message.messageId);
|
|
@@ -1327,30 +1604,30 @@ function mergeDeltaMessage(existing, incoming) {
|
|
|
1327
1604
|
const data = new Uint8Array(existing.data.length + incoming.data.length);
|
|
1328
1605
|
data.set(existing.data, 0);
|
|
1329
1606
|
data.set(incoming.data, existing.data.length);
|
|
1330
|
-
return
|
|
1607
|
+
return agent_messages_js_1.AgentAudioGenerationDelta.fromJson({ ...existing.toJson(), data });
|
|
1331
1608
|
}
|
|
1332
1609
|
if (existing.type === agent_messages_js_1.agentAudioTranscriptionDeltaType && existing instanceof agent_messages_js_1.AgentAudioTranscriptionDelta && incoming instanceof agent_messages_js_1.AgentAudioTranscriptionDelta) {
|
|
1333
|
-
return
|
|
1610
|
+
return agent_messages_js_1.AgentAudioTranscriptionDelta.fromJson({ ...existing.toJson(), text: `${existing.text}${incoming.text}` });
|
|
1334
1611
|
}
|
|
1335
1612
|
if (existing.type === agent_messages_js_1.agentFileContentDeltaType && incoming instanceof agent_messages_js_1.AgentFileContentDelta) {
|
|
1336
1613
|
return incoming;
|
|
1337
1614
|
}
|
|
1338
1615
|
if (existing.type === agent_messages_js_1.agentReasoningContentDeltaType && existing instanceof agent_messages_js_1.AgentReasoningContentDelta && incoming instanceof agent_messages_js_1.AgentReasoningContentDelta) {
|
|
1339
|
-
return
|
|
1616
|
+
return agent_messages_js_1.AgentReasoningContentDelta.fromJson({ ...existing.toJson(), text: `${existing.text}${incoming.text}` });
|
|
1340
1617
|
}
|
|
1341
1618
|
if (existing.type === agent_messages_js_1.agentTextContentDeltaType && existing instanceof agent_messages_js_1.AgentTextContentDelta && incoming instanceof agent_messages_js_1.AgentTextContentDelta) {
|
|
1342
|
-
return
|
|
1619
|
+
return agent_messages_js_1.AgentTextContentDelta.fromJson({ ...existing.toJson(), text: `${existing.text}${incoming.text}` });
|
|
1343
1620
|
}
|
|
1344
1621
|
if (existing.type === agent_messages_js_1.agentToolCallArgumentsDeltaType && existing instanceof agent_messages_js_1.AgentToolCallArgumentsDelta && incoming instanceof agent_messages_js_1.AgentToolCallArgumentsDelta) {
|
|
1345
|
-
return
|
|
1622
|
+
return agent_messages_js_1.AgentToolCallArgumentsDelta.fromJson({ ...existing.toJson(), delta: `${existing.delta}${incoming.delta}` });
|
|
1346
1623
|
}
|
|
1347
1624
|
if (existing.type === agent_messages_js_1.agentToolCallLogDeltaType && existing instanceof agent_messages_js_1.AgentToolCallLogDelta && incoming instanceof agent_messages_js_1.AgentToolCallLogDelta) {
|
|
1348
|
-
return
|
|
1625
|
+
return agent_messages_js_1.AgentToolCallLogDelta.fromJson({ ...existing.toJson(), lines: [...existing.lines, ...incoming.lines] });
|
|
1349
1626
|
}
|
|
1350
1627
|
return undefined;
|
|
1351
1628
|
}
|
|
1352
1629
|
function normalizedString(value) {
|
|
1353
|
-
const normalized = value
|
|
1630
|
+
const normalized = typeof value === "string" ? value.trim() : undefined;
|
|
1354
1631
|
return normalized == null || normalized === "" ? undefined : normalized;
|
|
1355
1632
|
}
|
|
1356
1633
|
function dateOrNull(value) {
|