@meshagent/meshagent-agents 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/LICENSE +1 -0
  3. package/README.md +206 -0
  4. package/dist/browser/agent-messages.d.ts +343 -0
  5. package/dist/browser/agent-messages.js +1015 -0
  6. package/dist/browser/change-emitter.d.ts +8 -0
  7. package/dist/browser/change-emitter.js +20 -0
  8. package/dist/browser/chat-client.d.ts +225 -0
  9. package/dist/browser/chat-client.js +642 -0
  10. package/dist/browser/images-dataset.d.ts +83 -0
  11. package/dist/browser/images-dataset.js +282 -0
  12. package/dist/browser/index.d.ts +6 -0
  13. package/dist/browser/index.js +22 -0
  14. package/dist/browser/package.json +1 -0
  15. package/dist/browser/room-shell-toolkit.d.ts +14 -0
  16. package/dist/browser/room-shell-toolkit.js +274 -0
  17. package/dist/browser/room-storage-toolkit.d.ts +11 -0
  18. package/dist/browser/room-storage-toolkit.js +513 -0
  19. package/dist/browser/thread-storage.d.ts +102 -0
  20. package/dist/browser/thread-storage.js +476 -0
  21. package/dist/esm/agent-messages.d.ts +343 -0
  22. package/dist/esm/agent-messages.js +989 -0
  23. package/dist/esm/change-emitter.d.ts +8 -0
  24. package/dist/esm/change-emitter.js +16 -0
  25. package/dist/esm/chat-client.d.ts +225 -0
  26. package/dist/esm/chat-client.js +632 -0
  27. package/dist/esm/images-dataset.d.ts +83 -0
  28. package/dist/esm/images-dataset.js +274 -0
  29. package/dist/esm/index.d.ts +6 -0
  30. package/dist/esm/index.js +6 -0
  31. package/dist/esm/package.json +1 -0
  32. package/dist/esm/room-shell-toolkit.d.ts +14 -0
  33. package/dist/esm/room-shell-toolkit.js +270 -0
  34. package/dist/esm/room-storage-toolkit.d.ts +11 -0
  35. package/dist/esm/room-storage-toolkit.js +509 -0
  36. package/dist/esm/thread-storage.d.ts +102 -0
  37. package/dist/esm/thread-storage.js +465 -0
  38. package/dist/node/agent-messages.d.ts +343 -0
  39. package/dist/node/agent-messages.js +1015 -0
  40. package/dist/node/change-emitter.d.ts +8 -0
  41. package/dist/node/change-emitter.js +20 -0
  42. package/dist/node/chat-client.d.ts +225 -0
  43. package/dist/node/chat-client.js +642 -0
  44. package/dist/node/images-dataset.d.ts +83 -0
  45. package/dist/node/images-dataset.js +282 -0
  46. package/dist/node/index.d.ts +6 -0
  47. package/dist/node/index.js +22 -0
  48. package/dist/node/package.json +1 -0
  49. package/dist/node/room-shell-toolkit.d.ts +14 -0
  50. package/dist/node/room-shell-toolkit.js +274 -0
  51. package/dist/node/room-storage-toolkit.d.ts +11 -0
  52. package/dist/node/room-storage-toolkit.js +513 -0
  53. package/dist/node/thread-storage.d.ts +102 -0
  54. package/dist/node/thread-storage.js +476 -0
  55. package/package.json +57 -0
