@antipopp/agno-client 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -1
- package/dist/index.d.mts +43 -19
- package/dist/index.d.ts +43 -19
- package/dist/index.js +1135 -478
- package/dist/index.mjs +1137 -478
- package/package.json +8 -4
package/dist/index.js
CHANGED
|
@@ -35,89 +35,11 @@ __export(src_exports, {
|
|
|
35
35
|
RunEvent: () => import_agno_types3.RunEvent
|
|
36
36
|
});
|
|
37
37
|
module.exports = __toCommonJS(src_exports);
|
|
38
|
+
var import_agno_types3 = require("@antipopp/agno-types");
|
|
38
39
|
|
|
39
40
|
// src/client.ts
|
|
40
|
-
var import_eventemitter3 = __toESM(require("eventemitter3"));
|
|
41
41
|
var import_agno_types2 = require("@antipopp/agno-types");
|
|
42
|
-
|
|
43
|
-
// src/stores/message-store.ts
|
|
44
|
-
var MessageStore = class {
|
|
45
|
-
constructor() {
|
|
46
|
-
this.messages = [];
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Get all messages
|
|
50
|
-
*/
|
|
51
|
-
getMessages() {
|
|
52
|
-
return [...this.messages];
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Set messages (replaces all)
|
|
56
|
-
*/
|
|
57
|
-
setMessages(messages) {
|
|
58
|
-
this.messages = [...messages];
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Add a message
|
|
62
|
-
*/
|
|
63
|
-
addMessage(message) {
|
|
64
|
-
this.messages = [...this.messages, message];
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Update the last message
|
|
68
|
-
*/
|
|
69
|
-
updateLastMessage(updater) {
|
|
70
|
-
if (this.messages.length === 0)
|
|
71
|
-
return void 0;
|
|
72
|
-
const lastMessage = this.messages[this.messages.length - 1];
|
|
73
|
-
const updatedMessage = updater(lastMessage);
|
|
74
|
-
this.messages = [
|
|
75
|
-
...this.messages.slice(0, -1),
|
|
76
|
-
updatedMessage
|
|
77
|
-
];
|
|
78
|
-
return updatedMessage;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Update a specific message by index
|
|
82
|
-
*/
|
|
83
|
-
updateMessage(index, updater) {
|
|
84
|
-
if (index < 0 || index >= this.messages.length)
|
|
85
|
-
return void 0;
|
|
86
|
-
const message = this.messages[index];
|
|
87
|
-
const updatedMessage = updater(message);
|
|
88
|
-
this.messages = [
|
|
89
|
-
...this.messages.slice(0, index),
|
|
90
|
-
updatedMessage,
|
|
91
|
-
...this.messages.slice(index + 1)
|
|
92
|
-
];
|
|
93
|
-
return updatedMessage;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Remove last N messages
|
|
97
|
-
*/
|
|
98
|
-
removeLastMessages(count) {
|
|
99
|
-
this.messages = this.messages.slice(0, -count);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Clear all messages
|
|
103
|
-
*/
|
|
104
|
-
clear() {
|
|
105
|
-
this.messages = [];
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Get the last message
|
|
109
|
-
*/
|
|
110
|
-
getLastMessage() {
|
|
111
|
-
return this.messages.length > 0 ? this.messages[this.messages.length - 1] : void 0;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Check if last message has streaming error
|
|
115
|
-
*/
|
|
116
|
-
hasLastMessageError() {
|
|
117
|
-
const lastMessage = this.getLastMessage();
|
|
118
|
-
return lastMessage?.streamingError === true;
|
|
119
|
-
}
|
|
120
|
-
};
|
|
42
|
+
var import_eventemitter3 = __toESM(require("eventemitter3"));
|
|
121
43
|
|
|
122
44
|
// src/managers/config-manager.ts
|
|
123
45
|
var ConfigManager = class {
|
|
@@ -262,6 +184,18 @@ var ConfigManager = class {
|
|
|
262
184
|
setParams(params) {
|
|
263
185
|
this.updateField("params", params);
|
|
264
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Get global dependencies
|
|
189
|
+
*/
|
|
190
|
+
getDependencies() {
|
|
191
|
+
return this.config.dependencies;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Set global dependencies
|
|
195
|
+
*/
|
|
196
|
+
setDependencies(dependencies) {
|
|
197
|
+
this.updateField("dependencies", dependencies);
|
|
198
|
+
}
|
|
265
199
|
/**
|
|
266
200
|
* Get current entity ID (agent or team based on mode)
|
|
267
201
|
*/
|
|
@@ -275,14 +209,14 @@ var ConfigManager = class {
|
|
|
275
209
|
const mode = this.getMode();
|
|
276
210
|
const endpoint = this.getEndpoint();
|
|
277
211
|
const entityId = this.getCurrentEntityId();
|
|
278
|
-
if (!entityId)
|
|
212
|
+
if (!entityId) {
|
|
279
213
|
return null;
|
|
214
|
+
}
|
|
280
215
|
const encodedEntityId = encodeURIComponent(entityId);
|
|
281
216
|
if (mode === "team") {
|
|
282
217
|
return `${endpoint}/teams/${encodedEntityId}/runs`;
|
|
283
|
-
} else {
|
|
284
|
-
return `${endpoint}/agents/${encodedEntityId}/runs`;
|
|
285
218
|
}
|
|
219
|
+
return `${endpoint}/agents/${encodedEntityId}/runs`;
|
|
286
220
|
}
|
|
287
221
|
/**
|
|
288
222
|
* Build request headers by merging global headers, per-request headers, and auth token.
|
|
@@ -305,7 +239,7 @@ var ConfigManager = class {
|
|
|
305
239
|
}
|
|
306
240
|
const authToken = this.getAuthToken();
|
|
307
241
|
if (authToken) {
|
|
308
|
-
headers
|
|
242
|
+
headers.Authorization = `Bearer ${authToken}`;
|
|
309
243
|
}
|
|
310
244
|
return headers;
|
|
311
245
|
}
|
|
@@ -329,6 +263,29 @@ var ConfigManager = class {
|
|
|
329
263
|
}
|
|
330
264
|
return new URLSearchParams(params);
|
|
331
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* Build dependencies by merging global dependencies and per-request dependencies.
|
|
268
|
+
* Merge order (lowest to highest precedence):
|
|
269
|
+
* 1. Global dependencies from config
|
|
270
|
+
* 2. Per-request dependencies (overrides global)
|
|
271
|
+
*
|
|
272
|
+
* @param perRequestDependencies - Optional dependencies for this specific request
|
|
273
|
+
* @returns Merged dependencies object, or undefined if no dependencies are configured
|
|
274
|
+
*/
|
|
275
|
+
buildDependencies(perRequestDependencies) {
|
|
276
|
+
const dependencies = {};
|
|
277
|
+
const globalDependencies = this.getDependencies();
|
|
278
|
+
if (globalDependencies) {
|
|
279
|
+
Object.assign(dependencies, globalDependencies);
|
|
280
|
+
}
|
|
281
|
+
if (perRequestDependencies) {
|
|
282
|
+
Object.assign(dependencies, perRequestDependencies);
|
|
283
|
+
}
|
|
284
|
+
if (Object.keys(dependencies).length === 0) {
|
|
285
|
+
return void 0;
|
|
286
|
+
}
|
|
287
|
+
return dependencies;
|
|
288
|
+
}
|
|
332
289
|
};
|
|
333
290
|
|
|
334
291
|
// src/managers/session-manager.ts
|
|
@@ -415,75 +372,470 @@ var SessionManager = class {
|
|
|
415
372
|
convertRunsToMessages(runs) {
|
|
416
373
|
const messages = [];
|
|
417
374
|
for (const run of runs) {
|
|
418
|
-
const timestamp =
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
if (run.tools && Array.isArray(run.tools)) {
|
|
428
|
-
for (const tool of run.tools) {
|
|
429
|
-
const toolObj = tool;
|
|
430
|
-
const toolCall = {
|
|
431
|
-
role: "tool",
|
|
432
|
-
content: toolObj.content ?? "",
|
|
433
|
-
tool_call_id: toolObj.tool_call_id ?? "",
|
|
434
|
-
tool_name: toolObj.tool_name ?? "",
|
|
435
|
-
tool_args: toolObj.tool_args ?? {},
|
|
436
|
-
tool_call_error: toolObj.tool_call_error ?? false,
|
|
437
|
-
metrics: toolObj.metrics ?? { time: 0 },
|
|
438
|
-
created_at: timestamp
|
|
439
|
-
};
|
|
440
|
-
toolCalls.push(toolCall);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
if (run.reasoning_messages && Array.isArray(run.reasoning_messages)) {
|
|
444
|
-
for (const msg of run.reasoning_messages) {
|
|
445
|
-
const reasoningMsg = msg;
|
|
446
|
-
if (reasoningMsg.role === "tool") {
|
|
447
|
-
toolCalls.push({
|
|
448
|
-
role: "tool",
|
|
449
|
-
content: reasoningMsg.content ?? "",
|
|
450
|
-
tool_call_id: reasoningMsg.tool_call_id ?? "",
|
|
451
|
-
tool_name: reasoningMsg.tool_name ?? "",
|
|
452
|
-
tool_args: reasoningMsg.tool_args ?? {},
|
|
453
|
-
tool_call_error: reasoningMsg.tool_call_error ?? false,
|
|
454
|
-
metrics: reasoningMsg.metrics ?? { time: 0 },
|
|
455
|
-
created_at: reasoningMsg.created_at ?? timestamp
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
let contentStr = "";
|
|
461
|
-
if (typeof run.content === "string") {
|
|
462
|
-
contentStr = run.content;
|
|
463
|
-
} else if (run.content && typeof run.content === "object") {
|
|
464
|
-
contentStr = JSON.stringify(run.content);
|
|
375
|
+
const timestamp = this.getRunTimestamp(run);
|
|
376
|
+
const inputMedia = this.mergeInputMedia(
|
|
377
|
+
this.extractInputMedia(run.input_media),
|
|
378
|
+
this.extractInputMediaFromMessages(run.messages)
|
|
379
|
+
);
|
|
380
|
+
if (run.run_input || this.hasAnyMedia(inputMedia)) {
|
|
381
|
+
messages.push(
|
|
382
|
+
this.buildUserMessage(run.run_input ?? "", timestamp, inputMedia)
|
|
383
|
+
);
|
|
465
384
|
}
|
|
466
|
-
const
|
|
467
|
-
reasoning_messages: run.reasoning_messages,
|
|
468
|
-
reasoning_steps: run.reasoning_steps,
|
|
469
|
-
references: run.references
|
|
470
|
-
} : void 0;
|
|
385
|
+
const toolCalls = this.extractToolCalls(run, timestamp);
|
|
471
386
|
messages.push({
|
|
472
387
|
role: "agent",
|
|
473
|
-
content:
|
|
388
|
+
content: this.normalizeRunContent(run.content),
|
|
474
389
|
tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
475
|
-
extra_data:
|
|
476
|
-
images: run.images,
|
|
477
|
-
videos: run.videos,
|
|
478
|
-
audio: run.audio,
|
|
479
|
-
|
|
390
|
+
extra_data: this.buildExtraData(run),
|
|
391
|
+
images: this.normalizeImages(run.images),
|
|
392
|
+
videos: this.normalizeVideos(run.videos),
|
|
393
|
+
audio: this.normalizeAudio(run.audio),
|
|
394
|
+
files: this.normalizeFiles(run.files),
|
|
395
|
+
response_audio: run.response_audio ?? void 0,
|
|
480
396
|
created_at: timestamp + 1
|
|
481
397
|
// Agent response is slightly after user message
|
|
482
398
|
});
|
|
483
399
|
}
|
|
484
400
|
return messages;
|
|
485
401
|
}
|
|
402
|
+
getRunTimestamp(run) {
|
|
403
|
+
return run.created_at ? new Date(run.created_at).getTime() / 1e3 : Math.floor(Date.now() / 1e3);
|
|
404
|
+
}
|
|
405
|
+
buildUserMessage(content, createdAt, media) {
|
|
406
|
+
return {
|
|
407
|
+
role: "user",
|
|
408
|
+
content,
|
|
409
|
+
images: media?.images,
|
|
410
|
+
videos: media?.videos,
|
|
411
|
+
audio: media?.audio,
|
|
412
|
+
files: media?.files,
|
|
413
|
+
created_at: createdAt
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
hasAnyMedia(media) {
|
|
417
|
+
return Boolean(
|
|
418
|
+
media.images && media.images.length > 0 || media.videos && media.videos.length > 0 || media.audio && media.audio.length > 0 || media.files && media.files.length > 0
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
isRecord(value) {
|
|
422
|
+
return typeof value === "object" && value !== null;
|
|
423
|
+
}
|
|
424
|
+
getStringValue(record, key) {
|
|
425
|
+
const value = record[key];
|
|
426
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
427
|
+
}
|
|
428
|
+
getNumberOrStringValue(record, key) {
|
|
429
|
+
const value = record[key];
|
|
430
|
+
return typeof value === "number" || typeof value === "string" ? value : void 0;
|
|
431
|
+
}
|
|
432
|
+
buildDataUrl(content, mimeType, fallbackMimeType) {
|
|
433
|
+
const safeMimeType = mimeType || fallbackMimeType;
|
|
434
|
+
return `data:${safeMimeType};base64,${content}`;
|
|
435
|
+
}
|
|
436
|
+
normalizeImage(item) {
|
|
437
|
+
if (!this.isRecord(item)) {
|
|
438
|
+
return void 0;
|
|
439
|
+
}
|
|
440
|
+
const mimeType = this.getStringValue(item, "mime_type");
|
|
441
|
+
const content = this.getStringValue(item, "content");
|
|
442
|
+
const url = this.getStringValue(item, "url") || (content ? this.buildDataUrl(content, mimeType, "image/png") : void 0);
|
|
443
|
+
if (!url) {
|
|
444
|
+
return void 0;
|
|
445
|
+
}
|
|
446
|
+
return {
|
|
447
|
+
url,
|
|
448
|
+
revised_prompt: this.getStringValue(item, "revised_prompt"),
|
|
449
|
+
original_prompt: this.getStringValue(item, "original_prompt"),
|
|
450
|
+
alt_text: this.getStringValue(item, "alt_text"),
|
|
451
|
+
id: this.getStringValue(item, "id"),
|
|
452
|
+
mime_type: mimeType,
|
|
453
|
+
format: this.getStringValue(item, "format")
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
normalizeVideo(item) {
|
|
457
|
+
if (!this.isRecord(item)) {
|
|
458
|
+
return void 0;
|
|
459
|
+
}
|
|
460
|
+
const mimeType = this.getStringValue(item, "mime_type");
|
|
461
|
+
const content = this.getStringValue(item, "content");
|
|
462
|
+
const url = this.getStringValue(item, "url") || (content ? this.buildDataUrl(content, mimeType, "video/mp4") : void 0);
|
|
463
|
+
const normalized = {
|
|
464
|
+
url,
|
|
465
|
+
id: this.getNumberOrStringValue(item, "id"),
|
|
466
|
+
eta: this.getNumberOrStringValue(item, "eta"),
|
|
467
|
+
mime_type: mimeType,
|
|
468
|
+
format: this.getStringValue(item, "format"),
|
|
469
|
+
original_prompt: this.getStringValue(item, "original_prompt"),
|
|
470
|
+
revised_prompt: this.getStringValue(item, "revised_prompt"),
|
|
471
|
+
width: typeof item.width === "number" ? item.width : void 0,
|
|
472
|
+
height: typeof item.height === "number" ? item.height : void 0,
|
|
473
|
+
fps: typeof item.fps === "number" ? item.fps : void 0,
|
|
474
|
+
duration: typeof item.duration === "number" ? item.duration : void 0
|
|
475
|
+
};
|
|
476
|
+
if (normalized.url || normalized.id !== void 0 || normalized.eta !== void 0) {
|
|
477
|
+
return normalized;
|
|
478
|
+
}
|
|
479
|
+
return void 0;
|
|
480
|
+
}
|
|
481
|
+
normalizeAudioEntry(item) {
|
|
482
|
+
if (!this.isRecord(item)) {
|
|
483
|
+
return void 0;
|
|
484
|
+
}
|
|
485
|
+
const mimeType = this.getStringValue(item, "mime_type");
|
|
486
|
+
const content = this.getStringValue(item, "content");
|
|
487
|
+
const url = this.getStringValue(item, "url") || (content ? this.buildDataUrl(content, mimeType, "audio/wav") : void 0);
|
|
488
|
+
const normalized = {
|
|
489
|
+
base64_audio: this.getStringValue(item, "base64_audio"),
|
|
490
|
+
mime_type: mimeType,
|
|
491
|
+
url,
|
|
492
|
+
id: this.getNumberOrStringValue(item, "id"),
|
|
493
|
+
content,
|
|
494
|
+
channels: typeof item.channels === "number" ? item.channels : void 0,
|
|
495
|
+
sample_rate: typeof item.sample_rate === "number" ? item.sample_rate : void 0,
|
|
496
|
+
format: this.getStringValue(item, "format"),
|
|
497
|
+
duration: typeof item.duration === "number" ? item.duration : void 0
|
|
498
|
+
};
|
|
499
|
+
if (normalized.url || normalized.base64_audio || normalized.content || normalized.id !== void 0) {
|
|
500
|
+
return normalized;
|
|
501
|
+
}
|
|
502
|
+
return void 0;
|
|
503
|
+
}
|
|
504
|
+
normalizeFileEntry(item) {
|
|
505
|
+
if (!this.isRecord(item)) {
|
|
506
|
+
return void 0;
|
|
507
|
+
}
|
|
508
|
+
const normalized = {
|
|
509
|
+
id: this.getStringValue(item, "id"),
|
|
510
|
+
url: this.getStringValue(item, "url"),
|
|
511
|
+
filename: this.getStringValue(item, "filename"),
|
|
512
|
+
name: this.getStringValue(item, "name"),
|
|
513
|
+
mime_type: this.getStringValue(item, "mime_type"),
|
|
514
|
+
format: this.getStringValue(item, "format"),
|
|
515
|
+
size: typeof item.size === "number" ? item.size : void 0
|
|
516
|
+
};
|
|
517
|
+
if (normalized.url || normalized.filename || normalized.name || normalized.id) {
|
|
518
|
+
return normalized;
|
|
519
|
+
}
|
|
520
|
+
return void 0;
|
|
521
|
+
}
|
|
522
|
+
normalizeArray(value, normalizer) {
|
|
523
|
+
if (!Array.isArray(value)) {
|
|
524
|
+
return void 0;
|
|
525
|
+
}
|
|
526
|
+
const items = value.map((item) => normalizer(item)).filter((item) => item !== void 0);
|
|
527
|
+
return items.length > 0 ? items : void 0;
|
|
528
|
+
}
|
|
529
|
+
normalizeImages(value) {
|
|
530
|
+
return this.normalizeArray(value, (item) => this.normalizeImage(item));
|
|
531
|
+
}
|
|
532
|
+
normalizeVideos(value) {
|
|
533
|
+
return this.normalizeArray(value, (item) => this.normalizeVideo(item));
|
|
534
|
+
}
|
|
535
|
+
normalizeAudio(value) {
|
|
536
|
+
return this.normalizeArray(value, (item) => this.normalizeAudioEntry(item));
|
|
537
|
+
}
|
|
538
|
+
normalizeFiles(value) {
|
|
539
|
+
return this.normalizeArray(value, (item) => this.normalizeFileEntry(item));
|
|
540
|
+
}
|
|
541
|
+
extractInputMedia(inputMedia) {
|
|
542
|
+
if (!this.isRecord(inputMedia)) {
|
|
543
|
+
return {};
|
|
544
|
+
}
|
|
545
|
+
return {
|
|
546
|
+
images: this.normalizeImages(inputMedia.images),
|
|
547
|
+
videos: this.normalizeVideos(inputMedia.videos),
|
|
548
|
+
audio: this.normalizeAudio(inputMedia.audios ?? inputMedia.audio),
|
|
549
|
+
files: this.normalizeFiles(inputMedia.files)
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
extractInputMediaFromMessages(messages) {
|
|
553
|
+
if (!Array.isArray(messages)) {
|
|
554
|
+
return {};
|
|
555
|
+
}
|
|
556
|
+
for (const message of messages) {
|
|
557
|
+
if (!this.isRecord(message)) {
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
if (this.getStringValue(message, "role") !== "user") {
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
563
|
+
const media = {
|
|
564
|
+
images: this.normalizeImages(message.images ?? message.image),
|
|
565
|
+
videos: this.normalizeVideos(message.videos ?? message.video),
|
|
566
|
+
audio: this.normalizeAudio(message.audios ?? message.audio),
|
|
567
|
+
files: this.normalizeFiles(message.files)
|
|
568
|
+
};
|
|
569
|
+
if (this.hasAnyMedia(media)) {
|
|
570
|
+
return media;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return {};
|
|
574
|
+
}
|
|
575
|
+
mergeInputMedia(primary, fallback) {
|
|
576
|
+
return {
|
|
577
|
+
images: primary.images ?? fallback.images,
|
|
578
|
+
videos: primary.videos ?? fallback.videos,
|
|
579
|
+
audio: primary.audio ?? fallback.audio,
|
|
580
|
+
files: primary.files ?? fallback.files
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
normalizeRunContent(content) {
|
|
584
|
+
if (typeof content === "string") {
|
|
585
|
+
return content;
|
|
586
|
+
}
|
|
587
|
+
if (content && typeof content === "object") {
|
|
588
|
+
return JSON.stringify(content);
|
|
589
|
+
}
|
|
590
|
+
return "";
|
|
591
|
+
}
|
|
592
|
+
buildToolCall(rawTool, fallbackTimestamp) {
|
|
593
|
+
return {
|
|
594
|
+
role: "tool",
|
|
595
|
+
content: rawTool.content ?? "",
|
|
596
|
+
tool_call_id: rawTool.tool_call_id ?? "",
|
|
597
|
+
tool_name: rawTool.tool_name ?? "",
|
|
598
|
+
tool_args: rawTool.tool_args ?? {},
|
|
599
|
+
tool_call_error: rawTool.tool_call_error ?? false,
|
|
600
|
+
metrics: rawTool.metrics ?? { time: 0 },
|
|
601
|
+
created_at: rawTool.created_at ?? fallbackTimestamp
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
extractToolCalls(run, timestamp) {
|
|
605
|
+
const toolCalls = [];
|
|
606
|
+
if (run.tools && Array.isArray(run.tools)) {
|
|
607
|
+
for (const tool of run.tools) {
|
|
608
|
+
toolCalls.push(this.buildToolCall(tool, timestamp));
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (run.reasoning_messages && Array.isArray(run.reasoning_messages)) {
|
|
612
|
+
for (const message of run.reasoning_messages) {
|
|
613
|
+
if (message.role === "tool") {
|
|
614
|
+
toolCalls.push(this.buildToolCall(message, timestamp));
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return toolCalls;
|
|
619
|
+
}
|
|
620
|
+
buildExtraData(run) {
|
|
621
|
+
if (!(run.reasoning_messages || run.reasoning_steps || run.references)) {
|
|
622
|
+
return void 0;
|
|
623
|
+
}
|
|
624
|
+
return {
|
|
625
|
+
reasoning_messages: run.reasoning_messages,
|
|
626
|
+
reasoning_steps: run.reasoning_steps,
|
|
627
|
+
references: run.references
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
// src/parsers/stream-parser.ts
|
|
633
|
+
var StreamResponseHttpError = class extends Error {
|
|
634
|
+
constructor(status, message) {
|
|
635
|
+
super(message);
|
|
636
|
+
this.name = "StreamResponseHttpError";
|
|
637
|
+
this.status = status;
|
|
638
|
+
}
|
|
486
639
|
};
|
|
640
|
+
function isLegacyFormat(data) {
|
|
641
|
+
return typeof data === "object" && data !== null && "event" in data && !("data" in data) && typeof data.event === "string";
|
|
642
|
+
}
|
|
643
|
+
function convertNewFormatToLegacy(newFormatData) {
|
|
644
|
+
const { event, data } = newFormatData;
|
|
645
|
+
let parsedData;
|
|
646
|
+
if (typeof data === "string") {
|
|
647
|
+
try {
|
|
648
|
+
parsedData = JSON.parse(data);
|
|
649
|
+
} catch {
|
|
650
|
+
parsedData = {};
|
|
651
|
+
}
|
|
652
|
+
} else {
|
|
653
|
+
parsedData = data;
|
|
654
|
+
}
|
|
655
|
+
return {
|
|
656
|
+
event,
|
|
657
|
+
...parsedData
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
function processChunk(chunk, onChunk) {
|
|
661
|
+
onChunk(chunk);
|
|
662
|
+
}
|
|
663
|
+
function updateJsonParserState(char, state) {
|
|
664
|
+
if (state.inString) {
|
|
665
|
+
if (state.escapeNext) {
|
|
666
|
+
state.escapeNext = false;
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
if (char === "\\") {
|
|
670
|
+
state.escapeNext = true;
|
|
671
|
+
return false;
|
|
672
|
+
}
|
|
673
|
+
if (char === '"') {
|
|
674
|
+
state.inString = false;
|
|
675
|
+
}
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
if (char === '"') {
|
|
679
|
+
state.inString = true;
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
if (char === "{") {
|
|
683
|
+
state.braceCount++;
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
if (char !== "}") {
|
|
687
|
+
return false;
|
|
688
|
+
}
|
|
689
|
+
state.braceCount--;
|
|
690
|
+
return state.braceCount === 0;
|
|
691
|
+
}
|
|
692
|
+
function findJsonSlice(buffer, fromIndex) {
|
|
693
|
+
const startIndex = buffer.indexOf("{", fromIndex);
|
|
694
|
+
if (startIndex === -1) {
|
|
695
|
+
return void 0;
|
|
696
|
+
}
|
|
697
|
+
const parserState = {
|
|
698
|
+
braceCount: 0,
|
|
699
|
+
inString: false,
|
|
700
|
+
escapeNext: false
|
|
701
|
+
};
|
|
702
|
+
for (let i = startIndex; i < buffer.length; i++) {
|
|
703
|
+
const isJsonComplete = updateJsonParserState(buffer[i], parserState);
|
|
704
|
+
if (isJsonComplete) {
|
|
705
|
+
return { startIndex, endIndex: i };
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
return void 0;
|
|
709
|
+
}
|
|
710
|
+
function logChunkParseError(error, jsonString, position) {
|
|
711
|
+
if (typeof process === "undefined" || process.env?.NODE_ENV !== "development") {
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
console.error("Failed to parse JSON chunk:", {
|
|
715
|
+
error,
|
|
716
|
+
chunk: jsonString.substring(0, 100) + (jsonString.length > 100 ? "..." : ""),
|
|
717
|
+
position
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
function processJsonSlice(jsonString, startIndex, onChunk) {
|
|
721
|
+
try {
|
|
722
|
+
const parsed = JSON.parse(jsonString);
|
|
723
|
+
if (isLegacyFormat(parsed)) {
|
|
724
|
+
processChunk(parsed, onChunk);
|
|
725
|
+
} else {
|
|
726
|
+
processChunk(convertNewFormatToLegacy(parsed), onChunk);
|
|
727
|
+
}
|
|
728
|
+
return true;
|
|
729
|
+
} catch (error) {
|
|
730
|
+
logChunkParseError(error, jsonString, startIndex);
|
|
731
|
+
if (jsonString.length > 1e4) {
|
|
732
|
+
throw new Error(
|
|
733
|
+
`Failed to parse large JSON chunk at position ${startIndex}`
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
return false;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
function parseBuffer(buffer, onChunk) {
|
|
740
|
+
let searchIndex = 0;
|
|
741
|
+
let remainingBuffer = buffer;
|
|
742
|
+
while (true) {
|
|
743
|
+
const jsonSlice = findJsonSlice(remainingBuffer, searchIndex);
|
|
744
|
+
if (!jsonSlice) {
|
|
745
|
+
break;
|
|
746
|
+
}
|
|
747
|
+
const jsonString = remainingBuffer.slice(
|
|
748
|
+
jsonSlice.startIndex,
|
|
749
|
+
jsonSlice.endIndex + 1
|
|
750
|
+
);
|
|
751
|
+
const parsed = processJsonSlice(jsonString, jsonSlice.startIndex, onChunk);
|
|
752
|
+
if (!parsed) {
|
|
753
|
+
searchIndex = jsonSlice.startIndex + 1;
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
remainingBuffer = remainingBuffer.slice(jsonSlice.endIndex + 1).trim();
|
|
757
|
+
searchIndex = 0;
|
|
758
|
+
}
|
|
759
|
+
return remainingBuffer;
|
|
760
|
+
}
|
|
761
|
+
function buildRequestHeaders(headers, requestBody) {
|
|
762
|
+
return {
|
|
763
|
+
...!(requestBody instanceof FormData) && {
|
|
764
|
+
"Content-Type": "application/json"
|
|
765
|
+
},
|
|
766
|
+
...headers
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
async function buildErrorMessage(response) {
|
|
770
|
+
const defaultMessage = `HTTP ${response.status}: ${response.statusText}`;
|
|
771
|
+
const contentType = response.headers.get("content-type");
|
|
772
|
+
if (!contentType?.includes("application/json")) {
|
|
773
|
+
return defaultMessage;
|
|
774
|
+
}
|
|
775
|
+
try {
|
|
776
|
+
const errorData = await response.json();
|
|
777
|
+
return errorData.detail || errorData.message || defaultMessage;
|
|
778
|
+
} catch {
|
|
779
|
+
return defaultMessage;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
async function consumeResponseStream(body, onChunk, onComplete) {
|
|
783
|
+
const reader = body.getReader();
|
|
784
|
+
const decoder = new TextDecoder();
|
|
785
|
+
let buffer = "";
|
|
786
|
+
while (true) {
|
|
787
|
+
const { done, value } = await reader.read();
|
|
788
|
+
if (done) {
|
|
789
|
+
parseBuffer(buffer, onChunk);
|
|
790
|
+
onComplete();
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
buffer += decoder.decode(value, { stream: true });
|
|
794
|
+
buffer = parseBuffer(buffer, onChunk);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
async function streamResponse(options) {
|
|
798
|
+
const {
|
|
799
|
+
apiUrl,
|
|
800
|
+
headers = {},
|
|
801
|
+
params,
|
|
802
|
+
requestBody,
|
|
803
|
+
onChunk,
|
|
804
|
+
onError,
|
|
805
|
+
onComplete,
|
|
806
|
+
signal
|
|
807
|
+
} = options;
|
|
808
|
+
const finalUrl = params?.toString() ? `${apiUrl}?${params.toString()}` : apiUrl;
|
|
809
|
+
try {
|
|
810
|
+
const response = await fetch(finalUrl, {
|
|
811
|
+
method: "POST",
|
|
812
|
+
headers: buildRequestHeaders(headers, requestBody),
|
|
813
|
+
body: requestBody instanceof FormData ? requestBody : JSON.stringify(requestBody),
|
|
814
|
+
signal
|
|
815
|
+
});
|
|
816
|
+
if (!response.ok) {
|
|
817
|
+
const errorMessage = await buildErrorMessage(response);
|
|
818
|
+
throw new StreamResponseHttpError(response.status, errorMessage);
|
|
819
|
+
}
|
|
820
|
+
if (!response.body) {
|
|
821
|
+
throw new Error("No response body");
|
|
822
|
+
}
|
|
823
|
+
await consumeResponseStream(response.body, onChunk, onComplete);
|
|
824
|
+
} catch (error) {
|
|
825
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
if (error instanceof Error) {
|
|
829
|
+
onError(error);
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
if (typeof error === "object" && error !== null && "detail" in error) {
|
|
833
|
+
onError(new Error(String(error.detail)));
|
|
834
|
+
} else {
|
|
835
|
+
onError(new Error(String(error)));
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
487
839
|
|
|
488
840
|
// src/processors/event-processor.ts
|
|
489
841
|
var import_agno_types = require("@antipopp/agno-types");
|
|
@@ -508,14 +860,18 @@ function processToolCall(toolCall, prevToolCalls = []) {
|
|
|
508
860
|
);
|
|
509
861
|
if (existingToolCallIndex >= 0) {
|
|
510
862
|
const updatedToolCalls = [...prevToolCalls];
|
|
511
|
-
updatedToolCalls[existingToolCallIndex]
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
863
|
+
const existing = updatedToolCalls[existingToolCallIndex];
|
|
864
|
+
const merged = { ...existing, ...toolCall };
|
|
865
|
+
if (existing.external_execution && existing.result !== void 0) {
|
|
866
|
+
merged.result = existing.result;
|
|
867
|
+
}
|
|
868
|
+
if (existing.ui_component !== void 0 && !toolCall.ui_component) {
|
|
869
|
+
merged.ui_component = existing.ui_component;
|
|
870
|
+
}
|
|
871
|
+
updatedToolCalls[existingToolCallIndex] = merged;
|
|
515
872
|
return updatedToolCalls;
|
|
516
|
-
} else {
|
|
517
|
-
return [...prevToolCalls, toolCall];
|
|
518
873
|
}
|
|
874
|
+
return [...prevToolCalls, toolCall];
|
|
519
875
|
}
|
|
520
876
|
function processChunkToolCalls(chunk, existingToolCalls = []) {
|
|
521
877
|
let updatedToolCalls = [...existingToolCalls];
|
|
@@ -533,6 +889,105 @@ var EventProcessor = class {
|
|
|
533
889
|
constructor() {
|
|
534
890
|
this.lastContent = "";
|
|
535
891
|
}
|
|
892
|
+
appendRunContent(chunk, updatedMessage) {
|
|
893
|
+
if (typeof chunk.content === "string") {
|
|
894
|
+
const uniqueContent = chunk.content.replace(this.lastContent, "");
|
|
895
|
+
updatedMessage.content = updatedMessage.content + uniqueContent;
|
|
896
|
+
this.lastContent = chunk.content;
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
if (typeof chunk.content !== "string" && chunk.content !== null) {
|
|
900
|
+
const jsonBlock = getJsonMarkdown(chunk.content);
|
|
901
|
+
updatedMessage.content = updatedMessage.content + jsonBlock;
|
|
902
|
+
this.lastContent = jsonBlock;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
applyRunContentFields(chunk, lastMessage, updatedMessage) {
|
|
906
|
+
this.appendRunContent(chunk, updatedMessage);
|
|
907
|
+
updatedMessage.tool_calls = processChunkToolCalls(
|
|
908
|
+
chunk,
|
|
909
|
+
lastMessage.tool_calls
|
|
910
|
+
);
|
|
911
|
+
if (chunk.extra_data?.reasoning_steps) {
|
|
912
|
+
updatedMessage.extra_data = {
|
|
913
|
+
...updatedMessage.extra_data,
|
|
914
|
+
reasoning_steps: chunk.extra_data.reasoning_steps
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
if (chunk.extra_data?.references) {
|
|
918
|
+
updatedMessage.extra_data = {
|
|
919
|
+
...updatedMessage.extra_data,
|
|
920
|
+
references: chunk.extra_data.references
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
924
|
+
if (chunk.images) {
|
|
925
|
+
updatedMessage.images = chunk.images;
|
|
926
|
+
}
|
|
927
|
+
if (chunk.image) {
|
|
928
|
+
const existingImages = updatedMessage.images ?? lastMessage.images ?? [];
|
|
929
|
+
const hasImage = existingImages.some((image) => {
|
|
930
|
+
if (image.id && chunk.image?.id) {
|
|
931
|
+
return image.id === chunk.image.id;
|
|
932
|
+
}
|
|
933
|
+
return image.url === chunk.image?.url;
|
|
934
|
+
});
|
|
935
|
+
if (!hasImage) {
|
|
936
|
+
updatedMessage.images = [...existingImages, chunk.image];
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
if (chunk.videos) {
|
|
940
|
+
updatedMessage.videos = chunk.videos;
|
|
941
|
+
}
|
|
942
|
+
if (chunk.audio) {
|
|
943
|
+
updatedMessage.audio = chunk.audio;
|
|
944
|
+
}
|
|
945
|
+
if (chunk.files) {
|
|
946
|
+
updatedMessage.files = chunk.files;
|
|
947
|
+
}
|
|
948
|
+
if (chunk.response_audio?.transcript && typeof chunk.response_audio.transcript === "string") {
|
|
949
|
+
updatedMessage.response_audio = {
|
|
950
|
+
...updatedMessage.response_audio,
|
|
951
|
+
transcript: (updatedMessage.response_audio?.transcript || "") + chunk.response_audio.transcript
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
applyCompletedFields(chunk, lastMessage, updatedMessage) {
|
|
956
|
+
let updatedContent;
|
|
957
|
+
if (typeof chunk.content === "string") {
|
|
958
|
+
updatedContent = chunk.content;
|
|
959
|
+
} else {
|
|
960
|
+
try {
|
|
961
|
+
updatedContent = JSON.stringify(chunk.content);
|
|
962
|
+
} catch {
|
|
963
|
+
updatedContent = "Error parsing response";
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
updatedMessage.content = updatedContent;
|
|
967
|
+
updatedMessage.tool_calls = processChunkToolCalls(
|
|
968
|
+
chunk,
|
|
969
|
+
lastMessage.tool_calls
|
|
970
|
+
);
|
|
971
|
+
const completedImages = chunk.images ?? (chunk.image ? [chunk.image] : void 0);
|
|
972
|
+
updatedMessage.images = completedImages ?? lastMessage.images;
|
|
973
|
+
updatedMessage.videos = chunk.videos ?? lastMessage.videos;
|
|
974
|
+
updatedMessage.audio = chunk.audio ?? lastMessage.audio;
|
|
975
|
+
updatedMessage.files = chunk.files ?? lastMessage.files;
|
|
976
|
+
updatedMessage.response_audio = chunk.response_audio;
|
|
977
|
+
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
978
|
+
updatedMessage.extra_data = {
|
|
979
|
+
reasoning_steps: chunk.extra_data?.reasoning_steps ?? lastMessage.extra_data?.reasoning_steps,
|
|
980
|
+
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
appendReasoningSteps(chunk, lastMessage, updatedMessage) {
|
|
984
|
+
const existingSteps = lastMessage.extra_data?.reasoning_steps ?? [];
|
|
985
|
+
const incomingSteps = chunk.extra_data?.reasoning_steps ?? [];
|
|
986
|
+
updatedMessage.extra_data = {
|
|
987
|
+
...updatedMessage.extra_data,
|
|
988
|
+
reasoning_steps: [...existingSteps, ...incomingSteps]
|
|
989
|
+
};
|
|
990
|
+
}
|
|
536
991
|
/**
|
|
537
992
|
* Process a chunk and update the last message
|
|
538
993
|
*/
|
|
@@ -559,58 +1014,13 @@ var EventProcessor = class {
|
|
|
559
1014
|
break;
|
|
560
1015
|
case import_agno_types.RunEvent.RunContent:
|
|
561
1016
|
case import_agno_types.RunEvent.TeamRunContent:
|
|
562
|
-
|
|
563
|
-
const uniqueContent = chunk.content.replace(this.lastContent, "");
|
|
564
|
-
updatedMessage.content = updatedMessage.content + uniqueContent;
|
|
565
|
-
this.lastContent = chunk.content;
|
|
566
|
-
} else if (typeof chunk.content !== "string" && chunk.content !== null) {
|
|
567
|
-
const jsonBlock = getJsonMarkdown(chunk.content);
|
|
568
|
-
updatedMessage.content = updatedMessage.content + jsonBlock;
|
|
569
|
-
this.lastContent = jsonBlock;
|
|
570
|
-
}
|
|
571
|
-
updatedMessage.tool_calls = processChunkToolCalls(
|
|
572
|
-
chunk,
|
|
573
|
-
lastMessage.tool_calls
|
|
574
|
-
);
|
|
575
|
-
if (chunk.extra_data?.reasoning_steps) {
|
|
576
|
-
updatedMessage.extra_data = {
|
|
577
|
-
...updatedMessage.extra_data,
|
|
578
|
-
reasoning_steps: chunk.extra_data.reasoning_steps
|
|
579
|
-
};
|
|
580
|
-
}
|
|
581
|
-
if (chunk.extra_data?.references) {
|
|
582
|
-
updatedMessage.extra_data = {
|
|
583
|
-
...updatedMessage.extra_data,
|
|
584
|
-
references: chunk.extra_data.references
|
|
585
|
-
};
|
|
586
|
-
}
|
|
587
|
-
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
588
|
-
if (chunk.images) {
|
|
589
|
-
updatedMessage.images = chunk.images;
|
|
590
|
-
}
|
|
591
|
-
if (chunk.videos) {
|
|
592
|
-
updatedMessage.videos = chunk.videos;
|
|
593
|
-
}
|
|
594
|
-
if (chunk.audio) {
|
|
595
|
-
updatedMessage.audio = chunk.audio;
|
|
596
|
-
}
|
|
597
|
-
if (chunk.response_audio?.transcript && typeof chunk.response_audio.transcript === "string") {
|
|
598
|
-
const transcript = chunk.response_audio.transcript;
|
|
599
|
-
updatedMessage.response_audio = {
|
|
600
|
-
...updatedMessage.response_audio,
|
|
601
|
-
transcript: (updatedMessage.response_audio?.transcript || "") + transcript
|
|
602
|
-
};
|
|
603
|
-
}
|
|
1017
|
+
this.applyRunContentFields(chunk, lastMessage, updatedMessage);
|
|
604
1018
|
break;
|
|
605
1019
|
case import_agno_types.RunEvent.ReasoningStep:
|
|
606
|
-
case import_agno_types.RunEvent.TeamReasoningStep:
|
|
607
|
-
|
|
608
|
-
const incomingSteps = chunk.extra_data?.reasoning_steps ?? [];
|
|
609
|
-
updatedMessage.extra_data = {
|
|
610
|
-
...updatedMessage.extra_data,
|
|
611
|
-
reasoning_steps: [...existingSteps, ...incomingSteps]
|
|
612
|
-
};
|
|
1020
|
+
case import_agno_types.RunEvent.TeamReasoningStep: {
|
|
1021
|
+
this.appendReasoningSteps(chunk, lastMessage, updatedMessage);
|
|
613
1022
|
break;
|
|
1023
|
+
}
|
|
614
1024
|
case import_agno_types.RunEvent.ReasoningCompleted:
|
|
615
1025
|
case import_agno_types.RunEvent.TeamReasoningCompleted:
|
|
616
1026
|
if (chunk.extra_data?.reasoning_steps) {
|
|
@@ -621,31 +1031,10 @@ var EventProcessor = class {
|
|
|
621
1031
|
}
|
|
622
1032
|
break;
|
|
623
1033
|
case import_agno_types.RunEvent.RunCompleted:
|
|
624
|
-
case import_agno_types.RunEvent.TeamRunCompleted:
|
|
625
|
-
|
|
626
|
-
if (typeof chunk.content === "string") {
|
|
627
|
-
updatedContent = chunk.content;
|
|
628
|
-
} else {
|
|
629
|
-
try {
|
|
630
|
-
updatedContent = JSON.stringify(chunk.content);
|
|
631
|
-
} catch {
|
|
632
|
-
updatedContent = "Error parsing response";
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
updatedMessage.content = updatedContent;
|
|
636
|
-
updatedMessage.tool_calls = processChunkToolCalls(
|
|
637
|
-
chunk,
|
|
638
|
-
lastMessage.tool_calls
|
|
639
|
-
);
|
|
640
|
-
updatedMessage.images = chunk.images ?? lastMessage.images;
|
|
641
|
-
updatedMessage.videos = chunk.videos ?? lastMessage.videos;
|
|
642
|
-
updatedMessage.response_audio = chunk.response_audio;
|
|
643
|
-
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
644
|
-
updatedMessage.extra_data = {
|
|
645
|
-
reasoning_steps: chunk.extra_data?.reasoning_steps ?? lastMessage.extra_data?.reasoning_steps,
|
|
646
|
-
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references
|
|
647
|
-
};
|
|
1034
|
+
case import_agno_types.RunEvent.TeamRunCompleted: {
|
|
1035
|
+
this.applyCompletedFields(chunk, lastMessage, updatedMessage);
|
|
648
1036
|
break;
|
|
1037
|
+
}
|
|
649
1038
|
case import_agno_types.RunEvent.UpdatingMemory:
|
|
650
1039
|
case import_agno_types.RunEvent.TeamMemoryUpdateStarted:
|
|
651
1040
|
case import_agno_types.RunEvent.TeamMemoryUpdateCompleted:
|
|
@@ -657,6 +1046,8 @@ var EventProcessor = class {
|
|
|
657
1046
|
case import_agno_types.RunEvent.TeamRunCancelled:
|
|
658
1047
|
updatedMessage.streamingError = true;
|
|
659
1048
|
break;
|
|
1049
|
+
default:
|
|
1050
|
+
break;
|
|
660
1051
|
}
|
|
661
1052
|
return updatedMessage;
|
|
662
1053
|
}
|
|
@@ -668,166 +1059,95 @@ var EventProcessor = class {
|
|
|
668
1059
|
}
|
|
669
1060
|
};
|
|
670
1061
|
|
|
671
|
-
// src/
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
let inString = false;
|
|
701
|
-
let escapeNext = false;
|
|
702
|
-
let jsonEndIndex = -1;
|
|
703
|
-
let i = jsonStartIndex;
|
|
704
|
-
for (; i < buffer.length; i++) {
|
|
705
|
-
const char = buffer[i];
|
|
706
|
-
if (inString) {
|
|
707
|
-
if (escapeNext) {
|
|
708
|
-
escapeNext = false;
|
|
709
|
-
} else if (char === "\\") {
|
|
710
|
-
escapeNext = true;
|
|
711
|
-
} else if (char === '"') {
|
|
712
|
-
inString = false;
|
|
713
|
-
}
|
|
714
|
-
} else {
|
|
715
|
-
if (char === '"') {
|
|
716
|
-
inString = true;
|
|
717
|
-
} else if (char === "{") {
|
|
718
|
-
braceCount++;
|
|
719
|
-
} else if (char === "}") {
|
|
720
|
-
braceCount--;
|
|
721
|
-
if (braceCount === 0) {
|
|
722
|
-
jsonEndIndex = i;
|
|
723
|
-
break;
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
if (jsonEndIndex !== -1) {
|
|
729
|
-
const jsonString = buffer.slice(jsonStartIndex, jsonEndIndex + 1);
|
|
730
|
-
try {
|
|
731
|
-
const parsed = JSON.parse(jsonString);
|
|
732
|
-
if (isLegacyFormat(parsed)) {
|
|
733
|
-
processChunk(parsed, onChunk);
|
|
734
|
-
} else {
|
|
735
|
-
const legacyChunk = convertNewFormatToLegacy(parsed);
|
|
736
|
-
processChunk(legacyChunk, onChunk);
|
|
737
|
-
}
|
|
738
|
-
} catch (error) {
|
|
739
|
-
if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") {
|
|
740
|
-
console.error("Failed to parse JSON chunk:", {
|
|
741
|
-
error,
|
|
742
|
-
chunk: jsonString.substring(0, 100) + (jsonString.length > 100 ? "..." : ""),
|
|
743
|
-
position: jsonStartIndex
|
|
744
|
-
});
|
|
745
|
-
}
|
|
746
|
-
if (jsonString.length > 1e4) {
|
|
747
|
-
throw new Error(`Failed to parse large JSON chunk at position ${jsonStartIndex}`);
|
|
748
|
-
}
|
|
749
|
-
jsonStartIndex = buffer.indexOf("{", jsonStartIndex + 1);
|
|
750
|
-
continue;
|
|
751
|
-
}
|
|
752
|
-
currentIndex = jsonEndIndex + 1;
|
|
753
|
-
buffer = buffer.slice(currentIndex).trim();
|
|
754
|
-
currentIndex = 0;
|
|
755
|
-
jsonStartIndex = buffer.indexOf("{", currentIndex);
|
|
756
|
-
} else {
|
|
757
|
-
break;
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
return buffer;
|
|
761
|
-
}
|
|
762
|
-
async function streamResponse(options) {
|
|
763
|
-
const {
|
|
764
|
-
apiUrl,
|
|
765
|
-
headers = {},
|
|
766
|
-
params,
|
|
767
|
-
requestBody,
|
|
768
|
-
onChunk,
|
|
769
|
-
onError,
|
|
770
|
-
onComplete,
|
|
771
|
-
signal
|
|
772
|
-
} = options;
|
|
773
|
-
let buffer = "";
|
|
774
|
-
const finalUrl = params && params.toString() ? `${apiUrl}?${params.toString()}` : apiUrl;
|
|
775
|
-
try {
|
|
776
|
-
const response = await fetch(finalUrl, {
|
|
777
|
-
method: "POST",
|
|
778
|
-
headers: {
|
|
779
|
-
...!(requestBody instanceof FormData) && {
|
|
780
|
-
"Content-Type": "application/json"
|
|
781
|
-
},
|
|
782
|
-
...headers
|
|
783
|
-
},
|
|
784
|
-
body: requestBody instanceof FormData ? requestBody : JSON.stringify(requestBody),
|
|
785
|
-
signal
|
|
786
|
-
});
|
|
787
|
-
if (!response.ok) {
|
|
788
|
-
let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
|
|
789
|
-
const contentType = response.headers.get("content-type");
|
|
790
|
-
if (contentType?.includes("application/json")) {
|
|
791
|
-
try {
|
|
792
|
-
const errorData = await response.json();
|
|
793
|
-
errorMessage = errorData.detail || errorData.message || errorMessage;
|
|
794
|
-
} catch {
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
throw new Error(errorMessage);
|
|
798
|
-
}
|
|
799
|
-
if (!response.body) {
|
|
800
|
-
throw new Error("No response body");
|
|
1062
|
+
// src/stores/message-store.ts
|
|
1063
|
+
var MessageStore = class {
|
|
1064
|
+
constructor() {
|
|
1065
|
+
this.messages = [];
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Get all messages
|
|
1069
|
+
*/
|
|
1070
|
+
getMessages() {
|
|
1071
|
+
return [...this.messages];
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Set messages (replaces all)
|
|
1075
|
+
*/
|
|
1076
|
+
setMessages(messages) {
|
|
1077
|
+
this.messages = [...messages];
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Add a message
|
|
1081
|
+
*/
|
|
1082
|
+
addMessage(message) {
|
|
1083
|
+
this.messages = [...this.messages, message];
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* Update the last message
|
|
1087
|
+
*/
|
|
1088
|
+
updateLastMessage(updater) {
|
|
1089
|
+
if (this.messages.length === 0) {
|
|
1090
|
+
return void 0;
|
|
801
1091
|
}
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
while (true) {
|
|
806
|
-
const { done, value } = await reader.read();
|
|
807
|
-
if (done) {
|
|
808
|
-
buffer = parseBuffer(buffer, onChunk);
|
|
809
|
-
onComplete();
|
|
810
|
-
return;
|
|
811
|
-
}
|
|
812
|
-
buffer += decoder.decode(value, { stream: true });
|
|
813
|
-
buffer = parseBuffer(buffer, onChunk);
|
|
814
|
-
}
|
|
815
|
-
};
|
|
816
|
-
await processStream();
|
|
817
|
-
} catch (error) {
|
|
818
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
819
|
-
return;
|
|
1092
|
+
const lastMessage = this.messages.at(-1);
|
|
1093
|
+
if (!lastMessage) {
|
|
1094
|
+
return void 0;
|
|
820
1095
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
1096
|
+
const updatedMessage = updater(lastMessage);
|
|
1097
|
+
this.messages = [...this.messages.slice(0, -1), updatedMessage];
|
|
1098
|
+
return updatedMessage;
|
|
1099
|
+
}
|
|
1100
|
+
/**
|
|
1101
|
+
* Update a specific message by index
|
|
1102
|
+
*/
|
|
1103
|
+
updateMessage(index, updater) {
|
|
1104
|
+
if (index < 0 || index >= this.messages.length) {
|
|
1105
|
+
return void 0;
|
|
825
1106
|
}
|
|
1107
|
+
const message = this.messages[index];
|
|
1108
|
+
const updatedMessage = updater(message);
|
|
1109
|
+
this.messages = [
|
|
1110
|
+
...this.messages.slice(0, index),
|
|
1111
|
+
updatedMessage,
|
|
1112
|
+
...this.messages.slice(index + 1)
|
|
1113
|
+
];
|
|
1114
|
+
return updatedMessage;
|
|
826
1115
|
}
|
|
827
|
-
|
|
1116
|
+
/**
|
|
1117
|
+
* Remove last N messages
|
|
1118
|
+
*/
|
|
1119
|
+
removeLastMessages(count) {
|
|
1120
|
+
this.messages = this.messages.slice(0, -count);
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Clear all messages
|
|
1124
|
+
*/
|
|
1125
|
+
clear() {
|
|
1126
|
+
this.messages = [];
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Get the last message
|
|
1130
|
+
*/
|
|
1131
|
+
getLastMessage() {
|
|
1132
|
+
return this.messages.length > 0 ? this.messages.at(-1) : void 0;
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* Check if last message has streaming error
|
|
1136
|
+
*/
|
|
1137
|
+
hasLastMessageError() {
|
|
1138
|
+
const lastMessage = this.getLastMessage();
|
|
1139
|
+
return lastMessage?.streamingError === true;
|
|
1140
|
+
}
|
|
1141
|
+
};
|
|
828
1142
|
|
|
829
1143
|
// src/utils/logger.ts
|
|
830
|
-
var SENSITIVE_KEYS = [
|
|
1144
|
+
var SENSITIVE_KEYS = [
|
|
1145
|
+
"authToken",
|
|
1146
|
+
"Authorization",
|
|
1147
|
+
"token",
|
|
1148
|
+
"password",
|
|
1149
|
+
"apiKey"
|
|
1150
|
+
];
|
|
831
1151
|
function sanitizeObject(obj) {
|
|
832
1152
|
if (obj === null || obj === void 0) {
|
|
833
1153
|
return obj;
|
|
@@ -855,36 +1175,36 @@ function sanitizeObject(obj) {
|
|
|
855
1175
|
function isDevelopment() {
|
|
856
1176
|
return typeof process !== "undefined" && process.env?.NODE_ENV === "development";
|
|
857
1177
|
}
|
|
858
|
-
var Logger =
|
|
1178
|
+
var Logger = {
|
|
859
1179
|
/**
|
|
860
1180
|
* Log debug information (only in development)
|
|
861
1181
|
*/
|
|
862
|
-
|
|
1182
|
+
debug(message, data) {
|
|
863
1183
|
if (isDevelopment()) {
|
|
864
1184
|
const sanitized = data ? sanitizeObject(data) : void 0;
|
|
865
1185
|
console.debug(`[DEBUG] ${message}`, sanitized || "");
|
|
866
1186
|
}
|
|
867
|
-
}
|
|
1187
|
+
},
|
|
868
1188
|
/**
|
|
869
1189
|
* Log informational messages (only in development)
|
|
870
1190
|
*/
|
|
871
|
-
|
|
1191
|
+
info(message, data) {
|
|
872
1192
|
if (isDevelopment()) {
|
|
873
1193
|
const sanitized = data ? sanitizeObject(data) : void 0;
|
|
874
1194
|
console.info(`[INFO] ${message}`, sanitized || "");
|
|
875
1195
|
}
|
|
876
|
-
}
|
|
1196
|
+
},
|
|
877
1197
|
/**
|
|
878
1198
|
* Log warnings (always logs)
|
|
879
1199
|
*/
|
|
880
|
-
|
|
1200
|
+
warn(message, data) {
|
|
881
1201
|
const sanitized = data ? sanitizeObject(data) : void 0;
|
|
882
1202
|
console.warn(`[WARN] ${message}`, sanitized || "");
|
|
883
|
-
}
|
|
1203
|
+
},
|
|
884
1204
|
/**
|
|
885
1205
|
* Log errors (always logs)
|
|
886
1206
|
*/
|
|
887
|
-
|
|
1207
|
+
error(message, data) {
|
|
888
1208
|
const sanitized = data ? sanitizeObject(data) : void 0;
|
|
889
1209
|
console.error(`[ERROR] ${message}`, sanitized || "");
|
|
890
1210
|
}
|
|
@@ -902,19 +1222,104 @@ function toSafeISOString(timestamp) {
|
|
|
902
1222
|
}
|
|
903
1223
|
return new Date(ts).toISOString();
|
|
904
1224
|
}
|
|
1225
|
+
function getFileName(file, index) {
|
|
1226
|
+
if ("name" in file && typeof file.name === "string" && file.name) {
|
|
1227
|
+
return file.name;
|
|
1228
|
+
}
|
|
1229
|
+
return `file-${index}`;
|
|
1230
|
+
}
|
|
1231
|
+
function getFileFormat(mimeType) {
|
|
1232
|
+
if (!mimeType) {
|
|
1233
|
+
return void 0;
|
|
1234
|
+
}
|
|
1235
|
+
const [, subtype] = mimeType.split("/");
|
|
1236
|
+
if (!subtype) {
|
|
1237
|
+
return void 0;
|
|
1238
|
+
}
|
|
1239
|
+
return subtype.split(";")[0]?.trim().toLowerCase() || void 0;
|
|
1240
|
+
}
|
|
1241
|
+
function createPreviewUrl(file) {
|
|
1242
|
+
if (typeof URL === "undefined" || typeof URL.createObjectURL !== "function") {
|
|
1243
|
+
return void 0;
|
|
1244
|
+
}
|
|
1245
|
+
try {
|
|
1246
|
+
return URL.createObjectURL(file);
|
|
1247
|
+
} catch {
|
|
1248
|
+
return void 0;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
function buildMessageMediaPayload(files) {
|
|
1252
|
+
const images = [];
|
|
1253
|
+
const videos = [];
|
|
1254
|
+
const audio = [];
|
|
1255
|
+
const fileAttachments = [];
|
|
1256
|
+
const objectUrls = [];
|
|
1257
|
+
files.forEach((file, index) => {
|
|
1258
|
+
const filename = getFileName(file, index);
|
|
1259
|
+
const mimeType = file.type || "application/octet-stream";
|
|
1260
|
+
const format = getFileFormat(mimeType);
|
|
1261
|
+
const previewUrl = createPreviewUrl(file);
|
|
1262
|
+
if (previewUrl) {
|
|
1263
|
+
objectUrls.push(previewUrl);
|
|
1264
|
+
}
|
|
1265
|
+
if (mimeType.startsWith("image/") && previewUrl) {
|
|
1266
|
+
images.push({
|
|
1267
|
+
url: previewUrl,
|
|
1268
|
+
mime_type: mimeType,
|
|
1269
|
+
format
|
|
1270
|
+
});
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1273
|
+
if (mimeType.startsWith("video/")) {
|
|
1274
|
+
videos.push({
|
|
1275
|
+
url: previewUrl,
|
|
1276
|
+
id: filename,
|
|
1277
|
+
mime_type: mimeType,
|
|
1278
|
+
format
|
|
1279
|
+
});
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1282
|
+
if (mimeType.startsWith("audio/")) {
|
|
1283
|
+
audio.push({
|
|
1284
|
+
url: previewUrl,
|
|
1285
|
+
id: filename,
|
|
1286
|
+
mime_type: mimeType,
|
|
1287
|
+
format
|
|
1288
|
+
});
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
fileAttachments.push({
|
|
1292
|
+
filename,
|
|
1293
|
+
name: filename,
|
|
1294
|
+
mime_type: mimeType,
|
|
1295
|
+
format,
|
|
1296
|
+
size: file.size,
|
|
1297
|
+
url: previewUrl
|
|
1298
|
+
});
|
|
1299
|
+
});
|
|
1300
|
+
return {
|
|
1301
|
+
images: images.length > 0 ? images : void 0,
|
|
1302
|
+
videos: videos.length > 0 ? videos : void 0,
|
|
1303
|
+
audio: audio.length > 0 ? audio : void 0,
|
|
1304
|
+
files: fileAttachments.length > 0 ? fileAttachments : void 0,
|
|
1305
|
+
objectUrls
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
905
1308
|
var AgnoClient = class extends import_eventemitter3.default {
|
|
906
1309
|
constructor(config) {
|
|
907
1310
|
super();
|
|
908
|
-
// toolCallId -> UIComponentSpec
|
|
909
1311
|
this.runCompletedSuccessfully = false;
|
|
1312
|
+
this.currentAbortController = null;
|
|
910
1313
|
this.messageStore = new MessageStore();
|
|
911
1314
|
this.configManager = new ConfigManager(config);
|
|
912
1315
|
this.sessionManager = new SessionManager();
|
|
913
1316
|
this.eventProcessor = new EventProcessor();
|
|
914
1317
|
this.pendingUISpecs = /* @__PURE__ */ new Map();
|
|
1318
|
+
this.localAttachmentUrls = /* @__PURE__ */ new Set();
|
|
915
1319
|
this.state = {
|
|
916
1320
|
isStreaming: false,
|
|
917
1321
|
isRefreshing: false,
|
|
1322
|
+
isCancelling: false,
|
|
918
1323
|
isEndpointActive: false,
|
|
919
1324
|
agents: [],
|
|
920
1325
|
teams: [],
|
|
@@ -953,12 +1358,99 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
953
1358
|
* Clear all messages
|
|
954
1359
|
*/
|
|
955
1360
|
clearMessages() {
|
|
1361
|
+
this.revokeAttachmentUrlsFromMessages(this.messageStore.getMessages());
|
|
1362
|
+
this.localAttachmentUrls.clear();
|
|
956
1363
|
this.messageStore.clear();
|
|
957
1364
|
this.configManager.setSessionId(void 0);
|
|
958
1365
|
this.pendingUISpecs.clear();
|
|
959
1366
|
this.emit("message:update", this.messageStore.getMessages());
|
|
960
1367
|
this.emit("state:change", this.getState());
|
|
961
1368
|
}
|
|
1369
|
+
/**
|
|
1370
|
+
* Cancel an active or paused run
|
|
1371
|
+
*/
|
|
1372
|
+
async cancelRun() {
|
|
1373
|
+
if (!(this.state.isStreaming || this.state.isPaused)) {
|
|
1374
|
+
throw new Error("No active or paused run to cancel");
|
|
1375
|
+
}
|
|
1376
|
+
const runId = this.state.pausedRunId || this.currentRunId;
|
|
1377
|
+
if (this.currentAbortController) {
|
|
1378
|
+
this.currentAbortController.abort();
|
|
1379
|
+
this.currentAbortController = null;
|
|
1380
|
+
}
|
|
1381
|
+
this.state.isCancelling = true;
|
|
1382
|
+
this.emit("state:change", this.getState());
|
|
1383
|
+
const cancelErrorMessage = runId ? await this.requestBackendCancel(runId) : this.logMissingRunIdForCancel();
|
|
1384
|
+
this.state.isStreaming = false;
|
|
1385
|
+
this.state.isPaused = false;
|
|
1386
|
+
this.state.isCancelling = false;
|
|
1387
|
+
this.state.pausedRunId = void 0;
|
|
1388
|
+
this.state.toolsAwaitingExecution = void 0;
|
|
1389
|
+
this.currentRunId = void 0;
|
|
1390
|
+
if (cancelErrorMessage) {
|
|
1391
|
+
this.state.errorMessage = cancelErrorMessage;
|
|
1392
|
+
this.emit("message:error", cancelErrorMessage);
|
|
1393
|
+
}
|
|
1394
|
+
this.emit("run:cancelled", { runId });
|
|
1395
|
+
this.emit("state:change", this.getState());
|
|
1396
|
+
}
|
|
1397
|
+
logMissingRunIdForCancel() {
|
|
1398
|
+
Logger.warn(
|
|
1399
|
+
"[AgnoClient] No run ID available, skipping backend cancel request"
|
|
1400
|
+
);
|
|
1401
|
+
return void 0;
|
|
1402
|
+
}
|
|
1403
|
+
async requestBackendCancel(runId) {
|
|
1404
|
+
const runUrl = this.configManager.getRunUrl();
|
|
1405
|
+
if (!runUrl) {
|
|
1406
|
+
const message = "Run cancelled locally, but backend cancel could not be sent: no agent or team selected";
|
|
1407
|
+
Logger.warn(`[AgnoClient] ${message}`);
|
|
1408
|
+
return message;
|
|
1409
|
+
}
|
|
1410
|
+
const cancelUrl = `${runUrl}/${runId}/cancel`;
|
|
1411
|
+
const headers = this.configManager.buildRequestHeaders();
|
|
1412
|
+
try {
|
|
1413
|
+
const response = await fetch(cancelUrl, {
|
|
1414
|
+
method: "POST",
|
|
1415
|
+
headers
|
|
1416
|
+
});
|
|
1417
|
+
if (response.ok) {
|
|
1418
|
+
return void 0;
|
|
1419
|
+
}
|
|
1420
|
+
if (response.status === 401 || response.status === 403) {
|
|
1421
|
+
const message = `Run cancelled locally, but backend cancel was rejected (${response.status})`;
|
|
1422
|
+
Logger.warn(`[AgnoClient] ${message}`);
|
|
1423
|
+
return message;
|
|
1424
|
+
}
|
|
1425
|
+
Logger.warn(
|
|
1426
|
+
`[AgnoClient] Backend cancel returned ${response.status} \u2014 run may have already completed`
|
|
1427
|
+
);
|
|
1428
|
+
return void 0;
|
|
1429
|
+
} catch (error) {
|
|
1430
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
1431
|
+
const message = `Run cancelled locally, but backend cancel failed: ${reason}`;
|
|
1432
|
+
Logger.warn(`[AgnoClient] ${message}`);
|
|
1433
|
+
return message;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Abort the active stream without calling the backend cancel endpoint.
|
|
1438
|
+
* Since streamResponse handles AbortError by returning silently
|
|
1439
|
+
* (no onComplete/onError called), state cleanup is done here.
|
|
1440
|
+
*/
|
|
1441
|
+
abortStream() {
|
|
1442
|
+
if (!this.state.isStreaming) {
|
|
1443
|
+
return;
|
|
1444
|
+
}
|
|
1445
|
+
if (this.currentAbortController) {
|
|
1446
|
+
this.currentAbortController.abort();
|
|
1447
|
+
this.currentAbortController = null;
|
|
1448
|
+
}
|
|
1449
|
+
this.state.isStreaming = false;
|
|
1450
|
+
this.currentRunId = void 0;
|
|
1451
|
+
this.emit("stream:end");
|
|
1452
|
+
this.emit("state:change", this.getState());
|
|
1453
|
+
}
|
|
962
1454
|
/**
|
|
963
1455
|
* Send a message to the agent/team (streaming)
|
|
964
1456
|
*/
|
|
@@ -979,16 +1471,30 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
979
1471
|
if (typeof message === "string") {
|
|
980
1472
|
formData.append("message", message);
|
|
981
1473
|
}
|
|
1474
|
+
if (options?.files) {
|
|
1475
|
+
options.files.forEach((file, index) => {
|
|
1476
|
+
formData.append("files", file, getFileName(file, index));
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
const requestFiles = formData.getAll("files").filter((entry) => typeof entry !== "string");
|
|
1480
|
+
const userMessageMedia = buildMessageMediaPayload(requestFiles);
|
|
1481
|
+
this.trackAttachmentUrls(userMessageMedia.objectUrls);
|
|
1482
|
+
const userMessageContent = String(formData.get("message") ?? "");
|
|
982
1483
|
const lastMessage = this.messageStore.getLastMessage();
|
|
983
1484
|
if (lastMessage?.streamingError) {
|
|
984
1485
|
const secondLast = this.messageStore.getMessages()[this.messageStore.getMessages().length - 2];
|
|
985
1486
|
if (secondLast?.role === "user") {
|
|
1487
|
+
this.revokeAttachmentUrlsFromMessages([secondLast, lastMessage]);
|
|
986
1488
|
this.messageStore.removeLastMessages(2);
|
|
987
1489
|
}
|
|
988
1490
|
}
|
|
989
1491
|
this.messageStore.addMessage({
|
|
990
1492
|
role: "user",
|
|
991
|
-
content:
|
|
1493
|
+
content: userMessageContent,
|
|
1494
|
+
images: userMessageMedia.images,
|
|
1495
|
+
videos: userMessageMedia.videos,
|
|
1496
|
+
audio: userMessageMedia.audio,
|
|
1497
|
+
files: userMessageMedia.files,
|
|
992
1498
|
created_at: Math.floor(Date.now() / 1e3)
|
|
993
1499
|
});
|
|
994
1500
|
this.messageStore.addMessage({
|
|
@@ -1002,33 +1508,42 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1002
1508
|
this.eventProcessor.reset();
|
|
1003
1509
|
let newSessionId = this.configManager.getSessionId();
|
|
1004
1510
|
try {
|
|
1005
|
-
formData.
|
|
1006
|
-
formData.
|
|
1511
|
+
formData.set("stream", "true");
|
|
1512
|
+
formData.set("session_id", newSessionId ?? "");
|
|
1007
1513
|
const userId = this.configManager.getUserId();
|
|
1008
1514
|
if (userId) {
|
|
1009
|
-
formData.
|
|
1515
|
+
formData.set("user_id", userId);
|
|
1516
|
+
}
|
|
1517
|
+
const dependencies = this.configManager.buildDependencies(
|
|
1518
|
+
options?.dependencies
|
|
1519
|
+
);
|
|
1520
|
+
if (dependencies) {
|
|
1521
|
+
formData.set("dependencies", JSON.stringify(dependencies));
|
|
1010
1522
|
}
|
|
1011
1523
|
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
1012
1524
|
const params = this.configManager.buildQueryString(options?.params);
|
|
1525
|
+
this.currentAbortController = new AbortController();
|
|
1013
1526
|
await streamResponse({
|
|
1014
1527
|
apiUrl: runUrl,
|
|
1015
1528
|
headers,
|
|
1016
1529
|
params,
|
|
1017
1530
|
requestBody: formData,
|
|
1531
|
+
signal: this.currentAbortController.signal,
|
|
1018
1532
|
onChunk: (chunk) => {
|
|
1019
|
-
this.handleChunk(chunk, newSessionId,
|
|
1020
|
-
if (chunk.event === import_agno_types2.RunEvent.RunStarted || chunk.event === import_agno_types2.RunEvent.TeamRunStarted || chunk.event === import_agno_types2.RunEvent.ReasoningStarted || chunk.event === import_agno_types2.RunEvent.TeamReasoningStarted) {
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
this.configManager.setSessionId(chunk.session_id);
|
|
1024
|
-
}
|
|
1533
|
+
this.handleChunk(chunk, newSessionId, userMessageContent);
|
|
1534
|
+
if ((chunk.event === import_agno_types2.RunEvent.RunStarted || chunk.event === import_agno_types2.RunEvent.TeamRunStarted || chunk.event === import_agno_types2.RunEvent.ReasoningStarted || chunk.event === import_agno_types2.RunEvent.TeamReasoningStarted) && chunk.session_id) {
|
|
1535
|
+
newSessionId = chunk.session_id;
|
|
1536
|
+
this.configManager.setSessionId(chunk.session_id);
|
|
1025
1537
|
}
|
|
1026
1538
|
},
|
|
1027
1539
|
onError: (error) => {
|
|
1540
|
+
this.currentAbortController = null;
|
|
1028
1541
|
this.handleError(error, newSessionId);
|
|
1029
1542
|
},
|
|
1030
1543
|
onComplete: async () => {
|
|
1544
|
+
this.currentAbortController = null;
|
|
1031
1545
|
this.state.isStreaming = false;
|
|
1546
|
+
this.currentRunId = void 0;
|
|
1032
1547
|
this.emit("stream:end");
|
|
1033
1548
|
this.emit("message:complete", this.messageStore.getMessages());
|
|
1034
1549
|
this.emit("state:change", this.getState());
|
|
@@ -1039,6 +1554,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1039
1554
|
}
|
|
1040
1555
|
});
|
|
1041
1556
|
} catch (error) {
|
|
1557
|
+
this.currentAbortController = null;
|
|
1042
1558
|
this.handleError(
|
|
1043
1559
|
error instanceof Error ? error : new Error(String(error)),
|
|
1044
1560
|
newSessionId
|
|
@@ -1050,20 +1566,21 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1050
1566
|
*/
|
|
1051
1567
|
handleChunk(chunk, currentSessionId, messageContent) {
|
|
1052
1568
|
const event = chunk.event;
|
|
1053
|
-
if (event === import_agno_types2.RunEvent.RunStarted || event === import_agno_types2.RunEvent.TeamRunStarted
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1569
|
+
if ((event === import_agno_types2.RunEvent.RunStarted || event === import_agno_types2.RunEvent.TeamRunStarted) && chunk.run_id) {
|
|
1570
|
+
this.currentRunId = chunk.run_id;
|
|
1571
|
+
}
|
|
1572
|
+
if ((event === import_agno_types2.RunEvent.RunStarted || event === import_agno_types2.RunEvent.TeamRunStarted || event === import_agno_types2.RunEvent.ReasoningStarted || event === import_agno_types2.RunEvent.TeamReasoningStarted) && chunk.session_id && (!currentSessionId || currentSessionId !== chunk.session_id)) {
|
|
1573
|
+
const sessionData = {
|
|
1574
|
+
session_id: chunk.session_id,
|
|
1575
|
+
session_name: messageContent,
|
|
1576
|
+
created_at: toSafeISOString(chunk.created_at)
|
|
1577
|
+
};
|
|
1578
|
+
const sessionExists = this.state.sessions.some(
|
|
1579
|
+
(s) => s.session_id === chunk.session_id
|
|
1580
|
+
);
|
|
1581
|
+
if (!sessionExists) {
|
|
1582
|
+
this.state.sessions = [sessionData, ...this.state.sessions];
|
|
1583
|
+
this.emit("session:created", sessionData);
|
|
1067
1584
|
}
|
|
1068
1585
|
}
|
|
1069
1586
|
if (event === import_agno_types2.RunEvent.RunPaused) {
|
|
@@ -1123,6 +1640,73 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1123
1640
|
this.emit("stream:end");
|
|
1124
1641
|
this.emit("state:change", this.getState());
|
|
1125
1642
|
}
|
|
1643
|
+
trackAttachmentUrls(urls) {
|
|
1644
|
+
for (const url of urls) {
|
|
1645
|
+
this.localAttachmentUrls.add(url);
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
collectAttachmentUrls(message) {
|
|
1649
|
+
const imageUrls = message.images?.map((image) => image.url) ?? [];
|
|
1650
|
+
const videoUrls = message.videos?.map((video) => video.url).filter((url) => Boolean(url)) ?? [];
|
|
1651
|
+
const audioUrls = message.audio?.map((audio) => audio.url).filter((url) => Boolean(url)) ?? [];
|
|
1652
|
+
const fileUrls = message.files?.map((file) => file.url).filter((url) => Boolean(url)) ?? [];
|
|
1653
|
+
return [...imageUrls, ...videoUrls, ...audioUrls, ...fileUrls];
|
|
1654
|
+
}
|
|
1655
|
+
revokeAttachmentUrls(urls) {
|
|
1656
|
+
if (typeof URL === "undefined" || typeof URL.revokeObjectURL !== "function") {
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
for (const url of urls) {
|
|
1660
|
+
if (!this.localAttachmentUrls.has(url)) {
|
|
1661
|
+
continue;
|
|
1662
|
+
}
|
|
1663
|
+
URL.revokeObjectURL(url);
|
|
1664
|
+
this.localAttachmentUrls.delete(url);
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
revokeAttachmentUrlsFromMessages(messages) {
|
|
1668
|
+
const urls = [];
|
|
1669
|
+
for (const message of messages) {
|
|
1670
|
+
if (!message) {
|
|
1671
|
+
continue;
|
|
1672
|
+
}
|
|
1673
|
+
urls.push(...this.collectAttachmentUrls(message));
|
|
1674
|
+
}
|
|
1675
|
+
this.revokeAttachmentUrls(urls);
|
|
1676
|
+
}
|
|
1677
|
+
collectExistingUIComponents() {
|
|
1678
|
+
const existingUIComponents = /* @__PURE__ */ new Map();
|
|
1679
|
+
for (const message of this.messageStore.getMessages()) {
|
|
1680
|
+
if (!message.tool_calls) {
|
|
1681
|
+
continue;
|
|
1682
|
+
}
|
|
1683
|
+
for (const toolCall of message.tool_calls) {
|
|
1684
|
+
if (toolCall.ui_component) {
|
|
1685
|
+
existingUIComponents.set(
|
|
1686
|
+
toolCall.tool_call_id,
|
|
1687
|
+
toolCall.ui_component
|
|
1688
|
+
);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
return existingUIComponents;
|
|
1693
|
+
}
|
|
1694
|
+
restoreUIComponents(messages, uiComponents) {
|
|
1695
|
+
if (uiComponents.size === 0) {
|
|
1696
|
+
return;
|
|
1697
|
+
}
|
|
1698
|
+
for (const message of messages) {
|
|
1699
|
+
if (!message.tool_calls) {
|
|
1700
|
+
continue;
|
|
1701
|
+
}
|
|
1702
|
+
for (const toolCall of message.tool_calls) {
|
|
1703
|
+
const uiComponent = uiComponents.get(toolCall.tool_call_id);
|
|
1704
|
+
if (uiComponent) {
|
|
1705
|
+
toolCall.ui_component = uiComponent;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1126
1710
|
/**
|
|
1127
1711
|
* Refresh messages from the session API after run completion.
|
|
1128
1712
|
* Replaces streamed messages with authoritative session data.
|
|
@@ -1135,19 +1719,14 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1135
1719
|
Logger.debug("[AgnoClient] Cannot refresh: no session ID");
|
|
1136
1720
|
return;
|
|
1137
1721
|
}
|
|
1722
|
+
if (this.state.isStreaming) {
|
|
1723
|
+
Logger.debug("[AgnoClient] Skipping refresh: stream is active");
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1138
1726
|
this.state.isRefreshing = true;
|
|
1139
1727
|
this.emit("state:change", this.getState());
|
|
1140
1728
|
try {
|
|
1141
|
-
const existingUIComponents =
|
|
1142
|
-
for (const message of this.messageStore.getMessages()) {
|
|
1143
|
-
if (message.tool_calls) {
|
|
1144
|
-
for (const toolCall of message.tool_calls) {
|
|
1145
|
-
if (toolCall.ui_component) {
|
|
1146
|
-
existingUIComponents.set(toolCall.tool_call_id, toolCall.ui_component);
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1729
|
+
const existingUIComponents = this.collectExistingUIComponents();
|
|
1151
1730
|
const config = this.configManager.getConfig();
|
|
1152
1731
|
const entityType = this.configManager.getMode();
|
|
1153
1732
|
const dbId = this.configManager.getDbId() || "";
|
|
@@ -1163,27 +1742,28 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1163
1742
|
userId,
|
|
1164
1743
|
params
|
|
1165
1744
|
);
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
const toolCall = message.tool_calls[i];
|
|
1172
|
-
const uiComponent = existingUIComponents.get(toolCall.tool_call_id);
|
|
1173
|
-
if (uiComponent) {
|
|
1174
|
-
message.tool_calls[i].ui_component = uiComponent;
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1745
|
+
if (this.state.isStreaming) {
|
|
1746
|
+
Logger.debug(
|
|
1747
|
+
"[AgnoClient] Aborting refresh: stream started during fetch"
|
|
1748
|
+
);
|
|
1749
|
+
return;
|
|
1179
1750
|
}
|
|
1751
|
+
const messages = this.sessionManager.convertSessionToMessages(response);
|
|
1752
|
+
this.restoreUIComponents(messages, existingUIComponents);
|
|
1753
|
+
this.revokeAttachmentUrlsFromMessages(this.messageStore.getMessages());
|
|
1180
1754
|
this.messageStore.setMessages(messages);
|
|
1181
|
-
Logger.debug(
|
|
1755
|
+
Logger.debug(
|
|
1756
|
+
"[AgnoClient] Session refreshed:",
|
|
1757
|
+
`${messages.length} messages`
|
|
1758
|
+
);
|
|
1182
1759
|
this.emit("message:refreshed", messages);
|
|
1183
1760
|
this.emit("message:update", messages);
|
|
1184
1761
|
} catch (error) {
|
|
1185
1762
|
Logger.error("[AgnoClient] Failed to refresh session:", error);
|
|
1186
|
-
this.emit(
|
|
1763
|
+
this.emit(
|
|
1764
|
+
"message:error",
|
|
1765
|
+
`Session refresh failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1766
|
+
);
|
|
1187
1767
|
} finally {
|
|
1188
1768
|
this.state.isRefreshing = false;
|
|
1189
1769
|
this.emit("state:change", this.getState());
|
|
@@ -1198,7 +1778,11 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1198
1778
|
const entityType = this.configManager.getMode();
|
|
1199
1779
|
const dbId = this.configManager.getDbId() || "";
|
|
1200
1780
|
const userId = this.configManager.getUserId();
|
|
1201
|
-
Logger.debug("[AgnoClient] Loading session with:", {
|
|
1781
|
+
Logger.debug("[AgnoClient] Loading session with:", {
|
|
1782
|
+
entityType,
|
|
1783
|
+
dbId,
|
|
1784
|
+
userId
|
|
1785
|
+
});
|
|
1202
1786
|
const headers = this.configManager.buildRequestHeaders();
|
|
1203
1787
|
const params = this.configManager.buildQueryString(options?.params);
|
|
1204
1788
|
const response = await this.sessionManager.fetchSession(
|
|
@@ -1211,7 +1795,11 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1211
1795
|
params
|
|
1212
1796
|
);
|
|
1213
1797
|
const messages = this.sessionManager.convertSessionToMessages(response);
|
|
1214
|
-
Logger.debug(
|
|
1798
|
+
Logger.debug(
|
|
1799
|
+
"[AgnoClient] Setting messages to store:",
|
|
1800
|
+
`${messages.length} messages`
|
|
1801
|
+
);
|
|
1802
|
+
this.revokeAttachmentUrlsFromMessages(this.messageStore.getMessages());
|
|
1215
1803
|
this.messageStore.setMessages(messages);
|
|
1216
1804
|
this.configManager.setSessionId(sessionId);
|
|
1217
1805
|
Logger.debug("[AgnoClient] Emitting events...");
|
|
@@ -1280,7 +1868,9 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1280
1868
|
}
|
|
1281
1869
|
const existingToolCalls = lastMessage.tool_calls || [];
|
|
1282
1870
|
const existingIds = new Set(existingToolCalls.map((t) => t.tool_call_id));
|
|
1283
|
-
const newToolCalls = toolCalls.filter(
|
|
1871
|
+
const newToolCalls = toolCalls.filter(
|
|
1872
|
+
(t) => !existingIds.has(t.tool_call_id)
|
|
1873
|
+
);
|
|
1284
1874
|
if (newToolCalls.length > 0) {
|
|
1285
1875
|
this.messageStore.updateLastMessage((msg) => ({
|
|
1286
1876
|
...msg,
|
|
@@ -1327,8 +1917,9 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1327
1917
|
* Batches all updates to emit only one message:update event
|
|
1328
1918
|
*/
|
|
1329
1919
|
applyPendingUISpecs() {
|
|
1330
|
-
if (this.pendingUISpecs.size === 0)
|
|
1920
|
+
if (this.pendingUISpecs.size === 0) {
|
|
1331
1921
|
return;
|
|
1922
|
+
}
|
|
1332
1923
|
const messages = this.messageStore.getMessages();
|
|
1333
1924
|
const updatedMessages = [];
|
|
1334
1925
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -1360,9 +1951,9 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1360
1951
|
}
|
|
1361
1952
|
}
|
|
1362
1953
|
if (updatedMessages.length > 0) {
|
|
1363
|
-
|
|
1954
|
+
for (const { index, message } of updatedMessages) {
|
|
1364
1955
|
this.messageStore.updateMessage(index, () => message);
|
|
1365
|
-
}
|
|
1956
|
+
}
|
|
1366
1957
|
this.emit("message:update", this.messageStore.getMessages());
|
|
1367
1958
|
}
|
|
1368
1959
|
}
|
|
@@ -1383,22 +1974,55 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1383
1974
|
"HITL (Human-in-the-Loop) frontend tool execution is not supported for teams. Only agents support the continue endpoint."
|
|
1384
1975
|
);
|
|
1385
1976
|
}
|
|
1386
|
-
if (!this.state.isPaused
|
|
1977
|
+
if (!(this.state.isPaused && this.state.pausedRunId)) {
|
|
1387
1978
|
throw new Error("No paused run to continue");
|
|
1388
1979
|
}
|
|
1389
1980
|
const runUrl = this.configManager.getRunUrl();
|
|
1390
1981
|
if (!runUrl) {
|
|
1391
1982
|
throw new Error("No agent or team selected");
|
|
1392
1983
|
}
|
|
1393
|
-
const
|
|
1394
|
-
|
|
1984
|
+
const pausedRunId = this.state.pausedRunId;
|
|
1985
|
+
const continueUrl = `${runUrl}/${pausedRunId}/continue`;
|
|
1395
1986
|
this.state.isStreaming = true;
|
|
1396
|
-
this.
|
|
1987
|
+
this.state.errorMessage = void 0;
|
|
1397
1988
|
this.emit("state:change", this.getState());
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1989
|
+
let hasContinued = false;
|
|
1990
|
+
let streamError;
|
|
1991
|
+
const markRunContinued = (runId) => {
|
|
1992
|
+
if (hasContinued) {
|
|
1993
|
+
return;
|
|
1994
|
+
}
|
|
1995
|
+
hasContinued = true;
|
|
1996
|
+
this.state.isPaused = false;
|
|
1997
|
+
this.state.toolsAwaitingExecution = void 0;
|
|
1998
|
+
this.emit("run:continued", { runId: runId || pausedRunId });
|
|
1999
|
+
this.emit("state:change", this.getState());
|
|
2000
|
+
};
|
|
2001
|
+
const handleContinueError = (error) => {
|
|
2002
|
+
streamError = error;
|
|
2003
|
+
this.state.isStreaming = false;
|
|
2004
|
+
this.state.errorMessage = error.message;
|
|
2005
|
+
const isConflictError = error instanceof StreamResponseHttpError && error.status === 409;
|
|
2006
|
+
if (isConflictError || !hasContinued) {
|
|
2007
|
+
this.state.isPaused = true;
|
|
2008
|
+
} else {
|
|
2009
|
+
this.state.isPaused = false;
|
|
2010
|
+
this.state.pausedRunId = void 0;
|
|
2011
|
+
this.state.toolsAwaitingExecution = void 0;
|
|
2012
|
+
this.messageStore.updateLastMessage((msg) => ({
|
|
2013
|
+
...msg,
|
|
2014
|
+
streamingError: true
|
|
2015
|
+
}));
|
|
2016
|
+
}
|
|
2017
|
+
this.emit("message:error", error.message);
|
|
2018
|
+
this.emit("stream:end");
|
|
2019
|
+
this.emit("state:change", this.getState());
|
|
2020
|
+
};
|
|
2021
|
+
const cleanedTools = tools.map(
|
|
2022
|
+
({ ui_component: _uiComponent, ...tool }) => {
|
|
2023
|
+
return tool;
|
|
2024
|
+
}
|
|
2025
|
+
);
|
|
1402
2026
|
const formData = new FormData();
|
|
1403
2027
|
formData.append("tools", JSON.stringify(cleanedTools));
|
|
1404
2028
|
formData.append("stream", "true");
|
|
@@ -1412,36 +2036,45 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1412
2036
|
}
|
|
1413
2037
|
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
1414
2038
|
const params = this.configManager.buildQueryString(options?.params);
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
|
|
2039
|
+
this.currentAbortController = new AbortController();
|
|
2040
|
+
await streamResponse({
|
|
2041
|
+
apiUrl: continueUrl,
|
|
2042
|
+
headers,
|
|
2043
|
+
params,
|
|
2044
|
+
requestBody: formData,
|
|
2045
|
+
signal: this.currentAbortController.signal,
|
|
2046
|
+
onChunk: (chunk) => {
|
|
2047
|
+
const event = chunk.event;
|
|
2048
|
+
if (!hasContinued && event !== import_agno_types2.RunEvent.RunPaused) {
|
|
2049
|
+
markRunContinued(chunk.run_id);
|
|
2050
|
+
}
|
|
2051
|
+
this.handleChunk(chunk, currentSessionId, "");
|
|
2052
|
+
},
|
|
2053
|
+
onError: (error) => {
|
|
2054
|
+
this.currentAbortController = null;
|
|
2055
|
+
handleContinueError(error);
|
|
2056
|
+
},
|
|
2057
|
+
onComplete: async () => {
|
|
2058
|
+
this.currentAbortController = null;
|
|
2059
|
+
if (!(hasContinued || this.state.isPaused)) {
|
|
2060
|
+
markRunContinued(pausedRunId);
|
|
2061
|
+
}
|
|
2062
|
+
this.state.isStreaming = false;
|
|
2063
|
+
if (!this.state.isPaused) {
|
|
1429
2064
|
this.state.pausedRunId = void 0;
|
|
1430
2065
|
this.state.toolsAwaitingExecution = void 0;
|
|
1431
|
-
this.emit("stream:end");
|
|
1432
|
-
this.emit("message:complete", this.messageStore.getMessages());
|
|
1433
|
-
this.emit("state:change", this.getState());
|
|
1434
|
-
if (this.runCompletedSuccessfully) {
|
|
1435
|
-
this.runCompletedSuccessfully = false;
|
|
1436
|
-
await this.refreshSessionMessages();
|
|
1437
|
-
}
|
|
1438
2066
|
}
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
2067
|
+
this.emit("stream:end");
|
|
2068
|
+
this.emit("message:complete", this.messageStore.getMessages());
|
|
2069
|
+
this.emit("state:change", this.getState());
|
|
2070
|
+
if (this.runCompletedSuccessfully) {
|
|
2071
|
+
this.runCompletedSuccessfully = false;
|
|
2072
|
+
await this.refreshSessionMessages();
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
});
|
|
2076
|
+
if (streamError) {
|
|
2077
|
+
throw streamError;
|
|
1445
2078
|
}
|
|
1446
2079
|
}
|
|
1447
2080
|
/**
|
|
@@ -1526,7 +2159,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1526
2159
|
const currentConfig = this.configManager.getConfig();
|
|
1527
2160
|
const hasAgentConfigured = currentConfig.agentId;
|
|
1528
2161
|
const hasTeamConfigured = currentConfig.teamId;
|
|
1529
|
-
if (!hasAgentConfigured
|
|
2162
|
+
if (!(hasAgentConfigured || hasTeamConfigured)) {
|
|
1530
2163
|
if (agents.length > 0) {
|
|
1531
2164
|
const firstAgent = agents[0];
|
|
1532
2165
|
this.configManager.updateConfig({
|
|
@@ -1547,10 +2180,34 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1547
2180
|
}
|
|
1548
2181
|
return { agents, teams };
|
|
1549
2182
|
}
|
|
2183
|
+
/**
|
|
2184
|
+
* Dispose of the client and clean up all resources.
|
|
2185
|
+
* Call this method when the client is no longer needed to prevent memory leaks.
|
|
2186
|
+
* After calling dispose(), the client instance should not be reused.
|
|
2187
|
+
*/
|
|
2188
|
+
dispose() {
|
|
2189
|
+
if (this.currentAbortController) {
|
|
2190
|
+
this.currentAbortController.abort();
|
|
2191
|
+
this.currentAbortController = null;
|
|
2192
|
+
}
|
|
2193
|
+
this.removeAllListeners();
|
|
2194
|
+
this.revokeAttachmentUrlsFromMessages(this.messageStore.getMessages());
|
|
2195
|
+
this.localAttachmentUrls.clear();
|
|
2196
|
+
this.messageStore.clear();
|
|
2197
|
+
this.pendingUISpecs.clear();
|
|
2198
|
+
this.eventProcessor.reset();
|
|
2199
|
+
this.state.isStreaming = false;
|
|
2200
|
+
this.state.isRefreshing = false;
|
|
2201
|
+
this.state.isEndpointActive = false;
|
|
2202
|
+
this.state.agents = [];
|
|
2203
|
+
this.state.teams = [];
|
|
2204
|
+
this.state.sessions = [];
|
|
2205
|
+
this.state.isPaused = false;
|
|
2206
|
+
this.state.pausedRunId = void 0;
|
|
2207
|
+
this.state.toolsAwaitingExecution = void 0;
|
|
2208
|
+
this.state.errorMessage = void 0;
|
|
2209
|
+
}
|
|
1550
2210
|
};
|
|
1551
|
-
|
|
1552
|
-
// src/index.ts
|
|
1553
|
-
var import_agno_types3 = require("@antipopp/agno-types");
|
|
1554
2211
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1555
2212
|
0 && (module.exports = {
|
|
1556
2213
|
AgnoClient,
|