@probelabs/probe 0.6.0-rc208 → 0.6.0-rc210
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-rc210-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc210-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc210-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc210-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc210-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.d.ts +4 -2
- package/build/agent/ProbeAgent.js +87 -5
- package/build/agent/bashCommandUtils.js +98 -12
- package/build/agent/bashPermissions.js +207 -1
- package/build/agent/index.js +283 -23
- package/build/agent/mcp/client.js +2 -1
- package/build/delegate.js +11 -2
- package/build/tools/vercel.js +5 -2
- package/cjs/agent/ProbeAgent.cjs +277 -17
- package/cjs/index.cjs +277 -17
- package/index.d.ts +4 -2
- package/package.json +1 -1
- package/src/agent/ProbeAgent.d.ts +4 -2
- package/src/agent/ProbeAgent.js +87 -5
- package/src/agent/bashCommandUtils.js +98 -12
- package/src/agent/bashPermissions.js +207 -1
- package/src/agent/index.js +5 -5
- package/src/agent/mcp/client.js +2 -1
- package/src/delegate.js +11 -2
- package/src/tools/vercel.js +5 -2
- package/bin/binaries/probe-v0.6.0-rc208-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc208-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc208-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc208-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc208-x86_64-unknown-linux-musl.tar.gz +0 -0
package/cjs/agent/ProbeAgent.cjs
CHANGED
|
@@ -30711,7 +30711,10 @@ async function delegate({
|
|
|
30711
30711
|
disableTools = false,
|
|
30712
30712
|
searchDelegate = void 0,
|
|
30713
30713
|
schema = null,
|
|
30714
|
-
enableTasks = false
|
|
30714
|
+
enableTasks = false,
|
|
30715
|
+
enableMcp = false,
|
|
30716
|
+
mcpConfig = null,
|
|
30717
|
+
mcpConfigPath = null
|
|
30715
30718
|
}) {
|
|
30716
30719
|
if (!task || typeof task !== "string") {
|
|
30717
30720
|
throw new Error("Task parameter is required and must be a string");
|
|
@@ -30767,8 +30770,14 @@ async function delegate({
|
|
|
30767
30770
|
allowedTools,
|
|
30768
30771
|
disableTools,
|
|
30769
30772
|
searchDelegate,
|
|
30770
|
-
enableTasks
|
|
30773
|
+
enableTasks,
|
|
30771
30774
|
// Inherit from parent (subagent gets isolated TaskManager)
|
|
30775
|
+
enableMcp,
|
|
30776
|
+
// Inherit from parent (subagent creates own MCPXmlBridge)
|
|
30777
|
+
mcpConfig,
|
|
30778
|
+
// Inherit from parent
|
|
30779
|
+
mcpConfigPath
|
|
30780
|
+
// Inherit from parent
|
|
30772
30781
|
});
|
|
30773
30782
|
if (debug) {
|
|
30774
30783
|
console.error(`[DELEGATE] Created subagent with session ${sessionId}`);
|
|
@@ -36739,7 +36748,7 @@ var init_vercel = __esm({
|
|
|
36739
36748
|
});
|
|
36740
36749
|
};
|
|
36741
36750
|
delegateTool = (options = {}) => {
|
|
36742
|
-
const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName } = options;
|
|
36751
|
+
const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null } = options;
|
|
36743
36752
|
return (0, import_ai2.tool)({
|
|
36744
36753
|
name: "delegate",
|
|
36745
36754
|
description: delegateDescription,
|
|
@@ -36798,7 +36807,10 @@ var init_vercel = __esm({
|
|
|
36798
36807
|
enableBash,
|
|
36799
36808
|
bashConfig,
|
|
36800
36809
|
architectureFileName,
|
|
36801
|
-
searchDelegate
|
|
36810
|
+
searchDelegate,
|
|
36811
|
+
enableMcp,
|
|
36812
|
+
mcpConfig,
|
|
36813
|
+
mcpConfigPath
|
|
36802
36814
|
});
|
|
36803
36815
|
return result;
|
|
36804
36816
|
}
|
|
@@ -37325,6 +37337,38 @@ function parseSimpleCommand(command) {
|
|
|
37325
37337
|
isComplex: false
|
|
37326
37338
|
};
|
|
37327
37339
|
}
|
|
37340
|
+
const stripQuotedContent = (str) => {
|
|
37341
|
+
let result = "";
|
|
37342
|
+
let inQuotes2 = false;
|
|
37343
|
+
let quoteChar2 = "";
|
|
37344
|
+
for (let i4 = 0; i4 < str.length; i4++) {
|
|
37345
|
+
const char = str[i4];
|
|
37346
|
+
const nextChar = str[i4 + 1];
|
|
37347
|
+
if (!inQuotes2 && char === "\\" && nextChar !== void 0) {
|
|
37348
|
+
i4++;
|
|
37349
|
+
continue;
|
|
37350
|
+
}
|
|
37351
|
+
if (inQuotes2 && quoteChar2 === '"' && char === "\\" && nextChar !== void 0) {
|
|
37352
|
+
i4++;
|
|
37353
|
+
continue;
|
|
37354
|
+
}
|
|
37355
|
+
if (!inQuotes2 && (char === '"' || char === "'")) {
|
|
37356
|
+
inQuotes2 = true;
|
|
37357
|
+
quoteChar2 = char;
|
|
37358
|
+
continue;
|
|
37359
|
+
}
|
|
37360
|
+
if (inQuotes2 && char === quoteChar2) {
|
|
37361
|
+
inQuotes2 = false;
|
|
37362
|
+
quoteChar2 = "";
|
|
37363
|
+
continue;
|
|
37364
|
+
}
|
|
37365
|
+
if (!inQuotes2) {
|
|
37366
|
+
result += char;
|
|
37367
|
+
}
|
|
37368
|
+
}
|
|
37369
|
+
return result;
|
|
37370
|
+
};
|
|
37371
|
+
const strippedForOperators = stripQuotedContent(trimmed);
|
|
37328
37372
|
const complexPatterns = [
|
|
37329
37373
|
/\|/,
|
|
37330
37374
|
// Pipes
|
|
@@ -37350,7 +37394,7 @@ function parseSimpleCommand(command) {
|
|
|
37350
37394
|
// Brace expansion like {a,b} or {1..10} (but not find {} placeholders)
|
|
37351
37395
|
];
|
|
37352
37396
|
for (const pattern of complexPatterns) {
|
|
37353
|
-
if (pattern.test(
|
|
37397
|
+
if (pattern.test(strippedForOperators)) {
|
|
37354
37398
|
return {
|
|
37355
37399
|
success: false,
|
|
37356
37400
|
error: "Complex shell commands with pipes, operators, or redirections are not supported for security reasons",
|
|
@@ -37365,17 +37409,17 @@ function parseSimpleCommand(command) {
|
|
|
37365
37409
|
let current = "";
|
|
37366
37410
|
let inQuotes = false;
|
|
37367
37411
|
let quoteChar = "";
|
|
37368
|
-
let escaped = false;
|
|
37369
37412
|
for (let i4 = 0; i4 < trimmed.length; i4++) {
|
|
37370
37413
|
const char = trimmed[i4];
|
|
37371
37414
|
const nextChar = i4 + 1 < trimmed.length ? trimmed[i4 + 1] : "";
|
|
37372
|
-
if (
|
|
37373
|
-
current +=
|
|
37374
|
-
|
|
37415
|
+
if (!inQuotes && char === "\\" && nextChar) {
|
|
37416
|
+
current += nextChar;
|
|
37417
|
+
i4++;
|
|
37375
37418
|
continue;
|
|
37376
37419
|
}
|
|
37377
|
-
if (char === "\\" &&
|
|
37378
|
-
|
|
37420
|
+
if (inQuotes && quoteChar === '"' && char === "\\" && nextChar) {
|
|
37421
|
+
current += nextChar;
|
|
37422
|
+
i4++;
|
|
37379
37423
|
continue;
|
|
37380
37424
|
}
|
|
37381
37425
|
if (!inQuotes && (char === '"' || char === "'")) {
|
|
@@ -37708,8 +37752,97 @@ var init_bashPermissions = __esm({
|
|
|
37708
37752
|
});
|
|
37709
37753
|
return result;
|
|
37710
37754
|
}
|
|
37755
|
+
/**
|
|
37756
|
+
* Split a complex command into component commands by operators
|
|
37757
|
+
*
|
|
37758
|
+
* ## Escape Handling (Security-Critical)
|
|
37759
|
+
*
|
|
37760
|
+
* This function intentionally PRESERVES escape sequences (both backslash AND
|
|
37761
|
+
* escaped character) in the output. This is step 1 of a 2-step parsing process:
|
|
37762
|
+
*
|
|
37763
|
+
* 1. _splitComplexCommand: Splits by operators, PRESERVES escapes → `echo "test\" && b"`
|
|
37764
|
+
* 2. parseCommand: Interprets escapes in each component → args: ['test" && b']
|
|
37765
|
+
*
|
|
37766
|
+
* This differs from stripQuotedContent() in bashCommandUtils.js which REMOVES
|
|
37767
|
+
* escapes entirely (for operator detection only).
|
|
37768
|
+
*
|
|
37769
|
+
* The security rationale: if we stripped escapes here, `\"` would become `"`,
|
|
37770
|
+
* potentially causing incorrect quote boundary detection and allowing operator
|
|
37771
|
+
* injection. By preserving escapes, parseCommand() can correctly interpret them.
|
|
37772
|
+
*
|
|
37773
|
+
* See bashCommandUtils.js module header for the full escape handling architecture.
|
|
37774
|
+
*
|
|
37775
|
+
* @private
|
|
37776
|
+
* @param {string} command - Complex command to split
|
|
37777
|
+
* @returns {string[]} Array of component commands (with escapes preserved)
|
|
37778
|
+
*/
|
|
37779
|
+
_splitComplexCommand(command) {
|
|
37780
|
+
const components = [];
|
|
37781
|
+
let current = "";
|
|
37782
|
+
let inQuotes = false;
|
|
37783
|
+
let quoteChar = "";
|
|
37784
|
+
let i4 = 0;
|
|
37785
|
+
while (i4 < command.length) {
|
|
37786
|
+
const char = command[i4];
|
|
37787
|
+
const nextChar = command[i4 + 1] || "";
|
|
37788
|
+
if (!inQuotes && char === "\\") {
|
|
37789
|
+
current += char;
|
|
37790
|
+
if (nextChar) {
|
|
37791
|
+
current += nextChar;
|
|
37792
|
+
i4 += 2;
|
|
37793
|
+
} else {
|
|
37794
|
+
i4++;
|
|
37795
|
+
}
|
|
37796
|
+
continue;
|
|
37797
|
+
}
|
|
37798
|
+
if (inQuotes && quoteChar === '"' && char === "\\" && nextChar) {
|
|
37799
|
+
current += char + nextChar;
|
|
37800
|
+
i4 += 2;
|
|
37801
|
+
continue;
|
|
37802
|
+
}
|
|
37803
|
+
if (!inQuotes && (char === '"' || char === "'")) {
|
|
37804
|
+
inQuotes = true;
|
|
37805
|
+
quoteChar = char;
|
|
37806
|
+
current += char;
|
|
37807
|
+
i4++;
|
|
37808
|
+
continue;
|
|
37809
|
+
}
|
|
37810
|
+
if (inQuotes && char === quoteChar) {
|
|
37811
|
+
inQuotes = false;
|
|
37812
|
+
quoteChar = "";
|
|
37813
|
+
current += char;
|
|
37814
|
+
i4++;
|
|
37815
|
+
continue;
|
|
37816
|
+
}
|
|
37817
|
+
if (!inQuotes) {
|
|
37818
|
+
if (char === "&" && nextChar === "&" || char === "|" && nextChar === "|") {
|
|
37819
|
+
if (current.trim()) {
|
|
37820
|
+
components.push(current.trim());
|
|
37821
|
+
}
|
|
37822
|
+
current = "";
|
|
37823
|
+
i4 += 2;
|
|
37824
|
+
continue;
|
|
37825
|
+
}
|
|
37826
|
+
if (char === "|") {
|
|
37827
|
+
if (current.trim()) {
|
|
37828
|
+
components.push(current.trim());
|
|
37829
|
+
}
|
|
37830
|
+
current = "";
|
|
37831
|
+
i4++;
|
|
37832
|
+
continue;
|
|
37833
|
+
}
|
|
37834
|
+
}
|
|
37835
|
+
current += char;
|
|
37836
|
+
i4++;
|
|
37837
|
+
}
|
|
37838
|
+
if (current.trim()) {
|
|
37839
|
+
components.push(current.trim());
|
|
37840
|
+
}
|
|
37841
|
+
return components;
|
|
37842
|
+
}
|
|
37711
37843
|
/**
|
|
37712
37844
|
* Check a complex command against complex patterns in allow/deny lists
|
|
37845
|
+
* Also supports auto-allowing commands where all components are individually allowed
|
|
37713
37846
|
* @private
|
|
37714
37847
|
* @param {string} command - Complex command to check
|
|
37715
37848
|
* @returns {Object} Permission result
|
|
@@ -37764,6 +37897,85 @@ var init_bashPermissions = __esm({
|
|
|
37764
37897
|
return result;
|
|
37765
37898
|
}
|
|
37766
37899
|
}
|
|
37900
|
+
const components = this._splitComplexCommand(command);
|
|
37901
|
+
if (this.debug) {
|
|
37902
|
+
console.log(`[BashPermissions] Checking ${components.length} command components: ${JSON.stringify(components)}`);
|
|
37903
|
+
}
|
|
37904
|
+
if (components.length > 1) {
|
|
37905
|
+
const componentResults = [];
|
|
37906
|
+
let allAllowed = true;
|
|
37907
|
+
let deniedComponent = null;
|
|
37908
|
+
let deniedReason = null;
|
|
37909
|
+
for (const component of components) {
|
|
37910
|
+
const parsed = parseCommand(component);
|
|
37911
|
+
if (parsed.error || parsed.isComplex) {
|
|
37912
|
+
if (this.debug) {
|
|
37913
|
+
console.log(`[BashPermissions] Component "${component}" is complex or has error: ${parsed.error}`);
|
|
37914
|
+
}
|
|
37915
|
+
allAllowed = false;
|
|
37916
|
+
deniedComponent = component;
|
|
37917
|
+
deniedReason = parsed.error || "Component contains nested complex constructs";
|
|
37918
|
+
break;
|
|
37919
|
+
}
|
|
37920
|
+
if (matchesAnyPattern(parsed, this.denyPatterns)) {
|
|
37921
|
+
if (this.debug) {
|
|
37922
|
+
console.log(`[BashPermissions] Component "${component}" matches deny pattern`);
|
|
37923
|
+
}
|
|
37924
|
+
allAllowed = false;
|
|
37925
|
+
deniedComponent = component;
|
|
37926
|
+
deniedReason = "Component matches deny pattern";
|
|
37927
|
+
break;
|
|
37928
|
+
}
|
|
37929
|
+
if (!matchesAnyPattern(parsed, this.allowPatterns)) {
|
|
37930
|
+
if (this.debug) {
|
|
37931
|
+
console.log(`[BashPermissions] Component "${component}" not in allow list`);
|
|
37932
|
+
}
|
|
37933
|
+
allAllowed = false;
|
|
37934
|
+
deniedComponent = component;
|
|
37935
|
+
deniedReason = "Component not in allow list";
|
|
37936
|
+
break;
|
|
37937
|
+
}
|
|
37938
|
+
componentResults.push({ component, parsed, allowed: true });
|
|
37939
|
+
}
|
|
37940
|
+
if (allAllowed) {
|
|
37941
|
+
if (this.debug) {
|
|
37942
|
+
console.log(`[BashPermissions] ALLOWED - all ${components.length} components passed individual checks`);
|
|
37943
|
+
}
|
|
37944
|
+
const result = {
|
|
37945
|
+
allowed: true,
|
|
37946
|
+
command,
|
|
37947
|
+
isComplex: true,
|
|
37948
|
+
allowedByComponents: true,
|
|
37949
|
+
components: componentResults
|
|
37950
|
+
};
|
|
37951
|
+
this.recordBashEvent("permission.allowed", {
|
|
37952
|
+
command,
|
|
37953
|
+
isComplex: true,
|
|
37954
|
+
allowedByComponents: true,
|
|
37955
|
+
componentCount: components.length
|
|
37956
|
+
});
|
|
37957
|
+
return result;
|
|
37958
|
+
} else {
|
|
37959
|
+
if (this.debug) {
|
|
37960
|
+
console.log(`[BashPermissions] DENIED - component "${deniedComponent}" failed: ${deniedReason}`);
|
|
37961
|
+
}
|
|
37962
|
+
const result = {
|
|
37963
|
+
allowed: false,
|
|
37964
|
+
reason: `Component "${deniedComponent}" not allowed: ${deniedReason}`,
|
|
37965
|
+
command,
|
|
37966
|
+
isComplex: true,
|
|
37967
|
+
failedComponent: deniedComponent
|
|
37968
|
+
};
|
|
37969
|
+
this.recordBashEvent("permission.denied", {
|
|
37970
|
+
command,
|
|
37971
|
+
reason: "component_not_allowed",
|
|
37972
|
+
failedComponent: deniedComponent,
|
|
37973
|
+
componentReason: deniedReason,
|
|
37974
|
+
isComplex: true
|
|
37975
|
+
});
|
|
37976
|
+
return result;
|
|
37977
|
+
}
|
|
37978
|
+
}
|
|
37767
37979
|
if (this.debug) {
|
|
37768
37980
|
console.log(`[BashPermissions] DENIED - no matching complex pattern found`);
|
|
37769
37981
|
}
|
|
@@ -85275,7 +85487,7 @@ var init_client2 = __esm({
|
|
|
85275
85487
|
clientInfo.client.callTool({
|
|
85276
85488
|
name: tool4.originalName,
|
|
85277
85489
|
arguments: args
|
|
85278
|
-
}),
|
|
85490
|
+
}, void 0, { timeout }),
|
|
85279
85491
|
timeoutPromise
|
|
85280
85492
|
]);
|
|
85281
85493
|
const durationMs = Date.now() - startTime;
|
|
@@ -95829,7 +96041,7 @@ var init_ProbeAgent = __esm({
|
|
|
95829
96041
|
this.maxIterations = options.maxIterations || null;
|
|
95830
96042
|
this.disableMermaidValidation = !!options.disableMermaidValidation;
|
|
95831
96043
|
this.disableJsonValidation = !!options.disableJsonValidation;
|
|
95832
|
-
this.enableSkills = options.disableSkills ? false : options.
|
|
96044
|
+
this.enableSkills = options.disableSkills ? false : !!(options.allowSkills || options.enableSkills);
|
|
95833
96045
|
if (Array.isArray(options.skillDirs)) {
|
|
95834
96046
|
this.skillDirs = options.skillDirs;
|
|
95835
96047
|
} else if (typeof options.skillDirs === "string") {
|
|
@@ -97724,6 +97936,9 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
97724
97936
|
let lastFormatErrorType = null;
|
|
97725
97937
|
let sameFormatErrorCount = 0;
|
|
97726
97938
|
const MAX_REPEATED_FORMAT_ERRORS = 3;
|
|
97939
|
+
let lastNoToolResponse = null;
|
|
97940
|
+
let sameResponseCount = 0;
|
|
97941
|
+
const MAX_REPEATED_IDENTICAL_RESPONSES = 3;
|
|
97727
97942
|
while (currentIteration < maxIterations && !completionAttempted) {
|
|
97728
97943
|
currentIteration++;
|
|
97729
97944
|
if (this.cancelled) throw new Error("Request was cancelled by the user");
|
|
@@ -98205,6 +98420,26 @@ ${errorXml}
|
|
|
98205
98420
|
}
|
|
98206
98421
|
break;
|
|
98207
98422
|
}
|
|
98423
|
+
if (lastNoToolResponse !== null && assistantResponseContent === lastNoToolResponse) {
|
|
98424
|
+
sameResponseCount++;
|
|
98425
|
+
if (sameResponseCount >= MAX_REPEATED_IDENTICAL_RESPONSES) {
|
|
98426
|
+
let cleanedResponse = assistantResponseContent;
|
|
98427
|
+
cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "").trim();
|
|
98428
|
+
cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*$/gi, "").trim();
|
|
98429
|
+
const hasSubstantialContent = cleanedResponse.length > 50 && !cleanedResponse.includes("<api_call>") && !cleanedResponse.includes("<tool_name>") && !cleanedResponse.includes("<function>");
|
|
98430
|
+
if (hasSubstantialContent) {
|
|
98431
|
+
if (this.debug) {
|
|
98432
|
+
console.log(`[DEBUG] Same response repeated ${sameResponseCount} times - accepting as final answer (${cleanedResponse.length} chars)`);
|
|
98433
|
+
}
|
|
98434
|
+
finalResult = cleanedResponse;
|
|
98435
|
+
completionAttempted = true;
|
|
98436
|
+
break;
|
|
98437
|
+
}
|
|
98438
|
+
}
|
|
98439
|
+
} else {
|
|
98440
|
+
lastNoToolResponse = assistantResponseContent;
|
|
98441
|
+
sameResponseCount = 1;
|
|
98442
|
+
}
|
|
98208
98443
|
currentMessages.push({ role: "assistant", content: assistantResponseContent });
|
|
98209
98444
|
const unrecognizedTool = detectUnrecognizedToolCall(assistantResponseContent, validTools);
|
|
98210
98445
|
let reminderContent;
|
|
@@ -98277,10 +98512,35 @@ Or if your previous response already contains a complete, direct answer (not a t
|
|
|
98277
98512
|
|
|
98278
98513
|
Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant message as the final answer. Only use this if that message was already a valid, complete response to the user's question.`;
|
|
98279
98514
|
}
|
|
98280
|
-
currentMessages.
|
|
98281
|
-
|
|
98282
|
-
|
|
98283
|
-
|
|
98515
|
+
const prevUserMsgIndex = currentMessages.length - 2;
|
|
98516
|
+
const prevUserMsg = currentMessages[prevUserMsgIndex];
|
|
98517
|
+
const isExistingReminder = prevUserMsg && prevUserMsg.role === "user" && (prevUserMsg.content.includes("Please use one of the available tools") || prevUserMsg.content.includes("<tool_result>"));
|
|
98518
|
+
if (isExistingReminder && sameResponseCount > 1) {
|
|
98519
|
+
const prevAssistantIndex = prevUserMsgIndex - 1;
|
|
98520
|
+
const hasSystemMessage2 = currentMessages.length > 0 && currentMessages[0].role === "system";
|
|
98521
|
+
const minValidIndex = hasSystemMessage2 ? 1 : 0;
|
|
98522
|
+
const canSafelyRemove = prevAssistantIndex >= minValidIndex && currentMessages[prevAssistantIndex] && currentMessages[prevAssistantIndex].role === "assistant" && currentMessages.length - 2 >= (hasSystemMessage2 ? 2 : 1);
|
|
98523
|
+
if (canSafelyRemove) {
|
|
98524
|
+
currentMessages.splice(prevAssistantIndex, 2);
|
|
98525
|
+
if (this.debug) {
|
|
98526
|
+
console.log(`[DEBUG] Removed duplicate assistant+reminder pair (iteration ${currentIteration}, same response #${sameResponseCount})`);
|
|
98527
|
+
}
|
|
98528
|
+
} else if (this.debug) {
|
|
98529
|
+
console.log(`[DEBUG] Skipped deduplication: pattern validation failed (prevAssistantIndex=${prevAssistantIndex}, arrayLength=${currentMessages.length})`);
|
|
98530
|
+
}
|
|
98531
|
+
const iterationHint = `
|
|
98532
|
+
|
|
98533
|
+
(Attempt #${sameResponseCount}: Your previous ${sameResponseCount} responses were identical. If you have a complete answer, use <attempt_complete></attempt_complete> to finalize it.)`;
|
|
98534
|
+
currentMessages.push({
|
|
98535
|
+
role: "user",
|
|
98536
|
+
content: reminderContent + iterationHint
|
|
98537
|
+
});
|
|
98538
|
+
} else {
|
|
98539
|
+
currentMessages.push({
|
|
98540
|
+
role: "user",
|
|
98541
|
+
content: reminderContent
|
|
98542
|
+
});
|
|
98543
|
+
}
|
|
98284
98544
|
if (this.debug) {
|
|
98285
98545
|
if (unrecognizedTool) {
|
|
98286
98546
|
console.log(`[DEBUG] Unrecognized tool '${unrecognizedTool}' used. Providing error feedback.`);
|