@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.mjs
CHANGED
|
@@ -148,6 +148,18 @@ var ConfigManager = class {
|
|
|
148
148
|
setParams(params) {
|
|
149
149
|
this.updateField("params", params);
|
|
150
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Get global dependencies
|
|
153
|
+
*/
|
|
154
|
+
getDependencies() {
|
|
155
|
+
return this.config.dependencies;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Set global dependencies
|
|
159
|
+
*/
|
|
160
|
+
setDependencies(dependencies) {
|
|
161
|
+
this.updateField("dependencies", dependencies);
|
|
162
|
+
}
|
|
151
163
|
/**
|
|
152
164
|
* Get current entity ID (agent or team based on mode)
|
|
153
165
|
*/
|
|
@@ -215,6 +227,29 @@ var ConfigManager = class {
|
|
|
215
227
|
}
|
|
216
228
|
return new URLSearchParams(params);
|
|
217
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Build dependencies by merging global dependencies and per-request dependencies.
|
|
232
|
+
* Merge order (lowest to highest precedence):
|
|
233
|
+
* 1. Global dependencies from config
|
|
234
|
+
* 2. Per-request dependencies (overrides global)
|
|
235
|
+
*
|
|
236
|
+
* @param perRequestDependencies - Optional dependencies for this specific request
|
|
237
|
+
* @returns Merged dependencies object, or undefined if no dependencies are configured
|
|
238
|
+
*/
|
|
239
|
+
buildDependencies(perRequestDependencies) {
|
|
240
|
+
const dependencies = {};
|
|
241
|
+
const globalDependencies = this.getDependencies();
|
|
242
|
+
if (globalDependencies) {
|
|
243
|
+
Object.assign(dependencies, globalDependencies);
|
|
244
|
+
}
|
|
245
|
+
if (perRequestDependencies) {
|
|
246
|
+
Object.assign(dependencies, perRequestDependencies);
|
|
247
|
+
}
|
|
248
|
+
if (Object.keys(dependencies).length === 0) {
|
|
249
|
+
return void 0;
|
|
250
|
+
}
|
|
251
|
+
return dependencies;
|
|
252
|
+
}
|
|
218
253
|
};
|
|
219
254
|
|
|
220
255
|
// src/managers/session-manager.ts
|
|
@@ -301,79 +336,271 @@ var SessionManager = class {
|
|
|
301
336
|
convertRunsToMessages(runs) {
|
|
302
337
|
const messages = [];
|
|
303
338
|
for (const run of runs) {
|
|
304
|
-
const timestamp =
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
if (run.tools && Array.isArray(run.tools)) {
|
|
314
|
-
for (const tool of run.tools) {
|
|
315
|
-
const toolObj = tool;
|
|
316
|
-
const toolCall = {
|
|
317
|
-
role: "tool",
|
|
318
|
-
content: toolObj.content ?? "",
|
|
319
|
-
tool_call_id: toolObj.tool_call_id ?? "",
|
|
320
|
-
tool_name: toolObj.tool_name ?? "",
|
|
321
|
-
tool_args: toolObj.tool_args ?? {},
|
|
322
|
-
tool_call_error: toolObj.tool_call_error ?? false,
|
|
323
|
-
metrics: toolObj.metrics ?? { time: 0 },
|
|
324
|
-
created_at: timestamp
|
|
325
|
-
};
|
|
326
|
-
toolCalls.push(toolCall);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
if (run.reasoning_messages && Array.isArray(run.reasoning_messages)) {
|
|
330
|
-
for (const msg of run.reasoning_messages) {
|
|
331
|
-
const reasoningMsg = msg;
|
|
332
|
-
if (reasoningMsg.role === "tool") {
|
|
333
|
-
toolCalls.push({
|
|
334
|
-
role: "tool",
|
|
335
|
-
content: reasoningMsg.content ?? "",
|
|
336
|
-
tool_call_id: reasoningMsg.tool_call_id ?? "",
|
|
337
|
-
tool_name: reasoningMsg.tool_name ?? "",
|
|
338
|
-
tool_args: reasoningMsg.tool_args ?? {},
|
|
339
|
-
tool_call_error: reasoningMsg.tool_call_error ?? false,
|
|
340
|
-
metrics: reasoningMsg.metrics ?? {
|
|
341
|
-
time: 0
|
|
342
|
-
},
|
|
343
|
-
created_at: reasoningMsg.created_at ?? timestamp
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
let contentStr = "";
|
|
349
|
-
if (typeof run.content === "string") {
|
|
350
|
-
contentStr = run.content;
|
|
351
|
-
} else if (run.content && typeof run.content === "object") {
|
|
352
|
-
contentStr = JSON.stringify(run.content);
|
|
339
|
+
const timestamp = this.getRunTimestamp(run);
|
|
340
|
+
const inputMedia = this.mergeInputMedia(
|
|
341
|
+
this.extractInputMedia(run.input_media),
|
|
342
|
+
this.extractInputMediaFromMessages(run.messages)
|
|
343
|
+
);
|
|
344
|
+
if (run.run_input || this.hasAnyMedia(inputMedia)) {
|
|
345
|
+
messages.push(
|
|
346
|
+
this.buildUserMessage(run.run_input ?? "", timestamp, inputMedia)
|
|
347
|
+
);
|
|
353
348
|
}
|
|
354
|
-
const
|
|
355
|
-
reasoning_messages: run.reasoning_messages,
|
|
356
|
-
reasoning_steps: run.reasoning_steps,
|
|
357
|
-
references: run.references
|
|
358
|
-
} : void 0;
|
|
349
|
+
const toolCalls = this.extractToolCalls(run, timestamp);
|
|
359
350
|
messages.push({
|
|
360
351
|
role: "agent",
|
|
361
|
-
content:
|
|
352
|
+
content: this.normalizeRunContent(run.content),
|
|
362
353
|
tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
363
|
-
extra_data:
|
|
364
|
-
images: run.images,
|
|
365
|
-
videos: run.videos,
|
|
366
|
-
audio: run.audio,
|
|
367
|
-
|
|
354
|
+
extra_data: this.buildExtraData(run),
|
|
355
|
+
images: this.normalizeImages(run.images),
|
|
356
|
+
videos: this.normalizeVideos(run.videos),
|
|
357
|
+
audio: this.normalizeAudio(run.audio),
|
|
358
|
+
files: this.normalizeFiles(run.files),
|
|
359
|
+
response_audio: run.response_audio ?? void 0,
|
|
368
360
|
created_at: timestamp + 1
|
|
369
361
|
// Agent response is slightly after user message
|
|
370
362
|
});
|
|
371
363
|
}
|
|
372
364
|
return messages;
|
|
373
365
|
}
|
|
366
|
+
getRunTimestamp(run) {
|
|
367
|
+
return run.created_at ? new Date(run.created_at).getTime() / 1e3 : Math.floor(Date.now() / 1e3);
|
|
368
|
+
}
|
|
369
|
+
buildUserMessage(content, createdAt, media) {
|
|
370
|
+
return {
|
|
371
|
+
role: "user",
|
|
372
|
+
content,
|
|
373
|
+
images: media?.images,
|
|
374
|
+
videos: media?.videos,
|
|
375
|
+
audio: media?.audio,
|
|
376
|
+
files: media?.files,
|
|
377
|
+
created_at: createdAt
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
hasAnyMedia(media) {
|
|
381
|
+
return Boolean(
|
|
382
|
+
media.images && media.images.length > 0 || media.videos && media.videos.length > 0 || media.audio && media.audio.length > 0 || media.files && media.files.length > 0
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
isRecord(value) {
|
|
386
|
+
return typeof value === "object" && value !== null;
|
|
387
|
+
}
|
|
388
|
+
getStringValue(record, key) {
|
|
389
|
+
const value = record[key];
|
|
390
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
391
|
+
}
|
|
392
|
+
getNumberOrStringValue(record, key) {
|
|
393
|
+
const value = record[key];
|
|
394
|
+
return typeof value === "number" || typeof value === "string" ? value : void 0;
|
|
395
|
+
}
|
|
396
|
+
buildDataUrl(content, mimeType, fallbackMimeType) {
|
|
397
|
+
const safeMimeType = mimeType || fallbackMimeType;
|
|
398
|
+
return `data:${safeMimeType};base64,${content}`;
|
|
399
|
+
}
|
|
400
|
+
normalizeImage(item) {
|
|
401
|
+
if (!this.isRecord(item)) {
|
|
402
|
+
return void 0;
|
|
403
|
+
}
|
|
404
|
+
const mimeType = this.getStringValue(item, "mime_type");
|
|
405
|
+
const content = this.getStringValue(item, "content");
|
|
406
|
+
const url = this.getStringValue(item, "url") || (content ? this.buildDataUrl(content, mimeType, "image/png") : void 0);
|
|
407
|
+
if (!url) {
|
|
408
|
+
return void 0;
|
|
409
|
+
}
|
|
410
|
+
return {
|
|
411
|
+
url,
|
|
412
|
+
revised_prompt: this.getStringValue(item, "revised_prompt"),
|
|
413
|
+
original_prompt: this.getStringValue(item, "original_prompt"),
|
|
414
|
+
alt_text: this.getStringValue(item, "alt_text"),
|
|
415
|
+
id: this.getStringValue(item, "id"),
|
|
416
|
+
mime_type: mimeType,
|
|
417
|
+
format: this.getStringValue(item, "format")
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
normalizeVideo(item) {
|
|
421
|
+
if (!this.isRecord(item)) {
|
|
422
|
+
return void 0;
|
|
423
|
+
}
|
|
424
|
+
const mimeType = this.getStringValue(item, "mime_type");
|
|
425
|
+
const content = this.getStringValue(item, "content");
|
|
426
|
+
const url = this.getStringValue(item, "url") || (content ? this.buildDataUrl(content, mimeType, "video/mp4") : void 0);
|
|
427
|
+
const normalized = {
|
|
428
|
+
url,
|
|
429
|
+
id: this.getNumberOrStringValue(item, "id"),
|
|
430
|
+
eta: this.getNumberOrStringValue(item, "eta"),
|
|
431
|
+
mime_type: mimeType,
|
|
432
|
+
format: this.getStringValue(item, "format"),
|
|
433
|
+
original_prompt: this.getStringValue(item, "original_prompt"),
|
|
434
|
+
revised_prompt: this.getStringValue(item, "revised_prompt"),
|
|
435
|
+
width: typeof item.width === "number" ? item.width : void 0,
|
|
436
|
+
height: typeof item.height === "number" ? item.height : void 0,
|
|
437
|
+
fps: typeof item.fps === "number" ? item.fps : void 0,
|
|
438
|
+
duration: typeof item.duration === "number" ? item.duration : void 0
|
|
439
|
+
};
|
|
440
|
+
if (normalized.url || normalized.id !== void 0 || normalized.eta !== void 0) {
|
|
441
|
+
return normalized;
|
|
442
|
+
}
|
|
443
|
+
return void 0;
|
|
444
|
+
}
|
|
445
|
+
normalizeAudioEntry(item) {
|
|
446
|
+
if (!this.isRecord(item)) {
|
|
447
|
+
return void 0;
|
|
448
|
+
}
|
|
449
|
+
const mimeType = this.getStringValue(item, "mime_type");
|
|
450
|
+
const content = this.getStringValue(item, "content");
|
|
451
|
+
const url = this.getStringValue(item, "url") || (content ? this.buildDataUrl(content, mimeType, "audio/wav") : void 0);
|
|
452
|
+
const normalized = {
|
|
453
|
+
base64_audio: this.getStringValue(item, "base64_audio"),
|
|
454
|
+
mime_type: mimeType,
|
|
455
|
+
url,
|
|
456
|
+
id: this.getNumberOrStringValue(item, "id"),
|
|
457
|
+
content,
|
|
458
|
+
channels: typeof item.channels === "number" ? item.channels : void 0,
|
|
459
|
+
sample_rate: typeof item.sample_rate === "number" ? item.sample_rate : void 0,
|
|
460
|
+
format: this.getStringValue(item, "format"),
|
|
461
|
+
duration: typeof item.duration === "number" ? item.duration : void 0
|
|
462
|
+
};
|
|
463
|
+
if (normalized.url || normalized.base64_audio || normalized.content || normalized.id !== void 0) {
|
|
464
|
+
return normalized;
|
|
465
|
+
}
|
|
466
|
+
return void 0;
|
|
467
|
+
}
|
|
468
|
+
normalizeFileEntry(item) {
|
|
469
|
+
if (!this.isRecord(item)) {
|
|
470
|
+
return void 0;
|
|
471
|
+
}
|
|
472
|
+
const normalized = {
|
|
473
|
+
id: this.getStringValue(item, "id"),
|
|
474
|
+
url: this.getStringValue(item, "url"),
|
|
475
|
+
filename: this.getStringValue(item, "filename"),
|
|
476
|
+
name: this.getStringValue(item, "name"),
|
|
477
|
+
mime_type: this.getStringValue(item, "mime_type"),
|
|
478
|
+
format: this.getStringValue(item, "format"),
|
|
479
|
+
size: typeof item.size === "number" ? item.size : void 0
|
|
480
|
+
};
|
|
481
|
+
if (normalized.url || normalized.filename || normalized.name || normalized.id) {
|
|
482
|
+
return normalized;
|
|
483
|
+
}
|
|
484
|
+
return void 0;
|
|
485
|
+
}
|
|
486
|
+
normalizeArray(value, normalizer) {
|
|
487
|
+
if (!Array.isArray(value)) {
|
|
488
|
+
return void 0;
|
|
489
|
+
}
|
|
490
|
+
const items = value.map((item) => normalizer(item)).filter((item) => item !== void 0);
|
|
491
|
+
return items.length > 0 ? items : void 0;
|
|
492
|
+
}
|
|
493
|
+
normalizeImages(value) {
|
|
494
|
+
return this.normalizeArray(value, (item) => this.normalizeImage(item));
|
|
495
|
+
}
|
|
496
|
+
normalizeVideos(value) {
|
|
497
|
+
return this.normalizeArray(value, (item) => this.normalizeVideo(item));
|
|
498
|
+
}
|
|
499
|
+
normalizeAudio(value) {
|
|
500
|
+
return this.normalizeArray(value, (item) => this.normalizeAudioEntry(item));
|
|
501
|
+
}
|
|
502
|
+
normalizeFiles(value) {
|
|
503
|
+
return this.normalizeArray(value, (item) => this.normalizeFileEntry(item));
|
|
504
|
+
}
|
|
505
|
+
extractInputMedia(inputMedia) {
|
|
506
|
+
if (!this.isRecord(inputMedia)) {
|
|
507
|
+
return {};
|
|
508
|
+
}
|
|
509
|
+
return {
|
|
510
|
+
images: this.normalizeImages(inputMedia.images),
|
|
511
|
+
videos: this.normalizeVideos(inputMedia.videos),
|
|
512
|
+
audio: this.normalizeAudio(inputMedia.audios ?? inputMedia.audio),
|
|
513
|
+
files: this.normalizeFiles(inputMedia.files)
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
extractInputMediaFromMessages(messages) {
|
|
517
|
+
if (!Array.isArray(messages)) {
|
|
518
|
+
return {};
|
|
519
|
+
}
|
|
520
|
+
for (const message of messages) {
|
|
521
|
+
if (!this.isRecord(message)) {
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
if (this.getStringValue(message, "role") !== "user") {
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
const media = {
|
|
528
|
+
images: this.normalizeImages(message.images ?? message.image),
|
|
529
|
+
videos: this.normalizeVideos(message.videos ?? message.video),
|
|
530
|
+
audio: this.normalizeAudio(message.audios ?? message.audio),
|
|
531
|
+
files: this.normalizeFiles(message.files)
|
|
532
|
+
};
|
|
533
|
+
if (this.hasAnyMedia(media)) {
|
|
534
|
+
return media;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return {};
|
|
538
|
+
}
|
|
539
|
+
mergeInputMedia(primary, fallback) {
|
|
540
|
+
return {
|
|
541
|
+
images: primary.images ?? fallback.images,
|
|
542
|
+
videos: primary.videos ?? fallback.videos,
|
|
543
|
+
audio: primary.audio ?? fallback.audio,
|
|
544
|
+
files: primary.files ?? fallback.files
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
normalizeRunContent(content) {
|
|
548
|
+
if (typeof content === "string") {
|
|
549
|
+
return content;
|
|
550
|
+
}
|
|
551
|
+
if (content && typeof content === "object") {
|
|
552
|
+
return JSON.stringify(content);
|
|
553
|
+
}
|
|
554
|
+
return "";
|
|
555
|
+
}
|
|
556
|
+
buildToolCall(rawTool, fallbackTimestamp) {
|
|
557
|
+
return {
|
|
558
|
+
role: "tool",
|
|
559
|
+
content: rawTool.content ?? "",
|
|
560
|
+
tool_call_id: rawTool.tool_call_id ?? "",
|
|
561
|
+
tool_name: rawTool.tool_name ?? "",
|
|
562
|
+
tool_args: rawTool.tool_args ?? {},
|
|
563
|
+
tool_call_error: rawTool.tool_call_error ?? false,
|
|
564
|
+
metrics: rawTool.metrics ?? { time: 0 },
|
|
565
|
+
created_at: rawTool.created_at ?? fallbackTimestamp
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
extractToolCalls(run, timestamp) {
|
|
569
|
+
const toolCalls = [];
|
|
570
|
+
if (run.tools && Array.isArray(run.tools)) {
|
|
571
|
+
for (const tool of run.tools) {
|
|
572
|
+
toolCalls.push(this.buildToolCall(tool, timestamp));
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (run.reasoning_messages && Array.isArray(run.reasoning_messages)) {
|
|
576
|
+
for (const message of run.reasoning_messages) {
|
|
577
|
+
if (message.role === "tool") {
|
|
578
|
+
toolCalls.push(this.buildToolCall(message, timestamp));
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return toolCalls;
|
|
583
|
+
}
|
|
584
|
+
buildExtraData(run) {
|
|
585
|
+
if (!(run.reasoning_messages || run.reasoning_steps || run.references)) {
|
|
586
|
+
return void 0;
|
|
587
|
+
}
|
|
588
|
+
return {
|
|
589
|
+
reasoning_messages: run.reasoning_messages,
|
|
590
|
+
reasoning_steps: run.reasoning_steps,
|
|
591
|
+
references: run.references
|
|
592
|
+
};
|
|
593
|
+
}
|
|
374
594
|
};
|
|
375
595
|
|
|
376
596
|
// src/parsers/stream-parser.ts
|
|
597
|
+
var StreamResponseHttpError = class extends Error {
|
|
598
|
+
constructor(status, message) {
|
|
599
|
+
super(message);
|
|
600
|
+
this.name = "StreamResponseHttpError";
|
|
601
|
+
this.status = status;
|
|
602
|
+
}
|
|
603
|
+
};
|
|
377
604
|
function isLegacyFormat(data) {
|
|
378
605
|
return typeof data === "object" && data !== null && "event" in data && !("data" in data) && typeof data.event === "string";
|
|
379
606
|
}
|
|
@@ -397,72 +624,139 @@ function convertNewFormatToLegacy(newFormatData) {
|
|
|
397
624
|
function processChunk(chunk, onChunk) {
|
|
398
625
|
onChunk(chunk);
|
|
399
626
|
}
|
|
400
|
-
function
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
let inString = false;
|
|
406
|
-
let escapeNext = false;
|
|
407
|
-
let jsonEndIndex = -1;
|
|
408
|
-
let i = jsonStartIndex;
|
|
409
|
-
for (; i < buffer.length; i++) {
|
|
410
|
-
const char = buffer[i];
|
|
411
|
-
if (inString) {
|
|
412
|
-
if (escapeNext) {
|
|
413
|
-
escapeNext = false;
|
|
414
|
-
} else if (char === "\\") {
|
|
415
|
-
escapeNext = true;
|
|
416
|
-
} else if (char === '"') {
|
|
417
|
-
inString = false;
|
|
418
|
-
}
|
|
419
|
-
} else if (char === '"') {
|
|
420
|
-
inString = true;
|
|
421
|
-
} else if (char === "{") {
|
|
422
|
-
braceCount++;
|
|
423
|
-
} else if (char === "}") {
|
|
424
|
-
braceCount--;
|
|
425
|
-
if (braceCount === 0) {
|
|
426
|
-
jsonEndIndex = i;
|
|
427
|
-
break;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
627
|
+
function updateJsonParserState(char, state) {
|
|
628
|
+
if (state.inString) {
|
|
629
|
+
if (state.escapeNext) {
|
|
630
|
+
state.escapeNext = false;
|
|
631
|
+
return false;
|
|
430
632
|
}
|
|
431
|
-
if (
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
633
|
+
if (char === "\\") {
|
|
634
|
+
state.escapeNext = true;
|
|
635
|
+
return false;
|
|
636
|
+
}
|
|
637
|
+
if (char === '"') {
|
|
638
|
+
state.inString = false;
|
|
639
|
+
}
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
if (char === '"') {
|
|
643
|
+
state.inString = true;
|
|
644
|
+
return false;
|
|
645
|
+
}
|
|
646
|
+
if (char === "{") {
|
|
647
|
+
state.braceCount++;
|
|
648
|
+
return false;
|
|
649
|
+
}
|
|
650
|
+
if (char !== "}") {
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
state.braceCount--;
|
|
654
|
+
return state.braceCount === 0;
|
|
655
|
+
}
|
|
656
|
+
function findJsonSlice(buffer, fromIndex) {
|
|
657
|
+
const startIndex = buffer.indexOf("{", fromIndex);
|
|
658
|
+
if (startIndex === -1) {
|
|
659
|
+
return void 0;
|
|
660
|
+
}
|
|
661
|
+
const parserState = {
|
|
662
|
+
braceCount: 0,
|
|
663
|
+
inString: false,
|
|
664
|
+
escapeNext: false
|
|
665
|
+
};
|
|
666
|
+
for (let i = startIndex; i < buffer.length; i++) {
|
|
667
|
+
const isJsonComplete = updateJsonParserState(buffer[i], parserState);
|
|
668
|
+
if (isJsonComplete) {
|
|
669
|
+
return { startIndex, endIndex: i };
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
return void 0;
|
|
673
|
+
}
|
|
674
|
+
function logChunkParseError(error, jsonString, position) {
|
|
675
|
+
if (typeof process === "undefined" || process.env?.NODE_ENV !== "development") {
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
console.error("Failed to parse JSON chunk:", {
|
|
679
|
+
error,
|
|
680
|
+
chunk: jsonString.substring(0, 100) + (jsonString.length > 100 ? "..." : ""),
|
|
681
|
+
position
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
function processJsonSlice(jsonString, startIndex, onChunk) {
|
|
685
|
+
try {
|
|
686
|
+
const parsed = JSON.parse(jsonString);
|
|
687
|
+
if (isLegacyFormat(parsed)) {
|
|
688
|
+
processChunk(parsed, onChunk);
|
|
461
689
|
} else {
|
|
690
|
+
processChunk(convertNewFormatToLegacy(parsed), onChunk);
|
|
691
|
+
}
|
|
692
|
+
return true;
|
|
693
|
+
} catch (error) {
|
|
694
|
+
logChunkParseError(error, jsonString, startIndex);
|
|
695
|
+
if (jsonString.length > 1e4) {
|
|
696
|
+
throw new Error(
|
|
697
|
+
`Failed to parse large JSON chunk at position ${startIndex}`
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
function parseBuffer(buffer, onChunk) {
|
|
704
|
+
let searchIndex = 0;
|
|
705
|
+
let remainingBuffer = buffer;
|
|
706
|
+
while (true) {
|
|
707
|
+
const jsonSlice = findJsonSlice(remainingBuffer, searchIndex);
|
|
708
|
+
if (!jsonSlice) {
|
|
462
709
|
break;
|
|
463
710
|
}
|
|
711
|
+
const jsonString = remainingBuffer.slice(
|
|
712
|
+
jsonSlice.startIndex,
|
|
713
|
+
jsonSlice.endIndex + 1
|
|
714
|
+
);
|
|
715
|
+
const parsed = processJsonSlice(jsonString, jsonSlice.startIndex, onChunk);
|
|
716
|
+
if (!parsed) {
|
|
717
|
+
searchIndex = jsonSlice.startIndex + 1;
|
|
718
|
+
continue;
|
|
719
|
+
}
|
|
720
|
+
remainingBuffer = remainingBuffer.slice(jsonSlice.endIndex + 1).trim();
|
|
721
|
+
searchIndex = 0;
|
|
722
|
+
}
|
|
723
|
+
return remainingBuffer;
|
|
724
|
+
}
|
|
725
|
+
function buildRequestHeaders(headers, requestBody) {
|
|
726
|
+
return {
|
|
727
|
+
...!(requestBody instanceof FormData) && {
|
|
728
|
+
"Content-Type": "application/json"
|
|
729
|
+
},
|
|
730
|
+
...headers
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
async function buildErrorMessage(response) {
|
|
734
|
+
const defaultMessage = `HTTP ${response.status}: ${response.statusText}`;
|
|
735
|
+
const contentType = response.headers.get("content-type");
|
|
736
|
+
if (!contentType?.includes("application/json")) {
|
|
737
|
+
return defaultMessage;
|
|
738
|
+
}
|
|
739
|
+
try {
|
|
740
|
+
const errorData = await response.json();
|
|
741
|
+
return errorData.detail || errorData.message || defaultMessage;
|
|
742
|
+
} catch {
|
|
743
|
+
return defaultMessage;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
async function consumeResponseStream(body, onChunk, onComplete) {
|
|
747
|
+
const reader = body.getReader();
|
|
748
|
+
const decoder = new TextDecoder();
|
|
749
|
+
let buffer = "";
|
|
750
|
+
while (true) {
|
|
751
|
+
const { done, value } = await reader.read();
|
|
752
|
+
if (done) {
|
|
753
|
+
parseBuffer(buffer, onChunk);
|
|
754
|
+
onComplete();
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
buffer += decoder.decode(value, { stream: true });
|
|
758
|
+
buffer = parseBuffer(buffer, onChunk);
|
|
464
759
|
}
|
|
465
|
-
return buffer;
|
|
466
760
|
}
|
|
467
761
|
async function streamResponse(options) {
|
|
468
762
|
const {
|
|
@@ -475,54 +769,30 @@ async function streamResponse(options) {
|
|
|
475
769
|
onComplete,
|
|
476
770
|
signal
|
|
477
771
|
} = options;
|
|
478
|
-
let buffer = "";
|
|
479
772
|
const finalUrl = params?.toString() ? `${apiUrl}?${params.toString()}` : apiUrl;
|
|
480
773
|
try {
|
|
481
774
|
const response = await fetch(finalUrl, {
|
|
482
775
|
method: "POST",
|
|
483
|
-
headers:
|
|
484
|
-
...!(requestBody instanceof FormData) && {
|
|
485
|
-
"Content-Type": "application/json"
|
|
486
|
-
},
|
|
487
|
-
...headers
|
|
488
|
-
},
|
|
776
|
+
headers: buildRequestHeaders(headers, requestBody),
|
|
489
777
|
body: requestBody instanceof FormData ? requestBody : JSON.stringify(requestBody),
|
|
490
778
|
signal
|
|
491
779
|
});
|
|
492
780
|
if (!response.ok) {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
if (contentType?.includes("application/json")) {
|
|
496
|
-
try {
|
|
497
|
-
const errorData = await response.json();
|
|
498
|
-
errorMessage = errorData.detail || errorData.message || errorMessage;
|
|
499
|
-
} catch {
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
throw new Error(errorMessage);
|
|
781
|
+
const errorMessage = await buildErrorMessage(response);
|
|
782
|
+
throw new StreamResponseHttpError(response.status, errorMessage);
|
|
503
783
|
}
|
|
504
784
|
if (!response.body) {
|
|
505
785
|
throw new Error("No response body");
|
|
506
786
|
}
|
|
507
|
-
|
|
508
|
-
const decoder = new TextDecoder();
|
|
509
|
-
const processStream = async () => {
|
|
510
|
-
while (true) {
|
|
511
|
-
const { done, value } = await reader.read();
|
|
512
|
-
if (done) {
|
|
513
|
-
buffer = parseBuffer(buffer, onChunk);
|
|
514
|
-
onComplete();
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
buffer += decoder.decode(value, { stream: true });
|
|
518
|
-
buffer = parseBuffer(buffer, onChunk);
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
await processStream();
|
|
787
|
+
await consumeResponseStream(response.body, onChunk, onComplete);
|
|
522
788
|
} catch (error) {
|
|
523
789
|
if (error instanceof Error && error.name === "AbortError") {
|
|
524
790
|
return;
|
|
525
791
|
}
|
|
792
|
+
if (error instanceof Error) {
|
|
793
|
+
onError(error);
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
526
796
|
if (typeof error === "object" && error !== null && "detail" in error) {
|
|
527
797
|
onError(new Error(String(error.detail)));
|
|
528
798
|
} else {
|
|
@@ -554,10 +824,15 @@ function processToolCall(toolCall, prevToolCalls = []) {
|
|
|
554
824
|
);
|
|
555
825
|
if (existingToolCallIndex >= 0) {
|
|
556
826
|
const updatedToolCalls = [...prevToolCalls];
|
|
557
|
-
updatedToolCalls[existingToolCallIndex]
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
827
|
+
const existing = updatedToolCalls[existingToolCallIndex];
|
|
828
|
+
const merged = { ...existing, ...toolCall };
|
|
829
|
+
if (existing.external_execution && existing.result !== void 0) {
|
|
830
|
+
merged.result = existing.result;
|
|
831
|
+
}
|
|
832
|
+
if (existing.ui_component !== void 0 && !toolCall.ui_component) {
|
|
833
|
+
merged.ui_component = existing.ui_component;
|
|
834
|
+
}
|
|
835
|
+
updatedToolCalls[existingToolCallIndex] = merged;
|
|
561
836
|
return updatedToolCalls;
|
|
562
837
|
}
|
|
563
838
|
return [...prevToolCalls, toolCall];
|
|
@@ -578,6 +853,105 @@ var EventProcessor = class {
|
|
|
578
853
|
constructor() {
|
|
579
854
|
this.lastContent = "";
|
|
580
855
|
}
|
|
856
|
+
appendRunContent(chunk, updatedMessage) {
|
|
857
|
+
if (typeof chunk.content === "string") {
|
|
858
|
+
const uniqueContent = chunk.content.replace(this.lastContent, "");
|
|
859
|
+
updatedMessage.content = updatedMessage.content + uniqueContent;
|
|
860
|
+
this.lastContent = chunk.content;
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
if (typeof chunk.content !== "string" && chunk.content !== null) {
|
|
864
|
+
const jsonBlock = getJsonMarkdown(chunk.content);
|
|
865
|
+
updatedMessage.content = updatedMessage.content + jsonBlock;
|
|
866
|
+
this.lastContent = jsonBlock;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
applyRunContentFields(chunk, lastMessage, updatedMessage) {
|
|
870
|
+
this.appendRunContent(chunk, updatedMessage);
|
|
871
|
+
updatedMessage.tool_calls = processChunkToolCalls(
|
|
872
|
+
chunk,
|
|
873
|
+
lastMessage.tool_calls
|
|
874
|
+
);
|
|
875
|
+
if (chunk.extra_data?.reasoning_steps) {
|
|
876
|
+
updatedMessage.extra_data = {
|
|
877
|
+
...updatedMessage.extra_data,
|
|
878
|
+
reasoning_steps: chunk.extra_data.reasoning_steps
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
if (chunk.extra_data?.references) {
|
|
882
|
+
updatedMessage.extra_data = {
|
|
883
|
+
...updatedMessage.extra_data,
|
|
884
|
+
references: chunk.extra_data.references
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
888
|
+
if (chunk.images) {
|
|
889
|
+
updatedMessage.images = chunk.images;
|
|
890
|
+
}
|
|
891
|
+
if (chunk.image) {
|
|
892
|
+
const existingImages = updatedMessage.images ?? lastMessage.images ?? [];
|
|
893
|
+
const hasImage = existingImages.some((image) => {
|
|
894
|
+
if (image.id && chunk.image?.id) {
|
|
895
|
+
return image.id === chunk.image.id;
|
|
896
|
+
}
|
|
897
|
+
return image.url === chunk.image?.url;
|
|
898
|
+
});
|
|
899
|
+
if (!hasImage) {
|
|
900
|
+
updatedMessage.images = [...existingImages, chunk.image];
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
if (chunk.videos) {
|
|
904
|
+
updatedMessage.videos = chunk.videos;
|
|
905
|
+
}
|
|
906
|
+
if (chunk.audio) {
|
|
907
|
+
updatedMessage.audio = chunk.audio;
|
|
908
|
+
}
|
|
909
|
+
if (chunk.files) {
|
|
910
|
+
updatedMessage.files = chunk.files;
|
|
911
|
+
}
|
|
912
|
+
if (chunk.response_audio?.transcript && typeof chunk.response_audio.transcript === "string") {
|
|
913
|
+
updatedMessage.response_audio = {
|
|
914
|
+
...updatedMessage.response_audio,
|
|
915
|
+
transcript: (updatedMessage.response_audio?.transcript || "") + chunk.response_audio.transcript
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
applyCompletedFields(chunk, lastMessage, updatedMessage) {
|
|
920
|
+
let updatedContent;
|
|
921
|
+
if (typeof chunk.content === "string") {
|
|
922
|
+
updatedContent = chunk.content;
|
|
923
|
+
} else {
|
|
924
|
+
try {
|
|
925
|
+
updatedContent = JSON.stringify(chunk.content);
|
|
926
|
+
} catch {
|
|
927
|
+
updatedContent = "Error parsing response";
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
updatedMessage.content = updatedContent;
|
|
931
|
+
updatedMessage.tool_calls = processChunkToolCalls(
|
|
932
|
+
chunk,
|
|
933
|
+
lastMessage.tool_calls
|
|
934
|
+
);
|
|
935
|
+
const completedImages = chunk.images ?? (chunk.image ? [chunk.image] : void 0);
|
|
936
|
+
updatedMessage.images = completedImages ?? lastMessage.images;
|
|
937
|
+
updatedMessage.videos = chunk.videos ?? lastMessage.videos;
|
|
938
|
+
updatedMessage.audio = chunk.audio ?? lastMessage.audio;
|
|
939
|
+
updatedMessage.files = chunk.files ?? lastMessage.files;
|
|
940
|
+
updatedMessage.response_audio = chunk.response_audio;
|
|
941
|
+
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
942
|
+
updatedMessage.extra_data = {
|
|
943
|
+
reasoning_steps: chunk.extra_data?.reasoning_steps ?? lastMessage.extra_data?.reasoning_steps,
|
|
944
|
+
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
appendReasoningSteps(chunk, lastMessage, updatedMessage) {
|
|
948
|
+
const existingSteps = lastMessage.extra_data?.reasoning_steps ?? [];
|
|
949
|
+
const incomingSteps = chunk.extra_data?.reasoning_steps ?? [];
|
|
950
|
+
updatedMessage.extra_data = {
|
|
951
|
+
...updatedMessage.extra_data,
|
|
952
|
+
reasoning_steps: [...existingSteps, ...incomingSteps]
|
|
953
|
+
};
|
|
954
|
+
}
|
|
581
955
|
/**
|
|
582
956
|
* Process a chunk and update the last message
|
|
583
957
|
*/
|
|
@@ -604,57 +978,11 @@ var EventProcessor = class {
|
|
|
604
978
|
break;
|
|
605
979
|
case RunEventEnum.RunContent:
|
|
606
980
|
case RunEventEnum.TeamRunContent:
|
|
607
|
-
|
|
608
|
-
const uniqueContent = chunk.content.replace(this.lastContent, "");
|
|
609
|
-
updatedMessage.content = updatedMessage.content + uniqueContent;
|
|
610
|
-
this.lastContent = chunk.content;
|
|
611
|
-
} else if (typeof chunk.content !== "string" && chunk.content !== null) {
|
|
612
|
-
const jsonBlock = getJsonMarkdown(chunk.content);
|
|
613
|
-
updatedMessage.content = updatedMessage.content + jsonBlock;
|
|
614
|
-
this.lastContent = jsonBlock;
|
|
615
|
-
}
|
|
616
|
-
updatedMessage.tool_calls = processChunkToolCalls(
|
|
617
|
-
chunk,
|
|
618
|
-
lastMessage.tool_calls
|
|
619
|
-
);
|
|
620
|
-
if (chunk.extra_data?.reasoning_steps) {
|
|
621
|
-
updatedMessage.extra_data = {
|
|
622
|
-
...updatedMessage.extra_data,
|
|
623
|
-
reasoning_steps: chunk.extra_data.reasoning_steps
|
|
624
|
-
};
|
|
625
|
-
}
|
|
626
|
-
if (chunk.extra_data?.references) {
|
|
627
|
-
updatedMessage.extra_data = {
|
|
628
|
-
...updatedMessage.extra_data,
|
|
629
|
-
references: chunk.extra_data.references
|
|
630
|
-
};
|
|
631
|
-
}
|
|
632
|
-
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
633
|
-
if (chunk.images) {
|
|
634
|
-
updatedMessage.images = chunk.images;
|
|
635
|
-
}
|
|
636
|
-
if (chunk.videos) {
|
|
637
|
-
updatedMessage.videos = chunk.videos;
|
|
638
|
-
}
|
|
639
|
-
if (chunk.audio) {
|
|
640
|
-
updatedMessage.audio = chunk.audio;
|
|
641
|
-
}
|
|
642
|
-
if (chunk.response_audio?.transcript && typeof chunk.response_audio.transcript === "string") {
|
|
643
|
-
const transcript = chunk.response_audio.transcript;
|
|
644
|
-
updatedMessage.response_audio = {
|
|
645
|
-
...updatedMessage.response_audio,
|
|
646
|
-
transcript: (updatedMessage.response_audio?.transcript || "") + transcript
|
|
647
|
-
};
|
|
648
|
-
}
|
|
981
|
+
this.applyRunContentFields(chunk, lastMessage, updatedMessage);
|
|
649
982
|
break;
|
|
650
983
|
case RunEventEnum.ReasoningStep:
|
|
651
984
|
case RunEventEnum.TeamReasoningStep: {
|
|
652
|
-
|
|
653
|
-
const incomingSteps = chunk.extra_data?.reasoning_steps ?? [];
|
|
654
|
-
updatedMessage.extra_data = {
|
|
655
|
-
...updatedMessage.extra_data,
|
|
656
|
-
reasoning_steps: [...existingSteps, ...incomingSteps]
|
|
657
|
-
};
|
|
985
|
+
this.appendReasoningSteps(chunk, lastMessage, updatedMessage);
|
|
658
986
|
break;
|
|
659
987
|
}
|
|
660
988
|
case RunEventEnum.ReasoningCompleted:
|
|
@@ -668,29 +996,7 @@ var EventProcessor = class {
|
|
|
668
996
|
break;
|
|
669
997
|
case RunEventEnum.RunCompleted:
|
|
670
998
|
case RunEventEnum.TeamRunCompleted: {
|
|
671
|
-
|
|
672
|
-
if (typeof chunk.content === "string") {
|
|
673
|
-
updatedContent = chunk.content;
|
|
674
|
-
} else {
|
|
675
|
-
try {
|
|
676
|
-
updatedContent = JSON.stringify(chunk.content);
|
|
677
|
-
} catch {
|
|
678
|
-
updatedContent = "Error parsing response";
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
updatedMessage.content = updatedContent;
|
|
682
|
-
updatedMessage.tool_calls = processChunkToolCalls(
|
|
683
|
-
chunk,
|
|
684
|
-
lastMessage.tool_calls
|
|
685
|
-
);
|
|
686
|
-
updatedMessage.images = chunk.images ?? lastMessage.images;
|
|
687
|
-
updatedMessage.videos = chunk.videos ?? lastMessage.videos;
|
|
688
|
-
updatedMessage.response_audio = chunk.response_audio;
|
|
689
|
-
updatedMessage.created_at = chunk.created_at ?? lastMessage.created_at;
|
|
690
|
-
updatedMessage.extra_data = {
|
|
691
|
-
reasoning_steps: chunk.extra_data?.reasoning_steps ?? lastMessage.extra_data?.reasoning_steps,
|
|
692
|
-
references: chunk.extra_data?.references ?? lastMessage.extra_data?.references
|
|
693
|
-
};
|
|
999
|
+
this.applyCompletedFields(chunk, lastMessage, updatedMessage);
|
|
694
1000
|
break;
|
|
695
1001
|
}
|
|
696
1002
|
case RunEventEnum.UpdatingMemory:
|
|
@@ -704,6 +1010,8 @@ var EventProcessor = class {
|
|
|
704
1010
|
case RunEventEnum.TeamRunCancelled:
|
|
705
1011
|
updatedMessage.streamingError = true;
|
|
706
1012
|
break;
|
|
1013
|
+
default:
|
|
1014
|
+
break;
|
|
707
1015
|
}
|
|
708
1016
|
return updatedMessage;
|
|
709
1017
|
}
|
|
@@ -831,36 +1139,36 @@ function sanitizeObject(obj) {
|
|
|
831
1139
|
function isDevelopment() {
|
|
832
1140
|
return typeof process !== "undefined" && process.env?.NODE_ENV === "development";
|
|
833
1141
|
}
|
|
834
|
-
var Logger =
|
|
1142
|
+
var Logger = {
|
|
835
1143
|
/**
|
|
836
1144
|
* Log debug information (only in development)
|
|
837
1145
|
*/
|
|
838
|
-
|
|
1146
|
+
debug(message, data) {
|
|
839
1147
|
if (isDevelopment()) {
|
|
840
1148
|
const sanitized = data ? sanitizeObject(data) : void 0;
|
|
841
1149
|
console.debug(`[DEBUG] ${message}`, sanitized || "");
|
|
842
1150
|
}
|
|
843
|
-
}
|
|
1151
|
+
},
|
|
844
1152
|
/**
|
|
845
1153
|
* Log informational messages (only in development)
|
|
846
1154
|
*/
|
|
847
|
-
|
|
1155
|
+
info(message, data) {
|
|
848
1156
|
if (isDevelopment()) {
|
|
849
1157
|
const sanitized = data ? sanitizeObject(data) : void 0;
|
|
850
1158
|
console.info(`[INFO] ${message}`, sanitized || "");
|
|
851
1159
|
}
|
|
852
|
-
}
|
|
1160
|
+
},
|
|
853
1161
|
/**
|
|
854
1162
|
* Log warnings (always logs)
|
|
855
1163
|
*/
|
|
856
|
-
|
|
1164
|
+
warn(message, data) {
|
|
857
1165
|
const sanitized = data ? sanitizeObject(data) : void 0;
|
|
858
1166
|
console.warn(`[WARN] ${message}`, sanitized || "");
|
|
859
|
-
}
|
|
1167
|
+
},
|
|
860
1168
|
/**
|
|
861
1169
|
* Log errors (always logs)
|
|
862
1170
|
*/
|
|
863
|
-
|
|
1171
|
+
error(message, data) {
|
|
864
1172
|
const sanitized = data ? sanitizeObject(data) : void 0;
|
|
865
1173
|
console.error(`[ERROR] ${message}`, sanitized || "");
|
|
866
1174
|
}
|
|
@@ -878,16 +1186,100 @@ function toSafeISOString(timestamp) {
|
|
|
878
1186
|
}
|
|
879
1187
|
return new Date(ts).toISOString();
|
|
880
1188
|
}
|
|
1189
|
+
function getFileName(file, index) {
|
|
1190
|
+
if ("name" in file && typeof file.name === "string" && file.name) {
|
|
1191
|
+
return file.name;
|
|
1192
|
+
}
|
|
1193
|
+
return `file-${index}`;
|
|
1194
|
+
}
|
|
1195
|
+
function getFileFormat(mimeType) {
|
|
1196
|
+
if (!mimeType) {
|
|
1197
|
+
return void 0;
|
|
1198
|
+
}
|
|
1199
|
+
const [, subtype] = mimeType.split("/");
|
|
1200
|
+
if (!subtype) {
|
|
1201
|
+
return void 0;
|
|
1202
|
+
}
|
|
1203
|
+
return subtype.split(";")[0]?.trim().toLowerCase() || void 0;
|
|
1204
|
+
}
|
|
1205
|
+
function createPreviewUrl(file) {
|
|
1206
|
+
if (typeof URL === "undefined" || typeof URL.createObjectURL !== "function") {
|
|
1207
|
+
return void 0;
|
|
1208
|
+
}
|
|
1209
|
+
try {
|
|
1210
|
+
return URL.createObjectURL(file);
|
|
1211
|
+
} catch {
|
|
1212
|
+
return void 0;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
function buildMessageMediaPayload(files) {
|
|
1216
|
+
const images = [];
|
|
1217
|
+
const videos = [];
|
|
1218
|
+
const audio = [];
|
|
1219
|
+
const fileAttachments = [];
|
|
1220
|
+
const objectUrls = [];
|
|
1221
|
+
files.forEach((file, index) => {
|
|
1222
|
+
const filename = getFileName(file, index);
|
|
1223
|
+
const mimeType = file.type || "application/octet-stream";
|
|
1224
|
+
const format = getFileFormat(mimeType);
|
|
1225
|
+
const previewUrl = createPreviewUrl(file);
|
|
1226
|
+
if (previewUrl) {
|
|
1227
|
+
objectUrls.push(previewUrl);
|
|
1228
|
+
}
|
|
1229
|
+
if (mimeType.startsWith("image/") && previewUrl) {
|
|
1230
|
+
images.push({
|
|
1231
|
+
url: previewUrl,
|
|
1232
|
+
mime_type: mimeType,
|
|
1233
|
+
format
|
|
1234
|
+
});
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
if (mimeType.startsWith("video/")) {
|
|
1238
|
+
videos.push({
|
|
1239
|
+
url: previewUrl,
|
|
1240
|
+
id: filename,
|
|
1241
|
+
mime_type: mimeType,
|
|
1242
|
+
format
|
|
1243
|
+
});
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
if (mimeType.startsWith("audio/")) {
|
|
1247
|
+
audio.push({
|
|
1248
|
+
url: previewUrl,
|
|
1249
|
+
id: filename,
|
|
1250
|
+
mime_type: mimeType,
|
|
1251
|
+
format
|
|
1252
|
+
});
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1255
|
+
fileAttachments.push({
|
|
1256
|
+
filename,
|
|
1257
|
+
name: filename,
|
|
1258
|
+
mime_type: mimeType,
|
|
1259
|
+
format,
|
|
1260
|
+
size: file.size,
|
|
1261
|
+
url: previewUrl
|
|
1262
|
+
});
|
|
1263
|
+
});
|
|
1264
|
+
return {
|
|
1265
|
+
images: images.length > 0 ? images : void 0,
|
|
1266
|
+
videos: videos.length > 0 ? videos : void 0,
|
|
1267
|
+
audio: audio.length > 0 ? audio : void 0,
|
|
1268
|
+
files: fileAttachments.length > 0 ? fileAttachments : void 0,
|
|
1269
|
+
objectUrls
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
881
1272
|
var AgnoClient = class extends EventEmitter {
|
|
882
1273
|
constructor(config) {
|
|
883
1274
|
super();
|
|
884
|
-
// toolCallId -> UIComponentSpec
|
|
885
1275
|
this.runCompletedSuccessfully = false;
|
|
1276
|
+
this.currentAbortController = null;
|
|
886
1277
|
this.messageStore = new MessageStore();
|
|
887
1278
|
this.configManager = new ConfigManager(config);
|
|
888
1279
|
this.sessionManager = new SessionManager();
|
|
889
1280
|
this.eventProcessor = new EventProcessor();
|
|
890
1281
|
this.pendingUISpecs = /* @__PURE__ */ new Map();
|
|
1282
|
+
this.localAttachmentUrls = /* @__PURE__ */ new Set();
|
|
891
1283
|
this.state = {
|
|
892
1284
|
isStreaming: false,
|
|
893
1285
|
isRefreshing: false,
|
|
@@ -930,6 +1322,8 @@ var AgnoClient = class extends EventEmitter {
|
|
|
930
1322
|
* Clear all messages
|
|
931
1323
|
*/
|
|
932
1324
|
clearMessages() {
|
|
1325
|
+
this.revokeAttachmentUrlsFromMessages(this.messageStore.getMessages());
|
|
1326
|
+
this.localAttachmentUrls.clear();
|
|
933
1327
|
this.messageStore.clear();
|
|
934
1328
|
this.configManager.setSessionId(void 0);
|
|
935
1329
|
this.pendingUISpecs.clear();
|
|
@@ -943,42 +1337,84 @@ var AgnoClient = class extends EventEmitter {
|
|
|
943
1337
|
if (!(this.state.isStreaming || this.state.isPaused)) {
|
|
944
1338
|
throw new Error("No active or paused run to cancel");
|
|
945
1339
|
}
|
|
1340
|
+
const runId = this.state.pausedRunId || this.currentRunId;
|
|
1341
|
+
if (this.currentAbortController) {
|
|
1342
|
+
this.currentAbortController.abort();
|
|
1343
|
+
this.currentAbortController = null;
|
|
1344
|
+
}
|
|
1345
|
+
this.state.isCancelling = true;
|
|
1346
|
+
this.emit("state:change", this.getState());
|
|
1347
|
+
const cancelErrorMessage = runId ? await this.requestBackendCancel(runId) : this.logMissingRunIdForCancel();
|
|
1348
|
+
this.state.isStreaming = false;
|
|
1349
|
+
this.state.isPaused = false;
|
|
1350
|
+
this.state.isCancelling = false;
|
|
1351
|
+
this.state.pausedRunId = void 0;
|
|
1352
|
+
this.state.toolsAwaitingExecution = void 0;
|
|
1353
|
+
this.currentRunId = void 0;
|
|
1354
|
+
if (cancelErrorMessage) {
|
|
1355
|
+
this.state.errorMessage = cancelErrorMessage;
|
|
1356
|
+
this.emit("message:error", cancelErrorMessage);
|
|
1357
|
+
}
|
|
1358
|
+
this.emit("run:cancelled", { runId });
|
|
1359
|
+
this.emit("state:change", this.getState());
|
|
1360
|
+
}
|
|
1361
|
+
logMissingRunIdForCancel() {
|
|
1362
|
+
Logger.warn(
|
|
1363
|
+
"[AgnoClient] No run ID available, skipping backend cancel request"
|
|
1364
|
+
);
|
|
1365
|
+
return void 0;
|
|
1366
|
+
}
|
|
1367
|
+
async requestBackendCancel(runId) {
|
|
946
1368
|
const runUrl = this.configManager.getRunUrl();
|
|
947
1369
|
if (!runUrl) {
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
if (!runId) {
|
|
952
|
-
throw new Error("No run ID available to cancel");
|
|
1370
|
+
const message = "Run cancelled locally, but backend cancel could not be sent: no agent or team selected";
|
|
1371
|
+
Logger.warn(`[AgnoClient] ${message}`);
|
|
1372
|
+
return message;
|
|
953
1373
|
}
|
|
954
1374
|
const cancelUrl = `${runUrl}/${runId}/cancel`;
|
|
955
1375
|
const headers = this.configManager.buildRequestHeaders();
|
|
956
|
-
this.state.isCancelling = true;
|
|
957
|
-
this.emit("state:change", this.getState());
|
|
958
1376
|
try {
|
|
959
1377
|
const response = await fetch(cancelUrl, {
|
|
960
1378
|
method: "POST",
|
|
961
1379
|
headers
|
|
962
1380
|
});
|
|
963
|
-
if (
|
|
964
|
-
|
|
1381
|
+
if (response.ok) {
|
|
1382
|
+
return void 0;
|
|
965
1383
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
this.emit("state:change", this.getState());
|
|
974
|
-
} catch (error) {
|
|
975
|
-
this.state.isCancelling = false;
|
|
976
|
-
this.emit("state:change", this.getState());
|
|
977
|
-
throw new Error(
|
|
978
|
-
`Error cancelling run: ${error instanceof Error ? error.message : String(error)}`
|
|
1384
|
+
if (response.status === 401 || response.status === 403) {
|
|
1385
|
+
const message = `Run cancelled locally, but backend cancel was rejected (${response.status})`;
|
|
1386
|
+
Logger.warn(`[AgnoClient] ${message}`);
|
|
1387
|
+
return message;
|
|
1388
|
+
}
|
|
1389
|
+
Logger.warn(
|
|
1390
|
+
`[AgnoClient] Backend cancel returned ${response.status} \u2014 run may have already completed`
|
|
979
1391
|
);
|
|
1392
|
+
return void 0;
|
|
1393
|
+
} catch (error) {
|
|
1394
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
1395
|
+
const message = `Run cancelled locally, but backend cancel failed: ${reason}`;
|
|
1396
|
+
Logger.warn(`[AgnoClient] ${message}`);
|
|
1397
|
+
return message;
|
|
980
1398
|
}
|
|
981
1399
|
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Abort the active stream without calling the backend cancel endpoint.
|
|
1402
|
+
* Since streamResponse handles AbortError by returning silently
|
|
1403
|
+
* (no onComplete/onError called), state cleanup is done here.
|
|
1404
|
+
*/
|
|
1405
|
+
abortStream() {
|
|
1406
|
+
if (!this.state.isStreaming) {
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
if (this.currentAbortController) {
|
|
1410
|
+
this.currentAbortController.abort();
|
|
1411
|
+
this.currentAbortController = null;
|
|
1412
|
+
}
|
|
1413
|
+
this.state.isStreaming = false;
|
|
1414
|
+
this.currentRunId = void 0;
|
|
1415
|
+
this.emit("stream:end");
|
|
1416
|
+
this.emit("state:change", this.getState());
|
|
1417
|
+
}
|
|
982
1418
|
/**
|
|
983
1419
|
* Send a message to the agent/team (streaming)
|
|
984
1420
|
*/
|
|
@@ -999,16 +1435,30 @@ var AgnoClient = class extends EventEmitter {
|
|
|
999
1435
|
if (typeof message === "string") {
|
|
1000
1436
|
formData.append("message", message);
|
|
1001
1437
|
}
|
|
1438
|
+
if (options?.files) {
|
|
1439
|
+
options.files.forEach((file, index) => {
|
|
1440
|
+
formData.append("files", file, getFileName(file, index));
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
const requestFiles = formData.getAll("files").filter((entry) => typeof entry !== "string");
|
|
1444
|
+
const userMessageMedia = buildMessageMediaPayload(requestFiles);
|
|
1445
|
+
this.trackAttachmentUrls(userMessageMedia.objectUrls);
|
|
1446
|
+
const userMessageContent = String(formData.get("message") ?? "");
|
|
1002
1447
|
const lastMessage = this.messageStore.getLastMessage();
|
|
1003
1448
|
if (lastMessage?.streamingError) {
|
|
1004
1449
|
const secondLast = this.messageStore.getMessages()[this.messageStore.getMessages().length - 2];
|
|
1005
1450
|
if (secondLast?.role === "user") {
|
|
1451
|
+
this.revokeAttachmentUrlsFromMessages([secondLast, lastMessage]);
|
|
1006
1452
|
this.messageStore.removeLastMessages(2);
|
|
1007
1453
|
}
|
|
1008
1454
|
}
|
|
1009
1455
|
this.messageStore.addMessage({
|
|
1010
1456
|
role: "user",
|
|
1011
|
-
content:
|
|
1457
|
+
content: userMessageContent,
|
|
1458
|
+
images: userMessageMedia.images,
|
|
1459
|
+
videos: userMessageMedia.videos,
|
|
1460
|
+
audio: userMessageMedia.audio,
|
|
1461
|
+
files: userMessageMedia.files,
|
|
1012
1462
|
created_at: Math.floor(Date.now() / 1e3)
|
|
1013
1463
|
});
|
|
1014
1464
|
this.messageStore.addMessage({
|
|
@@ -1022,34 +1472,40 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1022
1472
|
this.eventProcessor.reset();
|
|
1023
1473
|
let newSessionId = this.configManager.getSessionId();
|
|
1024
1474
|
try {
|
|
1025
|
-
formData.
|
|
1026
|
-
formData.
|
|
1475
|
+
formData.set("stream", "true");
|
|
1476
|
+
formData.set("session_id", newSessionId ?? "");
|
|
1027
1477
|
const userId = this.configManager.getUserId();
|
|
1028
1478
|
if (userId) {
|
|
1029
|
-
formData.
|
|
1479
|
+
formData.set("user_id", userId);
|
|
1480
|
+
}
|
|
1481
|
+
const dependencies = this.configManager.buildDependencies(
|
|
1482
|
+
options?.dependencies
|
|
1483
|
+
);
|
|
1484
|
+
if (dependencies) {
|
|
1485
|
+
formData.set("dependencies", JSON.stringify(dependencies));
|
|
1030
1486
|
}
|
|
1031
1487
|
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
1032
1488
|
const params = this.configManager.buildQueryString(options?.params);
|
|
1489
|
+
this.currentAbortController = new AbortController();
|
|
1033
1490
|
await streamResponse({
|
|
1034
1491
|
apiUrl: runUrl,
|
|
1035
1492
|
headers,
|
|
1036
1493
|
params,
|
|
1037
1494
|
requestBody: formData,
|
|
1495
|
+
signal: this.currentAbortController.signal,
|
|
1038
1496
|
onChunk: (chunk) => {
|
|
1039
|
-
this.handleChunk(
|
|
1040
|
-
chunk,
|
|
1041
|
-
newSessionId,
|
|
1042
|
-
formData.get("message")
|
|
1043
|
-
);
|
|
1497
|
+
this.handleChunk(chunk, newSessionId, userMessageContent);
|
|
1044
1498
|
if ((chunk.event === RunEvent.RunStarted || chunk.event === RunEvent.TeamRunStarted || chunk.event === RunEvent.ReasoningStarted || chunk.event === RunEvent.TeamReasoningStarted) && chunk.session_id) {
|
|
1045
1499
|
newSessionId = chunk.session_id;
|
|
1046
1500
|
this.configManager.setSessionId(chunk.session_id);
|
|
1047
1501
|
}
|
|
1048
1502
|
},
|
|
1049
1503
|
onError: (error) => {
|
|
1504
|
+
this.currentAbortController = null;
|
|
1050
1505
|
this.handleError(error, newSessionId);
|
|
1051
1506
|
},
|
|
1052
1507
|
onComplete: async () => {
|
|
1508
|
+
this.currentAbortController = null;
|
|
1053
1509
|
this.state.isStreaming = false;
|
|
1054
1510
|
this.currentRunId = void 0;
|
|
1055
1511
|
this.emit("stream:end");
|
|
@@ -1062,6 +1518,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1062
1518
|
}
|
|
1063
1519
|
});
|
|
1064
1520
|
} catch (error) {
|
|
1521
|
+
this.currentAbortController = null;
|
|
1065
1522
|
this.handleError(
|
|
1066
1523
|
error instanceof Error ? error : new Error(String(error)),
|
|
1067
1524
|
newSessionId
|
|
@@ -1147,6 +1604,73 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1147
1604
|
this.emit("stream:end");
|
|
1148
1605
|
this.emit("state:change", this.getState());
|
|
1149
1606
|
}
|
|
1607
|
+
trackAttachmentUrls(urls) {
|
|
1608
|
+
for (const url of urls) {
|
|
1609
|
+
this.localAttachmentUrls.add(url);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
collectAttachmentUrls(message) {
|
|
1613
|
+
const imageUrls = message.images?.map((image) => image.url) ?? [];
|
|
1614
|
+
const videoUrls = message.videos?.map((video) => video.url).filter((url) => Boolean(url)) ?? [];
|
|
1615
|
+
const audioUrls = message.audio?.map((audio) => audio.url).filter((url) => Boolean(url)) ?? [];
|
|
1616
|
+
const fileUrls = message.files?.map((file) => file.url).filter((url) => Boolean(url)) ?? [];
|
|
1617
|
+
return [...imageUrls, ...videoUrls, ...audioUrls, ...fileUrls];
|
|
1618
|
+
}
|
|
1619
|
+
revokeAttachmentUrls(urls) {
|
|
1620
|
+
if (typeof URL === "undefined" || typeof URL.revokeObjectURL !== "function") {
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1623
|
+
for (const url of urls) {
|
|
1624
|
+
if (!this.localAttachmentUrls.has(url)) {
|
|
1625
|
+
continue;
|
|
1626
|
+
}
|
|
1627
|
+
URL.revokeObjectURL(url);
|
|
1628
|
+
this.localAttachmentUrls.delete(url);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
revokeAttachmentUrlsFromMessages(messages) {
|
|
1632
|
+
const urls = [];
|
|
1633
|
+
for (const message of messages) {
|
|
1634
|
+
if (!message) {
|
|
1635
|
+
continue;
|
|
1636
|
+
}
|
|
1637
|
+
urls.push(...this.collectAttachmentUrls(message));
|
|
1638
|
+
}
|
|
1639
|
+
this.revokeAttachmentUrls(urls);
|
|
1640
|
+
}
|
|
1641
|
+
collectExistingUIComponents() {
|
|
1642
|
+
const existingUIComponents = /* @__PURE__ */ new Map();
|
|
1643
|
+
for (const message of this.messageStore.getMessages()) {
|
|
1644
|
+
if (!message.tool_calls) {
|
|
1645
|
+
continue;
|
|
1646
|
+
}
|
|
1647
|
+
for (const toolCall of message.tool_calls) {
|
|
1648
|
+
if (toolCall.ui_component) {
|
|
1649
|
+
existingUIComponents.set(
|
|
1650
|
+
toolCall.tool_call_id,
|
|
1651
|
+
toolCall.ui_component
|
|
1652
|
+
);
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
return existingUIComponents;
|
|
1657
|
+
}
|
|
1658
|
+
restoreUIComponents(messages, uiComponents) {
|
|
1659
|
+
if (uiComponents.size === 0) {
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
for (const message of messages) {
|
|
1663
|
+
if (!message.tool_calls) {
|
|
1664
|
+
continue;
|
|
1665
|
+
}
|
|
1666
|
+
for (const toolCall of message.tool_calls) {
|
|
1667
|
+
const uiComponent = uiComponents.get(toolCall.tool_call_id);
|
|
1668
|
+
if (uiComponent) {
|
|
1669
|
+
toolCall.ui_component = uiComponent;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1150
1674
|
/**
|
|
1151
1675
|
* Refresh messages from the session API after run completion.
|
|
1152
1676
|
* Replaces streamed messages with authoritative session data.
|
|
@@ -1159,22 +1683,14 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1159
1683
|
Logger.debug("[AgnoClient] Cannot refresh: no session ID");
|
|
1160
1684
|
return;
|
|
1161
1685
|
}
|
|
1686
|
+
if (this.state.isStreaming) {
|
|
1687
|
+
Logger.debug("[AgnoClient] Skipping refresh: stream is active");
|
|
1688
|
+
return;
|
|
1689
|
+
}
|
|
1162
1690
|
this.state.isRefreshing = true;
|
|
1163
1691
|
this.emit("state:change", this.getState());
|
|
1164
1692
|
try {
|
|
1165
|
-
const existingUIComponents =
|
|
1166
|
-
for (const message of this.messageStore.getMessages()) {
|
|
1167
|
-
if (message.tool_calls) {
|
|
1168
|
-
for (const toolCall of message.tool_calls) {
|
|
1169
|
-
if (toolCall.ui_component) {
|
|
1170
|
-
existingUIComponents.set(
|
|
1171
|
-
toolCall.tool_call_id,
|
|
1172
|
-
toolCall.ui_component
|
|
1173
|
-
);
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1693
|
+
const existingUIComponents = this.collectExistingUIComponents();
|
|
1178
1694
|
const config = this.configManager.getConfig();
|
|
1179
1695
|
const entityType = this.configManager.getMode();
|
|
1180
1696
|
const dbId = this.configManager.getDbId() || "";
|
|
@@ -1190,22 +1706,15 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1190
1706
|
userId,
|
|
1191
1707
|
params
|
|
1192
1708
|
);
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
const toolCall = message.tool_calls[i];
|
|
1199
|
-
const uiComponent = existingUIComponents.get(
|
|
1200
|
-
toolCall.tool_call_id
|
|
1201
|
-
);
|
|
1202
|
-
if (uiComponent) {
|
|
1203
|
-
message.tool_calls[i].ui_component = uiComponent;
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1709
|
+
if (this.state.isStreaming) {
|
|
1710
|
+
Logger.debug(
|
|
1711
|
+
"[AgnoClient] Aborting refresh: stream started during fetch"
|
|
1712
|
+
);
|
|
1713
|
+
return;
|
|
1208
1714
|
}
|
|
1715
|
+
const messages = this.sessionManager.convertSessionToMessages(response);
|
|
1716
|
+
this.restoreUIComponents(messages, existingUIComponents);
|
|
1717
|
+
this.revokeAttachmentUrlsFromMessages(this.messageStore.getMessages());
|
|
1209
1718
|
this.messageStore.setMessages(messages);
|
|
1210
1719
|
Logger.debug(
|
|
1211
1720
|
"[AgnoClient] Session refreshed:",
|
|
@@ -1254,6 +1763,7 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1254
1763
|
"[AgnoClient] Setting messages to store:",
|
|
1255
1764
|
`${messages.length} messages`
|
|
1256
1765
|
);
|
|
1766
|
+
this.revokeAttachmentUrlsFromMessages(this.messageStore.getMessages());
|
|
1257
1767
|
this.messageStore.setMessages(messages);
|
|
1258
1768
|
this.configManager.setSessionId(sessionId);
|
|
1259
1769
|
Logger.debug("[AgnoClient] Emitting events...");
|
|
@@ -1405,9 +1915,9 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1405
1915
|
}
|
|
1406
1916
|
}
|
|
1407
1917
|
if (updatedMessages.length > 0) {
|
|
1408
|
-
|
|
1918
|
+
for (const { index, message } of updatedMessages) {
|
|
1409
1919
|
this.messageStore.updateMessage(index, () => message);
|
|
1410
|
-
}
|
|
1920
|
+
}
|
|
1411
1921
|
this.emit("message:update", this.messageStore.getMessages());
|
|
1412
1922
|
}
|
|
1413
1923
|
}
|
|
@@ -1435,15 +1945,48 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1435
1945
|
if (!runUrl) {
|
|
1436
1946
|
throw new Error("No agent or team selected");
|
|
1437
1947
|
}
|
|
1438
|
-
const
|
|
1439
|
-
|
|
1948
|
+
const pausedRunId = this.state.pausedRunId;
|
|
1949
|
+
const continueUrl = `${runUrl}/${pausedRunId}/continue`;
|
|
1440
1950
|
this.state.isStreaming = true;
|
|
1441
|
-
this.
|
|
1951
|
+
this.state.errorMessage = void 0;
|
|
1442
1952
|
this.emit("state:change", this.getState());
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1953
|
+
let hasContinued = false;
|
|
1954
|
+
let streamError;
|
|
1955
|
+
const markRunContinued = (runId) => {
|
|
1956
|
+
if (hasContinued) {
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
hasContinued = true;
|
|
1960
|
+
this.state.isPaused = false;
|
|
1961
|
+
this.state.toolsAwaitingExecution = void 0;
|
|
1962
|
+
this.emit("run:continued", { runId: runId || pausedRunId });
|
|
1963
|
+
this.emit("state:change", this.getState());
|
|
1964
|
+
};
|
|
1965
|
+
const handleContinueError = (error) => {
|
|
1966
|
+
streamError = error;
|
|
1967
|
+
this.state.isStreaming = false;
|
|
1968
|
+
this.state.errorMessage = error.message;
|
|
1969
|
+
const isConflictError = error instanceof StreamResponseHttpError && error.status === 409;
|
|
1970
|
+
if (isConflictError || !hasContinued) {
|
|
1971
|
+
this.state.isPaused = true;
|
|
1972
|
+
} else {
|
|
1973
|
+
this.state.isPaused = false;
|
|
1974
|
+
this.state.pausedRunId = void 0;
|
|
1975
|
+
this.state.toolsAwaitingExecution = void 0;
|
|
1976
|
+
this.messageStore.updateLastMessage((msg) => ({
|
|
1977
|
+
...msg,
|
|
1978
|
+
streamingError: true
|
|
1979
|
+
}));
|
|
1980
|
+
}
|
|
1981
|
+
this.emit("message:error", error.message);
|
|
1982
|
+
this.emit("stream:end");
|
|
1983
|
+
this.emit("state:change", this.getState());
|
|
1984
|
+
};
|
|
1985
|
+
const cleanedTools = tools.map(
|
|
1986
|
+
({ ui_component: _uiComponent, ...tool }) => {
|
|
1987
|
+
return tool;
|
|
1988
|
+
}
|
|
1989
|
+
);
|
|
1447
1990
|
const formData = new FormData();
|
|
1448
1991
|
formData.append("tools", JSON.stringify(cleanedTools));
|
|
1449
1992
|
formData.append("stream", "true");
|
|
@@ -1457,36 +2000,45 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1457
2000
|
}
|
|
1458
2001
|
const headers = this.configManager.buildRequestHeaders(options?.headers);
|
|
1459
2002
|
const params = this.configManager.buildQueryString(options?.params);
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
|
|
2003
|
+
this.currentAbortController = new AbortController();
|
|
2004
|
+
await streamResponse({
|
|
2005
|
+
apiUrl: continueUrl,
|
|
2006
|
+
headers,
|
|
2007
|
+
params,
|
|
2008
|
+
requestBody: formData,
|
|
2009
|
+
signal: this.currentAbortController.signal,
|
|
2010
|
+
onChunk: (chunk) => {
|
|
2011
|
+
const event = chunk.event;
|
|
2012
|
+
if (!hasContinued && event !== RunEvent.RunPaused) {
|
|
2013
|
+
markRunContinued(chunk.run_id);
|
|
2014
|
+
}
|
|
2015
|
+
this.handleChunk(chunk, currentSessionId, "");
|
|
2016
|
+
},
|
|
2017
|
+
onError: (error) => {
|
|
2018
|
+
this.currentAbortController = null;
|
|
2019
|
+
handleContinueError(error);
|
|
2020
|
+
},
|
|
2021
|
+
onComplete: async () => {
|
|
2022
|
+
this.currentAbortController = null;
|
|
2023
|
+
if (!(hasContinued || this.state.isPaused)) {
|
|
2024
|
+
markRunContinued(pausedRunId);
|
|
2025
|
+
}
|
|
2026
|
+
this.state.isStreaming = false;
|
|
2027
|
+
if (!this.state.isPaused) {
|
|
1474
2028
|
this.state.pausedRunId = void 0;
|
|
1475
2029
|
this.state.toolsAwaitingExecution = void 0;
|
|
1476
|
-
this.emit("stream:end");
|
|
1477
|
-
this.emit("message:complete", this.messageStore.getMessages());
|
|
1478
|
-
this.emit("state:change", this.getState());
|
|
1479
|
-
if (this.runCompletedSuccessfully) {
|
|
1480
|
-
this.runCompletedSuccessfully = false;
|
|
1481
|
-
await this.refreshSessionMessages();
|
|
1482
|
-
}
|
|
1483
2030
|
}
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
2031
|
+
this.emit("stream:end");
|
|
2032
|
+
this.emit("message:complete", this.messageStore.getMessages());
|
|
2033
|
+
this.emit("state:change", this.getState());
|
|
2034
|
+
if (this.runCompletedSuccessfully) {
|
|
2035
|
+
this.runCompletedSuccessfully = false;
|
|
2036
|
+
await this.refreshSessionMessages();
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
});
|
|
2040
|
+
if (streamError) {
|
|
2041
|
+
throw streamError;
|
|
1490
2042
|
}
|
|
1491
2043
|
}
|
|
1492
2044
|
/**
|
|
@@ -1598,7 +2150,13 @@ var AgnoClient = class extends EventEmitter {
|
|
|
1598
2150
|
* After calling dispose(), the client instance should not be reused.
|
|
1599
2151
|
*/
|
|
1600
2152
|
dispose() {
|
|
2153
|
+
if (this.currentAbortController) {
|
|
2154
|
+
this.currentAbortController.abort();
|
|
2155
|
+
this.currentAbortController = null;
|
|
2156
|
+
}
|
|
1601
2157
|
this.removeAllListeners();
|
|
2158
|
+
this.revokeAttachmentUrlsFromMessages(this.messageStore.getMessages());
|
|
2159
|
+
this.localAttachmentUrls.clear();
|
|
1602
2160
|
this.messageStore.clear();
|
|
1603
2161
|
this.pendingUISpecs.clear();
|
|
1604
2162
|
this.eventProcessor.reset();
|