@probelabs/probe 0.6.0-rc285 → 0.6.0-rc286
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/bin/binaries/probe-v0.6.0-rc286-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc286-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc286-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc286-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc286-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +20 -3
- package/build/agent/index.js +24 -17
- package/build/downloader.js +5 -1
- package/build/tools/vercel.js +7 -5
- package/cjs/agent/ProbeAgent.cjs +24 -17
- package/cjs/index.cjs +24 -17
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +20 -3
- package/src/downloader.js +5 -1
- package/src/tools/vercel.js +7 -5
- package/bin/binaries/probe-v0.6.0-rc285-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc285-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc285-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc285-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc285-x86_64-unknown-linux-musl.tar.gz +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -93,7 +93,7 @@ import { formatAvailableSkillsXml as formatAvailableSkills } from './skills/form
|
|
|
93
93
|
import { createSkillToolInstances } from './skills/tools.js';
|
|
94
94
|
import { RetryManager, createRetryManagerFromEnv } from './RetryManager.js';
|
|
95
95
|
import { FallbackManager, createFallbackManagerFromEnv, buildFallbackProvidersFromEnv } from './FallbackManager.js';
|
|
96
|
-
import { handleContextLimitError } from './contextCompactor.js';
|
|
96
|
+
import { handleContextLimitError, compactMessages, calculateCompactionStats } from './contextCompactor.js';
|
|
97
97
|
import { formatErrorForAI, ParameterError } from '../utils/error-types.js';
|
|
98
98
|
import { getCommonPrefix, toRelativePath, safeRealpath } from '../utils/path-validation.js';
|
|
99
99
|
import { truncateIfNeeded, getMaxOutputTokens } from './outputTruncator.js';
|
|
@@ -3227,6 +3227,25 @@ Follow these instructions carefully:
|
|
|
3227
3227
|
];
|
|
3228
3228
|
}
|
|
3229
3229
|
|
|
3230
|
+
// Proactively compact for multi-turn conversations.
|
|
3231
|
+
// On turn 2+, previous turns contain full tool call/result history which can
|
|
3232
|
+
// be 50K+ tokens. This drowns out the new user message and causes the model to
|
|
3233
|
+
// focus on prior context rather than the new question.
|
|
3234
|
+
// compactMessages strips intermediate monologue from completed segments,
|
|
3235
|
+
// keeping user messages + final answers from prior turns.
|
|
3236
|
+
// Must run AFTER adding the new user message so the compactor sees 2+ segments
|
|
3237
|
+
// (completed prior turns + the new incomplete turn), preserving the latest segment.
|
|
3238
|
+
if (this.history.length > 0) {
|
|
3239
|
+
const compacted = compactMessages(currentMessages, { keepLastSegment: true, minSegmentsToKeep: 1 });
|
|
3240
|
+
if (compacted.length < currentMessages.length) {
|
|
3241
|
+
const stats = calculateCompactionStats(currentMessages, compacted);
|
|
3242
|
+
if (this.debug) {
|
|
3243
|
+
console.log(`[DEBUG] Proactive history compaction: ${currentMessages.length} → ${compacted.length} messages (${stats.reductionPercent}% reduction, ~${stats.tokensSaved} tokens saved)`);
|
|
3244
|
+
}
|
|
3245
|
+
currentMessages = compacted;
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3230
3249
|
let currentIteration = 0;
|
|
3231
3250
|
let finalResult = 'I was unable to complete your request due to reaching the maximum number of tool iterations.';
|
|
3232
3251
|
|
|
@@ -4141,8 +4160,6 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
4141
4160
|
* @returns {Object} Compaction statistics
|
|
4142
4161
|
*/
|
|
4143
4162
|
async compactHistory(options = {}) {
|
|
4144
|
-
const { compactMessages, calculateCompactionStats } = await import('./contextCompactor.js');
|
|
4145
|
-
|
|
4146
4163
|
if (this.history.length === 0) {
|
|
4147
4164
|
if (this.debug) {
|
|
4148
4165
|
console.log(`[DEBUG] No history to compact for session ${this.sessionId}`);
|
package/build/agent/index.js
CHANGED
|
@@ -2755,7 +2755,11 @@ async function extractBinary(assetPath, outputDir) {
|
|
|
2755
2755
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
2756
2756
|
console.log(`Extracting zip to ${extractDir}...`);
|
|
2757
2757
|
}
|
|
2758
|
-
|
|
2758
|
+
if (isWindows) {
|
|
2759
|
+
await exec(`powershell -NoProfile -Command "Expand-Archive -Path '${assetPath}' -DestinationPath '${extractDir}' -Force"`);
|
|
2760
|
+
} else {
|
|
2761
|
+
await exec(`unzip -q "${assetPath}" -d "${extractDir}"`);
|
|
2762
|
+
}
|
|
2759
2763
|
} else {
|
|
2760
2764
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
2761
2765
|
console.log(`Copying binary directly to ${binaryPath}`);
|
|
@@ -9651,14 +9655,15 @@ var init_vercel = __esm({
|
|
|
9651
9655
|
const parsedTargets = parseTargets(targets);
|
|
9652
9656
|
extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
9653
9657
|
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
9658
|
+
const { join: pathJoin, sep: pathSep } = await import("path");
|
|
9654
9659
|
extractFiles = extractFiles.map((target) => {
|
|
9655
9660
|
const { filePart, suffix } = splitTargetSuffix(target);
|
|
9656
9661
|
if (existsSync(filePart)) return target;
|
|
9657
|
-
const cwdPrefix = effectiveCwd.endsWith(
|
|
9662
|
+
const cwdPrefix = effectiveCwd.endsWith(pathSep) ? effectiveCwd : effectiveCwd + pathSep;
|
|
9658
9663
|
const relativePart = filePart.startsWith(cwdPrefix) ? filePart.slice(cwdPrefix.length) : null;
|
|
9659
9664
|
if (relativePart) {
|
|
9660
9665
|
for (const folder of options.allowedFolders) {
|
|
9661
|
-
const candidate = folder
|
|
9666
|
+
const candidate = pathJoin(folder, relativePart);
|
|
9662
9667
|
if (existsSync(candidate)) {
|
|
9663
9668
|
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} \u2192 ${candidate}`);
|
|
9664
9669
|
return candidate + suffix;
|
|
@@ -9666,11 +9671,12 @@ var init_vercel = __esm({
|
|
|
9666
9671
|
}
|
|
9667
9672
|
}
|
|
9668
9673
|
for (const folder of options.allowedFolders) {
|
|
9669
|
-
const folderPrefix = folder.endsWith(
|
|
9670
|
-
const
|
|
9674
|
+
const folderPrefix = folder.endsWith(pathSep) ? folder : folder + pathSep;
|
|
9675
|
+
const sepEscaped = pathSep === "\\" ? "\\\\" : pathSep;
|
|
9676
|
+
const wsParent = folderPrefix.replace(new RegExp("[^" + sepEscaped + "]+" + sepEscaped + "$"), "");
|
|
9671
9677
|
if (filePart.startsWith(wsParent)) {
|
|
9672
9678
|
const tail = filePart.slice(wsParent.length);
|
|
9673
|
-
const candidate = folderPrefix
|
|
9679
|
+
const candidate = pathJoin(folderPrefix, tail);
|
|
9674
9680
|
if (candidate !== filePart && existsSync(candidate)) {
|
|
9675
9681
|
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} \u2192 ${candidate}`);
|
|
9676
9682
|
return candidate + suffix;
|
|
@@ -79910,14 +79916,6 @@ var init_FallbackManager = __esm({
|
|
|
79910
79916
|
});
|
|
79911
79917
|
|
|
79912
79918
|
// src/agent/contextCompactor.js
|
|
79913
|
-
var contextCompactor_exports = {};
|
|
79914
|
-
__export(contextCompactor_exports, {
|
|
79915
|
-
calculateCompactionStats: () => calculateCompactionStats,
|
|
79916
|
-
compactMessages: () => compactMessages,
|
|
79917
|
-
handleContextLimitError: () => handleContextLimitError,
|
|
79918
|
-
identifyMessageSegments: () => identifyMessageSegments,
|
|
79919
|
-
isContextLimitError: () => isContextLimitError
|
|
79920
|
-
});
|
|
79921
79919
|
function isContextLimitError(error) {
|
|
79922
79920
|
if (!error) return false;
|
|
79923
79921
|
const errorMessage = (typeof error === "string" ? error : error?.message || "").toLowerCase();
|
|
@@ -84234,6 +84232,16 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
84234
84232
|
userMessage
|
|
84235
84233
|
];
|
|
84236
84234
|
}
|
|
84235
|
+
if (this.history.length > 0) {
|
|
84236
|
+
const compacted = compactMessages(currentMessages, { keepLastSegment: true, minSegmentsToKeep: 1 });
|
|
84237
|
+
if (compacted.length < currentMessages.length) {
|
|
84238
|
+
const stats = calculateCompactionStats(currentMessages, compacted);
|
|
84239
|
+
if (this.debug) {
|
|
84240
|
+
console.log(`[DEBUG] Proactive history compaction: ${currentMessages.length} \u2192 ${compacted.length} messages (${stats.reductionPercent}% reduction, ~${stats.tokensSaved} tokens saved)`);
|
|
84241
|
+
}
|
|
84242
|
+
currentMessages = compacted;
|
|
84243
|
+
}
|
|
84244
|
+
}
|
|
84237
84245
|
let currentIteration = 0;
|
|
84238
84246
|
let finalResult = "I was unable to complete your request due to reaching the maximum number of tool iterations.";
|
|
84239
84247
|
const baseMaxIterations = options._maxIterationsOverride || this.maxIterations || MAX_TOOL_ITERATIONS;
|
|
@@ -84934,7 +84942,6 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
84934
84942
|
* @returns {Object} Compaction statistics
|
|
84935
84943
|
*/
|
|
84936
84944
|
async compactHistory(options = {}) {
|
|
84937
|
-
const { compactMessages: compactMessages2, calculateCompactionStats: calculateCompactionStats2 } = await Promise.resolve().then(() => (init_contextCompactor(), contextCompactor_exports));
|
|
84938
84945
|
if (this.history.length === 0) {
|
|
84939
84946
|
if (this.debug) {
|
|
84940
84947
|
console.log(`[DEBUG] No history to compact for session ${this.sessionId}`);
|
|
@@ -84949,8 +84956,8 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
84949
84956
|
tokensSaved: 0
|
|
84950
84957
|
};
|
|
84951
84958
|
}
|
|
84952
|
-
const compactedMessages =
|
|
84953
|
-
const stats =
|
|
84959
|
+
const compactedMessages = compactMessages(this.history, options);
|
|
84960
|
+
const stats = calculateCompactionStats(this.history, compactedMessages);
|
|
84954
84961
|
this.history = compactedMessages;
|
|
84955
84962
|
try {
|
|
84956
84963
|
await this.storageAdapter.clearHistory(this.sessionId);
|
package/build/downloader.js
CHANGED
|
@@ -743,7 +743,11 @@ async function extractBinary(assetPath, outputDir) {
|
|
|
743
743
|
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
|
744
744
|
console.log(`Extracting zip to ${extractDir}...`);
|
|
745
745
|
}
|
|
746
|
-
|
|
746
|
+
if (isWindows) {
|
|
747
|
+
await exec(`powershell -NoProfile -Command "Expand-Archive -Path '${assetPath}' -DestinationPath '${extractDir}' -Force"`);
|
|
748
|
+
} else {
|
|
749
|
+
await exec(`unzip -q "${assetPath}" -d "${extractDir}"`);
|
|
750
|
+
}
|
|
747
751
|
} else {
|
|
748
752
|
// Assume it's a direct binary
|
|
749
753
|
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
package/build/tools/vercel.js
CHANGED
|
@@ -691,19 +691,20 @@ export const extractTool = (options = {}) => {
|
|
|
691
691
|
// model constructs wrong absolute paths (e.g., /workspace/gateway/file.go
|
|
692
692
|
// instead of /workspace/tyk/gateway/file.go)
|
|
693
693
|
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
694
|
+
const { join: pathJoin, sep: pathSep } = await import('path');
|
|
694
695
|
extractFiles = extractFiles.map(target => {
|
|
695
696
|
const { filePart, suffix } = splitTargetSuffix(target);
|
|
696
697
|
if (existsSync(filePart)) return target;
|
|
697
698
|
|
|
698
699
|
// Try resolving the relative tail against each allowedFolder
|
|
699
|
-
const cwdPrefix =
|
|
700
|
+
const cwdPrefix = effectiveCwd.endsWith(pathSep) ? effectiveCwd : effectiveCwd + pathSep;
|
|
700
701
|
const relativePart = filePart.startsWith(cwdPrefix)
|
|
701
702
|
? filePart.slice(cwdPrefix.length)
|
|
702
703
|
: null;
|
|
703
704
|
|
|
704
705
|
if (relativePart) {
|
|
705
706
|
for (const folder of options.allowedFolders) {
|
|
706
|
-
const candidate = folder
|
|
707
|
+
const candidate = pathJoin(folder, relativePart);
|
|
707
708
|
if (existsSync(candidate)) {
|
|
708
709
|
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} → ${candidate}`);
|
|
709
710
|
return candidate + suffix;
|
|
@@ -714,11 +715,12 @@ export const extractTool = (options = {}) => {
|
|
|
714
715
|
// Try stripping workspace prefix and resolving against allowedFolders
|
|
715
716
|
// e.g., /tmp/visor-workspaces/abc/gateway/file.go → try each folder + gateway/file.go
|
|
716
717
|
for (const folder of options.allowedFolders) {
|
|
717
|
-
const folderPrefix = folder.endsWith(
|
|
718
|
-
const
|
|
718
|
+
const folderPrefix = folder.endsWith(pathSep) ? folder : folder + pathSep;
|
|
719
|
+
const sepEscaped = pathSep === '\\' ? '\\\\' : pathSep;
|
|
720
|
+
const wsParent = folderPrefix.replace(new RegExp('[^' + sepEscaped + ']+' + sepEscaped + '$'), '');
|
|
719
721
|
if (filePart.startsWith(wsParent)) {
|
|
720
722
|
const tail = filePart.slice(wsParent.length);
|
|
721
|
-
const candidate = folderPrefix
|
|
723
|
+
const candidate = pathJoin(folderPrefix, tail);
|
|
722
724
|
if (candidate !== filePart && existsSync(candidate)) {
|
|
723
725
|
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} → ${candidate}`);
|
|
724
726
|
return candidate + suffix;
|
package/cjs/agent/ProbeAgent.cjs
CHANGED
|
@@ -24981,7 +24981,11 @@ async function extractBinary(assetPath, outputDir) {
|
|
|
24981
24981
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
24982
24982
|
console.log(`Extracting zip to ${extractDir}...`);
|
|
24983
24983
|
}
|
|
24984
|
-
|
|
24984
|
+
if (isWindows) {
|
|
24985
|
+
await exec(`powershell -NoProfile -Command "Expand-Archive -Path '${assetPath}' -DestinationPath '${extractDir}' -Force"`);
|
|
24986
|
+
} else {
|
|
24987
|
+
await exec(`unzip -q "${assetPath}" -d "${extractDir}"`);
|
|
24988
|
+
}
|
|
24985
24989
|
} else {
|
|
24986
24990
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
24987
24991
|
console.log(`Copying binary directly to ${binaryPath}`);
|
|
@@ -27789,14 +27793,15 @@ var init_vercel = __esm({
|
|
|
27789
27793
|
const parsedTargets = parseTargets(targets);
|
|
27790
27794
|
extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
27791
27795
|
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
27796
|
+
const { join: pathJoin, sep: pathSep } = await import("path");
|
|
27792
27797
|
extractFiles = extractFiles.map((target) => {
|
|
27793
27798
|
const { filePart, suffix } = splitTargetSuffix(target);
|
|
27794
27799
|
if ((0, import_fs4.existsSync)(filePart)) return target;
|
|
27795
|
-
const cwdPrefix = effectiveCwd.endsWith(
|
|
27800
|
+
const cwdPrefix = effectiveCwd.endsWith(pathSep) ? effectiveCwd : effectiveCwd + pathSep;
|
|
27796
27801
|
const relativePart = filePart.startsWith(cwdPrefix) ? filePart.slice(cwdPrefix.length) : null;
|
|
27797
27802
|
if (relativePart) {
|
|
27798
27803
|
for (const folder of options.allowedFolders) {
|
|
27799
|
-
const candidate = folder
|
|
27804
|
+
const candidate = pathJoin(folder, relativePart);
|
|
27800
27805
|
if ((0, import_fs4.existsSync)(candidate)) {
|
|
27801
27806
|
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} \u2192 ${candidate}`);
|
|
27802
27807
|
return candidate + suffix;
|
|
@@ -27804,11 +27809,12 @@ var init_vercel = __esm({
|
|
|
27804
27809
|
}
|
|
27805
27810
|
}
|
|
27806
27811
|
for (const folder of options.allowedFolders) {
|
|
27807
|
-
const folderPrefix = folder.endsWith(
|
|
27808
|
-
const
|
|
27812
|
+
const folderPrefix = folder.endsWith(pathSep) ? folder : folder + pathSep;
|
|
27813
|
+
const sepEscaped = pathSep === "\\" ? "\\\\" : pathSep;
|
|
27814
|
+
const wsParent = folderPrefix.replace(new RegExp("[^" + sepEscaped + "]+" + sepEscaped + "$"), "");
|
|
27809
27815
|
if (filePart.startsWith(wsParent)) {
|
|
27810
27816
|
const tail = filePart.slice(wsParent.length);
|
|
27811
|
-
const candidate = folderPrefix
|
|
27817
|
+
const candidate = pathJoin(folderPrefix, tail);
|
|
27812
27818
|
if (candidate !== filePart && (0, import_fs4.existsSync)(candidate)) {
|
|
27813
27819
|
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} \u2192 ${candidate}`);
|
|
27814
27820
|
return candidate + suffix;
|
|
@@ -97556,14 +97562,6 @@ var init_FallbackManager = __esm({
|
|
|
97556
97562
|
});
|
|
97557
97563
|
|
|
97558
97564
|
// src/agent/contextCompactor.js
|
|
97559
|
-
var contextCompactor_exports = {};
|
|
97560
|
-
__export(contextCompactor_exports, {
|
|
97561
|
-
calculateCompactionStats: () => calculateCompactionStats,
|
|
97562
|
-
compactMessages: () => compactMessages,
|
|
97563
|
-
handleContextLimitError: () => handleContextLimitError,
|
|
97564
|
-
identifyMessageSegments: () => identifyMessageSegments,
|
|
97565
|
-
isContextLimitError: () => isContextLimitError
|
|
97566
|
-
});
|
|
97567
97565
|
function isContextLimitError(error40) {
|
|
97568
97566
|
if (!error40) return false;
|
|
97569
97567
|
const errorMessage = (typeof error40 === "string" ? error40 : error40?.message || "").toLowerCase();
|
|
@@ -101879,6 +101877,16 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
101879
101877
|
userMessage
|
|
101880
101878
|
];
|
|
101881
101879
|
}
|
|
101880
|
+
if (this.history.length > 0) {
|
|
101881
|
+
const compacted = compactMessages(currentMessages, { keepLastSegment: true, minSegmentsToKeep: 1 });
|
|
101882
|
+
if (compacted.length < currentMessages.length) {
|
|
101883
|
+
const stats = calculateCompactionStats(currentMessages, compacted);
|
|
101884
|
+
if (this.debug) {
|
|
101885
|
+
console.log(`[DEBUG] Proactive history compaction: ${currentMessages.length} \u2192 ${compacted.length} messages (${stats.reductionPercent}% reduction, ~${stats.tokensSaved} tokens saved)`);
|
|
101886
|
+
}
|
|
101887
|
+
currentMessages = compacted;
|
|
101888
|
+
}
|
|
101889
|
+
}
|
|
101882
101890
|
let currentIteration = 0;
|
|
101883
101891
|
let finalResult = "I was unable to complete your request due to reaching the maximum number of tool iterations.";
|
|
101884
101892
|
const baseMaxIterations = options._maxIterationsOverride || this.maxIterations || MAX_TOOL_ITERATIONS;
|
|
@@ -102579,7 +102587,6 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
102579
102587
|
* @returns {Object} Compaction statistics
|
|
102580
102588
|
*/
|
|
102581
102589
|
async compactHistory(options = {}) {
|
|
102582
|
-
const { compactMessages: compactMessages2, calculateCompactionStats: calculateCompactionStats2 } = await Promise.resolve().then(() => (init_contextCompactor(), contextCompactor_exports));
|
|
102583
102590
|
if (this.history.length === 0) {
|
|
102584
102591
|
if (this.debug) {
|
|
102585
102592
|
console.log(`[DEBUG] No history to compact for session ${this.sessionId}`);
|
|
@@ -102594,8 +102601,8 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
102594
102601
|
tokensSaved: 0
|
|
102595
102602
|
};
|
|
102596
102603
|
}
|
|
102597
|
-
const compactedMessages =
|
|
102598
|
-
const stats =
|
|
102604
|
+
const compactedMessages = compactMessages(this.history, options);
|
|
102605
|
+
const stats = calculateCompactionStats(this.history, compactedMessages);
|
|
102599
102606
|
this.history = compactedMessages;
|
|
102600
102607
|
try {
|
|
102601
102608
|
await this.storageAdapter.clearHistory(this.sessionId);
|
package/cjs/index.cjs
CHANGED
|
@@ -1098,7 +1098,11 @@ async function extractBinary(assetPath, outputDir) {
|
|
|
1098
1098
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
1099
1099
|
console.log(`Extracting zip to ${extractDir}...`);
|
|
1100
1100
|
}
|
|
1101
|
-
|
|
1101
|
+
if (isWindows) {
|
|
1102
|
+
await exec(`powershell -NoProfile -Command "Expand-Archive -Path '${assetPath}' -DestinationPath '${extractDir}' -Force"`);
|
|
1103
|
+
} else {
|
|
1104
|
+
await exec(`unzip -q "${assetPath}" -d "${extractDir}"`);
|
|
1105
|
+
}
|
|
1102
1106
|
} else {
|
|
1103
1107
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
1104
1108
|
console.log(`Copying binary directly to ${binaryPath}`);
|
|
@@ -82266,14 +82270,6 @@ var init_FallbackManager = __esm({
|
|
|
82266
82270
|
});
|
|
82267
82271
|
|
|
82268
82272
|
// src/agent/contextCompactor.js
|
|
82269
|
-
var contextCompactor_exports = {};
|
|
82270
|
-
__export(contextCompactor_exports, {
|
|
82271
|
-
calculateCompactionStats: () => calculateCompactionStats,
|
|
82272
|
-
compactMessages: () => compactMessages,
|
|
82273
|
-
handleContextLimitError: () => handleContextLimitError,
|
|
82274
|
-
identifyMessageSegments: () => identifyMessageSegments,
|
|
82275
|
-
isContextLimitError: () => isContextLimitError
|
|
82276
|
-
});
|
|
82277
82273
|
function isContextLimitError(error40) {
|
|
82278
82274
|
if (!error40) return false;
|
|
82279
82275
|
const errorMessage = (typeof error40 === "string" ? error40 : error40?.message || "").toLowerCase();
|
|
@@ -98870,6 +98866,16 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
98870
98866
|
userMessage
|
|
98871
98867
|
];
|
|
98872
98868
|
}
|
|
98869
|
+
if (this.history.length > 0) {
|
|
98870
|
+
const compacted = compactMessages(currentMessages, { keepLastSegment: true, minSegmentsToKeep: 1 });
|
|
98871
|
+
if (compacted.length < currentMessages.length) {
|
|
98872
|
+
const stats = calculateCompactionStats(currentMessages, compacted);
|
|
98873
|
+
if (this.debug) {
|
|
98874
|
+
console.log(`[DEBUG] Proactive history compaction: ${currentMessages.length} \u2192 ${compacted.length} messages (${stats.reductionPercent}% reduction, ~${stats.tokensSaved} tokens saved)`);
|
|
98875
|
+
}
|
|
98876
|
+
currentMessages = compacted;
|
|
98877
|
+
}
|
|
98878
|
+
}
|
|
98873
98879
|
let currentIteration = 0;
|
|
98874
98880
|
let finalResult = "I was unable to complete your request due to reaching the maximum number of tool iterations.";
|
|
98875
98881
|
const baseMaxIterations = options._maxIterationsOverride || this.maxIterations || MAX_TOOL_ITERATIONS;
|
|
@@ -99570,7 +99576,6 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
99570
99576
|
* @returns {Object} Compaction statistics
|
|
99571
99577
|
*/
|
|
99572
99578
|
async compactHistory(options = {}) {
|
|
99573
|
-
const { compactMessages: compactMessages2, calculateCompactionStats: calculateCompactionStats2 } = await Promise.resolve().then(() => (init_contextCompactor(), contextCompactor_exports));
|
|
99574
99579
|
if (this.history.length === 0) {
|
|
99575
99580
|
if (this.debug) {
|
|
99576
99581
|
console.log(`[DEBUG] No history to compact for session ${this.sessionId}`);
|
|
@@ -99585,8 +99590,8 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
99585
99590
|
tokensSaved: 0
|
|
99586
99591
|
};
|
|
99587
99592
|
}
|
|
99588
|
-
const compactedMessages =
|
|
99589
|
-
const stats =
|
|
99593
|
+
const compactedMessages = compactMessages(this.history, options);
|
|
99594
|
+
const stats = calculateCompactionStats(this.history, compactedMessages);
|
|
99590
99595
|
this.history = compactedMessages;
|
|
99591
99596
|
try {
|
|
99592
99597
|
await this.storageAdapter.clearHistory(this.sessionId);
|
|
@@ -101405,14 +101410,15 @@ var init_vercel = __esm({
|
|
|
101405
101410
|
const parsedTargets = parseTargets(targets);
|
|
101406
101411
|
extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
101407
101412
|
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
101413
|
+
const { join: pathJoin, sep: pathSep } = await import("path");
|
|
101408
101414
|
extractFiles = extractFiles.map((target) => {
|
|
101409
101415
|
const { filePart, suffix } = splitTargetSuffix(target);
|
|
101410
101416
|
if ((0, import_fs11.existsSync)(filePart)) return target;
|
|
101411
|
-
const cwdPrefix = effectiveCwd.endsWith(
|
|
101417
|
+
const cwdPrefix = effectiveCwd.endsWith(pathSep) ? effectiveCwd : effectiveCwd + pathSep;
|
|
101412
101418
|
const relativePart = filePart.startsWith(cwdPrefix) ? filePart.slice(cwdPrefix.length) : null;
|
|
101413
101419
|
if (relativePart) {
|
|
101414
101420
|
for (const folder of options.allowedFolders) {
|
|
101415
|
-
const candidate = folder
|
|
101421
|
+
const candidate = pathJoin(folder, relativePart);
|
|
101416
101422
|
if ((0, import_fs11.existsSync)(candidate)) {
|
|
101417
101423
|
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} \u2192 ${candidate}`);
|
|
101418
101424
|
return candidate + suffix;
|
|
@@ -101420,11 +101426,12 @@ var init_vercel = __esm({
|
|
|
101420
101426
|
}
|
|
101421
101427
|
}
|
|
101422
101428
|
for (const folder of options.allowedFolders) {
|
|
101423
|
-
const folderPrefix = folder.endsWith(
|
|
101424
|
-
const
|
|
101429
|
+
const folderPrefix = folder.endsWith(pathSep) ? folder : folder + pathSep;
|
|
101430
|
+
const sepEscaped = pathSep === "\\" ? "\\\\" : pathSep;
|
|
101431
|
+
const wsParent = folderPrefix.replace(new RegExp("[^" + sepEscaped + "]+" + sepEscaped + "$"), "");
|
|
101425
101432
|
if (filePart.startsWith(wsParent)) {
|
|
101426
101433
|
const tail = filePart.slice(wsParent.length);
|
|
101427
|
-
const candidate = folderPrefix
|
|
101434
|
+
const candidate = pathJoin(folderPrefix, tail);
|
|
101428
101435
|
if (candidate !== filePart && (0, import_fs11.existsSync)(candidate)) {
|
|
101429
101436
|
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} \u2192 ${candidate}`);
|
|
101430
101437
|
return candidate + suffix;
|
package/package.json
CHANGED
package/src/agent/ProbeAgent.js
CHANGED
|
@@ -93,7 +93,7 @@ import { formatAvailableSkillsXml as formatAvailableSkills } from './skills/form
|
|
|
93
93
|
import { createSkillToolInstances } from './skills/tools.js';
|
|
94
94
|
import { RetryManager, createRetryManagerFromEnv } from './RetryManager.js';
|
|
95
95
|
import { FallbackManager, createFallbackManagerFromEnv, buildFallbackProvidersFromEnv } from './FallbackManager.js';
|
|
96
|
-
import { handleContextLimitError } from './contextCompactor.js';
|
|
96
|
+
import { handleContextLimitError, compactMessages, calculateCompactionStats } from './contextCompactor.js';
|
|
97
97
|
import { formatErrorForAI, ParameterError } from '../utils/error-types.js';
|
|
98
98
|
import { getCommonPrefix, toRelativePath, safeRealpath } from '../utils/path-validation.js';
|
|
99
99
|
import { truncateIfNeeded, getMaxOutputTokens } from './outputTruncator.js';
|
|
@@ -3227,6 +3227,25 @@ Follow these instructions carefully:
|
|
|
3227
3227
|
];
|
|
3228
3228
|
}
|
|
3229
3229
|
|
|
3230
|
+
// Proactively compact for multi-turn conversations.
|
|
3231
|
+
// On turn 2+, previous turns contain full tool call/result history which can
|
|
3232
|
+
// be 50K+ tokens. This drowns out the new user message and causes the model to
|
|
3233
|
+
// focus on prior context rather than the new question.
|
|
3234
|
+
// compactMessages strips intermediate monologue from completed segments,
|
|
3235
|
+
// keeping user messages + final answers from prior turns.
|
|
3236
|
+
// Must run AFTER adding the new user message so the compactor sees 2+ segments
|
|
3237
|
+
// (completed prior turns + the new incomplete turn), preserving the latest segment.
|
|
3238
|
+
if (this.history.length > 0) {
|
|
3239
|
+
const compacted = compactMessages(currentMessages, { keepLastSegment: true, minSegmentsToKeep: 1 });
|
|
3240
|
+
if (compacted.length < currentMessages.length) {
|
|
3241
|
+
const stats = calculateCompactionStats(currentMessages, compacted);
|
|
3242
|
+
if (this.debug) {
|
|
3243
|
+
console.log(`[DEBUG] Proactive history compaction: ${currentMessages.length} → ${compacted.length} messages (${stats.reductionPercent}% reduction, ~${stats.tokensSaved} tokens saved)`);
|
|
3244
|
+
}
|
|
3245
|
+
currentMessages = compacted;
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3230
3249
|
let currentIteration = 0;
|
|
3231
3250
|
let finalResult = 'I was unable to complete your request due to reaching the maximum number of tool iterations.';
|
|
3232
3251
|
|
|
@@ -4141,8 +4160,6 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
4141
4160
|
* @returns {Object} Compaction statistics
|
|
4142
4161
|
*/
|
|
4143
4162
|
async compactHistory(options = {}) {
|
|
4144
|
-
const { compactMessages, calculateCompactionStats } = await import('./contextCompactor.js');
|
|
4145
|
-
|
|
4146
4163
|
if (this.history.length === 0) {
|
|
4147
4164
|
if (this.debug) {
|
|
4148
4165
|
console.log(`[DEBUG] No history to compact for session ${this.sessionId}`);
|
package/src/downloader.js
CHANGED
|
@@ -743,7 +743,11 @@ async function extractBinary(assetPath, outputDir) {
|
|
|
743
743
|
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
|
744
744
|
console.log(`Extracting zip to ${extractDir}...`);
|
|
745
745
|
}
|
|
746
|
-
|
|
746
|
+
if (isWindows) {
|
|
747
|
+
await exec(`powershell -NoProfile -Command "Expand-Archive -Path '${assetPath}' -DestinationPath '${extractDir}' -Force"`);
|
|
748
|
+
} else {
|
|
749
|
+
await exec(`unzip -q "${assetPath}" -d "${extractDir}"`);
|
|
750
|
+
}
|
|
747
751
|
} else {
|
|
748
752
|
// Assume it's a direct binary
|
|
749
753
|
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
package/src/tools/vercel.js
CHANGED
|
@@ -691,19 +691,20 @@ export const extractTool = (options = {}) => {
|
|
|
691
691
|
// model constructs wrong absolute paths (e.g., /workspace/gateway/file.go
|
|
692
692
|
// instead of /workspace/tyk/gateway/file.go)
|
|
693
693
|
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
694
|
+
const { join: pathJoin, sep: pathSep } = await import('path');
|
|
694
695
|
extractFiles = extractFiles.map(target => {
|
|
695
696
|
const { filePart, suffix } = splitTargetSuffix(target);
|
|
696
697
|
if (existsSync(filePart)) return target;
|
|
697
698
|
|
|
698
699
|
// Try resolving the relative tail against each allowedFolder
|
|
699
|
-
const cwdPrefix =
|
|
700
|
+
const cwdPrefix = effectiveCwd.endsWith(pathSep) ? effectiveCwd : effectiveCwd + pathSep;
|
|
700
701
|
const relativePart = filePart.startsWith(cwdPrefix)
|
|
701
702
|
? filePart.slice(cwdPrefix.length)
|
|
702
703
|
: null;
|
|
703
704
|
|
|
704
705
|
if (relativePart) {
|
|
705
706
|
for (const folder of options.allowedFolders) {
|
|
706
|
-
const candidate = folder
|
|
707
|
+
const candidate = pathJoin(folder, relativePart);
|
|
707
708
|
if (existsSync(candidate)) {
|
|
708
709
|
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} → ${candidate}`);
|
|
709
710
|
return candidate + suffix;
|
|
@@ -714,11 +715,12 @@ export const extractTool = (options = {}) => {
|
|
|
714
715
|
// Try stripping workspace prefix and resolving against allowedFolders
|
|
715
716
|
// e.g., /tmp/visor-workspaces/abc/gateway/file.go → try each folder + gateway/file.go
|
|
716
717
|
for (const folder of options.allowedFolders) {
|
|
717
|
-
const folderPrefix = folder.endsWith(
|
|
718
|
-
const
|
|
718
|
+
const folderPrefix = folder.endsWith(pathSep) ? folder : folder + pathSep;
|
|
719
|
+
const sepEscaped = pathSep === '\\' ? '\\\\' : pathSep;
|
|
720
|
+
const wsParent = folderPrefix.replace(new RegExp('[^' + sepEscaped + ']+' + sepEscaped + '$'), '');
|
|
719
721
|
if (filePart.startsWith(wsParent)) {
|
|
720
722
|
const tail = filePart.slice(wsParent.length);
|
|
721
|
-
const candidate = folderPrefix
|
|
723
|
+
const candidate = pathJoin(folderPrefix, tail);
|
|
722
724
|
if (candidate !== filePart && existsSync(candidate)) {
|
|
723
725
|
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} → ${candidate}`);
|
|
724
726
|
return candidate + suffix;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|