@probelabs/probe 0.6.0-rc224 → 0.6.0-rc226
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-rc226-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc226-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc226-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc226-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc226-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +361 -36
- package/build/agent/index.js +570 -57
- package/build/agent/mcp/xmlBridge.js +10 -7
- package/build/agent/simpleTelemetry.js +198 -0
- package/build/agent/tools.js +8 -5
- package/build/tools/analyzeAll.js +6 -1
- package/build/tools/bash.js +18 -3
- package/build/tools/edit.js +19 -10
- package/build/tools/vercel.js +17 -7
- package/build/utils/path-validation.js +148 -1
- package/cjs/agent/ProbeAgent.cjs +392 -56
- package/cjs/agent/simpleTelemetry.cjs +177 -0
- package/cjs/index.cjs +569 -56
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +361 -36
- package/src/agent/mcp/xmlBridge.js +10 -7
- package/src/agent/simpleTelemetry.js +198 -0
- package/src/agent/tools.js +8 -5
- package/src/tools/analyzeAll.js +6 -1
- package/src/tools/bash.js +18 -3
- package/src/tools/edit.js +19 -10
- package/src/tools/vercel.js +17 -7
- package/src/utils/path-validation.js +148 -1
- package/bin/binaries/probe-v0.6.0-rc224-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc224-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc224-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc224-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc224-x86_64-unknown-linux-musl.tar.gz +0 -0
package/cjs/agent/ProbeAgent.cjs
CHANGED
|
@@ -32675,6 +32675,25 @@ var init_error_types = __esm({
|
|
|
32675
32675
|
});
|
|
32676
32676
|
|
|
32677
32677
|
// src/utils/path-validation.js
|
|
32678
|
+
function safeRealpath(inputPath) {
|
|
32679
|
+
try {
|
|
32680
|
+
return (0, import_fs3.realpathSync)(inputPath);
|
|
32681
|
+
} catch (error2) {
|
|
32682
|
+
const normalized = import_path4.default.normalize(inputPath);
|
|
32683
|
+
const parts = normalized.split(import_path4.default.sep);
|
|
32684
|
+
for (let i5 = parts.length - 1; i5 >= 0; i5--) {
|
|
32685
|
+
const ancestorPath = parts.slice(0, i5).join(import_path4.default.sep) || import_path4.default.sep;
|
|
32686
|
+
try {
|
|
32687
|
+
const resolvedAncestor = (0, import_fs3.realpathSync)(ancestorPath);
|
|
32688
|
+
const remainingParts = parts.slice(i5);
|
|
32689
|
+
return import_path4.default.join(resolvedAncestor, ...remainingParts);
|
|
32690
|
+
} catch (ancestorError) {
|
|
32691
|
+
continue;
|
|
32692
|
+
}
|
|
32693
|
+
}
|
|
32694
|
+
return normalized;
|
|
32695
|
+
}
|
|
32696
|
+
}
|
|
32678
32697
|
async function validateCwdPath(inputPath, defaultPath = process.cwd()) {
|
|
32679
32698
|
const targetPath = inputPath || defaultPath;
|
|
32680
32699
|
const normalizedPath = import_path4.default.normalize(import_path4.default.resolve(targetPath));
|
|
@@ -32707,6 +32726,53 @@ async function validateCwdPath(inputPath, defaultPath = process.cwd()) {
|
|
|
32707
32726
|
}
|
|
32708
32727
|
return normalizedPath;
|
|
32709
32728
|
}
|
|
32729
|
+
function getCommonPrefix(folders) {
|
|
32730
|
+
if (!folders || folders.length === 0) {
|
|
32731
|
+
return process.cwd();
|
|
32732
|
+
}
|
|
32733
|
+
if (folders.length === 1) {
|
|
32734
|
+
return safeRealpath(folders[0]);
|
|
32735
|
+
}
|
|
32736
|
+
const normalized = folders.map((f5) => safeRealpath(f5));
|
|
32737
|
+
const segments = normalized.map((f5) => f5.split(import_path4.default.sep));
|
|
32738
|
+
const minLen = Math.min(...segments.map((s5) => s5.length));
|
|
32739
|
+
const commonSegments = [];
|
|
32740
|
+
for (let i5 = 0; i5 < minLen; i5++) {
|
|
32741
|
+
const segment = segments[0][i5];
|
|
32742
|
+
if (segments.every((s5) => s5[i5] === segment)) {
|
|
32743
|
+
commonSegments.push(segment);
|
|
32744
|
+
} else {
|
|
32745
|
+
break;
|
|
32746
|
+
}
|
|
32747
|
+
}
|
|
32748
|
+
if (commonSegments.length === 0) {
|
|
32749
|
+
return normalized[0];
|
|
32750
|
+
}
|
|
32751
|
+
if (commonSegments.length === 1 && /^[a-zA-Z]:$/.test(commonSegments[0])) {
|
|
32752
|
+
return normalized[0];
|
|
32753
|
+
}
|
|
32754
|
+
if (commonSegments.length === 1 && commonSegments[0] === "") {
|
|
32755
|
+
return normalized[0];
|
|
32756
|
+
}
|
|
32757
|
+
return commonSegments.join(import_path4.default.sep);
|
|
32758
|
+
}
|
|
32759
|
+
function toRelativePath(absolutePath, workspaceRoot) {
|
|
32760
|
+
if (!absolutePath || !workspaceRoot) {
|
|
32761
|
+
return absolutePath;
|
|
32762
|
+
}
|
|
32763
|
+
let normalized = safeRealpath(absolutePath);
|
|
32764
|
+
let normalizedRoot = safeRealpath(workspaceRoot);
|
|
32765
|
+
while (normalizedRoot.length > 1 && normalizedRoot.endsWith(import_path4.default.sep)) {
|
|
32766
|
+
normalizedRoot = normalizedRoot.slice(0, -1);
|
|
32767
|
+
}
|
|
32768
|
+
if (normalized === normalizedRoot) {
|
|
32769
|
+
return ".";
|
|
32770
|
+
}
|
|
32771
|
+
if (normalized.startsWith(normalizedRoot + import_path4.default.sep)) {
|
|
32772
|
+
return import_path4.default.relative(normalizedRoot, normalized);
|
|
32773
|
+
}
|
|
32774
|
+
return absolutePath;
|
|
32775
|
+
}
|
|
32710
32776
|
var import_path4, import_fs3;
|
|
32711
32777
|
var init_path_validation = __esm({
|
|
32712
32778
|
"src/utils/path-validation.js"() {
|
|
@@ -33904,6 +33970,7 @@ async function analyzeAll(options) {
|
|
|
33904
33970
|
sessionId,
|
|
33905
33971
|
debug = false,
|
|
33906
33972
|
cwd,
|
|
33973
|
+
workspaceRoot,
|
|
33907
33974
|
allowedFolders,
|
|
33908
33975
|
provider,
|
|
33909
33976
|
model,
|
|
@@ -33916,10 +33983,11 @@ async function analyzeAll(options) {
|
|
|
33916
33983
|
if (!question) {
|
|
33917
33984
|
throw new Error('The "question" parameter is required.');
|
|
33918
33985
|
}
|
|
33986
|
+
const effectiveWorkspaceRoot = workspaceRoot || cwd || allowedFolders?.[0] || path9;
|
|
33919
33987
|
const delegateOptions = {
|
|
33920
33988
|
debug,
|
|
33921
33989
|
sessionId,
|
|
33922
|
-
path:
|
|
33990
|
+
path: effectiveWorkspaceRoot,
|
|
33923
33991
|
allowedFolders,
|
|
33924
33992
|
provider,
|
|
33925
33993
|
model,
|
|
@@ -38132,21 +38200,24 @@ var init_zod = __esm({
|
|
|
38132
38200
|
// src/tools/edit.js
|
|
38133
38201
|
function isPathAllowed(filePath, allowedFolders) {
|
|
38134
38202
|
if (!allowedFolders || allowedFolders.length === 0) {
|
|
38135
|
-
const resolvedPath3 = (
|
|
38136
|
-
const cwd = (
|
|
38203
|
+
const resolvedPath3 = safeRealpath(filePath);
|
|
38204
|
+
const cwd = safeRealpath(process.cwd());
|
|
38137
38205
|
return resolvedPath3 === cwd || resolvedPath3.startsWith(cwd + import_path5.sep);
|
|
38138
38206
|
}
|
|
38139
|
-
const resolvedPath2 = (
|
|
38207
|
+
const resolvedPath2 = safeRealpath(filePath);
|
|
38140
38208
|
return allowedFolders.some((folder) => {
|
|
38141
|
-
const allowedPath = (
|
|
38209
|
+
const allowedPath = safeRealpath(folder);
|
|
38142
38210
|
return resolvedPath2 === allowedPath || resolvedPath2.startsWith(allowedPath + import_path5.sep);
|
|
38143
38211
|
});
|
|
38144
38212
|
}
|
|
38145
38213
|
function parseFileToolOptions(options = {}) {
|
|
38214
|
+
const allowedFolders = options.allowedFolders || [];
|
|
38146
38215
|
return {
|
|
38147
38216
|
debug: options.debug || false,
|
|
38148
|
-
allowedFolders
|
|
38149
|
-
cwd: options.cwd
|
|
38217
|
+
allowedFolders,
|
|
38218
|
+
cwd: options.cwd,
|
|
38219
|
+
// Consistent fallback chain: workspaceRoot > cwd > allowedFolders[0] > process.cwd()
|
|
38220
|
+
workspaceRoot: options.workspaceRoot || options.cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd()
|
|
38150
38221
|
};
|
|
38151
38222
|
}
|
|
38152
38223
|
var import_ai, import_fs4, import_path5, import_fs5, editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
|
|
@@ -38157,8 +38228,9 @@ var init_edit = __esm({
|
|
|
38157
38228
|
import_fs4 = require("fs");
|
|
38158
38229
|
import_path5 = require("path");
|
|
38159
38230
|
import_fs5 = require("fs");
|
|
38231
|
+
init_path_validation();
|
|
38160
38232
|
editTool = (options = {}) => {
|
|
38161
|
-
const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
|
|
38233
|
+
const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
|
|
38162
38234
|
return (0, import_ai.tool)({
|
|
38163
38235
|
name: "edit",
|
|
38164
38236
|
description: `Edit files using exact string replacement (Claude Code style).
|
|
@@ -38214,7 +38286,8 @@ Important:
|
|
|
38214
38286
|
console.error(`[Edit] Attempting to edit file: ${resolvedPath2}`);
|
|
38215
38287
|
}
|
|
38216
38288
|
if (!isPathAllowed(resolvedPath2, allowedFolders)) {
|
|
38217
|
-
|
|
38289
|
+
const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
|
|
38290
|
+
return `Error editing file: Permission denied - ${relativePath} is outside allowed directories`;
|
|
38218
38291
|
}
|
|
38219
38292
|
if (!(0, import_fs5.existsSync)(resolvedPath2)) {
|
|
38220
38293
|
return `Error editing file: File not found - ${file_path}`;
|
|
@@ -38250,7 +38323,7 @@ Important:
|
|
|
38250
38323
|
});
|
|
38251
38324
|
};
|
|
38252
38325
|
createTool = (options = {}) => {
|
|
38253
|
-
const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
|
|
38326
|
+
const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
|
|
38254
38327
|
return (0, import_ai.tool)({
|
|
38255
38328
|
name: "create",
|
|
38256
38329
|
description: `Create new files with specified content.
|
|
@@ -38298,7 +38371,8 @@ Important:
|
|
|
38298
38371
|
console.error(`[Create] Attempting to create file: ${resolvedPath2}`);
|
|
38299
38372
|
}
|
|
38300
38373
|
if (!isPathAllowed(resolvedPath2, allowedFolders)) {
|
|
38301
|
-
|
|
38374
|
+
const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
|
|
38375
|
+
return `Error creating file: Permission denied - ${relativePath} is outside allowed directories`;
|
|
38302
38376
|
}
|
|
38303
38377
|
if ((0, import_fs5.existsSync)(resolvedPath2) && !overwrite) {
|
|
38304
38378
|
return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
|
|
@@ -39860,7 +39934,7 @@ var init_vercel = __esm({
|
|
|
39860
39934
|
});
|
|
39861
39935
|
};
|
|
39862
39936
|
delegateTool = (options = {}) => {
|
|
39863
|
-
const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null, delegationManager = null } = options;
|
|
39937
|
+
const { debug = false, timeout = 300, cwd, allowedFolders, workspaceRoot, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null, delegationManager = null } = options;
|
|
39864
39938
|
return (0, import_ai2.tool)({
|
|
39865
39939
|
name: "delegate",
|
|
39866
39940
|
description: delegateDescription,
|
|
@@ -39893,8 +39967,8 @@ var init_vercel = __esm({
|
|
|
39893
39967
|
if (searchDelegate !== void 0 && typeof searchDelegate !== "boolean") {
|
|
39894
39968
|
throw new TypeError("searchDelegate must be a boolean if provided");
|
|
39895
39969
|
}
|
|
39896
|
-
const
|
|
39897
|
-
const effectivePath = path9 ||
|
|
39970
|
+
const effectiveWorkspaceRoot = workspaceRoot || allowedFolders && allowedFolders[0];
|
|
39971
|
+
const effectivePath = path9 || effectiveWorkspaceRoot || cwd;
|
|
39898
39972
|
if (debug) {
|
|
39899
39973
|
console.error(`Executing delegate with task: "${task.substring(0, 100)}${task.length > 100 ? "..." : ""}"`);
|
|
39900
39974
|
if (parentSessionId) {
|
|
@@ -39931,7 +40005,7 @@ var init_vercel = __esm({
|
|
|
39931
40005
|
});
|
|
39932
40006
|
};
|
|
39933
40007
|
analyzeAllTool = (options = {}) => {
|
|
39934
|
-
const { sessionId, debug = false, delegationManager = null } = options;
|
|
40008
|
+
const { sessionId, debug = false, delegationManager = null, workspaceRoot } = options;
|
|
39935
40009
|
return (0, import_ai2.tool)({
|
|
39936
40010
|
name: "analyze_all",
|
|
39937
40011
|
description: analyzeAllDescription,
|
|
@@ -39950,12 +40024,14 @@ var init_vercel = __esm({
|
|
|
39950
40024
|
console.error(`[analyze_all] Question: ${question}`);
|
|
39951
40025
|
console.error(`[analyze_all] Path: ${searchPath}`);
|
|
39952
40026
|
}
|
|
40027
|
+
const effectiveWorkspaceRoot = workspaceRoot || options.cwd || options.allowedFolders && options.allowedFolders[0];
|
|
39953
40028
|
const result = await analyzeAll({
|
|
39954
40029
|
question,
|
|
39955
40030
|
path: searchPath,
|
|
39956
40031
|
sessionId,
|
|
39957
40032
|
debug,
|
|
39958
40033
|
cwd: options.cwd,
|
|
40034
|
+
workspaceRoot: effectiveWorkspaceRoot,
|
|
39959
40035
|
allowedFolders: options.allowedFolders,
|
|
39960
40036
|
provider: options.provider,
|
|
39961
40037
|
model: options.model,
|
|
@@ -41432,14 +41508,17 @@ var init_bash = __esm({
|
|
|
41432
41508
|
import_path8 = require("path");
|
|
41433
41509
|
init_bashPermissions();
|
|
41434
41510
|
init_bashExecutor();
|
|
41511
|
+
init_path_validation();
|
|
41435
41512
|
bashTool = (options = {}) => {
|
|
41436
41513
|
const {
|
|
41437
41514
|
bashConfig = {},
|
|
41438
41515
|
debug = false,
|
|
41439
41516
|
cwd,
|
|
41440
41517
|
allowedFolders = [],
|
|
41518
|
+
workspaceRoot: providedWorkspaceRoot,
|
|
41441
41519
|
tracer = null
|
|
41442
41520
|
} = options;
|
|
41521
|
+
const workspaceRoot = providedWorkspaceRoot || cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd();
|
|
41443
41522
|
const permissionChecker = new BashPermissionChecker({
|
|
41444
41523
|
allow: bashConfig.allow,
|
|
41445
41524
|
deny: bashConfig.deny,
|
|
@@ -41455,6 +41534,9 @@ var init_bash = __esm({
|
|
|
41455
41534
|
if (cwd) {
|
|
41456
41535
|
return cwd;
|
|
41457
41536
|
}
|
|
41537
|
+
if (workspaceRoot) {
|
|
41538
|
+
return workspaceRoot;
|
|
41539
|
+
}
|
|
41458
41540
|
if (allowedFolders && allowedFolders.length > 0) {
|
|
41459
41541
|
return allowedFolders[0];
|
|
41460
41542
|
}
|
|
@@ -41542,13 +41624,15 @@ For code exploration, try these safe alternatives:
|
|
|
41542
41624
|
const defaultDir = getDefaultWorkingDirectory();
|
|
41543
41625
|
const workingDir = workingDirectory ? (0, import_path8.isAbsolute)(workingDirectory) ? (0, import_path8.resolve)(workingDirectory) : (0, import_path8.resolve)(defaultDir, workingDirectory) : defaultDir;
|
|
41544
41626
|
if (allowedFolders && allowedFolders.length > 0) {
|
|
41545
|
-
const resolvedWorkingDir = (
|
|
41627
|
+
const resolvedWorkingDir = safeRealpath(workingDir);
|
|
41546
41628
|
const isAllowed = allowedFolders.some((folder) => {
|
|
41547
|
-
const resolvedFolder = (
|
|
41629
|
+
const resolvedFolder = safeRealpath(folder);
|
|
41548
41630
|
return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path8.sep);
|
|
41549
41631
|
});
|
|
41550
41632
|
if (!isAllowed) {
|
|
41551
|
-
|
|
41633
|
+
const relativeDir = toRelativePath(workingDir, workspaceRoot);
|
|
41634
|
+
const relativeAllowed = allowedFolders.map((f5) => toRelativePath(f5, workspaceRoot));
|
|
41635
|
+
return `Error: Working directory "${relativeDir}" is not within allowed folders: ${relativeAllowed.join(", ")}`;
|
|
41552
41636
|
}
|
|
41553
41637
|
}
|
|
41554
41638
|
const executionOptions = {
|
|
@@ -45715,7 +45799,7 @@ var init_esm3 = __esm({
|
|
|
45715
45799
|
});
|
|
45716
45800
|
|
|
45717
45801
|
// node_modules/path-scurry/dist/esm/index.js
|
|
45718
|
-
var import_node_path, import_node_url, import_fs9, actualFS, import_promises,
|
|
45802
|
+
var import_node_path, import_node_url, import_fs9, actualFS, import_promises, realpathSync2, defaultFS, fsFromOption, uncDriveRegexp, uncToDrive, eitherSep, UNKNOWN, IFIFO, IFCHR, IFDIR, IFBLK, IFREG, IFLNK, IFSOCK, IFMT, IFMT_UNKNOWN, READDIR_CALLED, LSTAT_CALLED, ENOTDIR, ENOENT, ENOREADLINK, ENOREALPATH, ENOCHILD, TYPEMASK, entToType, normalizeCache, normalize, normalizeNocaseCache, normalizeNocase, ResolveCache, ChildrenCache, setAsCwd, PathBase, PathWin32, PathPosix, PathScurryBase, PathScurryWin32, PathScurryPosix, PathScurryDarwin, Path, PathScurry;
|
|
45719
45803
|
var init_esm4 = __esm({
|
|
45720
45804
|
"node_modules/path-scurry/dist/esm/index.js"() {
|
|
45721
45805
|
init_esm2();
|
|
@@ -45725,13 +45809,13 @@ var init_esm4 = __esm({
|
|
|
45725
45809
|
actualFS = __toESM(require("node:fs"), 1);
|
|
45726
45810
|
import_promises = require("node:fs/promises");
|
|
45727
45811
|
init_esm3();
|
|
45728
|
-
|
|
45812
|
+
realpathSync2 = import_fs9.realpathSync.native;
|
|
45729
45813
|
defaultFS = {
|
|
45730
45814
|
lstatSync: import_fs9.lstatSync,
|
|
45731
45815
|
readdir: import_fs9.readdir,
|
|
45732
45816
|
readdirSync: import_fs9.readdirSync,
|
|
45733
45817
|
readlinkSync: import_fs9.readlinkSync,
|
|
45734
|
-
realpathSync,
|
|
45818
|
+
realpathSync: realpathSync2,
|
|
45735
45819
|
promises: {
|
|
45736
45820
|
lstat: import_promises.lstat,
|
|
45737
45821
|
readdir: import_promises.readdir,
|
|
@@ -49551,11 +49635,12 @@ function createTools(configOptions) {
|
|
|
49551
49635
|
return tools2;
|
|
49552
49636
|
}
|
|
49553
49637
|
function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
49554
|
-
const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
49638
|
+
const { cleanedXmlString, recoveryResult, thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
49555
49639
|
if (recoveryResult) {
|
|
49556
|
-
return recoveryResult;
|
|
49640
|
+
return { ...recoveryResult, thinkingContent };
|
|
49557
49641
|
}
|
|
49558
|
-
|
|
49642
|
+
const toolCall = parseXmlToolCall(cleanedXmlString, validTools);
|
|
49643
|
+
return toolCall ? { ...toolCall, thinkingContent } : null;
|
|
49559
49644
|
}
|
|
49560
49645
|
var import_crypto4, implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
|
|
49561
49646
|
var init_tools2 = __esm({
|
|
@@ -88850,25 +88935,27 @@ function parseXmlMcpToolCall(xmlString, mcpToolNames = []) {
|
|
|
88850
88935
|
function parseHybridXmlToolCall(xmlString, nativeTools = [], mcpBridge = null) {
|
|
88851
88936
|
const nativeResult = parseNativeXmlToolWithThinking(xmlString, nativeTools);
|
|
88852
88937
|
if (nativeResult) {
|
|
88853
|
-
|
|
88938
|
+
const { thinkingContent, ...rest } = nativeResult;
|
|
88939
|
+
return { ...rest, type: "native", thinkingContent };
|
|
88854
88940
|
}
|
|
88855
88941
|
if (mcpBridge) {
|
|
88856
88942
|
const mcpResult = parseXmlMcpToolCall(xmlString, mcpBridge.getToolNames());
|
|
88857
88943
|
if (mcpResult) {
|
|
88858
|
-
|
|
88944
|
+
const { thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, []);
|
|
88945
|
+
return { ...mcpResult, type: "mcp", thinkingContent };
|
|
88859
88946
|
}
|
|
88860
88947
|
}
|
|
88861
88948
|
return null;
|
|
88862
88949
|
}
|
|
88863
88950
|
function parseNativeXmlToolWithThinking(xmlString, validTools) {
|
|
88864
|
-
const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
88951
|
+
const { cleanedXmlString, recoveryResult, thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
88865
88952
|
if (recoveryResult) {
|
|
88866
|
-
return recoveryResult;
|
|
88953
|
+
return { ...recoveryResult, thinkingContent };
|
|
88867
88954
|
}
|
|
88868
88955
|
for (const toolName of validTools) {
|
|
88869
88956
|
const result = parseNativeXmlTool(cleanedXmlString, toolName);
|
|
88870
88957
|
if (result) {
|
|
88871
|
-
return result;
|
|
88958
|
+
return { ...result, thinkingContent };
|
|
88872
88959
|
}
|
|
88873
88960
|
}
|
|
88874
88961
|
return null;
|
|
@@ -99123,6 +99210,7 @@ var init_ProbeAgent = __esm({
|
|
|
99123
99210
|
init_FallbackManager();
|
|
99124
99211
|
init_contextCompactor();
|
|
99125
99212
|
init_error_types();
|
|
99213
|
+
init_path_validation();
|
|
99126
99214
|
init_outputTruncator();
|
|
99127
99215
|
init_delegate();
|
|
99128
99216
|
init_tasks();
|
|
@@ -99240,7 +99328,8 @@ var init_ProbeAgent = __esm({
|
|
|
99240
99328
|
} else {
|
|
99241
99329
|
this.allowedFolders = [process.cwd()];
|
|
99242
99330
|
}
|
|
99243
|
-
this.
|
|
99331
|
+
this.workspaceRoot = getCommonPrefix(this.allowedFolders);
|
|
99332
|
+
this.cwd = options.cwd || this.workspaceRoot;
|
|
99244
99333
|
this.clientApiProvider = options.provider || null;
|
|
99245
99334
|
this.clientApiModel = options.model || null;
|
|
99246
99335
|
this.clientApiKey = null;
|
|
@@ -99252,6 +99341,8 @@ var init_ProbeAgent = __esm({
|
|
|
99252
99341
|
console.log(`[DEBUG] Maximum tool iterations configured: ${MAX_TOOL_ITERATIONS}`);
|
|
99253
99342
|
console.log(`[DEBUG] Allow Edit (implement tool): ${this.allowEdit}`);
|
|
99254
99343
|
console.log(`[DEBUG] Search delegation enabled: ${this.searchDelegate}`);
|
|
99344
|
+
console.log(`[DEBUG] Workspace root: ${this.workspaceRoot}`);
|
|
99345
|
+
console.log(`[DEBUG] Working directory (cwd): ${this.cwd}`);
|
|
99255
99346
|
}
|
|
99256
99347
|
this.initializeTools();
|
|
99257
99348
|
this.history = [];
|
|
@@ -99329,6 +99420,181 @@ var init_ProbeAgent = __esm({
|
|
|
99329
99420
|
_filterMcpTools(mcpToolNames) {
|
|
99330
99421
|
return mcpToolNames.filter((toolName) => this._isMcpToolAllowed(toolName));
|
|
99331
99422
|
}
|
|
99423
|
+
/**
|
|
99424
|
+
* Check if tracer is AppTracer (expects sessionId as first param) vs SimpleAppTracer
|
|
99425
|
+
* @returns {boolean} - True if tracer is AppTracer style (requires sessionId)
|
|
99426
|
+
* @private
|
|
99427
|
+
*/
|
|
99428
|
+
_isAppTracerStyle() {
|
|
99429
|
+
return this.tracer && typeof this.tracer.sessionSpans !== "undefined";
|
|
99430
|
+
}
|
|
99431
|
+
/**
|
|
99432
|
+
* Record an error classification event for telemetry
|
|
99433
|
+
* Provides unified error recording across all error types
|
|
99434
|
+
* @param {string} errorType - Error type (wrapped_tool, unrecognized_tool, no_tool_call, circuit_breaker)
|
|
99435
|
+
* @param {string} message - Error message
|
|
99436
|
+
* @param {Object} context - Additional context data
|
|
99437
|
+
* @param {number} iteration - Current iteration number
|
|
99438
|
+
* @private
|
|
99439
|
+
*/
|
|
99440
|
+
_recordErrorTelemetry(errorType, message, context, iteration) {
|
|
99441
|
+
if (!this.tracer) return;
|
|
99442
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordErrorClassification === "function") {
|
|
99443
|
+
this.tracer.recordErrorClassification(this.sessionId, iteration, errorType, {
|
|
99444
|
+
message,
|
|
99445
|
+
context
|
|
99446
|
+
});
|
|
99447
|
+
} else if (typeof this.tracer.recordErrorEvent === "function") {
|
|
99448
|
+
this.tracer.recordErrorEvent(errorType, {
|
|
99449
|
+
message,
|
|
99450
|
+
context: { ...context, iteration }
|
|
99451
|
+
});
|
|
99452
|
+
} else {
|
|
99453
|
+
this.tracer.addEvent(`error.${errorType}`, {
|
|
99454
|
+
"error.type": errorType,
|
|
99455
|
+
"error.message": message,
|
|
99456
|
+
"error.recoverable": errorType !== "circuit_breaker",
|
|
99457
|
+
"error.context": JSON.stringify(context).substring(0, 1e3),
|
|
99458
|
+
"iteration": iteration
|
|
99459
|
+
});
|
|
99460
|
+
}
|
|
99461
|
+
}
|
|
99462
|
+
/**
|
|
99463
|
+
* Record AI thinking content for telemetry
|
|
99464
|
+
* @param {string} thinkingContent - The thinking content
|
|
99465
|
+
* @param {number} iteration - Current iteration number
|
|
99466
|
+
* @private
|
|
99467
|
+
*/
|
|
99468
|
+
_recordThinkingTelemetry(thinkingContent, iteration) {
|
|
99469
|
+
if (!this.tracer || !thinkingContent) return;
|
|
99470
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordThinkingContent === "function") {
|
|
99471
|
+
this.tracer.recordThinkingContent(this.sessionId, iteration, thinkingContent);
|
|
99472
|
+
} else if (typeof this.tracer.recordThinkingContent === "function") {
|
|
99473
|
+
this.tracer.recordThinkingContent(thinkingContent, { iteration });
|
|
99474
|
+
} else {
|
|
99475
|
+
this.tracer.addEvent("ai.thinking", {
|
|
99476
|
+
"ai.thinking.content": thinkingContent.substring(0, 5e4),
|
|
99477
|
+
"ai.thinking.length": thinkingContent.length,
|
|
99478
|
+
"iteration": iteration
|
|
99479
|
+
});
|
|
99480
|
+
}
|
|
99481
|
+
}
|
|
99482
|
+
/**
|
|
99483
|
+
* Record AI tool decision for telemetry
|
|
99484
|
+
* @param {string} toolName - The tool name
|
|
99485
|
+
* @param {Object} params - Tool parameters
|
|
99486
|
+
* @param {number} responseLength - Length of AI response
|
|
99487
|
+
* @param {number} iteration - Current iteration number
|
|
99488
|
+
* @private
|
|
99489
|
+
*/
|
|
99490
|
+
_recordToolDecisionTelemetry(toolName, params, responseLength, iteration) {
|
|
99491
|
+
if (!this.tracer) return;
|
|
99492
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordAIToolDecision === "function") {
|
|
99493
|
+
this.tracer.recordAIToolDecision(this.sessionId, iteration, toolName, params);
|
|
99494
|
+
} else if (typeof this.tracer.recordToolDecision === "function") {
|
|
99495
|
+
this.tracer.recordToolDecision(toolName, params, {
|
|
99496
|
+
iteration,
|
|
99497
|
+
"ai.tool_decision.raw_response_length": responseLength
|
|
99498
|
+
});
|
|
99499
|
+
} else {
|
|
99500
|
+
this.tracer.addEvent("ai.tool_decision", {
|
|
99501
|
+
"ai.tool_decision.name": toolName,
|
|
99502
|
+
"ai.tool_decision.params": JSON.stringify(params || {}).substring(0, 2e3),
|
|
99503
|
+
"ai.tool_decision.raw_response_length": responseLength,
|
|
99504
|
+
"iteration": iteration
|
|
99505
|
+
});
|
|
99506
|
+
}
|
|
99507
|
+
}
|
|
99508
|
+
/**
|
|
99509
|
+
* Record tool result for telemetry
|
|
99510
|
+
* @param {string} toolName - The tool name
|
|
99511
|
+
* @param {string|Object} result - Tool result
|
|
99512
|
+
* @param {boolean} success - Whether tool succeeded
|
|
99513
|
+
* @param {number} durationMs - Execution duration in milliseconds
|
|
99514
|
+
* @param {number} iteration - Current iteration number
|
|
99515
|
+
* @private
|
|
99516
|
+
*/
|
|
99517
|
+
_recordToolResultTelemetry(toolName, result, success, durationMs, iteration) {
|
|
99518
|
+
if (!this.tracer) return;
|
|
99519
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordToolResult === "function") {
|
|
99520
|
+
this.tracer.recordToolResult(this.sessionId, iteration, toolName, result, success, durationMs);
|
|
99521
|
+
} else if (typeof this.tracer.recordToolResult === "function") {
|
|
99522
|
+
this.tracer.recordToolResult(toolName, result, success, durationMs, { iteration });
|
|
99523
|
+
} else {
|
|
99524
|
+
const resultStr = typeof result === "string" ? result : JSON.stringify(result || "");
|
|
99525
|
+
this.tracer.addEvent("tool.result", {
|
|
99526
|
+
"tool.name": toolName,
|
|
99527
|
+
"tool.result": resultStr.substring(0, 1e4),
|
|
99528
|
+
"tool.result.length": resultStr.length,
|
|
99529
|
+
"tool.duration_ms": durationMs,
|
|
99530
|
+
"tool.success": success,
|
|
99531
|
+
"iteration": iteration
|
|
99532
|
+
});
|
|
99533
|
+
}
|
|
99534
|
+
}
|
|
99535
|
+
/**
|
|
99536
|
+
* Record MCP tool lifecycle event for telemetry
|
|
99537
|
+
* @param {string} phase - 'start' or 'end'
|
|
99538
|
+
* @param {string} toolName - MCP tool name
|
|
99539
|
+
* @param {Object} params - Tool parameters (for start) or null (for end)
|
|
99540
|
+
* @param {number} iteration - Current iteration number
|
|
99541
|
+
* @param {Object} [endData] - Additional data for end phase (result, success, durationMs, error)
|
|
99542
|
+
* @private
|
|
99543
|
+
*/
|
|
99544
|
+
_recordMcpToolTelemetry(phase, toolName, params, iteration, endData = null) {
|
|
99545
|
+
if (!this.tracer) return;
|
|
99546
|
+
if (phase === "start") {
|
|
99547
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordMcpToolStart === "function") {
|
|
99548
|
+
this.tracer.recordMcpToolStart(this.sessionId, iteration, toolName, "mcp", params);
|
|
99549
|
+
} else if (typeof this.tracer.recordMcpToolStart === "function") {
|
|
99550
|
+
this.tracer.recordMcpToolStart(toolName, "mcp", params, { iteration });
|
|
99551
|
+
} else {
|
|
99552
|
+
this.tracer.addEvent("mcp.tool.start", {
|
|
99553
|
+
"mcp.tool.name": toolName,
|
|
99554
|
+
"mcp.tool.server": "mcp",
|
|
99555
|
+
"mcp.tool.params": JSON.stringify(params || {}).substring(0, 2e3),
|
|
99556
|
+
"iteration": iteration
|
|
99557
|
+
});
|
|
99558
|
+
}
|
|
99559
|
+
} else if (phase === "end" && endData) {
|
|
99560
|
+
const { result, success, durationMs, error: error2 } = endData;
|
|
99561
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordMcpToolEnd === "function") {
|
|
99562
|
+
this.tracer.recordMcpToolEnd(this.sessionId, iteration, toolName, "mcp", result, success, durationMs, error2);
|
|
99563
|
+
} else if (typeof this.tracer.recordMcpToolEnd === "function") {
|
|
99564
|
+
this.tracer.recordMcpToolEnd(toolName, "mcp", result, success, durationMs, error2, { iteration });
|
|
99565
|
+
} else {
|
|
99566
|
+
const resultStr = typeof result === "string" ? result : JSON.stringify(result || "");
|
|
99567
|
+
this.tracer.addEvent("mcp.tool.end", {
|
|
99568
|
+
"mcp.tool.name": toolName,
|
|
99569
|
+
"mcp.tool.server": "mcp",
|
|
99570
|
+
"mcp.tool.result": resultStr.substring(0, 1e4),
|
|
99571
|
+
"mcp.tool.result.length": resultStr.length,
|
|
99572
|
+
"mcp.tool.duration_ms": durationMs,
|
|
99573
|
+
"mcp.tool.success": success,
|
|
99574
|
+
"mcp.tool.error": error2,
|
|
99575
|
+
"iteration": iteration
|
|
99576
|
+
});
|
|
99577
|
+
}
|
|
99578
|
+
}
|
|
99579
|
+
}
|
|
99580
|
+
/**
|
|
99581
|
+
* Record iteration lifecycle event for telemetry
|
|
99582
|
+
* @param {string} phase - 'end' (start is already handled elsewhere)
|
|
99583
|
+
* @param {number} iteration - Current iteration number
|
|
99584
|
+
* @param {Object} data - Additional iteration data
|
|
99585
|
+
* @private
|
|
99586
|
+
*/
|
|
99587
|
+
_recordIterationTelemetry(phase, iteration, data2 = {}) {
|
|
99588
|
+
if (!this.tracer) return;
|
|
99589
|
+
if (typeof this.tracer.recordIterationEvent === "function") {
|
|
99590
|
+
this.tracer.recordIterationEvent(phase, iteration, data2);
|
|
99591
|
+
} else {
|
|
99592
|
+
this.tracer.addEvent(`iteration.${phase}`, {
|
|
99593
|
+
"iteration": iteration,
|
|
99594
|
+
...data2
|
|
99595
|
+
});
|
|
99596
|
+
}
|
|
99597
|
+
}
|
|
99332
99598
|
/**
|
|
99333
99599
|
* Initialize the agent asynchronously (must be called after constructor)
|
|
99334
99600
|
* This method initializes MCP and merges MCP tools into the tool list, and loads history from storage
|
|
@@ -99424,8 +99690,9 @@ var init_ProbeAgent = __esm({
|
|
|
99424
99690
|
const configOptions = {
|
|
99425
99691
|
sessionId: this.sessionId,
|
|
99426
99692
|
debug: this.debug,
|
|
99427
|
-
// Use
|
|
99428
|
-
cwd: this.cwd
|
|
99693
|
+
// Use cwd (which defaults to workspaceRoot in constructor)
|
|
99694
|
+
cwd: this.cwd,
|
|
99695
|
+
workspaceRoot: this.workspaceRoot,
|
|
99429
99696
|
allowedFolders: this.allowedFolders,
|
|
99430
99697
|
outline: this.outline,
|
|
99431
99698
|
searchDelegate: this.searchDelegate,
|
|
@@ -100112,16 +100379,16 @@ var init_ProbeAgent = __esm({
|
|
|
100112
100379
|
let absolutePath;
|
|
100113
100380
|
let isPathAllowed2 = false;
|
|
100114
100381
|
if ((0, import_path17.isAbsolute)(imagePath)) {
|
|
100115
|
-
absolutePath = (
|
|
100382
|
+
absolutePath = safeRealpath((0, import_path17.resolve)(imagePath));
|
|
100116
100383
|
isPathAllowed2 = allowedDirs.some((dir) => {
|
|
100117
|
-
const
|
|
100118
|
-
return absolutePath ===
|
|
100384
|
+
const resolvedDir = safeRealpath(dir);
|
|
100385
|
+
return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path17.sep);
|
|
100119
100386
|
});
|
|
100120
100387
|
} else {
|
|
100121
100388
|
for (const dir of allowedDirs) {
|
|
100122
|
-
const
|
|
100123
|
-
const resolvedPath2 = (
|
|
100124
|
-
if (resolvedPath2 ===
|
|
100389
|
+
const resolvedDir = safeRealpath(dir);
|
|
100390
|
+
const resolvedPath2 = safeRealpath((0, import_path17.resolve)(dir, imagePath));
|
|
100391
|
+
if (resolvedPath2 === resolvedDir || resolvedPath2.startsWith(resolvedDir + import_path17.sep)) {
|
|
100125
100392
|
absolutePath = resolvedPath2;
|
|
100126
100393
|
isPathAllowed2 = true;
|
|
100127
100394
|
break;
|
|
@@ -100304,7 +100571,7 @@ var init_ProbeAgent = __esm({
|
|
|
100304
100571
|
if (this._architectureContextLoaded) {
|
|
100305
100572
|
return this.architectureContext;
|
|
100306
100573
|
}
|
|
100307
|
-
const rootDirectory = this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd();
|
|
100574
|
+
const rootDirectory = this.workspaceRoot || (this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd());
|
|
100308
100575
|
const configuredName = typeof this.architectureFileName === "string" ? this.architectureFileName.trim() : "";
|
|
100309
100576
|
const hasConfiguredName = !!configuredName;
|
|
100310
100577
|
let guidanceCandidates = [];
|
|
@@ -100441,6 +100708,9 @@ ${this.architectureContext.content}
|
|
|
100441
100708
|
`;
|
|
100442
100709
|
}
|
|
100443
100710
|
_getSkillsRepoRoot() {
|
|
100711
|
+
if (this.workspaceRoot) {
|
|
100712
|
+
return (0, import_path17.resolve)(this.workspaceRoot);
|
|
100713
|
+
}
|
|
100444
100714
|
if (this.allowedFolders && this.allowedFolders.length > 0) {
|
|
100445
100715
|
return (0, import_path17.resolve)(this.allowedFolders[0]);
|
|
100446
100716
|
}
|
|
@@ -100508,7 +100778,7 @@ Workspace: ${this.allowedFolders.join(", ")}`;
|
|
|
100508
100778
|
|
|
100509
100779
|
# Repository Structure
|
|
100510
100780
|
`;
|
|
100511
|
-
systemPrompt += `You are working with a repository located at: ${this.
|
|
100781
|
+
systemPrompt += `You are working with a repository located at: ${this.workspaceRoot}
|
|
100512
100782
|
|
|
100513
100783
|
`;
|
|
100514
100784
|
systemPrompt += `Here's an overview of the repository structure (showing up to 100 most relevant files):
|
|
@@ -100561,7 +100831,7 @@ Workspace: ${this.allowedFolders.join(", ")}`;
|
|
|
100561
100831
|
|
|
100562
100832
|
# Repository Structure
|
|
100563
100833
|
`;
|
|
100564
|
-
systemPrompt += `You are working with a repository located at: ${this.
|
|
100834
|
+
systemPrompt += `You are working with a repository located at: ${this.workspaceRoot}
|
|
100565
100835
|
|
|
100566
100836
|
`;
|
|
100567
100837
|
systemPrompt += `Here's an overview of the repository structure (showing up to 100 most relevant files):
|
|
@@ -100860,21 +101130,34 @@ For MCP tools, use JSON format within the params tag, e.g.:
|
|
|
100860
101130
|
`;
|
|
100861
101131
|
}
|
|
100862
101132
|
}
|
|
100863
|
-
const searchDirectory = this.
|
|
101133
|
+
const searchDirectory = this.workspaceRoot;
|
|
100864
101134
|
if (this.debug) {
|
|
100865
|
-
console.log(`[DEBUG] Generating file list for
|
|
101135
|
+
console.log(`[DEBUG] Generating file list for workspace root: ${searchDirectory}...`);
|
|
101136
|
+
}
|
|
101137
|
+
const relativeWorkspaces = this.allowedFolders.map((f5) => {
|
|
101138
|
+
const rel = toRelativePath(f5, this.workspaceRoot);
|
|
101139
|
+
if (rel && rel !== "." && !rel.startsWith(".") && !rel.startsWith("/")) {
|
|
101140
|
+
return "./" + rel;
|
|
101141
|
+
}
|
|
101142
|
+
return rel;
|
|
101143
|
+
}).filter((f5) => f5 && f5 !== ".");
|
|
101144
|
+
let workspaceDesc;
|
|
101145
|
+
if (relativeWorkspaces.length === 0) {
|
|
101146
|
+
workspaceDesc = ". (current directory)";
|
|
101147
|
+
} else {
|
|
101148
|
+
workspaceDesc = relativeWorkspaces.join(", ");
|
|
100866
101149
|
}
|
|
100867
101150
|
try {
|
|
100868
101151
|
const files = await listFilesByLevel({
|
|
100869
101152
|
directory: searchDirectory,
|
|
100870
101153
|
maxFiles: 100,
|
|
100871
101154
|
respectGitignore: !process.env.PROBE_NO_GITIGNORE || process.env.PROBE_NO_GITIGNORE === "",
|
|
100872
|
-
cwd:
|
|
101155
|
+
cwd: this.workspaceRoot
|
|
100873
101156
|
});
|
|
100874
101157
|
systemMessage += `
|
|
100875
101158
|
# Repository Structure
|
|
100876
101159
|
|
|
100877
|
-
You are working with a
|
|
101160
|
+
You are working with a workspace. Available paths: ${workspaceDesc}
|
|
100878
101161
|
|
|
100879
101162
|
Here's an overview of the repository structure (showing up to 100 most relevant files):
|
|
100880
101163
|
|
|
@@ -100890,15 +101173,22 @@ ${files}
|
|
|
100890
101173
|
systemMessage += `
|
|
100891
101174
|
# Repository Structure
|
|
100892
101175
|
|
|
100893
|
-
You are working with a
|
|
101176
|
+
You are working with a workspace. Available paths: ${workspaceDesc}
|
|
100894
101177
|
|
|
100895
101178
|
`;
|
|
100896
101179
|
}
|
|
100897
101180
|
await this.loadArchitectureContext();
|
|
100898
101181
|
systemMessage += this.getArchitectureSection();
|
|
100899
101182
|
if (this.allowedFolders.length > 0) {
|
|
101183
|
+
const relativeAllowed = this.allowedFolders.map((f5) => {
|
|
101184
|
+
const rel = toRelativePath(f5, this.workspaceRoot);
|
|
101185
|
+
if (rel && rel !== "." && !rel.startsWith(".") && !rel.startsWith("/")) {
|
|
101186
|
+
return "./" + rel;
|
|
101187
|
+
}
|
|
101188
|
+
return rel;
|
|
101189
|
+
});
|
|
100900
101190
|
systemMessage += `
|
|
100901
|
-
**Important**: For security reasons, you can only
|
|
101191
|
+
**Important**: For security reasons, you can only access these paths: ${relativeAllowed.join(", ")}
|
|
100902
101192
|
|
|
100903
101193
|
`;
|
|
100904
101194
|
}
|
|
@@ -101283,8 +101573,12 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
101283
101573
|
}
|
|
101284
101574
|
const nativeTools = validTools;
|
|
101285
101575
|
const parsedTool = this.mcpBridge && !options._disableTools ? parseHybridXmlToolCall(assistantResponseContent, nativeTools, this.mcpBridge) : parseXmlToolCallWithThinking(assistantResponseContent, validTools);
|
|
101576
|
+
if (parsedTool?.thinkingContent) {
|
|
101577
|
+
this._recordThinkingTelemetry(parsedTool.thinkingContent, currentIteration);
|
|
101578
|
+
}
|
|
101286
101579
|
if (parsedTool) {
|
|
101287
101580
|
const { toolName, params } = parsedTool;
|
|
101581
|
+
this._recordToolDecisionTelemetry(toolName, params, assistantResponseContent.length, currentIteration);
|
|
101288
101582
|
if (this.debug) console.log(`[DEBUG] Parsed tool call: ${toolName} with params:`, params);
|
|
101289
101583
|
if (toolName === "attempt_completion") {
|
|
101290
101584
|
completionAttempted = true;
|
|
@@ -101361,6 +101655,8 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
101361
101655
|
} else {
|
|
101362
101656
|
const { type } = parsedTool;
|
|
101363
101657
|
if (type === "mcp" && this.mcpBridge && this.mcpBridge.isMcpTool(toolName)) {
|
|
101658
|
+
const mcpStartTime = Date.now();
|
|
101659
|
+
this._recordMcpToolTelemetry("start", toolName, params, currentIteration);
|
|
101364
101660
|
try {
|
|
101365
101661
|
if (this.debug) {
|
|
101366
101662
|
console.error(`
|
|
@@ -101390,6 +101686,13 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
101390
101686
|
} catch (truncateError) {
|
|
101391
101687
|
console.error(`[WARN] Tool output truncation failed: ${truncateError.message}`);
|
|
101392
101688
|
}
|
|
101689
|
+
const mcpDurationMs = Date.now() - mcpStartTime;
|
|
101690
|
+
this._recordMcpToolTelemetry("end", toolName, null, currentIteration, {
|
|
101691
|
+
result: toolResultContent,
|
|
101692
|
+
success: true,
|
|
101693
|
+
durationMs: mcpDurationMs,
|
|
101694
|
+
error: null
|
|
101695
|
+
});
|
|
101393
101696
|
if (this.debug) {
|
|
101394
101697
|
const preview = toolResultContent.length > 500 ? toolResultContent.substring(0, 500) + "..." : toolResultContent;
|
|
101395
101698
|
console.error(`[DEBUG] ========================================`);
|
|
@@ -101399,10 +101702,18 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
101399
101702
|
console.error(`[DEBUG] ========================================
|
|
101400
101703
|
`);
|
|
101401
101704
|
}
|
|
101705
|
+
currentMessages.push({ role: "assistant", content: assistantResponseContent });
|
|
101402
101706
|
currentMessages.push({ role: "user", content: `<tool_result>
|
|
101403
101707
|
${toolResultContent}
|
|
101404
101708
|
</tool_result>` });
|
|
101405
101709
|
} catch (error2) {
|
|
101710
|
+
const mcpDurationMs = Date.now() - mcpStartTime;
|
|
101711
|
+
this._recordMcpToolTelemetry("end", toolName, null, currentIteration, {
|
|
101712
|
+
result: null,
|
|
101713
|
+
success: false,
|
|
101714
|
+
durationMs: mcpDurationMs,
|
|
101715
|
+
error: error2.message
|
|
101716
|
+
});
|
|
101406
101717
|
console.error(`Error executing MCP tool ${toolName}:`, error2);
|
|
101407
101718
|
if (this.debug) {
|
|
101408
101719
|
console.error(`[DEBUG] ========================================`);
|
|
@@ -101412,17 +101723,18 @@ ${toolResultContent}
|
|
|
101412
101723
|
`);
|
|
101413
101724
|
}
|
|
101414
101725
|
const errorXml = formatErrorForAI(error2);
|
|
101726
|
+
currentMessages.push({ role: "assistant", content: assistantResponseContent });
|
|
101415
101727
|
currentMessages.push({ role: "user", content: `<tool_result>
|
|
101416
101728
|
${errorXml}
|
|
101417
101729
|
</tool_result>` });
|
|
101418
101730
|
}
|
|
101419
101731
|
} else if (this.toolImplementations[toolName]) {
|
|
101420
101732
|
try {
|
|
101421
|
-
let resolvedWorkingDirectory = this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
|
|
101733
|
+
let resolvedWorkingDirectory = this.workspaceRoot || this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
|
|
101422
101734
|
if (params.workingDirectory) {
|
|
101423
|
-
const requestedDir = (0, import_path17.isAbsolute)(params.workingDirectory) ? (0, import_path17.resolve)(params.workingDirectory) : (0, import_path17.resolve)(resolvedWorkingDirectory, params.workingDirectory);
|
|
101735
|
+
const requestedDir = safeRealpath((0, import_path17.isAbsolute)(params.workingDirectory) ? (0, import_path17.resolve)(params.workingDirectory) : (0, import_path17.resolve)(resolvedWorkingDirectory, params.workingDirectory));
|
|
101424
101736
|
const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 || this.allowedFolders.some((folder) => {
|
|
101425
|
-
const resolvedFolder = (
|
|
101737
|
+
const resolvedFolder = safeRealpath(folder);
|
|
101426
101738
|
return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path17.sep);
|
|
101427
101739
|
});
|
|
101428
101740
|
if (isWithinAllowed) {
|
|
@@ -101494,6 +101806,7 @@ ${errorXml}
|
|
|
101494
101806
|
return await this.toolImplementations[toolName].execute(toolParams);
|
|
101495
101807
|
};
|
|
101496
101808
|
let toolResult;
|
|
101809
|
+
const toolStartTime = Date.now();
|
|
101497
101810
|
try {
|
|
101498
101811
|
if (this.tracer) {
|
|
101499
101812
|
toolResult = await this.tracer.withSpan("tool.call", executeToolCall, {
|
|
@@ -101504,6 +101817,8 @@ ${errorXml}
|
|
|
101504
101817
|
} else {
|
|
101505
101818
|
toolResult = await executeToolCall();
|
|
101506
101819
|
}
|
|
101820
|
+
const toolDurationMs = Date.now() - toolStartTime;
|
|
101821
|
+
this._recordToolResultTelemetry(toolName, toolResult, true, toolDurationMs, currentIteration);
|
|
101507
101822
|
if (this.debug) {
|
|
101508
101823
|
const resultPreview = typeof toolResult === "string" ? toolResult.length > 500 ? toolResult.substring(0, 500) + "..." : toolResult : toolResult ? JSON.stringify(toolResult, null, 2).substring(0, 500) + "..." : "No Result";
|
|
101509
101824
|
console.error(`[DEBUG] ========================================`);
|
|
@@ -101560,6 +101875,20 @@ ${toolResultContent}
|
|
|
101560
101875
|
role: "user",
|
|
101561
101876
|
content: toolResultMessage
|
|
101562
101877
|
});
|
|
101878
|
+
if (this.tracer) {
|
|
101879
|
+
if (typeof this.tracer.recordConversationTurn === "function") {
|
|
101880
|
+
this.tracer.recordConversationTurn("assistant", assistantResponseContent, {
|
|
101881
|
+
iteration: currentIteration,
|
|
101882
|
+
has_tool_call: true,
|
|
101883
|
+
tool_name: toolName
|
|
101884
|
+
});
|
|
101885
|
+
this.tracer.recordConversationTurn("tool_result", toolResultContent, {
|
|
101886
|
+
iteration: currentIteration,
|
|
101887
|
+
tool_name: toolName,
|
|
101888
|
+
tool_success: true
|
|
101889
|
+
});
|
|
101890
|
+
}
|
|
101891
|
+
}
|
|
101563
101892
|
if (this.debug) {
|
|
101564
101893
|
console.log(`[DEBUG] Tool ${toolName} executed successfully. Result length: ${typeof toolResult === "string" ? toolResult.length : JSON.stringify(toolResult).length}`);
|
|
101565
101894
|
}
|
|
@@ -101630,6 +101959,7 @@ ${errorXml}
|
|
|
101630
101959
|
if (this.debug) {
|
|
101631
101960
|
console.log(`[DEBUG] Detected wrapped tool '${wrappedToolName}' in assistant response - wrong XML format.`);
|
|
101632
101961
|
}
|
|
101962
|
+
this._recordErrorTelemetry("wrapped_tool", "Tool call wrapped in markdown", { toolName: wrappedToolName }, currentIteration);
|
|
101633
101963
|
const toolError = new ParameterError(
|
|
101634
101964
|
`Tool '${wrappedToolName}' found but in WRONG FORMAT - do not wrap tools in other XML tags.`,
|
|
101635
101965
|
{
|
|
@@ -101655,6 +101985,7 @@ ${formatErrorForAI(toolError)}
|
|
|
101655
101985
|
if (this.debug) {
|
|
101656
101986
|
console.log(`[DEBUG] Detected unrecognized tool '${unrecognizedTool}' in assistant response.`);
|
|
101657
101987
|
}
|
|
101988
|
+
this._recordErrorTelemetry("unrecognized_tool", `Unknown tool: ${unrecognizedTool}`, { toolName: unrecognizedTool, validTools }, currentIteration);
|
|
101658
101989
|
const toolError = new ParameterError(`Tool '${unrecognizedTool}' is not available in this context.`, {
|
|
101659
101990
|
suggestion: `Available tools: ${validTools.join(", ")}. Please use one of these tools instead.`
|
|
101660
101991
|
});
|
|
@@ -101662,6 +101993,7 @@ ${formatErrorForAI(toolError)}
|
|
|
101662
101993
|
${formatErrorForAI(toolError)}
|
|
101663
101994
|
</tool_result>`;
|
|
101664
101995
|
} else {
|
|
101996
|
+
this._recordErrorTelemetry("no_tool_call", "AI response did not contain tool call", { responsePreview: assistantResponseContent.substring(0, 500) }, currentIteration);
|
|
101665
101997
|
if (currentIteration >= maxIterations) {
|
|
101666
101998
|
let cleanedResponse = assistantResponseContent;
|
|
101667
101999
|
cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "").trim();
|
|
@@ -101737,6 +102069,7 @@ Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant messa
|
|
|
101737
102069
|
sameFormatErrorCount++;
|
|
101738
102070
|
if (sameFormatErrorCount >= MAX_REPEATED_FORMAT_ERRORS) {
|
|
101739
102071
|
const errorDesc = isWrapped ? "wrapped tool format" : unrecognizedTool;
|
|
102072
|
+
this._recordErrorTelemetry("circuit_breaker", "Format error limit exceeded", { formatErrorCount: sameFormatErrorCount, errorCategory }, currentIteration);
|
|
101740
102073
|
console.error(`[ERROR] Format error category '${errorCategory}' repeated ${sameFormatErrorCount} times. Breaking loop early to prevent infinite iteration.`);
|
|
101741
102074
|
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.`;
|
|
101742
102075
|
break;
|
|
@@ -101750,6 +102083,10 @@ Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant messa
|
|
|
101750
102083
|
sameFormatErrorCount = 0;
|
|
101751
102084
|
}
|
|
101752
102085
|
}
|
|
102086
|
+
this._recordIterationTelemetry("end", currentIteration, {
|
|
102087
|
+
"iteration.completed": completionAttempted,
|
|
102088
|
+
"iteration.message_count": currentMessages.length
|
|
102089
|
+
});
|
|
101753
102090
|
if (currentMessages.length > MAX_HISTORY_MESSAGES) {
|
|
101754
102091
|
const messagesBefore = currentMessages.length;
|
|
101755
102092
|
const systemMsg = currentMessages[0];
|
|
@@ -101866,7 +102203,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
101866
102203
|
}
|
|
101867
102204
|
const mermaidValidation = await validateAndFixMermaidResponse(finalResult, {
|
|
101868
102205
|
debug: this.debug,
|
|
101869
|
-
path: this.allowedFolders[0],
|
|
102206
|
+
path: this.workspaceRoot || this.allowedFolders[0],
|
|
101870
102207
|
provider: this.clientApiProvider,
|
|
101871
102208
|
model: this.model,
|
|
101872
102209
|
tracer: this.tracer
|
|
@@ -101939,7 +102276,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
101939
102276
|
}
|
|
101940
102277
|
const { JsonFixingAgent: JsonFixingAgent2 } = await Promise.resolve().then(() => (init_schemaUtils(), schemaUtils_exports));
|
|
101941
102278
|
const jsonFixer = new JsonFixingAgent2({
|
|
101942
|
-
path: this.allowedFolders[0],
|
|
102279
|
+
path: this.workspaceRoot || this.allowedFolders[0],
|
|
101943
102280
|
provider: this.clientApiProvider,
|
|
101944
102281
|
model: this.model,
|
|
101945
102282
|
debug: this.debug,
|
|
@@ -102008,7 +102345,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
102008
102345
|
}
|
|
102009
102346
|
const mermaidValidation = await validateAndFixMermaidResponse(finalResult, {
|
|
102010
102347
|
debug: this.debug,
|
|
102011
|
-
path: this.allowedFolders[0],
|
|
102348
|
+
path: this.workspaceRoot || this.allowedFolders[0],
|
|
102012
102349
|
provider: this.clientApiProvider,
|
|
102013
102350
|
model: this.model,
|
|
102014
102351
|
tracer: this.tracer
|
|
@@ -102140,7 +102477,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
102140
102477
|
}
|
|
102141
102478
|
const finalMermaidValidation = await validateAndFixMermaidResponse(finalResult, {
|
|
102142
102479
|
debug: this.debug,
|
|
102143
|
-
path: this.allowedFolders[0],
|
|
102480
|
+
path: this.workspaceRoot || this.allowedFolders[0],
|
|
102144
102481
|
provider: this.clientApiProvider,
|
|
102145
102482
|
model: this.model,
|
|
102146
102483
|
tracer: this.tracer
|
|
@@ -102290,8 +102627,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
102290
102627
|
allowEdit: this.allowEdit,
|
|
102291
102628
|
enableDelegate: this.enableDelegate,
|
|
102292
102629
|
architectureFileName: this.architectureFileName,
|
|
102293
|
-
|
|
102294
|
-
// Use first allowed folder as primary path
|
|
102630
|
+
// Pass allowedFolders which will recompute workspaceRoot correctly
|
|
102295
102631
|
allowedFolders: [...this.allowedFolders],
|
|
102296
102632
|
cwd: this.cwd,
|
|
102297
102633
|
// Preserve explicit working directory
|