@probelabs/probe 0.6.0-rc159 → 0.6.0-rc161
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/README.md +80 -1
- package/build/agent/FallbackManager.d.ts +176 -0
- package/build/agent/FallbackManager.js +545 -0
- package/build/agent/ProbeAgent.d.ts +7 -1
- package/build/agent/ProbeAgent.js +199 -7
- package/build/agent/RetryManager.d.ts +157 -0
- package/build/agent/RetryManager.js +334 -0
- package/build/agent/acp/tools.js +6 -2
- package/build/agent/index.js +1379 -168
- package/build/agent/probeTool.js +20 -2
- package/build/agent/tools.js +16 -0
- package/build/index.js +13 -0
- package/build/tools/common.js +5 -3
- package/build/tools/edit.js +409 -0
- package/build/tools/index.js +11 -0
- package/cjs/agent/ProbeAgent.cjs +1822 -497
- package/cjs/index.cjs +1784 -454
- package/package.json +2 -2
- package/src/agent/FallbackManager.d.ts +176 -0
- package/src/agent/FallbackManager.js +545 -0
- package/src/agent/ProbeAgent.d.ts +7 -1
- package/src/agent/ProbeAgent.js +199 -7
- package/src/agent/RetryManager.d.ts +157 -0
- package/src/agent/RetryManager.js +334 -0
- package/src/agent/acp/tools.js +6 -2
- package/src/agent/probeTool.js +20 -2
- package/src/agent/tools.js +16 -0
- package/src/index.js +13 -0
- package/src/tools/common.js +5 -3
- package/src/tools/edit.js +409 -0
- package/src/tools/index.js +11 -0
- package/bin/binaries/probe-v0.6.0-rc159-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc159-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc159-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc159-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc159-x86_64-unknown-linux-musl.tar.gz +0 -0
package/build/agent/index.js
CHANGED
|
@@ -2007,7 +2007,7 @@ async function waitForFileLock(lockPath, binaryPath) {
|
|
|
2007
2007
|
}
|
|
2008
2008
|
} catch {
|
|
2009
2009
|
}
|
|
2010
|
-
await new Promise((
|
|
2010
|
+
await new Promise((resolve6) => setTimeout(resolve6, LOCK_POLL_INTERVAL_MS));
|
|
2011
2011
|
}
|
|
2012
2012
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
2013
2013
|
console.log(`Timeout waiting for file lock`);
|
|
@@ -2978,7 +2978,7 @@ Command: ${command}`;
|
|
|
2978
2978
|
}
|
|
2979
2979
|
}
|
|
2980
2980
|
function extractWithStdin(binaryPath, cliArgs, content, options) {
|
|
2981
|
-
return new Promise((
|
|
2981
|
+
return new Promise((resolve6, reject2) => {
|
|
2982
2982
|
const childProcess = spawn(binaryPath, ["extract", ...cliArgs], {
|
|
2983
2983
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2984
2984
|
});
|
|
@@ -3000,7 +3000,7 @@ function extractWithStdin(binaryPath, cliArgs, content, options) {
|
|
|
3000
3000
|
}
|
|
3001
3001
|
try {
|
|
3002
3002
|
const result = processExtractOutput(stdout, options);
|
|
3003
|
-
|
|
3003
|
+
resolve6(result);
|
|
3004
3004
|
} catch (error) {
|
|
3005
3005
|
reject2(error);
|
|
3006
3006
|
}
|
|
@@ -7560,7 +7560,7 @@ function parseTargets(targets) {
|
|
|
7560
7560
|
}
|
|
7561
7561
|
return targets.split(/\s+/).filter((f) => f.length > 0);
|
|
7562
7562
|
}
|
|
7563
|
-
var searchSchema, querySchema, extractSchema, delegateSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, DEFAULT_VALID_TOOLS;
|
|
7563
|
+
var searchSchema, querySchema, extractSchema, delegateSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, bashToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, DEFAULT_VALID_TOOLS;
|
|
7564
7564
|
var init_common = __esm({
|
|
7565
7565
|
"src/tools/common.js"() {
|
|
7566
7566
|
"use strict";
|
|
@@ -7573,11 +7573,12 @@ var init_common = __esm({
|
|
|
7573
7573
|
pattern: external_exports.string().describe("AST pattern to search for. Use $NAME for variable names, $$$PARAMS for parameter lists, etc."),
|
|
7574
7574
|
path: external_exports.string().optional().default(".").describe("Path to search in"),
|
|
7575
7575
|
language: external_exports.string().optional().default("rust").describe("Programming language to use for parsing"),
|
|
7576
|
-
allow_tests: external_exports.boolean().optional().default(
|
|
7576
|
+
allow_tests: external_exports.boolean().optional().default(true).describe("Allow test files in search results")
|
|
7577
7577
|
});
|
|
7578
7578
|
extractSchema = external_exports.object({
|
|
7579
7579
|
targets: external_exports.string().optional().describe('File paths or symbols to extract from. Formats: "file.js" (whole file), "file.js:42" (line 42), "file.js:10-20" (lines 10-20), "file.js#funcName" (symbol). Multiple targets separated by spaces.'),
|
|
7580
|
-
input_content: external_exports.string().optional().describe("Text content to extract file paths from (alternative to targets)")
|
|
7580
|
+
input_content: external_exports.string().optional().describe("Text content to extract file paths from (alternative to targets)"),
|
|
7581
|
+
allow_tests: external_exports.boolean().optional().default(true).describe("Include test files in extraction results")
|
|
7581
7582
|
});
|
|
7582
7583
|
delegateSchema = external_exports.object({
|
|
7583
7584
|
task: external_exports.string().describe("The task to delegate to a subagent. Be specific about what needs to be accomplished.")
|
|
@@ -7704,7 +7705,7 @@ Parameters:
|
|
|
7704
7705
|
- pattern: (required) AST pattern to search for. Use $NAME for variable names, $$$PARAMS for parameter lists, etc.
|
|
7705
7706
|
- path: (optional, default: '.') Path to search in.
|
|
7706
7707
|
- language: (optional, default: 'rust') Programming language to use for parsing.
|
|
7707
|
-
- allow_tests: (optional, default:
|
|
7708
|
+
- allow_tests: (optional, default: true) Allow test files in search results (true/false).
|
|
7708
7709
|
Usage Example:
|
|
7709
7710
|
|
|
7710
7711
|
<examples>
|
|
@@ -7729,6 +7730,7 @@ Full file extraction should be the LAST RESORT! Always prefer search.
|
|
|
7729
7730
|
Parameters:
|
|
7730
7731
|
- targets: (required) File paths or symbols to extract from. Formats: "file.js" (whole file), "file.js:42" (code block at line 42), "file.js:10-20" (lines 10-20), "file.js#funcName" (specific symbol). Multiple targets separated by spaces.
|
|
7731
7732
|
- input_content: (optional) Text content to extract file paths from (alternative to targets for processing diffs/logs).
|
|
7733
|
+
- allow_tests: (optional, default: true) Include test files in extraction results.
|
|
7732
7734
|
|
|
7733
7735
|
Usage Example:
|
|
7734
7736
|
|
|
@@ -7795,6 +7797,61 @@ Usage Example:
|
|
|
7795
7797
|
<attempt_completion>
|
|
7796
7798
|
I have refactored the search module according to the requirements and verified the tests pass. The module now uses the new BM25 ranking algorithm and has improved error handling.
|
|
7797
7799
|
</attempt_completion>
|
|
7800
|
+
`;
|
|
7801
|
+
bashToolDefinition = `
|
|
7802
|
+
## bash
|
|
7803
|
+
Description: Execute bash commands for system exploration and development tasks. This tool has built-in security with allow/deny lists. By default, only safe read-only commands are allowed for code exploration.
|
|
7804
|
+
|
|
7805
|
+
Parameters:
|
|
7806
|
+
- command: (required) The bash command to execute
|
|
7807
|
+
- workingDirectory: (optional) Directory to execute the command in
|
|
7808
|
+
- timeout: (optional) Command timeout in milliseconds
|
|
7809
|
+
- env: (optional) Additional environment variables as an object
|
|
7810
|
+
|
|
7811
|
+
Security: Commands are filtered through allow/deny lists for safety:
|
|
7812
|
+
- Allowed by default: ls, cat, git status, npm list, find, grep, etc.
|
|
7813
|
+
- Denied by default: rm -rf, sudo, npm install, dangerous system commands
|
|
7814
|
+
|
|
7815
|
+
Usage Examples:
|
|
7816
|
+
|
|
7817
|
+
<examples>
|
|
7818
|
+
|
|
7819
|
+
User: What files are in the src directory?
|
|
7820
|
+
<bash>
|
|
7821
|
+
<command>ls -la src/</command>
|
|
7822
|
+
</bash>
|
|
7823
|
+
|
|
7824
|
+
User: Show me the git status
|
|
7825
|
+
<bash>
|
|
7826
|
+
<command>git status</command>
|
|
7827
|
+
</bash>
|
|
7828
|
+
|
|
7829
|
+
User: Find all TypeScript files
|
|
7830
|
+
<bash>
|
|
7831
|
+
<command>find . -name "*.ts" -type f</command>
|
|
7832
|
+
</bash>
|
|
7833
|
+
|
|
7834
|
+
User: Check installed npm packages
|
|
7835
|
+
<bash>
|
|
7836
|
+
<command>npm list --depth=0</command>
|
|
7837
|
+
</bash>
|
|
7838
|
+
|
|
7839
|
+
User: Search for TODO comments in code
|
|
7840
|
+
<bash>
|
|
7841
|
+
<command>grep -r "TODO" src/</command>
|
|
7842
|
+
</bash>
|
|
7843
|
+
|
|
7844
|
+
User: Show recent git commits
|
|
7845
|
+
<bash>
|
|
7846
|
+
<command>git log --oneline -10</command>
|
|
7847
|
+
</bash>
|
|
7848
|
+
|
|
7849
|
+
User: Check system info
|
|
7850
|
+
<bash>
|
|
7851
|
+
<command>uname -a</command>
|
|
7852
|
+
</bash>
|
|
7853
|
+
|
|
7854
|
+
</examples>
|
|
7798
7855
|
`;
|
|
7799
7856
|
searchDescription = "Search code in the repository using Elasticsearch-like query syntax. Use this tool first for any code-related questions.";
|
|
7800
7857
|
queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
|
|
@@ -8894,14 +8951,14 @@ async function executeBashCommand(command, options = {}) {
|
|
|
8894
8951
|
console.log(`[BashExecutor] Working directory: "${cwd}"`);
|
|
8895
8952
|
console.log(`[BashExecutor] Timeout: ${timeout}ms`);
|
|
8896
8953
|
}
|
|
8897
|
-
return new Promise((
|
|
8954
|
+
return new Promise((resolve6, reject2) => {
|
|
8898
8955
|
const processEnv = {
|
|
8899
8956
|
...process.env,
|
|
8900
8957
|
...env
|
|
8901
8958
|
};
|
|
8902
8959
|
const args = parseCommandForExecution(command);
|
|
8903
8960
|
if (!args || args.length === 0) {
|
|
8904
|
-
|
|
8961
|
+
resolve6({
|
|
8905
8962
|
success: false,
|
|
8906
8963
|
error: "Failed to parse command",
|
|
8907
8964
|
stdout: "",
|
|
@@ -8984,7 +9041,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
8984
9041
|
success = false;
|
|
8985
9042
|
error = `Command exited with code ${code}`;
|
|
8986
9043
|
}
|
|
8987
|
-
|
|
9044
|
+
resolve6({
|
|
8988
9045
|
success,
|
|
8989
9046
|
error,
|
|
8990
9047
|
stdout: stdout.trim(),
|
|
@@ -9004,7 +9061,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
9004
9061
|
if (debug) {
|
|
9005
9062
|
console.log(`[BashExecutor] Spawn error:`, error);
|
|
9006
9063
|
}
|
|
9007
|
-
|
|
9064
|
+
resolve6({
|
|
9008
9065
|
success: false,
|
|
9009
9066
|
error: `Failed to execute command: ${error.message}`,
|
|
9010
9067
|
stdout: "",
|
|
@@ -9276,6 +9333,283 @@ Command failed with exit code ${result.exitCode}`;
|
|
|
9276
9333
|
}
|
|
9277
9334
|
});
|
|
9278
9335
|
|
|
9336
|
+
// src/tools/edit.js
|
|
9337
|
+
import { tool as tool3 } from "ai";
|
|
9338
|
+
import { promises as fs4 } from "fs";
|
|
9339
|
+
import { dirname, resolve as resolve3, isAbsolute, sep } from "path";
|
|
9340
|
+
import { existsSync as existsSync2 } from "fs";
|
|
9341
|
+
function isPathAllowed(filePath, allowedFolders) {
|
|
9342
|
+
if (!allowedFolders || allowedFolders.length === 0) {
|
|
9343
|
+
const resolvedPath2 = resolve3(filePath);
|
|
9344
|
+
const cwd = resolve3(process.cwd());
|
|
9345
|
+
return resolvedPath2 === cwd || resolvedPath2.startsWith(cwd + sep);
|
|
9346
|
+
}
|
|
9347
|
+
const resolvedPath = resolve3(filePath);
|
|
9348
|
+
return allowedFolders.some((folder) => {
|
|
9349
|
+
const allowedPath = resolve3(folder);
|
|
9350
|
+
return resolvedPath === allowedPath || resolvedPath.startsWith(allowedPath + sep);
|
|
9351
|
+
});
|
|
9352
|
+
}
|
|
9353
|
+
function parseFileToolOptions(options = {}) {
|
|
9354
|
+
return {
|
|
9355
|
+
debug: options.debug || false,
|
|
9356
|
+
allowedFolders: options.allowedFolders || [],
|
|
9357
|
+
defaultPath: options.defaultPath
|
|
9358
|
+
};
|
|
9359
|
+
}
|
|
9360
|
+
var editTool, createTool, editDescription, createDescription, editToolDefinition, createToolDefinition;
|
|
9361
|
+
var init_edit = __esm({
|
|
9362
|
+
"src/tools/edit.js"() {
|
|
9363
|
+
"use strict";
|
|
9364
|
+
editTool = (options = {}) => {
|
|
9365
|
+
const { debug, allowedFolders, defaultPath } = parseFileToolOptions(options);
|
|
9366
|
+
return tool3({
|
|
9367
|
+
name: "edit",
|
|
9368
|
+
description: `Edit files using exact string replacement (Claude Code style).
|
|
9369
|
+
|
|
9370
|
+
This tool performs exact string replacements in files. It requires the old_string to match exactly what's in the file, including all whitespace and indentation.
|
|
9371
|
+
|
|
9372
|
+
Parameters:
|
|
9373
|
+
- file_path: Path to the file to edit (absolute or relative)
|
|
9374
|
+
- old_string: Exact text to find and replace (must be unique in the file unless replace_all is true)
|
|
9375
|
+
- new_string: Text to replace with
|
|
9376
|
+
- replace_all: (optional) Replace all occurrences instead of requiring uniqueness
|
|
9377
|
+
|
|
9378
|
+
Important:
|
|
9379
|
+
- The old_string must match EXACTLY including whitespace
|
|
9380
|
+
- If old_string appears multiple times and replace_all is false, the edit will fail
|
|
9381
|
+
- Use larger context around the string to ensure uniqueness when needed`,
|
|
9382
|
+
inputSchema: {
|
|
9383
|
+
type: "object",
|
|
9384
|
+
properties: {
|
|
9385
|
+
file_path: {
|
|
9386
|
+
type: "string",
|
|
9387
|
+
description: "Path to the file to edit"
|
|
9388
|
+
},
|
|
9389
|
+
old_string: {
|
|
9390
|
+
type: "string",
|
|
9391
|
+
description: "Exact text to find and replace"
|
|
9392
|
+
},
|
|
9393
|
+
new_string: {
|
|
9394
|
+
type: "string",
|
|
9395
|
+
description: "Text to replace with"
|
|
9396
|
+
},
|
|
9397
|
+
replace_all: {
|
|
9398
|
+
type: "boolean",
|
|
9399
|
+
description: "Replace all occurrences (default: false)",
|
|
9400
|
+
default: false
|
|
9401
|
+
}
|
|
9402
|
+
},
|
|
9403
|
+
required: ["file_path", "old_string", "new_string"]
|
|
9404
|
+
},
|
|
9405
|
+
execute: async ({ file_path, old_string, new_string, replace_all = false }) => {
|
|
9406
|
+
try {
|
|
9407
|
+
if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
|
|
9408
|
+
return `Error editing file: Invalid file_path - must be a non-empty string`;
|
|
9409
|
+
}
|
|
9410
|
+
if (old_string === void 0 || old_string === null || typeof old_string !== "string") {
|
|
9411
|
+
return `Error editing file: Invalid old_string - must be a string`;
|
|
9412
|
+
}
|
|
9413
|
+
if (new_string === void 0 || new_string === null || typeof new_string !== "string") {
|
|
9414
|
+
return `Error editing file: Invalid new_string - must be a string`;
|
|
9415
|
+
}
|
|
9416
|
+
const resolvedPath = isAbsolute(file_path) ? file_path : resolve3(defaultPath || process.cwd(), file_path);
|
|
9417
|
+
if (debug) {
|
|
9418
|
+
console.error(`[Edit] Attempting to edit file: ${resolvedPath}`);
|
|
9419
|
+
}
|
|
9420
|
+
if (!isPathAllowed(resolvedPath, allowedFolders)) {
|
|
9421
|
+
return `Error editing file: Permission denied - ${file_path} is outside allowed directories`;
|
|
9422
|
+
}
|
|
9423
|
+
if (!existsSync2(resolvedPath)) {
|
|
9424
|
+
return `Error editing file: File not found - ${file_path}`;
|
|
9425
|
+
}
|
|
9426
|
+
const content = await fs4.readFile(resolvedPath, "utf-8");
|
|
9427
|
+
if (!content.includes(old_string)) {
|
|
9428
|
+
return `Error editing file: String not found - the specified old_string was not found in ${file_path}`;
|
|
9429
|
+
}
|
|
9430
|
+
const occurrences = content.split(old_string).length - 1;
|
|
9431
|
+
if (!replace_all && occurrences > 1) {
|
|
9432
|
+
return `Error editing file: Multiple occurrences found - the old_string appears ${occurrences} times. Use replace_all: true to replace all occurrences, or provide more context to make the string unique.`;
|
|
9433
|
+
}
|
|
9434
|
+
let newContent;
|
|
9435
|
+
if (replace_all) {
|
|
9436
|
+
newContent = content.replaceAll(old_string, new_string);
|
|
9437
|
+
} else {
|
|
9438
|
+
newContent = content.replace(old_string, new_string);
|
|
9439
|
+
}
|
|
9440
|
+
if (newContent === content) {
|
|
9441
|
+
return `Error editing file: No changes made - old_string and new_string might be the same`;
|
|
9442
|
+
}
|
|
9443
|
+
await fs4.writeFile(resolvedPath, newContent, "utf-8");
|
|
9444
|
+
const replacedCount = replace_all ? occurrences : 1;
|
|
9445
|
+
if (debug) {
|
|
9446
|
+
console.error(`[Edit] Successfully edited ${resolvedPath}, replaced ${replacedCount} occurrence(s)`);
|
|
9447
|
+
}
|
|
9448
|
+
return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""})`;
|
|
9449
|
+
} catch (error) {
|
|
9450
|
+
console.error("[Edit] Error:", error);
|
|
9451
|
+
return `Error editing file: ${error.message}`;
|
|
9452
|
+
}
|
|
9453
|
+
}
|
|
9454
|
+
});
|
|
9455
|
+
};
|
|
9456
|
+
createTool = (options = {}) => {
|
|
9457
|
+
const { debug, allowedFolders, defaultPath } = parseFileToolOptions(options);
|
|
9458
|
+
return tool3({
|
|
9459
|
+
name: "create",
|
|
9460
|
+
description: `Create new files with specified content.
|
|
9461
|
+
|
|
9462
|
+
This tool creates new files in the filesystem. It will create parent directories if they don't exist.
|
|
9463
|
+
|
|
9464
|
+
Parameters:
|
|
9465
|
+
- file_path: Path where the file should be created (absolute or relative)
|
|
9466
|
+
- content: Content to write to the file
|
|
9467
|
+
- overwrite: (optional) Whether to overwrite if file exists (default: false)
|
|
9468
|
+
|
|
9469
|
+
Important:
|
|
9470
|
+
- By default, will fail if the file already exists
|
|
9471
|
+
- Set overwrite: true to replace existing files
|
|
9472
|
+
- Parent directories will be created automatically if needed`,
|
|
9473
|
+
inputSchema: {
|
|
9474
|
+
type: "object",
|
|
9475
|
+
properties: {
|
|
9476
|
+
file_path: {
|
|
9477
|
+
type: "string",
|
|
9478
|
+
description: "Path where the file should be created"
|
|
9479
|
+
},
|
|
9480
|
+
content: {
|
|
9481
|
+
type: "string",
|
|
9482
|
+
description: "Content to write to the file"
|
|
9483
|
+
},
|
|
9484
|
+
overwrite: {
|
|
9485
|
+
type: "boolean",
|
|
9486
|
+
description: "Overwrite if file exists (default: false)",
|
|
9487
|
+
default: false
|
|
9488
|
+
}
|
|
9489
|
+
},
|
|
9490
|
+
required: ["file_path", "content"]
|
|
9491
|
+
},
|
|
9492
|
+
execute: async ({ file_path, content, overwrite = false }) => {
|
|
9493
|
+
try {
|
|
9494
|
+
if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
|
|
9495
|
+
return `Error creating file: Invalid file_path - must be a non-empty string`;
|
|
9496
|
+
}
|
|
9497
|
+
if (content === void 0 || content === null || typeof content !== "string") {
|
|
9498
|
+
return `Error creating file: Invalid content - must be a string`;
|
|
9499
|
+
}
|
|
9500
|
+
const resolvedPath = isAbsolute(file_path) ? file_path : resolve3(defaultPath || process.cwd(), file_path);
|
|
9501
|
+
if (debug) {
|
|
9502
|
+
console.error(`[Create] Attempting to create file: ${resolvedPath}`);
|
|
9503
|
+
}
|
|
9504
|
+
if (!isPathAllowed(resolvedPath, allowedFolders)) {
|
|
9505
|
+
return `Error creating file: Permission denied - ${file_path} is outside allowed directories`;
|
|
9506
|
+
}
|
|
9507
|
+
if (existsSync2(resolvedPath) && !overwrite) {
|
|
9508
|
+
return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
|
|
9509
|
+
}
|
|
9510
|
+
const dir = dirname(resolvedPath);
|
|
9511
|
+
await fs4.mkdir(dir, { recursive: true });
|
|
9512
|
+
await fs4.writeFile(resolvedPath, content, "utf-8");
|
|
9513
|
+
const action = existsSync2(resolvedPath) && overwrite ? "overwrote" : "created";
|
|
9514
|
+
const bytes = Buffer.byteLength(content, "utf-8");
|
|
9515
|
+
if (debug) {
|
|
9516
|
+
console.error(`[Create] Successfully ${action} ${resolvedPath}`);
|
|
9517
|
+
}
|
|
9518
|
+
return `Successfully ${action} ${file_path} (${bytes} bytes)`;
|
|
9519
|
+
} catch (error) {
|
|
9520
|
+
console.error("[Create] Error:", error);
|
|
9521
|
+
return `Error creating file: ${error.message}`;
|
|
9522
|
+
}
|
|
9523
|
+
}
|
|
9524
|
+
});
|
|
9525
|
+
};
|
|
9526
|
+
editDescription = "Edit files using exact string replacement. Requires exact match including whitespace.";
|
|
9527
|
+
createDescription = "Create new files with specified content. Will create parent directories if needed.";
|
|
9528
|
+
editToolDefinition = `
|
|
9529
|
+
## edit
|
|
9530
|
+
Description: ${editDescription}
|
|
9531
|
+
|
|
9532
|
+
When to use:
|
|
9533
|
+
- For precise, surgical edits to existing files
|
|
9534
|
+
- When you need to change specific lines or blocks of code
|
|
9535
|
+
- For renaming functions, variables, or updating configuration values
|
|
9536
|
+
- When the exact text to replace is known and unique (or use replace_all for multiple occurrences)
|
|
9537
|
+
|
|
9538
|
+
When NOT to use:
|
|
9539
|
+
- For creating new files (use 'create' tool instead)
|
|
9540
|
+
- When you cannot determine the exact text to replace
|
|
9541
|
+
- When changes span multiple locations that would be better handled together
|
|
9542
|
+
|
|
9543
|
+
Parameters:
|
|
9544
|
+
- file_path: (required) Path to the file to edit
|
|
9545
|
+
- old_string: (required) Exact text to find and replace (must match including whitespace, newlines, and indentation)
|
|
9546
|
+
- new_string: (required) Text to replace with
|
|
9547
|
+
- replace_all: (optional, default: false) Replace all occurrences if the string appears multiple times
|
|
9548
|
+
|
|
9549
|
+
Important notes:
|
|
9550
|
+
- The old_string MUST match EXACTLY, including all whitespace, indentation, and line breaks
|
|
9551
|
+
- If old_string appears multiple times and replace_all is false, the tool will fail
|
|
9552
|
+
- Always verify the exact formatting of the text you want to replace
|
|
9553
|
+
|
|
9554
|
+
Examples:
|
|
9555
|
+
<edit>
|
|
9556
|
+
<file_path>src/main.js</file_path>
|
|
9557
|
+
<old_string>function oldName() {
|
|
9558
|
+
return 42;
|
|
9559
|
+
}</old_string>
|
|
9560
|
+
<new_string>function newName() {
|
|
9561
|
+
return 42;
|
|
9562
|
+
}</new_string>
|
|
9563
|
+
</edit>
|
|
9564
|
+
|
|
9565
|
+
<edit>
|
|
9566
|
+
<file_path>config.json</file_path>
|
|
9567
|
+
<old_string>"debug": false</old_string>
|
|
9568
|
+
<new_string>"debug": true</new_string>
|
|
9569
|
+
<replace_all>true</replace_all>
|
|
9570
|
+
</edit>`;
|
|
9571
|
+
createToolDefinition = `
|
|
9572
|
+
## create
|
|
9573
|
+
Description: ${createDescription}
|
|
9574
|
+
|
|
9575
|
+
When to use:
|
|
9576
|
+
- For creating brand new files from scratch
|
|
9577
|
+
- When you need to add configuration files, documentation, or new modules
|
|
9578
|
+
- For generating boilerplate code or templates
|
|
9579
|
+
- When you have the complete content ready to write
|
|
9580
|
+
|
|
9581
|
+
When NOT to use:
|
|
9582
|
+
- For editing existing files (use 'edit' tool instead)
|
|
9583
|
+
- When a file already exists unless you explicitly want to overwrite it
|
|
9584
|
+
|
|
9585
|
+
Parameters:
|
|
9586
|
+
- file_path: (required) Path where the file should be created
|
|
9587
|
+
- content: (required) Complete content to write to the file
|
|
9588
|
+
- overwrite: (optional, default: false) Whether to overwrite if file already exists
|
|
9589
|
+
|
|
9590
|
+
Important notes:
|
|
9591
|
+
- Parent directories will be created automatically if they don't exist
|
|
9592
|
+
- The tool will fail if the file already exists and overwrite is false
|
|
9593
|
+
- Be careful with the overwrite option as it completely replaces existing files
|
|
9594
|
+
|
|
9595
|
+
Examples:
|
|
9596
|
+
<create>
|
|
9597
|
+
<file_path>src/newFile.js</file_path>
|
|
9598
|
+
<content>export function hello() {
|
|
9599
|
+
return "Hello, world!";
|
|
9600
|
+
}</content>
|
|
9601
|
+
</create>
|
|
9602
|
+
|
|
9603
|
+
<create>
|
|
9604
|
+
<file_path>README.md</file_path>
|
|
9605
|
+
<content># My Project
|
|
9606
|
+
|
|
9607
|
+
This is a new project.</content>
|
|
9608
|
+
<overwrite>true</overwrite>
|
|
9609
|
+
</create>`;
|
|
9610
|
+
}
|
|
9611
|
+
});
|
|
9612
|
+
|
|
9279
9613
|
// src/tools/langchain.js
|
|
9280
9614
|
var init_langchain = __esm({
|
|
9281
9615
|
"src/tools/langchain.js"() {
|
|
@@ -9425,8 +9759,10 @@ var init_tools = __esm({
|
|
|
9425
9759
|
"use strict";
|
|
9426
9760
|
init_vercel();
|
|
9427
9761
|
init_bash();
|
|
9762
|
+
init_edit();
|
|
9428
9763
|
init_langchain();
|
|
9429
9764
|
init_common();
|
|
9765
|
+
init_edit();
|
|
9430
9766
|
init_system_message();
|
|
9431
9767
|
init_vercel();
|
|
9432
9768
|
init_bash();
|
|
@@ -9443,7 +9779,7 @@ var init_tools = __esm({
|
|
|
9443
9779
|
});
|
|
9444
9780
|
|
|
9445
9781
|
// src/utils/file-lister.js
|
|
9446
|
-
import
|
|
9782
|
+
import fs5 from "fs";
|
|
9447
9783
|
import path4 from "path";
|
|
9448
9784
|
import { promisify as promisify6 } from "util";
|
|
9449
9785
|
import { exec as exec4 } from "child_process";
|
|
@@ -9453,10 +9789,10 @@ async function listFilesByLevel(options) {
|
|
|
9453
9789
|
maxFiles = 100,
|
|
9454
9790
|
respectGitignore = true
|
|
9455
9791
|
} = options;
|
|
9456
|
-
if (!
|
|
9792
|
+
if (!fs5.existsSync(directory)) {
|
|
9457
9793
|
throw new Error(`Directory does not exist: ${directory}`);
|
|
9458
9794
|
}
|
|
9459
|
-
const gitDirExists =
|
|
9795
|
+
const gitDirExists = fs5.existsSync(path4.join(directory, ".git"));
|
|
9460
9796
|
if (gitDirExists && respectGitignore) {
|
|
9461
9797
|
try {
|
|
9462
9798
|
return await listFilesUsingGit(directory, maxFiles);
|
|
@@ -9487,7 +9823,7 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
|
|
|
9487
9823
|
while (queue.length > 0 && result.length < maxFiles) {
|
|
9488
9824
|
const { dir, level } = queue.shift();
|
|
9489
9825
|
try {
|
|
9490
|
-
const entries =
|
|
9826
|
+
const entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
9491
9827
|
const files = entries.filter((entry) => entry.isFile());
|
|
9492
9828
|
for (const file of files) {
|
|
9493
9829
|
if (result.length >= maxFiles) break;
|
|
@@ -9512,11 +9848,11 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
|
|
|
9512
9848
|
}
|
|
9513
9849
|
function loadGitignorePatterns(directory) {
|
|
9514
9850
|
const gitignorePath = path4.join(directory, ".gitignore");
|
|
9515
|
-
if (!
|
|
9851
|
+
if (!fs5.existsSync(gitignorePath)) {
|
|
9516
9852
|
return [];
|
|
9517
9853
|
}
|
|
9518
9854
|
try {
|
|
9519
|
-
const content =
|
|
9855
|
+
const content = fs5.readFileSync(gitignorePath, "utf8");
|
|
9520
9856
|
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
9521
9857
|
} catch (error) {
|
|
9522
9858
|
console.error(`Warning: Could not read .gitignore: ${error.message}`);
|
|
@@ -9543,8 +9879,8 @@ var init_file_lister = __esm({
|
|
|
9543
9879
|
});
|
|
9544
9880
|
|
|
9545
9881
|
// src/agent/simpleTelemetry.js
|
|
9546
|
-
import { existsSync as
|
|
9547
|
-
import { dirname } from "path";
|
|
9882
|
+
import { existsSync as existsSync3, mkdirSync, createWriteStream } from "fs";
|
|
9883
|
+
import { dirname as dirname2 } from "path";
|
|
9548
9884
|
function initializeSimpleTelemetryFromOptions(options) {
|
|
9549
9885
|
const telemetry = new SimpleTelemetry({
|
|
9550
9886
|
serviceName: "probe-agent",
|
|
@@ -9571,8 +9907,8 @@ var init_simpleTelemetry = __esm({
|
|
|
9571
9907
|
}
|
|
9572
9908
|
initializeFileExporter() {
|
|
9573
9909
|
try {
|
|
9574
|
-
const dir =
|
|
9575
|
-
if (!
|
|
9910
|
+
const dir = dirname2(this.filePath);
|
|
9911
|
+
if (!existsSync3(dir)) {
|
|
9576
9912
|
mkdirSync(dir, { recursive: true });
|
|
9577
9913
|
}
|
|
9578
9914
|
this.stream = createWriteStream(this.filePath, { flags: "a" });
|
|
@@ -9636,20 +9972,20 @@ var init_simpleTelemetry = __esm({
|
|
|
9636
9972
|
}
|
|
9637
9973
|
async flush() {
|
|
9638
9974
|
if (this.stream) {
|
|
9639
|
-
return new Promise((
|
|
9640
|
-
this.stream.once("drain",
|
|
9975
|
+
return new Promise((resolve6) => {
|
|
9976
|
+
this.stream.once("drain", resolve6);
|
|
9641
9977
|
if (!this.stream.writableNeedDrain) {
|
|
9642
|
-
|
|
9978
|
+
resolve6();
|
|
9643
9979
|
}
|
|
9644
9980
|
});
|
|
9645
9981
|
}
|
|
9646
9982
|
}
|
|
9647
9983
|
async shutdown() {
|
|
9648
9984
|
if (this.stream) {
|
|
9649
|
-
return new Promise((
|
|
9985
|
+
return new Promise((resolve6) => {
|
|
9650
9986
|
this.stream.end(() => {
|
|
9651
9987
|
console.log(`[SimpleTelemetry] File stream closed: ${this.filePath}`);
|
|
9652
|
-
|
|
9988
|
+
resolve6();
|
|
9653
9989
|
});
|
|
9654
9990
|
});
|
|
9655
9991
|
}
|
|
@@ -10612,7 +10948,7 @@ var init_escape = __esm({
|
|
|
10612
10948
|
});
|
|
10613
10949
|
|
|
10614
10950
|
// node_modules/minimatch/dist/esm/index.js
|
|
10615
|
-
var import_brace_expansion, minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path5,
|
|
10951
|
+
var import_brace_expansion, minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path5, sep2, GLOBSTAR, qmark2, star2, twoStarDot, twoStarNoDot, filter, ext, defaults, braceExpand, makeRe, match, globMagic, regExpEscape2, Minimatch;
|
|
10616
10952
|
var init_esm = __esm({
|
|
10617
10953
|
"node_modules/minimatch/dist/esm/index.js"() {
|
|
10618
10954
|
import_brace_expansion = __toESM(require_brace_expansion(), 1);
|
|
@@ -10685,8 +11021,8 @@ var init_esm = __esm({
|
|
|
10685
11021
|
win32: { sep: "\\" },
|
|
10686
11022
|
posix: { sep: "/" }
|
|
10687
11023
|
};
|
|
10688
|
-
|
|
10689
|
-
minimatch.sep =
|
|
11024
|
+
sep2 = defaultPlatform === "win32" ? path5.win32.sep : path5.posix.sep;
|
|
11025
|
+
minimatch.sep = sep2;
|
|
10690
11026
|
GLOBSTAR = Symbol("globstar **");
|
|
10691
11027
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
10692
11028
|
qmark2 = "[^/]";
|
|
@@ -13448,10 +13784,10 @@ var init_esm3 = __esm({
|
|
|
13448
13784
|
* Return a void Promise that resolves once the stream ends.
|
|
13449
13785
|
*/
|
|
13450
13786
|
async promise() {
|
|
13451
|
-
return new Promise((
|
|
13787
|
+
return new Promise((resolve6, reject2) => {
|
|
13452
13788
|
this.on(DESTROYED, () => reject2(new Error("stream destroyed")));
|
|
13453
13789
|
this.on("error", (er) => reject2(er));
|
|
13454
|
-
this.on("end", () =>
|
|
13790
|
+
this.on("end", () => resolve6());
|
|
13455
13791
|
});
|
|
13456
13792
|
}
|
|
13457
13793
|
/**
|
|
@@ -13475,7 +13811,7 @@ var init_esm3 = __esm({
|
|
|
13475
13811
|
return Promise.resolve({ done: false, value: res });
|
|
13476
13812
|
if (this[EOF])
|
|
13477
13813
|
return stop();
|
|
13478
|
-
let
|
|
13814
|
+
let resolve6;
|
|
13479
13815
|
let reject2;
|
|
13480
13816
|
const onerr = (er) => {
|
|
13481
13817
|
this.off("data", ondata);
|
|
@@ -13489,19 +13825,19 @@ var init_esm3 = __esm({
|
|
|
13489
13825
|
this.off("end", onend);
|
|
13490
13826
|
this.off(DESTROYED, ondestroy);
|
|
13491
13827
|
this.pause();
|
|
13492
|
-
|
|
13828
|
+
resolve6({ value, done: !!this[EOF] });
|
|
13493
13829
|
};
|
|
13494
13830
|
const onend = () => {
|
|
13495
13831
|
this.off("error", onerr);
|
|
13496
13832
|
this.off("data", ondata);
|
|
13497
13833
|
this.off(DESTROYED, ondestroy);
|
|
13498
13834
|
stop();
|
|
13499
|
-
|
|
13835
|
+
resolve6({ done: true, value: void 0 });
|
|
13500
13836
|
};
|
|
13501
13837
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
13502
13838
|
return new Promise((res2, rej) => {
|
|
13503
13839
|
reject2 = rej;
|
|
13504
|
-
|
|
13840
|
+
resolve6 = res2;
|
|
13505
13841
|
this.once(DESTROYED, ondestroy);
|
|
13506
13842
|
this.once("error", onerr);
|
|
13507
13843
|
this.once("end", onend);
|
|
@@ -14481,9 +14817,9 @@ var init_esm4 = __esm({
|
|
|
14481
14817
|
if (this.#asyncReaddirInFlight) {
|
|
14482
14818
|
await this.#asyncReaddirInFlight;
|
|
14483
14819
|
} else {
|
|
14484
|
-
let
|
|
14820
|
+
let resolve6 = () => {
|
|
14485
14821
|
};
|
|
14486
|
-
this.#asyncReaddirInFlight = new Promise((res) =>
|
|
14822
|
+
this.#asyncReaddirInFlight = new Promise((res) => resolve6 = res);
|
|
14487
14823
|
try {
|
|
14488
14824
|
for (const e of await this.#fs.promises.readdir(fullpath, {
|
|
14489
14825
|
withFileTypes: true
|
|
@@ -14496,7 +14832,7 @@ var init_esm4 = __esm({
|
|
|
14496
14832
|
children.provisional = 0;
|
|
14497
14833
|
}
|
|
14498
14834
|
this.#asyncReaddirInFlight = void 0;
|
|
14499
|
-
|
|
14835
|
+
resolve6();
|
|
14500
14836
|
}
|
|
14501
14837
|
return children.slice(0, children.provisional);
|
|
14502
14838
|
}
|
|
@@ -14726,8 +15062,8 @@ var init_esm4 = __esm({
|
|
|
14726
15062
|
*
|
|
14727
15063
|
* @internal
|
|
14728
15064
|
*/
|
|
14729
|
-
constructor(cwd = process.cwd(), pathImpl,
|
|
14730
|
-
this.#fs = fsFromOption(
|
|
15065
|
+
constructor(cwd = process.cwd(), pathImpl, sep3, { nocase, childrenCacheSize = 16 * 1024, fs: fs7 = defaultFS } = {}) {
|
|
15066
|
+
this.#fs = fsFromOption(fs7);
|
|
14731
15067
|
if (cwd instanceof URL || cwd.startsWith("file://")) {
|
|
14732
15068
|
cwd = fileURLToPath4(cwd);
|
|
14733
15069
|
}
|
|
@@ -14737,7 +15073,7 @@ var init_esm4 = __esm({
|
|
|
14737
15073
|
this.#resolveCache = new ResolveCache();
|
|
14738
15074
|
this.#resolvePosixCache = new ResolveCache();
|
|
14739
15075
|
this.#children = new ChildrenCache(childrenCacheSize);
|
|
14740
|
-
const split = cwdPath.substring(this.rootPath.length).split(
|
|
15076
|
+
const split = cwdPath.substring(this.rootPath.length).split(sep3);
|
|
14741
15077
|
if (split.length === 1 && !split[0]) {
|
|
14742
15078
|
split.pop();
|
|
14743
15079
|
}
|
|
@@ -15285,8 +15621,8 @@ var init_esm4 = __esm({
|
|
|
15285
15621
|
/**
|
|
15286
15622
|
* @internal
|
|
15287
15623
|
*/
|
|
15288
|
-
newRoot(
|
|
15289
|
-
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs:
|
|
15624
|
+
newRoot(fs7) {
|
|
15625
|
+
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs7 });
|
|
15290
15626
|
}
|
|
15291
15627
|
/**
|
|
15292
15628
|
* Return true if the provided path string is an absolute path
|
|
@@ -15314,8 +15650,8 @@ var init_esm4 = __esm({
|
|
|
15314
15650
|
/**
|
|
15315
15651
|
* @internal
|
|
15316
15652
|
*/
|
|
15317
|
-
newRoot(
|
|
15318
|
-
return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs:
|
|
15653
|
+
newRoot(fs7) {
|
|
15654
|
+
return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs7 });
|
|
15319
15655
|
}
|
|
15320
15656
|
/**
|
|
15321
15657
|
* Return true if the provided path string is an absolute path
|
|
@@ -16455,7 +16791,7 @@ import { exec as exec5 } from "child_process";
|
|
|
16455
16791
|
import { promisify as promisify7 } from "util";
|
|
16456
16792
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
16457
16793
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
16458
|
-
import
|
|
16794
|
+
import fs6 from "fs";
|
|
16459
16795
|
import { promises as fsPromises } from "fs";
|
|
16460
16796
|
import path6 from "path";
|
|
16461
16797
|
function isSessionCancelled(sessionId) {
|
|
@@ -16515,6 +16851,20 @@ function createWrappedTools(baseTools) {
|
|
|
16515
16851
|
baseTools.bashTool.execute
|
|
16516
16852
|
);
|
|
16517
16853
|
}
|
|
16854
|
+
if (baseTools.editTool) {
|
|
16855
|
+
wrappedTools.editToolInstance = wrapToolWithEmitter(
|
|
16856
|
+
baseTools.editTool,
|
|
16857
|
+
"edit",
|
|
16858
|
+
baseTools.editTool.execute
|
|
16859
|
+
);
|
|
16860
|
+
}
|
|
16861
|
+
if (baseTools.createTool) {
|
|
16862
|
+
wrappedTools.createToolInstance = wrapToolWithEmitter(
|
|
16863
|
+
baseTools.createTool,
|
|
16864
|
+
"create",
|
|
16865
|
+
baseTools.createTool.execute
|
|
16866
|
+
);
|
|
16867
|
+
}
|
|
16518
16868
|
return wrappedTools;
|
|
16519
16869
|
}
|
|
16520
16870
|
var toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
|
|
@@ -16525,9 +16875,9 @@ var init_probeTool = __esm({
|
|
|
16525
16875
|
init_esm5();
|
|
16526
16876
|
toolCallEmitter = new EventEmitter2();
|
|
16527
16877
|
activeToolExecutions = /* @__PURE__ */ new Map();
|
|
16528
|
-
wrapToolWithEmitter = (
|
|
16878
|
+
wrapToolWithEmitter = (tool4, toolName, baseExecute) => {
|
|
16529
16879
|
return {
|
|
16530
|
-
...
|
|
16880
|
+
...tool4,
|
|
16531
16881
|
// Spread schema, description etc.
|
|
16532
16882
|
execute: async (params) => {
|
|
16533
16883
|
const debug = process.env.DEBUG === "1";
|
|
@@ -16762,8 +17112,10 @@ var init_index = __esm({
|
|
|
16762
17112
|
init_file_lister();
|
|
16763
17113
|
init_system_message();
|
|
16764
17114
|
init_common();
|
|
17115
|
+
init_edit();
|
|
16765
17116
|
init_vercel();
|
|
16766
17117
|
init_bash();
|
|
17118
|
+
init_edit();
|
|
16767
17119
|
init_ProbeAgent();
|
|
16768
17120
|
init_simpleTelemetry();
|
|
16769
17121
|
init_probeTool();
|
|
@@ -16845,8 +17197,8 @@ function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
|
|
|
16845
17197
|
function hasOtherToolTags(xmlString, validTools = []) {
|
|
16846
17198
|
const defaultTools = ["search", "query", "extract", "listFiles", "searchFiles", "implement", "attempt_completion"];
|
|
16847
17199
|
const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
|
|
16848
|
-
for (const
|
|
16849
|
-
if (
|
|
17200
|
+
for (const tool4 of toolsToCheck) {
|
|
17201
|
+
if (tool4 !== "attempt_completion" && xmlString.includes(`<${tool4}`)) {
|
|
16850
17202
|
return true;
|
|
16851
17203
|
}
|
|
16852
17204
|
}
|
|
@@ -16884,6 +17236,10 @@ function createTools(configOptions) {
|
|
|
16884
17236
|
if (configOptions.enableBash) {
|
|
16885
17237
|
tools2.bashTool = bashTool(configOptions);
|
|
16886
17238
|
}
|
|
17239
|
+
if (configOptions.allowEdit) {
|
|
17240
|
+
tools2.editTool = editTool(configOptions);
|
|
17241
|
+
tools2.createTool = createTool(configOptions);
|
|
17242
|
+
}
|
|
16887
17243
|
return tools2;
|
|
16888
17244
|
}
|
|
16889
17245
|
function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
@@ -16984,7 +17340,7 @@ function createMockProvider() {
|
|
|
16984
17340
|
provider: "mock",
|
|
16985
17341
|
// Mock the doGenerate method used by Vercel AI SDK
|
|
16986
17342
|
doGenerate: async ({ messages, tools: tools2 }) => {
|
|
16987
|
-
await new Promise((
|
|
17343
|
+
await new Promise((resolve6) => setTimeout(resolve6, 10));
|
|
16988
17344
|
return {
|
|
16989
17345
|
text: "This is a mock response for testing",
|
|
16990
17346
|
toolCalls: [],
|
|
@@ -28971,16 +29327,6 @@ var init_parser2 = __esm({
|
|
|
28971
29327
|
this.subgraph = this.RULE("subgraph", () => {
|
|
28972
29328
|
this.CONSUME(SubgraphKeyword);
|
|
28973
29329
|
this.OR([
|
|
28974
|
-
{
|
|
28975
|
-
ALT: () => {
|
|
28976
|
-
this.CONSUME(Identifier, { LABEL: "subgraphId" });
|
|
28977
|
-
this.OPTION(() => {
|
|
28978
|
-
this.CONSUME1(SquareOpen);
|
|
28979
|
-
this.SUBRULE(this.nodeContent);
|
|
28980
|
-
this.CONSUME1(SquareClose);
|
|
28981
|
-
});
|
|
28982
|
-
}
|
|
28983
|
-
},
|
|
28984
29330
|
{
|
|
28985
29331
|
ALT: () => {
|
|
28986
29332
|
this.CONSUME(QuotedString, { LABEL: "subgraphTitleQ" });
|
|
@@ -28992,6 +29338,33 @@ var init_parser2 = __esm({
|
|
|
28992
29338
|
this.SUBRULE2(this.nodeContent);
|
|
28993
29339
|
this.CONSUME2(SquareClose);
|
|
28994
29340
|
}
|
|
29341
|
+
},
|
|
29342
|
+
{
|
|
29343
|
+
ALT: () => {
|
|
29344
|
+
this.CONSUME1(Identifier, { LABEL: "subgraphIdOrFirstWord" });
|
|
29345
|
+
this.OPTION(() => {
|
|
29346
|
+
this.OR1([
|
|
29347
|
+
{
|
|
29348
|
+
ALT: () => {
|
|
29349
|
+
this.CONSUME1(SquareOpen);
|
|
29350
|
+
this.SUBRULE(this.nodeContent);
|
|
29351
|
+
this.CONSUME1(SquareClose);
|
|
29352
|
+
}
|
|
29353
|
+
},
|
|
29354
|
+
{
|
|
29355
|
+
ALT: () => {
|
|
29356
|
+
this.AT_LEAST_ONE(() => {
|
|
29357
|
+
this.OR2([
|
|
29358
|
+
{ ALT: () => this.CONSUME2(Identifier) },
|
|
29359
|
+
{ ALT: () => this.CONSUME(Text) },
|
|
29360
|
+
{ ALT: () => this.CONSUME(NumberLiteral) }
|
|
29361
|
+
]);
|
|
29362
|
+
});
|
|
29363
|
+
}
|
|
29364
|
+
}
|
|
29365
|
+
]);
|
|
29366
|
+
});
|
|
29367
|
+
}
|
|
28995
29368
|
}
|
|
28996
29369
|
]);
|
|
28997
29370
|
this.CONSUME(Newline);
|
|
@@ -29595,7 +29968,6 @@ var init_semantics = __esm({
|
|
|
29595
29968
|
const last2 = allChildren[allChildren.length - 1];
|
|
29596
29969
|
const isSlash = (t) => t.image === "/" || t.image === "\\";
|
|
29597
29970
|
if (isSlash(first2) && isSlash(last2)) {
|
|
29598
|
-
continue;
|
|
29599
29971
|
}
|
|
29600
29972
|
}
|
|
29601
29973
|
const opens = ch.RoundOpen || [];
|
|
@@ -30389,16 +30761,19 @@ function mapFlowchartParserError(err, text) {
|
|
|
30389
30761
|
const subgraphIdx = lineStr.indexOf("subgraph");
|
|
30390
30762
|
if (subgraphIdx !== -1) {
|
|
30391
30763
|
const afterSubgraph = lineStr.slice(subgraphIdx + 8).trim();
|
|
30392
|
-
if (afterSubgraph && !afterSubgraph.startsWith('"') && !afterSubgraph.startsWith("'")
|
|
30393
|
-
|
|
30394
|
-
|
|
30395
|
-
|
|
30396
|
-
|
|
30397
|
-
|
|
30398
|
-
|
|
30399
|
-
|
|
30400
|
-
|
|
30401
|
-
|
|
30764
|
+
if (afterSubgraph && !afterSubgraph.startsWith('"') && !afterSubgraph.startsWith("'")) {
|
|
30765
|
+
const hasHazard = /[\[\](){}/:|"'\\]/.test(afterSubgraph);
|
|
30766
|
+
if (hasHazard) {
|
|
30767
|
+
return {
|
|
30768
|
+
line,
|
|
30769
|
+
column,
|
|
30770
|
+
severity: "error",
|
|
30771
|
+
code: "FL-SUBGRAPH-UNQUOTED-TITLE",
|
|
30772
|
+
message: "Subgraph title contains special characters; wrap it in quotes.",
|
|
30773
|
+
hint: 'Example: subgraph "Streams (inside Gateway)"',
|
|
30774
|
+
length: afterSubgraph.length
|
|
30775
|
+
};
|
|
30776
|
+
}
|
|
30402
30777
|
}
|
|
30403
30778
|
}
|
|
30404
30779
|
}
|
|
@@ -31096,11 +31471,11 @@ function validateFlowchart(text, options = {}) {
|
|
|
31096
31471
|
const byLine = /* @__PURE__ */ new Map();
|
|
31097
31472
|
const collect = (arr) => {
|
|
31098
31473
|
for (const e of arr || []) {
|
|
31099
|
-
if (e && e.code === "FL-LABEL-PARENS-UNQUOTED") {
|
|
31474
|
+
if (e && (e.code === "FL-LABEL-PARENS-UNQUOTED" || e.code === "FL-LABEL-AT-IN-UNQUOTED")) {
|
|
31100
31475
|
const ln = e.line ?? 0;
|
|
31101
31476
|
const col = e.column ?? 1;
|
|
31102
31477
|
const list = byLine.get(ln) || [];
|
|
31103
|
-
list.push(col);
|
|
31478
|
+
list.push({ start: col, end: col });
|
|
31104
31479
|
byLine.set(ln, list);
|
|
31105
31480
|
}
|
|
31106
31481
|
}
|
|
@@ -31109,33 +31484,91 @@ function validateFlowchart(text, options = {}) {
|
|
|
31109
31484
|
collect(errs);
|
|
31110
31485
|
const lines2 = text2.split(/\r?\n/);
|
|
31111
31486
|
for (let ii = 0; ii < lines2.length; ii++) {
|
|
31112
|
-
const
|
|
31113
|
-
if (!
|
|
31487
|
+
const raw = lines2[ii] || "";
|
|
31488
|
+
if (!raw.includes("[") || !raw.includes("]"))
|
|
31114
31489
|
continue;
|
|
31115
|
-
let
|
|
31116
|
-
|
|
31117
|
-
|
|
31118
|
-
|
|
31119
|
-
|
|
31120
|
-
const
|
|
31121
|
-
if (
|
|
31122
|
-
|
|
31123
|
-
|
|
31124
|
-
|
|
31125
|
-
|
|
31126
|
-
|
|
31127
|
-
|
|
31128
|
-
|
|
31129
|
-
|
|
31130
|
-
|
|
31131
|
-
|
|
31132
|
-
|
|
31133
|
-
|
|
31134
|
-
|
|
31135
|
-
|
|
31136
|
-
|
|
31490
|
+
let i = 0;
|
|
31491
|
+
const n = raw.length;
|
|
31492
|
+
let inQuote = false;
|
|
31493
|
+
let esc = false;
|
|
31494
|
+
while (i < n) {
|
|
31495
|
+
const ch = raw[i];
|
|
31496
|
+
if (inQuote) {
|
|
31497
|
+
if (esc) {
|
|
31498
|
+
esc = false;
|
|
31499
|
+
} else if (ch === "\\") {
|
|
31500
|
+
esc = true;
|
|
31501
|
+
} else if (ch === '"') {
|
|
31502
|
+
inQuote = false;
|
|
31503
|
+
}
|
|
31504
|
+
i++;
|
|
31505
|
+
continue;
|
|
31506
|
+
}
|
|
31507
|
+
if (ch === '"') {
|
|
31508
|
+
inQuote = true;
|
|
31509
|
+
i++;
|
|
31510
|
+
continue;
|
|
31511
|
+
}
|
|
31512
|
+
if (ch === "[") {
|
|
31513
|
+
let j = i + 1;
|
|
31514
|
+
let inQ = false;
|
|
31515
|
+
let esc2 = false;
|
|
31516
|
+
let depth = 1;
|
|
31517
|
+
while (j < n && depth > 0) {
|
|
31518
|
+
const cj = raw[j];
|
|
31519
|
+
if (inQ) {
|
|
31520
|
+
if (esc2) {
|
|
31521
|
+
esc2 = false;
|
|
31522
|
+
} else if (cj === "\\") {
|
|
31523
|
+
esc2 = true;
|
|
31524
|
+
} else if (cj === '"') {
|
|
31525
|
+
inQ = false;
|
|
31526
|
+
}
|
|
31527
|
+
j++;
|
|
31528
|
+
continue;
|
|
31529
|
+
}
|
|
31530
|
+
if (cj === '"') {
|
|
31531
|
+
inQ = true;
|
|
31532
|
+
j++;
|
|
31533
|
+
continue;
|
|
31534
|
+
}
|
|
31535
|
+
if (cj === "[")
|
|
31536
|
+
depth++;
|
|
31537
|
+
else if (cj === "]")
|
|
31538
|
+
depth--;
|
|
31539
|
+
j++;
|
|
31540
|
+
}
|
|
31541
|
+
if (depth === 0) {
|
|
31542
|
+
const startCol = i + 2;
|
|
31543
|
+
const endCol = j;
|
|
31544
|
+
const seg = raw.slice(i + 1, j - 1);
|
|
31545
|
+
const trimmed = seg.trim();
|
|
31546
|
+
const ln = ii + 1;
|
|
31547
|
+
const lsp = trimmed.slice(0, 1), rsp = trimmed.slice(-1);
|
|
31548
|
+
const isSlashPair = (lsp === "/" || lsp === "\\") && (rsp === "/" || rsp === "\\");
|
|
31549
|
+
const isParenWrapped = lsp === "(" && rsp === ")";
|
|
31550
|
+
const isQuoted = /^"[\s\S]*"$/.test(trimmed);
|
|
31551
|
+
const existing = byLine.get(ln) || [];
|
|
31552
|
+
const covered = existing.some((r) => !(endCol < r.start || startCol > r.end));
|
|
31553
|
+
const hasParens = seg.includes("(") || seg.includes(")");
|
|
31554
|
+
const hasAt = seg.includes("@");
|
|
31555
|
+
if (!covered && !isQuoted && !isParenWrapped && hasParens) {
|
|
31556
|
+
errs.push({ line: ln, column: startCol, severity: "error", code: "FL-LABEL-PARENS-UNQUOTED", message: "Parentheses inside an unquoted label are not supported by Mermaid.", hint: 'Wrap the label in quotes, e.g., A["Mark (X)"] \u2014 or replace ( and ) with HTML entities: ( and ).' });
|
|
31557
|
+
existing.push({ start: startCol, end: endCol });
|
|
31558
|
+
byLine.set(ln, existing);
|
|
31559
|
+
}
|
|
31560
|
+
if (!covered && !isQuoted && !isSlashPair && hasAt) {
|
|
31561
|
+
errs.push({ line: ln, column: startCol, severity: "error", code: "FL-LABEL-AT-IN-UNQUOTED", message: "'@' inside an unquoted label can be misparsed by Mermaid.", hint: 'Wrap the label in quotes, e.g., B["@probelabs/probe v0.6.0-rc149"]' });
|
|
31562
|
+
existing.push({ start: startCol, end: endCol });
|
|
31563
|
+
byLine.set(ln, existing);
|
|
31564
|
+
}
|
|
31565
|
+
i = j;
|
|
31566
|
+
continue;
|
|
31567
|
+
} else {
|
|
31568
|
+
break;
|
|
31569
|
+
}
|
|
31137
31570
|
}
|
|
31138
|
-
|
|
31571
|
+
i++;
|
|
31139
31572
|
}
|
|
31140
31573
|
}
|
|
31141
31574
|
}
|
|
@@ -42621,7 +43054,7 @@ var require_bk = __commonJS({
|
|
|
42621
43054
|
return xs;
|
|
42622
43055
|
}
|
|
42623
43056
|
function buildBlockGraph(g, layering, root2, reverseSep) {
|
|
42624
|
-
var blockGraph = new Graph(), graphLabel = g.graph(), sepFn =
|
|
43057
|
+
var blockGraph = new Graph(), graphLabel = g.graph(), sepFn = sep3(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
|
|
42625
43058
|
_.forEach(layering, function(layer) {
|
|
42626
43059
|
var u;
|
|
42627
43060
|
_.forEach(layer, function(v) {
|
|
@@ -42711,7 +43144,7 @@ var require_bk = __commonJS({
|
|
|
42711
43144
|
alignCoordinates(xss, smallestWidth);
|
|
42712
43145
|
return balance(xss, g.graph().align);
|
|
42713
43146
|
}
|
|
42714
|
-
function
|
|
43147
|
+
function sep3(nodeSep, edgeSep, reverseSep) {
|
|
42715
43148
|
return function(g, v, w) {
|
|
42716
43149
|
var vLabel = g.node(v);
|
|
42717
43150
|
var wLabel = g.node(w);
|
|
@@ -50005,7 +50438,7 @@ var require_compile = __commonJS({
|
|
|
50005
50438
|
const schOrFunc = root2.refs[ref];
|
|
50006
50439
|
if (schOrFunc)
|
|
50007
50440
|
return schOrFunc;
|
|
50008
|
-
let _sch =
|
|
50441
|
+
let _sch = resolve6.call(this, root2, ref);
|
|
50009
50442
|
if (_sch === void 0) {
|
|
50010
50443
|
const schema = (_a = root2.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
50011
50444
|
const { schemaId } = this.opts;
|
|
@@ -50032,7 +50465,7 @@ var require_compile = __commonJS({
|
|
|
50032
50465
|
function sameSchemaEnv(s1, s2) {
|
|
50033
50466
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
50034
50467
|
}
|
|
50035
|
-
function
|
|
50468
|
+
function resolve6(root2, ref) {
|
|
50036
50469
|
let sch;
|
|
50037
50470
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
50038
50471
|
ref = sch;
|
|
@@ -50607,7 +51040,7 @@ var require_fast_uri = __commonJS({
|
|
|
50607
51040
|
}
|
|
50608
51041
|
return uri;
|
|
50609
51042
|
}
|
|
50610
|
-
function
|
|
51043
|
+
function resolve6(baseURI, relativeURI, options) {
|
|
50611
51044
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
50612
51045
|
const resolved = resolveComponent(parse6(baseURI, schemelessOptions), parse6(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
50613
51046
|
schemelessOptions.skipEscape = true;
|
|
@@ -50834,7 +51267,7 @@ var require_fast_uri = __commonJS({
|
|
|
50834
51267
|
var fastUri = {
|
|
50835
51268
|
SCHEMES,
|
|
50836
51269
|
normalize: normalize2,
|
|
50837
|
-
resolve:
|
|
51270
|
+
resolve: resolve6,
|
|
50838
51271
|
resolveComponent,
|
|
50839
51272
|
equal,
|
|
50840
51273
|
serialize,
|
|
@@ -54852,15 +55285,15 @@ Provide only the corrected Mermaid diagram within a mermaid code block. Do not a
|
|
|
54852
55285
|
});
|
|
54853
55286
|
|
|
54854
55287
|
// src/agent/mcp/config.js
|
|
54855
|
-
import { readFileSync, existsSync as
|
|
54856
|
-
import { join as join2, dirname as
|
|
55288
|
+
import { readFileSync, existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync } from "fs";
|
|
55289
|
+
import { join as join2, dirname as dirname3 } from "path";
|
|
54857
55290
|
import { homedir } from "os";
|
|
54858
55291
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
54859
55292
|
function loadMCPConfigurationFromPath(configPath) {
|
|
54860
55293
|
if (!configPath) {
|
|
54861
55294
|
throw new Error("Config path is required");
|
|
54862
55295
|
}
|
|
54863
|
-
if (!
|
|
55296
|
+
if (!existsSync4(configPath)) {
|
|
54864
55297
|
throw new Error(`MCP configuration file not found: ${configPath}`);
|
|
54865
55298
|
}
|
|
54866
55299
|
try {
|
|
@@ -54889,7 +55322,7 @@ function loadMCPConfiguration() {
|
|
|
54889
55322
|
].filter(Boolean);
|
|
54890
55323
|
let config = null;
|
|
54891
55324
|
for (const configPath of configPaths) {
|
|
54892
|
-
if (
|
|
55325
|
+
if (existsSync4(configPath)) {
|
|
54893
55326
|
try {
|
|
54894
55327
|
const content = readFileSync(configPath, "utf8");
|
|
54895
55328
|
config = JSON.parse(content);
|
|
@@ -54992,7 +55425,7 @@ var init_config = __esm({
|
|
|
54992
55425
|
"src/agent/mcp/config.js"() {
|
|
54993
55426
|
"use strict";
|
|
54994
55427
|
__filename4 = fileURLToPath6(import.meta.url);
|
|
54995
|
-
__dirname4 =
|
|
55428
|
+
__dirname4 = dirname3(__filename4);
|
|
54996
55429
|
DEFAULT_CONFIG = {
|
|
54997
55430
|
mcpServers: {
|
|
54998
55431
|
// Example probe server configuration
|
|
@@ -55181,12 +55614,12 @@ var init_client = __esm({
|
|
|
55181
55614
|
const toolsResponse = await client.listTools();
|
|
55182
55615
|
const toolCount = toolsResponse?.tools?.length || 0;
|
|
55183
55616
|
if (toolsResponse && toolsResponse.tools) {
|
|
55184
|
-
for (const
|
|
55185
|
-
const qualifiedName = `${name}_${
|
|
55617
|
+
for (const tool4 of toolsResponse.tools) {
|
|
55618
|
+
const qualifiedName = `${name}_${tool4.name}`;
|
|
55186
55619
|
this.tools.set(qualifiedName, {
|
|
55187
|
-
...
|
|
55620
|
+
...tool4,
|
|
55188
55621
|
serverName: name,
|
|
55189
|
-
originalName:
|
|
55622
|
+
originalName: tool4.name
|
|
55190
55623
|
});
|
|
55191
55624
|
if (this.debug) {
|
|
55192
55625
|
console.error(`[MCP DEBUG] Registered tool: ${qualifiedName}`);
|
|
@@ -55209,13 +55642,13 @@ var init_client = __esm({
|
|
|
55209
55642
|
* @param {Object} args - Tool arguments
|
|
55210
55643
|
*/
|
|
55211
55644
|
async callTool(toolName, args) {
|
|
55212
|
-
const
|
|
55213
|
-
if (!
|
|
55645
|
+
const tool4 = this.tools.get(toolName);
|
|
55646
|
+
if (!tool4) {
|
|
55214
55647
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
55215
55648
|
}
|
|
55216
|
-
const clientInfo = this.clients.get(
|
|
55649
|
+
const clientInfo = this.clients.get(tool4.serverName);
|
|
55217
55650
|
if (!clientInfo) {
|
|
55218
|
-
throw new Error(`Server ${
|
|
55651
|
+
throw new Error(`Server ${tool4.serverName} not connected`);
|
|
55219
55652
|
}
|
|
55220
55653
|
try {
|
|
55221
55654
|
if (this.debug) {
|
|
@@ -55229,7 +55662,7 @@ var init_client = __esm({
|
|
|
55229
55662
|
});
|
|
55230
55663
|
const result = await Promise.race([
|
|
55231
55664
|
clientInfo.client.callTool({
|
|
55232
|
-
name:
|
|
55665
|
+
name: tool4.originalName,
|
|
55233
55666
|
arguments: args
|
|
55234
55667
|
}),
|
|
55235
55668
|
timeoutPromise
|
|
@@ -55252,11 +55685,11 @@ var init_client = __esm({
|
|
|
55252
55685
|
*/
|
|
55253
55686
|
getTools() {
|
|
55254
55687
|
const tools2 = {};
|
|
55255
|
-
for (const [name,
|
|
55688
|
+
for (const [name, tool4] of this.tools.entries()) {
|
|
55256
55689
|
tools2[name] = {
|
|
55257
|
-
description:
|
|
55258
|
-
inputSchema:
|
|
55259
|
-
serverName:
|
|
55690
|
+
description: tool4.description,
|
|
55691
|
+
inputSchema: tool4.inputSchema,
|
|
55692
|
+
serverName: tool4.serverName
|
|
55260
55693
|
};
|
|
55261
55694
|
}
|
|
55262
55695
|
return tools2;
|
|
@@ -55267,10 +55700,10 @@ var init_client = __esm({
|
|
|
55267
55700
|
*/
|
|
55268
55701
|
getVercelTools() {
|
|
55269
55702
|
const tools2 = {};
|
|
55270
|
-
for (const [name,
|
|
55703
|
+
for (const [name, tool4] of this.tools.entries()) {
|
|
55271
55704
|
tools2[name] = {
|
|
55272
|
-
description:
|
|
55273
|
-
inputSchema:
|
|
55705
|
+
description: tool4.description,
|
|
55706
|
+
inputSchema: tool4.inputSchema,
|
|
55274
55707
|
execute: async (args) => {
|
|
55275
55708
|
const result = await this.callTool(name, args);
|
|
55276
55709
|
if (result.content && result.content[0]) {
|
|
@@ -55319,9 +55752,9 @@ var init_client = __esm({
|
|
|
55319
55752
|
});
|
|
55320
55753
|
|
|
55321
55754
|
// src/agent/mcp/xmlBridge.js
|
|
55322
|
-
function mcpToolToXmlDefinition(name,
|
|
55323
|
-
const description =
|
|
55324
|
-
const inputSchema =
|
|
55755
|
+
function mcpToolToXmlDefinition(name, tool4) {
|
|
55756
|
+
const description = tool4.description || "MCP tool";
|
|
55757
|
+
const inputSchema = tool4.inputSchema || tool4.parameters || {};
|
|
55325
55758
|
let paramDocs = "";
|
|
55326
55759
|
if (inputSchema.properties) {
|
|
55327
55760
|
paramDocs = "\n\nParameters (provide as JSON object):";
|
|
@@ -55500,8 +55933,8 @@ var init_xmlBridge = __esm({
|
|
|
55500
55933
|
const vercelTools = this.mcpManager.getVercelTools();
|
|
55501
55934
|
this.mcpTools = vercelTools;
|
|
55502
55935
|
const toolCount = Object.keys(vercelTools).length;
|
|
55503
|
-
for (const [name,
|
|
55504
|
-
this.xmlDefinitions[name] = mcpToolToXmlDefinition(name,
|
|
55936
|
+
for (const [name, tool4] of Object.entries(vercelTools)) {
|
|
55937
|
+
this.xmlDefinitions[name] = mcpToolToXmlDefinition(name, tool4);
|
|
55505
55938
|
}
|
|
55506
55939
|
if (toolCount === 0) {
|
|
55507
55940
|
console.error("[MCP INFO] MCP initialization complete: 0 tools loaded");
|
|
@@ -55548,14 +55981,14 @@ var init_xmlBridge = __esm({
|
|
|
55548
55981
|
console.error(`[MCP DEBUG] Executing MCP tool: ${toolName}`);
|
|
55549
55982
|
console.error(`[MCP DEBUG] Parameters:`, JSON.stringify(params, null, 2));
|
|
55550
55983
|
}
|
|
55551
|
-
const
|
|
55552
|
-
if (!
|
|
55984
|
+
const tool4 = this.mcpTools[toolName];
|
|
55985
|
+
if (!tool4) {
|
|
55553
55986
|
console.error(`[MCP ERROR] Unknown MCP tool: ${toolName}`);
|
|
55554
55987
|
console.error(`[MCP ERROR] Available tools: ${this.getToolNames().join(", ")}`);
|
|
55555
55988
|
throw new Error(`Unknown MCP tool: ${toolName}`);
|
|
55556
55989
|
}
|
|
55557
55990
|
try {
|
|
55558
|
-
const result = await
|
|
55991
|
+
const result = await tool4.execute(params);
|
|
55559
55992
|
if (this.debug) {
|
|
55560
55993
|
console.error(`[MCP DEBUG] Tool ${toolName} executed successfully`);
|
|
55561
55994
|
}
|
|
@@ -55609,22 +56042,636 @@ var init_mcp = __esm({
|
|
|
55609
56042
|
}
|
|
55610
56043
|
});
|
|
55611
56044
|
|
|
56045
|
+
// src/agent/RetryManager.js
|
|
56046
|
+
function isRetryableError(error, retryableErrors = DEFAULT_RETRYABLE_ERRORS) {
|
|
56047
|
+
if (!error) return false;
|
|
56048
|
+
const errorString = error.toString().toLowerCase();
|
|
56049
|
+
const errorMessage = (error.message || "").toLowerCase();
|
|
56050
|
+
const errorCode = (error.code || "").toLowerCase();
|
|
56051
|
+
const errorType = (error.type || "").toLowerCase();
|
|
56052
|
+
const statusCode = error.statusCode || error.status;
|
|
56053
|
+
for (const pattern of retryableErrors) {
|
|
56054
|
+
const lowerPattern = pattern.toLowerCase();
|
|
56055
|
+
if (errorString.includes(lowerPattern) || errorMessage.includes(lowerPattern) || errorCode.includes(lowerPattern) || errorType.includes(lowerPattern) || statusCode?.toString() === pattern) {
|
|
56056
|
+
return true;
|
|
56057
|
+
}
|
|
56058
|
+
}
|
|
56059
|
+
return false;
|
|
56060
|
+
}
|
|
56061
|
+
function extractErrorInfo(error) {
|
|
56062
|
+
return {
|
|
56063
|
+
message: error.message || error.toString(),
|
|
56064
|
+
type: error.type || error.constructor.name,
|
|
56065
|
+
code: error.code,
|
|
56066
|
+
statusCode: error.statusCode || error.status,
|
|
56067
|
+
provider: error.provider,
|
|
56068
|
+
isRetryable: isRetryableError(error)
|
|
56069
|
+
};
|
|
56070
|
+
}
|
|
56071
|
+
function sleep(ms) {
|
|
56072
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
56073
|
+
}
|
|
56074
|
+
var DEFAULT_RETRYABLE_ERRORS, RetryManager;
|
|
56075
|
+
var init_RetryManager = __esm({
|
|
56076
|
+
"src/agent/RetryManager.js"() {
|
|
56077
|
+
"use strict";
|
|
56078
|
+
DEFAULT_RETRYABLE_ERRORS = [
|
|
56079
|
+
"Overloaded",
|
|
56080
|
+
"overloaded",
|
|
56081
|
+
"rate_limit",
|
|
56082
|
+
"rate limit",
|
|
56083
|
+
"429",
|
|
56084
|
+
"500",
|
|
56085
|
+
"502",
|
|
56086
|
+
"503",
|
|
56087
|
+
"504",
|
|
56088
|
+
"timeout",
|
|
56089
|
+
"ECONNRESET",
|
|
56090
|
+
"ETIMEDOUT",
|
|
56091
|
+
"ENOTFOUND",
|
|
56092
|
+
"api_error"
|
|
56093
|
+
];
|
|
56094
|
+
RetryManager = class {
|
|
56095
|
+
/**
|
|
56096
|
+
* Create a new RetryManager
|
|
56097
|
+
* @param {Object} options - Configuration options
|
|
56098
|
+
* @param {number} [options.maxRetries=3] - Maximum retry attempts
|
|
56099
|
+
* @param {number} [options.initialDelay=1000] - Initial delay in ms (1 second)
|
|
56100
|
+
* @param {number} [options.maxDelay=30000] - Maximum delay in ms (30 seconds)
|
|
56101
|
+
* @param {number} [options.backoffFactor=2] - Exponential backoff multiplier
|
|
56102
|
+
* @param {Array<string>} [options.retryableErrors] - List of retryable error patterns
|
|
56103
|
+
* @param {boolean} [options.debug=false] - Enable debug logging
|
|
56104
|
+
*/
|
|
56105
|
+
constructor(options = {}) {
|
|
56106
|
+
this.maxRetries = this._validateNumber(options.maxRetries, 3, "maxRetries", 0, 100);
|
|
56107
|
+
this.initialDelay = this._validateNumber(options.initialDelay, 1e3, "initialDelay", 0, 6e4);
|
|
56108
|
+
this.maxDelay = this._validateNumber(options.maxDelay, 3e4, "maxDelay", 0, 3e5);
|
|
56109
|
+
this.backoffFactor = this._validateNumber(options.backoffFactor, 2, "backoffFactor", 1, 10);
|
|
56110
|
+
this.retryableErrors = options.retryableErrors || DEFAULT_RETRYABLE_ERRORS;
|
|
56111
|
+
this.debug = options.debug ?? false;
|
|
56112
|
+
this.jitter = options.jitter ?? true;
|
|
56113
|
+
if (this.maxDelay < this.initialDelay) {
|
|
56114
|
+
throw new Error("maxDelay must be greater than or equal to initialDelay");
|
|
56115
|
+
}
|
|
56116
|
+
this.stats = {
|
|
56117
|
+
totalAttempts: 0,
|
|
56118
|
+
totalRetries: 0,
|
|
56119
|
+
successfulRetries: 0,
|
|
56120
|
+
failedRetries: 0
|
|
56121
|
+
};
|
|
56122
|
+
}
|
|
56123
|
+
/**
|
|
56124
|
+
* Validate a numeric parameter
|
|
56125
|
+
* @param {*} value - Value to validate
|
|
56126
|
+
* @param {number} defaultValue - Default if undefined
|
|
56127
|
+
* @param {string} name - Parameter name for error messages
|
|
56128
|
+
* @param {number} min - Minimum allowed value
|
|
56129
|
+
* @param {number} max - Maximum allowed value
|
|
56130
|
+
* @returns {number} - Validated number
|
|
56131
|
+
* @private
|
|
56132
|
+
*/
|
|
56133
|
+
_validateNumber(value, defaultValue, name, min, max) {
|
|
56134
|
+
if (value === void 0 || value === null) {
|
|
56135
|
+
return defaultValue;
|
|
56136
|
+
}
|
|
56137
|
+
const num = Number(value);
|
|
56138
|
+
if (isNaN(num)) {
|
|
56139
|
+
throw new Error(`${name} must be a number, got: ${value}`);
|
|
56140
|
+
}
|
|
56141
|
+
if (num < min || num > max) {
|
|
56142
|
+
throw new Error(`${name} must be between ${min} and ${max}, got: ${num}`);
|
|
56143
|
+
}
|
|
56144
|
+
return num;
|
|
56145
|
+
}
|
|
56146
|
+
/**
|
|
56147
|
+
* Execute a function with retry logic
|
|
56148
|
+
* @param {Function} fn - Async function to execute
|
|
56149
|
+
* @param {Object} [context={}] - Context information for logging
|
|
56150
|
+
* @param {AbortSignal} [context.signal] - Optional abort signal for cancellation
|
|
56151
|
+
* @returns {Promise<*>} - Result from the function
|
|
56152
|
+
* @throws {Error} - If all retries are exhausted or operation is aborted
|
|
56153
|
+
*/
|
|
56154
|
+
async executeWithRetry(fn, context = {}) {
|
|
56155
|
+
let lastError = null;
|
|
56156
|
+
let currentDelay = this.initialDelay;
|
|
56157
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
56158
|
+
if (context.signal?.aborted) {
|
|
56159
|
+
const abortError = new Error("Operation aborted");
|
|
56160
|
+
abortError.name = "AbortError";
|
|
56161
|
+
throw abortError;
|
|
56162
|
+
}
|
|
56163
|
+
this.stats.totalAttempts++;
|
|
56164
|
+
try {
|
|
56165
|
+
if (this.debug && attempt > 0) {
|
|
56166
|
+
console.log(`[RetryManager] Retry attempt ${attempt}/${this.maxRetries}`, context);
|
|
56167
|
+
}
|
|
56168
|
+
const result = await fn();
|
|
56169
|
+
if (attempt > 0) {
|
|
56170
|
+
this.stats.successfulRetries++;
|
|
56171
|
+
if (this.debug) {
|
|
56172
|
+
console.log(`[RetryManager] \u2705 Retry successful on attempt ${attempt + 1}`, context);
|
|
56173
|
+
}
|
|
56174
|
+
}
|
|
56175
|
+
return result;
|
|
56176
|
+
} catch (error) {
|
|
56177
|
+
lastError = error;
|
|
56178
|
+
const errorInfo = extractErrorInfo(error);
|
|
56179
|
+
const shouldRetry = isRetryableError(error, this.retryableErrors);
|
|
56180
|
+
const hasRetriesLeft = attempt < this.maxRetries;
|
|
56181
|
+
if (this.debug) {
|
|
56182
|
+
console.log(`[RetryManager] \u274C Attempt ${attempt + 1}/${this.maxRetries + 1} failed:`, {
|
|
56183
|
+
...context,
|
|
56184
|
+
error: errorInfo,
|
|
56185
|
+
shouldRetry,
|
|
56186
|
+
hasRetriesLeft
|
|
56187
|
+
});
|
|
56188
|
+
}
|
|
56189
|
+
if (!shouldRetry) {
|
|
56190
|
+
if (this.debug) {
|
|
56191
|
+
console.log(`[RetryManager] Error is not retryable, failing immediately`, errorInfo);
|
|
56192
|
+
}
|
|
56193
|
+
throw error;
|
|
56194
|
+
}
|
|
56195
|
+
if (!hasRetriesLeft) {
|
|
56196
|
+
this.stats.failedRetries++;
|
|
56197
|
+
if (this.debug) {
|
|
56198
|
+
console.log(`[RetryManager] Max retries (${this.maxRetries}) exhausted`, context);
|
|
56199
|
+
}
|
|
56200
|
+
throw error;
|
|
56201
|
+
}
|
|
56202
|
+
this.stats.totalRetries++;
|
|
56203
|
+
let delayWithJitter = currentDelay;
|
|
56204
|
+
if (this.jitter) {
|
|
56205
|
+
const jitterAmount = currentDelay * 0.25;
|
|
56206
|
+
delayWithJitter = currentDelay + (Math.random() * jitterAmount * 2 - jitterAmount);
|
|
56207
|
+
}
|
|
56208
|
+
if (this.debug) {
|
|
56209
|
+
console.log(`[RetryManager] Waiting ${Math.round(delayWithJitter)}ms before retry...`);
|
|
56210
|
+
}
|
|
56211
|
+
await sleep(delayWithJitter);
|
|
56212
|
+
currentDelay = Math.min(currentDelay * this.backoffFactor, this.maxDelay);
|
|
56213
|
+
}
|
|
56214
|
+
}
|
|
56215
|
+
throw lastError;
|
|
56216
|
+
}
|
|
56217
|
+
/**
|
|
56218
|
+
* Check if an error is retryable
|
|
56219
|
+
* @param {Error} error - The error to check
|
|
56220
|
+
* @returns {boolean} - True if error should be retried
|
|
56221
|
+
*/
|
|
56222
|
+
isRetryable(error) {
|
|
56223
|
+
return isRetryableError(error, this.retryableErrors);
|
|
56224
|
+
}
|
|
56225
|
+
/**
|
|
56226
|
+
* Get retry statistics
|
|
56227
|
+
* @returns {Object} - Statistics object
|
|
56228
|
+
*/
|
|
56229
|
+
getStats() {
|
|
56230
|
+
return { ...this.stats };
|
|
56231
|
+
}
|
|
56232
|
+
/**
|
|
56233
|
+
* Reset statistics
|
|
56234
|
+
*/
|
|
56235
|
+
resetStats() {
|
|
56236
|
+
this.stats = {
|
|
56237
|
+
totalAttempts: 0,
|
|
56238
|
+
totalRetries: 0,
|
|
56239
|
+
successfulRetries: 0,
|
|
56240
|
+
failedRetries: 0
|
|
56241
|
+
};
|
|
56242
|
+
}
|
|
56243
|
+
};
|
|
56244
|
+
}
|
|
56245
|
+
});
|
|
56246
|
+
|
|
56247
|
+
// src/agent/FallbackManager.js
|
|
56248
|
+
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
56249
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
56250
|
+
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
56251
|
+
import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock";
|
|
56252
|
+
function createFallbackManagerFromEnv(debug = false) {
|
|
56253
|
+
const fallbackProvidersEnv = process.env.FALLBACK_PROVIDERS;
|
|
56254
|
+
const fallbackModelsEnv = process.env.FALLBACK_MODELS;
|
|
56255
|
+
if (!fallbackProvidersEnv && !fallbackModelsEnv) {
|
|
56256
|
+
return null;
|
|
56257
|
+
}
|
|
56258
|
+
let providers = [];
|
|
56259
|
+
let models = [];
|
|
56260
|
+
let strategy = FALLBACK_STRATEGIES.ANY;
|
|
56261
|
+
if (fallbackProvidersEnv) {
|
|
56262
|
+
try {
|
|
56263
|
+
if (typeof fallbackProvidersEnv !== "string" || fallbackProvidersEnv.length > 1e4) {
|
|
56264
|
+
console.error("[FallbackManager] FALLBACK_PROVIDERS must be a valid JSON string under 10KB");
|
|
56265
|
+
return null;
|
|
56266
|
+
}
|
|
56267
|
+
const parsed = JSON.parse(fallbackProvidersEnv);
|
|
56268
|
+
if (!Array.isArray(parsed)) {
|
|
56269
|
+
console.error("[FallbackManager] FALLBACK_PROVIDERS must be a JSON array");
|
|
56270
|
+
return null;
|
|
56271
|
+
}
|
|
56272
|
+
providers = parsed;
|
|
56273
|
+
strategy = FALLBACK_STRATEGIES.CUSTOM;
|
|
56274
|
+
} catch (error) {
|
|
56275
|
+
console.error("[FallbackManager] Failed to parse FALLBACK_PROVIDERS:", error.message);
|
|
56276
|
+
return null;
|
|
56277
|
+
}
|
|
56278
|
+
}
|
|
56279
|
+
if (fallbackModelsEnv) {
|
|
56280
|
+
try {
|
|
56281
|
+
if (typeof fallbackModelsEnv !== "string" || fallbackModelsEnv.length > 1e4) {
|
|
56282
|
+
console.error("[FallbackManager] FALLBACK_MODELS must be a valid JSON string under 10KB");
|
|
56283
|
+
return null;
|
|
56284
|
+
}
|
|
56285
|
+
const parsed = JSON.parse(fallbackModelsEnv);
|
|
56286
|
+
if (!Array.isArray(parsed)) {
|
|
56287
|
+
console.error("[FallbackManager] FALLBACK_MODELS must be a JSON array");
|
|
56288
|
+
return null;
|
|
56289
|
+
}
|
|
56290
|
+
models = parsed;
|
|
56291
|
+
strategy = FALLBACK_STRATEGIES.SAME_PROVIDER;
|
|
56292
|
+
} catch (error) {
|
|
56293
|
+
console.error("[FallbackManager] Failed to parse FALLBACK_MODELS:", error.message);
|
|
56294
|
+
return null;
|
|
56295
|
+
}
|
|
56296
|
+
}
|
|
56297
|
+
const maxTotalAttempts = process.env.FALLBACK_MAX_TOTAL_ATTEMPTS ? (() => {
|
|
56298
|
+
const val = parseInt(process.env.FALLBACK_MAX_TOTAL_ATTEMPTS, 10);
|
|
56299
|
+
if (isNaN(val) || val < 1 || val > 100) {
|
|
56300
|
+
console.warn("[FallbackManager] FALLBACK_MAX_TOTAL_ATTEMPTS must be between 1 and 100, using default: 10");
|
|
56301
|
+
return 10;
|
|
56302
|
+
}
|
|
56303
|
+
return val;
|
|
56304
|
+
})() : 10;
|
|
56305
|
+
return new FallbackManager({
|
|
56306
|
+
strategy,
|
|
56307
|
+
providers,
|
|
56308
|
+
models,
|
|
56309
|
+
maxTotalAttempts,
|
|
56310
|
+
debug
|
|
56311
|
+
});
|
|
56312
|
+
}
|
|
56313
|
+
function buildFallbackProvidersFromEnv(options = {}) {
|
|
56314
|
+
const providers = [];
|
|
56315
|
+
const anthropicApiKey = process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN;
|
|
56316
|
+
const openaiApiKey = process.env.OPENAI_API_KEY;
|
|
56317
|
+
const googleApiKey = process.env.GOOGLE_GENERATIVE_AI_API_KEY || process.env.GOOGLE_API_KEY;
|
|
56318
|
+
const awsAccessKeyId = process.env.AWS_ACCESS_KEY_ID;
|
|
56319
|
+
const awsSecretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
|
|
56320
|
+
const awsRegion = process.env.AWS_REGION;
|
|
56321
|
+
const awsApiKey = process.env.AWS_BEDROCK_API_KEY;
|
|
56322
|
+
const llmBaseUrl = process.env.LLM_BASE_URL;
|
|
56323
|
+
const anthropicApiUrl = process.env.ANTHROPIC_API_URL || process.env.ANTHROPIC_BASE_URL || llmBaseUrl;
|
|
56324
|
+
const openaiApiUrl = process.env.OPENAI_API_URL || llmBaseUrl;
|
|
56325
|
+
const googleApiUrl = process.env.GOOGLE_API_URL || llmBaseUrl;
|
|
56326
|
+
const awsBedrockBaseUrl = process.env.AWS_BEDROCK_BASE_URL || llmBaseUrl;
|
|
56327
|
+
const primaryProvider = options.primaryProvider?.toLowerCase();
|
|
56328
|
+
const primaryModel = options.primaryModel;
|
|
56329
|
+
if (primaryProvider === "anthropic" && anthropicApiKey) {
|
|
56330
|
+
providers.push({
|
|
56331
|
+
provider: "anthropic",
|
|
56332
|
+
apiKey: anthropicApiKey,
|
|
56333
|
+
...anthropicApiUrl && { baseURL: anthropicApiUrl },
|
|
56334
|
+
...primaryModel && { model: primaryModel }
|
|
56335
|
+
});
|
|
56336
|
+
} else if (primaryProvider === "openai" && openaiApiKey) {
|
|
56337
|
+
providers.push({
|
|
56338
|
+
provider: "openai",
|
|
56339
|
+
apiKey: openaiApiKey,
|
|
56340
|
+
...openaiApiUrl && { baseURL: openaiApiUrl },
|
|
56341
|
+
...primaryModel && { model: primaryModel }
|
|
56342
|
+
});
|
|
56343
|
+
} else if (primaryProvider === "google" && googleApiKey) {
|
|
56344
|
+
providers.push({
|
|
56345
|
+
provider: "google",
|
|
56346
|
+
apiKey: googleApiKey,
|
|
56347
|
+
...googleApiUrl && { baseURL: googleApiUrl },
|
|
56348
|
+
...primaryModel && { model: primaryModel }
|
|
56349
|
+
});
|
|
56350
|
+
} else if (primaryProvider === "bedrock" && (awsAccessKeyId && awsSecretAccessKey && awsRegion || awsApiKey)) {
|
|
56351
|
+
const config = { provider: "bedrock" };
|
|
56352
|
+
if (awsApiKey) {
|
|
56353
|
+
config.apiKey = awsApiKey;
|
|
56354
|
+
} else {
|
|
56355
|
+
config.accessKeyId = awsAccessKeyId;
|
|
56356
|
+
config.secretAccessKey = awsSecretAccessKey;
|
|
56357
|
+
config.region = awsRegion;
|
|
56358
|
+
if (process.env.AWS_SESSION_TOKEN) {
|
|
56359
|
+
config.sessionToken = process.env.AWS_SESSION_TOKEN;
|
|
56360
|
+
}
|
|
56361
|
+
}
|
|
56362
|
+
if (awsBedrockBaseUrl) config.baseURL = awsBedrockBaseUrl;
|
|
56363
|
+
if (primaryModel) config.model = primaryModel;
|
|
56364
|
+
providers.push(config);
|
|
56365
|
+
}
|
|
56366
|
+
if (anthropicApiKey && primaryProvider !== "anthropic") {
|
|
56367
|
+
providers.push({
|
|
56368
|
+
provider: "anthropic",
|
|
56369
|
+
apiKey: anthropicApiKey,
|
|
56370
|
+
...anthropicApiUrl && { baseURL: anthropicApiUrl }
|
|
56371
|
+
});
|
|
56372
|
+
}
|
|
56373
|
+
if (openaiApiKey && primaryProvider !== "openai") {
|
|
56374
|
+
providers.push({
|
|
56375
|
+
provider: "openai",
|
|
56376
|
+
apiKey: openaiApiKey,
|
|
56377
|
+
...openaiApiUrl && { baseURL: openaiApiUrl }
|
|
56378
|
+
});
|
|
56379
|
+
}
|
|
56380
|
+
if (googleApiKey && primaryProvider !== "google") {
|
|
56381
|
+
providers.push({
|
|
56382
|
+
provider: "google",
|
|
56383
|
+
apiKey: googleApiKey,
|
|
56384
|
+
...googleApiUrl && { baseURL: googleApiUrl }
|
|
56385
|
+
});
|
|
56386
|
+
}
|
|
56387
|
+
if ((awsAccessKeyId && awsSecretAccessKey && awsRegion || awsApiKey) && primaryProvider !== "bedrock") {
|
|
56388
|
+
const config = { provider: "bedrock" };
|
|
56389
|
+
if (awsApiKey) {
|
|
56390
|
+
config.apiKey = awsApiKey;
|
|
56391
|
+
} else {
|
|
56392
|
+
config.accessKeyId = awsAccessKeyId;
|
|
56393
|
+
config.secretAccessKey = awsSecretAccessKey;
|
|
56394
|
+
config.region = awsRegion;
|
|
56395
|
+
if (process.env.AWS_SESSION_TOKEN) {
|
|
56396
|
+
config.sessionToken = process.env.AWS_SESSION_TOKEN;
|
|
56397
|
+
}
|
|
56398
|
+
}
|
|
56399
|
+
if (awsBedrockBaseUrl) config.baseURL = awsBedrockBaseUrl;
|
|
56400
|
+
providers.push(config);
|
|
56401
|
+
}
|
|
56402
|
+
return providers;
|
|
56403
|
+
}
|
|
56404
|
+
var FALLBACK_STRATEGIES, DEFAULT_MODELS, FallbackManager;
|
|
56405
|
+
var init_FallbackManager = __esm({
|
|
56406
|
+
"src/agent/FallbackManager.js"() {
|
|
56407
|
+
"use strict";
|
|
56408
|
+
FALLBACK_STRATEGIES = {
|
|
56409
|
+
SAME_MODEL: "same-model",
|
|
56410
|
+
// Try same model on different providers
|
|
56411
|
+
SAME_PROVIDER: "same-provider",
|
|
56412
|
+
// Try different models on same provider
|
|
56413
|
+
ANY: "any",
|
|
56414
|
+
// Try any available provider/model
|
|
56415
|
+
CUSTOM: "custom"
|
|
56416
|
+
// Use custom provider list
|
|
56417
|
+
};
|
|
56418
|
+
DEFAULT_MODELS = {
|
|
56419
|
+
anthropic: "claude-sonnet-4-5-20250929",
|
|
56420
|
+
openai: "gpt-4o",
|
|
56421
|
+
google: "gemini-2.0-flash-exp",
|
|
56422
|
+
bedrock: "anthropic.claude-sonnet-4-20250514-v1:0"
|
|
56423
|
+
};
|
|
56424
|
+
FallbackManager = class {
|
|
56425
|
+
/**
|
|
56426
|
+
* Create a new FallbackManager
|
|
56427
|
+
* @param {Object} options - Configuration options
|
|
56428
|
+
* @param {string} [options.strategy='any'] - Fallback strategy
|
|
56429
|
+
* @param {Array<string>} [options.models] - List of models for same-provider fallback
|
|
56430
|
+
* @param {Array<ProviderConfig>} [options.providers] - List of provider configurations
|
|
56431
|
+
* @param {boolean} [options.stopOnSuccess=true] - Stop on first success
|
|
56432
|
+
* @param {boolean} [options.continueOnNonRetryableError=false] - Continue to fallback on non-retryable errors
|
|
56433
|
+
* @param {number} [options.maxTotalAttempts=10] - Maximum total attempts across all providers
|
|
56434
|
+
* @param {boolean} [options.debug=false] - Enable debug logging
|
|
56435
|
+
*/
|
|
56436
|
+
constructor(options = {}) {
|
|
56437
|
+
this.strategy = options.strategy || FALLBACK_STRATEGIES.ANY;
|
|
56438
|
+
this.models = Array.isArray(options.models) ? options.models : [];
|
|
56439
|
+
this.providers = Array.isArray(options.providers) ? options.providers : [];
|
|
56440
|
+
this.stopOnSuccess = options.stopOnSuccess ?? true;
|
|
56441
|
+
this.continueOnNonRetryableError = options.continueOnNonRetryableError ?? false;
|
|
56442
|
+
this.debug = options.debug ?? false;
|
|
56443
|
+
const maxAttempts = options.maxTotalAttempts ?? 10;
|
|
56444
|
+
if (typeof maxAttempts !== "number" || isNaN(maxAttempts) || maxAttempts < 1 || maxAttempts > 100) {
|
|
56445
|
+
throw new Error(`FallbackManager: maxTotalAttempts must be a number between 1 and 100, got: ${maxAttempts}`);
|
|
56446
|
+
}
|
|
56447
|
+
this.maxTotalAttempts = maxAttempts;
|
|
56448
|
+
this.stats = {
|
|
56449
|
+
totalAttempts: 0,
|
|
56450
|
+
providerAttempts: {},
|
|
56451
|
+
successfulProvider: null,
|
|
56452
|
+
failedProviders: []
|
|
56453
|
+
};
|
|
56454
|
+
this._validateConfiguration();
|
|
56455
|
+
}
|
|
56456
|
+
/**
|
|
56457
|
+
* Validate the fallback configuration
|
|
56458
|
+
* @private
|
|
56459
|
+
*/
|
|
56460
|
+
_validateConfiguration() {
|
|
56461
|
+
if (this.strategy === FALLBACK_STRATEGIES.SAME_PROVIDER && this.models.length === 0) {
|
|
56462
|
+
throw new Error('FallbackManager: strategy "same-provider" requires models list');
|
|
56463
|
+
}
|
|
56464
|
+
if (this.strategy === FALLBACK_STRATEGIES.CUSTOM && this.providers.length === 0) {
|
|
56465
|
+
throw new Error('FallbackManager: strategy "custom" requires providers list');
|
|
56466
|
+
}
|
|
56467
|
+
for (const config of this.providers) {
|
|
56468
|
+
if (!config.provider) {
|
|
56469
|
+
throw new Error('FallbackManager: Each provider config must have a "provider" field');
|
|
56470
|
+
}
|
|
56471
|
+
if (!["anthropic", "openai", "google", "bedrock"].includes(config.provider)) {
|
|
56472
|
+
throw new Error(`FallbackManager: Invalid provider "${config.provider}". Must be: anthropic, openai, google, or bedrock`);
|
|
56473
|
+
}
|
|
56474
|
+
if (config.provider === "bedrock") {
|
|
56475
|
+
const hasCredentials = config.accessKeyId && config.secretAccessKey && config.region;
|
|
56476
|
+
const hasApiKey = config.apiKey;
|
|
56477
|
+
if (!hasCredentials && !hasApiKey) {
|
|
56478
|
+
throw new Error("FallbackManager: Bedrock provider requires either (accessKeyId, secretAccessKey, region) or apiKey");
|
|
56479
|
+
}
|
|
56480
|
+
} else {
|
|
56481
|
+
if (!config.apiKey) {
|
|
56482
|
+
throw new Error(`FallbackManager: Provider "${config.provider}" requires apiKey`);
|
|
56483
|
+
}
|
|
56484
|
+
}
|
|
56485
|
+
}
|
|
56486
|
+
}
|
|
56487
|
+
/**
|
|
56488
|
+
* Create a provider instance from configuration
|
|
56489
|
+
* @param {ProviderConfig} config - Provider configuration
|
|
56490
|
+
* @returns {Object} - Provider instance
|
|
56491
|
+
* @throws {Error} - If provider creation fails
|
|
56492
|
+
* @private
|
|
56493
|
+
*/
|
|
56494
|
+
_createProviderInstance(config) {
|
|
56495
|
+
try {
|
|
56496
|
+
switch (config.provider) {
|
|
56497
|
+
case "anthropic":
|
|
56498
|
+
return createAnthropic({
|
|
56499
|
+
apiKey: config.apiKey,
|
|
56500
|
+
...config.baseURL && { baseURL: config.baseURL }
|
|
56501
|
+
});
|
|
56502
|
+
case "openai":
|
|
56503
|
+
return createOpenAI({
|
|
56504
|
+
compatibility: "strict",
|
|
56505
|
+
apiKey: config.apiKey,
|
|
56506
|
+
...config.baseURL && { baseURL: config.baseURL }
|
|
56507
|
+
});
|
|
56508
|
+
case "google":
|
|
56509
|
+
return createGoogleGenerativeAI({
|
|
56510
|
+
apiKey: config.apiKey,
|
|
56511
|
+
...config.baseURL && { baseURL: config.baseURL }
|
|
56512
|
+
});
|
|
56513
|
+
case "bedrock": {
|
|
56514
|
+
const bedrockConfig = {};
|
|
56515
|
+
if (config.apiKey) {
|
|
56516
|
+
bedrockConfig.apiKey = config.apiKey;
|
|
56517
|
+
} else if (config.accessKeyId && config.secretAccessKey) {
|
|
56518
|
+
bedrockConfig.accessKeyId = config.accessKeyId;
|
|
56519
|
+
bedrockConfig.secretAccessKey = config.secretAccessKey;
|
|
56520
|
+
if (config.sessionToken) {
|
|
56521
|
+
bedrockConfig.sessionToken = config.sessionToken;
|
|
56522
|
+
}
|
|
56523
|
+
}
|
|
56524
|
+
if (config.region) {
|
|
56525
|
+
bedrockConfig.region = config.region;
|
|
56526
|
+
}
|
|
56527
|
+
if (config.baseURL) {
|
|
56528
|
+
bedrockConfig.baseURL = config.baseURL;
|
|
56529
|
+
}
|
|
56530
|
+
return createAmazonBedrock(bedrockConfig);
|
|
56531
|
+
}
|
|
56532
|
+
default:
|
|
56533
|
+
throw new Error(`FallbackManager: Unknown provider "${config.provider}"`);
|
|
56534
|
+
}
|
|
56535
|
+
} catch (error) {
|
|
56536
|
+
const providerName = this._getProviderDisplayName(config);
|
|
56537
|
+
throw new Error(`Failed to create provider instance for ${providerName}: ${error.message}`);
|
|
56538
|
+
}
|
|
56539
|
+
}
|
|
56540
|
+
/**
|
|
56541
|
+
* Get the model name for a provider configuration
|
|
56542
|
+
* @param {ProviderConfig} config - Provider configuration
|
|
56543
|
+
* @returns {string} - Model name
|
|
56544
|
+
* @private
|
|
56545
|
+
*/
|
|
56546
|
+
_getModelName(config) {
|
|
56547
|
+
return config.model || DEFAULT_MODELS[config.provider];
|
|
56548
|
+
}
|
|
56549
|
+
/**
|
|
56550
|
+
* Get provider display name for logging
|
|
56551
|
+
* @param {ProviderConfig} config - Provider configuration
|
|
56552
|
+
* @returns {string} - Display name
|
|
56553
|
+
* @private
|
|
56554
|
+
*/
|
|
56555
|
+
_getProviderDisplayName(config) {
|
|
56556
|
+
const model = this._getModelName(config);
|
|
56557
|
+
const provider = config.provider;
|
|
56558
|
+
const url = config.baseURL ? ` (${config.baseURL})` : "";
|
|
56559
|
+
return `${provider}/${model}${url}`;
|
|
56560
|
+
}
|
|
56561
|
+
/**
|
|
56562
|
+
* Execute a function with fallback support
|
|
56563
|
+
* @param {Function} fn - Function that takes (provider, model, config) and returns a Promise
|
|
56564
|
+
* @returns {Promise<*>} - Result from the function
|
|
56565
|
+
* @throws {Error} - If all fallbacks are exhausted
|
|
56566
|
+
*/
|
|
56567
|
+
async executeWithFallback(fn) {
|
|
56568
|
+
if (this.providers.length === 0) {
|
|
56569
|
+
throw new Error("FallbackManager: No providers configured for fallback");
|
|
56570
|
+
}
|
|
56571
|
+
let lastError = null;
|
|
56572
|
+
let totalAttempts = 0;
|
|
56573
|
+
for (const config of this.providers) {
|
|
56574
|
+
if (totalAttempts >= this.maxTotalAttempts) {
|
|
56575
|
+
if (this.debug) {
|
|
56576
|
+
console.log(`[FallbackManager] \u26A0\uFE0F Max total attempts (${this.maxTotalAttempts}) reached`);
|
|
56577
|
+
}
|
|
56578
|
+
break;
|
|
56579
|
+
}
|
|
56580
|
+
totalAttempts++;
|
|
56581
|
+
this.stats.totalAttempts++;
|
|
56582
|
+
const providerName = this._getProviderDisplayName(config);
|
|
56583
|
+
this.stats.providerAttempts[providerName] = (this.stats.providerAttempts[providerName] || 0) + 1;
|
|
56584
|
+
try {
|
|
56585
|
+
if (this.debug) {
|
|
56586
|
+
console.log(`[FallbackManager] Attempting provider: ${providerName} (attempt ${totalAttempts}/${this.maxTotalAttempts})`);
|
|
56587
|
+
}
|
|
56588
|
+
const provider = this._createProviderInstance(config);
|
|
56589
|
+
const model = this._getModelName(config);
|
|
56590
|
+
const result = await fn(provider, model, config);
|
|
56591
|
+
this.stats.successfulProvider = providerName;
|
|
56592
|
+
if (this.debug) {
|
|
56593
|
+
console.log(`[FallbackManager] \u2705 Success with provider: ${providerName}`);
|
|
56594
|
+
}
|
|
56595
|
+
return result;
|
|
56596
|
+
} catch (error) {
|
|
56597
|
+
lastError = error;
|
|
56598
|
+
const errorInfo = {
|
|
56599
|
+
message: error.message || error.toString(),
|
|
56600
|
+
type: error.type || error.constructor.name,
|
|
56601
|
+
statusCode: error.statusCode || error.status
|
|
56602
|
+
};
|
|
56603
|
+
this.stats.failedProviders.push({
|
|
56604
|
+
provider: providerName,
|
|
56605
|
+
error: errorInfo
|
|
56606
|
+
});
|
|
56607
|
+
if (this.debug) {
|
|
56608
|
+
console.log(`[FallbackManager] \u274C Failed with provider: ${providerName}`, errorInfo);
|
|
56609
|
+
}
|
|
56610
|
+
if (!this.continueOnNonRetryableError && error.nonRetryable) {
|
|
56611
|
+
if (this.debug) {
|
|
56612
|
+
console.log(`[FallbackManager] Non-retryable error, stopping fallback chain`);
|
|
56613
|
+
}
|
|
56614
|
+
throw error;
|
|
56615
|
+
}
|
|
56616
|
+
if (this.debug) {
|
|
56617
|
+
const remaining = this.providers.length - (this.providers.indexOf(config) + 1);
|
|
56618
|
+
console.log(`[FallbackManager] Trying next provider (${remaining} remaining)...`);
|
|
56619
|
+
}
|
|
56620
|
+
}
|
|
56621
|
+
}
|
|
56622
|
+
if (this.debug) {
|
|
56623
|
+
console.log(`[FallbackManager] \u274C All providers exhausted. Total attempts: ${totalAttempts}`);
|
|
56624
|
+
}
|
|
56625
|
+
const fallbackError = new Error(
|
|
56626
|
+
`All provider fallbacks exhausted after ${totalAttempts} attempts. Last error: ${lastError?.message || "Unknown error"}`
|
|
56627
|
+
);
|
|
56628
|
+
fallbackError.cause = lastError;
|
|
56629
|
+
fallbackError.stats = this.getStats();
|
|
56630
|
+
fallbackError.allProvidersFailed = true;
|
|
56631
|
+
throw fallbackError;
|
|
56632
|
+
}
|
|
56633
|
+
/**
|
|
56634
|
+
* Get fallback statistics
|
|
56635
|
+
* @returns {Object} - Statistics object
|
|
56636
|
+
*/
|
|
56637
|
+
getStats() {
|
|
56638
|
+
return {
|
|
56639
|
+
...this.stats,
|
|
56640
|
+
providerAttempts: { ...this.stats.providerAttempts },
|
|
56641
|
+
failedProviders: [...this.stats.failedProviders]
|
|
56642
|
+
};
|
|
56643
|
+
}
|
|
56644
|
+
/**
|
|
56645
|
+
* Reset statistics
|
|
56646
|
+
*/
|
|
56647
|
+
resetStats() {
|
|
56648
|
+
this.stats = {
|
|
56649
|
+
totalAttempts: 0,
|
|
56650
|
+
providerAttempts: {},
|
|
56651
|
+
successfulProvider: null,
|
|
56652
|
+
failedProviders: []
|
|
56653
|
+
};
|
|
56654
|
+
}
|
|
56655
|
+
};
|
|
56656
|
+
}
|
|
56657
|
+
});
|
|
56658
|
+
|
|
55612
56659
|
// src/agent/ProbeAgent.js
|
|
55613
56660
|
var ProbeAgent_exports = {};
|
|
55614
56661
|
__export(ProbeAgent_exports, {
|
|
55615
56662
|
ProbeAgent: () => ProbeAgent
|
|
55616
56663
|
});
|
|
55617
56664
|
import dotenv2 from "dotenv";
|
|
55618
|
-
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
55619
|
-
import { createOpenAI } from "@ai-sdk/openai";
|
|
55620
|
-
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
55621
|
-
import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock";
|
|
56665
|
+
import { createAnthropic as createAnthropic2 } from "@ai-sdk/anthropic";
|
|
56666
|
+
import { createOpenAI as createOpenAI2 } from "@ai-sdk/openai";
|
|
56667
|
+
import { createGoogleGenerativeAI as createGoogleGenerativeAI2 } from "@ai-sdk/google";
|
|
56668
|
+
import { createAmazonBedrock as createAmazonBedrock2 } from "@ai-sdk/amazon-bedrock";
|
|
55622
56669
|
import { streamText } from "ai";
|
|
55623
56670
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
55624
56671
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
55625
|
-
import { existsSync as
|
|
56672
|
+
import { existsSync as existsSync5 } from "fs";
|
|
55626
56673
|
import { readFile, stat } from "fs/promises";
|
|
55627
|
-
import { resolve as
|
|
56674
|
+
import { resolve as resolve4, isAbsolute as isAbsolute2, dirname as dirname4 } from "path";
|
|
55628
56675
|
var MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
|
|
55629
56676
|
var init_ProbeAgent = __esm({
|
|
55630
56677
|
"src/agent/ProbeAgent.js"() {
|
|
@@ -55641,8 +56688,17 @@ var init_ProbeAgent = __esm({
|
|
|
55641
56688
|
init_schemaUtils();
|
|
55642
56689
|
init_xmlParsingUtils();
|
|
55643
56690
|
init_mcp();
|
|
56691
|
+
init_RetryManager();
|
|
56692
|
+
init_FallbackManager();
|
|
55644
56693
|
dotenv2.config();
|
|
55645
|
-
MAX_TOOL_ITERATIONS =
|
|
56694
|
+
MAX_TOOL_ITERATIONS = (() => {
|
|
56695
|
+
const val = parseInt(process.env.MAX_TOOL_ITERATIONS || "30", 10);
|
|
56696
|
+
if (isNaN(val) || val < 1 || val > 200) {
|
|
56697
|
+
console.warn("[ProbeAgent] MAX_TOOL_ITERATIONS must be between 1 and 200, using default: 30");
|
|
56698
|
+
return 30;
|
|
56699
|
+
}
|
|
56700
|
+
return val;
|
|
56701
|
+
})();
|
|
55646
56702
|
MAX_HISTORY_MESSAGES = 100;
|
|
55647
56703
|
MAX_IMAGE_FILE_SIZE = 20 * 1024 * 1024;
|
|
55648
56704
|
ProbeAgent = class _ProbeAgent {
|
|
@@ -55669,6 +56725,18 @@ var init_ProbeAgent = __esm({
|
|
|
55669
56725
|
* @param {Array} [options.mcpServers] - Deprecated, use mcpConfig instead
|
|
55670
56726
|
* @param {Object} [options.storageAdapter] - Custom storage adapter for history management
|
|
55671
56727
|
* @param {Object} [options.hooks] - Hook callbacks for events (e.g., {'tool:start': callback})
|
|
56728
|
+
* @param {Object} [options.retry] - Retry configuration
|
|
56729
|
+
* @param {number} [options.retry.maxRetries=3] - Maximum retry attempts per provider
|
|
56730
|
+
* @param {number} [options.retry.initialDelay=1000] - Initial delay in ms
|
|
56731
|
+
* @param {number} [options.retry.maxDelay=30000] - Maximum delay in ms
|
|
56732
|
+
* @param {number} [options.retry.backoffFactor=2] - Exponential backoff multiplier
|
|
56733
|
+
* @param {Array<string>} [options.retry.retryableErrors] - List of retryable error patterns
|
|
56734
|
+
* @param {Object} [options.fallback] - Fallback configuration
|
|
56735
|
+
* @param {string} [options.fallback.strategy] - Fallback strategy: 'same-model', 'same-provider', 'any', 'custom'
|
|
56736
|
+
* @param {Array<string>} [options.fallback.models] - List of models for same-provider fallback
|
|
56737
|
+
* @param {Array<Object>} [options.fallback.providers] - List of provider configurations for custom fallback
|
|
56738
|
+
* @param {boolean} [options.fallback.stopOnSuccess=true] - Stop on first success
|
|
56739
|
+
* @param {number} [options.fallback.maxTotalAttempts=10] - Maximum total attempts across all providers
|
|
55672
56740
|
*/
|
|
55673
56741
|
constructor(options = {}) {
|
|
55674
56742
|
this.sessionId = options.sessionId || randomUUID4();
|
|
@@ -55680,7 +56748,13 @@ var init_ProbeAgent = __esm({
|
|
|
55680
56748
|
this.cancelled = false;
|
|
55681
56749
|
this.tracer = options.tracer || null;
|
|
55682
56750
|
this.outline = !!options.outline;
|
|
55683
|
-
this.maxResponseTokens = options.maxResponseTokens ||
|
|
56751
|
+
this.maxResponseTokens = options.maxResponseTokens || (() => {
|
|
56752
|
+
const val = parseInt(process.env.MAX_RESPONSE_TOKENS || "0", 10);
|
|
56753
|
+
if (isNaN(val) || val < 0 || val > 2e5) {
|
|
56754
|
+
return null;
|
|
56755
|
+
}
|
|
56756
|
+
return val || null;
|
|
56757
|
+
})();
|
|
55684
56758
|
this.maxIterations = options.maxIterations || null;
|
|
55685
56759
|
this.disableMermaidValidation = !!options.disableMermaidValidation;
|
|
55686
56760
|
this.disableJsonValidation = !!options.disableJsonValidation;
|
|
@@ -55721,6 +56795,10 @@ var init_ProbeAgent = __esm({
|
|
|
55721
56795
|
this.mcpServers = options.mcpServers || null;
|
|
55722
56796
|
this.mcpBridge = null;
|
|
55723
56797
|
this._mcpInitialized = false;
|
|
56798
|
+
this.retryConfig = options.retry || {};
|
|
56799
|
+
this.retryManager = null;
|
|
56800
|
+
this.fallbackConfig = options.fallback || null;
|
|
56801
|
+
this.fallbackManager = null;
|
|
55724
56802
|
this.initializeModel();
|
|
55725
56803
|
}
|
|
55726
56804
|
/**
|
|
@@ -55805,6 +56883,14 @@ var init_ProbeAgent = __esm({
|
|
|
55805
56883
|
if (this.enableBash && wrappedTools.bashToolInstance) {
|
|
55806
56884
|
this.toolImplementations.bash = wrappedTools.bashToolInstance;
|
|
55807
56885
|
}
|
|
56886
|
+
if (this.allowEdit) {
|
|
56887
|
+
if (wrappedTools.editToolInstance) {
|
|
56888
|
+
this.toolImplementations.edit = wrappedTools.editToolInstance;
|
|
56889
|
+
}
|
|
56890
|
+
if (wrappedTools.createToolInstance) {
|
|
56891
|
+
this.toolImplementations.create = wrappedTools.createToolInstance;
|
|
56892
|
+
}
|
|
56893
|
+
}
|
|
55808
56894
|
this.wrappedTools = wrappedTools;
|
|
55809
56895
|
if (this.debug) {
|
|
55810
56896
|
console.error("\n[DEBUG] ========================================");
|
|
@@ -55855,36 +56941,147 @@ var init_ProbeAgent = __esm({
|
|
|
55855
56941
|
if (forceProvider) {
|
|
55856
56942
|
if (forceProvider === "anthropic" && anthropicApiKey) {
|
|
55857
56943
|
this.initializeAnthropicModel(anthropicApiKey, anthropicApiUrl, modelName);
|
|
56944
|
+
this.initializeFallbackManager(forceProvider, modelName);
|
|
55858
56945
|
return;
|
|
55859
56946
|
} else if (forceProvider === "openai" && openaiApiKey) {
|
|
55860
56947
|
this.initializeOpenAIModel(openaiApiKey, openaiApiUrl, modelName);
|
|
56948
|
+
this.initializeFallbackManager(forceProvider, modelName);
|
|
55861
56949
|
return;
|
|
55862
56950
|
} else if (forceProvider === "google" && googleApiKey) {
|
|
55863
56951
|
this.initializeGoogleModel(googleApiKey, googleApiUrl, modelName);
|
|
56952
|
+
this.initializeFallbackManager(forceProvider, modelName);
|
|
55864
56953
|
return;
|
|
55865
56954
|
} else if (forceProvider === "bedrock" && (awsAccessKeyId && awsSecretAccessKey && awsRegion || awsApiKey)) {
|
|
55866
56955
|
this.initializeBedrockModel(awsAccessKeyId, awsSecretAccessKey, awsRegion, awsSessionToken, awsApiKey, awsBedrockBaseUrl, modelName);
|
|
56956
|
+
this.initializeFallbackManager(forceProvider, modelName);
|
|
55867
56957
|
return;
|
|
55868
56958
|
}
|
|
55869
56959
|
console.warn(`WARNING: Forced provider "${forceProvider}" selected but required API key is missing or invalid! Falling back to auto-detection.`);
|
|
55870
56960
|
}
|
|
55871
56961
|
if (anthropicApiKey) {
|
|
55872
56962
|
this.initializeAnthropicModel(anthropicApiKey, anthropicApiUrl, modelName);
|
|
56963
|
+
this.initializeFallbackManager("anthropic", modelName);
|
|
55873
56964
|
} else if (openaiApiKey) {
|
|
55874
56965
|
this.initializeOpenAIModel(openaiApiKey, openaiApiUrl, modelName);
|
|
56966
|
+
this.initializeFallbackManager("openai", modelName);
|
|
55875
56967
|
} else if (googleApiKey) {
|
|
55876
56968
|
this.initializeGoogleModel(googleApiKey, googleApiUrl, modelName);
|
|
56969
|
+
this.initializeFallbackManager("google", modelName);
|
|
55877
56970
|
} else if (awsAccessKeyId && awsSecretAccessKey && awsRegion || awsApiKey) {
|
|
55878
56971
|
this.initializeBedrockModel(awsAccessKeyId, awsSecretAccessKey, awsRegion, awsSessionToken, awsApiKey, awsBedrockBaseUrl, modelName);
|
|
56972
|
+
this.initializeFallbackManager("bedrock", modelName);
|
|
55879
56973
|
} else {
|
|
55880
56974
|
throw new Error("No API key provided. Please set ANTHROPIC_API_KEY (or ANTHROPIC_AUTH_TOKEN), OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY (or GOOGLE_API_KEY), AWS credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION), or AWS_BEDROCK_API_KEY environment variables.");
|
|
55881
56975
|
}
|
|
55882
56976
|
}
|
|
56977
|
+
/**
|
|
56978
|
+
* Initialize fallback manager based on configuration
|
|
56979
|
+
* @param {string} primaryProvider - The primary provider being used
|
|
56980
|
+
* @param {string} primaryModel - The primary model being used
|
|
56981
|
+
* @private
|
|
56982
|
+
*/
|
|
56983
|
+
initializeFallbackManager(primaryProvider, primaryModel) {
|
|
56984
|
+
if (this.fallbackConfig === false || process.env.DISABLE_FALLBACK === "1") {
|
|
56985
|
+
return;
|
|
56986
|
+
}
|
|
56987
|
+
if (this.fallbackConfig && this.fallbackConfig.providers) {
|
|
56988
|
+
try {
|
|
56989
|
+
this.fallbackManager = new FallbackManager({
|
|
56990
|
+
...this.fallbackConfig,
|
|
56991
|
+
debug: this.debug
|
|
56992
|
+
});
|
|
56993
|
+
if (this.debug) {
|
|
56994
|
+
console.log(`[DEBUG] Fallback manager initialized with ${this.fallbackManager.providers.length} providers`);
|
|
56995
|
+
}
|
|
56996
|
+
} catch (error) {
|
|
56997
|
+
console.error("[WARNING] Failed to initialize fallback manager:", error.message);
|
|
56998
|
+
}
|
|
56999
|
+
return;
|
|
57000
|
+
}
|
|
57001
|
+
const envFallbackManager = createFallbackManagerFromEnv(this.debug);
|
|
57002
|
+
if (envFallbackManager) {
|
|
57003
|
+
this.fallbackManager = envFallbackManager;
|
|
57004
|
+
if (this.debug) {
|
|
57005
|
+
console.log(`[DEBUG] Fallback manager initialized from environment variables`);
|
|
57006
|
+
}
|
|
57007
|
+
return;
|
|
57008
|
+
}
|
|
57009
|
+
if (process.env.AUTO_FALLBACK === "1" || this.fallbackConfig?.auto) {
|
|
57010
|
+
const providers = buildFallbackProvidersFromEnv({
|
|
57011
|
+
primaryProvider,
|
|
57012
|
+
primaryModel
|
|
57013
|
+
});
|
|
57014
|
+
if (providers.length > 1) {
|
|
57015
|
+
try {
|
|
57016
|
+
this.fallbackManager = new FallbackManager({
|
|
57017
|
+
strategy: "custom",
|
|
57018
|
+
providers,
|
|
57019
|
+
debug: this.debug
|
|
57020
|
+
});
|
|
57021
|
+
if (this.debug) {
|
|
57022
|
+
console.log(`[DEBUG] Auto-fallback enabled with ${providers.length} providers`);
|
|
57023
|
+
}
|
|
57024
|
+
} catch (error) {
|
|
57025
|
+
console.error("[WARNING] Failed to initialize auto-fallback:", error.message);
|
|
57026
|
+
}
|
|
57027
|
+
}
|
|
57028
|
+
}
|
|
57029
|
+
}
|
|
57030
|
+
/**
|
|
57031
|
+
* Execute streamText with retry and fallback support
|
|
57032
|
+
* @param {Object} options - streamText options
|
|
57033
|
+
* @returns {Promise<Object>} - streamText result
|
|
57034
|
+
* @private
|
|
57035
|
+
*/
|
|
57036
|
+
async streamTextWithRetryAndFallback(options) {
|
|
57037
|
+
if (!this.retryManager) {
|
|
57038
|
+
this.retryManager = new RetryManager({
|
|
57039
|
+
maxRetries: this.retryConfig.maxRetries ?? 3,
|
|
57040
|
+
initialDelay: this.retryConfig.initialDelay ?? 1e3,
|
|
57041
|
+
maxDelay: this.retryConfig.maxDelay ?? 3e4,
|
|
57042
|
+
backoffFactor: this.retryConfig.backoffFactor ?? 2,
|
|
57043
|
+
retryableErrors: this.retryConfig.retryableErrors,
|
|
57044
|
+
debug: this.debug
|
|
57045
|
+
});
|
|
57046
|
+
}
|
|
57047
|
+
if (!this.fallbackManager) {
|
|
57048
|
+
return await this.retryManager.executeWithRetry(
|
|
57049
|
+
() => streamText(options),
|
|
57050
|
+
{
|
|
57051
|
+
provider: this.apiType,
|
|
57052
|
+
model: this.model
|
|
57053
|
+
}
|
|
57054
|
+
);
|
|
57055
|
+
}
|
|
57056
|
+
return await this.fallbackManager.executeWithFallback(
|
|
57057
|
+
async (provider, model, config) => {
|
|
57058
|
+
const fallbackOptions = {
|
|
57059
|
+
...options,
|
|
57060
|
+
model: provider(model)
|
|
57061
|
+
};
|
|
57062
|
+
const providerRetryManager = new RetryManager({
|
|
57063
|
+
maxRetries: config.maxRetries ?? this.retryConfig.maxRetries ?? 3,
|
|
57064
|
+
initialDelay: this.retryConfig.initialDelay ?? 1e3,
|
|
57065
|
+
maxDelay: this.retryConfig.maxDelay ?? 3e4,
|
|
57066
|
+
backoffFactor: this.retryConfig.backoffFactor ?? 2,
|
|
57067
|
+
retryableErrors: this.retryConfig.retryableErrors,
|
|
57068
|
+
debug: this.debug
|
|
57069
|
+
});
|
|
57070
|
+
return await providerRetryManager.executeWithRetry(
|
|
57071
|
+
() => streamText(fallbackOptions),
|
|
57072
|
+
{
|
|
57073
|
+
provider: config.provider,
|
|
57074
|
+
model
|
|
57075
|
+
}
|
|
57076
|
+
);
|
|
57077
|
+
}
|
|
57078
|
+
);
|
|
57079
|
+
}
|
|
55883
57080
|
/**
|
|
55884
57081
|
* Initialize Anthropic model
|
|
55885
57082
|
*/
|
|
55886
57083
|
initializeAnthropicModel(apiKey, apiUrl, modelName) {
|
|
55887
|
-
this.provider =
|
|
57084
|
+
this.provider = createAnthropic2({
|
|
55888
57085
|
apiKey,
|
|
55889
57086
|
...apiUrl && { baseURL: apiUrl }
|
|
55890
57087
|
});
|
|
@@ -55898,7 +57095,7 @@ var init_ProbeAgent = __esm({
|
|
|
55898
57095
|
* Initialize OpenAI model
|
|
55899
57096
|
*/
|
|
55900
57097
|
initializeOpenAIModel(apiKey, apiUrl, modelName) {
|
|
55901
|
-
this.provider =
|
|
57098
|
+
this.provider = createOpenAI2({
|
|
55902
57099
|
compatibility: "strict",
|
|
55903
57100
|
apiKey,
|
|
55904
57101
|
...apiUrl && { baseURL: apiUrl }
|
|
@@ -55913,7 +57110,7 @@ var init_ProbeAgent = __esm({
|
|
|
55913
57110
|
* Initialize Google model
|
|
55914
57111
|
*/
|
|
55915
57112
|
initializeGoogleModel(apiKey, apiUrl, modelName) {
|
|
55916
|
-
this.provider =
|
|
57113
|
+
this.provider = createGoogleGenerativeAI2({
|
|
55917
57114
|
apiKey,
|
|
55918
57115
|
...apiUrl && { baseURL: apiUrl }
|
|
55919
57116
|
});
|
|
@@ -55943,7 +57140,7 @@ var init_ProbeAgent = __esm({
|
|
|
55943
57140
|
if (baseURL) {
|
|
55944
57141
|
config.baseURL = baseURL;
|
|
55945
57142
|
}
|
|
55946
|
-
this.provider =
|
|
57143
|
+
this.provider = createAmazonBedrock2(config);
|
|
55947
57144
|
this.model = modelName || "anthropic.claude-sonnet-4-20250514-v1:0";
|
|
55948
57145
|
this.apiType = "bedrock";
|
|
55949
57146
|
if (this.debug) {
|
|
@@ -55988,7 +57185,7 @@ var init_ProbeAgent = __esm({
|
|
|
55988
57185
|
let resolvedPath = imagePath;
|
|
55989
57186
|
if (!imagePath.includes("/") && !imagePath.includes("\\")) {
|
|
55990
57187
|
for (const dir of listFilesDirectories) {
|
|
55991
|
-
const potentialPath =
|
|
57188
|
+
const potentialPath = resolve4(dir, imagePath);
|
|
55992
57189
|
const loaded = await this.loadImageIfValid(potentialPath);
|
|
55993
57190
|
if (loaded) {
|
|
55994
57191
|
if (this.debug) {
|
|
@@ -56013,7 +57210,7 @@ var init_ProbeAgent = __esm({
|
|
|
56013
57210
|
let match2;
|
|
56014
57211
|
while ((match2 = fileHeaderPattern.exec(content)) !== null) {
|
|
56015
57212
|
const filePath = match2[1].trim();
|
|
56016
|
-
const dir =
|
|
57213
|
+
const dir = dirname4(filePath);
|
|
56017
57214
|
if (dir && dir !== ".") {
|
|
56018
57215
|
directories.push(dir);
|
|
56019
57216
|
if (this.debug) {
|
|
@@ -56057,21 +57254,21 @@ var init_ProbeAgent = __esm({
|
|
|
56057
57254
|
}
|
|
56058
57255
|
const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
|
|
56059
57256
|
let absolutePath;
|
|
56060
|
-
let
|
|
56061
|
-
if (
|
|
57257
|
+
let isPathAllowed2 = false;
|
|
57258
|
+
if (isAbsolute2(imagePath)) {
|
|
56062
57259
|
absolutePath = imagePath;
|
|
56063
|
-
|
|
57260
|
+
isPathAllowed2 = allowedDirs.some((dir) => absolutePath.startsWith(resolve4(dir)));
|
|
56064
57261
|
} else {
|
|
56065
57262
|
for (const dir of allowedDirs) {
|
|
56066
|
-
const resolvedPath =
|
|
56067
|
-
if (resolvedPath.startsWith(
|
|
57263
|
+
const resolvedPath = resolve4(dir, imagePath);
|
|
57264
|
+
if (resolvedPath.startsWith(resolve4(dir))) {
|
|
56068
57265
|
absolutePath = resolvedPath;
|
|
56069
|
-
|
|
57266
|
+
isPathAllowed2 = true;
|
|
56070
57267
|
break;
|
|
56071
57268
|
}
|
|
56072
57269
|
}
|
|
56073
57270
|
}
|
|
56074
|
-
if (!
|
|
57271
|
+
if (!isPathAllowed2) {
|
|
56075
57272
|
if (this.debug) {
|
|
56076
57273
|
console.log(`[DEBUG] Image path outside allowed directories: ${imagePath}`);
|
|
56077
57274
|
}
|
|
@@ -56270,6 +57467,14 @@ ${attemptCompletionToolDefinition}
|
|
|
56270
57467
|
`;
|
|
56271
57468
|
if (this.allowEdit) {
|
|
56272
57469
|
toolDefinitions += `${implementToolDefinition}
|
|
57470
|
+
`;
|
|
57471
|
+
toolDefinitions += `${editToolDefinition}
|
|
57472
|
+
`;
|
|
57473
|
+
toolDefinitions += `${createToolDefinition}
|
|
57474
|
+
`;
|
|
57475
|
+
}
|
|
57476
|
+
if (this.enableBash) {
|
|
57477
|
+
toolDefinitions += `${bashToolDefinition}
|
|
56273
57478
|
`;
|
|
56274
57479
|
}
|
|
56275
57480
|
if (this.enableDelegate) {
|
|
@@ -56337,7 +57542,7 @@ Available Tools:
|
|
|
56337
57542
|
- extract: Extract specific code blocks or lines from files.
|
|
56338
57543
|
- listFiles: List files and directories in a specified location.
|
|
56339
57544
|
- searchFiles: Find files matching a glob pattern with recursive search capability.
|
|
56340
|
-
${this.allowEdit ? "- implement: Implement a feature or fix a bug using aider.\n" : ""}${this.enableDelegate ? "- delegate: Delegate big distinct tasks to specialized probe subagents.\n" : ""}
|
|
57545
|
+
${this.allowEdit ? "- implement: Implement a feature or fix a bug using aider.\n- edit: Edit files using exact string replacement.\n- create: Create new files with specified content.\n" : ""}${this.enableDelegate ? "- delegate: Delegate big distinct tasks to specialized probe subagents.\n" : ""}${this.enableBash ? "- bash: Execute bash commands for system operations.\n" : ""}
|
|
56341
57546
|
- attempt_completion: Finalize the task and provide the result to the user.
|
|
56342
57547
|
- attempt_complete: Quick completion using previous response (shorthand).
|
|
56343
57548
|
`;
|
|
@@ -56351,7 +57556,10 @@ Follow these instructions carefully:
|
|
|
56351
57556
|
6. You MUST respond with exactly ONE tool call per message, using the specified XML format, until the task is complete.
|
|
56352
57557
|
7. Wait for the tool execution result (provided in the next user message in a <tool_result> block) before proceeding to the next step.
|
|
56353
57558
|
8. Once the task is fully completed, use the '<attempt_completion>' tool to provide the final result. This is the ONLY way to signal completion.
|
|
56354
|
-
9. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results.
|
|
57559
|
+
9. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results.${this.allowEdit ? `
|
|
57560
|
+
10. When modifying files, choose the appropriate tool:
|
|
57561
|
+
- Use 'edit' for precise changes to existing files (requires exact string match)
|
|
57562
|
+
- Use 'create' for new files or complete file rewrites` : ""}
|
|
56355
57563
|
</instructions>
|
|
56356
57564
|
`;
|
|
56357
57565
|
const predefinedPrompts = {
|
|
@@ -56603,7 +57811,7 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
56603
57811
|
try {
|
|
56604
57812
|
const executeAIRequest = async () => {
|
|
56605
57813
|
const messagesForAI = this.prepareMessagesWithImages(currentMessages);
|
|
56606
|
-
const result = await
|
|
57814
|
+
const result = await this.streamTextWithRetryAndFallback({
|
|
56607
57815
|
model: this.provider(this.model),
|
|
56608
57816
|
messages: messagesForAI,
|
|
56609
57817
|
maxTokens: maxResponseTokens,
|
|
@@ -56655,7 +57863,10 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
56655
57863
|
"attempt_completion"
|
|
56656
57864
|
];
|
|
56657
57865
|
if (this.allowEdit) {
|
|
56658
|
-
validTools.push("implement");
|
|
57866
|
+
validTools.push("implement", "edit", "create");
|
|
57867
|
+
}
|
|
57868
|
+
if (this.enableBash) {
|
|
57869
|
+
validTools.push("bash");
|
|
56659
57870
|
}
|
|
56660
57871
|
if (this.enableDelegate) {
|
|
56661
57872
|
validTools.push("delegate");
|
|
@@ -57569,8 +58780,8 @@ import {
|
|
|
57569
58780
|
ListToolsRequestSchema,
|
|
57570
58781
|
McpError
|
|
57571
58782
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
57572
|
-
import { readFileSync as readFileSync2, existsSync as
|
|
57573
|
-
import { resolve as
|
|
58783
|
+
import { readFileSync as readFileSync2, existsSync as existsSync6 } from "fs";
|
|
58784
|
+
import { resolve as resolve5 } from "path";
|
|
57574
58785
|
|
|
57575
58786
|
// src/agent/acp/server.js
|
|
57576
58787
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
@@ -57829,8 +59040,8 @@ var ACPConnection = class extends EventEmitter4 {
|
|
|
57829
59040
|
if (params !== null) {
|
|
57830
59041
|
message.params = params;
|
|
57831
59042
|
}
|
|
57832
|
-
return new Promise((
|
|
57833
|
-
this.pendingRequests.set(id, { resolve:
|
|
59043
|
+
return new Promise((resolve6, reject2) => {
|
|
59044
|
+
this.pendingRequests.set(id, { resolve: resolve6, reject: reject2 });
|
|
57834
59045
|
this.sendMessage(message);
|
|
57835
59046
|
setTimeout(() => {
|
|
57836
59047
|
if (this.pendingRequests.has(id)) {
|
|
@@ -58244,8 +59455,8 @@ dotenv3.config();
|
|
|
58244
59455
|
function readInputContent(input) {
|
|
58245
59456
|
if (!input) return null;
|
|
58246
59457
|
try {
|
|
58247
|
-
const resolvedPath =
|
|
58248
|
-
if (
|
|
59458
|
+
const resolvedPath = resolve5(input);
|
|
59459
|
+
if (existsSync6(resolvedPath)) {
|
|
58249
59460
|
return readFileSync2(resolvedPath, "utf-8").trim();
|
|
58250
59461
|
}
|
|
58251
59462
|
} catch (error) {
|
|
@@ -58253,7 +59464,7 @@ function readInputContent(input) {
|
|
|
58253
59464
|
return input;
|
|
58254
59465
|
}
|
|
58255
59466
|
function readFromStdin() {
|
|
58256
|
-
return new Promise((
|
|
59467
|
+
return new Promise((resolve6, reject2) => {
|
|
58257
59468
|
let data = "";
|
|
58258
59469
|
let hasReceivedData = false;
|
|
58259
59470
|
let dataChunks = [];
|
|
@@ -58278,7 +59489,7 @@ function readFromStdin() {
|
|
|
58278
59489
|
if (!trimmed && dataChunks.length === 0) {
|
|
58279
59490
|
reject2(new Error("No input received from stdin"));
|
|
58280
59491
|
} else {
|
|
58281
|
-
|
|
59492
|
+
resolve6(trimmed);
|
|
58282
59493
|
}
|
|
58283
59494
|
});
|
|
58284
59495
|
process.stdin.on("error", (error) => {
|
|
@@ -58804,7 +60015,7 @@ async function main() {
|
|
|
58804
60015
|
bashConfig.timeout = timeout;
|
|
58805
60016
|
}
|
|
58806
60017
|
if (config.bashWorkingDir) {
|
|
58807
|
-
if (!
|
|
60018
|
+
if (!existsSync6(config.bashWorkingDir)) {
|
|
58808
60019
|
console.error(`Error: Bash working directory does not exist: ${config.bashWorkingDir}`);
|
|
58809
60020
|
process.exit(1);
|
|
58810
60021
|
}
|