extrait 0.7.0 → 0.7.1
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/dist/extract-parse-hint.d.ts +3 -0
- package/dist/extract-shape.d.ts +21 -0
- package/dist/generate-debug.d.ts +26 -0
- package/dist/generate-model-call.d.ts +3 -0
- package/dist/generate-output.d.ts +10 -0
- package/dist/generate-shared.d.ts +6 -10
- package/dist/generate-tool-timeout.d.ts +3 -0
- package/dist/index.cjs +1010 -1119
- package/dist/index.js +1010 -1119
- package/dist/providers/mcp-runtime-debug.d.ts +3 -0
- package/dist/providers/mcp-runtime.d.ts +1 -1
- package/dist/structured-streaming.d.ts +1 -0
- package/dist/type-definitions/llm.d.ts +246 -0
- package/dist/type-definitions/markdown.d.ts +10 -0
- package/dist/type-definitions/parse.d.ts +93 -0
- package/dist/type-definitions/structured.d.ts +123 -0
- package/dist/types.d.ts +4 -468
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -91,9 +91,6 @@ __export(exports_src, {
|
|
|
91
91
|
});
|
|
92
92
|
module.exports = __toCommonJS(exports_src);
|
|
93
93
|
|
|
94
|
-
// src/extract.ts
|
|
95
|
-
var import_jsonrepair = require("jsonrepair");
|
|
96
|
-
|
|
97
94
|
// src/utils/common.ts
|
|
98
95
|
function toErrorMessage(error) {
|
|
99
96
|
if (error instanceof Error) {
|
|
@@ -311,184 +308,77 @@ function isOnlyWhitespace(value) {
|
|
|
311
308
|
return true;
|
|
312
309
|
}
|
|
313
310
|
|
|
314
|
-
// src/extract.ts
|
|
315
|
-
var
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
firstPassMin: 12,
|
|
320
|
-
firstPassCap: 30,
|
|
321
|
-
firstPassMultiplier: 6,
|
|
322
|
-
secondPassMin: 4,
|
|
323
|
-
secondPassCap: 8,
|
|
324
|
-
secondPassMultiplier: 2,
|
|
325
|
-
hintMaxLength: 50000
|
|
326
|
-
};
|
|
327
|
-
function extractJsonCandidates(input, options = {}) {
|
|
328
|
-
const maxCandidates = options.maxCandidates ?? 5;
|
|
329
|
-
const acceptArrays = options.acceptArrays ?? true;
|
|
330
|
-
const allowRepairHints = options.allowRepairHints ?? true;
|
|
331
|
-
const heuristics = resolveExtractionHeuristics(options.heuristics);
|
|
332
|
-
const extractionInput = input;
|
|
333
|
-
const candidates = [];
|
|
334
|
-
candidates.push(...extractFromMarkdown(extractionInput, acceptArrays));
|
|
335
|
-
candidates.push(...scanBalancedSegments(extractionInput, acceptArrays));
|
|
336
|
-
if (candidates.length === 0 && extractionInput.trim()) {
|
|
337
|
-
const content = extractionInput.trim();
|
|
338
|
-
candidates.push({
|
|
339
|
-
id: "raw:fallback",
|
|
340
|
-
source: "raw",
|
|
341
|
-
content,
|
|
342
|
-
start: 0,
|
|
343
|
-
end: extractionInput.length,
|
|
344
|
-
score: 10 + Math.floor(lengthScore(content.length) / 3)
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
const prefiltered = prefilterByJsonShape(candidates, acceptArrays);
|
|
348
|
-
const firstPassLimit = clamp(maxCandidates * heuristics.firstPassMultiplier, heuristics.firstPassMin, heuristics.firstPassCap);
|
|
349
|
-
const firstPass = prefiltered.slice(0, firstPassLimit);
|
|
350
|
-
const secondPassLimit = Math.min(firstPass.length, clamp(maxCandidates * heuristics.secondPassMultiplier, heuristics.secondPassMin, heuristics.secondPassCap));
|
|
351
|
-
for (let i = 0;i < secondPassLimit; i += 1) {
|
|
352
|
-
const candidate = firstPass[i];
|
|
353
|
-
if (!candidate) {
|
|
354
|
-
continue;
|
|
355
|
-
}
|
|
356
|
-
const parseHint = buildParseHint(candidate.content, allowRepairHints, heuristics.hintMaxLength);
|
|
357
|
-
if (!parseHint) {
|
|
358
|
-
continue;
|
|
359
|
-
}
|
|
360
|
-
candidate.parseHint = parseHint;
|
|
361
|
-
candidate.score += parseHintBonus(parseHint);
|
|
311
|
+
// src/extract-parse-hint.ts
|
|
312
|
+
var import_jsonrepair = require("jsonrepair");
|
|
313
|
+
function buildParseHint(content, allowRepair, hintMaxLength) {
|
|
314
|
+
if (content.length > hintMaxLength) {
|
|
315
|
+
return null;
|
|
362
316
|
}
|
|
363
|
-
|
|
364
|
-
const deduped = dedupeCandidates(sorted);
|
|
365
|
-
return deduped.slice(0, maxCandidates).map((candidate, index) => ({
|
|
366
|
-
id: `${candidate.source}:${index}`,
|
|
367
|
-
source: candidate.source,
|
|
368
|
-
content: candidate.content,
|
|
369
|
-
language: candidate.language,
|
|
370
|
-
parseHint: candidate.parseHint,
|
|
371
|
-
start: candidate.start,
|
|
372
|
-
end: candidate.end,
|
|
373
|
-
score: candidate.score
|
|
374
|
-
}));
|
|
375
|
-
}
|
|
376
|
-
function prefilterByJsonShape(candidates, acceptArrays) {
|
|
377
|
-
const shaped = candidates.map((candidate) => {
|
|
378
|
-
const shapeScore = jsonShapeScore(candidate.content, acceptArrays);
|
|
317
|
+
try {
|
|
379
318
|
return {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
319
|
+
success: true,
|
|
320
|
+
parsed: JSON.parse(content),
|
|
321
|
+
repaired: null,
|
|
322
|
+
usedRepair: false,
|
|
323
|
+
stage: "parse",
|
|
324
|
+
error: ""
|
|
383
325
|
};
|
|
384
|
-
})
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
326
|
+
} catch (directError) {
|
|
327
|
+
if (!allowRepair) {
|
|
328
|
+
return {
|
|
329
|
+
success: false,
|
|
330
|
+
parsed: null,
|
|
331
|
+
repaired: null,
|
|
332
|
+
usedRepair: false,
|
|
333
|
+
stage: "parse",
|
|
334
|
+
error: toErrorMessage(directError)
|
|
335
|
+
};
|
|
392
336
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
337
|
+
let repaired;
|
|
338
|
+
try {
|
|
339
|
+
repaired = import_jsonrepair.jsonrepair(content);
|
|
340
|
+
} catch (repairError) {
|
|
341
|
+
return {
|
|
342
|
+
success: false,
|
|
343
|
+
parsed: null,
|
|
344
|
+
repaired: null,
|
|
345
|
+
usedRepair: true,
|
|
346
|
+
stage: "repair",
|
|
347
|
+
error: toErrorMessage(repairError)
|
|
348
|
+
};
|
|
404
349
|
}
|
|
405
|
-
|
|
406
|
-
return
|
|
350
|
+
try {
|
|
351
|
+
return {
|
|
352
|
+
success: true,
|
|
353
|
+
parsed: JSON.parse(repaired),
|
|
354
|
+
repaired,
|
|
355
|
+
usedRepair: true,
|
|
356
|
+
stage: "parse",
|
|
357
|
+
error: ""
|
|
358
|
+
};
|
|
359
|
+
} catch (parseError) {
|
|
360
|
+
return {
|
|
361
|
+
success: false,
|
|
362
|
+
parsed: null,
|
|
363
|
+
repaired,
|
|
364
|
+
usedRepair: true,
|
|
365
|
+
stage: "parse",
|
|
366
|
+
error: toErrorMessage(parseError || directError)
|
|
367
|
+
};
|
|
407
368
|
}
|
|
408
|
-
|
|
409
|
-
return [
|
|
410
|
-
{
|
|
411
|
-
id: `fenced:${index}`,
|
|
412
|
-
source: "fenced",
|
|
413
|
-
language,
|
|
414
|
-
content,
|
|
415
|
-
start: block.start,
|
|
416
|
-
end: block.end,
|
|
417
|
-
score: 260 + langBonus + lengthScore(content.length)
|
|
418
|
-
}
|
|
419
|
-
];
|
|
420
|
-
});
|
|
369
|
+
}
|
|
421
370
|
}
|
|
422
|
-
function
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
let inString = false;
|
|
426
|
-
let quote = null;
|
|
427
|
-
let escaped = false;
|
|
428
|
-
for (let i = 0;i < input.length; i += 1) {
|
|
429
|
-
const char = input[i];
|
|
430
|
-
if (!char) {
|
|
431
|
-
continue;
|
|
432
|
-
}
|
|
433
|
-
if (inString) {
|
|
434
|
-
if (escaped) {
|
|
435
|
-
escaped = false;
|
|
436
|
-
continue;
|
|
437
|
-
}
|
|
438
|
-
if (char === "\\") {
|
|
439
|
-
escaped = true;
|
|
440
|
-
continue;
|
|
441
|
-
}
|
|
442
|
-
if (char === quote) {
|
|
443
|
-
inString = false;
|
|
444
|
-
quote = null;
|
|
445
|
-
}
|
|
446
|
-
continue;
|
|
447
|
-
}
|
|
448
|
-
const allowSingleQuoted = stack.length > 0;
|
|
449
|
-
if (char === '"' || allowSingleQuoted && (char === "'" || char === "`")) {
|
|
450
|
-
inString = true;
|
|
451
|
-
quote = char;
|
|
452
|
-
continue;
|
|
453
|
-
}
|
|
454
|
-
if (char === "{" || char === "[") {
|
|
455
|
-
stack.push({ char, index: i });
|
|
456
|
-
continue;
|
|
457
|
-
}
|
|
458
|
-
if (char !== "}" && char !== "]") {
|
|
459
|
-
continue;
|
|
460
|
-
}
|
|
461
|
-
const expectedOpen = char === "}" ? "{" : "[";
|
|
462
|
-
while (stack.length > 0 && stack[stack.length - 1]?.char !== expectedOpen) {
|
|
463
|
-
stack.pop();
|
|
464
|
-
}
|
|
465
|
-
const opened = stack.pop();
|
|
466
|
-
if (!opened) {
|
|
467
|
-
continue;
|
|
468
|
-
}
|
|
469
|
-
if (stack.length > 0) {
|
|
470
|
-
continue;
|
|
471
|
-
}
|
|
472
|
-
if (!acceptArrays && opened.char === "[") {
|
|
473
|
-
continue;
|
|
474
|
-
}
|
|
475
|
-
const content = input.slice(opened.index, i + 1).trim();
|
|
476
|
-
if (!content) {
|
|
477
|
-
continue;
|
|
478
|
-
}
|
|
479
|
-
const rootBonus = opened.char === "{" ? 40 : 20;
|
|
480
|
-
const boundaryBonus = boundaryScore(input, opened.index, i + 1);
|
|
481
|
-
results.push({
|
|
482
|
-
id: `scan:${results.length}`,
|
|
483
|
-
source: "scan",
|
|
484
|
-
content,
|
|
485
|
-
start: opened.index,
|
|
486
|
-
end: i + 1,
|
|
487
|
-
score: 120 + rootBonus + boundaryBonus + lengthScore(content.length)
|
|
488
|
-
});
|
|
371
|
+
function parseHintBonus(hint) {
|
|
372
|
+
if (hint.success) {
|
|
373
|
+
return hint.usedRepair ? 70 : 120;
|
|
489
374
|
}
|
|
490
|
-
return
|
|
375
|
+
return hint.usedRepair ? -20 : -10;
|
|
491
376
|
}
|
|
377
|
+
|
|
378
|
+
// src/extract-shape.ts
|
|
379
|
+
var RE_EMPTY_OBJECT = /^\{\s*\}$/;
|
|
380
|
+
var RE_EMPTY_ARRAY = /^\[\s*\]$/;
|
|
381
|
+
var RE_BOUNDARY_CHAR = /[\s,.;:!?`"'()[\]{}<>]/;
|
|
492
382
|
function looksLikeJsonEnvelope(content, acceptArrays) {
|
|
493
383
|
const trimmed = content.trim();
|
|
494
384
|
if (trimmed.startsWith("{")) {
|
|
@@ -597,95 +487,6 @@ function passesShapeFilter(candidate) {
|
|
|
597
487
|
}
|
|
598
488
|
return candidate.shapeScore >= 35;
|
|
599
489
|
}
|
|
600
|
-
function buildParseHint(content, allowRepair, hintMaxLength) {
|
|
601
|
-
if (content.length > hintMaxLength) {
|
|
602
|
-
return null;
|
|
603
|
-
}
|
|
604
|
-
try {
|
|
605
|
-
return {
|
|
606
|
-
success: true,
|
|
607
|
-
parsed: JSON.parse(content),
|
|
608
|
-
repaired: null,
|
|
609
|
-
usedRepair: false,
|
|
610
|
-
stage: "parse",
|
|
611
|
-
error: ""
|
|
612
|
-
};
|
|
613
|
-
} catch (directError) {
|
|
614
|
-
if (!allowRepair) {
|
|
615
|
-
return {
|
|
616
|
-
success: false,
|
|
617
|
-
parsed: null,
|
|
618
|
-
repaired: null,
|
|
619
|
-
usedRepair: false,
|
|
620
|
-
stage: "parse",
|
|
621
|
-
error: toErrorMessage(directError)
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
|
-
let repaired;
|
|
625
|
-
try {
|
|
626
|
-
repaired = import_jsonrepair.jsonrepair(content);
|
|
627
|
-
} catch (repairError) {
|
|
628
|
-
return {
|
|
629
|
-
success: false,
|
|
630
|
-
parsed: null,
|
|
631
|
-
repaired: null,
|
|
632
|
-
usedRepair: true,
|
|
633
|
-
stage: "repair",
|
|
634
|
-
error: toErrorMessage(repairError)
|
|
635
|
-
};
|
|
636
|
-
}
|
|
637
|
-
try {
|
|
638
|
-
return {
|
|
639
|
-
success: true,
|
|
640
|
-
parsed: JSON.parse(repaired),
|
|
641
|
-
repaired,
|
|
642
|
-
usedRepair: true,
|
|
643
|
-
stage: "parse",
|
|
644
|
-
error: ""
|
|
645
|
-
};
|
|
646
|
-
} catch (parseError) {
|
|
647
|
-
return {
|
|
648
|
-
success: false,
|
|
649
|
-
parsed: null,
|
|
650
|
-
repaired,
|
|
651
|
-
usedRepair: true,
|
|
652
|
-
stage: "parse",
|
|
653
|
-
error: toErrorMessage(parseError || directError)
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
function resolveExtractionHeuristics(input) {
|
|
659
|
-
const merged = {
|
|
660
|
-
...DEFAULT_EXTRACTION_HEURISTICS,
|
|
661
|
-
...input
|
|
662
|
-
};
|
|
663
|
-
const firstPassMin = normalizeInteger(merged.firstPassMin, DEFAULT_EXTRACTION_HEURISTICS.firstPassMin);
|
|
664
|
-
const firstPassCap = Math.max(firstPassMin, normalizeInteger(merged.firstPassCap, DEFAULT_EXTRACTION_HEURISTICS.firstPassCap));
|
|
665
|
-
const secondPassMin = normalizeInteger(merged.secondPassMin, DEFAULT_EXTRACTION_HEURISTICS.secondPassMin);
|
|
666
|
-
const secondPassCap = Math.max(secondPassMin, normalizeInteger(merged.secondPassCap, DEFAULT_EXTRACTION_HEURISTICS.secondPassCap));
|
|
667
|
-
return {
|
|
668
|
-
firstPassMin,
|
|
669
|
-
firstPassCap,
|
|
670
|
-
firstPassMultiplier: normalizeInteger(merged.firstPassMultiplier, DEFAULT_EXTRACTION_HEURISTICS.firstPassMultiplier),
|
|
671
|
-
secondPassMin,
|
|
672
|
-
secondPassCap,
|
|
673
|
-
secondPassMultiplier: normalizeInteger(merged.secondPassMultiplier, DEFAULT_EXTRACTION_HEURISTICS.secondPassMultiplier),
|
|
674
|
-
hintMaxLength: normalizeInteger(merged.hintMaxLength, DEFAULT_EXTRACTION_HEURISTICS.hintMaxLength)
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
function normalizeInteger(value, fallback) {
|
|
678
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
679
|
-
return fallback;
|
|
680
|
-
}
|
|
681
|
-
return Math.max(0, Math.floor(value));
|
|
682
|
-
}
|
|
683
|
-
function parseHintBonus(hint) {
|
|
684
|
-
if (hint.success) {
|
|
685
|
-
return hint.usedRepair ? 70 : 120;
|
|
686
|
-
}
|
|
687
|
-
return hint.usedRepair ? -20 : -10;
|
|
688
|
-
}
|
|
689
490
|
function hasBalancedJsonDelimiters(input) {
|
|
690
491
|
const stack = [];
|
|
691
492
|
let inString = false;
|
|
@@ -771,6 +572,207 @@ function dedupeCandidates(candidates) {
|
|
|
771
572
|
function clamp(value, min, max) {
|
|
772
573
|
return Math.max(min, Math.min(max, Math.floor(value)));
|
|
773
574
|
}
|
|
575
|
+
function normalizeInteger(value, fallback) {
|
|
576
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
577
|
+
return fallback;
|
|
578
|
+
}
|
|
579
|
+
return Math.max(0, Math.floor(value));
|
|
580
|
+
}
|
|
581
|
+
function resolveExtractionHeuristics(input, defaults) {
|
|
582
|
+
const merged = {
|
|
583
|
+
...defaults,
|
|
584
|
+
...input
|
|
585
|
+
};
|
|
586
|
+
const firstPassMin = normalizeInteger(merged.firstPassMin, defaults.firstPassMin);
|
|
587
|
+
const firstPassCap = Math.max(firstPassMin, normalizeInteger(merged.firstPassCap, defaults.firstPassCap));
|
|
588
|
+
const secondPassMin = normalizeInteger(merged.secondPassMin, defaults.secondPassMin);
|
|
589
|
+
const secondPassCap = Math.max(secondPassMin, normalizeInteger(merged.secondPassCap, defaults.secondPassCap));
|
|
590
|
+
return {
|
|
591
|
+
firstPassMin,
|
|
592
|
+
firstPassCap,
|
|
593
|
+
firstPassMultiplier: normalizeInteger(merged.firstPassMultiplier, defaults.firstPassMultiplier),
|
|
594
|
+
secondPassMin,
|
|
595
|
+
secondPassCap,
|
|
596
|
+
secondPassMultiplier: normalizeInteger(merged.secondPassMultiplier, defaults.secondPassMultiplier),
|
|
597
|
+
hintMaxLength: normalizeInteger(merged.hintMaxLength, defaults.hintMaxLength)
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// src/extract.ts
|
|
602
|
+
var DEFAULT_EXTRACTION_HEURISTICS = {
|
|
603
|
+
firstPassMin: 12,
|
|
604
|
+
firstPassCap: 30,
|
|
605
|
+
firstPassMultiplier: 6,
|
|
606
|
+
secondPassMin: 4,
|
|
607
|
+
secondPassCap: 8,
|
|
608
|
+
secondPassMultiplier: 2,
|
|
609
|
+
hintMaxLength: 50000
|
|
610
|
+
};
|
|
611
|
+
function extractJsonCandidates(input, options = {}) {
|
|
612
|
+
const maxCandidates = options.maxCandidates ?? 5;
|
|
613
|
+
const acceptArrays = options.acceptArrays ?? true;
|
|
614
|
+
const allowRepairHints = options.allowRepairHints ?? true;
|
|
615
|
+
const heuristics = resolveExtractionHeuristics(options.heuristics, DEFAULT_EXTRACTION_HEURISTICS);
|
|
616
|
+
const extractionInput = input;
|
|
617
|
+
const candidates = [];
|
|
618
|
+
candidates.push(...extractFromMarkdown(extractionInput, acceptArrays));
|
|
619
|
+
candidates.push(...scanBalancedSegments(extractionInput, acceptArrays));
|
|
620
|
+
if (candidates.length === 0 && extractionInput.trim()) {
|
|
621
|
+
const content = extractionInput.trim();
|
|
622
|
+
candidates.push({
|
|
623
|
+
id: "raw:fallback",
|
|
624
|
+
source: "raw",
|
|
625
|
+
content,
|
|
626
|
+
start: 0,
|
|
627
|
+
end: extractionInput.length,
|
|
628
|
+
score: 10 + Math.floor(lengthScore(content.length) / 3)
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
const prefiltered = prefilterByJsonShape(candidates, acceptArrays);
|
|
632
|
+
const firstPassLimit = clamp(maxCandidates * heuristics.firstPassMultiplier, heuristics.firstPassMin, heuristics.firstPassCap);
|
|
633
|
+
const firstPass = prefiltered.slice(0, firstPassLimit);
|
|
634
|
+
const secondPassLimit = Math.min(firstPass.length, clamp(maxCandidates * heuristics.secondPassMultiplier, heuristics.secondPassMin, heuristics.secondPassCap));
|
|
635
|
+
for (let i = 0;i < secondPassLimit; i += 1) {
|
|
636
|
+
const candidate = firstPass[i];
|
|
637
|
+
if (!candidate) {
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
const parseHint = buildParseHint(candidate.content, allowRepairHints, heuristics.hintMaxLength);
|
|
641
|
+
if (!parseHint) {
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
candidate.parseHint = parseHint;
|
|
645
|
+
candidate.score += parseHintBonus(parseHint);
|
|
646
|
+
}
|
|
647
|
+
const sorted = sortCandidates(firstPass);
|
|
648
|
+
const deduped = dedupeCandidates(sorted);
|
|
649
|
+
return deduped.slice(0, maxCandidates).map((candidate, index) => ({
|
|
650
|
+
id: `${candidate.source}:${index}`,
|
|
651
|
+
source: candidate.source,
|
|
652
|
+
content: candidate.content,
|
|
653
|
+
language: candidate.language,
|
|
654
|
+
parseHint: candidate.parseHint,
|
|
655
|
+
start: candidate.start,
|
|
656
|
+
end: candidate.end,
|
|
657
|
+
score: candidate.score
|
|
658
|
+
}));
|
|
659
|
+
}
|
|
660
|
+
function prefilterByJsonShape(candidates, acceptArrays) {
|
|
661
|
+
const shaped = candidates.map((candidate) => {
|
|
662
|
+
const shapeScore = jsonShapeScore(candidate.content, acceptArrays);
|
|
663
|
+
return {
|
|
664
|
+
...candidate,
|
|
665
|
+
shapeScore,
|
|
666
|
+
score: candidate.score + shapeScore
|
|
667
|
+
};
|
|
668
|
+
});
|
|
669
|
+
const sorted = sortCandidates(shaped);
|
|
670
|
+
const deduped = dedupeCandidates(sorted);
|
|
671
|
+
const filtered = deduped.filter((candidate) => passesShapeFilter(candidate));
|
|
672
|
+
if (filtered.length > 0) {
|
|
673
|
+
const fallback = deduped.find((candidate) => !passesShapeFilter(candidate));
|
|
674
|
+
if (fallback) {
|
|
675
|
+
filtered.push(fallback);
|
|
676
|
+
}
|
|
677
|
+
return sortCandidates(filtered);
|
|
678
|
+
}
|
|
679
|
+
return deduped.slice(0, Math.min(1, deduped.length));
|
|
680
|
+
}
|
|
681
|
+
function extractFromMarkdown(input, acceptArrays) {
|
|
682
|
+
const blocks = extractMarkdownCodeBlocks(input);
|
|
683
|
+
return blocks.flatMap((block, index) => {
|
|
684
|
+
const language = block.language || null;
|
|
685
|
+
const content = block.code.trim();
|
|
686
|
+
if (!content) {
|
|
687
|
+
return [];
|
|
688
|
+
}
|
|
689
|
+
if (!looksLikeJsonEnvelope(content, acceptArrays)) {
|
|
690
|
+
return [];
|
|
691
|
+
}
|
|
692
|
+
const langBonus = languageBonus(language);
|
|
693
|
+
return [
|
|
694
|
+
{
|
|
695
|
+
id: `fenced:${index}`,
|
|
696
|
+
source: "fenced",
|
|
697
|
+
language,
|
|
698
|
+
content,
|
|
699
|
+
start: block.start,
|
|
700
|
+
end: block.end,
|
|
701
|
+
score: 260 + langBonus + lengthScore(content.length)
|
|
702
|
+
}
|
|
703
|
+
];
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
function scanBalancedSegments(input, acceptArrays) {
|
|
707
|
+
const results = [];
|
|
708
|
+
const stack = [];
|
|
709
|
+
let inString = false;
|
|
710
|
+
let quote = null;
|
|
711
|
+
let escaped = false;
|
|
712
|
+
for (let i = 0;i < input.length; i += 1) {
|
|
713
|
+
const char = input[i];
|
|
714
|
+
if (!char) {
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
if (inString) {
|
|
718
|
+
if (escaped) {
|
|
719
|
+
escaped = false;
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
if (char === "\\") {
|
|
723
|
+
escaped = true;
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
if (char === quote) {
|
|
727
|
+
inString = false;
|
|
728
|
+
quote = null;
|
|
729
|
+
}
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
const allowSingleQuoted = stack.length > 0;
|
|
733
|
+
if (char === '"' || allowSingleQuoted && (char === "'" || char === "`")) {
|
|
734
|
+
inString = true;
|
|
735
|
+
quote = char;
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
if (char === "{" || char === "[") {
|
|
739
|
+
stack.push({ char, index: i });
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
742
|
+
if (char !== "}" && char !== "]") {
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
const expectedOpen = char === "}" ? "{" : "[";
|
|
746
|
+
while (stack.length > 0 && stack[stack.length - 1]?.char !== expectedOpen) {
|
|
747
|
+
stack.pop();
|
|
748
|
+
}
|
|
749
|
+
const opened = stack.pop();
|
|
750
|
+
if (!opened) {
|
|
751
|
+
continue;
|
|
752
|
+
}
|
|
753
|
+
if (stack.length > 0) {
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
if (!acceptArrays && opened.char === "[") {
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
759
|
+
const content = input.slice(opened.index, i + 1).trim();
|
|
760
|
+
if (!content) {
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
const rootBonus = opened.char === "{" ? 40 : 20;
|
|
764
|
+
const boundaryBonus = boundaryScore(input, opened.index, i + 1);
|
|
765
|
+
results.push({
|
|
766
|
+
id: `scan:${results.length}`,
|
|
767
|
+
source: "scan",
|
|
768
|
+
content,
|
|
769
|
+
start: opened.index,
|
|
770
|
+
end: i + 1,
|
|
771
|
+
score: 120 + rootBonus + boundaryBonus + lengthScore(content.length)
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
return results;
|
|
775
|
+
}
|
|
774
776
|
// src/schema.ts
|
|
775
777
|
var RE_SIMPLE_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
776
778
|
var RE_WHITESPACE = /\s+/g;
|
|
@@ -1219,17 +1221,107 @@ function findSSEBoundary(buffer) {
|
|
|
1219
1221
|
return Math.max(crlfIndex, lfIndex);
|
|
1220
1222
|
}
|
|
1221
1223
|
|
|
1222
|
-
// src/providers/mcp-runtime.ts
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1224
|
+
// src/providers/mcp-runtime-debug.ts
|
|
1225
|
+
function formatToolExecutionDebugLine(execution) {
|
|
1226
|
+
const status = execution.error ? "error" : "ok";
|
|
1227
|
+
const scope = [execution.provider, execution.model].filter(Boolean).join("/") || "unknown";
|
|
1228
|
+
const toolRef = execution.clientId ? `${execution.clientId}:${execution.name ?? "unknown"}` : execution.name ?? "unknown";
|
|
1229
|
+
const duration = typeof execution.durationMs === "number" ? ` ${execution.durationMs}ms` : "";
|
|
1230
|
+
const base = `[tool:mcp:${status}] ${scope} ${toolRef}#${execution.callId}${duration}`;
|
|
1231
|
+
if (execution.error) {
|
|
1232
|
+
return `${base} -> ${execution.error}`;
|
|
1233
|
+
}
|
|
1234
|
+
return base;
|
|
1235
|
+
}
|
|
1236
|
+
function emitToolExecution(request, execution) {
|
|
1237
|
+
request.onToolExecution?.(execution);
|
|
1238
|
+
const debug = resolveToolDebugOptions(request.toolDebug);
|
|
1239
|
+
if (!debug.enabled) {
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
debug.logger(formatToolExecutionDebugLine(execution));
|
|
1243
|
+
if (debug.includeRequest) {
|
|
1244
|
+
debug.logger(formatToolExecutionRequestDebugLine(execution, debug));
|
|
1245
|
+
}
|
|
1246
|
+
if (debug.includeResult && (!execution.error || debug.includeResultOnError)) {
|
|
1247
|
+
debug.logger(formatToolExecutionResultDebugLine(execution, debug));
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
function resolveToolDebugOptions(value) {
|
|
1251
|
+
if (value === true) {
|
|
1252
|
+
return {
|
|
1253
|
+
enabled: true,
|
|
1254
|
+
logger: defaultToolDebugLogger,
|
|
1255
|
+
includeRequest: true,
|
|
1256
|
+
includeResult: true,
|
|
1257
|
+
includeResultOnError: true,
|
|
1258
|
+
pretty: false
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
if (value === undefined || value === false) {
|
|
1262
|
+
return {
|
|
1263
|
+
enabled: false,
|
|
1264
|
+
logger: () => {
|
|
1265
|
+
return;
|
|
1266
|
+
},
|
|
1267
|
+
includeRequest: false,
|
|
1268
|
+
includeResult: false,
|
|
1269
|
+
includeResultOnError: false,
|
|
1270
|
+
pretty: false
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
return {
|
|
1274
|
+
enabled: value.enabled ?? true,
|
|
1275
|
+
logger: value.logger ?? defaultToolDebugLogger,
|
|
1276
|
+
includeRequest: value.includeRequest ?? true,
|
|
1277
|
+
includeResult: value.includeResult ?? true,
|
|
1278
|
+
includeResultOnError: value.includeResultOnError ?? true,
|
|
1279
|
+
pretty: value.pretty ?? false
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
function defaultToolDebugLogger(line) {
|
|
1283
|
+
const { log } = globalThis.console;
|
|
1284
|
+
log(line);
|
|
1285
|
+
}
|
|
1286
|
+
function formatToolExecutionRequestDebugLine(execution, debug) {
|
|
1287
|
+
const scope = [execution.provider, execution.model].filter(Boolean).join("/") || "unknown";
|
|
1288
|
+
const toolRef = execution.clientId ? `${execution.clientId}:${execution.name ?? "unknown"}` : execution.name ?? "unknown";
|
|
1289
|
+
const payload = formatDebugPayload(execution.arguments, debug.pretty);
|
|
1290
|
+
return `[tool:mcp:request] ${scope} ${toolRef}#${execution.callId} arguments=${payload}`;
|
|
1291
|
+
}
|
|
1292
|
+
function formatToolExecutionResultDebugLine(execution, debug) {
|
|
1293
|
+
const scope = [execution.provider, execution.model].filter(Boolean).join("/") || "unknown";
|
|
1294
|
+
const toolRef = execution.clientId ? `${execution.clientId}:${execution.name ?? "unknown"}` : execution.name ?? "unknown";
|
|
1295
|
+
if (execution.error) {
|
|
1296
|
+
const payload2 = formatDebugPayload({ error: execution.error }, debug.pretty);
|
|
1297
|
+
return `[tool:mcp:result:error] ${scope} ${toolRef}#${execution.callId} output=${payload2}`;
|
|
1298
|
+
}
|
|
1299
|
+
const payload = formatDebugPayload(execution.output, debug.pretty);
|
|
1300
|
+
return `[tool:mcp:result:ok] ${scope} ${toolRef}#${execution.callId} output=${payload}`;
|
|
1301
|
+
}
|
|
1302
|
+
function formatDebugPayload(value, pretty) {
|
|
1303
|
+
if (value === undefined) {
|
|
1304
|
+
return "undefined";
|
|
1305
|
+
}
|
|
1306
|
+
try {
|
|
1307
|
+
const serialized = JSON.stringify(value, null, pretty ? 2 : 0);
|
|
1308
|
+
return serialized ?? "undefined";
|
|
1309
|
+
} catch {
|
|
1310
|
+
return String(value);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// src/providers/mcp-runtime.ts
|
|
1315
|
+
var DEFAULT_MAX_TOOL_ROUNDS = 100;
|
|
1316
|
+
async function resolveMCPToolset(clients) {
|
|
1317
|
+
if (!Array.isArray(clients) || clients.length === 0) {
|
|
1318
|
+
return {
|
|
1319
|
+
tools: [],
|
|
1320
|
+
byName: new Map
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
const listed = [];
|
|
1324
|
+
for (const client of clients) {
|
|
1233
1325
|
let cursor;
|
|
1234
1326
|
do {
|
|
1235
1327
|
const page = await client.listTools(cursor ? { cursor } : undefined);
|
|
@@ -1411,90 +1503,6 @@ function stringifyToolOutput(value) {
|
|
|
1411
1503
|
}
|
|
1412
1504
|
return JSON.stringify(value ?? null);
|
|
1413
1505
|
}
|
|
1414
|
-
function formatToolExecutionDebugLine(execution) {
|
|
1415
|
-
const status = execution.error ? "error" : "ok";
|
|
1416
|
-
const scope = [execution.provider, execution.model].filter(Boolean).join("/") || "unknown";
|
|
1417
|
-
const toolRef = execution.clientId ? `${execution.clientId}:${execution.name ?? "unknown"}` : execution.name ?? "unknown";
|
|
1418
|
-
const duration = typeof execution.durationMs === "number" ? ` ${execution.durationMs}ms` : "";
|
|
1419
|
-
const base = `[tool:mcp:${status}] ${scope} ${toolRef}#${execution.callId}${duration}`;
|
|
1420
|
-
if (execution.error) {
|
|
1421
|
-
return `${base} -> ${execution.error}`;
|
|
1422
|
-
}
|
|
1423
|
-
return base;
|
|
1424
|
-
}
|
|
1425
|
-
function emitToolExecution(request, execution) {
|
|
1426
|
-
request.onToolExecution?.(execution);
|
|
1427
|
-
const debug = resolveToolDebugOptions(request.toolDebug);
|
|
1428
|
-
if (!debug.enabled) {
|
|
1429
|
-
return;
|
|
1430
|
-
}
|
|
1431
|
-
debug.logger(formatToolExecutionDebugLine(execution));
|
|
1432
|
-
if (debug.includeRequest) {
|
|
1433
|
-
debug.logger(formatToolExecutionRequestDebugLine(execution, debug));
|
|
1434
|
-
}
|
|
1435
|
-
if (debug.includeResult && (!execution.error || debug.includeResultOnError)) {
|
|
1436
|
-
debug.logger(formatToolExecutionResultDebugLine(execution, debug));
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
function resolveToolDebugOptions(value) {
|
|
1440
|
-
if (value === true) {
|
|
1441
|
-
return {
|
|
1442
|
-
enabled: true,
|
|
1443
|
-
logger: (line) => console.log(line),
|
|
1444
|
-
includeRequest: true,
|
|
1445
|
-
includeResult: true,
|
|
1446
|
-
includeResultOnError: true,
|
|
1447
|
-
pretty: false
|
|
1448
|
-
};
|
|
1449
|
-
}
|
|
1450
|
-
if (value === undefined || value === false) {
|
|
1451
|
-
return {
|
|
1452
|
-
enabled: false,
|
|
1453
|
-
logger: () => {
|
|
1454
|
-
return;
|
|
1455
|
-
},
|
|
1456
|
-
includeRequest: false,
|
|
1457
|
-
includeResult: false,
|
|
1458
|
-
includeResultOnError: false,
|
|
1459
|
-
pretty: false
|
|
1460
|
-
};
|
|
1461
|
-
}
|
|
1462
|
-
return {
|
|
1463
|
-
enabled: value.enabled ?? true,
|
|
1464
|
-
logger: value.logger ?? ((line) => console.log(line)),
|
|
1465
|
-
includeRequest: value.includeRequest ?? true,
|
|
1466
|
-
includeResult: value.includeResult ?? true,
|
|
1467
|
-
includeResultOnError: value.includeResultOnError ?? true,
|
|
1468
|
-
pretty: value.pretty ?? false
|
|
1469
|
-
};
|
|
1470
|
-
}
|
|
1471
|
-
function formatToolExecutionRequestDebugLine(execution, debug) {
|
|
1472
|
-
const scope = [execution.provider, execution.model].filter(Boolean).join("/") || "unknown";
|
|
1473
|
-
const toolRef = execution.clientId ? `${execution.clientId}:${execution.name ?? "unknown"}` : execution.name ?? "unknown";
|
|
1474
|
-
const payload = formatDebugPayload(execution.arguments, debug.pretty);
|
|
1475
|
-
return `[tool:mcp:request] ${scope} ${toolRef}#${execution.callId} arguments=${payload}`;
|
|
1476
|
-
}
|
|
1477
|
-
function formatToolExecutionResultDebugLine(execution, debug) {
|
|
1478
|
-
const scope = [execution.provider, execution.model].filter(Boolean).join("/") || "unknown";
|
|
1479
|
-
const toolRef = execution.clientId ? `${execution.clientId}:${execution.name ?? "unknown"}` : execution.name ?? "unknown";
|
|
1480
|
-
if (execution.error) {
|
|
1481
|
-
const payload2 = formatDebugPayload({ error: execution.error }, debug.pretty);
|
|
1482
|
-
return `[tool:mcp:result:error] ${scope} ${toolRef}#${execution.callId} output=${payload2}`;
|
|
1483
|
-
}
|
|
1484
|
-
const payload = formatDebugPayload(execution.output, debug.pretty);
|
|
1485
|
-
return `[tool:mcp:result:ok] ${scope} ${toolRef}#${execution.callId} output=${payload}`;
|
|
1486
|
-
}
|
|
1487
|
-
function formatDebugPayload(value, pretty) {
|
|
1488
|
-
if (value === undefined) {
|
|
1489
|
-
return "undefined";
|
|
1490
|
-
}
|
|
1491
|
-
try {
|
|
1492
|
-
const serialized = JSON.stringify(value, null, pretty ? 2 : 0);
|
|
1493
|
-
return serialized ?? "undefined";
|
|
1494
|
-
} catch {
|
|
1495
|
-
return String(value);
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
1506
|
function countNameCollisions(names) {
|
|
1499
1507
|
const out = new Map;
|
|
1500
1508
|
for (const name of names) {
|
|
@@ -1691,103 +1699,89 @@ function createOpenAICompatibleAdapter(options) {
|
|
|
1691
1699
|
if (usesMCP) {
|
|
1692
1700
|
return streamWithChatCompletionsWithMCP(options, fetcher, path, request, callbacks);
|
|
1693
1701
|
}
|
|
1694
|
-
|
|
1695
|
-
method: "POST",
|
|
1696
|
-
headers: buildHeaders(options),
|
|
1697
|
-
body: JSON.stringify(cleanUndefined({
|
|
1698
|
-
...options.defaultBody,
|
|
1699
|
-
...request.body,
|
|
1700
|
-
model: options.model,
|
|
1701
|
-
messages: buildMessages(request),
|
|
1702
|
-
temperature: request.temperature,
|
|
1703
|
-
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1704
|
-
max_tokens: request.maxTokens,
|
|
1705
|
-
stream: true
|
|
1706
|
-
})),
|
|
1707
|
-
signal: request.signal
|
|
1708
|
-
});
|
|
1709
|
-
if (!response.ok) {
|
|
1710
|
-
const message = await response.text();
|
|
1711
|
-
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
1712
|
-
}
|
|
1713
|
-
callbacks.onStart?.();
|
|
1714
|
-
let text = "";
|
|
1715
|
-
let reasoning = "";
|
|
1716
|
-
let usage;
|
|
1717
|
-
let finishReason;
|
|
1718
|
-
await consumeSSE(response, (data) => {
|
|
1719
|
-
if (data === "[DONE]") {
|
|
1720
|
-
return;
|
|
1721
|
-
}
|
|
1722
|
-
const json = safeJSONParse(data);
|
|
1723
|
-
if (!isRecord2(json)) {
|
|
1724
|
-
return;
|
|
1725
|
-
}
|
|
1726
|
-
const delta = pickAssistantDelta(json);
|
|
1727
|
-
const reasoningDelta = pickAssistantReasoningDelta(json);
|
|
1728
|
-
const chunkUsage = pickUsage(json);
|
|
1729
|
-
const chunkFinishReason = pickFinishReason(json);
|
|
1730
|
-
usage = preferLatestUsage(usage, chunkUsage);
|
|
1731
|
-
if (chunkFinishReason) {
|
|
1732
|
-
finishReason = chunkFinishReason;
|
|
1733
|
-
}
|
|
1734
|
-
if (delta) {
|
|
1735
|
-
text += delta;
|
|
1736
|
-
callbacks.onToken?.(delta);
|
|
1737
|
-
}
|
|
1738
|
-
if (reasoningDelta) {
|
|
1739
|
-
reasoning += reasoningDelta;
|
|
1740
|
-
}
|
|
1741
|
-
if (delta || reasoningDelta || chunkUsage || chunkFinishReason) {
|
|
1742
|
-
const chunk = {
|
|
1743
|
-
textDelta: delta,
|
|
1744
|
-
reasoningDelta: reasoningDelta || undefined,
|
|
1745
|
-
raw: json,
|
|
1746
|
-
usage: chunkUsage,
|
|
1747
|
-
finishReason: chunkFinishReason
|
|
1748
|
-
};
|
|
1749
|
-
callbacks.onChunk?.(chunk);
|
|
1750
|
-
}
|
|
1751
|
-
});
|
|
1752
|
-
const out = {
|
|
1753
|
-
text,
|
|
1754
|
-
reasoning: reasoning.length > 0 ? reasoning : undefined,
|
|
1755
|
-
usage,
|
|
1756
|
-
finishReason
|
|
1757
|
-
};
|
|
1758
|
-
callbacks.onComplete?.(out);
|
|
1759
|
-
return out;
|
|
1702
|
+
return streamWithChatCompletionsPassThrough(options, fetcher, path, request, callbacks);
|
|
1760
1703
|
},
|
|
1761
1704
|
async embed(request) {
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1705
|
+
return embedOpenAI(options, fetcher, embeddingPath, request);
|
|
1706
|
+
}
|
|
1707
|
+
};
|
|
1708
|
+
}
|
|
1709
|
+
async function streamWithChatCompletionsPassThrough(options, fetcher, path, request, callbacks) {
|
|
1710
|
+
const response = await sendOpenAIRequest(options, fetcher, path, request, buildChatCompletionsBody(options, request, {
|
|
1711
|
+
messages: buildMessages(request),
|
|
1712
|
+
stream: true
|
|
1713
|
+
}));
|
|
1714
|
+
if (!response.ok) {
|
|
1715
|
+
const message = await response.text();
|
|
1716
|
+
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
1717
|
+
}
|
|
1718
|
+
callbacks.onStart?.();
|
|
1719
|
+
let text = "";
|
|
1720
|
+
let reasoning = "";
|
|
1721
|
+
let usage;
|
|
1722
|
+
let finishReason;
|
|
1723
|
+
await consumeSSE(response, (data) => {
|
|
1724
|
+
if (data === "[DONE]") {
|
|
1725
|
+
return;
|
|
1726
|
+
}
|
|
1727
|
+
const json = safeJSONParse(data);
|
|
1728
|
+
if (!isRecord2(json)) {
|
|
1729
|
+
return;
|
|
1730
|
+
}
|
|
1731
|
+
const delta = pickAssistantDelta(json);
|
|
1732
|
+
const reasoningDelta = pickAssistantReasoningDelta(json);
|
|
1733
|
+
const chunkUsage = pickUsage(json);
|
|
1734
|
+
const chunkFinishReason = pickFinishReason(json);
|
|
1735
|
+
usage = preferLatestUsage(usage, chunkUsage);
|
|
1736
|
+
if (chunkFinishReason) {
|
|
1737
|
+
finishReason = chunkFinishReason;
|
|
1738
|
+
}
|
|
1739
|
+
if (delta) {
|
|
1740
|
+
text += delta;
|
|
1741
|
+
callbacks.onToken?.(delta);
|
|
1790
1742
|
}
|
|
1743
|
+
if (reasoningDelta) {
|
|
1744
|
+
reasoning += reasoningDelta;
|
|
1745
|
+
}
|
|
1746
|
+
emitOpenAIStreamChunk(callbacks, undefined, json, delta, reasoningDelta, chunkUsage, chunkFinishReason);
|
|
1747
|
+
});
|
|
1748
|
+
const out = {
|
|
1749
|
+
text,
|
|
1750
|
+
reasoning: reasoning.length > 0 ? reasoning : undefined,
|
|
1751
|
+
usage,
|
|
1752
|
+
finishReason
|
|
1753
|
+
};
|
|
1754
|
+
callbacks.onComplete?.(out);
|
|
1755
|
+
return out;
|
|
1756
|
+
}
|
|
1757
|
+
async function embedOpenAI(options, fetcher, path, request) {
|
|
1758
|
+
const body = cleanUndefined({
|
|
1759
|
+
...options.defaultBody,
|
|
1760
|
+
...request.body,
|
|
1761
|
+
model: request.model ?? options.model,
|
|
1762
|
+
input: request.input,
|
|
1763
|
+
dimensions: request.dimensions,
|
|
1764
|
+
encoding_format: "float"
|
|
1765
|
+
});
|
|
1766
|
+
const response = await fetcher(buildURL(options.baseURL, path), {
|
|
1767
|
+
method: "POST",
|
|
1768
|
+
headers: buildHeaders(options),
|
|
1769
|
+
body: JSON.stringify(body)
|
|
1770
|
+
});
|
|
1771
|
+
if (!response.ok) {
|
|
1772
|
+
const message = await response.text();
|
|
1773
|
+
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
1774
|
+
}
|
|
1775
|
+
const json = await response.json();
|
|
1776
|
+
const data = json.data;
|
|
1777
|
+
if (!Array.isArray(data)) {
|
|
1778
|
+
throw new Error("Unexpected embedding response: missing data array");
|
|
1779
|
+
}
|
|
1780
|
+
return {
|
|
1781
|
+
embeddings: data.map((d) => isRecord2(d) && Array.isArray(d.embedding) ? d.embedding : []),
|
|
1782
|
+
model: pickString(json.model) ?? body.model,
|
|
1783
|
+
usage: pickUsage(json),
|
|
1784
|
+
raw: json
|
|
1791
1785
|
};
|
|
1792
1786
|
}
|
|
1793
1787
|
async function completeOpenAIRequest(options, fetcher, chatPath, responsesPath, request) {
|
|
@@ -1804,22 +1798,80 @@ async function completeOpenAIRequest(options, fetcher, chatPath, responsesPath,
|
|
|
1804
1798
|
}
|
|
1805
1799
|
return completeWithChatCompletionsPassThrough(options, fetcher, chatPath, request);
|
|
1806
1800
|
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1801
|
+
function buildChatCompletionsBody(options, request, overrides) {
|
|
1802
|
+
return buildOpenAIRequestBody(options, request, "max_tokens", overrides);
|
|
1803
|
+
}
|
|
1804
|
+
function buildResponsesBody(options, request, overrides) {
|
|
1805
|
+
return buildOpenAIRequestBody(options, request, "max_output_tokens", overrides);
|
|
1806
|
+
}
|
|
1807
|
+
function buildOpenAIRequestBody(options, request, maxTokenKey, overrides) {
|
|
1808
|
+
return cleanUndefined({
|
|
1809
|
+
...options.defaultBody,
|
|
1810
|
+
...request.body,
|
|
1811
|
+
model: options.model,
|
|
1812
|
+
temperature: request.temperature,
|
|
1813
|
+
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1814
|
+
[maxTokenKey]: request.maxTokens,
|
|
1815
|
+
...overrides
|
|
1816
|
+
});
|
|
1817
|
+
}
|
|
1818
|
+
function sendOpenAIRequest(options, fetcher, path, request, body) {
|
|
1819
|
+
return fetcher(buildURL(options.baseURL, path), {
|
|
1809
1820
|
method: "POST",
|
|
1810
1821
|
headers: buildHeaders(options),
|
|
1811
|
-
body: JSON.stringify(
|
|
1812
|
-
...options.defaultBody,
|
|
1813
|
-
...request.body,
|
|
1814
|
-
model: options.model,
|
|
1815
|
-
messages: buildMessages(request),
|
|
1816
|
-
temperature: request.temperature,
|
|
1817
|
-
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1818
|
-
max_tokens: request.maxTokens,
|
|
1819
|
-
stream: false
|
|
1820
|
-
})),
|
|
1822
|
+
body: JSON.stringify(body),
|
|
1821
1823
|
signal: request.signal
|
|
1822
1824
|
});
|
|
1825
|
+
}
|
|
1826
|
+
async function sendOpenAIJsonRequest(options, fetcher, path, request, body) {
|
|
1827
|
+
const response = await sendOpenAIRequest(options, fetcher, path, request, body);
|
|
1828
|
+
if (!response.ok) {
|
|
1829
|
+
const message = await response.text();
|
|
1830
|
+
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
1831
|
+
}
|
|
1832
|
+
return await response.json();
|
|
1833
|
+
}
|
|
1834
|
+
function createResponsesMCPState(request) {
|
|
1835
|
+
return {
|
|
1836
|
+
input: buildResponsesInput(request),
|
|
1837
|
+
previousResponseId: pickString(isRecord2(request.body) ? request.body.previous_response_id : undefined),
|
|
1838
|
+
aggregatedUsage: undefined,
|
|
1839
|
+
finishReason: undefined,
|
|
1840
|
+
lastPayload: undefined,
|
|
1841
|
+
executedToolCalls: [],
|
|
1842
|
+
toolExecutions: [],
|
|
1843
|
+
reasoningBlocks: []
|
|
1844
|
+
};
|
|
1845
|
+
}
|
|
1846
|
+
function buildResponsesMCPResult(state, text, raw) {
|
|
1847
|
+
return {
|
|
1848
|
+
text,
|
|
1849
|
+
reasoning: joinReasoningBlocks(state.reasoningBlocks) || undefined,
|
|
1850
|
+
reasoningBlocks: state.reasoningBlocks.length > 0 ? state.reasoningBlocks : undefined,
|
|
1851
|
+
raw,
|
|
1852
|
+
usage: state.aggregatedUsage,
|
|
1853
|
+
finishReason: state.finishReason,
|
|
1854
|
+
toolCalls: state.executedToolCalls.length > 0 ? state.executedToolCalls : undefined,
|
|
1855
|
+
toolExecutions: state.toolExecutions.length > 0 ? state.toolExecutions : undefined
|
|
1856
|
+
};
|
|
1857
|
+
}
|
|
1858
|
+
function emitOpenAIStreamChunk(callbacks, round, raw, delta, reasoningDelta, usage, finishReason) {
|
|
1859
|
+
if (delta || reasoningDelta || usage || finishReason) {
|
|
1860
|
+
callbacks.onChunk?.({
|
|
1861
|
+
textDelta: delta,
|
|
1862
|
+
reasoningDelta: reasoningDelta || undefined,
|
|
1863
|
+
...round !== undefined ? { turnIndex: round } : {},
|
|
1864
|
+
raw,
|
|
1865
|
+
usage,
|
|
1866
|
+
finishReason
|
|
1867
|
+
});
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
async function completeWithChatCompletionsPassThrough(options, fetcher, path, request) {
|
|
1871
|
+
const response = await sendOpenAIRequest(options, fetcher, path, request, buildChatCompletionsBody(options, request, {
|
|
1872
|
+
messages: buildMessages(request),
|
|
1873
|
+
stream: false
|
|
1874
|
+
}));
|
|
1823
1875
|
if (!response.ok) {
|
|
1824
1876
|
const message = await response.text();
|
|
1825
1877
|
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
@@ -1871,28 +1923,12 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
|
|
|
1871
1923
|
for (let round = 1;round <= maxToolRounds + 1; round += 1) {
|
|
1872
1924
|
const mcpToolset = await resolveMCPToolset(request.mcpClients);
|
|
1873
1925
|
const transportTools = toProviderFunctionTools(mcpToolset);
|
|
1874
|
-
const
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
model: options.model,
|
|
1881
|
-
messages,
|
|
1882
|
-
temperature: request.temperature,
|
|
1883
|
-
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1884
|
-
max_tokens: request.maxTokens,
|
|
1885
|
-
tools: transportTools,
|
|
1886
|
-
tool_choice: request.toolChoice,
|
|
1887
|
-
parallel_tool_calls: request.parallelToolCalls
|
|
1888
|
-
})),
|
|
1889
|
-
signal: request.signal
|
|
1890
|
-
});
|
|
1891
|
-
if (!response.ok) {
|
|
1892
|
-
const message = await response.text();
|
|
1893
|
-
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
1894
|
-
}
|
|
1895
|
-
const payload = await response.json();
|
|
1926
|
+
const payload = await sendOpenAIJsonRequest(options, fetcher, path, request, buildChatCompletionsBody(options, request, {
|
|
1927
|
+
messages,
|
|
1928
|
+
tools: transportTools,
|
|
1929
|
+
tool_choice: request.toolChoice,
|
|
1930
|
+
parallel_tool_calls: request.parallelToolCalls
|
|
1931
|
+
}));
|
|
1896
1932
|
lastPayload = payload;
|
|
1897
1933
|
aggregatedUsage = mergeUsage(aggregatedUsage, pickUsage(payload));
|
|
1898
1934
|
finishReason = pickFinishReason(payload);
|
|
@@ -1947,26 +1983,10 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
|
|
|
1947
1983
|
}
|
|
1948
1984
|
async function completeWithResponsesAPIPassThrough(options, fetcher, path, request) {
|
|
1949
1985
|
const body = isRecord2(request.body) ? request.body : undefined;
|
|
1950
|
-
const
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
...options.defaultBody,
|
|
1955
|
-
...request.body,
|
|
1956
|
-
model: options.model,
|
|
1957
|
-
input: buildResponsesInput(request),
|
|
1958
|
-
previous_response_id: pickString(body?.previous_response_id),
|
|
1959
|
-
temperature: request.temperature,
|
|
1960
|
-
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
1961
|
-
max_output_tokens: request.maxTokens
|
|
1962
|
-
})),
|
|
1963
|
-
signal: request.signal
|
|
1964
|
-
});
|
|
1965
|
-
if (!response.ok) {
|
|
1966
|
-
const message = await response.text();
|
|
1967
|
-
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
1968
|
-
}
|
|
1969
|
-
const payload = await response.json();
|
|
1986
|
+
const payload = await sendOpenAIJsonRequest(options, fetcher, path, request, buildResponsesBody(options, request, {
|
|
1987
|
+
input: buildResponsesInput(request),
|
|
1988
|
+
previous_response_id: pickString(body?.previous_response_id)
|
|
1989
|
+
}));
|
|
1970
1990
|
const toolCalls = pickResponsesToolCalls(payload);
|
|
1971
1991
|
return {
|
|
1972
1992
|
text: pickResponsesText(payload) || pickAssistantText(payload),
|
|
@@ -1978,58 +1998,26 @@ async function completeWithResponsesAPIPassThrough(options, fetcher, path, reque
|
|
|
1978
1998
|
}
|
|
1979
1999
|
async function completeWithResponsesAPIWithMCP(options, fetcher, path, request) {
|
|
1980
2000
|
const maxToolRounds = normalizeMaxToolRounds(request.maxToolRounds ?? options.defaultMaxToolRounds);
|
|
1981
|
-
|
|
1982
|
-
let previousResponseId = pickString(isRecord2(request.body) ? request.body.previous_response_id : undefined);
|
|
1983
|
-
let aggregatedUsage;
|
|
1984
|
-
let finishReason;
|
|
1985
|
-
let lastPayload;
|
|
1986
|
-
const executedToolCalls = [];
|
|
1987
|
-
const toolExecutions = [];
|
|
1988
|
-
const reasoningBlocks = [];
|
|
2001
|
+
const state = createResponsesMCPState(request);
|
|
1989
2002
|
for (let round = 1;round <= maxToolRounds + 1; round += 1) {
|
|
1990
2003
|
const mcpToolset = await resolveMCPToolset(request.mcpClients);
|
|
1991
2004
|
const transportTools = toResponsesTools(toProviderFunctionTools(mcpToolset));
|
|
1992
|
-
const
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
max_output_tokens: request.maxTokens,
|
|
2004
|
-
tools: transportTools,
|
|
2005
|
-
tool_choice: request.toolChoice,
|
|
2006
|
-
parallel_tool_calls: request.parallelToolCalls
|
|
2007
|
-
})),
|
|
2008
|
-
signal: request.signal
|
|
2009
|
-
});
|
|
2010
|
-
if (!response.ok) {
|
|
2011
|
-
const message = await response.text();
|
|
2012
|
-
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
2013
|
-
}
|
|
2014
|
-
const payload = await response.json();
|
|
2015
|
-
lastPayload = payload;
|
|
2016
|
-
aggregatedUsage = mergeUsage(aggregatedUsage, pickUsage(payload));
|
|
2017
|
-
finishReason = pickResponsesFinishReason(payload) ?? finishReason;
|
|
2018
|
-
pushReasoningBlock(reasoningBlocks, round, pickResponsesReasoning(payload));
|
|
2005
|
+
const payload = await sendOpenAIJsonRequest(options, fetcher, path, request, buildResponsesBody(options, request, {
|
|
2006
|
+
input: state.input,
|
|
2007
|
+
previous_response_id: state.previousResponseId,
|
|
2008
|
+
tools: transportTools,
|
|
2009
|
+
tool_choice: request.toolChoice,
|
|
2010
|
+
parallel_tool_calls: request.parallelToolCalls
|
|
2011
|
+
}));
|
|
2012
|
+
state.lastPayload = payload;
|
|
2013
|
+
state.aggregatedUsage = mergeUsage(state.aggregatedUsage, pickUsage(payload));
|
|
2014
|
+
state.finishReason = pickResponsesFinishReason(payload) ?? state.finishReason;
|
|
2015
|
+
pushReasoningBlock(state.reasoningBlocks, round, pickResponsesReasoning(payload));
|
|
2019
2016
|
const providerToolCalls = pickResponsesToolCalls(payload);
|
|
2020
2017
|
const functionCalls = providerToolCalls.filter((toolCall) => toolCall.type === "function" && typeof toolCall.id === "string" && typeof toolCall.name === "string");
|
|
2021
2018
|
if (functionCalls.length === 0) {
|
|
2022
2019
|
const text = pickResponsesText(payload) || pickAssistantText(payload);
|
|
2023
|
-
return
|
|
2024
|
-
text,
|
|
2025
|
-
reasoning: joinReasoningBlocks(reasoningBlocks) || undefined,
|
|
2026
|
-
reasoningBlocks: reasoningBlocks.length > 0 ? reasoningBlocks : undefined,
|
|
2027
|
-
raw: payload,
|
|
2028
|
-
usage: aggregatedUsage,
|
|
2029
|
-
finishReason,
|
|
2030
|
-
toolCalls: executedToolCalls.length > 0 ? executedToolCalls : undefined,
|
|
2031
|
-
toolExecutions: toolExecutions.length > 0 ? toolExecutions : undefined
|
|
2032
|
-
};
|
|
2020
|
+
return buildResponsesMCPResult(state, text, payload);
|
|
2033
2021
|
}
|
|
2034
2022
|
if (round > maxToolRounds) {
|
|
2035
2023
|
throw new Error(`Tool call loop exceeded maxToolRounds (${maxToolRounds}).`);
|
|
@@ -2040,25 +2028,16 @@ async function completeWithResponsesAPIWithMCP(options, fetcher, path, request)
|
|
|
2040
2028
|
provider: "openai-compatible",
|
|
2041
2029
|
model: options.model
|
|
2042
2030
|
});
|
|
2043
|
-
executedToolCalls.push(...outputs.map((entry) => entry.call));
|
|
2044
|
-
toolExecutions.push(...outputs.map((entry) => entry.execution));
|
|
2045
|
-
input = outputs.map((entry) => ({
|
|
2031
|
+
state.executedToolCalls.push(...outputs.map((entry) => entry.call));
|
|
2032
|
+
state.toolExecutions.push(...outputs.map((entry) => entry.execution));
|
|
2033
|
+
state.input = outputs.map((entry) => ({
|
|
2046
2034
|
type: "function_call_output",
|
|
2047
2035
|
call_id: entry.call.id,
|
|
2048
2036
|
output: stringifyToolOutput(entry.call.error ? { error: entry.call.error } : entry.call.output)
|
|
2049
2037
|
}));
|
|
2050
|
-
previousResponseId = pickString(payload.id);
|
|
2038
|
+
state.previousResponseId = pickString(payload.id);
|
|
2051
2039
|
}
|
|
2052
|
-
return {
|
|
2053
|
-
text: pickResponsesText(lastPayload ?? {}) || pickAssistantText(lastPayload ?? {}),
|
|
2054
|
-
reasoning: joinReasoningBlocks(reasoningBlocks) || undefined,
|
|
2055
|
-
reasoningBlocks: reasoningBlocks.length > 0 ? reasoningBlocks : undefined,
|
|
2056
|
-
raw: lastPayload,
|
|
2057
|
-
usage: aggregatedUsage,
|
|
2058
|
-
finishReason,
|
|
2059
|
-
toolCalls: executedToolCalls.length > 0 ? executedToolCalls : undefined,
|
|
2060
|
-
toolExecutions: toolExecutions.length > 0 ? toolExecutions : undefined
|
|
2061
|
-
};
|
|
2040
|
+
return buildResponsesMCPResult(state, pickResponsesText(state.lastPayload ?? {}) || pickAssistantText(state.lastPayload ?? {}), state.lastPayload);
|
|
2062
2041
|
}
|
|
2063
2042
|
async function streamWithChatCompletionsWithMCP(options, fetcher, path, request, callbacks) {
|
|
2064
2043
|
const maxToolRounds = normalizeMaxToolRounds(request.maxToolRounds ?? options.defaultMaxToolRounds);
|
|
@@ -2074,24 +2053,13 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2074
2053
|
for (let round = 1;round <= maxToolRounds + 1; round += 1) {
|
|
2075
2054
|
const mcpToolset = await resolveMCPToolset(request.mcpClients);
|
|
2076
2055
|
const transportTools = toProviderFunctionTools(mcpToolset);
|
|
2077
|
-
const response = await
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
messages,
|
|
2085
|
-
temperature: request.temperature,
|
|
2086
|
-
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
2087
|
-
max_tokens: request.maxTokens,
|
|
2088
|
-
tools: transportTools,
|
|
2089
|
-
tool_choice: request.toolChoice,
|
|
2090
|
-
parallel_tool_calls: request.parallelToolCalls,
|
|
2091
|
-
stream: true
|
|
2092
|
-
})),
|
|
2093
|
-
signal: request.signal
|
|
2094
|
-
});
|
|
2056
|
+
const response = await sendOpenAIRequest(options, fetcher, path, request, buildChatCompletionsBody(options, request, {
|
|
2057
|
+
messages,
|
|
2058
|
+
tools: transportTools,
|
|
2059
|
+
tool_choice: request.toolChoice,
|
|
2060
|
+
parallel_tool_calls: request.parallelToolCalls,
|
|
2061
|
+
stream: true
|
|
2062
|
+
}));
|
|
2095
2063
|
if (!response.ok) {
|
|
2096
2064
|
const message = await response.text();
|
|
2097
2065
|
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
@@ -2128,17 +2096,7 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2128
2096
|
roundReasoning += reasoningDelta;
|
|
2129
2097
|
reasoningFieldName ??= pickAssistantReasoningDeltaFieldName(json);
|
|
2130
2098
|
}
|
|
2131
|
-
|
|
2132
|
-
const chunk = {
|
|
2133
|
-
textDelta: delta,
|
|
2134
|
-
reasoningDelta: reasoningDelta || undefined,
|
|
2135
|
-
turnIndex: round,
|
|
2136
|
-
raw: json,
|
|
2137
|
-
usage: chunkUsage,
|
|
2138
|
-
finishReason: chunkFinishReason
|
|
2139
|
-
};
|
|
2140
|
-
callbacks.onChunk?.(chunk);
|
|
2141
|
-
}
|
|
2099
|
+
emitOpenAIStreamChunk(callbacks, round, json, delta, reasoningDelta, chunkUsage, chunkFinishReason);
|
|
2142
2100
|
});
|
|
2143
2101
|
aggregatedUsage = mergeUsage(aggregatedUsage, roundUsage);
|
|
2144
2102
|
if (roundFinishReason) {
|
|
@@ -2217,22 +2175,11 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
|
|
|
2217
2175
|
}
|
|
2218
2176
|
async function streamWithResponsesAPIPassThrough(options, fetcher, path, request, callbacks) {
|
|
2219
2177
|
const body = isRecord2(request.body) ? request.body : undefined;
|
|
2220
|
-
const response = await
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
...request.body,
|
|
2226
|
-
model: options.model,
|
|
2227
|
-
input: buildResponsesInput(request),
|
|
2228
|
-
previous_response_id: pickString(body?.previous_response_id),
|
|
2229
|
-
temperature: request.temperature,
|
|
2230
|
-
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
2231
|
-
max_output_tokens: request.maxTokens,
|
|
2232
|
-
stream: true
|
|
2233
|
-
})),
|
|
2234
|
-
signal: request.signal
|
|
2235
|
-
});
|
|
2178
|
+
const response = await sendOpenAIRequest(options, fetcher, path, request, buildResponsesBody(options, request, {
|
|
2179
|
+
input: buildResponsesInput(request),
|
|
2180
|
+
previous_response_id: pickString(body?.previous_response_id),
|
|
2181
|
+
stream: true
|
|
2182
|
+
}));
|
|
2236
2183
|
if (!response.ok) {
|
|
2237
2184
|
const message = await response.text();
|
|
2238
2185
|
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
@@ -2265,15 +2212,7 @@ async function streamWithResponsesAPIPassThrough(options, fetcher, path, request
|
|
|
2265
2212
|
text += delta;
|
|
2266
2213
|
callbacks.onToken?.(delta);
|
|
2267
2214
|
}
|
|
2268
|
-
|
|
2269
|
-
const chunk = {
|
|
2270
|
-
textDelta: delta,
|
|
2271
|
-
raw: json,
|
|
2272
|
-
usage: chunkUsage,
|
|
2273
|
-
finishReason: chunkFinishReason
|
|
2274
|
-
};
|
|
2275
|
-
callbacks.onChunk?.(chunk);
|
|
2276
|
-
}
|
|
2215
|
+
emitOpenAIStreamChunk(callbacks, undefined, json, delta, "", chunkUsage, chunkFinishReason);
|
|
2277
2216
|
});
|
|
2278
2217
|
const finalPayload = lastPayload ?? {};
|
|
2279
2218
|
const out = {
|
|
@@ -2287,37 +2226,19 @@ async function streamWithResponsesAPIPassThrough(options, fetcher, path, request
|
|
|
2287
2226
|
}
|
|
2288
2227
|
async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, callbacks) {
|
|
2289
2228
|
const maxToolRounds = normalizeMaxToolRounds(request.maxToolRounds ?? options.defaultMaxToolRounds);
|
|
2290
|
-
|
|
2291
|
-
let previousResponseId = pickString(isRecord2(request.body) ? request.body.previous_response_id : undefined);
|
|
2292
|
-
let aggregatedUsage;
|
|
2293
|
-
let finishReason;
|
|
2294
|
-
let lastPayload;
|
|
2295
|
-
const executedToolCalls = [];
|
|
2296
|
-
const toolExecutions = [];
|
|
2297
|
-
const reasoningBlocks = [];
|
|
2229
|
+
const state = createResponsesMCPState(request);
|
|
2298
2230
|
callbacks.onStart?.();
|
|
2299
2231
|
for (let round = 1;round <= maxToolRounds + 1; round += 1) {
|
|
2300
2232
|
const mcpToolset = await resolveMCPToolset(request.mcpClients);
|
|
2301
2233
|
const transportTools = toResponsesTools(toProviderFunctionTools(mcpToolset));
|
|
2302
|
-
const response = await
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
previous_response_id: previousResponseId,
|
|
2311
|
-
temperature: request.temperature,
|
|
2312
|
-
reasoning_effort: toOpenAIReasoningEffort(request.reasoningEffort),
|
|
2313
|
-
max_output_tokens: request.maxTokens,
|
|
2314
|
-
tools: transportTools,
|
|
2315
|
-
tool_choice: request.toolChoice,
|
|
2316
|
-
parallel_tool_calls: request.parallelToolCalls,
|
|
2317
|
-
stream: true
|
|
2318
|
-
})),
|
|
2319
|
-
signal: request.signal
|
|
2320
|
-
});
|
|
2234
|
+
const response = await sendOpenAIRequest(options, fetcher, path, request, buildResponsesBody(options, request, {
|
|
2235
|
+
input: state.input,
|
|
2236
|
+
previous_response_id: state.previousResponseId,
|
|
2237
|
+
tools: transportTools,
|
|
2238
|
+
tool_choice: request.toolChoice,
|
|
2239
|
+
parallel_tool_calls: request.parallelToolCalls,
|
|
2240
|
+
stream: true
|
|
2241
|
+
}));
|
|
2321
2242
|
if (!response.ok) {
|
|
2322
2243
|
const message = await response.text();
|
|
2323
2244
|
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
@@ -2339,7 +2260,7 @@ async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, ca
|
|
|
2339
2260
|
const payload = pickResponsesStreamPayload(json);
|
|
2340
2261
|
if (payload) {
|
|
2341
2262
|
roundPayload = payload;
|
|
2342
|
-
lastPayload = payload;
|
|
2263
|
+
state.lastPayload = payload;
|
|
2343
2264
|
}
|
|
2344
2265
|
const delta = pickResponsesStreamTextDelta(json);
|
|
2345
2266
|
const reasoningDelta = pickResponsesStreamReasoningDelta(json);
|
|
@@ -2357,24 +2278,14 @@ async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, ca
|
|
|
2357
2278
|
if (reasoningDelta) {
|
|
2358
2279
|
roundReasoning += reasoningDelta;
|
|
2359
2280
|
}
|
|
2360
|
-
|
|
2361
|
-
const chunk = {
|
|
2362
|
-
textDelta: delta,
|
|
2363
|
-
reasoningDelta: reasoningDelta || undefined,
|
|
2364
|
-
turnIndex: round,
|
|
2365
|
-
raw: json,
|
|
2366
|
-
usage: chunkUsage,
|
|
2367
|
-
finishReason: chunkFinishReason
|
|
2368
|
-
};
|
|
2369
|
-
callbacks.onChunk?.(chunk);
|
|
2370
|
-
}
|
|
2281
|
+
emitOpenAIStreamChunk(callbacks, round, json, delta, reasoningDelta, chunkUsage, chunkFinishReason);
|
|
2371
2282
|
});
|
|
2372
2283
|
const resolvedRoundUsage = preferLatestUsage(roundUsage, roundPayload ? pickUsage(roundPayload) : undefined);
|
|
2373
|
-
aggregatedUsage = mergeUsage(aggregatedUsage, resolvedRoundUsage);
|
|
2284
|
+
state.aggregatedUsage = mergeUsage(state.aggregatedUsage, resolvedRoundUsage);
|
|
2374
2285
|
if (roundFinishReason) {
|
|
2375
|
-
finishReason = roundFinishReason;
|
|
2286
|
+
state.finishReason = roundFinishReason;
|
|
2376
2287
|
} else if (roundPayload) {
|
|
2377
|
-
finishReason = pickResponsesFinishReason(roundPayload) ?? finishReason;
|
|
2288
|
+
state.finishReason = pickResponsesFinishReason(roundPayload) ?? state.finishReason;
|
|
2378
2289
|
}
|
|
2379
2290
|
const payloadToolCalls = roundPayload ? pickResponsesToolCalls(roundPayload) : [];
|
|
2380
2291
|
if (roundPayload && roundReasoning.length === 0) {
|
|
@@ -2383,7 +2294,7 @@ async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, ca
|
|
|
2383
2294
|
const streamedCalls = buildResponsesStreamToolCalls(streamedToolCalls);
|
|
2384
2295
|
const providerToolCalls = payloadToolCalls.length > 0 ? payloadToolCalls : streamedCalls;
|
|
2385
2296
|
const functionCalls = providerToolCalls.filter((toolCall) => toolCall.type === "function" && typeof toolCall.id === "string" && typeof toolCall.name === "string");
|
|
2386
|
-
pushReasoningBlock(reasoningBlocks, round, roundReasoning);
|
|
2297
|
+
pushReasoningBlock(state.reasoningBlocks, round, roundReasoning);
|
|
2387
2298
|
request.onTurnTransition?.({
|
|
2388
2299
|
turnIndex: round,
|
|
2389
2300
|
kind: "reasoningComplete",
|
|
@@ -2391,16 +2302,7 @@ async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, ca
|
|
|
2391
2302
|
});
|
|
2392
2303
|
if (functionCalls.length === 0) {
|
|
2393
2304
|
const finalText = roundText.length > 0 ? roundText : roundPayload ? pickResponsesText(roundPayload) || pickAssistantText(roundPayload) : "";
|
|
2394
|
-
const out2 =
|
|
2395
|
-
text: finalText,
|
|
2396
|
-
reasoning: joinReasoningBlocks(reasoningBlocks) || undefined,
|
|
2397
|
-
reasoningBlocks: reasoningBlocks.length > 0 ? reasoningBlocks : undefined,
|
|
2398
|
-
raw: roundPayload ?? lastPayload,
|
|
2399
|
-
usage: aggregatedUsage,
|
|
2400
|
-
finishReason,
|
|
2401
|
-
toolCalls: executedToolCalls.length > 0 ? executedToolCalls : undefined,
|
|
2402
|
-
toolExecutions: toolExecutions.length > 0 ? toolExecutions : undefined
|
|
2403
|
-
};
|
|
2305
|
+
const out2 = buildResponsesMCPResult(state, finalText, roundPayload ?? state.lastPayload);
|
|
2404
2306
|
request.onTurnTransition?.({ turnIndex: round, kind: "streamEnd" });
|
|
2405
2307
|
callbacks.onComplete?.(out2);
|
|
2406
2308
|
return out2;
|
|
@@ -2425,26 +2327,17 @@ async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, ca
|
|
|
2425
2327
|
provider: "openai-compatible",
|
|
2426
2328
|
model: options.model
|
|
2427
2329
|
});
|
|
2428
|
-
executedToolCalls.push(...outputs.map((entry) => entry.call));
|
|
2429
|
-
toolExecutions.push(...outputs.map((entry) => entry.execution));
|
|
2330
|
+
state.executedToolCalls.push(...outputs.map((entry) => entry.call));
|
|
2331
|
+
state.toolExecutions.push(...outputs.map((entry) => entry.execution));
|
|
2430
2332
|
request.onTurnTransition?.({ turnIndex: round, kind: "toolResultsReceived" });
|
|
2431
|
-
input = outputs.map((entry) => ({
|
|
2333
|
+
state.input = outputs.map((entry) => ({
|
|
2432
2334
|
type: "function_call_output",
|
|
2433
2335
|
call_id: entry.call.id,
|
|
2434
2336
|
output: stringifyToolOutput(entry.call.error ? { error: entry.call.error } : entry.call.output)
|
|
2435
2337
|
}));
|
|
2436
|
-
previousResponseId = pickString(roundPayload?.id);
|
|
2338
|
+
state.previousResponseId = pickString(roundPayload?.id);
|
|
2437
2339
|
}
|
|
2438
|
-
const out = {
|
|
2439
|
-
text: pickResponsesText(lastPayload ?? {}) || pickAssistantText(lastPayload ?? {}),
|
|
2440
|
-
reasoning: joinReasoningBlocks(reasoningBlocks) || undefined,
|
|
2441
|
-
reasoningBlocks: reasoningBlocks.length > 0 ? reasoningBlocks : undefined,
|
|
2442
|
-
raw: lastPayload,
|
|
2443
|
-
usage: aggregatedUsage,
|
|
2444
|
-
finishReason,
|
|
2445
|
-
toolCalls: executedToolCalls.length > 0 ? executedToolCalls : undefined,
|
|
2446
|
-
toolExecutions: toolExecutions.length > 0 ? toolExecutions : undefined
|
|
2447
|
-
};
|
|
2340
|
+
const out = buildResponsesMCPResult(state, pickResponsesText(state.lastPayload ?? {}) || pickAssistantText(state.lastPayload ?? {}), state.lastPayload);
|
|
2448
2341
|
request.onTurnTransition?.({ turnIndex: maxToolRounds + 1, kind: "streamEnd" });
|
|
2449
2342
|
callbacks.onComplete?.(out);
|
|
2450
2343
|
return out;
|
|
@@ -2597,7 +2490,7 @@ function pickAssistantDelta(payload) {
|
|
|
2597
2490
|
if (!isRecord2(delta)) {
|
|
2598
2491
|
return "";
|
|
2599
2492
|
}
|
|
2600
|
-
return
|
|
2493
|
+
return pickTextLike(delta.content);
|
|
2601
2494
|
}
|
|
2602
2495
|
function pickAssistantReasoning(payload) {
|
|
2603
2496
|
const message = pickAssistantMessage(payload);
|
|
@@ -2905,7 +2798,7 @@ function pickResponsesReasoning(payload) {
|
|
|
2905
2798
|
function pickAssistantText(payload) {
|
|
2906
2799
|
const message = pickAssistantMessage(payload);
|
|
2907
2800
|
if (message) {
|
|
2908
|
-
const text =
|
|
2801
|
+
const text = pickTextLike(message.content);
|
|
2909
2802
|
if (text.length > 0) {
|
|
2910
2803
|
return text;
|
|
2911
2804
|
}
|
|
@@ -2934,9 +2827,6 @@ function joinReasoningBlocks(blocks) {
|
|
|
2934
2827
|
|
|
2935
2828
|
`);
|
|
2936
2829
|
}
|
|
2937
|
-
function pickTextFromOpenAIContent(value) {
|
|
2938
|
-
return pickTextLike(value);
|
|
2939
|
-
}
|
|
2940
2830
|
function pickTextLike(value) {
|
|
2941
2831
|
if (typeof value === "string") {
|
|
2942
2832
|
return value;
|
|
@@ -3010,83 +2900,81 @@ function createAnthropicCompatibleAdapter(options) {
|
|
|
3010
2900
|
if (hasMCPClients(request.mcpClients)) {
|
|
3011
2901
|
return streamWithMCPToolLoop(options, fetcher, path, request, callbacks);
|
|
3012
2902
|
}
|
|
3013
|
-
|
|
3014
|
-
const response = await fetcher(buildURL(options.baseURL, path), {
|
|
3015
|
-
method: "POST",
|
|
3016
|
-
headers: buildHeaders2(options),
|
|
3017
|
-
body: JSON.stringify(buildAnthropicRequestBody(options, request, {
|
|
3018
|
-
...options.defaultBody,
|
|
3019
|
-
...request.body,
|
|
3020
|
-
model: options.model,
|
|
3021
|
-
system: input.systemPrompt,
|
|
3022
|
-
messages: input.messages,
|
|
3023
|
-
temperature: request.temperature,
|
|
3024
|
-
stream: true
|
|
3025
|
-
})),
|
|
3026
|
-
signal: request.signal
|
|
3027
|
-
});
|
|
3028
|
-
if (!response.ok) {
|
|
3029
|
-
const message = await response.text();
|
|
3030
|
-
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
3031
|
-
}
|
|
3032
|
-
callbacks.onStart?.();
|
|
3033
|
-
let text = "";
|
|
3034
|
-
let usage;
|
|
3035
|
-
let finishReason;
|
|
3036
|
-
await consumeSSE(response, (data) => {
|
|
3037
|
-
if (data === "[DONE]") {
|
|
3038
|
-
return;
|
|
3039
|
-
}
|
|
3040
|
-
const json = safeJSONParse(data);
|
|
3041
|
-
if (!isRecord2(json)) {
|
|
3042
|
-
return;
|
|
3043
|
-
}
|
|
3044
|
-
const delta = pickAnthropicDelta(json);
|
|
3045
|
-
const chunkUsage = pickUsage2(json);
|
|
3046
|
-
const chunkFinishReason = pickFinishReason2(json);
|
|
3047
|
-
usage = preferLatestUsage(usage, chunkUsage);
|
|
3048
|
-
if (chunkFinishReason) {
|
|
3049
|
-
finishReason = chunkFinishReason;
|
|
3050
|
-
}
|
|
3051
|
-
if (delta) {
|
|
3052
|
-
text += delta;
|
|
3053
|
-
callbacks.onToken?.(delta);
|
|
3054
|
-
}
|
|
3055
|
-
if (delta || chunkUsage || chunkFinishReason) {
|
|
3056
|
-
const chunk = {
|
|
3057
|
-
textDelta: delta,
|
|
3058
|
-
raw: json,
|
|
3059
|
-
usage: chunkUsage,
|
|
3060
|
-
finishReason: chunkFinishReason
|
|
3061
|
-
};
|
|
3062
|
-
callbacks.onChunk?.(chunk);
|
|
3063
|
-
}
|
|
3064
|
-
});
|
|
3065
|
-
const out = { text, usage, finishReason };
|
|
3066
|
-
callbacks.onComplete?.(out);
|
|
3067
|
-
return out;
|
|
2903
|
+
return streamPassThrough(options, fetcher, path, request, callbacks);
|
|
3068
2904
|
},
|
|
3069
2905
|
async embed() {
|
|
3070
2906
|
throw new Error("Anthropic does not provide a native embedding API. " + "Use the openai-compatible provider with Voyage AI (https://api.voyageai.com) — " + "Anthropic's recommended embedding solution, which uses the same request format.");
|
|
3071
2907
|
}
|
|
3072
2908
|
};
|
|
3073
2909
|
}
|
|
3074
|
-
async function
|
|
2910
|
+
async function streamPassThrough(options, fetcher, path, request, callbacks) {
|
|
3075
2911
|
const input = resolveAnthropicInput(request);
|
|
3076
|
-
const response = await
|
|
2912
|
+
const response = await sendAnthropicMessage(options, fetcher, path, request, {
|
|
2913
|
+
system: input.systemPrompt,
|
|
2914
|
+
messages: input.messages,
|
|
2915
|
+
stream: true
|
|
2916
|
+
});
|
|
2917
|
+
if (!response.ok) {
|
|
2918
|
+
const message = await response.text();
|
|
2919
|
+
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
2920
|
+
}
|
|
2921
|
+
callbacks.onStart?.();
|
|
2922
|
+
let text = "";
|
|
2923
|
+
let usage;
|
|
2924
|
+
let finishReason;
|
|
2925
|
+
await consumeSSE(response, (data) => {
|
|
2926
|
+
if (data === "[DONE]") {
|
|
2927
|
+
return;
|
|
2928
|
+
}
|
|
2929
|
+
const json = safeJSONParse(data);
|
|
2930
|
+
if (!isRecord2(json)) {
|
|
2931
|
+
return;
|
|
2932
|
+
}
|
|
2933
|
+
const delta = pickAnthropicDelta(json);
|
|
2934
|
+
const chunkUsage = pickUsage2(json);
|
|
2935
|
+
const chunkFinishReason = pickFinishReason2(json);
|
|
2936
|
+
usage = preferLatestUsage(usage, chunkUsage);
|
|
2937
|
+
if (chunkFinishReason) {
|
|
2938
|
+
finishReason = chunkFinishReason;
|
|
2939
|
+
}
|
|
2940
|
+
if (delta) {
|
|
2941
|
+
text += delta;
|
|
2942
|
+
callbacks.onToken?.(delta);
|
|
2943
|
+
}
|
|
2944
|
+
if (delta || chunkUsage || chunkFinishReason) {
|
|
2945
|
+
callbacks.onChunk?.({
|
|
2946
|
+
textDelta: delta,
|
|
2947
|
+
raw: json,
|
|
2948
|
+
usage: chunkUsage,
|
|
2949
|
+
finishReason: chunkFinishReason
|
|
2950
|
+
});
|
|
2951
|
+
}
|
|
2952
|
+
});
|
|
2953
|
+
const out = { text, usage, finishReason };
|
|
2954
|
+
callbacks.onComplete?.(out);
|
|
2955
|
+
return out;
|
|
2956
|
+
}
|
|
2957
|
+
function sendAnthropicMessage(options, fetcher, path, request, body) {
|
|
2958
|
+
return fetcher(buildURL(options.baseURL, path), {
|
|
3077
2959
|
method: "POST",
|
|
3078
2960
|
headers: buildHeaders2(options),
|
|
3079
2961
|
body: JSON.stringify(buildAnthropicRequestBody(options, request, {
|
|
3080
2962
|
...options.defaultBody,
|
|
3081
2963
|
...request.body,
|
|
3082
2964
|
model: options.model,
|
|
3083
|
-
system: input.systemPrompt,
|
|
3084
|
-
messages: input.messages,
|
|
3085
2965
|
temperature: request.temperature,
|
|
3086
|
-
|
|
2966
|
+
...body
|
|
3087
2967
|
})),
|
|
3088
2968
|
signal: request.signal
|
|
3089
2969
|
});
|
|
2970
|
+
}
|
|
2971
|
+
async function completePassThrough(options, fetcher, path, request) {
|
|
2972
|
+
const input = resolveAnthropicInput(request);
|
|
2973
|
+
const response = await sendAnthropicMessage(options, fetcher, path, request, {
|
|
2974
|
+
system: input.systemPrompt,
|
|
2975
|
+
messages: input.messages,
|
|
2976
|
+
stream: false
|
|
2977
|
+
});
|
|
3090
2978
|
if (!response.ok) {
|
|
3091
2979
|
const message = await response.text();
|
|
3092
2980
|
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
@@ -3118,21 +3006,12 @@ async function completeWithMCPToolLoop(options, fetcher, path, request) {
|
|
|
3118
3006
|
for (let round = 1;round <= maxToolRounds + 1; round += 1) {
|
|
3119
3007
|
const mcpToolset = await resolveMCPToolset(request.mcpClients);
|
|
3120
3008
|
const tools = toAnthropicTools(toProviderFunctionTools(mcpToolset));
|
|
3121
|
-
const response = await
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
model: options.model,
|
|
3128
|
-
system: input.systemPrompt,
|
|
3129
|
-
messages,
|
|
3130
|
-
temperature: request.temperature,
|
|
3131
|
-
tools,
|
|
3132
|
-
tool_choice: toAnthropicToolChoice(request.toolChoice),
|
|
3133
|
-
stream: false
|
|
3134
|
-
})),
|
|
3135
|
-
signal: request.signal
|
|
3009
|
+
const response = await sendAnthropicMessage(options, fetcher, path, request, {
|
|
3010
|
+
system: input.systemPrompt,
|
|
3011
|
+
messages,
|
|
3012
|
+
tools,
|
|
3013
|
+
tool_choice: toAnthropicToolChoice(request.toolChoice),
|
|
3014
|
+
stream: false
|
|
3136
3015
|
});
|
|
3137
3016
|
if (!response.ok) {
|
|
3138
3017
|
const message = await response.text();
|
|
@@ -3208,21 +3087,12 @@ async function streamWithMCPToolLoop(options, fetcher, path, request, callbacks)
|
|
|
3208
3087
|
for (let round = 1;round <= maxToolRounds + 1; round += 1) {
|
|
3209
3088
|
const mcpToolset = await resolveMCPToolset(request.mcpClients);
|
|
3210
3089
|
const tools = toAnthropicTools(toProviderFunctionTools(mcpToolset));
|
|
3211
|
-
const response = await
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
model: options.model,
|
|
3218
|
-
system: input.systemPrompt,
|
|
3219
|
-
messages,
|
|
3220
|
-
temperature: request.temperature,
|
|
3221
|
-
tools,
|
|
3222
|
-
tool_choice: toAnthropicToolChoice(request.toolChoice),
|
|
3223
|
-
stream: true
|
|
3224
|
-
})),
|
|
3225
|
-
signal: request.signal
|
|
3090
|
+
const response = await sendAnthropicMessage(options, fetcher, path, request, {
|
|
3091
|
+
system: input.systemPrompt,
|
|
3092
|
+
messages,
|
|
3093
|
+
tools,
|
|
3094
|
+
tool_choice: toAnthropicToolChoice(request.toolChoice),
|
|
3095
|
+
stream: true
|
|
3226
3096
|
});
|
|
3227
3097
|
if (!response.ok) {
|
|
3228
3098
|
const message = await response.text();
|
|
@@ -3766,39 +3636,10 @@ function buildProviderOptions(config) {
|
|
|
3766
3636
|
return {
|
|
3767
3637
|
model: config.model,
|
|
3768
3638
|
...transport,
|
|
3769
|
-
...config.options
|
|
3639
|
+
...config.options
|
|
3770
3640
|
};
|
|
3771
3641
|
}
|
|
3772
3642
|
|
|
3773
|
-
// src/utils/debug-colors.ts
|
|
3774
|
-
var ANSI = {
|
|
3775
|
-
reset: "\x1B[0m",
|
|
3776
|
-
bold: "\x1B[1m",
|
|
3777
|
-
cyan: "\x1B[36m",
|
|
3778
|
-
yellow: "\x1B[33m",
|
|
3779
|
-
green: "\x1B[32m",
|
|
3780
|
-
red: "\x1B[31m",
|
|
3781
|
-
dim: "\x1B[2m"
|
|
3782
|
-
};
|
|
3783
|
-
function color(config, text, tone) {
|
|
3784
|
-
if (!config.colors) {
|
|
3785
|
-
return text;
|
|
3786
|
-
}
|
|
3787
|
-
return `${ANSI[tone]}${text}${ANSI.reset}`;
|
|
3788
|
-
}
|
|
3789
|
-
function dim(config, text) {
|
|
3790
|
-
if (!config.colors) {
|
|
3791
|
-
return text;
|
|
3792
|
-
}
|
|
3793
|
-
return `${ANSI.dim}${text}${ANSI.reset}`;
|
|
3794
|
-
}
|
|
3795
|
-
function title(config, text) {
|
|
3796
|
-
if (!config.colors) {
|
|
3797
|
-
return text;
|
|
3798
|
-
}
|
|
3799
|
-
return `${ANSI.bold}${text}${ANSI.reset}`;
|
|
3800
|
-
}
|
|
3801
|
-
|
|
3802
3643
|
// src/outdent.ts
|
|
3803
3644
|
var DEFAULT_OPTIONS = {
|
|
3804
3645
|
trimLeadingNewline: true,
|
|
@@ -3936,132 +3777,213 @@ function createOutdent(options = {}) {
|
|
|
3936
3777
|
return outdent;
|
|
3937
3778
|
}
|
|
3938
3779
|
|
|
3939
|
-
// src/generate-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3780
|
+
// src/generate-tool-timeout.ts
|
|
3781
|
+
function withToolTimeout(client, toolTimeoutMs) {
|
|
3782
|
+
return {
|
|
3783
|
+
id: client.id,
|
|
3784
|
+
listTools: client.listTools.bind(client),
|
|
3785
|
+
close: client.close?.bind(client),
|
|
3786
|
+
async callTool(params) {
|
|
3787
|
+
let timeoutId;
|
|
3788
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
3789
|
+
timeoutId = setTimeout(() => reject(new Error(`Tool call timed out after ${toolTimeoutMs}ms`)), toolTimeoutMs);
|
|
3790
|
+
});
|
|
3791
|
+
try {
|
|
3792
|
+
return await Promise.race([client.callTool(params), timeoutPromise]);
|
|
3793
|
+
} finally {
|
|
3794
|
+
clearTimeout(timeoutId);
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
};
|
|
3798
|
+
}
|
|
3799
|
+
function applyToolTimeout(clients, toolTimeoutMs) {
|
|
3800
|
+
return clients.map((client) => withToolTimeout(client, toolTimeoutMs));
|
|
3801
|
+
}
|
|
3802
|
+
// src/generate-output.ts
|
|
3946
3803
|
var RE_THINK_TAGS = /<\/?think\s*>/gi;
|
|
3947
|
-
function
|
|
3948
|
-
const
|
|
3949
|
-
|
|
3804
|
+
function normalizeModelOutput(text, dedicatedReasoning, reasoningBlocks) {
|
|
3805
|
+
const sanitized = sanitizeThink(text);
|
|
3806
|
+
const visibleText = stripThinkBlocks(text, sanitized.thinkBlocks);
|
|
3807
|
+
const reasoning = joinReasoningSegments([
|
|
3808
|
+
dedicatedReasoning,
|
|
3809
|
+
...sanitized.thinkBlocks.map((block) => block.content)
|
|
3810
|
+
]);
|
|
3811
|
+
return {
|
|
3812
|
+
text: visibleText,
|
|
3813
|
+
reasoning,
|
|
3814
|
+
reasoningBlocks: normalizeReasoningBlocks(reasoningBlocks),
|
|
3815
|
+
thinkBlocks: sanitized.thinkBlocks,
|
|
3816
|
+
parseSource: composeParseSource(visibleText, reasoning)
|
|
3817
|
+
};
|
|
3950
3818
|
}
|
|
3951
|
-
function
|
|
3952
|
-
if (
|
|
3953
|
-
return
|
|
3954
|
-
prompt: value
|
|
3955
|
-
};
|
|
3956
|
-
}
|
|
3957
|
-
if (isPromptResolver(value)) {
|
|
3958
|
-
return normalizePromptPayload(value.resolvePrompt(_context));
|
|
3819
|
+
function normalizeReasoningBlocks(blocks) {
|
|
3820
|
+
if (!Array.isArray(blocks)) {
|
|
3821
|
+
return;
|
|
3959
3822
|
}
|
|
3960
|
-
|
|
3823
|
+
const normalized = blocks.map((block) => ({
|
|
3824
|
+
turnIndex: block.turnIndex,
|
|
3825
|
+
text: block.text.replace(RE_THINK_TAGS, "").trim()
|
|
3826
|
+
})).filter((block) => Number.isFinite(block.turnIndex) && block.text.length > 0);
|
|
3827
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
3961
3828
|
}
|
|
3962
|
-
function
|
|
3963
|
-
const
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
throw new Error("Structured prompt payload must include a non-empty prompt or messages.");
|
|
3829
|
+
function appendReasoningBlock(blocks, transition) {
|
|
3830
|
+
const text = transition.reasoningText?.replace(RE_THINK_TAGS, "").trim();
|
|
3831
|
+
if (!text) {
|
|
3832
|
+
return blocks;
|
|
3967
3833
|
}
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
systemPrompt: typeof value.systemPrompt === "string" ? value.systemPrompt : undefined,
|
|
3971
|
-
messages: messages && messages.length > 0 ? messages.map((message) => ({ ...message })) : undefined
|
|
3972
|
-
};
|
|
3834
|
+
const next = [...blocks ?? [], { turnIndex: transition.turnIndex, text }];
|
|
3835
|
+
return normalizeReasoningBlocks(next);
|
|
3973
3836
|
}
|
|
3974
|
-
function
|
|
3975
|
-
if (
|
|
3976
|
-
return
|
|
3837
|
+
function composeParseSource(text, reasoning) {
|
|
3838
|
+
if (typeof reasoning !== "string" || reasoning.length === 0) {
|
|
3839
|
+
return text;
|
|
3977
3840
|
}
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
content: typeof message.content === "string" ? sharedOutdent.string(message.content) : message.content
|
|
3984
|
-
}))
|
|
3985
|
-
};
|
|
3841
|
+
const sanitized = reasoning.replace(RE_THINK_TAGS, "");
|
|
3842
|
+
if (sanitized.length === 0) {
|
|
3843
|
+
return text;
|
|
3844
|
+
}
|
|
3845
|
+
return `<think>${sanitized}</think>${text}`;
|
|
3986
3846
|
}
|
|
3987
|
-
function
|
|
3988
|
-
|
|
3989
|
-
|
|
3847
|
+
function aggregateUsage(attempts) {
|
|
3848
|
+
let usage;
|
|
3849
|
+
for (const attempt of attempts) {
|
|
3850
|
+
usage = mergeUsage2(usage, attempt.usage);
|
|
3990
3851
|
}
|
|
3991
|
-
return
|
|
3852
|
+
return usage;
|
|
3992
3853
|
}
|
|
3993
|
-
function
|
|
3994
|
-
|
|
3995
|
-
if (prompts.length === 0) {
|
|
3854
|
+
function mergeUsage2(base, next) {
|
|
3855
|
+
if (!base && !next) {
|
|
3996
3856
|
return;
|
|
3997
3857
|
}
|
|
3998
|
-
return
|
|
3858
|
+
return {
|
|
3859
|
+
inputTokens: (base?.inputTokens ?? 0) + (next?.inputTokens ?? 0),
|
|
3860
|
+
outputTokens: (base?.outputTokens ?? 0) + (next?.outputTokens ?? 0),
|
|
3861
|
+
totalTokens: (base?.totalTokens ?? 0) + (next?.totalTokens ?? 0),
|
|
3862
|
+
cost: (base?.cost ?? 0) + (next?.cost ?? 0)
|
|
3863
|
+
};
|
|
3864
|
+
}
|
|
3865
|
+
function joinReasoningSegments(parts) {
|
|
3866
|
+
return parts.map((value) => value?.trim()).filter((value) => Boolean(value)).join(`
|
|
3999
3867
|
|
|
4000
3868
|
`);
|
|
4001
3869
|
}
|
|
4002
|
-
function
|
|
4003
|
-
if (
|
|
4004
|
-
return
|
|
4005
|
-
enabled: option
|
|
4006
|
-
};
|
|
3870
|
+
function stripThinkBlocks(text, thinkBlocks) {
|
|
3871
|
+
if (thinkBlocks.length === 0) {
|
|
3872
|
+
return text;
|
|
4007
3873
|
}
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
3874
|
+
let output = "";
|
|
3875
|
+
let cursor = 0;
|
|
3876
|
+
for (const block of thinkBlocks) {
|
|
3877
|
+
output += text.slice(cursor, block.start);
|
|
3878
|
+
cursor = block.end;
|
|
4012
3879
|
}
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
onData: option.onData,
|
|
4016
|
-
onTurnTransition: option.onTurnTransition,
|
|
4017
|
-
to: option.to
|
|
4018
|
-
};
|
|
3880
|
+
output += text.slice(cursor);
|
|
3881
|
+
return output;
|
|
4019
3882
|
}
|
|
4020
|
-
function
|
|
4021
|
-
|
|
4022
|
-
return
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
verbose: false,
|
|
4026
|
-
logger: (line) => console.log(line)
|
|
4027
|
-
};
|
|
3883
|
+
function toStreamDataFingerprint(value) {
|
|
3884
|
+
try {
|
|
3885
|
+
return JSON.stringify(value);
|
|
3886
|
+
} catch {
|
|
3887
|
+
return "__unserializable__";
|
|
4028
3888
|
}
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
3889
|
+
}
|
|
3890
|
+
|
|
3891
|
+
// src/utils/debug-colors.ts
|
|
3892
|
+
var ANSI = {
|
|
3893
|
+
reset: "\x1B[0m",
|
|
3894
|
+
bold: "\x1B[1m",
|
|
3895
|
+
cyan: "\x1B[36m",
|
|
3896
|
+
yellow: "\x1B[33m",
|
|
3897
|
+
green: "\x1B[32m",
|
|
3898
|
+
red: "\x1B[31m",
|
|
3899
|
+
dim: "\x1B[2m"
|
|
3900
|
+
};
|
|
3901
|
+
function color(config, text, tone) {
|
|
3902
|
+
if (!config.colors) {
|
|
3903
|
+
return text;
|
|
4036
3904
|
}
|
|
4037
|
-
return {
|
|
4038
|
-
enabled: option.enabled ?? true,
|
|
4039
|
-
colors: option.colors ?? true,
|
|
4040
|
-
verbose: option.verbose ?? false,
|
|
4041
|
-
logger: option.logger ?? ((line) => console.log(line))
|
|
4042
|
-
};
|
|
3905
|
+
return `${ANSI[tone]}${text}${ANSI.reset}`;
|
|
4043
3906
|
}
|
|
4044
|
-
function
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
async callTool(params) {
|
|
4050
|
-
let timeoutId;
|
|
4051
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
4052
|
-
timeoutId = setTimeout(() => reject(new Error(`Tool call timed out after ${toolTimeoutMs}ms`)), toolTimeoutMs);
|
|
4053
|
-
});
|
|
4054
|
-
try {
|
|
4055
|
-
return await Promise.race([client.callTool(params), timeoutPromise]);
|
|
4056
|
-
} finally {
|
|
4057
|
-
clearTimeout(timeoutId);
|
|
4058
|
-
}
|
|
4059
|
-
}
|
|
4060
|
-
};
|
|
3907
|
+
function dim(config, text) {
|
|
3908
|
+
if (!config.colors) {
|
|
3909
|
+
return text;
|
|
3910
|
+
}
|
|
3911
|
+
return `${ANSI.dim}${text}${ANSI.reset}`;
|
|
4061
3912
|
}
|
|
4062
|
-
function
|
|
4063
|
-
|
|
3913
|
+
function title(config, text) {
|
|
3914
|
+
if (!config.colors) {
|
|
3915
|
+
return text;
|
|
3916
|
+
}
|
|
3917
|
+
return `${ANSI.bold}${text}${ANSI.reset}`;
|
|
4064
3918
|
}
|
|
3919
|
+
|
|
3920
|
+
// src/generate-debug.ts
|
|
3921
|
+
function emitDebugRequest(config, input) {
|
|
3922
|
+
const requestBody = input.requestPayload.body !== undefined ? JSON.stringify(input.requestPayload.body, null, 2) : "(none)";
|
|
3923
|
+
const requestMessages = input.requestPayload.messages !== undefined ? JSON.stringify(input.requestPayload.messages, null, 2) : "(none)";
|
|
3924
|
+
const lines = [
|
|
3925
|
+
color(config, title(config, [
|
|
3926
|
+
`[${input.label}][request]`,
|
|
3927
|
+
`attempt=${input.attempt}`,
|
|
3928
|
+
`selfHealEnabled=${input.selfHealEnabled}`,
|
|
3929
|
+
`selfHealAttempt=${input.selfHealAttempt}`
|
|
3930
|
+
].join(" ")), "cyan"),
|
|
3931
|
+
dim(config, [
|
|
3932
|
+
`provider=${input.provider ?? "unknown"}`,
|
|
3933
|
+
`model=${input.model ?? "unknown"}`,
|
|
3934
|
+
`stream=${input.stream}`
|
|
3935
|
+
].join(" ")),
|
|
3936
|
+
color(config, "prompt:", "yellow"),
|
|
3937
|
+
input.requestPayload.prompt ?? "(none)",
|
|
3938
|
+
color(config, "messages:", "yellow"),
|
|
3939
|
+
requestMessages,
|
|
3940
|
+
color(config, "systemPrompt:", "yellow"),
|
|
3941
|
+
input.requestPayload.systemPrompt ?? "(none)",
|
|
3942
|
+
color(config, "request.body:", "yellow"),
|
|
3943
|
+
requestBody
|
|
3944
|
+
];
|
|
3945
|
+
emitDebug(config, lines.join(`
|
|
3946
|
+
`));
|
|
3947
|
+
}
|
|
3948
|
+
function emitDebugResponse(config, input) {
|
|
3949
|
+
const text = input.text.length > 0 ? input.text : "(none)";
|
|
3950
|
+
const reasoning = input.reasoning.length > 0 ? input.reasoning : "(none)";
|
|
3951
|
+
const metadata = [
|
|
3952
|
+
`via=${input.via}`,
|
|
3953
|
+
`textChars=${input.text.length}`,
|
|
3954
|
+
`reasoningChars=${input.reasoning.length}`
|
|
3955
|
+
];
|
|
3956
|
+
if (config.verbose) {
|
|
3957
|
+
metadata.push(`parseSourceChars=${input.parseSource.length}`);
|
|
3958
|
+
}
|
|
3959
|
+
metadata.push(`finishReason=${input.finishReason ?? "unknown"}`, `usage=${JSON.stringify(input.usage ?? {})}`);
|
|
3960
|
+
const lines = [
|
|
3961
|
+
color(config, title(config, [
|
|
3962
|
+
`[${input.label}][response]`,
|
|
3963
|
+
`attempt=${input.attempt}`,
|
|
3964
|
+
`selfHealEnabled=${input.selfHealEnabled}`,
|
|
3965
|
+
`selfHealAttempt=${input.selfHealAttempt}`
|
|
3966
|
+
].join(" ")), "green"),
|
|
3967
|
+
dim(config, metadata.join(" ")),
|
|
3968
|
+
color(config, "text:", "yellow"),
|
|
3969
|
+
text,
|
|
3970
|
+
color(config, "reasoning:", "yellow"),
|
|
3971
|
+
reasoning
|
|
3972
|
+
];
|
|
3973
|
+
if (config.verbose) {
|
|
3974
|
+
lines.push(color(config, "parseSource:", "yellow"), input.parseSource);
|
|
3975
|
+
}
|
|
3976
|
+
emitDebug(config, lines.join(`
|
|
3977
|
+
`));
|
|
3978
|
+
}
|
|
3979
|
+
function emitDebug(config, message) {
|
|
3980
|
+
if (!config.enabled) {
|
|
3981
|
+
return;
|
|
3982
|
+
}
|
|
3983
|
+
config.logger(message);
|
|
3984
|
+
}
|
|
3985
|
+
|
|
3986
|
+
// src/generate-model-call.ts
|
|
4065
3987
|
async function callModel(adapter, options) {
|
|
4066
3988
|
const requestSignal = options.request?.signal ?? (options.timeout?.request !== undefined ? AbortSignal.timeout(options.timeout.request) : undefined);
|
|
4067
3989
|
const requestPayload = {
|
|
@@ -4281,67 +4203,115 @@ async function callModel(adapter, options) {
|
|
|
4281
4203
|
reasoningBlocks: normalized.reasoningBlocks
|
|
4282
4204
|
};
|
|
4283
4205
|
}
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4206
|
+
|
|
4207
|
+
// src/generate-shared.ts
|
|
4208
|
+
var sharedOutdent = createOutdent({
|
|
4209
|
+
trimLeadingNewline: true,
|
|
4210
|
+
trimTrailingNewline: true,
|
|
4211
|
+
newline: `
|
|
4212
|
+
`
|
|
4213
|
+
});
|
|
4214
|
+
function resolvePrompt(prompt, context) {
|
|
4215
|
+
const resolved = typeof prompt === "function" ? prompt(context) : prompt;
|
|
4216
|
+
return normalizePromptValue(resolved, context);
|
|
4217
|
+
}
|
|
4218
|
+
function normalizePromptValue(value, _context) {
|
|
4219
|
+
if (typeof value === "string") {
|
|
4220
|
+
return {
|
|
4221
|
+
prompt: value
|
|
4222
|
+
};
|
|
4223
|
+
}
|
|
4224
|
+
if (isPromptResolver(value)) {
|
|
4225
|
+
return normalizePromptPayload(value.resolvePrompt(_context));
|
|
4226
|
+
}
|
|
4227
|
+
return normalizePromptPayload(value);
|
|
4228
|
+
}
|
|
4229
|
+
function normalizePromptPayload(value) {
|
|
4230
|
+
const prompt = typeof value.prompt === "string" ? value.prompt : undefined;
|
|
4231
|
+
const messages = Array.isArray(value.messages) ? value.messages.filter(isLLMMessage) : undefined;
|
|
4232
|
+
if ((!prompt || prompt.trim().length === 0) && (!messages || messages.length === 0)) {
|
|
4233
|
+
throw new Error("Structured prompt payload must include a non-empty prompt or messages.");
|
|
4234
|
+
}
|
|
4291
4235
|
return {
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
thinkBlocks: sanitized.thinkBlocks,
|
|
4296
|
-
parseSource: composeParseSource(visibleText, reasoning)
|
|
4236
|
+
prompt,
|
|
4237
|
+
systemPrompt: typeof value.systemPrompt === "string" ? value.systemPrompt : undefined,
|
|
4238
|
+
messages: messages && messages.length > 0 ? messages.map((message) => ({ ...message })) : undefined
|
|
4297
4239
|
};
|
|
4298
4240
|
}
|
|
4299
|
-
function
|
|
4300
|
-
if (!
|
|
4301
|
-
return;
|
|
4241
|
+
function applyPromptOutdent(payload, enabled) {
|
|
4242
|
+
if (!enabled) {
|
|
4243
|
+
return payload;
|
|
4302
4244
|
}
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4245
|
+
return {
|
|
4246
|
+
prompt: typeof payload.prompt === "string" ? sharedOutdent.string(payload.prompt) : undefined,
|
|
4247
|
+
systemPrompt: applyOutdentToOptionalPrompt(payload.systemPrompt, enabled),
|
|
4248
|
+
messages: payload.messages?.map((message) => ({
|
|
4249
|
+
...message,
|
|
4250
|
+
content: typeof message.content === "string" ? sharedOutdent.string(message.content) : message.content
|
|
4251
|
+
}))
|
|
4252
|
+
};
|
|
4308
4253
|
}
|
|
4309
|
-
function
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
return blocks;
|
|
4254
|
+
function applyOutdentToOptionalPrompt(value, enabled) {
|
|
4255
|
+
if (!enabled || typeof value !== "string") {
|
|
4256
|
+
return value;
|
|
4313
4257
|
}
|
|
4314
|
-
|
|
4315
|
-
return normalizeReasoningBlocks(next);
|
|
4258
|
+
return sharedOutdent.string(value);
|
|
4316
4259
|
}
|
|
4317
|
-
function
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
const sanitized = reasoning.replace(RE_THINK_TAGS, "");
|
|
4322
|
-
if (sanitized.length === 0) {
|
|
4323
|
-
return text;
|
|
4260
|
+
function mergeSystemPrompts(primary, secondary) {
|
|
4261
|
+
const prompts = [primary, secondary].map((value) => value?.trim()).filter((value) => Boolean(value));
|
|
4262
|
+
if (prompts.length === 0) {
|
|
4263
|
+
return;
|
|
4324
4264
|
}
|
|
4325
|
-
return
|
|
4265
|
+
return prompts.join(`
|
|
4266
|
+
|
|
4267
|
+
`);
|
|
4326
4268
|
}
|
|
4327
|
-
function
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4269
|
+
function normalizeStreamConfig(option) {
|
|
4270
|
+
if (typeof option === "boolean") {
|
|
4271
|
+
return {
|
|
4272
|
+
enabled: option
|
|
4273
|
+
};
|
|
4274
|
+
}
|
|
4275
|
+
if (!option) {
|
|
4276
|
+
return {
|
|
4277
|
+
enabled: false
|
|
4278
|
+
};
|
|
4331
4279
|
}
|
|
4332
|
-
return
|
|
4280
|
+
return {
|
|
4281
|
+
enabled: option.enabled ?? true,
|
|
4282
|
+
onData: option.onData,
|
|
4283
|
+
onTurnTransition: option.onTurnTransition,
|
|
4284
|
+
to: option.to
|
|
4285
|
+
};
|
|
4333
4286
|
}
|
|
4334
|
-
function
|
|
4335
|
-
if (
|
|
4336
|
-
return
|
|
4287
|
+
function normalizeDebugConfig(option) {
|
|
4288
|
+
if (typeof option === "boolean") {
|
|
4289
|
+
return {
|
|
4290
|
+
enabled: option,
|
|
4291
|
+
colors: true,
|
|
4292
|
+
verbose: false,
|
|
4293
|
+
logger: defaultDebugLogger
|
|
4294
|
+
};
|
|
4295
|
+
}
|
|
4296
|
+
if (!option) {
|
|
4297
|
+
return {
|
|
4298
|
+
enabled: false,
|
|
4299
|
+
colors: true,
|
|
4300
|
+
verbose: false,
|
|
4301
|
+
logger: defaultDebugLogger
|
|
4302
|
+
};
|
|
4337
4303
|
}
|
|
4338
4304
|
return {
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4305
|
+
enabled: option.enabled ?? true,
|
|
4306
|
+
colors: option.colors ?? true,
|
|
4307
|
+
verbose: option.verbose ?? false,
|
|
4308
|
+
logger: option.logger ?? defaultDebugLogger
|
|
4343
4309
|
};
|
|
4344
4310
|
}
|
|
4311
|
+
function defaultDebugLogger(line) {
|
|
4312
|
+
const { log } = globalThis.console;
|
|
4313
|
+
log(line);
|
|
4314
|
+
}
|
|
4345
4315
|
function isPromptResolver(value) {
|
|
4346
4316
|
return typeof value === "object" && value !== null && "resolvePrompt" in value && typeof value.resolvePrompt === "function";
|
|
4347
4317
|
}
|
|
@@ -4355,95 +4325,6 @@ function isLLMMessage(value) {
|
|
|
4355
4325
|
}
|
|
4356
4326
|
return "content" in candidate;
|
|
4357
4327
|
}
|
|
4358
|
-
function joinReasoningSegments(parts) {
|
|
4359
|
-
return parts.map((value) => value?.trim()).filter((value) => Boolean(value)).join(`
|
|
4360
|
-
|
|
4361
|
-
`);
|
|
4362
|
-
}
|
|
4363
|
-
function stripThinkBlocks(text, thinkBlocks) {
|
|
4364
|
-
if (thinkBlocks.length === 0) {
|
|
4365
|
-
return text;
|
|
4366
|
-
}
|
|
4367
|
-
let output = "";
|
|
4368
|
-
let cursor = 0;
|
|
4369
|
-
for (const block of thinkBlocks) {
|
|
4370
|
-
output += text.slice(cursor, block.start);
|
|
4371
|
-
cursor = block.end;
|
|
4372
|
-
}
|
|
4373
|
-
output += text.slice(cursor);
|
|
4374
|
-
return output;
|
|
4375
|
-
}
|
|
4376
|
-
function toStreamDataFingerprint(value) {
|
|
4377
|
-
try {
|
|
4378
|
-
return JSON.stringify(value);
|
|
4379
|
-
} catch {
|
|
4380
|
-
return "__unserializable__";
|
|
4381
|
-
}
|
|
4382
|
-
}
|
|
4383
|
-
function emitDebugRequest(config, input) {
|
|
4384
|
-
const requestBody = input.requestPayload.body !== undefined ? JSON.stringify(input.requestPayload.body, null, 2) : "(none)";
|
|
4385
|
-
const requestMessages = input.requestPayload.messages !== undefined ? JSON.stringify(input.requestPayload.messages, null, 2) : "(none)";
|
|
4386
|
-
const lines = [
|
|
4387
|
-
color(config, title(config, [
|
|
4388
|
-
`[${input.label}][request]`,
|
|
4389
|
-
`attempt=${input.attempt}`,
|
|
4390
|
-
`selfHealEnabled=${input.selfHealEnabled}`,
|
|
4391
|
-
`selfHealAttempt=${input.selfHealAttempt}`
|
|
4392
|
-
].join(" ")), "cyan"),
|
|
4393
|
-
dim(config, [
|
|
4394
|
-
`provider=${input.provider ?? "unknown"}`,
|
|
4395
|
-
`model=${input.model ?? "unknown"}`,
|
|
4396
|
-
`stream=${input.stream}`
|
|
4397
|
-
].join(" ")),
|
|
4398
|
-
color(config, "prompt:", "yellow"),
|
|
4399
|
-
input.requestPayload.prompt ?? "(none)",
|
|
4400
|
-
color(config, "messages:", "yellow"),
|
|
4401
|
-
requestMessages,
|
|
4402
|
-
color(config, "systemPrompt:", "yellow"),
|
|
4403
|
-
input.requestPayload.systemPrompt ?? "(none)",
|
|
4404
|
-
color(config, "request.body:", "yellow"),
|
|
4405
|
-
requestBody
|
|
4406
|
-
];
|
|
4407
|
-
emitDebug(config, lines.join(`
|
|
4408
|
-
`));
|
|
4409
|
-
}
|
|
4410
|
-
function emitDebugResponse(config, input) {
|
|
4411
|
-
const text = input.text.length > 0 ? input.text : "(none)";
|
|
4412
|
-
const reasoning = input.reasoning.length > 0 ? input.reasoning : "(none)";
|
|
4413
|
-
const metadata = [
|
|
4414
|
-
`via=${input.via}`,
|
|
4415
|
-
`textChars=${input.text.length}`,
|
|
4416
|
-
`reasoningChars=${input.reasoning.length}`
|
|
4417
|
-
];
|
|
4418
|
-
if (config.verbose) {
|
|
4419
|
-
metadata.push(`parseSourceChars=${input.parseSource.length}`);
|
|
4420
|
-
}
|
|
4421
|
-
metadata.push(`finishReason=${input.finishReason ?? "unknown"}`, `usage=${JSON.stringify(input.usage ?? {})}`);
|
|
4422
|
-
const lines = [
|
|
4423
|
-
color(config, title(config, [
|
|
4424
|
-
`[${input.label}][response]`,
|
|
4425
|
-
`attempt=${input.attempt}`,
|
|
4426
|
-
`selfHealEnabled=${input.selfHealEnabled}`,
|
|
4427
|
-
`selfHealAttempt=${input.selfHealAttempt}`
|
|
4428
|
-
].join(" ")), "green"),
|
|
4429
|
-
dim(config, metadata.join(" ")),
|
|
4430
|
-
color(config, "text:", "yellow"),
|
|
4431
|
-
text,
|
|
4432
|
-
color(config, "reasoning:", "yellow"),
|
|
4433
|
-
reasoning
|
|
4434
|
-
];
|
|
4435
|
-
if (config.verbose) {
|
|
4436
|
-
lines.push(color(config, "parseSource:", "yellow"), input.parseSource);
|
|
4437
|
-
}
|
|
4438
|
-
emitDebug(config, lines.join(`
|
|
4439
|
-
`));
|
|
4440
|
-
}
|
|
4441
|
-
function emitDebug(config, message) {
|
|
4442
|
-
if (!config.enabled) {
|
|
4443
|
-
return;
|
|
4444
|
-
}
|
|
4445
|
-
config.logger(message);
|
|
4446
|
-
}
|
|
4447
4328
|
|
|
4448
4329
|
// src/generate.ts
|
|
4449
4330
|
async function generate(adapter, promptOrOptions, callOptions) {
|
|
@@ -4519,7 +4400,7 @@ function normalizeGenerateInput(promptOrOptions, callOptions) {
|
|
|
4519
4400
|
throw new Error("Missing prompt in generate(adapter, prompt, options?) call.");
|
|
4520
4401
|
}
|
|
4521
4402
|
return {
|
|
4522
|
-
...callOptions
|
|
4403
|
+
...callOptions,
|
|
4523
4404
|
prompt: promptOrOptions
|
|
4524
4405
|
};
|
|
4525
4406
|
}
|
|
@@ -4545,9 +4426,6 @@ function prepareGeneratePromptPayload(payload, systemPrompt) {
|
|
|
4545
4426
|
};
|
|
4546
4427
|
}
|
|
4547
4428
|
|
|
4548
|
-
// src/structured.ts
|
|
4549
|
-
var import_jsonrepair3 = require("jsonrepair");
|
|
4550
|
-
|
|
4551
4429
|
// src/parse.ts
|
|
4552
4430
|
var import_jsonrepair2 = require("jsonrepair");
|
|
4553
4431
|
function parseLLMOutput(output, schema, options = {}) {
|
|
@@ -4847,6 +4725,80 @@ function formatZodIssues(issues) {
|
|
|
4847
4725
|
`);
|
|
4848
4726
|
}
|
|
4849
4727
|
|
|
4728
|
+
// src/structured-streaming.ts
|
|
4729
|
+
var import_jsonrepair3 = require("jsonrepair");
|
|
4730
|
+
function parseStreamingStructuredData(parseSource) {
|
|
4731
|
+
const sanitized = sanitizeThink(parseSource);
|
|
4732
|
+
const start = findFirstJsonRootStart(sanitized.visibleText);
|
|
4733
|
+
if (start < 0) {
|
|
4734
|
+
return null;
|
|
4735
|
+
}
|
|
4736
|
+
const candidate = sanitized.visibleText.slice(start).trim();
|
|
4737
|
+
if (!candidate) {
|
|
4738
|
+
return null;
|
|
4739
|
+
}
|
|
4740
|
+
try {
|
|
4741
|
+
const repaired = import_jsonrepair3.jsonrepair(candidate);
|
|
4742
|
+
const parsed = JSON.parse(repaired);
|
|
4743
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
4744
|
+
return null;
|
|
4745
|
+
}
|
|
4746
|
+
return parsed;
|
|
4747
|
+
} catch {
|
|
4748
|
+
return null;
|
|
4749
|
+
}
|
|
4750
|
+
}
|
|
4751
|
+
function findFirstJsonRootStart(input) {
|
|
4752
|
+
const unquotedRootStart = findFirstUnquotedJsonRootStart(input);
|
|
4753
|
+
if (unquotedRootStart >= 0) {
|
|
4754
|
+
return unquotedRootStart;
|
|
4755
|
+
}
|
|
4756
|
+
return findFirstRawJsonRootStart(input);
|
|
4757
|
+
}
|
|
4758
|
+
function findFirstUnquotedJsonRootStart(input) {
|
|
4759
|
+
let inString = false;
|
|
4760
|
+
let escaped = false;
|
|
4761
|
+
for (let index = 0;index < input.length; index += 1) {
|
|
4762
|
+
const char = input[index];
|
|
4763
|
+
if (!char) {
|
|
4764
|
+
continue;
|
|
4765
|
+
}
|
|
4766
|
+
if (inString) {
|
|
4767
|
+
if (escaped) {
|
|
4768
|
+
escaped = false;
|
|
4769
|
+
continue;
|
|
4770
|
+
}
|
|
4771
|
+
if (char === "\\") {
|
|
4772
|
+
escaped = true;
|
|
4773
|
+
continue;
|
|
4774
|
+
}
|
|
4775
|
+
if (char === '"') {
|
|
4776
|
+
inString = false;
|
|
4777
|
+
}
|
|
4778
|
+
continue;
|
|
4779
|
+
}
|
|
4780
|
+
if (char === '"') {
|
|
4781
|
+
inString = true;
|
|
4782
|
+
continue;
|
|
4783
|
+
}
|
|
4784
|
+
if (char === "{" || char === "[") {
|
|
4785
|
+
return index;
|
|
4786
|
+
}
|
|
4787
|
+
}
|
|
4788
|
+
return -1;
|
|
4789
|
+
}
|
|
4790
|
+
function findFirstRawJsonRootStart(input) {
|
|
4791
|
+
const objectStart = input.indexOf("{");
|
|
4792
|
+
const arrayStart = input.indexOf("[");
|
|
4793
|
+
if (objectStart < 0) {
|
|
4794
|
+
return arrayStart;
|
|
4795
|
+
}
|
|
4796
|
+
if (arrayStart < 0) {
|
|
4797
|
+
return objectStart;
|
|
4798
|
+
}
|
|
4799
|
+
return Math.min(objectStart, arrayStart);
|
|
4800
|
+
}
|
|
4801
|
+
|
|
4850
4802
|
// src/structured.ts
|
|
4851
4803
|
class StructuredParseError extends Error {
|
|
4852
4804
|
name = "StructuredParseError";
|
|
@@ -5084,7 +5036,7 @@ function normalizeStructuredInput(schemaOrOptions, promptInput, callOptions) {
|
|
|
5084
5036
|
throw new Error("Missing prompt in structured(adapter, schema, prompt, options?) call.");
|
|
5085
5037
|
}
|
|
5086
5038
|
return {
|
|
5087
|
-
...callOptions
|
|
5039
|
+
...callOptions,
|
|
5088
5040
|
schema: schemaOrOptions,
|
|
5089
5041
|
prompt: promptInput
|
|
5090
5042
|
};
|
|
@@ -5355,67 +5307,6 @@ async function callModel2(adapter, options) {
|
|
|
5355
5307
|
debugLabel: "structured"
|
|
5356
5308
|
});
|
|
5357
5309
|
}
|
|
5358
|
-
function parseStreamingStructuredData(parseSource) {
|
|
5359
|
-
const sanitized = sanitizeThink(parseSource);
|
|
5360
|
-
const start = findFirstJsonRootStart(sanitized.visibleText);
|
|
5361
|
-
if (start < 0) {
|
|
5362
|
-
return null;
|
|
5363
|
-
}
|
|
5364
|
-
const candidate = sanitized.visibleText.slice(start).trim();
|
|
5365
|
-
if (!candidate) {
|
|
5366
|
-
return null;
|
|
5367
|
-
}
|
|
5368
|
-
try {
|
|
5369
|
-
const repaired = import_jsonrepair3.jsonrepair(candidate);
|
|
5370
|
-
const parsed = JSON.parse(repaired);
|
|
5371
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
5372
|
-
return null;
|
|
5373
|
-
}
|
|
5374
|
-
return parsed;
|
|
5375
|
-
} catch {
|
|
5376
|
-
return null;
|
|
5377
|
-
}
|
|
5378
|
-
}
|
|
5379
|
-
function findFirstJsonRootStart(input) {
|
|
5380
|
-
let inString = false;
|
|
5381
|
-
let escaped = false;
|
|
5382
|
-
for (let index = 0;index < input.length; index += 1) {
|
|
5383
|
-
const char = input[index];
|
|
5384
|
-
if (!char) {
|
|
5385
|
-
continue;
|
|
5386
|
-
}
|
|
5387
|
-
if (inString) {
|
|
5388
|
-
if (escaped) {
|
|
5389
|
-
escaped = false;
|
|
5390
|
-
continue;
|
|
5391
|
-
}
|
|
5392
|
-
if (char === "\\") {
|
|
5393
|
-
escaped = true;
|
|
5394
|
-
continue;
|
|
5395
|
-
}
|
|
5396
|
-
if (char === '"') {
|
|
5397
|
-
inString = false;
|
|
5398
|
-
}
|
|
5399
|
-
continue;
|
|
5400
|
-
}
|
|
5401
|
-
if (char === '"') {
|
|
5402
|
-
inString = true;
|
|
5403
|
-
continue;
|
|
5404
|
-
}
|
|
5405
|
-
if (char === "{" || char === "[") {
|
|
5406
|
-
return index;
|
|
5407
|
-
}
|
|
5408
|
-
}
|
|
5409
|
-
const objectStart = input.indexOf("{");
|
|
5410
|
-
const arrayStart = input.indexOf("[");
|
|
5411
|
-
if (objectStart < 0) {
|
|
5412
|
-
return arrayStart;
|
|
5413
|
-
}
|
|
5414
|
-
if (arrayStart < 0) {
|
|
5415
|
-
return objectStart;
|
|
5416
|
-
}
|
|
5417
|
-
return Math.min(objectStart, arrayStart);
|
|
5418
|
-
}
|
|
5419
5310
|
function parseWithObserve(output, schema, parseOptions, context) {
|
|
5420
5311
|
const userParseTrace = parseOptions.onTrace;
|
|
5421
5312
|
return parseLLMOutput(output, schema, {
|
|
@@ -5518,12 +5409,12 @@ function mergeStructuredOptions(defaults, overrides) {
|
|
|
5518
5409
|
...defaults,
|
|
5519
5410
|
...overrides,
|
|
5520
5411
|
parse: {
|
|
5521
|
-
...defaults?.parse
|
|
5522
|
-
...overrides?.parse
|
|
5412
|
+
...defaults?.parse,
|
|
5413
|
+
...overrides?.parse
|
|
5523
5414
|
},
|
|
5524
5415
|
request: {
|
|
5525
|
-
...defaults?.request
|
|
5526
|
-
...overrides?.request
|
|
5416
|
+
...defaults?.request,
|
|
5417
|
+
...overrides?.request
|
|
5527
5418
|
},
|
|
5528
5419
|
stream: mergeObjectLike(defaults?.stream, overrides?.stream),
|
|
5529
5420
|
selfHeal: mergeObjectLike(defaults?.selfHeal, overrides?.selfHeal),
|
|
@@ -5539,8 +5430,8 @@ function mergeGenerateOptions(defaults, overrides) {
|
|
|
5539
5430
|
outdent: overrides?.outdent ?? defaults?.outdent,
|
|
5540
5431
|
systemPrompt: overrides?.systemPrompt ?? defaults?.systemPrompt,
|
|
5541
5432
|
request: {
|
|
5542
|
-
...defaults?.request
|
|
5543
|
-
...overrides?.request
|
|
5433
|
+
...defaults?.request,
|
|
5434
|
+
...overrides?.request
|
|
5544
5435
|
},
|
|
5545
5436
|
stream: mergeObjectLike(defaults?.stream, overrides?.stream),
|
|
5546
5437
|
debug: mergeObjectLike(defaults?.debug, overrides?.debug),
|