@probelabs/probe 0.6.0-rc258 → 0.6.0-rc259
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-rc258-aarch64-apple-darwin.tar.gz → probe-v0.6.0-rc259-aarch64-apple-darwin.tar.gz} +0 -0
- package/bin/binaries/probe-v0.6.0-rc259-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/{probe-v0.6.0-rc258-x86_64-apple-darwin.tar.gz → probe-v0.6.0-rc259-x86_64-apple-darwin.tar.gz} +0 -0
- package/bin/binaries/probe-v0.6.0-rc259-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc259-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +13 -0
- package/build/agent/index.js +177 -19
- package/build/agent/probeTool.js +9 -0
- package/build/agent/tools.js +8 -0
- package/build/index.js +7 -2
- package/build/tools/common.js +56 -23
- package/build/tools/edit.js +139 -6
- package/build/tools/index.js +5 -2
- package/cjs/agent/ProbeAgent.cjs +177 -19
- package/cjs/index.cjs +187 -19
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +13 -0
- package/src/agent/probeTool.js +9 -0
- package/src/agent/tools.js +8 -0
- package/src/index.js +7 -2
- package/src/tools/common.js +56 -23
- package/src/tools/edit.js +139 -6
- package/src/tools/index.js +5 -2
- package/bin/binaries/probe-v0.6.0-rc258-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc258-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc258-x86_64-unknown-linux-musl.tar.gz +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
attemptCompletionToolDefinition,
|
|
60
60
|
editToolDefinition,
|
|
61
61
|
createToolDefinition,
|
|
62
|
+
multiEditToolDefinition,
|
|
62
63
|
googleSearchToolDefinition,
|
|
63
64
|
urlContextToolDefinition,
|
|
64
65
|
attemptCompletionSchema,
|
|
@@ -964,6 +965,9 @@ export class ProbeAgent {
|
|
|
964
965
|
if (wrappedTools.createToolInstance && isToolAllowed('create')) {
|
|
965
966
|
this.toolImplementations.create = wrappedTools.createToolInstance;
|
|
966
967
|
}
|
|
968
|
+
if (wrappedTools.multiEditToolInstance && isToolAllowed('multi_edit')) {
|
|
969
|
+
this.toolImplementations.multi_edit = wrappedTools.multiEditToolInstance;
|
|
970
|
+
}
|
|
967
971
|
}
|
|
968
972
|
|
|
969
973
|
// Store wrapped tools for ACP system
|
|
@@ -2565,6 +2569,9 @@ ${extractGuidance}
|
|
|
2565
2569
|
if (this.allowEdit && isToolAllowed('create')) {
|
|
2566
2570
|
toolDefinitions += `${createToolDefinition}\n`;
|
|
2567
2571
|
}
|
|
2572
|
+
if (this.allowEdit && isToolAllowed('multi_edit')) {
|
|
2573
|
+
toolDefinitions += `${multiEditToolDefinition}\n`;
|
|
2574
|
+
}
|
|
2568
2575
|
// Bash tool (require both enableBash flag AND allowedTools permission)
|
|
2569
2576
|
if (this.enableBash && isToolAllowed('bash')) {
|
|
2570
2577
|
toolDefinitions += `${bashToolDefinition}\n`;
|
|
@@ -2670,6 +2677,9 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
|
|
|
2670
2677
|
if (this.allowEdit && isToolAllowed('create')) {
|
|
2671
2678
|
availableToolsList += '- create: Create new files with specified content.\n';
|
|
2672
2679
|
}
|
|
2680
|
+
if (this.allowEdit && isToolAllowed('multi_edit')) {
|
|
2681
|
+
availableToolsList += '- multi_edit: Apply multiple file edits in one call using a JSON array of operations.\n';
|
|
2682
|
+
}
|
|
2673
2683
|
if (this.enableDelegate && isToolAllowed('delegate')) {
|
|
2674
2684
|
availableToolsList += '- delegate: Delegate big distinct tasks to specialized probe subagents.\n';
|
|
2675
2685
|
}
|
|
@@ -3430,6 +3440,9 @@ Follow these instructions carefully:
|
|
|
3430
3440
|
if (this.allowEdit && this.allowedTools.isEnabled('create')) {
|
|
3431
3441
|
validTools.push('create');
|
|
3432
3442
|
}
|
|
3443
|
+
if (this.allowEdit && this.allowedTools.isEnabled('multi_edit')) {
|
|
3444
|
+
validTools.push('multi_edit');
|
|
3445
|
+
}
|
|
3433
3446
|
// Bash tool (require both enableBash flag AND allowedTools permission)
|
|
3434
3447
|
if (this.enableBash && this.allowedTools.isEnabled('bash')) {
|
|
3435
3448
|
validTools.push('bash');
|
package/build/agent/index.js
CHANGED
|
@@ -9427,7 +9427,7 @@ async function handleLineEdit({ resolvedPath, file_path, start_line, end_line, n
|
|
|
9427
9427
|
return buildLineEditResponse(file_path, startLine, endLine, newLines.length, fileLines, startLine - 1, action, modifications);
|
|
9428
9428
|
}
|
|
9429
9429
|
}
|
|
9430
|
-
var editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
|
|
9430
|
+
var editTool, createTool, multiEditTool, editSchema, createSchema, multiEditSchema, editDescription, createDescription, multiEditDescription, editToolDefinition, createToolDefinition, multiEditToolDefinition;
|
|
9431
9431
|
var init_edit = __esm({
|
|
9432
9432
|
"src/tools/edit.js"() {
|
|
9433
9433
|
"use strict";
|
|
@@ -9497,7 +9497,7 @@ Parameters:
|
|
|
9497
9497
|
},
|
|
9498
9498
|
required: ["file_path", "new_string"]
|
|
9499
9499
|
},
|
|
9500
|
-
execute: async ({ file_path, old_string, new_string, replace_all = false, symbol, position, start_line, end_line }) => {
|
|
9500
|
+
execute: async ({ file_path, old_string, new_string, replace_all = false, symbol, position, start_line, end_line, workingDirectory }) => {
|
|
9501
9501
|
try {
|
|
9502
9502
|
if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
|
|
9503
9503
|
return `Error editing file: Invalid file_path - must be a non-empty string. Provide an absolute path or a path relative to the working directory (e.g. "src/main.js").`;
|
|
@@ -9505,7 +9505,8 @@ Parameters:
|
|
|
9505
9505
|
if (new_string === void 0 || new_string === null || typeof new_string !== "string") {
|
|
9506
9506
|
return `Error editing file: Invalid new_string - must be a string. Provide the replacement content as a string value (empty string "" is valid for deletions).`;
|
|
9507
9507
|
}
|
|
9508
|
-
const
|
|
9508
|
+
const effectiveCwd = workingDirectory || cwd || process.cwd();
|
|
9509
|
+
const resolvedPath = isAbsolute(file_path) ? file_path : resolve(effectiveCwd, file_path);
|
|
9509
9510
|
if (debug) {
|
|
9510
9511
|
console.error(`[Edit] Attempting to edit file: ${resolvedPath}`);
|
|
9511
9512
|
}
|
|
@@ -9612,7 +9613,7 @@ Important:
|
|
|
9612
9613
|
},
|
|
9613
9614
|
required: ["file_path", "content"]
|
|
9614
9615
|
},
|
|
9615
|
-
execute: async ({ file_path, content, overwrite = false }) => {
|
|
9616
|
+
execute: async ({ file_path, content, overwrite = false, workingDirectory }) => {
|
|
9616
9617
|
try {
|
|
9617
9618
|
if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
|
|
9618
9619
|
return `Error creating file: Invalid file_path - must be a non-empty string. Provide an absolute path or a path relative to the working directory (e.g. "src/newFile.js").`;
|
|
@@ -9620,7 +9621,8 @@ Important:
|
|
|
9620
9621
|
if (content === void 0 || content === null || typeof content !== "string") {
|
|
9621
9622
|
return `Error creating file: Invalid content - must be a string. Provide the file content as a string value (empty string "" is valid for an empty file).`;
|
|
9622
9623
|
}
|
|
9623
|
-
const
|
|
9624
|
+
const effectiveCwd = workingDirectory || cwd || process.cwd();
|
|
9625
|
+
const resolvedPath = isAbsolute(file_path) ? file_path : resolve(effectiveCwd, file_path);
|
|
9624
9626
|
if (debug) {
|
|
9625
9627
|
console.error(`[Create] Attempting to create file: ${resolvedPath}`);
|
|
9626
9628
|
}
|
|
@@ -9649,6 +9651,70 @@ Important:
|
|
|
9649
9651
|
}
|
|
9650
9652
|
});
|
|
9651
9653
|
};
|
|
9654
|
+
multiEditTool = (options = {}) => {
|
|
9655
|
+
const editInstance = editTool(options);
|
|
9656
|
+
return tool({
|
|
9657
|
+
name: "multi_edit",
|
|
9658
|
+
description: "Apply multiple file edits in a single tool call. Accepts a JSON array of edit operations.",
|
|
9659
|
+
inputSchema: {
|
|
9660
|
+
type: "object",
|
|
9661
|
+
properties: {
|
|
9662
|
+
edits: {
|
|
9663
|
+
type: "string",
|
|
9664
|
+
description: "JSON array of edit operations. Each object supports: file_path, old_string, new_string, replace_all, symbol, position, start_line, end_line."
|
|
9665
|
+
}
|
|
9666
|
+
},
|
|
9667
|
+
required: ["edits"]
|
|
9668
|
+
},
|
|
9669
|
+
execute: async ({ edits: rawEdits }) => {
|
|
9670
|
+
let edits;
|
|
9671
|
+
if (typeof rawEdits === "string") {
|
|
9672
|
+
try {
|
|
9673
|
+
edits = JSON.parse(rawEdits);
|
|
9674
|
+
} catch (e) {
|
|
9675
|
+
return `Error: Invalid JSON in edits parameter - ${e.message}. Provide a raw JSON array between <edits> tags.`;
|
|
9676
|
+
}
|
|
9677
|
+
} else if (Array.isArray(rawEdits)) {
|
|
9678
|
+
edits = rawEdits;
|
|
9679
|
+
} else {
|
|
9680
|
+
return "Error: edits must be a JSON array of edit operations.";
|
|
9681
|
+
}
|
|
9682
|
+
if (!Array.isArray(edits) || edits.length === 0) {
|
|
9683
|
+
return "Error: edits must be a non-empty JSON array.";
|
|
9684
|
+
}
|
|
9685
|
+
if (edits.length > 50) {
|
|
9686
|
+
return `Error: Too many edits (${edits.length}). Maximum 50 per batch.`;
|
|
9687
|
+
}
|
|
9688
|
+
const results = [];
|
|
9689
|
+
let successCount = 0;
|
|
9690
|
+
let failCount = 0;
|
|
9691
|
+
for (let i = 0; i < edits.length; i++) {
|
|
9692
|
+
const editOp = edits[i];
|
|
9693
|
+
if (!editOp || typeof editOp !== "object" || Array.isArray(editOp)) {
|
|
9694
|
+
results.push(`[${i + 1}] FAIL: Invalid edit operation - must be an object`);
|
|
9695
|
+
failCount++;
|
|
9696
|
+
continue;
|
|
9697
|
+
}
|
|
9698
|
+
try {
|
|
9699
|
+
const result = await editInstance.execute(editOp);
|
|
9700
|
+
const isError = typeof result === "string" && result.startsWith("Error");
|
|
9701
|
+
if (isError) {
|
|
9702
|
+
results.push(`[${i + 1}] FAIL: ${result}`);
|
|
9703
|
+
failCount++;
|
|
9704
|
+
} else {
|
|
9705
|
+
results.push(`[${i + 1}] OK: ${result}`);
|
|
9706
|
+
successCount++;
|
|
9707
|
+
}
|
|
9708
|
+
} catch (error) {
|
|
9709
|
+
results.push(`[${i + 1}] FAIL: ${error.message}`);
|
|
9710
|
+
failCount++;
|
|
9711
|
+
}
|
|
9712
|
+
}
|
|
9713
|
+
const summary = `Multi-edit: ${successCount}/${edits.length} succeeded` + (failCount > 0 ? `, ${failCount} failed` : "");
|
|
9714
|
+
return summary + "\n\n" + results.join("\n");
|
|
9715
|
+
}
|
|
9716
|
+
});
|
|
9717
|
+
};
|
|
9652
9718
|
editSchema = {
|
|
9653
9719
|
type: "object",
|
|
9654
9720
|
properties: {
|
|
@@ -9706,8 +9772,19 @@ Important:
|
|
|
9706
9772
|
},
|
|
9707
9773
|
required: ["file_path", "content"]
|
|
9708
9774
|
};
|
|
9775
|
+
multiEditSchema = {
|
|
9776
|
+
type: "object",
|
|
9777
|
+
properties: {
|
|
9778
|
+
edits: {
|
|
9779
|
+
type: "string",
|
|
9780
|
+
description: "JSON array of edit operations"
|
|
9781
|
+
}
|
|
9782
|
+
},
|
|
9783
|
+
required: ["edits"]
|
|
9784
|
+
};
|
|
9709
9785
|
editDescription = "Edit files using text replacement, AST-aware symbol operations, or line-targeted editing. Supports fuzzy matching for text edits and optional hash-based integrity verification for line edits.";
|
|
9710
9786
|
createDescription = "Create new files with specified content. Will create parent directories if needed.";
|
|
9787
|
+
multiEditDescription = "Apply multiple file edits in a single tool call. Accepts a JSON array of edit operations, each supporting the same modes as the edit tool.";
|
|
9711
9788
|
editToolDefinition = `
|
|
9712
9789
|
## edit
|
|
9713
9790
|
Description: ${editDescription}
|
|
@@ -9863,6 +9940,44 @@ Examples:
|
|
|
9863
9940
|
This is a new project.</content>
|
|
9864
9941
|
<overwrite>true</overwrite>
|
|
9865
9942
|
</create>`;
|
|
9943
|
+
multiEditToolDefinition = `
|
|
9944
|
+
## multi_edit
|
|
9945
|
+
Description: ${multiEditDescription}
|
|
9946
|
+
|
|
9947
|
+
Apply multiple edits in one call. Each operation in the array uses the same parameters as the edit tool:
|
|
9948
|
+
- file_path, old_string, new_string (text mode)
|
|
9949
|
+
- file_path, symbol, new_string (symbol replace)
|
|
9950
|
+
- file_path, symbol, new_string, position (symbol insert)
|
|
9951
|
+
- file_path, start_line, new_string (line-targeted)
|
|
9952
|
+
|
|
9953
|
+
Edits are applied sequentially. Failures do not stop remaining edits. Maximum 50 edits per call.
|
|
9954
|
+
|
|
9955
|
+
Parameters:
|
|
9956
|
+
- edits: (required) JSON array of edit objects. Place raw JSON between tags.
|
|
9957
|
+
|
|
9958
|
+
When to use multi_edit vs edit:
|
|
9959
|
+
- Use edit for a single change to one file
|
|
9960
|
+
- Use multi_edit when making 2+ related changes across files (e.g., rename a function and update all call sites)
|
|
9961
|
+
- Use multi_edit for coordinated multi-file refactoring where order matters
|
|
9962
|
+
|
|
9963
|
+
Examples:
|
|
9964
|
+
|
|
9965
|
+
Multiple text replacements across files:
|
|
9966
|
+
<multi_edit>
|
|
9967
|
+
<edits>[
|
|
9968
|
+
{"file_path": "src/main.js", "old_string": "return false;", "new_string": "return true;"},
|
|
9969
|
+
{"file_path": "src/config.js", "old_string": "debug: false", "new_string": "debug: true"}
|
|
9970
|
+
]</edits>
|
|
9971
|
+
</multi_edit>
|
|
9972
|
+
|
|
9973
|
+
Mixed edit modes in one batch:
|
|
9974
|
+
<multi_edit>
|
|
9975
|
+
<edits>[
|
|
9976
|
+
{"file_path": "src/utils.js", "symbol": "oldHelper", "new_string": "function newHelper() { return 42; }"},
|
|
9977
|
+
{"file_path": "src/main.js", "old_string": "oldHelper()", "new_string": "newHelper()", "replace_all": true},
|
|
9978
|
+
{"file_path": "src/index.js", "start_line": "10", "end_line": "12", "new_string": "export { newHelper };"}
|
|
9979
|
+
]</edits>
|
|
9980
|
+
</multi_edit>`;
|
|
9866
9981
|
}
|
|
9867
9982
|
});
|
|
9868
9983
|
|
|
@@ -10356,7 +10471,8 @@ function getValidParamsForTool(toolName) {
|
|
|
10356
10471
|
task: taskSchema,
|
|
10357
10472
|
attempt_completion: attemptCompletionSchema,
|
|
10358
10473
|
edit: editSchema,
|
|
10359
|
-
create: createSchema
|
|
10474
|
+
create: createSchema,
|
|
10475
|
+
multi_edit: multiEditSchema
|
|
10360
10476
|
};
|
|
10361
10477
|
const schema = schemaMap[toolName];
|
|
10362
10478
|
if (!schema) {
|
|
@@ -10396,7 +10512,7 @@ function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
|
10396
10512
|
const closeTag = `</${toolName}>`;
|
|
10397
10513
|
const openIndex = earliestOpenIndex;
|
|
10398
10514
|
let closeIndex;
|
|
10399
|
-
if (toolName
|
|
10515
|
+
if (LAST_INDEX_TOOLS.has(toolName)) {
|
|
10400
10516
|
closeIndex = xmlString.lastIndexOf(closeTag);
|
|
10401
10517
|
if (closeIndex !== -1 && closeIndex <= openIndex + openTag.length) {
|
|
10402
10518
|
closeIndex = -1;
|
|
@@ -10421,7 +10537,15 @@ function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
|
10421
10537
|
if (paramOpenIndex === -1) {
|
|
10422
10538
|
continue;
|
|
10423
10539
|
}
|
|
10424
|
-
let paramCloseIndex
|
|
10540
|
+
let paramCloseIndex;
|
|
10541
|
+
if (RAW_CONTENT_PARAMS.has(paramName)) {
|
|
10542
|
+
paramCloseIndex = innerContent.lastIndexOf(paramCloseTag);
|
|
10543
|
+
if (paramCloseIndex !== -1 && paramCloseIndex <= paramOpenIndex + paramOpenTag.length) {
|
|
10544
|
+
paramCloseIndex = -1;
|
|
10545
|
+
}
|
|
10546
|
+
} else {
|
|
10547
|
+
paramCloseIndex = innerContent.indexOf(paramCloseTag, paramOpenIndex + paramOpenTag.length);
|
|
10548
|
+
}
|
|
10425
10549
|
if (paramCloseIndex === -1) {
|
|
10426
10550
|
let nextTagIndex = innerContent.length;
|
|
10427
10551
|
for (const nextParam of validParams) {
|
|
@@ -10433,18 +10557,26 @@ function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
|
10433
10557
|
}
|
|
10434
10558
|
paramCloseIndex = nextTagIndex;
|
|
10435
10559
|
}
|
|
10436
|
-
|
|
10560
|
+
const rawValue = innerContent.substring(
|
|
10437
10561
|
paramOpenIndex + paramOpenTag.length,
|
|
10438
10562
|
paramCloseIndex
|
|
10439
|
-
)
|
|
10440
|
-
|
|
10441
|
-
|
|
10442
|
-
|
|
10443
|
-
|
|
10444
|
-
|
|
10445
|
-
|
|
10446
|
-
|
|
10447
|
-
|
|
10563
|
+
);
|
|
10564
|
+
let paramValue;
|
|
10565
|
+
if (RAW_CONTENT_PARAMS.has(paramName)) {
|
|
10566
|
+
paramValue = unescapeXmlEntities(rawValue.replace(/^\n/, "").replace(/\n$/, ""));
|
|
10567
|
+
} else {
|
|
10568
|
+
paramValue = unescapeXmlEntities(rawValue.trim());
|
|
10569
|
+
}
|
|
10570
|
+
if (!RAW_CONTENT_PARAMS.has(paramName)) {
|
|
10571
|
+
if (paramValue.toLowerCase() === "true") {
|
|
10572
|
+
paramValue = true;
|
|
10573
|
+
} else if (paramValue.toLowerCase() === "false") {
|
|
10574
|
+
paramValue = false;
|
|
10575
|
+
} else if (!isNaN(paramValue) && paramValue.trim() !== "") {
|
|
10576
|
+
const num = Number(paramValue);
|
|
10577
|
+
if (Number.isFinite(num)) {
|
|
10578
|
+
paramValue = num;
|
|
10579
|
+
}
|
|
10448
10580
|
}
|
|
10449
10581
|
}
|
|
10450
10582
|
params[paramName] = paramValue;
|
|
@@ -10487,6 +10619,7 @@ function detectUnrecognizedToolCall(xmlString, validTools) {
|
|
|
10487
10619
|
"readImage",
|
|
10488
10620
|
"edit",
|
|
10489
10621
|
"create",
|
|
10622
|
+
"multi_edit",
|
|
10490
10623
|
"delegate",
|
|
10491
10624
|
"bash",
|
|
10492
10625
|
"task",
|
|
@@ -10616,7 +10749,7 @@ function resolveTargetPath(target, cwd) {
|
|
|
10616
10749
|
}
|
|
10617
10750
|
return filePart + suffix;
|
|
10618
10751
|
}
|
|
10619
|
-
var searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, analyzeAllToolDefinition, bashToolDefinition, googleSearchToolDefinition, urlContextToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription, DEFAULT_VALID_TOOLS;
|
|
10752
|
+
var searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, analyzeAllToolDefinition, bashToolDefinition, googleSearchToolDefinition, urlContextToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription, DEFAULT_VALID_TOOLS, RAW_CONTENT_PARAMS, LAST_INDEX_TOOLS;
|
|
10620
10753
|
var init_common = __esm({
|
|
10621
10754
|
"src/tools/common.js"() {
|
|
10622
10755
|
"use strict";
|
|
@@ -11034,6 +11167,8 @@ Capabilities:
|
|
|
11034
11167
|
"task",
|
|
11035
11168
|
"attempt_completion"
|
|
11036
11169
|
];
|
|
11170
|
+
RAW_CONTENT_PARAMS = /* @__PURE__ */ new Set(["content", "new_string", "old_string"]);
|
|
11171
|
+
LAST_INDEX_TOOLS = /* @__PURE__ */ new Set(["attempt_completion", "create", "edit"]);
|
|
11037
11172
|
}
|
|
11038
11173
|
});
|
|
11039
11174
|
|
|
@@ -32036,6 +32171,13 @@ function createWrappedTools(baseTools) {
|
|
|
32036
32171
|
baseTools.createTool.execute
|
|
32037
32172
|
);
|
|
32038
32173
|
}
|
|
32174
|
+
if (baseTools.multiEditTool) {
|
|
32175
|
+
wrappedTools.multiEditToolInstance = wrapToolWithEmitter(
|
|
32176
|
+
baseTools.multiEditTool,
|
|
32177
|
+
"multi_edit",
|
|
32178
|
+
baseTools.multiEditTool.execute
|
|
32179
|
+
);
|
|
32180
|
+
}
|
|
32039
32181
|
return wrappedTools;
|
|
32040
32182
|
}
|
|
32041
32183
|
var toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
|
|
@@ -32954,6 +33096,9 @@ function createTools(configOptions) {
|
|
|
32954
33096
|
if (configOptions.allowEdit && isToolAllowed("create")) {
|
|
32955
33097
|
tools2.createTool = createTool(configOptions);
|
|
32956
33098
|
}
|
|
33099
|
+
if (configOptions.allowEdit && isToolAllowed("multi_edit")) {
|
|
33100
|
+
tools2.multiEditTool = multiEditTool(configOptions);
|
|
33101
|
+
}
|
|
32957
33102
|
return tools2;
|
|
32958
33103
|
}
|
|
32959
33104
|
function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
@@ -83452,6 +83597,9 @@ var init_ProbeAgent = __esm({
|
|
|
83452
83597
|
if (wrappedTools.createToolInstance && isToolAllowed("create")) {
|
|
83453
83598
|
this.toolImplementations.create = wrappedTools.createToolInstance;
|
|
83454
83599
|
}
|
|
83600
|
+
if (wrappedTools.multiEditToolInstance && isToolAllowed("multi_edit")) {
|
|
83601
|
+
this.toolImplementations.multi_edit = wrappedTools.multiEditToolInstance;
|
|
83602
|
+
}
|
|
83455
83603
|
}
|
|
83456
83604
|
this.wrappedTools = wrappedTools;
|
|
83457
83605
|
if (this.debug) {
|
|
@@ -84741,6 +84889,10 @@ Workspace: ${this.allowedFolders.join(", ")}`;
|
|
|
84741
84889
|
}
|
|
84742
84890
|
if (this.allowEdit && isToolAllowed("create")) {
|
|
84743
84891
|
toolDefinitions += `${createToolDefinition}
|
|
84892
|
+
`;
|
|
84893
|
+
}
|
|
84894
|
+
if (this.allowEdit && isToolAllowed("multi_edit")) {
|
|
84895
|
+
toolDefinitions += `${multiEditToolDefinition}
|
|
84744
84896
|
`;
|
|
84745
84897
|
}
|
|
84746
84898
|
if (this.enableBash && isToolAllowed("bash")) {
|
|
@@ -84837,6 +84989,9 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
|
|
|
84837
84989
|
if (this.allowEdit && isToolAllowed("create")) {
|
|
84838
84990
|
availableToolsList += "- create: Create new files with specified content.\n";
|
|
84839
84991
|
}
|
|
84992
|
+
if (this.allowEdit && isToolAllowed("multi_edit")) {
|
|
84993
|
+
availableToolsList += "- multi_edit: Apply multiple file edits in one call using a JSON array of operations.\n";
|
|
84994
|
+
}
|
|
84840
84995
|
if (this.enableDelegate && isToolAllowed("delegate")) {
|
|
84841
84996
|
availableToolsList += "- delegate: Delegate big distinct tasks to specialized probe subagents.\n";
|
|
84842
84997
|
}
|
|
@@ -85431,6 +85586,9 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
85431
85586
|
if (this.allowEdit && this.allowedTools.isEnabled("create")) {
|
|
85432
85587
|
validTools.push("create");
|
|
85433
85588
|
}
|
|
85589
|
+
if (this.allowEdit && this.allowedTools.isEnabled("multi_edit")) {
|
|
85590
|
+
validTools.push("multi_edit");
|
|
85591
|
+
}
|
|
85434
85592
|
if (this.enableBash && this.allowedTools.isEnabled("bash")) {
|
|
85435
85593
|
validTools.push("bash");
|
|
85436
85594
|
}
|
package/build/agent/probeTool.js
CHANGED
|
@@ -256,6 +256,15 @@ export function createWrappedTools(baseTools) {
|
|
|
256
256
|
);
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
+
// Wrap multi_edit tool
|
|
260
|
+
if (baseTools.multiEditTool) {
|
|
261
|
+
wrappedTools.multiEditToolInstance = wrapToolWithEmitter(
|
|
262
|
+
baseTools.multiEditTool,
|
|
263
|
+
'multi_edit',
|
|
264
|
+
baseTools.multiEditTool.execute
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
259
268
|
return wrappedTools;
|
|
260
269
|
}
|
|
261
270
|
|
package/build/agent/tools.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
bashTool,
|
|
11
11
|
editTool,
|
|
12
12
|
createTool,
|
|
13
|
+
multiEditTool,
|
|
13
14
|
DEFAULT_SYSTEM_MESSAGE,
|
|
14
15
|
attemptCompletionSchema,
|
|
15
16
|
attemptCompletionToolDefinition,
|
|
@@ -23,6 +24,7 @@ import {
|
|
|
23
24
|
bashSchema,
|
|
24
25
|
editSchema,
|
|
25
26
|
createSchema,
|
|
27
|
+
multiEditSchema,
|
|
26
28
|
searchToolDefinition,
|
|
27
29
|
queryToolDefinition,
|
|
28
30
|
extractToolDefinition,
|
|
@@ -33,6 +35,7 @@ import {
|
|
|
33
35
|
bashToolDefinition,
|
|
34
36
|
editToolDefinition,
|
|
35
37
|
createToolDefinition,
|
|
38
|
+
multiEditToolDefinition,
|
|
36
39
|
googleSearchToolDefinition,
|
|
37
40
|
urlContextToolDefinition,
|
|
38
41
|
parseXmlToolCall
|
|
@@ -87,6 +90,9 @@ export function createTools(configOptions) {
|
|
|
87
90
|
if (configOptions.allowEdit && isToolAllowed('create')) {
|
|
88
91
|
tools.createTool = createTool(configOptions);
|
|
89
92
|
}
|
|
93
|
+
if (configOptions.allowEdit && isToolAllowed('multi_edit')) {
|
|
94
|
+
tools.multiEditTool = multiEditTool(configOptions);
|
|
95
|
+
}
|
|
90
96
|
return tools;
|
|
91
97
|
}
|
|
92
98
|
|
|
@@ -114,6 +120,7 @@ export {
|
|
|
114
120
|
bashSchema,
|
|
115
121
|
editSchema,
|
|
116
122
|
createSchema,
|
|
123
|
+
multiEditSchema,
|
|
117
124
|
attemptCompletionSchema,
|
|
118
125
|
searchToolDefinition,
|
|
119
126
|
queryToolDefinition,
|
|
@@ -125,6 +132,7 @@ export {
|
|
|
125
132
|
bashToolDefinition,
|
|
126
133
|
editToolDefinition,
|
|
127
134
|
createToolDefinition,
|
|
135
|
+
multiEditToolDefinition,
|
|
128
136
|
attemptCompletionToolDefinition,
|
|
129
137
|
googleSearchToolDefinition,
|
|
130
138
|
urlContextToolDefinition,
|
package/build/index.js
CHANGED
|
@@ -44,13 +44,15 @@ import {
|
|
|
44
44
|
import {
|
|
45
45
|
editSchema,
|
|
46
46
|
createSchema,
|
|
47
|
+
multiEditSchema,
|
|
47
48
|
editToolDefinition,
|
|
48
|
-
createToolDefinition
|
|
49
|
+
createToolDefinition,
|
|
50
|
+
multiEditToolDefinition
|
|
49
51
|
} from './tools/edit.js';
|
|
50
52
|
import { searchTool, queryTool, extractTool, delegateTool, analyzeAllTool } from './tools/vercel.js';
|
|
51
53
|
import { createExecutePlanTool, getExecutePlanToolDefinition, createCleanupExecutePlanTool, getCleanupExecutePlanToolDefinition } from './tools/executePlan.js';
|
|
52
54
|
import { bashTool } from './tools/bash.js';
|
|
53
|
-
import { editTool, createTool } from './tools/edit.js';
|
|
55
|
+
import { editTool, createTool, multiEditTool } from './tools/edit.js';
|
|
54
56
|
import { FileTracker } from './tools/fileTracker.js';
|
|
55
57
|
import { ProbeAgent } from './agent/ProbeAgent.js';
|
|
56
58
|
import { SimpleTelemetry, SimpleAppTracer, initializeSimpleTelemetryFromOptions } from './agent/simpleTelemetry.js';
|
|
@@ -99,6 +101,7 @@ export {
|
|
|
99
101
|
bashTool,
|
|
100
102
|
editTool,
|
|
101
103
|
createTool,
|
|
104
|
+
multiEditTool,
|
|
102
105
|
FileTracker,
|
|
103
106
|
// Export tool instances
|
|
104
107
|
listFilesToolInstance,
|
|
@@ -115,6 +118,7 @@ export {
|
|
|
115
118
|
bashSchema,
|
|
116
119
|
editSchema,
|
|
117
120
|
createSchema,
|
|
121
|
+
multiEditSchema,
|
|
118
122
|
// Export tool definitions
|
|
119
123
|
searchToolDefinition,
|
|
120
124
|
queryToolDefinition,
|
|
@@ -127,6 +131,7 @@ export {
|
|
|
127
131
|
bashToolDefinition,
|
|
128
132
|
editToolDefinition,
|
|
129
133
|
createToolDefinition,
|
|
134
|
+
multiEditToolDefinition,
|
|
130
135
|
googleSearchToolDefinition,
|
|
131
136
|
urlContextToolDefinition,
|
|
132
137
|
// Export parser function
|
package/build/tools/common.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import { resolve, isAbsolute } from 'path';
|
|
8
|
-
import { editSchema, createSchema } from './edit.js';
|
|
8
|
+
import { editSchema, createSchema, multiEditSchema } from './edit.js';
|
|
9
9
|
import { taskSchema } from '../agent/tasks/taskTool.js';
|
|
10
10
|
|
|
11
11
|
// Common schemas for tool parameters (used for internal execution after XML parsing)
|
|
@@ -492,7 +492,8 @@ function getValidParamsForTool(toolName) {
|
|
|
492
492
|
task: taskSchema,
|
|
493
493
|
attempt_completion: attemptCompletionSchema,
|
|
494
494
|
edit: editSchema,
|
|
495
|
-
create: createSchema
|
|
495
|
+
create: createSchema,
|
|
496
|
+
multi_edit: multiEditSchema
|
|
496
497
|
};
|
|
497
498
|
|
|
498
499
|
const schema = schemaMap[toolName];
|
|
@@ -538,6 +539,15 @@ export function unescapeXmlEntities(str) {
|
|
|
538
539
|
.replace(/&/g, '&');
|
|
539
540
|
}
|
|
540
541
|
|
|
542
|
+
// Parameters that contain arbitrary code/file content — use lastIndexOf for closing tag
|
|
543
|
+
// to handle cases where the content itself contains the closing tag string.
|
|
544
|
+
const RAW_CONTENT_PARAMS = new Set(['content', 'new_string', 'old_string']);
|
|
545
|
+
|
|
546
|
+
// Tools whose content can include their own closing tag string (e.g., file content
|
|
547
|
+
// containing </create> or </edit>). Use lastIndexOf for outer tag boundary, same
|
|
548
|
+
// strategy already used for attempt_completion.
|
|
549
|
+
const LAST_INDEX_TOOLS = new Set(['attempt_completion', 'create', 'edit']);
|
|
550
|
+
|
|
541
551
|
// Simple XML parser helper - safer string-based approach
|
|
542
552
|
export function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
543
553
|
// Find the tool that appears EARLIEST in the string
|
|
@@ -564,13 +574,13 @@ export function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
|
564
574
|
const closeTag = `</${toolName}>`;
|
|
565
575
|
const openIndex = earliestOpenIndex;
|
|
566
576
|
|
|
567
|
-
// For
|
|
568
|
-
//
|
|
569
|
-
//
|
|
577
|
+
// For tools that contain arbitrary content (file content, code), use lastIndexOf
|
|
578
|
+
// to find the LAST occurrence of the closing tag. This prevents issues where the
|
|
579
|
+
// content itself contains the closing tag string (e.g., file content with </create>).
|
|
580
|
+
// For other tools, use indexOf from the opening tag position.
|
|
570
581
|
let closeIndex;
|
|
571
|
-
if (toolName
|
|
582
|
+
if (LAST_INDEX_TOOLS.has(toolName)) {
|
|
572
583
|
// Find the last occurrence of the closing tag in the entire string
|
|
573
|
-
// This assumes attempt_completion doesn't have nested tags of the same name
|
|
574
584
|
closeIndex = xmlString.lastIndexOf(closeTag);
|
|
575
585
|
// Make sure the closing tag is after the opening tag
|
|
576
586
|
if (closeIndex !== -1 && closeIndex <= openIndex + openTag.length) {
|
|
@@ -610,7 +620,19 @@ export function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
|
610
620
|
continue; // Parameter not found
|
|
611
621
|
}
|
|
612
622
|
|
|
613
|
-
|
|
623
|
+
// For raw content params (file content, code), use lastIndexOf to find the
|
|
624
|
+
// LAST closing tag — the content itself may contain the closing tag string.
|
|
625
|
+
// For other params (file_path, overwrite, etc.), use indexOf (first match).
|
|
626
|
+
let paramCloseIndex;
|
|
627
|
+
if (RAW_CONTENT_PARAMS.has(paramName)) {
|
|
628
|
+
paramCloseIndex = innerContent.lastIndexOf(paramCloseTag);
|
|
629
|
+
// Ensure it's after the opening tag
|
|
630
|
+
if (paramCloseIndex !== -1 && paramCloseIndex <= paramOpenIndex + paramOpenTag.length) {
|
|
631
|
+
paramCloseIndex = -1;
|
|
632
|
+
}
|
|
633
|
+
} else {
|
|
634
|
+
paramCloseIndex = innerContent.indexOf(paramCloseTag, paramOpenIndex + paramOpenTag.length);
|
|
635
|
+
}
|
|
614
636
|
|
|
615
637
|
// Handle unclosed parameter tags - use content until next tag or end of content
|
|
616
638
|
if (paramCloseIndex === -1) {
|
|
@@ -626,23 +648,34 @@ export function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
|
626
648
|
paramCloseIndex = nextTagIndex;
|
|
627
649
|
}
|
|
628
650
|
|
|
629
|
-
|
|
651
|
+
const rawValue = innerContent.substring(
|
|
630
652
|
paramOpenIndex + paramOpenTag.length,
|
|
631
653
|
paramCloseIndex
|
|
632
|
-
)
|
|
633
|
-
|
|
634
|
-
//
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
paramValue =
|
|
639
|
-
} else
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
654
|
+
);
|
|
655
|
+
|
|
656
|
+
// For raw content params, preserve whitespace (only strip XML formatting newlines).
|
|
657
|
+
// For other params, trim all whitespace.
|
|
658
|
+
let paramValue;
|
|
659
|
+
if (RAW_CONTENT_PARAMS.has(paramName)) {
|
|
660
|
+
paramValue = unescapeXmlEntities(rawValue.replace(/^\n/, '').replace(/\n$/, ''));
|
|
661
|
+
} else {
|
|
662
|
+
paramValue = unescapeXmlEntities(rawValue.trim());
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// Type coercion for non-content params only (content/new_string/old_string must stay strings)
|
|
666
|
+
if (!RAW_CONTENT_PARAMS.has(paramName)) {
|
|
667
|
+
if (paramValue.toLowerCase() === 'true') {
|
|
668
|
+
paramValue = true;
|
|
669
|
+
} else if (paramValue.toLowerCase() === 'false') {
|
|
670
|
+
paramValue = false;
|
|
671
|
+
} else if (!isNaN(paramValue) && paramValue.trim() !== '') {
|
|
672
|
+
// Check if it's potentially a number (handle integers and floats)
|
|
673
|
+
const num = Number(paramValue);
|
|
674
|
+
if (Number.isFinite(num)) { // Use Number.isFinite to avoid Infinity/NaN
|
|
675
|
+
paramValue = num;
|
|
676
|
+
}
|
|
677
|
+
// Keep as string if not a valid finite number
|
|
644
678
|
}
|
|
645
|
-
// Keep as string if not a valid finite number
|
|
646
679
|
}
|
|
647
680
|
|
|
648
681
|
params[paramName] = paramValue;
|
|
@@ -707,7 +740,7 @@ export function detectUnrecognizedToolCall(xmlString, validTools) {
|
|
|
707
740
|
const knownToolNames = [
|
|
708
741
|
'search', 'query', 'extract', 'listFiles', 'searchFiles',
|
|
709
742
|
'listSkills', 'useSkill', 'readImage', 'edit',
|
|
710
|
-
'create', 'delegate', 'bash', 'task', 'attempt_completion',
|
|
743
|
+
'create', 'multi_edit', 'delegate', 'bash', 'task', 'attempt_completion',
|
|
711
744
|
'attempt_complete', 'read_file', 'write_file', 'run_command',
|
|
712
745
|
'grep', 'find', 'cat', 'list_directory'
|
|
713
746
|
];
|