@@ -0,0 +1,642 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChatThreadSession = exports.MessagingChatClient = exports.BaseChatClient = exports.ChatThreadStartResult = exports.ChatThreadSessionLoadState = exports.ChatThreadSessionLoadPhase = exports.PendingAgentInput = exports.AgentMessageEvent = void 0;
4
+ const meshagent_1 = require("@meshagent/meshagent");
5
+ const uuid_1 = require("uuid");
6
+ const agent_messages_js_1 = require("./agent-messages.js");
7
+ const change_emitter_js_1 = require("./change-emitter.js");
8
+ class AgentMessageEvent {
9
+ constructor({ message, attachment }) {
10
+ this.message = message;
11
+ this.attachment = attachment;
12
+ }
13
+ get payload() {
14
+ return this.message.toJson();
15
+ }
16
+ }
17
+ exports.AgentMessageEvent = AgentMessageEvent;
18
+ class PendingAgentInput {
19
+ constructor({ messageId, messageType, threadPath, payload, createdAt, awaitingAcceptance = false, awaitingApplication = false, awaitingOnline = false, }) {
20
+ this.messageId = messageId;
21
+ this.messageType = messageType;
22
+ this.threadPath = threadPath;
23
+ this.payload = payload;
24
+ this.createdAt = createdAt;
25
+ this.awaitingAcceptance = awaitingAcceptance;
26
+ this.awaitingApplication = awaitingApplication;
27
+ this.awaitingOnline = awaitingOnline;
28
+ }
29
+ copyWith({ awaitingAcceptance, awaitingApplication, awaitingOnline, }) {
30
+ return new PendingAgentInput({
31
+ messageId: this.messageId,
32
+ messageType: this.messageType,
33
+ threadPath: this.threadPath,
34
+ payload: this.payload,
35
+ createdAt: this.createdAt,
36
+ awaitingAcceptance: awaitingAcceptance ?? this.awaitingAcceptance,
37
+ awaitingApplication: awaitingApplication ?? this.awaitingApplication,
38
+ awaitingOnline: awaitingOnline ?? this.awaitingOnline,
39
+ });
40
+ }
41
+ }
42
+ exports.PendingAgentInput = PendingAgentInput;
43
+ var ChatThreadSessionLoadPhase;
44
+ (function (ChatThreadSessionLoadPhase) {
45
+ ChatThreadSessionLoadPhase["Idle"] = "idle";
46
+ ChatThreadSessionLoadPhase["Loading"] = "loading";
47
+ ChatThreadSessionLoadPhase["Loaded"] = "loaded";
48
+ ChatThreadSessionLoadPhase["Failed"] = "failed";
49
+ })(ChatThreadSessionLoadPhase || (exports.ChatThreadSessionLoadPhase = ChatThreadSessionLoadPhase = {}));
50
+ class ChatThreadSessionLoadState {
51
+ constructor({ phase, startedAt, completedAt, requestMessageId, sinceTurn, error, lastMessageType, lastMessageAt, }) {
52
+ this.phase = phase;
53
+ this.startedAt = startedAt;
54
+ this.completedAt = completedAt;
55
+ this.requestMessageId = requestMessageId;
56
+ this.sinceTurn = sinceTurn;
57
+ this.error = error;
58
+ this.lastMessageType = lastMessageType;
59
+ this.lastMessageAt = lastMessageAt;
60
+ }
61
+ static idle() {
62
+ return new ChatThreadSessionLoadState({ phase: ChatThreadSessionLoadPhase.Idle });
63
+ }
64
+ get isLoading() {
65
+ return this.phase === ChatThreadSessionLoadPhase.Loading;
66
+ }
67
+ }
68
+ exports.ChatThreadSessionLoadState = ChatThreadSessionLoadState;
69
+ class ChatThreadStartResult {
70
+ constructor({ session, threadPath, realtimeConnection }) {
71
+ this.session = session;
72
+ this.threadPath = threadPath;
73
+ this.realtimeConnection = realtimeConnection;
74
+ }
75
+ }
76
+ exports.ChatThreadStartResult = ChatThreadStartResult;
77
+ class EventQueue {
78
+ constructor() {
79
+ this.items = [];
80
+ this.waiters = [];
81
+ }
82
+ add(item) {
83
+ const waiter = this.waiters.shift();
84
+ if (waiter != null) {
85
+ waiter({ value: item, done: false });
86
+ return;
87
+ }
88
+ this.items.push(item);
89
+ }
90
+ get stream() {
91
+ return {
92
+ [Symbol.asyncIterator]: () => ({
93
+ next: async () => {
94
+ const item = this.items.shift();
95
+ if (item !== undefined) {
96
+ return { value: item, done: false };
97
+ }
98
+ return new Promise((resolve) => this.waiters.push(resolve));
99
+ },
100
+ }),
101
+ };
102
+ }
103
+ }
104
+ class BaseChatClient extends change_emitter_js_1.ChangeEmitter {
105
+ constructor() {
106
+ super(...arguments);
107
+ this.sessionsByPath = new Map();
108
+ this.pendingStartRequests = new Map();
109
+ this.eventQueue = new EventQueue();
110
+ }
111
+ get events() {
112
+ return this.eventQueue.stream;
113
+ }
114
+ get connectionStatus() {
115
+ return this._connectionStatus;
116
+ }
117
+ get sessions() {
118
+ return [...this.sessionsByPath.values()];
119
+ }
120
+ async start() { }
121
+ async stop() { }
122
+ agentParticipant() {
123
+ return null;
124
+ }
125
+ localParticipantName() {
126
+ return undefined;
127
+ }
128
+ cleanParticipantName(value) {
129
+ return nonEmptyTrimmed(value);
130
+ }
131
+ openThread(threadPath, { load = true, sinceTurn, reloadIfOpen = false } = {}) {
132
+ const normalized = threadPath.trim();
133
+ if (normalized === "") {
134
+ throw new TypeError("thread path cannot be empty");
135
+ }
136
+ const existing = this.sessionsByPath.get(normalized);
137
+ if (existing != null) {
138
+ if (!existing.isOpen || reloadIfOpen) {
139
+ void existing.open({ load, sinceTurn });
140
+ }
141
+ return existing;
142
+ }
143
+ const created = new ChatThreadSession({ client: this, threadPath: normalized });
144
+ this.sessionsByPath.set(normalized, created);
145
+ void created.open({ load, sinceTurn });
146
+ this.notifyListeners();
147
+ return created;
148
+ }
149
+ async startThread({ messageId, message, attachments, name, provider, model, voice, outputModalities, realtimeProtocol, senderName, clientToolkits, omitContent = false, }) {
150
+ const resolvedMessageId = messageId == null || messageId.trim() === "" ? (0, uuid_1.v4)() : messageId.trim();
151
+ const resolvedSenderName = this.cleanParticipantName(senderName) ?? this.localParticipantName();
152
+ const payload = new agent_messages_js_1.StartThread({
153
+ messageId: resolvedMessageId,
154
+ content: omitContent ? undefined : (0, agent_messages_js_1.agentInputContent)({ text: message, attachments }),
155
+ name: nonEmptyTrimmed(name),
156
+ provider: nonEmptyTrimmed(provider),
157
+ model: nonEmptyTrimmed(model),
158
+ voice: nonEmptyTrimmed(voice),
159
+ outputModalities: outputModalities != null && outputModalities.length > 0 ? outputModalities : undefined,
160
+ realtimeProtocol: nonEmptyTrimmed(realtimeProtocol),
161
+ senderName: resolvedSenderName,
162
+ clientToolkits: clientToolkits != null && clientToolkits.length > 0 ? clientToolkits : undefined,
163
+ });
164
+ const completer = new meshagent_1.Completer();
165
+ this.pendingStartRequests.set(resolvedMessageId, completer);
166
+ try {
167
+ await this.sendAgentMessage(payload);
168
+ const response = await completer.fut;
169
+ const threadPath = "threadId" in response
170
+ ? String(response.threadId ?? "").trim()
171
+ : "";
172
+ if (threadPath === "") {
173
+ throw new Error("Agent did not return a thread_id for the new thread.");
174
+ }
175
+ const session = this.openThread(threadPath, { load: false });
176
+ if (!omitContent) {
177
+ session.addAgentMessage(new AgentMessageEvent({ message: payload }));
178
+ }
179
+ return new ChatThreadStartResult({
180
+ session,
181
+ threadPath,
182
+ realtimeConnection: response.type === agent_messages_js_1.agentThreadStartedType && response.realtimeConnection != null
183
+ ? response.realtimeConnection.toJson()
184
+ : undefined,
185
+ });
186
+ }
187
+ finally {
188
+ this.pendingStartRequests.delete(resolvedMessageId);
189
+ }
190
+ }
191
+ handleAgentMessage(message, { attachment } = {}) {
192
+ if (message.type === agent_messages_js_1.agentConnectionStatusType) {
193
+ this._connectionStatus = message;
194
+ for (const session of this.sessionsByPath.values()) {
195
+ if (session.isOpen) {
196
+ session.addAgentMessage(new AgentMessageEvent({ message, attachment }));
197
+ }
198
+ }
199
+ }
200
+ this.eventQueue.add(new AgentMessageEvent({ message, attachment }));
201
+ const sourceMessageId = sourceMessageIdFor(message);
202
+ if ((message.type === agent_messages_js_1.agentThreadStartedType || message.type === agent_messages_js_1.agentThreadStartRejectedType) &&
203
+ sourceMessageId != null &&
204
+ sourceMessageId.trim() !== "") {
205
+ const pending = this.pendingStartRequests.get(sourceMessageId.trim());
206
+ if (pending != null && !pending.completed) {
207
+ pending.complete(message);
208
+ }
209
+ }
210
+ const threadPath = "threadId" in message ? String(message.threadId).trim() : "";
211
+ if (threadPath === "") {
212
+ this.notifyListeners();
213
+ return;
214
+ }
215
+ this.sessionsByPath.get(threadPath)?.addAgentMessage(new AgentMessageEvent({ message, attachment }));
216
+ this.notifyListeners();
217
+ }
218
+ emitConnectionStatus({ status, message, reason, retryDelay, }) {
219
+ const event = new agent_messages_js_1.AgentConnectionStatus({
220
+ status,
221
+ message,
222
+ reason,
223
+ retryInSeconds: retryDelay == null ? undefined : retryDelay / 1000,
224
+ });
225
+ this._connectionStatus = event;
226
+ this.eventQueue.add(new AgentMessageEvent({ message: event }));
227
+ for (const session of this.sessionsByPath.values()) {
228
+ if (session.isOpen) {
229
+ session.addAgentMessage(new AgentMessageEvent({ message: event }));
230
+ }
231
+ }
232
+ this.notifyListeners();
233
+ }
234
+ removeThreadSession(threadPath) {
235
+ const normalized = threadPath.trim();
236
+ const removed = this.sessionsByPath.get(normalized);
237
+ this.sessionsByPath.delete(normalized);
238
+ removed?.markClosed({ notify: false });
239
+ if (removed != null) {
240
+ this.notifyListeners();
241
+ }
242
+ }
243
+ }
244
+ exports.BaseChatClient = BaseChatClient;
245
+ class MessagingChatClient extends BaseChatClient {
246
+ constructor({ room, agentName }) {
247
+ super();
248
+ this.pendingParticipantWaits = new Map();
249
+ this.roomAbortController = new AbortController();
250
+ this.started = false;
251
+ this.onMessagingChanged = () => {
252
+ const participant = this.agentParticipant();
253
+ if (participant != null) {
254
+ this.emitConnectionStatus({ status: "connected", message: "Agent messaging connected" });
255
+ for (const wait of this.pendingParticipantWaits.values()) {
256
+ if (!wait.completed) {
257
+ wait.complete(participant);
258
+ }
259
+ }
260
+ }
261
+ this.notifyListeners();
262
+ };
263
+ this.room = room;
264
+ this.agentName = agentName;
265
+ this.room.messaging.addListener("message", this.onMessagingChanged);
266
+ this.roomPump = this.consumeRoomEvents();
267
+ }
268
+ localParticipantName() {
269
+ const name = this.room.localParticipant?.getAttribute("name");
270
+ return typeof name === "string" ? this.cleanParticipantName(name) : undefined;
271
+ }
272
+ async start() {
273
+ if (this.started) {
274
+ return;
275
+ }
276
+ this.started = true;
277
+ this.room.messaging.start();
278
+ this.room.messaging.enable();
279
+ }
280
+ async stop() {
281
+ this.started = false;
282
+ this.roomAbortController.abort();
283
+ this.room.messaging.removeListener("message", this.onMessagingChanged);
284
+ for (const wait of this.pendingParticipantWaits.values()) {
285
+ if (!wait.completed) {
286
+ wait.completeError(new Error("Chat client stopped while waiting for an agent participant."));
287
+ }
288
+ }
289
+ this.pendingParticipantWaits.clear();
290
+ await this.roomPump?.catch(() => undefined);
291
+ }
292
+ agentParticipant() {
293
+ const normalizedAgentName = this.agentName?.trim();
294
+ for (const participant of this.room.messaging.remoteParticipants) {
295
+ if (normalizedAgentName != null && normalizedAgentName !== "" && participant.getAttribute("name") !== normalizedAgentName) {
296
+ continue;
297
+ }
298
+ if (participant.getAttribute("supports_agent_messages") === true) {
299
+ return participant;
300
+ }
301
+ }
302
+ return null;
303
+ }
304
+ async waitForAgentParticipant({ waitKey } = {}) {
305
+ const existing = this.agentParticipant();
306
+ if (existing != null) {
307
+ return existing;
308
+ }
309
+ const key = waitKey == null || waitKey.trim() === "" ? (0, uuid_1.v4)() : waitKey.trim();
310
+ const completer = new meshagent_1.Completer();
311
+ this.pendingParticipantWaits.set(key, completer);
312
+ this.onMessagingChanged();
313
+ try {
314
+ return await completer.fut;
315
+ }
316
+ finally {
317
+ this.pendingParticipantWaits.delete(key);
318
+ }
319
+ }
320
+ async sendAgentMessage(message, { attachment, ignoreOffline = false } = {}) {
321
+ await this.start();
322
+ const participant = this.agentParticipant() ?? await this.waitForAgentParticipant({ waitKey: message.messageId });
323
+ await this.room.messaging.sendMessage({
324
+ to: participant,
325
+ type: agent_messages_js_1.agentRoomMessageType,
326
+ message: message.toJson(),
327
+ attachment,
328
+ ignoreOffline,
329
+ });
330
+ }
331
+ async consumeRoomEvents() {
332
+ try {
333
+ for await (const event of this.room.listen({ abortSignal: this.roomAbortController.signal })) {
334
+ this.onRoomEvent(event);
335
+ }
336
+ }
337
+ catch {
338
+ if (!this.roomAbortController.signal.aborted) {
339
+ throw new Error("chat client room event listener stopped unexpectedly");
340
+ }
341
+ }
342
+ }
343
+ onRoomEvent(event) {
344
+ if (!(event instanceof meshagent_1.RoomMessageEvent) || event.message.type !== agent_messages_js_1.agentRoomMessageType) {
345
+ return;
346
+ }
347
+ const participant = this.agentParticipant();
348
+ if (participant == null || event.message.fromParticipantId !== participant.id) {
349
+ return;
350
+ }
351
+ const message = event.message.message;
352
+ const rawPayload = typeof message.type === "string" ? message : message.payload;
353
+ if (rawPayload != null && typeof rawPayload === "object" && !Array.isArray(rawPayload)) {
354
+ this.handleAgentMessage(agent_messages_js_1.AgentMessage.fromJson(rawPayload), { attachment: event.message.attachment });
355
+ }
356
+ }
357
+ }
358
+ exports.MessagingChatClient = MessagingChatClient;
359
+ class ChatThreadSession extends change_emitter_js_1.ChangeEmitter {
360
+ constructor({ client, threadPath }) {
361
+ super();
362
+ this._messages = [];
363
+ this.pendingInputsById = new Map();
364
+ this.openState = false;
365
+ this.loadStateValue = ChatThreadSessionLoadState.idle();
366
+ this.client = client;
367
+ this.threadPath = threadPath;
368
+ }
369
+ get messages() {
370
+ return [...this._messages];
371
+ }
372
+ get pendingInputs() {
373
+ return [...this.pendingInputsById.values()];
374
+ }
375
+ get isOpen() {
376
+ return this.openState;
377
+ }
378
+ get loadState() {
379
+ return this.loadStateValue;
380
+ }
381
+ get isLoading() {
382
+ return this.loadStateValue.isLoading;
383
+ }
384
+ get lastCompletedTurnId() {
385
+ return this.lastCompletedTurnIdValue;
386
+ }
387
+ async open({ load = true, sinceTurn } = {}) {
388
+ if (this.openState) {
389
+ if (load) {
390
+ const openThread = new agent_messages_js_1.OpenThread({ threadId: this.threadPath, load: true, sinceTurn });
391
+ this.setLoadState(this.loadingStateForOpen(openThread, sinceTurn));
392
+ try {
393
+ await this.client.sendAgentMessage(openThread, { ignoreOffline: true });
394
+ await this.requestModels({ ignoreOffline: true });
395
+ }
396
+ catch (error) {
397
+ this.setLoadState(this.failedLoadState(error));
398
+ throw error;
399
+ }
400
+ }
401
+ return;
402
+ }
403
+ this.openState = true;
404
+ const openThread = new agent_messages_js_1.OpenThread({ threadId: this.threadPath, load, sinceTurn: load ? sinceTurn : undefined });
405
+ if (load) {
406
+ this.setLoadState(this.loadingStateForOpen(openThread, sinceTurn));
407
+ }
408
+ else {
409
+ this.notifyListeners();
410
+ }
411
+ try {
412
+ await this.client.sendAgentMessage(openThread, { ignoreOffline: true });
413
+ await this.requestModels({ ignoreOffline: true });
414
+ }
415
+ catch (error) {
416
+ this.setLoadState(this.failedLoadState(error));
417
+ throw error;
418
+ }
419
+ }
420
+ async close() {
421
+ if (!this.openState) {
422
+ return;
423
+ }
424
+ this.markClosed();
425
+ await this.client.sendAgentMessage(new agent_messages_js_1.CloseThread({ threadId: this.threadPath }), { ignoreOffline: true });
426
+ }
427
+ requestModels({ ignoreOffline = false } = {}) {
428
+ return this.client.sendAgentMessage(new agent_messages_js_1.ModelsRequest({ messageId: (0, uuid_1.v4)() }), { ignoreOffline });
429
+ }
430
+ changeModel({ provider, model, voice }) {
431
+ return this.client.sendAgentMessage(new agent_messages_js_1.ChangeModel({
432
+ threadId: this.threadPath,
433
+ messageId: (0, uuid_1.v4)(),
434
+ provider,
435
+ model,
436
+ voice: nonEmptyTrimmed(voice),
437
+ }));
438
+ }
439
+ interruptTurn(turnId) {
440
+ return this.client.sendAgentMessage(new agent_messages_js_1.TurnInterrupt({ threadId: this.threadPath, turnId }));
441
+ }
442
+ respondToClientToolCall({ turnId, requestId, response }) {
443
+ return this.client.sendAgentMessage(new agent_messages_js_1.AgentClientToolCallResponse({
444
+ threadId: this.threadPath,
445
+ turnId,
446
+ requestId,
447
+ response,
448
+ }));
449
+ }
450
+ async sendText({ messageId, text, attachments, steer = false, turnId, provider, model, voice, outputModalities, senderName, clientToolkits, }) {
451
+ const resolvedMessageId = messageId == null || messageId.trim() === "" ? (0, uuid_1.v4)() : messageId.trim();
452
+ const payload = steer
453
+ ? new agent_messages_js_1.TurnSteer({
454
+ threadId: this.threadPath,
455
+ messageId: resolvedMessageId,
456
+ senderName: nonEmptyTrimmed(senderName),
457
+ turnId: nonEmptyTrimmed(turnId) ?? resolvedMessageId,
458
+ content: (0, agent_messages_js_1.agentInputContent)({ text, attachments }),
459
+ })
460
+ : new agent_messages_js_1.TurnStart({
461
+ threadId: this.threadPath,
462
+ messageId: resolvedMessageId,
463
+ senderName: nonEmptyTrimmed(senderName),
464
+ content: (0, agent_messages_js_1.agentInputContent)({ text, attachments }),
465
+ provider: nonEmptyTrimmed(provider),
466
+ model: nonEmptyTrimmed(model),
467
+ voice: nonEmptyTrimmed(voice),
468
+ outputModalities: outputModalities != null && outputModalities.length > 0 ? outputModalities : undefined,
469
+ clientToolkits: clientToolkits != null && clientToolkits.length > 0 ? clientToolkits : undefined,
470
+ });
471
+ this.markPending(new PendingAgentInput({
472
+ messageId: resolvedMessageId,
473
+ messageType: payload.type,
474
+ threadPath: this.threadPath,
475
+ payload,
476
+ createdAt: new Date(),
477
+ awaitingAcceptance: true,
478
+ awaitingApplication: true,
479
+ }));
480
+ this.addAgentMessage(new AgentMessageEvent({ message: payload }));
481
+ try {
482
+ await this.client.sendAgentMessage(payload);
483
+ return resolvedMessageId;
484
+ }
485
+ catch (error) {
486
+ this.pendingInputsById.delete(resolvedMessageId);
487
+ this.notifyListeners();
488
+ throw error;
489
+ }
490
+ }
491
+ async sendRealtimeAudioChunk({ chunk, format }) {
492
+ await this.client.sendAgentMessage(new agent_messages_js_1.AgentRealtimeAudioChunk({
493
+ threadId: this.threadPath,
494
+ messageId: (0, uuid_1.v4)(),
495
+ format,
496
+ }), { attachment: chunk });
497
+ }
498
+ async commitRealtimeAudio({ turnId, provider, model, voice, outputModalities, }) {
499
+ const messageId = (0, uuid_1.v4)();
500
+ await this.client.sendAgentMessage(new agent_messages_js_1.AgentRealtimeAudioCommit({
501
+ threadId: this.threadPath,
502
+ messageId,
503
+ turnId,
504
+ }));
505
+ await this.client.sendAgentMessage(new agent_messages_js_1.TurnStart({
506
+ threadId: this.threadPath,
507
+ messageId: (0, uuid_1.v4)(),
508
+ turnId,
509
+ provider: nonEmptyTrimmed(provider),
510
+ model: nonEmptyTrimmed(model),
511
+ voice: nonEmptyTrimmed(voice),
512
+ outputModalities: outputModalities != null && outputModalities.length > 0 ? outputModalities : undefined,
513
+ }));
514
+ return messageId;
515
+ }
516
+ deleteThread(threadPath) {
517
+ return this.client.sendAgentMessage(new agent_messages_js_1.DeleteThread({ threadId: threadPath }));
518
+ }
519
+ renameThread(threadPath, name) {
520
+ return this.client.sendAgentMessage(new agent_messages_js_1.RenameThread({ threadId: threadPath, name }));
521
+ }
522
+ addAgentMessage(event) {
523
+ this._messages.push(event);
524
+ const message = event.message;
525
+ const type = message.type;
526
+ this.lastAgentMessageType = type;
527
+ this.lastAgentMessageAt = new Date();
528
+ const messageId = message.messageId;
529
+ const sourceMessageId = sourceMessageIdFor(message);
530
+ if (type === agent_messages_js_1.agentTurnStartType || type === agent_messages_js_1.agentTurnSteerType) {
531
+ const normalizedMessageId = messageId.trim();
532
+ if (normalizedMessageId !== "") {
533
+ this.markPending(new PendingAgentInput({
534
+ messageId: normalizedMessageId,
535
+ messageType: type,
536
+ threadPath: this.threadPath,
537
+ payload: message,
538
+ createdAt: new Date(),
539
+ awaitingAcceptance: true,
540
+ awaitingApplication: true,
541
+ }));
542
+ }
543
+ }
544
+ else if (type === agent_messages_js_1.agentTurnStartAcceptedType || type === agent_messages_js_1.agentTurnSteerAcceptedType) {
545
+ this.updatePending(sourceMessageId, { awaitingAcceptance: false, awaitingApplication: true });
546
+ }
547
+ else if (type === agent_messages_js_1.agentTurnStartedType || type === agent_messages_js_1.agentTurnSteeredType) {
548
+ if (sourceMessageId != null) {
549
+ this.pendingInputsById.delete(sourceMessageId);
550
+ }
551
+ }
552
+ else if (type === agent_messages_js_1.agentTurnStartRejectedType || type === agent_messages_js_1.agentTurnSteerRejectedType) {
553
+ if (sourceMessageId != null) {
554
+ this.pendingInputsById.delete(sourceMessageId);
555
+ }
556
+ }
557
+ else if (type === agent_messages_js_1.agentTurnEndedType || type === agent_messages_js_1.agentThreadClearedType) {
558
+ this.pendingInputsById.clear();
559
+ if (message.type === agent_messages_js_1.agentTurnEndedType && "turnId" in message && typeof message.turnId === "string" && message.turnId.trim() !== "") {
560
+ this.lastCompletedTurnIdValue = message.turnId.trim();
561
+ }
562
+ }
563
+ else if (type === agent_messages_js_1.agentThreadLoadedType) {
564
+ this.setLoadState(new ChatThreadSessionLoadState({
565
+ phase: ChatThreadSessionLoadPhase.Loaded,
566
+ startedAt: this.loadStateValue.startedAt,
567
+ completedAt: this.lastAgentMessageAt,
568
+ requestMessageId: this.loadStateValue.requestMessageId,
569
+ sinceTurn: this.loadStateValue.sinceTurn,
570
+ lastMessageType: type,
571
+ lastMessageAt: this.lastAgentMessageAt,
572
+ }), { notify: false });
573
+ }
574
+ this.notifyListeners();
575
+ }
576
+ markClosed({ notify = true } = {}) {
577
+ this.openState = false;
578
+ this.loadStateValue = new ChatThreadSessionLoadState({
579
+ phase: ChatThreadSessionLoadPhase.Idle,
580
+ lastMessageType: this.lastAgentMessageType,
581
+ lastMessageAt: this.lastAgentMessageAt,
582
+ });
583
+ if (notify) {
584
+ this.notifyListeners();
585
+ }
586
+ }
587
+ loadingStateForOpen(request, sinceTurn) {
588
+ return new ChatThreadSessionLoadState({
589
+ phase: ChatThreadSessionLoadPhase.Loading,
590
+ startedAt: new Date(),
591
+ requestMessageId: request.messageId,
592
+ sinceTurn,
593
+ lastMessageType: this.lastAgentMessageType,
594
+ lastMessageAt: this.lastAgentMessageAt,
595
+ });
596
+ }
597
+ failedLoadState(error) {
598
+ return new ChatThreadSessionLoadState({
599
+ phase: ChatThreadSessionLoadPhase.Failed,
600
+ startedAt: this.loadStateValue.startedAt,
601
+ completedAt: new Date(),
602
+ requestMessageId: this.loadStateValue.requestMessageId,
603
+ sinceTurn: this.loadStateValue.sinceTurn,
604
+ error: String(error),
605
+ lastMessageType: this.lastAgentMessageType,
606
+ lastMessageAt: this.lastAgentMessageAt,
607
+ });
608
+ }
609
+ setLoadState(loadState, { notify = true } = {}) {
610
+ this.loadStateValue = loadState;
611
+ if (notify) {
612
+ this.notifyListeners();
613
+ }
614
+ }
615
+ markPending(pending) {
616
+ this.pendingInputsById.set(pending.messageId, pending);
617
+ }
618
+ updatePending(messageId, { awaitingAcceptance, awaitingApplication, awaitingOnline, }) {
619
+ const normalized = messageId?.trim();
620
+ if (normalized == null || normalized === "") {
621
+ return;
622
+ }
623
+ const existing = this.pendingInputsById.get(normalized);
624
+ if (existing == null) {
625
+ return;
626
+ }
627
+ this.pendingInputsById.set(normalized, existing.copyWith({
628
+ awaitingAcceptance,
629
+ awaitingApplication,
630
+ awaitingOnline,
631
+ }));
632
+ }
633
+ }
634
+ exports.ChatThreadSession = ChatThreadSession;
635
+ function sourceMessageIdFor(message) {
636
+ const value = "sourceMessageId" in message ? message.sourceMessageId : undefined;
637
+ return typeof value === "string" ? value : undefined;
638
+ }
639
+ function nonEmptyTrimmed(value) {
640
+ const normalized = value?.trim();
641
+ return normalized == null || normalized === "" ? undefined : normalized;
642
+ }