@probelabs/probe 0.6.0-rc206 → 0.6.0-rc208
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-rc206-aarch64-apple-darwin.tar.gz → 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/build/agent/ProbeAgent.js +144 -2
- package/build/agent/bashPermissions.js +88 -7
- package/build/agent/index.js +450 -18
- package/build/agent/mcp/client.js +234 -4
- package/build/agent/mcp/config.js +87 -0
- package/build/agent/mcp/xmlBridge.js +15 -5
- package/build/agent/simpleTelemetry.js +26 -0
- package/build/tools/bash.js +5 -3
- package/build/tools/common.js +31 -0
- package/cjs/agent/ProbeAgent.cjs +428 -18
- package/cjs/agent/simpleTelemetry.cjs +22 -0
- package/cjs/index.cjs +450 -18
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +144 -2
- package/src/agent/bashPermissions.js +88 -7
- package/src/agent/mcp/client.js +234 -4
- package/src/agent/mcp/config.js +87 -0
- package/src/agent/mcp/xmlBridge.js +15 -5
- package/src/agent/simpleTelemetry.js +26 -0
- package/src/tools/bash.js +5 -3
- package/src/tools/common.js +31 -0
- package/bin/binaries/probe-v0.6.0-rc206-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc206-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc206-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc206-x86_64-unknown-linux-musl.tar.gz +0 -0
package/build/agent/index.js
CHANGED
|
@@ -9059,6 +9059,22 @@ function detectUnrecognizedToolCall(xmlString, validTools) {
|
|
|
9059
9059
|
return toolName;
|
|
9060
9060
|
}
|
|
9061
9061
|
}
|
|
9062
|
+
const allToolNames = [.../* @__PURE__ */ new Set([...knownToolNames, ...validTools])];
|
|
9063
|
+
for (const toolName of allToolNames) {
|
|
9064
|
+
const escapedToolName = toolName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9065
|
+
const wrapperPatterns = [
|
|
9066
|
+
new RegExp(`<tool_name>\\s*${escapedToolName}\\s*</tool_name>`, "i"),
|
|
9067
|
+
new RegExp(`<function>\\s*${escapedToolName}\\s*</function>`, "i"),
|
|
9068
|
+
new RegExp(`<name>\\s*${escapedToolName}\\s*</name>`, "i"),
|
|
9069
|
+
// Also check for tool name immediately after api_call or call opening tag
|
|
9070
|
+
new RegExp(`<(?:api_call|call)[^>]*>[\\s\\S]*?<tool_name>\\s*${escapedToolName}`, "i")
|
|
9071
|
+
];
|
|
9072
|
+
for (const pattern of wrapperPatterns) {
|
|
9073
|
+
if (pattern.test(xmlString)) {
|
|
9074
|
+
return `wrapped_tool:${toolName}`;
|
|
9075
|
+
}
|
|
9076
|
+
}
|
|
9077
|
+
}
|
|
9062
9078
|
return null;
|
|
9063
9079
|
}
|
|
9064
9080
|
function parseTargets(targets) {
|
|
@@ -10585,9 +10601,11 @@ var init_bashPermissions = __esm({
|
|
|
10585
10601
|
* @param {boolean} [config.disableDefaultAllow] - Disable default allow list
|
|
10586
10602
|
* @param {boolean} [config.disableDefaultDeny] - Disable default deny list
|
|
10587
10603
|
* @param {boolean} [config.debug] - Enable debug logging
|
|
10604
|
+
* @param {Object} [config.tracer] - Optional tracer for telemetry
|
|
10588
10605
|
*/
|
|
10589
10606
|
constructor(config = {}) {
|
|
10590
10607
|
this.debug = config.debug || false;
|
|
10608
|
+
this.tracer = config.tracer || null;
|
|
10591
10609
|
this.allowPatterns = [];
|
|
10592
10610
|
if (!config.disableDefaultAllow) {
|
|
10593
10611
|
this.allowPatterns.push(...DEFAULT_ALLOW_PATTERNS);
|
|
@@ -10617,6 +10635,24 @@ var init_bashPermissions = __esm({
|
|
|
10617
10635
|
if (this.debug) {
|
|
10618
10636
|
console.log(`[BashPermissions] Total patterns - Allow: ${this.allowPatterns.length}, Deny: ${this.denyPatterns.length}`);
|
|
10619
10637
|
}
|
|
10638
|
+
this.recordBashEvent("permissions.initialized", {
|
|
10639
|
+
allowPatternCount: this.allowPatterns.length,
|
|
10640
|
+
denyPatternCount: this.denyPatterns.length,
|
|
10641
|
+
hasCustomAllowPatterns: !!(config.allow && config.allow.length > 0),
|
|
10642
|
+
hasCustomDenyPatterns: !!(config.deny && config.deny.length > 0),
|
|
10643
|
+
disableDefaultAllow: !!config.disableDefaultAllow,
|
|
10644
|
+
disableDefaultDeny: !!config.disableDefaultDeny
|
|
10645
|
+
});
|
|
10646
|
+
}
|
|
10647
|
+
/**
|
|
10648
|
+
* Record a bash telemetry event if tracer is available
|
|
10649
|
+
* @param {string} eventType - Event type (e.g., 'permission.checked', 'permission.denied')
|
|
10650
|
+
* @param {Object} data - Event data
|
|
10651
|
+
*/
|
|
10652
|
+
recordBashEvent(eventType, data = {}) {
|
|
10653
|
+
if (this.tracer && typeof this.tracer.recordBashEvent === "function") {
|
|
10654
|
+
this.tracer.recordBashEvent(eventType, data);
|
|
10655
|
+
}
|
|
10620
10656
|
}
|
|
10621
10657
|
/**
|
|
10622
10658
|
* Check if a simple command is allowed (complex commands allowed if they match patterns)
|
|
@@ -10625,11 +10661,17 @@ var init_bashPermissions = __esm({
|
|
|
10625
10661
|
*/
|
|
10626
10662
|
check(command) {
|
|
10627
10663
|
if (!command || typeof command !== "string") {
|
|
10628
|
-
|
|
10664
|
+
const result2 = {
|
|
10629
10665
|
allowed: false,
|
|
10630
10666
|
reason: "Invalid or empty command",
|
|
10631
10667
|
command
|
|
10632
10668
|
};
|
|
10669
|
+
this.recordBashEvent("permission.denied", {
|
|
10670
|
+
command: String(command),
|
|
10671
|
+
reason: result2.reason,
|
|
10672
|
+
isComplex: false
|
|
10673
|
+
});
|
|
10674
|
+
return result2;
|
|
10633
10675
|
}
|
|
10634
10676
|
const commandIsComplex = isComplexCommand(command);
|
|
10635
10677
|
if (commandIsComplex) {
|
|
@@ -10637,18 +10679,31 @@ var init_bashPermissions = __esm({
|
|
|
10637
10679
|
}
|
|
10638
10680
|
const parsed = parseCommand(command);
|
|
10639
10681
|
if (parsed.error) {
|
|
10640
|
-
|
|
10682
|
+
const result2 = {
|
|
10641
10683
|
allowed: false,
|
|
10642
10684
|
reason: parsed.error,
|
|
10643
10685
|
command
|
|
10644
10686
|
};
|
|
10687
|
+
this.recordBashEvent("permission.denied", {
|
|
10688
|
+
command,
|
|
10689
|
+
reason: result2.reason,
|
|
10690
|
+
isComplex: false,
|
|
10691
|
+
parseError: true
|
|
10692
|
+
});
|
|
10693
|
+
return result2;
|
|
10645
10694
|
}
|
|
10646
10695
|
if (!parsed.command) {
|
|
10647
|
-
|
|
10696
|
+
const result2 = {
|
|
10648
10697
|
allowed: false,
|
|
10649
10698
|
reason: "No valid command found",
|
|
10650
10699
|
command
|
|
10651
10700
|
};
|
|
10701
|
+
this.recordBashEvent("permission.denied", {
|
|
10702
|
+
command,
|
|
10703
|
+
reason: result2.reason,
|
|
10704
|
+
isComplex: false
|
|
10705
|
+
});
|
|
10706
|
+
return result2;
|
|
10652
10707
|
}
|
|
10653
10708
|
if (this.debug) {
|
|
10654
10709
|
console.log(`[BashPermissions] Checking simple command: "${command}"`);
|
|
@@ -10656,22 +10711,37 @@ var init_bashPermissions = __esm({
|
|
|
10656
10711
|
}
|
|
10657
10712
|
if (matchesAnyPattern(parsed, this.denyPatterns)) {
|
|
10658
10713
|
const matchedPatterns = this.denyPatterns.filter((pattern) => matchesPattern(parsed, pattern));
|
|
10659
|
-
|
|
10714
|
+
const result2 = {
|
|
10660
10715
|
allowed: false,
|
|
10661
10716
|
reason: `Command matches deny pattern: ${matchedPatterns[0]}`,
|
|
10662
10717
|
command,
|
|
10663
10718
|
parsed,
|
|
10664
10719
|
matchedPatterns
|
|
10665
10720
|
};
|
|
10721
|
+
this.recordBashEvent("permission.denied", {
|
|
10722
|
+
command,
|
|
10723
|
+
parsedCommand: parsed.command,
|
|
10724
|
+
reason: "matches_deny_pattern",
|
|
10725
|
+
matchedPattern: matchedPatterns[0],
|
|
10726
|
+
isComplex: false
|
|
10727
|
+
});
|
|
10728
|
+
return result2;
|
|
10666
10729
|
}
|
|
10667
10730
|
if (this.allowPatterns.length > 0) {
|
|
10668
10731
|
if (!matchesAnyPattern(parsed, this.allowPatterns)) {
|
|
10669
|
-
|
|
10732
|
+
const result2 = {
|
|
10670
10733
|
allowed: false,
|
|
10671
10734
|
reason: "Command not in allow list",
|
|
10672
10735
|
command,
|
|
10673
10736
|
parsed
|
|
10674
10737
|
};
|
|
10738
|
+
this.recordBashEvent("permission.denied", {
|
|
10739
|
+
command,
|
|
10740
|
+
parsedCommand: parsed.command,
|
|
10741
|
+
reason: "not_in_allow_list",
|
|
10742
|
+
isComplex: false
|
|
10743
|
+
});
|
|
10744
|
+
return result2;
|
|
10675
10745
|
}
|
|
10676
10746
|
}
|
|
10677
10747
|
const result = {
|
|
@@ -10683,6 +10753,11 @@ var init_bashPermissions = __esm({
|
|
|
10683
10753
|
if (this.debug) {
|
|
10684
10754
|
console.log(`[BashPermissions] ALLOWED - command passed all checks`);
|
|
10685
10755
|
}
|
|
10756
|
+
this.recordBashEvent("permission.allowed", {
|
|
10757
|
+
command,
|
|
10758
|
+
parsedCommand: parsed.command,
|
|
10759
|
+
isComplex: false
|
|
10760
|
+
});
|
|
10686
10761
|
return result;
|
|
10687
10762
|
}
|
|
10688
10763
|
/**
|
|
@@ -10706,13 +10781,20 @@ var init_bashPermissions = __esm({
|
|
|
10706
10781
|
if (this.debug) {
|
|
10707
10782
|
console.log(`[BashPermissions] DENIED - matches complex deny pattern: ${pattern}`);
|
|
10708
10783
|
}
|
|
10709
|
-
|
|
10784
|
+
const result = {
|
|
10710
10785
|
allowed: false,
|
|
10711
10786
|
reason: `Command matches deny pattern: ${pattern}`,
|
|
10712
10787
|
command,
|
|
10713
10788
|
isComplex: true,
|
|
10714
10789
|
matchedPatterns: [pattern]
|
|
10715
10790
|
};
|
|
10791
|
+
this.recordBashEvent("permission.denied", {
|
|
10792
|
+
command,
|
|
10793
|
+
reason: "matches_deny_pattern",
|
|
10794
|
+
matchedPattern: pattern,
|
|
10795
|
+
isComplex: true
|
|
10796
|
+
});
|
|
10797
|
+
return result;
|
|
10716
10798
|
}
|
|
10717
10799
|
}
|
|
10718
10800
|
for (const pattern of complexAllowPatterns) {
|
|
@@ -10720,17 +10802,28 @@ var init_bashPermissions = __esm({
|
|
|
10720
10802
|
if (this.debug) {
|
|
10721
10803
|
console.log(`[BashPermissions] ALLOWED - matches complex allow pattern: ${pattern}`);
|
|
10722
10804
|
}
|
|
10723
|
-
|
|
10805
|
+
const result = {
|
|
10724
10806
|
allowed: true,
|
|
10725
10807
|
command,
|
|
10726
10808
|
isComplex: true,
|
|
10727
10809
|
matchedPattern: pattern
|
|
10728
10810
|
};
|
|
10811
|
+
this.recordBashEvent("permission.allowed", {
|
|
10812
|
+
command,
|
|
10813
|
+
matchedPattern: pattern,
|
|
10814
|
+
isComplex: true
|
|
10815
|
+
});
|
|
10816
|
+
return result;
|
|
10729
10817
|
}
|
|
10730
10818
|
}
|
|
10731
10819
|
if (this.debug) {
|
|
10732
10820
|
console.log(`[BashPermissions] DENIED - no matching complex pattern found`);
|
|
10733
10821
|
}
|
|
10822
|
+
this.recordBashEvent("permission.denied", {
|
|
10823
|
+
command,
|
|
10824
|
+
reason: "no_matching_complex_pattern",
|
|
10825
|
+
isComplex: true
|
|
10826
|
+
});
|
|
10734
10827
|
return {
|
|
10735
10828
|
allowed: false,
|
|
10736
10829
|
reason: 'Complex shell commands require explicit allow patterns (e.g., "cd * && git *")',
|
|
@@ -11028,14 +11121,16 @@ var init_bash = __esm({
|
|
|
11028
11121
|
bashConfig = {},
|
|
11029
11122
|
debug = false,
|
|
11030
11123
|
cwd,
|
|
11031
|
-
allowedFolders = []
|
|
11124
|
+
allowedFolders = [],
|
|
11125
|
+
tracer = null
|
|
11032
11126
|
} = options;
|
|
11033
11127
|
const permissionChecker = new BashPermissionChecker({
|
|
11034
11128
|
allow: bashConfig.allow,
|
|
11035
11129
|
deny: bashConfig.deny,
|
|
11036
11130
|
disableDefaultAllow: bashConfig.disableDefaultAllow,
|
|
11037
11131
|
disableDefaultDeny: bashConfig.disableDefaultDeny,
|
|
11038
|
-
debug
|
|
11132
|
+
debug,
|
|
11133
|
+
tracer
|
|
11039
11134
|
});
|
|
11040
11135
|
const getDefaultWorkingDirectory = () => {
|
|
11041
11136
|
if (bashConfig.workingDirectory) {
|
|
@@ -11665,6 +11760,28 @@ var init_simpleTelemetry = __esm({
|
|
|
11665
11760
|
...data
|
|
11666
11761
|
});
|
|
11667
11762
|
}
|
|
11763
|
+
/**
|
|
11764
|
+
* Record MCP (Model Context Protocol) events
|
|
11765
|
+
* Tracks server connections, tool discovery, method filtering, and tool execution
|
|
11766
|
+
*/
|
|
11767
|
+
recordMcpEvent(eventType, data = {}) {
|
|
11768
|
+
if (!this.isEnabled()) return;
|
|
11769
|
+
this.addEvent(`mcp.${eventType}`, {
|
|
11770
|
+
"session.id": this.sessionId,
|
|
11771
|
+
...data
|
|
11772
|
+
});
|
|
11773
|
+
}
|
|
11774
|
+
/**
|
|
11775
|
+
* Record bash tool events
|
|
11776
|
+
* Tracks command permission checks, allowed/denied commands, and execution
|
|
11777
|
+
*/
|
|
11778
|
+
recordBashEvent(eventType, data = {}) {
|
|
11779
|
+
if (!this.isEnabled()) return;
|
|
11780
|
+
this.addEvent(`bash.${eventType}`, {
|
|
11781
|
+
"session.id": this.sessionId,
|
|
11782
|
+
...data
|
|
11783
|
+
});
|
|
11784
|
+
}
|
|
11668
11785
|
setAttributes(attributes) {
|
|
11669
11786
|
if (this.telemetry && this.telemetry.enableConsole) {
|
|
11670
11787
|
console.log("[Attributes]", attributes);
|
|
@@ -57891,6 +58008,47 @@ function validateTimeout(value) {
|
|
|
57891
58008
|
if (!Number.isFinite(num) || num < 0) return void 0;
|
|
57892
58009
|
return Math.min(num, MAX_TIMEOUT);
|
|
57893
58010
|
}
|
|
58011
|
+
function validateMethodFilter(serverConfig, serverName = "unknown") {
|
|
58012
|
+
const result = { allowedMethods: null, blockedMethods: null };
|
|
58013
|
+
const debug = process.env.DEBUG === "1" || process.env.DEBUG_MCP === "1";
|
|
58014
|
+
if (serverConfig.allowedMethods && serverConfig.blockedMethods) {
|
|
58015
|
+
console.error(`[MCP WARN] Server '${serverName}' has both allowedMethods and blockedMethods - using allowedMethods only`);
|
|
58016
|
+
}
|
|
58017
|
+
if (serverConfig.allowedMethods) {
|
|
58018
|
+
if (!Array.isArray(serverConfig.allowedMethods)) {
|
|
58019
|
+
console.error(`[MCP WARN] Server '${serverName}' allowedMethods must be an array, ignoring`);
|
|
58020
|
+
} else {
|
|
58021
|
+
const validMethods = serverConfig.allowedMethods.filter((m) => typeof m === "string" && m.length > 0);
|
|
58022
|
+
if (validMethods.length !== serverConfig.allowedMethods.length) {
|
|
58023
|
+
console.error(`[MCP WARN] Server '${serverName}' allowedMethods contains non-string values, skipping those`);
|
|
58024
|
+
}
|
|
58025
|
+
if (validMethods.length > 0) {
|
|
58026
|
+
result.allowedMethods = validMethods;
|
|
58027
|
+
if (debug) {
|
|
58028
|
+
console.error(`[MCP DEBUG] Server '${serverName}' allowedMethods: ${validMethods.join(", ")}`);
|
|
58029
|
+
}
|
|
58030
|
+
}
|
|
58031
|
+
}
|
|
58032
|
+
return result;
|
|
58033
|
+
}
|
|
58034
|
+
if (serverConfig.blockedMethods) {
|
|
58035
|
+
if (!Array.isArray(serverConfig.blockedMethods)) {
|
|
58036
|
+
console.error(`[MCP WARN] Server '${serverName}' blockedMethods must be an array, ignoring`);
|
|
58037
|
+
} else {
|
|
58038
|
+
const validMethods = serverConfig.blockedMethods.filter((m) => typeof m === "string" && m.length > 0);
|
|
58039
|
+
if (validMethods.length !== serverConfig.blockedMethods.length) {
|
|
58040
|
+
console.error(`[MCP WARN] Server '${serverName}' blockedMethods contains non-string values, skipping those`);
|
|
58041
|
+
}
|
|
58042
|
+
if (validMethods.length > 0) {
|
|
58043
|
+
result.blockedMethods = validMethods;
|
|
58044
|
+
if (debug) {
|
|
58045
|
+
console.error(`[MCP DEBUG] Server '${serverName}' blockedMethods: ${validMethods.join(", ")}`);
|
|
58046
|
+
}
|
|
58047
|
+
}
|
|
58048
|
+
}
|
|
58049
|
+
}
|
|
58050
|
+
return result;
|
|
58051
|
+
}
|
|
57894
58052
|
function loadMCPConfigurationFromPath(configPath) {
|
|
57895
58053
|
if (!configPath) {
|
|
57896
58054
|
throw new Error("Config path is required");
|
|
@@ -57984,6 +58142,12 @@ function mergeWithEnvironment(config) {
|
|
|
57984
58142
|
console.error(`[MCP WARN] Invalid timeout value for ${normalizedName}: ${value}`);
|
|
57985
58143
|
}
|
|
57986
58144
|
break;
|
|
58145
|
+
case "ALLOWLIST":
|
|
58146
|
+
config.mcpServers[normalizedName].allowedMethods = value.split(",").map((m) => m.trim()).filter(Boolean);
|
|
58147
|
+
break;
|
|
58148
|
+
case "BLOCKLIST":
|
|
58149
|
+
config.mcpServers[normalizedName].blockedMethods = value.split(",").map((m) => m.trim()).filter(Boolean);
|
|
58150
|
+
break;
|
|
57987
58151
|
}
|
|
57988
58152
|
}
|
|
57989
58153
|
}
|
|
@@ -58034,6 +58198,9 @@ function parseEnabledServers(config) {
|
|
|
58034
58198
|
}
|
|
58035
58199
|
server.timeout = validatedTimeout;
|
|
58036
58200
|
}
|
|
58201
|
+
const methodFilter = validateMethodFilter(serverConfig, name);
|
|
58202
|
+
server.allowedMethods = methodFilter.allowedMethods;
|
|
58203
|
+
server.blockedMethods = methodFilter.blockedMethods;
|
|
58037
58204
|
servers.push(server);
|
|
58038
58205
|
}
|
|
58039
58206
|
return servers;
|
|
@@ -58071,6 +58238,22 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
|
58071
58238
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
58072
58239
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
58073
58240
|
import { WebSocketClientTransport } from "@modelcontextprotocol/sdk/client/websocket.js";
|
|
58241
|
+
function isMethodAllowed(methodName, allowedMethods, blockedMethods) {
|
|
58242
|
+
const matchesPattern2 = (name, pattern) => {
|
|
58243
|
+
if (!pattern.includes("*")) {
|
|
58244
|
+
return name === pattern;
|
|
58245
|
+
}
|
|
58246
|
+
const regexPattern = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
58247
|
+
return new RegExp(`^${regexPattern}$`).test(name);
|
|
58248
|
+
};
|
|
58249
|
+
if (allowedMethods && allowedMethods.length > 0) {
|
|
58250
|
+
return allowedMethods.some((pattern) => matchesPattern2(methodName, pattern));
|
|
58251
|
+
}
|
|
58252
|
+
if (blockedMethods && blockedMethods.length > 0) {
|
|
58253
|
+
return !blockedMethods.some((pattern) => matchesPattern2(methodName, pattern));
|
|
58254
|
+
}
|
|
58255
|
+
return true;
|
|
58256
|
+
}
|
|
58074
58257
|
function createTransport(serverConfig) {
|
|
58075
58258
|
const { transport, command, args, url, env } = serverConfig;
|
|
58076
58259
|
switch (transport) {
|
|
@@ -58151,6 +58334,17 @@ var init_client = __esm({
|
|
|
58151
58334
|
this.tools = /* @__PURE__ */ new Map();
|
|
58152
58335
|
this.debug = options.debug || process.env.DEBUG_MCP === "1";
|
|
58153
58336
|
this.config = null;
|
|
58337
|
+
this.tracer = options.tracer || null;
|
|
58338
|
+
}
|
|
58339
|
+
/**
|
|
58340
|
+
* Record an MCP telemetry event if tracer is available
|
|
58341
|
+
* @param {string} eventType - Event type (e.g., 'server.connect', 'tool.discovered')
|
|
58342
|
+
* @param {Object} data - Event data
|
|
58343
|
+
*/
|
|
58344
|
+
recordMcpEvent(eventType, data = {}) {
|
|
58345
|
+
if (this.tracer && typeof this.tracer.recordMcpEvent === "function") {
|
|
58346
|
+
this.tracer.recordMcpEvent(eventType, data);
|
|
58347
|
+
}
|
|
58154
58348
|
}
|
|
58155
58349
|
/**
|
|
58156
58350
|
* Initialize MCP clients from configuration
|
|
@@ -58159,10 +58353,20 @@ var init_client = __esm({
|
|
|
58159
58353
|
async initialize(config = null) {
|
|
58160
58354
|
this.config = config || loadMCPConfiguration();
|
|
58161
58355
|
const servers = parseEnabledServers(this.config);
|
|
58356
|
+
this.recordMcpEvent("initialization.started", {
|
|
58357
|
+
serverCount: servers.length,
|
|
58358
|
+
serverNames: servers.map((s) => s.name)
|
|
58359
|
+
});
|
|
58162
58360
|
console.error(`[MCP INFO] Found ${servers.length} enabled MCP server${servers.length !== 1 ? "s" : ""}`);
|
|
58163
58361
|
if (servers.length === 0) {
|
|
58164
58362
|
console.error("[MCP INFO] No MCP servers configured or enabled");
|
|
58165
58363
|
console.error("[MCP INFO] 0 MCP tools available");
|
|
58364
|
+
this.recordMcpEvent("initialization.completed", {
|
|
58365
|
+
connected: 0,
|
|
58366
|
+
total: 0,
|
|
58367
|
+
toolCount: 0,
|
|
58368
|
+
tools: []
|
|
58369
|
+
});
|
|
58166
58370
|
return {
|
|
58167
58371
|
connected: 0,
|
|
58168
58372
|
total: 0,
|
|
@@ -58199,10 +58403,17 @@ var init_client = __esm({
|
|
|
58199
58403
|
console.error(`[MCP DEBUG] - ${toolName}`);
|
|
58200
58404
|
});
|
|
58201
58405
|
}
|
|
58406
|
+
const toolNames = Array.from(this.tools.keys());
|
|
58407
|
+
this.recordMcpEvent("initialization.completed", {
|
|
58408
|
+
connected: connectedCount,
|
|
58409
|
+
total: servers.length,
|
|
58410
|
+
toolCount: this.tools.size,
|
|
58411
|
+
tools: toolNames
|
|
58412
|
+
});
|
|
58202
58413
|
return {
|
|
58203
58414
|
connected: connectedCount,
|
|
58204
58415
|
total: servers.length,
|
|
58205
|
-
tools:
|
|
58416
|
+
tools: toolNames
|
|
58206
58417
|
};
|
|
58207
58418
|
}
|
|
58208
58419
|
/**
|
|
@@ -58211,6 +58422,12 @@ var init_client = __esm({
|
|
|
58211
58422
|
*/
|
|
58212
58423
|
async connectToServer(serverConfig) {
|
|
58213
58424
|
const { name } = serverConfig;
|
|
58425
|
+
this.recordMcpEvent("server.connecting", {
|
|
58426
|
+
serverName: name,
|
|
58427
|
+
transport: serverConfig.transport,
|
|
58428
|
+
hasAllowedMethods: !!(serverConfig.allowedMethods && serverConfig.allowedMethods.length > 0),
|
|
58429
|
+
hasBlockedMethods: !!(serverConfig.blockedMethods && serverConfig.blockedMethods.length > 0)
|
|
58430
|
+
});
|
|
58214
58431
|
try {
|
|
58215
58432
|
if (this.debug) {
|
|
58216
58433
|
console.error(`[MCP DEBUG] Connecting to ${name} via ${serverConfig.transport}...`);
|
|
@@ -58232,27 +58449,92 @@ var init_client = __esm({
|
|
|
58232
58449
|
config: serverConfig
|
|
58233
58450
|
});
|
|
58234
58451
|
const toolsResponse = await client.listTools();
|
|
58235
|
-
const
|
|
58452
|
+
const totalToolCount = toolsResponse?.tools?.length || 0;
|
|
58453
|
+
let registeredCount = 0;
|
|
58454
|
+
let filteredCount = 0;
|
|
58455
|
+
const registeredTools = [];
|
|
58456
|
+
const filteredTools = [];
|
|
58236
58457
|
if (toolsResponse && toolsResponse.tools) {
|
|
58458
|
+
const { allowedMethods, blockedMethods } = serverConfig;
|
|
58459
|
+
const allToolNames = toolsResponse.tools.map((t) => t.name);
|
|
58460
|
+
this.recordMcpEvent("tools.discovered", {
|
|
58461
|
+
serverName: name,
|
|
58462
|
+
toolCount: totalToolCount,
|
|
58463
|
+
tools: allToolNames
|
|
58464
|
+
});
|
|
58237
58465
|
for (const tool4 of toolsResponse.tools) {
|
|
58466
|
+
if (!isMethodAllowed(tool4.name, allowedMethods, blockedMethods)) {
|
|
58467
|
+
filteredCount++;
|
|
58468
|
+
filteredTools.push(tool4.name);
|
|
58469
|
+
if (this.debug) {
|
|
58470
|
+
console.error(`[MCP DEBUG] Filtered out tool: ${tool4.name} (not allowed by method filter)`);
|
|
58471
|
+
}
|
|
58472
|
+
continue;
|
|
58473
|
+
}
|
|
58238
58474
|
const qualifiedName = `${name}_${tool4.name}`;
|
|
58239
58475
|
this.tools.set(qualifiedName, {
|
|
58240
58476
|
...tool4,
|
|
58241
58477
|
serverName: name,
|
|
58242
58478
|
originalName: tool4.name
|
|
58243
58479
|
});
|
|
58480
|
+
registeredCount++;
|
|
58481
|
+
registeredTools.push(qualifiedName);
|
|
58244
58482
|
if (this.debug) {
|
|
58245
58483
|
console.error(`[MCP DEBUG] Registered tool: ${qualifiedName}`);
|
|
58246
58484
|
}
|
|
58247
58485
|
}
|
|
58486
|
+
if (filteredCount > 0) {
|
|
58487
|
+
this.recordMcpEvent("tools.filtered", {
|
|
58488
|
+
serverName: name,
|
|
58489
|
+
filteredCount,
|
|
58490
|
+
filteredTools,
|
|
58491
|
+
allowedMethods: allowedMethods || [],
|
|
58492
|
+
blockedMethods: blockedMethods || []
|
|
58493
|
+
});
|
|
58494
|
+
}
|
|
58495
|
+
if (allowedMethods && allowedMethods.length > 0) {
|
|
58496
|
+
const unmatchedPatterns = allowedMethods.filter((pattern) => {
|
|
58497
|
+
return !allToolNames.some((toolName) => isMethodAllowed(toolName, [pattern], null));
|
|
58498
|
+
});
|
|
58499
|
+
if (unmatchedPatterns.length > 0) {
|
|
58500
|
+
console.error(`[MCP WARN] Server '${name}': The following allowedMethods patterns did not match any tools: ${unmatchedPatterns.join(", ")}`);
|
|
58501
|
+
console.error(`[MCP WARN] Available methods from '${name}': ${allToolNames.join(", ")}`);
|
|
58502
|
+
}
|
|
58503
|
+
}
|
|
58504
|
+
if (blockedMethods && blockedMethods.length > 0) {
|
|
58505
|
+
const unmatchedPatterns = blockedMethods.filter((pattern) => {
|
|
58506
|
+
return !allToolNames.some((toolName) => !isMethodAllowed(toolName, null, [pattern]));
|
|
58507
|
+
});
|
|
58508
|
+
if (unmatchedPatterns.length > 0) {
|
|
58509
|
+
console.error(`[MCP WARN] Server '${name}': The following blockedMethods patterns did not match any tools: ${unmatchedPatterns.join(", ")}`);
|
|
58510
|
+
console.error(`[MCP WARN] Available methods from '${name}': ${allToolNames.join(", ")}`);
|
|
58511
|
+
}
|
|
58512
|
+
}
|
|
58248
58513
|
}
|
|
58249
|
-
|
|
58514
|
+
if (filteredCount > 0) {
|
|
58515
|
+
console.error(`[MCP INFO] Connected to ${name}: ${registeredCount} tool${registeredCount !== 1 ? "s" : ""} loaded (${filteredCount} filtered out)`);
|
|
58516
|
+
} else {
|
|
58517
|
+
console.error(`[MCP INFO] Connected to ${name}: ${registeredCount} tool${registeredCount !== 1 ? "s" : ""} loaded`);
|
|
58518
|
+
}
|
|
58519
|
+
this.recordMcpEvent("server.connected", {
|
|
58520
|
+
serverName: name,
|
|
58521
|
+
transport: serverConfig.transport,
|
|
58522
|
+
totalToolCount,
|
|
58523
|
+
registeredCount,
|
|
58524
|
+
filteredCount,
|
|
58525
|
+
registeredTools
|
|
58526
|
+
});
|
|
58250
58527
|
return true;
|
|
58251
58528
|
} catch (error) {
|
|
58252
58529
|
console.error(`[MCP ERROR] Error connecting to ${name}:`, error.message);
|
|
58253
58530
|
if (this.debug) {
|
|
58254
58531
|
console.error(`[MCP DEBUG] Full error details:`, error);
|
|
58255
58532
|
}
|
|
58533
|
+
this.recordMcpEvent("server.connection_failed", {
|
|
58534
|
+
serverName: name,
|
|
58535
|
+
transport: serverConfig.transport,
|
|
58536
|
+
error: error.message
|
|
58537
|
+
});
|
|
58256
58538
|
return false;
|
|
58257
58539
|
}
|
|
58258
58540
|
}
|
|
@@ -58264,12 +58546,27 @@ var init_client = __esm({
|
|
|
58264
58546
|
async callTool(toolName, args) {
|
|
58265
58547
|
const tool4 = this.tools.get(toolName);
|
|
58266
58548
|
if (!tool4) {
|
|
58549
|
+
this.recordMcpEvent("tool.call_failed", {
|
|
58550
|
+
toolName,
|
|
58551
|
+
error: "Unknown tool"
|
|
58552
|
+
});
|
|
58267
58553
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
58268
58554
|
}
|
|
58269
58555
|
const clientInfo = this.clients.get(tool4.serverName);
|
|
58270
58556
|
if (!clientInfo) {
|
|
58557
|
+
this.recordMcpEvent("tool.call_failed", {
|
|
58558
|
+
toolName,
|
|
58559
|
+
serverName: tool4.serverName,
|
|
58560
|
+
error: "Server not connected"
|
|
58561
|
+
});
|
|
58271
58562
|
throw new Error(`Server ${tool4.serverName} not connected`);
|
|
58272
58563
|
}
|
|
58564
|
+
const startTime = Date.now();
|
|
58565
|
+
this.recordMcpEvent("tool.call_started", {
|
|
58566
|
+
toolName,
|
|
58567
|
+
serverName: tool4.serverName,
|
|
58568
|
+
originalToolName: tool4.originalName
|
|
58569
|
+
});
|
|
58273
58570
|
try {
|
|
58274
58571
|
if (this.debug) {
|
|
58275
58572
|
console.error(`[MCP DEBUG] Calling ${toolName} with args:`, JSON.stringify(args, null, 2));
|
|
@@ -58289,15 +58586,31 @@ var init_client = __esm({
|
|
|
58289
58586
|
}),
|
|
58290
58587
|
timeoutPromise
|
|
58291
58588
|
]);
|
|
58589
|
+
const durationMs = Date.now() - startTime;
|
|
58292
58590
|
if (this.debug) {
|
|
58293
58591
|
console.error(`[MCP DEBUG] Tool ${toolName} executed successfully`);
|
|
58294
58592
|
}
|
|
58593
|
+
this.recordMcpEvent("tool.call_completed", {
|
|
58594
|
+
toolName,
|
|
58595
|
+
serverName: tool4.serverName,
|
|
58596
|
+
originalToolName: tool4.originalName,
|
|
58597
|
+
durationMs
|
|
58598
|
+
});
|
|
58295
58599
|
return result;
|
|
58296
58600
|
} catch (error) {
|
|
58601
|
+
const durationMs = Date.now() - startTime;
|
|
58297
58602
|
console.error(`[MCP ERROR] Error calling tool ${toolName}:`, error.message);
|
|
58298
58603
|
if (this.debug) {
|
|
58299
58604
|
console.error(`[MCP DEBUG] Full error details:`, error);
|
|
58300
58605
|
}
|
|
58606
|
+
this.recordMcpEvent("tool.call_failed", {
|
|
58607
|
+
toolName,
|
|
58608
|
+
serverName: tool4.serverName,
|
|
58609
|
+
originalToolName: tool4.originalName,
|
|
58610
|
+
error: error.message,
|
|
58611
|
+
durationMs,
|
|
58612
|
+
isTimeout: error.message.includes("timeout")
|
|
58613
|
+
});
|
|
58301
58614
|
throw error;
|
|
58302
58615
|
}
|
|
58303
58616
|
}
|
|
@@ -58342,12 +58655,17 @@ var init_client = __esm({
|
|
|
58342
58655
|
*/
|
|
58343
58656
|
async disconnect() {
|
|
58344
58657
|
const disconnectPromises = [];
|
|
58658
|
+
const serverNames = Array.from(this.clients.keys());
|
|
58345
58659
|
if (this.clients.size === 0) {
|
|
58346
58660
|
if (this.debug) {
|
|
58347
58661
|
console.error("[MCP DEBUG] No MCP clients to disconnect");
|
|
58348
58662
|
}
|
|
58349
58663
|
return;
|
|
58350
58664
|
}
|
|
58665
|
+
this.recordMcpEvent("disconnection.started", {
|
|
58666
|
+
serverCount: this.clients.size,
|
|
58667
|
+
serverNames
|
|
58668
|
+
});
|
|
58351
58669
|
if (this.debug) {
|
|
58352
58670
|
console.error(`[MCP DEBUG] Disconnecting from ${this.clients.size} MCP server${this.clients.size !== 1 ? "s" : ""}...`);
|
|
58353
58671
|
}
|
|
@@ -58357,14 +58675,25 @@ var init_client = __esm({
|
|
|
58357
58675
|
if (this.debug) {
|
|
58358
58676
|
console.error(`[MCP DEBUG] Disconnected from ${name}`);
|
|
58359
58677
|
}
|
|
58678
|
+
this.recordMcpEvent("server.disconnected", {
|
|
58679
|
+
serverName: name
|
|
58680
|
+
});
|
|
58360
58681
|
}).catch((error) => {
|
|
58361
58682
|
console.error(`[MCP ERROR] Error disconnecting from ${name}:`, error.message);
|
|
58683
|
+
this.recordMcpEvent("server.disconnect_failed", {
|
|
58684
|
+
serverName: name,
|
|
58685
|
+
error: error.message
|
|
58686
|
+
});
|
|
58362
58687
|
})
|
|
58363
58688
|
);
|
|
58364
58689
|
}
|
|
58365
58690
|
await Promise.all(disconnectPromises);
|
|
58366
58691
|
this.clients.clear();
|
|
58367
58692
|
this.tools.clear();
|
|
58693
|
+
this.recordMcpEvent("disconnection.completed", {
|
|
58694
|
+
serverCount: serverNames.length,
|
|
58695
|
+
serverNames
|
|
58696
|
+
});
|
|
58368
58697
|
if (this.debug) {
|
|
58369
58698
|
console.error("[MCP DEBUG] All MCP connections closed");
|
|
58370
58699
|
}
|
|
@@ -58508,6 +58837,7 @@ var init_xmlBridge = __esm({
|
|
|
58508
58837
|
MCPXmlBridge = class {
|
|
58509
58838
|
constructor(options = {}) {
|
|
58510
58839
|
this.debug = options.debug || false;
|
|
58840
|
+
this.tracer = options.tracer || null;
|
|
58511
58841
|
this.mcpTools = {};
|
|
58512
58842
|
this.mcpManager = null;
|
|
58513
58843
|
this.xmlDefinitions = {};
|
|
@@ -58550,7 +58880,7 @@ var init_xmlBridge = __esm({
|
|
|
58550
58880
|
if (this.debug) {
|
|
58551
58881
|
console.error("[MCP DEBUG] Initializing MCP client manager...");
|
|
58552
58882
|
}
|
|
58553
|
-
this.mcpManager = new MCPClientManager({ debug: this.debug });
|
|
58883
|
+
this.mcpManager = new MCPClientManager({ debug: this.debug, tracer: this.tracer });
|
|
58554
58884
|
const result = await this.mcpManager.initialize(mcpConfigs);
|
|
58555
58885
|
const vercelTools = this.mcpManager.getVercelTools();
|
|
58556
58886
|
this.mcpTools = vercelTools;
|
|
@@ -58574,11 +58904,15 @@ var init_xmlBridge = __esm({
|
|
|
58574
58904
|
}
|
|
58575
58905
|
}
|
|
58576
58906
|
/**
|
|
58577
|
-
* Get
|
|
58907
|
+
* Get XML tool definitions for inclusion in system prompt
|
|
58908
|
+
* @param {Array<string>|null} filterToolNames - Optional list of tool names to include (if null, include all)
|
|
58578
58909
|
* @returns {string} Combined XML tool definitions
|
|
58579
58910
|
*/
|
|
58580
|
-
getXmlToolDefinitions() {
|
|
58581
|
-
|
|
58911
|
+
getXmlToolDefinitions(filterToolNames = null) {
|
|
58912
|
+
if (filterToolNames === null) {
|
|
58913
|
+
return Object.values(this.xmlDefinitions).join("\n\n");
|
|
58914
|
+
}
|
|
58915
|
+
return Object.entries(this.xmlDefinitions).filter(([name]) => filterToolNames.includes(name)).map(([, def]) => def).join("\n\n");
|
|
58582
58916
|
}
|
|
58583
58917
|
/**
|
|
58584
58918
|
* Get list of MCP tool names
|
|
@@ -68676,6 +69010,27 @@ import { EventEmitter as EventEmitter5 } from "events";
|
|
|
68676
69010
|
import { existsSync as existsSync6 } from "fs";
|
|
68677
69011
|
import { readFile as readFile3, stat, readdir as readdir3 } from "fs/promises";
|
|
68678
69012
|
import { resolve as resolve6, isAbsolute as isAbsolute5, dirname as dirname5, basename, normalize as normalize2, sep as sep5 } from "path";
|
|
69013
|
+
function extractWrappedToolName(wrappedToolError) {
|
|
69014
|
+
if (!wrappedToolError || typeof wrappedToolError !== "string") {
|
|
69015
|
+
return "unknown";
|
|
69016
|
+
}
|
|
69017
|
+
const colonIndex = wrappedToolError.indexOf(":");
|
|
69018
|
+
return colonIndex !== -1 ? wrappedToolError.slice(colonIndex + 1) : "unknown";
|
|
69019
|
+
}
|
|
69020
|
+
function isWrappedToolError(error) {
|
|
69021
|
+
return error && typeof error === "string" && error.startsWith("wrapped_tool:");
|
|
69022
|
+
}
|
|
69023
|
+
function createWrappedToolErrorMessage(wrappedToolName) {
|
|
69024
|
+
return `Your response contained an incorrectly formatted tool call (${wrappedToolName} wrapped in XML tags). This cannot be used.
|
|
69025
|
+
|
|
69026
|
+
Please use the CORRECT format:
|
|
69027
|
+
|
|
69028
|
+
<${wrappedToolName}>
|
|
69029
|
+
Your content here
|
|
69030
|
+
</${wrappedToolName}>
|
|
69031
|
+
|
|
69032
|
+
Do NOT wrap in other tags like <api_call>, <tool_name>, <function>, etc.`;
|
|
69033
|
+
}
|
|
68679
69034
|
var MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
|
|
68680
69035
|
var init_ProbeAgent = __esm({
|
|
68681
69036
|
"src/agent/ProbeAgent.js"() {
|
|
@@ -70675,6 +71030,9 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
70675
71030
|
console.log(`[DEBUG] Schema provided, using extended iteration limit: ${maxIterations} (base: ${baseMaxIterations})`);
|
|
70676
71031
|
}
|
|
70677
71032
|
}
|
|
71033
|
+
let lastFormatErrorType = null;
|
|
71034
|
+
let sameFormatErrorCount = 0;
|
|
71035
|
+
const MAX_REPEATED_FORMAT_ERRORS = 3;
|
|
70678
71036
|
while (currentIteration < maxIterations && !completionAttempted) {
|
|
70679
71037
|
currentIteration++;
|
|
70680
71038
|
if (this.cancelled) throw new Error("Request was cancelled by the user");
|
|
@@ -70873,7 +71231,22 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
70873
71231
|
(msg) => msg.role === "assistant" && msg.content && !(this.mcpBridge ? parseHybridXmlToolCall(msg.content, validTools, this.mcpBridge) : parseXmlToolCallWithThinking(msg.content, validTools))
|
|
70874
71232
|
);
|
|
70875
71233
|
if (lastAssistantMessage) {
|
|
70876
|
-
|
|
71234
|
+
const prevContent = lastAssistantMessage.content;
|
|
71235
|
+
const wrappedToolError = detectUnrecognizedToolCall(prevContent, validTools);
|
|
71236
|
+
if (isWrappedToolError(wrappedToolError)) {
|
|
71237
|
+
const wrappedToolName = extractWrappedToolName(wrappedToolError);
|
|
71238
|
+
if (this.debug) {
|
|
71239
|
+
console.log(`[DEBUG] Previous response contains wrapped tool '${wrappedToolName}' - rejecting for __PREVIOUS_RESPONSE__`);
|
|
71240
|
+
}
|
|
71241
|
+
currentMessages.push({ role: "assistant", content: assistantResponseContent });
|
|
71242
|
+
currentMessages.push({
|
|
71243
|
+
role: "user",
|
|
71244
|
+
content: createWrappedToolErrorMessage(wrappedToolName)
|
|
71245
|
+
});
|
|
71246
|
+
completionAttempted = false;
|
|
71247
|
+
continue;
|
|
71248
|
+
}
|
|
71249
|
+
finalResult = prevContent;
|
|
70877
71250
|
if (this.debug) console.log(`[DEBUG] Using previous response as completion: ${finalResult.substring(0, 100)}...`);
|
|
70878
71251
|
} else {
|
|
70879
71252
|
finalResult = "Error: No previous response found to use as completion.";
|
|
@@ -71144,7 +71517,33 @@ ${errorXml}
|
|
|
71144
71517
|
currentMessages.push({ role: "assistant", content: assistantResponseContent });
|
|
71145
71518
|
const unrecognizedTool = detectUnrecognizedToolCall(assistantResponseContent, validTools);
|
|
71146
71519
|
let reminderContent;
|
|
71147
|
-
if (unrecognizedTool) {
|
|
71520
|
+
if (isWrappedToolError(unrecognizedTool)) {
|
|
71521
|
+
const wrappedToolName = extractWrappedToolName(unrecognizedTool);
|
|
71522
|
+
if (this.debug) {
|
|
71523
|
+
console.log(`[DEBUG] Detected wrapped tool '${wrappedToolName}' in assistant response - wrong XML format.`);
|
|
71524
|
+
}
|
|
71525
|
+
const toolError = new ParameterError(
|
|
71526
|
+
`Tool '${wrappedToolName}' found but in WRONG FORMAT - do not wrap tools in other XML tags.`,
|
|
71527
|
+
{
|
|
71528
|
+
suggestion: `Use the tool tag DIRECTLY without any wrapper:
|
|
71529
|
+
|
|
71530
|
+
CORRECT FORMAT:
|
|
71531
|
+
<${wrappedToolName}>
|
|
71532
|
+
<param>value</param>
|
|
71533
|
+
</${wrappedToolName}>
|
|
71534
|
+
|
|
71535
|
+
WRONG (what you did - do not wrap in other tags):
|
|
71536
|
+
<api_call><tool_name>${wrappedToolName}</tool_name>...</api_call>
|
|
71537
|
+
<function>${wrappedToolName}</function>
|
|
71538
|
+
<call name="${wrappedToolName}">...</call>
|
|
71539
|
+
|
|
71540
|
+
Remove ALL wrapper tags and use <${wrappedToolName}> directly as the outermost tag.`
|
|
71541
|
+
}
|
|
71542
|
+
);
|
|
71543
|
+
reminderContent = `<tool_result>
|
|
71544
|
+
${formatErrorForAI(toolError)}
|
|
71545
|
+
</tool_result>`;
|
|
71546
|
+
} else if (unrecognizedTool) {
|
|
71148
71547
|
if (this.debug) {
|
|
71149
71548
|
console.log(`[DEBUG] Detected unrecognized tool '${unrecognizedTool}' in assistant response.`);
|
|
71150
71549
|
}
|
|
@@ -71155,6 +71554,20 @@ ${errorXml}
|
|
|
71155
71554
|
${formatErrorForAI(toolError)}
|
|
71156
71555
|
</tool_result>`;
|
|
71157
71556
|
} else {
|
|
71557
|
+
if (currentIteration >= maxIterations) {
|
|
71558
|
+
let cleanedResponse = assistantResponseContent;
|
|
71559
|
+
cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "").trim();
|
|
71560
|
+
cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*$/gi, "").trim();
|
|
71561
|
+
const hasSubstantialContent = cleanedResponse.length > 50 && !cleanedResponse.includes("<api_call>") && !cleanedResponse.includes("<tool_name>") && !cleanedResponse.includes("<function>");
|
|
71562
|
+
if (hasSubstantialContent) {
|
|
71563
|
+
if (this.debug) {
|
|
71564
|
+
console.log(`[DEBUG] Max iterations reached - accepting AI response as final answer (${cleanedResponse.length} chars)`);
|
|
71565
|
+
}
|
|
71566
|
+
finalResult = cleanedResponse;
|
|
71567
|
+
completionAttempted = true;
|
|
71568
|
+
break;
|
|
71569
|
+
}
|
|
71570
|
+
}
|
|
71158
71571
|
reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
|
|
71159
71572
|
|
|
71160
71573
|
Remember: Use proper XML format with BOTH opening and closing tags:
|
|
@@ -71184,6 +71597,25 @@ Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant messa
|
|
|
71184
71597
|
console.log(`[DEBUG] No tool call detected in assistant response. Prompting for tool use.`);
|
|
71185
71598
|
}
|
|
71186
71599
|
}
|
|
71600
|
+
if (unrecognizedTool) {
|
|
71601
|
+
const isWrapped = isWrappedToolError(unrecognizedTool);
|
|
71602
|
+
const errorCategory = isWrapped ? "wrapped_tool" : unrecognizedTool;
|
|
71603
|
+
if (errorCategory === lastFormatErrorType) {
|
|
71604
|
+
sameFormatErrorCount++;
|
|
71605
|
+
if (sameFormatErrorCount >= MAX_REPEATED_FORMAT_ERRORS) {
|
|
71606
|
+
const errorDesc = isWrapped ? "wrapped tool format" : unrecognizedTool;
|
|
71607
|
+
console.error(`[ERROR] Format error category '${errorCategory}' repeated ${sameFormatErrorCount} times. Breaking loop early to prevent infinite iteration.`);
|
|
71608
|
+
finalResult = `Error: Unable to complete request. The AI model repeatedly used incorrect tool call format (${errorDesc}). Please try rephrasing your question or using a different model.`;
|
|
71609
|
+
break;
|
|
71610
|
+
}
|
|
71611
|
+
} else {
|
|
71612
|
+
lastFormatErrorType = errorCategory;
|
|
71613
|
+
sameFormatErrorCount = 1;
|
|
71614
|
+
}
|
|
71615
|
+
} else {
|
|
71616
|
+
lastFormatErrorType = null;
|
|
71617
|
+
sameFormatErrorCount = 0;
|
|
71618
|
+
}
|
|
71187
71619
|
}
|
|
71188
71620
|
if (currentMessages.length > MAX_HISTORY_MESSAGES) {
|
|
71189
71621
|
const messagesBefore = currentMessages.length;
|