@antipopp/agno-client 0.10.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 +25 -12
- package/dist/index.d.ts +25 -12
- package/dist/index.js +890 -332
- package/dist/index.mjs +890 -332
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -184,6 +184,18 @@ var ConfigManager = class {
|
|
|
184
184
|
setParams(params) {
|
|
185
185
|
this.updateField("params", params);
|
|
186
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
|
+
}
|
|
187
199
|
/**
|
|
188
200
|
* Get current entity ID (agent or team based on mode)
|
|
189
201
|
*/
|
|
@@ -251,6 +263,29 @@ var ConfigManager = class {
|
|
|
251
263
|
}
|
|
252
264
|
return new URLSearchParams(params);
|
|
253
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
|
+
}
|
|
254
289
|
};
|
|
255
290
|
|
|
256
291
|
// src/managers/session-manager.ts
|
|
@@ -337,79 +372,271 @@ var SessionManager = class {
|
|
|
337
372
|
convertRunsToMessages(runs) {
|
|
338
373
|
const messages = [];
|
|
339
374
|
for (const run of runs) {
|
|
340
|
-
const timestamp =
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
if (run.tools && Array.isArray(run.tools)) {
|
|
350
|
-
for (const tool of run.tools) {
|
|
351
|
-
const toolObj = tool;
|
|
352
|
-
const toolCall = {
|
|
353
|
-
role: "tool",
|
|
354
|
-
content: toolObj.content ?? "",
|
|
355
|
-
tool_call_id: toolObj.tool_call_id ?? "",
|
|
356
|
-
tool_name: toolObj.tool_name ?? "",
|
|
357
|
-
tool_args: toolObj.tool_args ?? {},
|
|
358
|
-
tool_call_error: toolObj.tool_call_error ?? false,
|
|
359
|
-
metrics: toolObj.metrics ?? { time: 0 },
|
|
360
|
-
created_at: timestamp
|
|
361
|
-
};
|
|
362
|
-
toolCalls.push(toolCall);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
if (run.reasoning_messages && Array.isArray(run.reasoning_messages)) {
|
|
366
|
-
for (const msg of run.reasoning_messages) {
|
|
367
|
-
const reasoningMsg = msg;
|
|
368
|
-
if (reasoningMsg.role === "tool") {
|
|
369
|
-
toolCalls.push({
|
|
370
|
-
role: "tool",
|
|
371
|
-
content: reasoningMsg.content ?? "",
|
|
372
|
-
tool_call_id: reasoningMsg.tool_call_id ?? "",
|
|
373
|
-
tool_name: reasoningMsg.tool_name ?? "",
|
|
374
|
-
tool_args: reasoningMsg.tool_args ?? {},
|
|
375
|
-
tool_call_error: reasoningMsg.tool_call_error ?? false,
|
|
376
|
-
metrics: reasoningMsg.metrics ?? {
|
|
377
|
-
time: 0
|
|
378
|
-
},
|
|
379
|
-
created_at: reasoningMsg.created_at ?? timestamp
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
let contentStr = "";
|
|
385
|
-
if (typeof run.content === "string") {
|
|
386
|
-
contentStr = run.content;
|
|
387
|
-
} else if (run.content && typeof run.content === "object") {
|
|
388
|
-
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
|
+
);
|
|
389
384
|
}
|
|
390
|
-
const
|
|
391
|
-
reasoning_messages: run.reasoning_messages,
|
|
392
|
-
reasoning_steps: run.reasoning_steps,
|
|
393
|
-
references: run.references
|
|
394
|
-
} : void 0;
|
|
385
|
+
const toolCalls = this.extractToolCalls(run, timestamp);
|
|
395
386
|
messages.push({
|
|
396
387
|
role: "agent",
|
|
397
|
-
content:
|
|
388
|
+
content: this.normalizeRunContent(run.content),
|
|
398
389
|
tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
399
|
-
extra_data:
|
|
400
|
-
images: run.images,
|
|
401
|
-
videos: run.videos,
|
|
402
|
-
audio: run.audio,
|
|
403
|
-
|
|
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,
|
|
404
396
|
created_at: timestamp + 1
|
|
405
397
|
// Agent response is slightly after user message
|
|
406
398
|
});
|
|
407
399
|
}
|
|
408
400
|
return messages;
|
|
409
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
|
+
}
|
|
410
630
|
};
|
|
411
631
|
|
|
412
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
|
+
}
|
|
639
|
+
};
|
|
413
640
|
function isLegacyFormat(data) {
|
|
414
641
|
return typeof data === "object" && data !== null && "event" in data && !("data" in data) && typeof data.event === "string";
|
|
415
642
|
}
|
|
@@ -433,72 +660,139 @@ function convertNewFormatToLegacy(newFormatData) {
|
|
|
433
660
|
function processChunk(chunk, onChunk) {
|
|
434
661
|
onChunk(chunk);
|
|
435
662
|
}
|
|
436
|
-
function
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
let inString = false;
|
|
442
|
-
let escapeNext = false;
|
|
443
|
-
let jsonEndIndex = -1;
|
|
444
|
-
let i = jsonStartIndex;
|
|
445
|
-
for (; i < buffer.length; i++) {
|
|
446
|
-
const char = buffer[i];
|
|
447
|
-
if (inString) {
|
|
448
|
-
if (escapeNext) {
|
|
449
|
-
escapeNext = false;
|
|
450
|
-
} else if (char === "\\") {
|
|
451
|
-
escapeNext = true;
|
|
452
|
-
} else if (char === '"') {
|
|
453
|
-
inString = false;
|
|
454
|
-
}
|
|
455
|
-
} else if (char === '"') {
|
|
456
|
-
inString = true;
|
|
457
|
-
} else if (char === "{") {
|
|
458
|
-
braceCount++;
|
|
459
|
-
} else if (char === "}") {
|
|
460
|
-
braceCount--;
|
|
461
|
-
if (braceCount === 0) {
|
|
462
|
-
jsonEndIndex = i;
|
|
463
|
-
break;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
663
|
+
function updateJsonParserState(char, state) {
|
|
664
|
+
if (state.inString) {
|
|
665
|
+
if (state.escapeNext) {
|
|
666
|
+
state.escapeNext = false;
|
|
667
|
+
return false;
|
|
466
668
|
}
|
|
467
|
-
if (
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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);
|
|
497
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) {
|
|
498
745
|
break;
|
|
499
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);
|
|
500
795
|
}
|
|
501
|
-
return buffer;
|
|
502
796
|
}
|
|
503
797
|
async function streamResponse(options) {
|
|
504
798
|
const {
|
|
@@ -511,54 +805,30 @@ async function streamResponse(options) {
|
|
|
511
805
|
onComplete,
|
|
512
806
|
signal
|
|
513
807
|
} = options;
|
|
514
|
-
let buffer = "";
|
|
515
808
|
const finalUrl = params?.toString() ? `${apiUrl}?${params.toString()}` : apiUrl;
|
|
516
809
|
try {
|
|
517
810
|
const response = await fetch(finalUrl, {
|
|
518
811
|
method: "POST",
|
|
519
|
-
headers:
|
|
520
|
-
...!(requestBody instanceof FormData) && {
|
|
521
|
-
"Content-Type": "application/json"
|
|
522
|
-
},
|
|
523
|
-
...headers
|
|
524
|
-
},
|
|
812
|
+
headers: buildRequestHeaders(headers, requestBody),
|
|
525
813
|
body: requestBody instanceof FormData ? requestBody : JSON.stringify(requestBody),
|
|
526
814
|
signal
|
|
527
815
|
});
|
|
528
816
|
if (!response.ok) {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
if (contentType?.includes("application/json")) {
|
|
532
|
-
try {
|
|
533
|
-
const errorData = await response.json();
|
|
534
|
-
errorMessage = errorData.detail || errorData.message || errorMessage;
|
|
535
|
-
} catch {
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
throw new Error(errorMessage);
|
|
817
|
+
const errorMessage = await buildErrorMessage(response);
|
|
818
|
+
throw new StreamResponseHttpError(response.status, errorMessage);
|
|
539
819
|
}
|
|
540
820
|
if (!response.body) {
|
|
541
821
|
throw new Error("No response body");
|
|
542
822
|
}
|
|
543
|
-
|
|
544
|
-
const decoder = new TextDecoder();
|
|
545
|
-
const processStream = async () => {
|
|
546
|
-
while (true) {
|
|
547
|
-
const { done, value } = await reader.read();
|
|
548
|
-
if (done) {
|
|
549
|
-
buffer = parseBuffer(buffer, onChunk);
|
|
550
|
-
onComplete();
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
553
|
-
buffer += decoder.decode(value, { stream: true });
|
|
554
|
-
buffer = parseBuffer(buffer, onChunk);
|
|
555
|
-
}
|
|
556
|
-
};
|
|
557
|
-
await processStream();
|
|
823
|
+
await consumeResponseStream(response.body, onChunk, onComplete);
|
|
558
824
|
} catch (error) {
|
|
559
825
|
if (error instanceof Error && error.name === "AbortError") {
|
|
560
826
|
return;
|
|
561
827
|
}
|
|
828
|
+
if (error instanceof Error) {
|
|
829
|
+
onError(error);
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
562
832
|
if (typeof error === "object" && error !== null && "detail" in error) {
|
|
563
833
|
onError(new Error(String(error.detail)));
|
|
564
834
|
} else {
|
|
@@ -590,10 +860,15 @@ function processToolCall(toolCall, prevToolCalls = []) {
|
|
|
590
860
|
);
|
|
591
861
|
if (existingToolCallIndex >= 0) {
|
|
592
862
|
const updatedToolCalls = [...prevToolCalls];
|
|
593
|
-
updatedToolCalls[existingToolCallIndex]
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
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;
|
|
597
872
|
return updatedToolCalls;
|
|
598
873
|
}
|
|
599
874
|
return [...prevToolCalls, toolCall];
|
|
@@ -614,6 +889,105 @@ var EventProcessor = class {
|
|
|
614
889
|
constructor() {
|
|
615
890
|
this.lastContent = "";
|
|
616
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
|
+
}
|
|
617
991
|
/**
|
|
618
992
|
* Process a chunk and update the last message
|
|
619
993
|
*/
|
|
@@ -640,57 +1014,11 @@ var EventProcessor = class {
|
|
|
640
1014
|
break;
|
|
641
1015
|
case import_agno_types.RunEvent.RunContent:
|
|
642
1016
|
case import_agno_types.RunEvent.TeamRunContent:
|
|
643
|
-
|
|
644
|
-
const uniqueContent = chunk.content.replace(this.lastContent, "");
|
|
645
|
-
updatedMessage.content = updatedMessage.content + uniqueContent;
|
|
646
|
-
this.lastContent = chunk.content;
|
|
647
|
-
} else if (typeof chunk.content !== "string" && chunk.content !== null) {
|
|
648
|
-
const jsonBlock = getJsonMarkdown(chunk.content);
|
|
649
|
-
updatedMessage.content = updatedMessage.content + jsonBlock;
|
|
650
|
-
this.lastContent = jsonBlock;
|
|
651
|
-
}
|
|
652
|
-
updatedMessage.tool_calls = processChunkToolCalls(
|
|
653
|
-
chunk,
|
|
654
|
-
lastMessage.tool_calls
|
|
655
|
-
);
|
|
656
|
-
if (chunk.extra_data?.reasoning_steps) {
|
|
657
|
-
updatedMessage.extra_data = {
|
|
658
|
-
...updatedMessage.extra_data,
|
|
659
|
-
reasoning_steps: chunk.extra_data.reasoning_steps
|
|
660
|
-
};
|
|
661
|
-
}
|
|
662
|
-
if (chunk.extra_data?.references) {
|
|
663
|
-
updatedMessage.extra_data = {
|
|
664
|
-
...updatedMessage.extra_data,
|
|
665
|
-
references: chunk.extra_data.references
|
|
666
|
-
};
|
|
667
|
-
}
|
|
668
|
-
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
669
|
-
if (chunk.images) {
|
|
670
|
-
updatedMessage.images = chunk.images;
|
|
671
|
-
}
|
|
672
|
-
if (chunk.videos) {
|
|
673
|
-
updatedMessage.videos = chunk.videos;
|
|
674
|
-
}
|
|
675
|
-
if (chunk.audio) {
|
|
676
|
-
updatedMessage.audio = chunk.audio;
|
|
677
|
-
}
|
|
678
|
-
if (chunk.response_audio?.transcript && typeof chunk.response_audio.transcript === "string") {
|
|
679
|
-
const transcript = chunk.response_audio.transcript;
|
|
680
|
-
updatedMessage.response_audio = {
|
|
681
|
-
...updatedMessage.response_audio,
|
|
682
|
-
transcript: (updatedMessage.response_audio?.transcript || "") + transcript
|
|
683
|
-
};
|
|
684
|
-
}
|
|
1017
|
+
this.applyRunContentFields(chunk, lastMessage, updatedMessage);
|
|
685
1018
|
break;
|
|
686
1019
|
case import_agno_types.RunEvent.ReasoningStep:
|
|
687
1020
|
case import_agno_types.RunEvent.TeamReasoningStep: {
|
|
688
|
-
|
|
689
|
-
const incomingSteps = chunk.extra_data?.reasoning_steps ?? [];
|
|
690
|
-
updatedMessage.extra_data = {
|
|
691
|
-
...updatedMessage.extra_data,
|
|
692
|
-
reasoning_steps: [...existingSteps, ...incomingSteps]
|
|
693
|
-
};
|
|
1021
|
+
this.appendReasoningSteps(chunk, lastMessage, updatedMessage);
|
|
694
1022
|
break;
|
|
695
1023
|
}
|
|
696
1024
|
case import_agno_types.RunEvent.ReasoningCompleted:
|
|
@@ -704,29 +1032,7 @@ var EventProcessor = class {
|
|
|
704
1032
|
break;
|
|
705
1033
|
case import_agno_types.RunEvent.RunCompleted:
|
|
706
1034
|
case import_agno_types.RunEvent.TeamRunCompleted: {
|
|
707
|
-
|
|
708
|
-
if (typeof chunk.content === "string") {
|
|
709
|
-
updatedContent = chunk.content;
|
|
710
|
-
} else {
|
|
711
|
-
try {
|
|
712
|
-
updatedContent = JSON.stringify(chunk.content);
|
|
713
|
-
} catch {
|
|
714
|
-
updatedContent = "Error parsing response";
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
updatedMessage.content = updatedContent;
|
|
718
|
-
updatedMessage.tool_calls = processChunkToolCalls(
|
|
719
|
-
chunk,
|
|
720
|
-
lastMessage.tool_calls
|
|
721
|
-
);
|
|
722
|
-
updatedMessage.images = chunk.images ?? lastMessage.images;
|
|
723
|
-
updatedMessage.videos = chunk.videos ?? lastMessage.videos;
|
|
724
|
-
updatedMessage.response_audio = chunk.response_audio;
|
|
725
|
-
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
726
|
-
updatedMessage.extra_data = {
|
|
727
|
-
reasoning_steps: chunk.extra_data?.reasoning_steps ?? lastMessage.extra_data?.reasoning_steps,
|
|
728
|
-
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references
|
|
729
|
-
};
|
|
1035
|
+
this.applyCompletedFields(chunk, lastMessage, updatedMessage);
|
|
730
1036
|
break;
|
|
731
1037
|
}
|
|
732
1038
|
case import_agno_types.RunEvent.UpdatingMemory:
|
|
@@ -740,6 +1046,8 @@ var EventProcessor = class {
|
|
|
740
1046
|
case import_agno_types.RunEvent.TeamRunCancelled:
|
|
741
1047
|
updatedMessage.streamingError = true;
|
|
742
1048
|
break;
|
|
1049
|
+
default:
|
|
1050
|
+
break;
|
|
743
1051
|
}
|
|
744
1052
|
return updatedMessage;
|
|
745
1053
|
}
|
|
@@ -867,36 +1175,36 @@ function sanitizeObject(obj) {
|
|
|
867
1175
|
function isDevelopment() {
|
|
868
1176
|
return typeof process !== "undefined" && process.env?.NODE_ENV === "development";
|
|
869
1177
|
}
|
|
870
|
-
var Logger =
|
|
1178
|
+
var Logger = {
|
|
871
1179
|
/**
|
|
872
1180
|
* Log debug information (only in development)
|
|
873
1181
|
*/
|
|
874
|
-
|
|
1182
|
+
debug(message, data) {
|
|
875
1183
|
if (isDevelopment()) {
|
|
876
1184
|
const sanitized = data ? sanitizeObject(data) : void 0;
|
|
877
1185
|
console.debug(`[DEBUG] ${message}`, sanitized || "");
|
|
878
1186
|
}
|
|
879
|
-
}
|
|
1187
|
+
},
|
|
880
1188
|
/**
|
|
881
1189
|
* Log informational messages (only in development)
|
|
882
1190
|
*/
|
|
883
|
-
|
|
1191
|
+
info(message, data) {
|
|
884
1192
|
if (isDevelopment()) {
|
|
885
1193
|
const sanitized = data ? sanitizeObject(data) : void 0;
|
|
886
1194
|
console.info(`[INFO] ${message}`, sanitized || "");
|
|
887
1195
|
}
|
|
888
|
-
}
|
|
1196
|
+
},
|
|
889
1197
|
/**
|
|
890
1198
|
* Log warnings (always logs)
|
|
891
1199
|
*/
|
|
892
|
-
|
|
1200
|
+
warn(message, data) {
|
|
893
1201
|
const sanitized = data ? sanitizeObject(data) : void 0;
|
|
894
1202
|
console.warn(`[WARN] ${message}`, sanitized || "");
|
|
895
|
-
}
|
|
1203
|
+
},
|
|
896
1204
|
/**
|
|
897
1205
|
* Log errors (always logs)
|
|
898
1206
|
*/
|
|
899
|
-
|
|
1207
|
+
error(message, data) {
|
|
900
1208
|
const sanitized = data ? sanitizeObject(data) : void 0;
|
|
901
1209
|
console.error(`[ERROR] ${message}`, sanitized || "");
|
|
902
1210
|
}
|
|
@@ -914,16 +1222,100 @@ function toSafeISOString(timestamp) {
|
|
|
914
1222
|
}
|
|
915
1223
|
return new Date(ts).toISOString();
|
|
916
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
|
+
}
|
|
917
1308
|
var AgnoClient = class extends import_eventemitter3.default {
|
|
918
1309
|
constructor(config) {
|
|
919
1310
|
super();
|
|
920
|
-
// toolCallId -> UIComponentSpec
|
|
921
1311
|
this.runCompletedSuccessfully = false;
|
|
1312
|
+
this.currentAbortController = null;
|
|
922
1313
|
this.messageStore = new MessageStore();
|
|
923
1314
|
this.configManager = new ConfigManager(config);
|
|
924
1315
|
this.sessionManager = new SessionManager();
|
|
925
1316
|
this.eventProcessor = new EventProcessor();
|
|
926
1317
|
this.pendingUISpecs = /* @__PURE__ */ new Map();
|
|
1318
|
+
this.localAttachmentUrls = /* @__PURE__ */ new Set();
|
|
927
1319
|
this.state = {
|
|
928
1320
|
isStreaming: false,
|
|
929
1321
|
isRefreshing: false,
|
|
@@ -966,6 +1358,8 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
966
1358
|
* Clear all messages
|
|
967
1359
|
*/
|
|
968
1360
|
clearMessages() {
|
|
1361
|
+
this.revokeAttachmentUrlsFromMessages(this.messageStore.getMessages());
|
|
1362
|
+
this.localAttachmentUrls.clear();
|
|
969
1363
|
this.messageStore.clear();
|
|
970
1364
|
this.configManager.setSessionId(void 0);
|
|
971
1365
|
this.pendingUISpecs.clear();
|
|
@@ -979,42 +1373,84 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
979
1373
|
if (!(this.state.isStreaming || this.state.isPaused)) {
|
|
980
1374
|
throw new Error("No active or paused run to cancel");
|
|
981
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) {
|
|
982
1404
|
const runUrl = this.configManager.getRunUrl();
|
|
983
1405
|
if (!runUrl) {
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
if (!runId) {
|
|
988
|
-
throw new Error("No run ID available to cancel");
|
|
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;
|
|
989
1409
|
}
|
|
990
1410
|
const cancelUrl = `${runUrl}/${runId}/cancel`;
|
|
991
1411
|
const headers = this.configManager.buildRequestHeaders();
|
|
992
|
-
this.state.isCancelling = true;
|
|
993
|
-
this.emit("state:change", this.getState());
|
|
994
1412
|
try {
|
|
995
1413
|
const response = await fetch(cancelUrl, {
|
|
996
1414
|
method: "POST",
|
|
997
1415
|
headers
|
|
998
1416
|
});
|
|
999
|
-
if (
|
|
1000
|
-
|
|
1417
|
+
if (response.ok) {
|
|
1418
|
+
return void 0;
|
|
1001
1419
|
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
this.emit("state:change", this.getState());
|
|
1010
|
-
} catch (error) {
|
|
1011
|
-
this.state.isCancelling = false;
|
|
1012
|
-
this.emit("state:change", this.getState());
|
|
1013
|
-
throw new Error(
|
|
1014
|
-
`Error cancelling run: ${error instanceof Error ? error.message : String(error)}`
|
|
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`
|
|
1015
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;
|
|
1016
1434
|
}
|
|
1017
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
|
+
}
|
|
1018
1454
|
/**
|
|
1019
1455
|
* Send a message to the agent/team (streaming)
|
|
1020
1456
|
*/
|
|
@@ -1035,16 +1471,30 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1035
1471
|
if (typeof message === "string") {
|
|
1036
1472
|
formData.append("message", message);
|
|
1037
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") ?? "");
|
|
1038
1483
|
const lastMessage = this.messageStore.getLastMessage();
|
|
1039
1484
|
if (lastMessage?.streamingError) {
|
|
1040
1485
|
const secondLast = this.messageStore.getMessages()[this.messageStore.getMessages().length - 2];
|
|
1041
1486
|
if (secondLast?.role === "user") {
|
|
1487
|
+
this.revokeAttachmentUrlsFromMessages([secondLast, lastMessage]);
|
|
1042
1488
|
this.messageStore.removeLastMessages(2);
|
|
1043
1489
|
}
|
|
1044
1490
|
}
|
|
1045
1491
|
this.messageStore.addMessage({
|
|
1046
1492
|
role: "user",
|
|
1047
|
-
content:
|
|
1493
|
+
content: userMessageContent,
|
|
1494
|
+
images: userMessageMedia.images,
|
|
1495
|
+
videos: userMessageMedia.videos,
|
|
1496
|
+
audio: userMessageMedia.audio,
|
|
1497
|
+
files: userMessageMedia.files,
|
|
1048
1498
|
created_at: Math.floor(Date.now() / 1e3)
|
|
1049
1499
|
});
|
|
1050
1500
|
this.messageStore.addMessage({
|
|
@@ -1058,34 +1508,40 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1058
1508
|
this.eventProcessor.reset();
|
|
1059
1509
|
let newSessionId = this.configManager.getSessionId();
|
|
1060
1510
|
try {
|
|
1061
|
-
formData.
|
|
1062
|
-
formData.
|
|
1511
|
+
formData.set("stream", "true");
|
|
1512
|
+
formData.set("session_id", newSessionId ?? "");
|
|
1063
1513
|
const userId = this.configManager.getUserId();
|
|
1064
1514
|
if (userId) {
|
|
1065
|
-
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));
|
|
1066
1522
|
}
|
|
1067
1523
|
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
1068
1524
|
const params = this.configManager.buildQueryString(options?.params);
|
|
1525
|
+
this.currentAbortController = new AbortController();
|
|
1069
1526
|
await streamResponse({
|
|
1070
1527
|
apiUrl: runUrl,
|
|
1071
1528
|
headers,
|
|
1072
1529
|
params,
|
|
1073
1530
|
requestBody: formData,
|
|
1531
|
+
signal: this.currentAbortController.signal,
|
|
1074
1532
|
onChunk: (chunk) => {
|
|
1075
|
-
this.handleChunk(
|
|
1076
|
-
chunk,
|
|
1077
|
-
newSessionId,
|
|
1078
|
-
formData.get("message")
|
|
1079
|
-
);
|
|
1533
|
+
this.handleChunk(chunk, newSessionId, userMessageContent);
|
|
1080
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) {
|
|
1081
1535
|
newSessionId = chunk.session_id;
|
|
1082
1536
|
this.configManager.setSessionId(chunk.session_id);
|
|
1083
1537
|
}
|
|
1084
1538
|
},
|
|
1085
1539
|
onError: (error) => {
|
|
1540
|
+
this.currentAbortController = null;
|
|
1086
1541
|
this.handleError(error, newSessionId);
|
|
1087
1542
|
},
|
|
1088
1543
|
onComplete: async () => {
|
|
1544
|
+
this.currentAbortController = null;
|
|
1089
1545
|
this.state.isStreaming = false;
|
|
1090
1546
|
this.currentRunId = void 0;
|
|
1091
1547
|
this.emit("stream:end");
|
|
@@ -1098,6 +1554,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1098
1554
|
}
|
|
1099
1555
|
});
|
|
1100
1556
|
} catch (error) {
|
|
1557
|
+
this.currentAbortController = null;
|
|
1101
1558
|
this.handleError(
|
|
1102
1559
|
error instanceof Error ? error : new Error(String(error)),
|
|
1103
1560
|
newSessionId
|
|
@@ -1183,6 +1640,73 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1183
1640
|
this.emit("stream:end");
|
|
1184
1641
|
this.emit("state:change", this.getState());
|
|
1185
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
|
+
}
|
|
1186
1710
|
/**
|
|
1187
1711
|
* Refresh messages from the session API after run completion.
|
|
1188
1712
|
* Replaces streamed messages with authoritative session data.
|
|
@@ -1195,22 +1719,14 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1195
1719
|
Logger.debug("[AgnoClient] Cannot refresh: no session ID");
|
|
1196
1720
|
return;
|
|
1197
1721
|
}
|
|
1722
|
+
if (this.state.isStreaming) {
|
|
1723
|
+
Logger.debug("[AgnoClient] Skipping refresh: stream is active");
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1198
1726
|
this.state.isRefreshing = true;
|
|
1199
1727
|
this.emit("state:change", this.getState());
|
|
1200
1728
|
try {
|
|
1201
|
-
const existingUIComponents =
|
|
1202
|
-
for (const message of this.messageStore.getMessages()) {
|
|
1203
|
-
if (message.tool_calls) {
|
|
1204
|
-
for (const toolCall of message.tool_calls) {
|
|
1205
|
-
if (toolCall.ui_component) {
|
|
1206
|
-
existingUIComponents.set(
|
|
1207
|
-
toolCall.tool_call_id,
|
|
1208
|
-
toolCall.ui_component
|
|
1209
|
-
);
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1729
|
+
const existingUIComponents = this.collectExistingUIComponents();
|
|
1214
1730
|
const config = this.configManager.getConfig();
|
|
1215
1731
|
const entityType = this.configManager.getMode();
|
|
1216
1732
|
const dbId = this.configManager.getDbId() || "";
|
|
@@ -1226,22 +1742,15 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1226
1742
|
userId,
|
|
1227
1743
|
params
|
|
1228
1744
|
);
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
const toolCall = message.tool_calls[i];
|
|
1235
|
-
const uiComponent = existingUIComponents.get(
|
|
1236
|
-
toolCall.tool_call_id
|
|
1237
|
-
);
|
|
1238
|
-
if (uiComponent) {
|
|
1239
|
-
message.tool_calls[i].ui_component = uiComponent;
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1745
|
+
if (this.state.isStreaming) {
|
|
1746
|
+
Logger.debug(
|
|
1747
|
+
"[AgnoClient] Aborting refresh: stream started during fetch"
|
|
1748
|
+
);
|
|
1749
|
+
return;
|
|
1244
1750
|
}
|
|
1751
|
+
const messages = this.sessionManager.convertSessionToMessages(response);
|
|
1752
|
+
this.restoreUIComponents(messages, existingUIComponents);
|
|
1753
|
+
this.revokeAttachmentUrlsFromMessages(this.messageStore.getMessages());
|
|
1245
1754
|
this.messageStore.setMessages(messages);
|
|
1246
1755
|
Logger.debug(
|
|
1247
1756
|
"[AgnoClient] Session refreshed:",
|
|
@@ -1290,6 +1799,7 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1290
1799
|
"[AgnoClient] Setting messages to store:",
|
|
1291
1800
|
`${messages.length} messages`
|
|
1292
1801
|
);
|
|
1802
|
+
this.revokeAttachmentUrlsFromMessages(this.messageStore.getMessages());
|
|
1293
1803
|
this.messageStore.setMessages(messages);
|
|
1294
1804
|
this.configManager.setSessionId(sessionId);
|
|
1295
1805
|
Logger.debug("[AgnoClient] Emitting events...");
|
|
@@ -1441,9 +1951,9 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1441
1951
|
}
|
|
1442
1952
|
}
|
|
1443
1953
|
if (updatedMessages.length > 0) {
|
|
1444
|
-
|
|
1954
|
+
for (const { index, message } of updatedMessages) {
|
|
1445
1955
|
this.messageStore.updateMessage(index, () => message);
|
|
1446
|
-
}
|
|
1956
|
+
}
|
|
1447
1957
|
this.emit("message:update", this.messageStore.getMessages());
|
|
1448
1958
|
}
|
|
1449
1959
|
}
|
|
@@ -1471,15 +1981,48 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1471
1981
|
if (!runUrl) {
|
|
1472
1982
|
throw new Error("No agent or team selected");
|
|
1473
1983
|
}
|
|
1474
|
-
const
|
|
1475
|
-
|
|
1984
|
+
const pausedRunId = this.state.pausedRunId;
|
|
1985
|
+
const continueUrl = `${runUrl}/${pausedRunId}/continue`;
|
|
1476
1986
|
this.state.isStreaming = true;
|
|
1477
|
-
this.
|
|
1987
|
+
this.state.errorMessage = void 0;
|
|
1478
1988
|
this.emit("state:change", this.getState());
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
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
|
+
);
|
|
1483
2026
|
const formData = new FormData();
|
|
1484
2027
|
formData.append("tools", JSON.stringify(cleanedTools));
|
|
1485
2028
|
formData.append("stream", "true");
|
|
@@ -1493,36 +2036,45 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1493
2036
|
}
|
|
1494
2037
|
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
1495
2038
|
const params = this.configManager.buildQueryString(options?.params);
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
|
|
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) {
|
|
1510
2064
|
this.state.pausedRunId = void 0;
|
|
1511
2065
|
this.state.toolsAwaitingExecution = void 0;
|
|
1512
|
-
this.emit("stream:end");
|
|
1513
|
-
this.emit("message:complete", this.messageStore.getMessages());
|
|
1514
|
-
this.emit("state:change", this.getState());
|
|
1515
|
-
if (this.runCompletedSuccessfully) {
|
|
1516
|
-
this.runCompletedSuccessfully = false;
|
|
1517
|
-
await this.refreshSessionMessages();
|
|
1518
|
-
}
|
|
1519
2066
|
}
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
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;
|
|
1526
2078
|
}
|
|
1527
2079
|
}
|
|
1528
2080
|
/**
|
|
@@ -1634,7 +2186,13 @@ var AgnoClient = class extends import_eventemitter3.default {
|
|
|
1634
2186
|
* After calling dispose(), the client instance should not be reused.
|
|
1635
2187
|
*/
|
|
1636
2188
|
dispose() {
|
|
2189
|
+
if (this.currentAbortController) {
|
|
2190
|
+
this.currentAbortController.abort();
|
|
2191
|
+
this.currentAbortController = null;
|
|
2192
|
+
}
|
|
1637
2193
|
this.removeAllListeners();
|
|
2194
|
+
this.revokeAttachmentUrlsFromMessages(this.messageStore.getMessages());
|
|
2195
|
+
this.localAttachmentUrls.clear();
|
|
1638
2196
|
this.messageStore.clear();
|
|
1639
2197
|
this.pendingUISpecs.clear();
|
|
1640
2198
|
this.eventProcessor.reset();
|