@cydm/pie 2.6.5 → 2.6.7
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/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/mcp-adapter/index.js +141 -31
- package/dist/builtin/extensions/plan-mode/index.js +3 -3
- package/dist/builtin/extensions/subagent/index.js +362 -6
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-bridge.js +3 -2
- package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-runtime.js +1 -1
- package/dist/builtin/skills/chrome-devtools-axi/{chunk-UPATXALW.js → chunk-U75F4DPF.js} +60 -0
- package/dist/builtin/skills/chrome-devtools-axi/{cli-5Z4COIKQ.js → cli-4ITIR57L.js} +85 -36
- package/dist/builtin/skills/skill-creator/SKILL.md +7 -8
- package/dist/chunks/{chunk-5OXH6NUH.js → chunk-7B4IIBVS.js} +307 -6
- package/dist/chunks/{chunk-AETQBDEG.js → chunk-PAC62XU4.js} +1 -1
- package/dist/chunks/{chunk-QKSK5K5N.js → chunk-T6GMEDIE.js} +1207 -225
- package/dist/chunks/{chunk-TFRQE7UQ.js → chunk-VUKF7U7Q.js} +1 -1
- package/dist/chunks/{src-Z4KWMX6E.js → src-HPIBCE2I.js} +2 -2
- package/dist/chunks/{test-stream-3FG7FHHU.js → test-stream-Y7WXELAJ.js} +1 -1
- package/dist/cli.js +2619 -2510
- package/package.json +2 -2
|
@@ -722,6 +722,9 @@ var NodeFileSystem = class {
|
|
|
722
722
|
}
|
|
723
723
|
}
|
|
724
724
|
async readTextRange(path, options, signal) {
|
|
725
|
+
if (options?.tailLines !== void 0) {
|
|
726
|
+
return this.readTextRangeTail(path, options, signal);
|
|
727
|
+
}
|
|
725
728
|
const fs = getNodeFs();
|
|
726
729
|
const range = normalizeRangeOptions(options);
|
|
727
730
|
const stat = await fs.promises.stat(path);
|
|
@@ -747,6 +750,7 @@ var NodeFileSystem = class {
|
|
|
747
750
|
const selectedBinaryDetector = new StreamingBinaryDetector();
|
|
748
751
|
const textDecoder = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
749
752
|
let rawLineIndex = 0;
|
|
753
|
+
let lastCharWasNewline = false;
|
|
750
754
|
const selectedEndLine = Number.isFinite(range.limitLines) ? range.offsetLine + range.limitLines : Number.POSITIVE_INFINITY;
|
|
751
755
|
const startLine = () => {
|
|
752
756
|
if (lineStarted) return;
|
|
@@ -843,6 +847,7 @@ var NodeFileSystem = class {
|
|
|
843
847
|
for (const char of text) {
|
|
844
848
|
if (char === "\n") finishLine();
|
|
845
849
|
else scanLineChar(char);
|
|
850
|
+
lastCharWasNewline = char === "\n";
|
|
846
851
|
}
|
|
847
852
|
};
|
|
848
853
|
const stream = fs.createReadStream(path);
|
|
@@ -877,6 +882,181 @@ var NodeFileSystem = class {
|
|
|
877
882
|
firstLineExceedsLimit,
|
|
878
883
|
selectedBytesLookBinary: selectedBinaryDetector.finish(),
|
|
879
884
|
fileBytesLookBinary: fileBinaryDetector.finish(),
|
|
885
|
+
endsWithNewline: lastCharWasNewline,
|
|
886
|
+
mtimeMs: stat.mtime.getTime(),
|
|
887
|
+
size: stat.size
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Tail read: select the last N lines in ONE forward scan. The full-file
|
|
892
|
+
* hash and totalLines (which the observation ledger requires of every
|
|
893
|
+
* read) force a complete scan anyway, so the tail window is extracted with
|
|
894
|
+
* a bounded ring buffer during that same scan — no probing passes, no
|
|
895
|
+
* second/third read. Ring bounds: at most `effectiveN` line entries and
|
|
896
|
+
* 2×maxOutputBytes of text; a single line longer than maxOutputBytes keeps
|
|
897
|
+
* only its byte length (it can never be output). When the ring evicts
|
|
898
|
+
* older lines (window bytes over budget), the result degrades honestly:
|
|
899
|
+
* truncated=true, and the reported window covers exactly what was kept.
|
|
900
|
+
*/
|
|
901
|
+
async readTextRangeTail(path, options, signal) {
|
|
902
|
+
const fs = getNodeFs();
|
|
903
|
+
const stat = await fs.promises.stat(path);
|
|
904
|
+
const maxOutputLines = Number.isFinite(options.maxOutputLines) ? Math.max(0, Math.floor(options.maxOutputLines)) : Number.POSITIVE_INFINITY;
|
|
905
|
+
const maxOutputBytes = Number.isFinite(options.maxOutputBytes) ? Math.max(0, Math.floor(options.maxOutputBytes)) : Number.POSITIVE_INFINITY;
|
|
906
|
+
const requested = Math.max(1, Math.floor(options.tailLines));
|
|
907
|
+
const effectiveN = Math.max(1, Math.min(requested, maxOutputLines));
|
|
908
|
+
const fullHasher = createTextHasher();
|
|
909
|
+
const fileBinaryDetector = new StreamingBinaryDetector();
|
|
910
|
+
const textDecoder = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
911
|
+
const entries = [];
|
|
912
|
+
let entryBytes = 0;
|
|
913
|
+
let totalLines = 0;
|
|
914
|
+
let lastCharWasNewline = false;
|
|
915
|
+
let currentLine = "";
|
|
916
|
+
let currentLineBytes = 0;
|
|
917
|
+
let keepLineText = true;
|
|
918
|
+
const ringByteBudget = Number.isFinite(maxOutputBytes) ? 2 * maxOutputBytes : Number.POSITIVE_INFINITY;
|
|
919
|
+
const trimRing = () => {
|
|
920
|
+
while (entries.length > effectiveN || entries.length > 1 && entryBytes > ringByteBudget) {
|
|
921
|
+
const evicted = entries.shift();
|
|
922
|
+
entryBytes -= evicted.bytes;
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
const scanText = (text) => {
|
|
926
|
+
if (!text) return;
|
|
927
|
+
fullHasher.update(text);
|
|
928
|
+
for (const char of text) {
|
|
929
|
+
if (char === "\n") {
|
|
930
|
+
entries.push({ text: keepLineText ? currentLine : null, bytes: currentLineBytes });
|
|
931
|
+
entryBytes += currentLineBytes;
|
|
932
|
+
totalLines++;
|
|
933
|
+
currentLine = "";
|
|
934
|
+
currentLineBytes = 0;
|
|
935
|
+
keepLineText = true;
|
|
936
|
+
trimRing();
|
|
937
|
+
} else {
|
|
938
|
+
const charBytes = byteLength(char);
|
|
939
|
+
currentLineBytes += charBytes;
|
|
940
|
+
if (currentLineBytes > maxOutputBytes) {
|
|
941
|
+
keepLineText = false;
|
|
942
|
+
currentLine = "";
|
|
943
|
+
} else {
|
|
944
|
+
currentLine += char;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
lastCharWasNewline = char === "\n";
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
const stream = fs.createReadStream(path);
|
|
951
|
+
try {
|
|
952
|
+
for await (const chunk of stream) {
|
|
953
|
+
if (signal?.aborted) {
|
|
954
|
+
stream.destroy();
|
|
955
|
+
throw new Error("Operation aborted");
|
|
956
|
+
}
|
|
957
|
+
const bytes = chunk;
|
|
958
|
+
fileBinaryDetector.update(bytes);
|
|
959
|
+
scanText(textDecoder.decode(bytes, { stream: true }));
|
|
960
|
+
}
|
|
961
|
+
scanText(textDecoder.decode());
|
|
962
|
+
} finally {
|
|
963
|
+
stream.destroy();
|
|
964
|
+
}
|
|
965
|
+
if (lastCharWasNewline) {
|
|
966
|
+
totalLines++;
|
|
967
|
+
} else if (currentLine !== "" || currentLineBytes > 0) {
|
|
968
|
+
entries.push({ text: keepLineText ? currentLine : null, bytes: currentLineBytes });
|
|
969
|
+
entryBytes += currentLineBytes;
|
|
970
|
+
totalLines++;
|
|
971
|
+
trimRing();
|
|
972
|
+
} else if (totalLines === 0) {
|
|
973
|
+
totalLines = 1;
|
|
974
|
+
}
|
|
975
|
+
const phantomIncluded = lastCharWasNewline;
|
|
976
|
+
const emptyFileSingleLine = entries.length === 0 && !phantomIncluded && totalLines === 1;
|
|
977
|
+
const windowLines = entries.length + (phantomIncluded ? 1 : 0) + (emptyFileSingleLine ? 1 : 0);
|
|
978
|
+
const selectedBytes = entries.reduce((sum, entry) => sum + entry.bytes, 0) + Math.max(0, windowLines - 1);
|
|
979
|
+
const firstLineBytes = entries.length > 0 ? entries[0].bytes : 0;
|
|
980
|
+
const firstLineExceedsLimit = entries.length === 1 && entries[0].text === null;
|
|
981
|
+
const streamedLines = totalLines - (phantomIncluded ? 1 : 0) - (emptyFileSingleLine ? 1 : 0);
|
|
982
|
+
const lostWindowLines = Math.max(0, Math.min(streamedLines, effectiveN) - entries.length);
|
|
983
|
+
const outputLines = [];
|
|
984
|
+
let outputBytes = 0;
|
|
985
|
+
let truncated = lostWindowLines > 0;
|
|
986
|
+
let truncatedBy = lostWindowLines > 0 ? "bytes" : null;
|
|
987
|
+
let firstShownEntryIndex;
|
|
988
|
+
const phantomReserve = phantomIncluded && !emptyFileSingleLine ? 1 : 0;
|
|
989
|
+
for (let index = entries.length - 1; index >= 0; index--) {
|
|
990
|
+
const entry = entries[index];
|
|
991
|
+
if (outputLines.length + phantomReserve >= maxOutputLines) {
|
|
992
|
+
truncated = true;
|
|
993
|
+
truncatedBy = truncatedBy ?? "lines";
|
|
994
|
+
break;
|
|
995
|
+
}
|
|
996
|
+
if (entry.text === null) {
|
|
997
|
+
truncated = true;
|
|
998
|
+
truncatedBy = "bytes";
|
|
999
|
+
break;
|
|
1000
|
+
}
|
|
1001
|
+
const candidate = outputBytes + (outputLines.length > 0 ? 1 : 0) + entry.bytes;
|
|
1002
|
+
if (candidate > maxOutputBytes) {
|
|
1003
|
+
truncated = true;
|
|
1004
|
+
truncatedBy = "bytes";
|
|
1005
|
+
break;
|
|
1006
|
+
}
|
|
1007
|
+
outputLines.unshift(entry.text);
|
|
1008
|
+
outputBytes = candidate;
|
|
1009
|
+
firstShownEntryIndex = index;
|
|
1010
|
+
}
|
|
1011
|
+
if (phantomIncluded) {
|
|
1012
|
+
if (outputLines.length + 1 <= maxOutputLines || outputLines.length === 0) {
|
|
1013
|
+
const phantomBytes = outputLines.length > 0 ? 1 : 0;
|
|
1014
|
+
if (outputBytes + phantomBytes <= maxOutputBytes) {
|
|
1015
|
+
outputLines.push("");
|
|
1016
|
+
outputBytes += phantomBytes;
|
|
1017
|
+
} else {
|
|
1018
|
+
truncated = true;
|
|
1019
|
+
truncatedBy = "bytes";
|
|
1020
|
+
}
|
|
1021
|
+
} else {
|
|
1022
|
+
truncated = true;
|
|
1023
|
+
truncatedBy = truncatedBy ?? "lines";
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
if (emptyFileSingleLine) {
|
|
1027
|
+
outputLines.push("");
|
|
1028
|
+
}
|
|
1029
|
+
if (firstLineExceedsLimit) {
|
|
1030
|
+
truncated = true;
|
|
1031
|
+
truncatedBy = "bytes";
|
|
1032
|
+
}
|
|
1033
|
+
const realLastLine = totalLines - (phantomIncluded ? 1 : 0);
|
|
1034
|
+
const outputStartLine = outputLines.length === 0 ? totalLines + 1 : firstShownEntryIndex !== void 0 ? realLastLine - entries.length + 1 + firstShownEntryIndex : totalLines;
|
|
1035
|
+
const content = outputLines.join("\n");
|
|
1036
|
+
const selectedHasher = createTextHasher();
|
|
1037
|
+
selectedHasher.update(content);
|
|
1038
|
+
const selectedBinaryDetector = new StreamingBinaryDetector();
|
|
1039
|
+
if (content.length > 0) {
|
|
1040
|
+
selectedBinaryDetector.update(Buffer.from(content, "utf-8"));
|
|
1041
|
+
}
|
|
1042
|
+
return {
|
|
1043
|
+
content,
|
|
1044
|
+
contentHash: fullHasher.digest(),
|
|
1045
|
+
selectedContentHash: selectedHasher.digest(),
|
|
1046
|
+
totalLines,
|
|
1047
|
+
totalBytes: stat.size,
|
|
1048
|
+
selectedLines: windowLines,
|
|
1049
|
+
selectedBytes,
|
|
1050
|
+
firstLineBytes,
|
|
1051
|
+
outputLines: outputLines.length,
|
|
1052
|
+
outputBytes,
|
|
1053
|
+
truncated,
|
|
1054
|
+
truncatedBy,
|
|
1055
|
+
firstLineExceedsLimit,
|
|
1056
|
+
selectedBytesLookBinary: selectedBinaryDetector.finish(),
|
|
1057
|
+
fileBytesLookBinary: fileBinaryDetector.finish(),
|
|
1058
|
+
endsWithNewline: lastCharWasNewline,
|
|
1059
|
+
outputStartLine,
|
|
880
1060
|
mtimeMs: stat.mtime.getTime(),
|
|
881
1061
|
size: stat.size
|
|
882
1062
|
};
|
|
@@ -1206,6 +1386,9 @@ var PuerTSFileSystem = class {
|
|
|
1206
1386
|
if (signal?.aborted) {
|
|
1207
1387
|
throw new Error("Operation aborted");
|
|
1208
1388
|
}
|
|
1389
|
+
if (options?.tailLines !== void 0 && Number.isFinite(options.tailLines) && options.tailLines > 0) {
|
|
1390
|
+
return this.readTextRangeTailViaBridge(path, options, signal);
|
|
1391
|
+
}
|
|
1209
1392
|
const bridge = getPieFileBridge();
|
|
1210
1393
|
const normalizedPath = this.normalizePath(path);
|
|
1211
1394
|
if (typeof bridge.StartReadTextRange !== "function" || typeof bridge.CancelRequest !== "function" || typeof bridge.ReleaseRequest !== "function") {
|
|
@@ -1237,6 +1420,80 @@ var PuerTSFileSystem = class {
|
|
|
1237
1420
|
bridge.ReleaseRequest(requestId);
|
|
1238
1421
|
}
|
|
1239
1422
|
}
|
|
1423
|
+
/**
|
|
1424
|
+
* Tail fallback for the PuerTS host: the Unity C# bridge has no native
|
|
1425
|
+
* tail support yet (follow-up: a purpose-built bridge method mirroring
|
|
1426
|
+
* NodeFileSystem's single-scan ring buffer). Until then, translate
|
|
1427
|
+
* tailLines into the bridge's offset/limit windows — a 1-line probe for
|
|
1428
|
+
* the line count, one for phantom detection, then the window read. The
|
|
1429
|
+
* extra scans stay inside the platform so every caller (the shared read
|
|
1430
|
+
* tool, future hosts) sees one uniform tailLines contract.
|
|
1431
|
+
*
|
|
1432
|
+
* Two contract guards live here because the bridge reads windows FORWARD:
|
|
1433
|
+
* 1. The C# side keeps the window's HEAD under the byte cap — the opposite
|
|
1434
|
+
* of tail semantics. Halve the window until it fits so the delivered
|
|
1435
|
+
* content always ends at the file's last line (matching NodeFileSystem);
|
|
1436
|
+
* a single over-cap line degrades to firstLineExceedsLimit, the same
|
|
1437
|
+
* signal Node produces.
|
|
1438
|
+
* 2. Out-of-band appends between the probes and the window read would
|
|
1439
|
+
* stale the line count; verify mtime stability and retry a bounded
|
|
1440
|
+
* number of times, then fall through best-effort (append-heavy logs
|
|
1441
|
+
* legitimately churn).
|
|
1442
|
+
*/
|
|
1443
|
+
async readTextRangeTailViaBridge(path, options, signal) {
|
|
1444
|
+
const probeOptions = {
|
|
1445
|
+
offsetLine: 0,
|
|
1446
|
+
limitLines: 1,
|
|
1447
|
+
maxOutputLines: 1,
|
|
1448
|
+
maxOutputBytes: options.maxOutputBytes
|
|
1449
|
+
};
|
|
1450
|
+
const maxOutputLines = Number.isFinite(options.maxOutputLines) ? Math.floor(options.maxOutputLines) : Number.POSITIVE_INFINITY;
|
|
1451
|
+
for (let attempt = 0; ; attempt++) {
|
|
1452
|
+
const countProbe = await this.readTextRange(path, probeOptions, signal);
|
|
1453
|
+
const totalLines = countProbe.totalLines;
|
|
1454
|
+
const requested = Math.floor(options.tailLines);
|
|
1455
|
+
let effectiveN = Math.max(1, Math.min(requested, maxOutputLines));
|
|
1456
|
+
const lastProbe = await this.readTextRange(path, { ...probeOptions, offsetLine: Math.max(0, totalLines - 1) }, signal);
|
|
1457
|
+
const phantom = lastProbe.selectedBytes === 0 && !lastProbe.firstLineExceedsLimit && totalLines > 1;
|
|
1458
|
+
let result;
|
|
1459
|
+
let windowOffsetLine = 0;
|
|
1460
|
+
let narrowedByBytes = false;
|
|
1461
|
+
for (; ; ) {
|
|
1462
|
+
windowOffsetLine = Math.max(0, totalLines - effectiveN - (phantom ? 1 : 0));
|
|
1463
|
+
result = await this.readTextRange(path, {
|
|
1464
|
+
offsetLine: windowOffsetLine,
|
|
1465
|
+
limitLines: effectiveN + (phantom ? 1 : 0),
|
|
1466
|
+
maxOutputLines: options.maxOutputLines,
|
|
1467
|
+
maxOutputBytes: options.maxOutputBytes
|
|
1468
|
+
}, signal);
|
|
1469
|
+
const byteTruncated = result.truncated && result.truncatedBy === "bytes" && !result.firstLineExceedsLimit;
|
|
1470
|
+
const oversizedHead = result.truncated && result.firstLineExceedsLimit;
|
|
1471
|
+
if (byteTruncated && effectiveN > 1) {
|
|
1472
|
+
narrowedByBytes = true;
|
|
1473
|
+
effectiveN = Math.max(1, Math.floor(effectiveN / 2));
|
|
1474
|
+
continue;
|
|
1475
|
+
}
|
|
1476
|
+
if (oversizedHead) {
|
|
1477
|
+
const nextEffectiveN = totalLines - (phantom ? 1 : 0) - (windowOffsetLine + 1);
|
|
1478
|
+
if (nextEffectiveN < 1 || nextEffectiveN >= effectiveN) break;
|
|
1479
|
+
narrowedByBytes = true;
|
|
1480
|
+
effectiveN = nextEffectiveN;
|
|
1481
|
+
continue;
|
|
1482
|
+
}
|
|
1483
|
+
break;
|
|
1484
|
+
}
|
|
1485
|
+
const stable = countProbe.mtimeMs === lastProbe.mtimeMs && lastProbe.mtimeMs === result.mtimeMs && countProbe.contentHash === lastProbe.contentHash && lastProbe.contentHash === result.contentHash;
|
|
1486
|
+
if (stable || attempt >= 2) {
|
|
1487
|
+
return {
|
|
1488
|
+
...result,
|
|
1489
|
+
truncated: result.truncated || narrowedByBytes,
|
|
1490
|
+
truncatedBy: narrowedByBytes ? "bytes" : result.truncatedBy,
|
|
1491
|
+
endsWithNewline: phantom,
|
|
1492
|
+
outputStartLine: windowOffsetLine + 1
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1240
1497
|
async writeFile(path, data, encoding = "utf-8") {
|
|
1241
1498
|
const bridge = getPieFileBridge();
|
|
1242
1499
|
const normalizedPath = this.normalizePath(path);
|
|
@@ -2750,6 +3007,17 @@ function isPuertsReparsePoint(path) {
|
|
|
2750
3007
|
return false;
|
|
2751
3008
|
}
|
|
2752
3009
|
}
|
|
3010
|
+
var warnedPuertsDeletionShells = false;
|
|
3011
|
+
function warnPuertsDeletionShellsOnce(path) {
|
|
3012
|
+
if (warnedPuertsDeletionShells) return;
|
|
3013
|
+
warnedPuertsDeletionShells = true;
|
|
3014
|
+
try {
|
|
3015
|
+
console.warn(
|
|
3016
|
+
`[platform] Directory.Delete is unbound on this host; '${path}' contents were removed but empty directory shells cannot be deleted by this binding (logged once)`
|
|
3017
|
+
);
|
|
3018
|
+
} catch {
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
2753
3021
|
function deletePuertsDirectoryByEnumeration(path, recursive) {
|
|
2754
3022
|
const directory = CS.System.IO.Directory;
|
|
2755
3023
|
const file = CS.System.IO.File;
|
|
@@ -2764,13 +3032,19 @@ function deletePuertsDirectoryByEnumeration(path, recursive) {
|
|
|
2764
3032
|
);
|
|
2765
3033
|
}
|
|
2766
3034
|
const files = Array.from(directory.GetFiles(path) ?? []);
|
|
2767
|
-
for (const entry of files) file.Delete(entry);
|
|
2768
|
-
if (!recursive) return;
|
|
2769
3035
|
const subdirs = Array.from(directory.GetDirectories(path) ?? []);
|
|
3036
|
+
if (!recursive) {
|
|
3037
|
+
if (files.length > 0 || subdirs.length > 0) {
|
|
3038
|
+
throw new Error(`Directory not empty: ${path}`);
|
|
3039
|
+
}
|
|
3040
|
+
return;
|
|
3041
|
+
}
|
|
3042
|
+
for (const entry of files) file.Delete(entry);
|
|
2770
3043
|
for (const subdir of subdirs) {
|
|
2771
3044
|
if (isPuertsReparsePoint(String(subdir))) continue;
|
|
2772
3045
|
deletePuertsDirectoryByEnumeration(String(subdir), true);
|
|
2773
3046
|
}
|
|
3047
|
+
warnPuertsDeletionShellsOnce(path);
|
|
2774
3048
|
}
|
|
2775
3049
|
|
|
2776
3050
|
// ../../packages/platform/src/index.ts
|
|
@@ -2841,10 +3115,15 @@ function parseStreamingJson(partialJson) {
|
|
|
2841
3115
|
}
|
|
2842
3116
|
|
|
2843
3117
|
// ../../packages/ai/src/providers/simple-options.ts
|
|
3118
|
+
var DEFAULT_MAX_TOKENS = 32e3;
|
|
3119
|
+
function positiveFiniteOrInfinity(value) {
|
|
3120
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : Number.POSITIVE_INFINITY;
|
|
3121
|
+
}
|
|
2844
3122
|
function buildBaseOptions(model, options, apiKey) {
|
|
3123
|
+
const modelMaxTokens = positiveFiniteOrInfinity(model.maxTokens);
|
|
2845
3124
|
return {
|
|
2846
3125
|
temperature: options?.temperature,
|
|
2847
|
-
maxTokens: options?.maxTokens || Math.min(
|
|
3126
|
+
maxTokens: options?.maxTokens || Math.min(modelMaxTokens, DEFAULT_MAX_TOKENS),
|
|
2848
3127
|
signal: options?.signal,
|
|
2849
3128
|
apiKey: apiKey || options?.apiKey,
|
|
2850
3129
|
cacheRetention: options?.cacheRetention,
|
|
@@ -2866,11 +3145,18 @@ function adjustMaxTokensForThinking(baseMaxTokens, modelMaxTokens, reasoningLeve
|
|
|
2866
3145
|
medium: 8192,
|
|
2867
3146
|
high: 16384
|
|
2868
3147
|
};
|
|
2869
|
-
const budgets = { ...defaultBudgets
|
|
3148
|
+
const budgets = { ...defaultBudgets };
|
|
3149
|
+
if (customBudgets) {
|
|
3150
|
+
for (const key of Object.keys(defaultBudgets)) {
|
|
3151
|
+
const value = customBudgets[key];
|
|
3152
|
+
if (typeof value === "number" && Number.isFinite(value) && value >= 0) budgets[key] = value;
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
2870
3155
|
const minOutputTokens = 1024;
|
|
2871
3156
|
const level = clampReasoning(reasoningLevel);
|
|
2872
|
-
let thinkingBudget = budgets[level];
|
|
2873
|
-
const
|
|
3157
|
+
let thinkingBudget = budgets[level] ?? defaultBudgets[level] ?? 0;
|
|
3158
|
+
const outputCap = positiveFiniteOrInfinity(modelMaxTokens);
|
|
3159
|
+
const maxTokens = Math.min(baseMaxTokens + thinkingBudget, outputCap);
|
|
2874
3160
|
if (maxTokens <= thinkingBudget) {
|
|
2875
3161
|
thinkingBudget = Math.max(0, maxTokens - minOutputTokens);
|
|
2876
3162
|
}
|
|
@@ -3796,7 +4082,11 @@ var streamOpenAICompletions = (model, context, options) => {
|
|
|
3796
4082
|
}
|
|
3797
4083
|
const emittedCallCounts = /* @__PURE__ */ new Map();
|
|
3798
4084
|
const excessDuplicateEntries = /* @__PURE__ */ new Set();
|
|
4085
|
+
const repeatExempt = new Set(
|
|
4086
|
+
(context.tools ?? []).filter((tool) => tool.allowIdenticalRepeatCalls === true).map((tool) => tool.name)
|
|
4087
|
+
);
|
|
3799
4088
|
for (const entry of toolCallEntries) {
|
|
4089
|
+
if (repeatExempt.has(entry.block.name)) continue;
|
|
3800
4090
|
const key = `${entry.block.name}
|
|
3801
4091
|
${entry.partialArgs}`;
|
|
3802
4092
|
const seen = (emittedCallCounts.get(key) ?? 0) + 1;
|
|
@@ -3871,8 +4161,18 @@ var streamSimpleOpenAICompletions = (model, context, options) => {
|
|
|
3871
4161
|
}
|
|
3872
4162
|
const base = buildBaseOptions(model, options, apiKey);
|
|
3873
4163
|
const reasoningEffort = clampReasoning(options?.reasoning);
|
|
4164
|
+
const needsThinkingAllowance = Boolean(model.reasoning) && options?.reasoning !== void 0;
|
|
4165
|
+
const adjusted = needsThinkingAllowance ? adjustMaxTokensForThinking(base.maxTokens || 0, model.maxTokens, options.reasoning, options?.thinkingBudgets) : void 0;
|
|
4166
|
+
let maxTokens = adjusted ? adjusted.maxTokens : base.maxTokens;
|
|
4167
|
+
if (maxTokens === void 0) {
|
|
4168
|
+
maxTokens = DEFAULT_MAX_TOKENS;
|
|
4169
|
+
}
|
|
4170
|
+
if (options?.maxTokens === void 0) {
|
|
4171
|
+
maxTokens = Math.min(maxTokens, DEFAULT_MAX_TOKENS);
|
|
4172
|
+
}
|
|
3874
4173
|
return streamOpenAICompletions(model, context, {
|
|
3875
4174
|
...base,
|
|
4175
|
+
maxTokens,
|
|
3876
4176
|
reasoningEffort
|
|
3877
4177
|
});
|
|
3878
4178
|
};
|
|
@@ -7793,6 +8093,7 @@ export {
|
|
|
7793
8093
|
type_exports,
|
|
7794
8094
|
ExtendsUndefinedCheck,
|
|
7795
8095
|
EventStream,
|
|
8096
|
+
AssistantMessageEventStream,
|
|
7796
8097
|
getModelCacheCapability,
|
|
7797
8098
|
EMPTY_ASSISTANT_CONTENT_ERROR,
|
|
7798
8099
|
OPENAI_COMPAT_PROTOCOL_ERROR_CODE,
|