@probelabs/probe 0.6.0-rc154 → 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 +9 -1
- package/build/agent/ProbeAgent.js +218 -10
- package/build/agent/RetryManager.d.ts +157 -0
- package/build/agent/RetryManager.js +334 -0
- package/build/agent/acp/server.js +1 -0
- package/build/agent/acp/tools.js +6 -2
- package/build/agent/index.js +1814 -355
- package/build/agent/probeTool.js +20 -2
- package/build/agent/tools.js +16 -0
- package/build/delegate.js +326 -201
- package/build/downloader.js +46 -17
- package/build/extractor.js +12 -12
- 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/build/tools/vercel.js +55 -14
- package/build/utils.js +18 -9
- package/cjs/agent/ProbeAgent.cjs +2268 -699
- package/cjs/index.cjs +75902 -74348
- 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 +9 -1
- package/src/agent/ProbeAgent.js +218 -10
- package/src/agent/RetryManager.d.ts +157 -0
- package/src/agent/RetryManager.js +334 -0
- package/src/agent/acp/server.js +1 -0
- package/src/agent/acp/tools.js +6 -2
- package/src/agent/index.js +8 -0
- package/src/agent/probeTool.js +20 -2
- package/src/agent/tools.js +16 -0
- package/src/delegate.js +326 -201
- package/src/downloader.js +46 -17
- package/src/extractor.js +12 -12
- 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/src/tools/vercel.js +55 -14
- package/src/utils.js +18 -9
- package/bin/binaries/probe-v0.6.0-rc154-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc154-aarch64-unknown-linux-gnu.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc154-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc154-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc154-x86_64-unknown-linux-gnu.tar.gz +0 -0
package/build/agent/index.js
CHANGED
|
@@ -1893,6 +1893,28 @@ import { exec as execCallback } from "child_process";
|
|
|
1893
1893
|
import tar from "tar";
|
|
1894
1894
|
import os2 from "os";
|
|
1895
1895
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1896
|
+
function sanitizeError(err) {
|
|
1897
|
+
try {
|
|
1898
|
+
const status = err?.response?.status;
|
|
1899
|
+
const statusText = err?.response?.statusText;
|
|
1900
|
+
const url = err?.config?.url || err?.response?.config?.url;
|
|
1901
|
+
const code = err?.code;
|
|
1902
|
+
const serverMsg = typeof err?.response?.data === "string" ? err.response.data.slice(0, 500) : typeof err?.response?.data?.message === "string" ? err.response.data.message : void 0;
|
|
1903
|
+
const base = err?.message || String(err);
|
|
1904
|
+
const parts = [base];
|
|
1905
|
+
if (status || statusText) parts.push(`[${status ?? ""} ${statusText ?? ""}]`.trim());
|
|
1906
|
+
if (code) parts.push(`code=${code}`);
|
|
1907
|
+
if (url) parts.push(`url=${url}`);
|
|
1908
|
+
if (serverMsg) parts.push(`server="${String(serverMsg).replace(/\s+/g, " ").trim()}"`);
|
|
1909
|
+
const e = new Error(parts.filter(Boolean).join(" "));
|
|
1910
|
+
if (status) e.status = status;
|
|
1911
|
+
if (code) e.code = code;
|
|
1912
|
+
if (url) e.url = url;
|
|
1913
|
+
return e;
|
|
1914
|
+
} catch (_) {
|
|
1915
|
+
return new Error(err?.message || String(err));
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1896
1918
|
async function acquireFileLock(lockPath, version) {
|
|
1897
1919
|
const lockData = {
|
|
1898
1920
|
version,
|
|
@@ -1985,7 +2007,7 @@ async function waitForFileLock(lockPath, binaryPath) {
|
|
|
1985
2007
|
}
|
|
1986
2008
|
} catch {
|
|
1987
2009
|
}
|
|
1988
|
-
await new Promise((
|
|
2010
|
+
await new Promise((resolve6) => setTimeout(resolve6, LOCK_POLL_INTERVAL_MS));
|
|
1989
2011
|
}
|
|
1990
2012
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
1991
2013
|
console.log(`Timeout waiting for file lock`);
|
|
@@ -2041,7 +2063,7 @@ function detectOsArch() {
|
|
|
2041
2063
|
case "linux":
|
|
2042
2064
|
osInfo = {
|
|
2043
2065
|
type: "linux",
|
|
2044
|
-
keywords: ["linux", "Linux", "gnu"]
|
|
2066
|
+
keywords: ["linux", "Linux", "musl", "gnu"]
|
|
2045
2067
|
};
|
|
2046
2068
|
break;
|
|
2047
2069
|
case "darwin":
|
|
@@ -2085,7 +2107,7 @@ function constructAssetInfo(version, osInfo, archInfo) {
|
|
|
2085
2107
|
let extension;
|
|
2086
2108
|
switch (osInfo.type) {
|
|
2087
2109
|
case "linux":
|
|
2088
|
-
platform = `${archInfo.type}-unknown-linux-
|
|
2110
|
+
platform = `${archInfo.type}-unknown-linux-musl`;
|
|
2089
2111
|
extension = "tar.gz";
|
|
2090
2112
|
break;
|
|
2091
2113
|
case "darwin":
|
|
@@ -2202,7 +2224,7 @@ async function getLatestRelease(version) {
|
|
|
2202
2224
|
}
|
|
2203
2225
|
return { tag, assets };
|
|
2204
2226
|
}
|
|
2205
|
-
throw error;
|
|
2227
|
+
throw sanitizeError(error);
|
|
2206
2228
|
}
|
|
2207
2229
|
}
|
|
2208
2230
|
function findBestAsset(assets, osInfo, archInfo) {
|
|
@@ -2416,7 +2438,7 @@ async function extractBinary(assetPath, outputDir) {
|
|
|
2416
2438
|
return binaryPath;
|
|
2417
2439
|
} catch (error) {
|
|
2418
2440
|
console.error(`Error extracting binary: ${error instanceof Error ? error.message : String(error)}`);
|
|
2419
|
-
throw error;
|
|
2441
|
+
throw sanitizeError(error);
|
|
2420
2442
|
}
|
|
2421
2443
|
}
|
|
2422
2444
|
async function getVersionInfo(binDir) {
|
|
@@ -2581,8 +2603,8 @@ async function downloadProbeBinary(version) {
|
|
|
2581
2603
|
}
|
|
2582
2604
|
return await withDownloadLock(version, () => doDownload(version));
|
|
2583
2605
|
} catch (error) {
|
|
2584
|
-
console.error("Error downloading probe binary:", error);
|
|
2585
|
-
throw error;
|
|
2606
|
+
console.error("Error downloading probe binary:", error?.message || String(error));
|
|
2607
|
+
throw sanitizeError(error);
|
|
2586
2608
|
}
|
|
2587
2609
|
}
|
|
2588
2610
|
var exec, REPO_OWNER, REPO_NAME, BINARY_NAME, __filename2, __dirname2, downloadLocks, LOCK_TIMEOUT_MS, LOCK_POLL_INTERVAL_MS, MAX_LOCK_WAIT_MS;
|
|
@@ -2619,9 +2641,15 @@ async function getBinaryPath(options = {}) {
|
|
|
2619
2641
|
probeBinaryPath = await downloadProbeBinary(version);
|
|
2620
2642
|
return probeBinaryPath;
|
|
2621
2643
|
}
|
|
2622
|
-
const binDir = await getPackageBinDir();
|
|
2623
2644
|
const isWindows = process.platform === "win32";
|
|
2624
2645
|
const binaryName = isWindows ? "probe.exe" : "probe-binary";
|
|
2646
|
+
const localPackageBin = path3.resolve(__dirname3, "..", "bin");
|
|
2647
|
+
const localBinaryPath = path3.join(localPackageBin, binaryName);
|
|
2648
|
+
if (fs3.existsSync(localBinaryPath) && !forceDownload) {
|
|
2649
|
+
probeBinaryPath = localBinaryPath;
|
|
2650
|
+
return probeBinaryPath;
|
|
2651
|
+
}
|
|
2652
|
+
const binDir = await getPackageBinDir();
|
|
2625
2653
|
const binaryPath = path3.join(binDir, binaryName);
|
|
2626
2654
|
if (fs3.existsSync(binaryPath) && !forceDownload) {
|
|
2627
2655
|
probeBinaryPath = binaryPath;
|
|
@@ -2950,7 +2978,7 @@ Command: ${command}`;
|
|
|
2950
2978
|
}
|
|
2951
2979
|
}
|
|
2952
2980
|
function extractWithStdin(binaryPath, cliArgs, content, options) {
|
|
2953
|
-
return new Promise((
|
|
2981
|
+
return new Promise((resolve6, reject2) => {
|
|
2954
2982
|
const childProcess = spawn(binaryPath, ["extract", ...cliArgs], {
|
|
2955
2983
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2956
2984
|
});
|
|
@@ -2972,7 +3000,7 @@ function extractWithStdin(binaryPath, cliArgs, content, options) {
|
|
|
2972
3000
|
}
|
|
2973
3001
|
try {
|
|
2974
3002
|
const result = processExtractOutput(stdout, options);
|
|
2975
|
-
|
|
3003
|
+
resolve6(result);
|
|
2976
3004
|
} catch (error) {
|
|
2977
3005
|
reject2(error);
|
|
2978
3006
|
}
|
|
@@ -3063,6 +3091,262 @@ var init_grep = __esm({
|
|
|
3063
3091
|
}
|
|
3064
3092
|
});
|
|
3065
3093
|
|
|
3094
|
+
// src/delegate.js
|
|
3095
|
+
import { randomUUID } from "crypto";
|
|
3096
|
+
async function delegate({
|
|
3097
|
+
task,
|
|
3098
|
+
timeout = 300,
|
|
3099
|
+
debug = false,
|
|
3100
|
+
currentIteration = 0,
|
|
3101
|
+
maxIterations = 30,
|
|
3102
|
+
tracer = null,
|
|
3103
|
+
parentSessionId = null,
|
|
3104
|
+
path: path7 = null,
|
|
3105
|
+
provider = null,
|
|
3106
|
+
model = null
|
|
3107
|
+
}) {
|
|
3108
|
+
if (!task || typeof task !== "string") {
|
|
3109
|
+
throw new Error("Task parameter is required and must be a string");
|
|
3110
|
+
}
|
|
3111
|
+
const sessionId = randomUUID();
|
|
3112
|
+
const startTime = Date.now();
|
|
3113
|
+
const remainingIterations = Math.max(1, maxIterations - currentIteration);
|
|
3114
|
+
const delegationSpan = tracer ? tracer.createDelegationSpan(sessionId, task) : null;
|
|
3115
|
+
let timeoutId = null;
|
|
3116
|
+
let acquired = false;
|
|
3117
|
+
try {
|
|
3118
|
+
delegationManager.tryAcquire(parentSessionId);
|
|
3119
|
+
acquired = true;
|
|
3120
|
+
if (debug) {
|
|
3121
|
+
const stats = delegationManager.getStats();
|
|
3122
|
+
console.error(`[DELEGATE] Starting delegation session ${sessionId}`);
|
|
3123
|
+
console.error(`[DELEGATE] Parent session: ${parentSessionId || "none"}`);
|
|
3124
|
+
console.error(`[DELEGATE] Task: ${task}`);
|
|
3125
|
+
console.error(`[DELEGATE] Current iteration: ${currentIteration}/${maxIterations}`);
|
|
3126
|
+
console.error(`[DELEGATE] Remaining iterations for subagent: ${remainingIterations}`);
|
|
3127
|
+
console.error(`[DELEGATE] Timeout configured: ${timeout} seconds`);
|
|
3128
|
+
console.error(`[DELEGATE] Global active delegations: ${stats.globalActive}/${stats.maxConcurrent}`);
|
|
3129
|
+
console.error(`[DELEGATE] Using ProbeAgent SDK with code-researcher prompt`);
|
|
3130
|
+
}
|
|
3131
|
+
const subagent = new ProbeAgent({
|
|
3132
|
+
sessionId,
|
|
3133
|
+
promptType: "code-researcher",
|
|
3134
|
+
// Clean prompt, not inherited from parent
|
|
3135
|
+
enableDelegate: false,
|
|
3136
|
+
// Explicitly disable delegation to prevent recursion
|
|
3137
|
+
disableMermaidValidation: true,
|
|
3138
|
+
// Faster processing
|
|
3139
|
+
disableJsonValidation: true,
|
|
3140
|
+
// Simpler responses
|
|
3141
|
+
maxIterations: remainingIterations,
|
|
3142
|
+
debug,
|
|
3143
|
+
tracer,
|
|
3144
|
+
path: path7,
|
|
3145
|
+
// Inherit from parent
|
|
3146
|
+
provider,
|
|
3147
|
+
// Inherit from parent
|
|
3148
|
+
model
|
|
3149
|
+
// Inherit from parent
|
|
3150
|
+
});
|
|
3151
|
+
if (debug) {
|
|
3152
|
+
console.error(`[DELEGATE] Created subagent with session ${sessionId}`);
|
|
3153
|
+
console.error(`[DELEGATE] Subagent config: promptType=code-researcher, enableDelegate=false, maxIterations=${remainingIterations}`);
|
|
3154
|
+
}
|
|
3155
|
+
const timeoutPromise = new Promise((_, reject2) => {
|
|
3156
|
+
timeoutId = setTimeout(() => {
|
|
3157
|
+
reject2(new Error(`Delegation timed out after ${timeout} seconds`));
|
|
3158
|
+
}, timeout * 1e3);
|
|
3159
|
+
});
|
|
3160
|
+
const answerPromise = subagent.answer(task);
|
|
3161
|
+
const response = await Promise.race([answerPromise, timeoutPromise]);
|
|
3162
|
+
if (timeoutId !== null) {
|
|
3163
|
+
clearTimeout(timeoutId);
|
|
3164
|
+
timeoutId = null;
|
|
3165
|
+
}
|
|
3166
|
+
const duration = Date.now() - startTime;
|
|
3167
|
+
if (typeof response !== "string") {
|
|
3168
|
+
throw new Error("Delegate agent returned invalid response (not a string)");
|
|
3169
|
+
}
|
|
3170
|
+
const trimmedResponse = response.trim();
|
|
3171
|
+
if (trimmedResponse.length === 0) {
|
|
3172
|
+
throw new Error("Delegate agent returned empty or whitespace-only response");
|
|
3173
|
+
}
|
|
3174
|
+
if (trimmedResponse.includes("\0")) {
|
|
3175
|
+
throw new Error("Delegate agent returned response containing null bytes");
|
|
3176
|
+
}
|
|
3177
|
+
if (debug) {
|
|
3178
|
+
console.error(`[DELEGATE] Task completed successfully for session ${sessionId}`);
|
|
3179
|
+
console.error(`[DELEGATE] Duration: ${(duration / 1e3).toFixed(2)}s`);
|
|
3180
|
+
console.error(`[DELEGATE] Response length: ${response.length} chars`);
|
|
3181
|
+
}
|
|
3182
|
+
if (tracer) {
|
|
3183
|
+
tracer.recordDelegationEvent("completed", {
|
|
3184
|
+
"delegation.session_id": sessionId,
|
|
3185
|
+
"delegation.parent_session_id": parentSessionId,
|
|
3186
|
+
"delegation.duration_ms": duration,
|
|
3187
|
+
"delegation.response_length": response.length,
|
|
3188
|
+
"delegation.success": true
|
|
3189
|
+
});
|
|
3190
|
+
if (delegationSpan) {
|
|
3191
|
+
delegationSpan.setAttributes({
|
|
3192
|
+
"delegation.result.success": true,
|
|
3193
|
+
"delegation.result.response_length": response.length,
|
|
3194
|
+
"delegation.result.duration_ms": duration
|
|
3195
|
+
});
|
|
3196
|
+
delegationSpan.setStatus({ code: 1 });
|
|
3197
|
+
delegationSpan.end();
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
if (acquired) {
|
|
3201
|
+
delegationManager.release(parentSessionId, debug);
|
|
3202
|
+
}
|
|
3203
|
+
return response;
|
|
3204
|
+
} catch (error) {
|
|
3205
|
+
if (timeoutId !== null) {
|
|
3206
|
+
clearTimeout(timeoutId);
|
|
3207
|
+
timeoutId = null;
|
|
3208
|
+
}
|
|
3209
|
+
const duration = Date.now() - startTime;
|
|
3210
|
+
if (acquired) {
|
|
3211
|
+
delegationManager.release(parentSessionId, debug);
|
|
3212
|
+
}
|
|
3213
|
+
if (debug) {
|
|
3214
|
+
console.error(`[DELEGATE] Task failed for session ${sessionId} after ${duration}ms`);
|
|
3215
|
+
console.error(`[DELEGATE] Error: ${error.message}`);
|
|
3216
|
+
console.error(`[DELEGATE] Stack: ${error.stack}`);
|
|
3217
|
+
}
|
|
3218
|
+
if (tracer) {
|
|
3219
|
+
tracer.recordDelegationEvent("failed", {
|
|
3220
|
+
"delegation.session_id": sessionId,
|
|
3221
|
+
"delegation.parent_session_id": parentSessionId,
|
|
3222
|
+
"delegation.duration_ms": duration,
|
|
3223
|
+
"delegation.error_message": error.message,
|
|
3224
|
+
"delegation.success": false
|
|
3225
|
+
});
|
|
3226
|
+
if (delegationSpan) {
|
|
3227
|
+
delegationSpan.setAttributes({
|
|
3228
|
+
"delegation.result.success": false,
|
|
3229
|
+
"delegation.result.error": error.message,
|
|
3230
|
+
"delegation.result.duration_ms": duration
|
|
3231
|
+
});
|
|
3232
|
+
delegationSpan.setStatus({ code: 2, message: error.message });
|
|
3233
|
+
delegationSpan.end();
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
throw new Error(`Delegation failed: ${error.message}`);
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
var DelegationManager, delegationManager;
|
|
3240
|
+
var init_delegate = __esm({
|
|
3241
|
+
"src/delegate.js"() {
|
|
3242
|
+
"use strict";
|
|
3243
|
+
init_ProbeAgent();
|
|
3244
|
+
DelegationManager = class {
|
|
3245
|
+
constructor() {
|
|
3246
|
+
this.maxConcurrent = parseInt(process.env.MAX_CONCURRENT_DELEGATIONS || "3", 10);
|
|
3247
|
+
this.maxPerSession = parseInt(process.env.MAX_DELEGATIONS_PER_SESSION || "10", 10);
|
|
3248
|
+
this.sessionDelegations = /* @__PURE__ */ new Map();
|
|
3249
|
+
this.globalActive = 0;
|
|
3250
|
+
this.cleanupInterval = setInterval(() => {
|
|
3251
|
+
try {
|
|
3252
|
+
this.cleanupStaleSessions();
|
|
3253
|
+
} catch (error) {
|
|
3254
|
+
console.error("[DelegationManager] Error during cleanup:", error);
|
|
3255
|
+
}
|
|
3256
|
+
}, 5 * 60 * 1e3);
|
|
3257
|
+
if (this.cleanupInterval.unref) {
|
|
3258
|
+
this.cleanupInterval.unref();
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
/**
|
|
3262
|
+
* Check limits and increment counters (synchronous, atomic in Node.js event loop)
|
|
3263
|
+
* @param {string|null|undefined} parentSessionId - Parent session ID for tracking
|
|
3264
|
+
*/
|
|
3265
|
+
tryAcquire(parentSessionId) {
|
|
3266
|
+
if (parentSessionId !== null && parentSessionId !== void 0 && typeof parentSessionId !== "string") {
|
|
3267
|
+
throw new TypeError("parentSessionId must be a string, null, or undefined");
|
|
3268
|
+
}
|
|
3269
|
+
if (this.globalActive >= this.maxConcurrent) {
|
|
3270
|
+
throw new Error(`Maximum concurrent delegations (${this.maxConcurrent}) reached. Please wait for some delegations to complete.`);
|
|
3271
|
+
}
|
|
3272
|
+
if (parentSessionId) {
|
|
3273
|
+
const sessionData = this.sessionDelegations.get(parentSessionId);
|
|
3274
|
+
const sessionCount = sessionData?.count || 0;
|
|
3275
|
+
if (sessionCount >= this.maxPerSession) {
|
|
3276
|
+
throw new Error(`Maximum delegations per session (${this.maxPerSession}) reached for session ${parentSessionId}`);
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
this.globalActive++;
|
|
3280
|
+
if (parentSessionId) {
|
|
3281
|
+
const sessionData = this.sessionDelegations.get(parentSessionId);
|
|
3282
|
+
if (sessionData) {
|
|
3283
|
+
sessionData.count++;
|
|
3284
|
+
sessionData.lastUpdated = Date.now();
|
|
3285
|
+
} else {
|
|
3286
|
+
this.sessionDelegations.set(parentSessionId, {
|
|
3287
|
+
count: 1,
|
|
3288
|
+
lastUpdated: Date.now()
|
|
3289
|
+
});
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
return true;
|
|
3293
|
+
}
|
|
3294
|
+
/**
|
|
3295
|
+
* Decrement counters (synchronous, atomic in Node.js event loop)
|
|
3296
|
+
*/
|
|
3297
|
+
release(parentSessionId, debug = false) {
|
|
3298
|
+
this.globalActive = Math.max(0, this.globalActive - 1);
|
|
3299
|
+
if (parentSessionId) {
|
|
3300
|
+
const sessionData = this.sessionDelegations.get(parentSessionId);
|
|
3301
|
+
if (sessionData) {
|
|
3302
|
+
sessionData.count = Math.max(0, sessionData.count - 1);
|
|
3303
|
+
if (sessionData.count === 0) {
|
|
3304
|
+
this.sessionDelegations.delete(parentSessionId);
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
if (debug) {
|
|
3309
|
+
console.error(`[DELEGATE] Released. Global active: ${this.globalActive}`);
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
/**
|
|
3313
|
+
* Get current stats for monitoring
|
|
3314
|
+
*/
|
|
3315
|
+
getStats() {
|
|
3316
|
+
return {
|
|
3317
|
+
globalActive: this.globalActive,
|
|
3318
|
+
maxConcurrent: this.maxConcurrent,
|
|
3319
|
+
maxPerSession: this.maxPerSession,
|
|
3320
|
+
sessionCount: this.sessionDelegations.size
|
|
3321
|
+
};
|
|
3322
|
+
}
|
|
3323
|
+
/**
|
|
3324
|
+
* Clean up stale sessions (sessions with count=0 that haven't been updated in 1 hour)
|
|
3325
|
+
*/
|
|
3326
|
+
cleanupStaleSessions() {
|
|
3327
|
+
const oneHourAgo = Date.now() - 60 * 60 * 1e3;
|
|
3328
|
+
for (const [sessionId, data] of this.sessionDelegations.entries()) {
|
|
3329
|
+
if (data.count === 0 && data.lastUpdated < oneHourAgo) {
|
|
3330
|
+
this.sessionDelegations.delete(sessionId);
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
/**
|
|
3335
|
+
* Cleanup all resources (for testing or shutdown)
|
|
3336
|
+
*/
|
|
3337
|
+
cleanup() {
|
|
3338
|
+
if (this.cleanupInterval) {
|
|
3339
|
+
clearInterval(this.cleanupInterval);
|
|
3340
|
+
this.cleanupInterval = null;
|
|
3341
|
+
}
|
|
3342
|
+
this.sessionDelegations.clear();
|
|
3343
|
+
this.globalActive = 0;
|
|
3344
|
+
}
|
|
3345
|
+
};
|
|
3346
|
+
delegationManager = new DelegationManager();
|
|
3347
|
+
}
|
|
3348
|
+
});
|
|
3349
|
+
|
|
3066
3350
|
// node_modules/zod/v3/helpers/util.js
|
|
3067
3351
|
var util, objectUtil, ZodParsedType, getParsedType;
|
|
3068
3352
|
var init_util2 = __esm({
|
|
@@ -7276,7 +7560,7 @@ function parseTargets(targets) {
|
|
|
7276
7560
|
}
|
|
7277
7561
|
return targets.split(/\s+/).filter((f) => f.length > 0);
|
|
7278
7562
|
}
|
|
7279
|
-
var searchSchema, querySchema, extractSchema, delegateSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, 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;
|
|
7280
7564
|
var init_common = __esm({
|
|
7281
7565
|
"src/tools/common.js"() {
|
|
7282
7566
|
"use strict";
|
|
@@ -7289,11 +7573,12 @@ var init_common = __esm({
|
|
|
7289
7573
|
pattern: external_exports.string().describe("AST pattern to search for. Use $NAME for variable names, $$$PARAMS for parameter lists, etc."),
|
|
7290
7574
|
path: external_exports.string().optional().default(".").describe("Path to search in"),
|
|
7291
7575
|
language: external_exports.string().optional().default("rust").describe("Programming language to use for parsing"),
|
|
7292
|
-
allow_tests: external_exports.boolean().optional().default(
|
|
7576
|
+
allow_tests: external_exports.boolean().optional().default(true).describe("Allow test files in search results")
|
|
7293
7577
|
});
|
|
7294
7578
|
extractSchema = external_exports.object({
|
|
7295
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.'),
|
|
7296
|
-
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")
|
|
7297
7582
|
});
|
|
7298
7583
|
delegateSchema = external_exports.object({
|
|
7299
7584
|
task: external_exports.string().describe("The task to delegate to a subagent. Be specific about what needs to be accomplished.")
|
|
@@ -7420,7 +7705,7 @@ Parameters:
|
|
|
7420
7705
|
- pattern: (required) AST pattern to search for. Use $NAME for variable names, $$$PARAMS for parameter lists, etc.
|
|
7421
7706
|
- path: (optional, default: '.') Path to search in.
|
|
7422
7707
|
- language: (optional, default: 'rust') Programming language to use for parsing.
|
|
7423
|
-
- allow_tests: (optional, default:
|
|
7708
|
+
- allow_tests: (optional, default: true) Allow test files in search results (true/false).
|
|
7424
7709
|
Usage Example:
|
|
7425
7710
|
|
|
7426
7711
|
<examples>
|
|
@@ -7445,6 +7730,7 @@ Full file extraction should be the LAST RESORT! Always prefer search.
|
|
|
7445
7730
|
Parameters:
|
|
7446
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.
|
|
7447
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.
|
|
7448
7734
|
|
|
7449
7735
|
Usage Example:
|
|
7450
7736
|
|
|
@@ -7481,6 +7767,26 @@ User: Read file inside the dependency
|
|
|
7481
7767
|
</extract>
|
|
7482
7768
|
|
|
7483
7769
|
</examples>
|
|
7770
|
+
`;
|
|
7771
|
+
delegateToolDefinition = `
|
|
7772
|
+
## delegate
|
|
7773
|
+
Description: Automatically delegate big distinct tasks to specialized probe subagents within the agentic loop. Use this when you recognize that a user's request involves multiple large, distinct components that would benefit from parallel processing or specialized focus. The AI agent should automatically identify opportunities for task separation and use delegation without explicit user instruction.
|
|
7774
|
+
|
|
7775
|
+
Parameters:
|
|
7776
|
+
- task: (required) A complete, self-contained task that can be executed independently by a subagent. Should be specific and focused on one area of expertise.
|
|
7777
|
+
|
|
7778
|
+
Usage Pattern:
|
|
7779
|
+
When the AI agent encounters complex multi-part requests, it should automatically break them down and delegate:
|
|
7780
|
+
|
|
7781
|
+
<delegate>
|
|
7782
|
+
<task>Analyze all authentication and authorization code in the codebase for security vulnerabilities and provide specific remediation recommendations</task>
|
|
7783
|
+
</delegate>
|
|
7784
|
+
|
|
7785
|
+
<delegate>
|
|
7786
|
+
<task>Review database queries and API endpoints for performance bottlenecks and suggest optimization strategies</task>
|
|
7787
|
+
</delegate>
|
|
7788
|
+
|
|
7789
|
+
The agent uses this tool automatically when it identifies that work can be separated into distinct, parallel tasks for more efficient processing.
|
|
7484
7790
|
`;
|
|
7485
7791
|
attemptCompletionToolDefinition = `
|
|
7486
7792
|
## attempt_completion
|
|
@@ -7491,6 +7797,61 @@ Usage Example:
|
|
|
7491
7797
|
<attempt_completion>
|
|
7492
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.
|
|
7493
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>
|
|
7494
7855
|
`;
|
|
7495
7856
|
searchDescription = "Search code in the repository using Elasticsearch-like query syntax. Use this tool first for any code-related questions.";
|
|
7496
7857
|
queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
|
|
@@ -7509,193 +7870,6 @@ I have refactored the search module according to the requirements and verified t
|
|
|
7509
7870
|
}
|
|
7510
7871
|
});
|
|
7511
7872
|
|
|
7512
|
-
// src/delegate.js
|
|
7513
|
-
import { spawn as spawn2 } from "child_process";
|
|
7514
|
-
import { randomUUID } from "crypto";
|
|
7515
|
-
async function delegate({ task, timeout = 300, debug = false, currentIteration = 0, maxIterations = 30, tracer = null }) {
|
|
7516
|
-
if (!task || typeof task !== "string") {
|
|
7517
|
-
throw new Error("Task parameter is required and must be a string");
|
|
7518
|
-
}
|
|
7519
|
-
const sessionId = randomUUID();
|
|
7520
|
-
const startTime = Date.now();
|
|
7521
|
-
const remainingIterations = Math.max(1, maxIterations - currentIteration);
|
|
7522
|
-
if (debug) {
|
|
7523
|
-
console.error(`[DELEGATE] Starting delegation session ${sessionId}`);
|
|
7524
|
-
console.error(`[DELEGATE] Task: ${task}`);
|
|
7525
|
-
console.error(`[DELEGATE] Current iteration: ${currentIteration}/${maxIterations}`);
|
|
7526
|
-
console.error(`[DELEGATE] Remaining iterations for subagent: ${remainingIterations}`);
|
|
7527
|
-
console.error(`[DELEGATE] Timeout configured: ${timeout} seconds`);
|
|
7528
|
-
console.error(`[DELEGATE] Using clean agent environment with code-researcher prompt`);
|
|
7529
|
-
}
|
|
7530
|
-
try {
|
|
7531
|
-
const binaryPath = await getBinaryPath();
|
|
7532
|
-
const args = [
|
|
7533
|
-
"agent",
|
|
7534
|
-
"--task",
|
|
7535
|
-
task,
|
|
7536
|
-
"--session-id",
|
|
7537
|
-
sessionId,
|
|
7538
|
-
"--prompt-type",
|
|
7539
|
-
"code-researcher",
|
|
7540
|
-
// Automatically use default code researcher prompt
|
|
7541
|
-
"--no-schema-validation",
|
|
7542
|
-
// Automatically disable schema validation
|
|
7543
|
-
"--no-mermaid-validation",
|
|
7544
|
-
// Automatically disable mermaid validation
|
|
7545
|
-
"--max-iterations",
|
|
7546
|
-
remainingIterations.toString()
|
|
7547
|
-
// Automatically limit to remaining iterations
|
|
7548
|
-
];
|
|
7549
|
-
if (debug) {
|
|
7550
|
-
args.push("--debug");
|
|
7551
|
-
console.error(`[DELEGATE] Using binary at: ${binaryPath}`);
|
|
7552
|
-
console.error(`[DELEGATE] Command args: ${args.join(" ")}`);
|
|
7553
|
-
}
|
|
7554
|
-
return new Promise((resolve5, reject2) => {
|
|
7555
|
-
const delegationSpan = tracer ? tracer.createDelegationSpan(sessionId, task) : null;
|
|
7556
|
-
const process2 = spawn2(binaryPath, args, {
|
|
7557
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
7558
|
-
timeout: timeout * 1e3
|
|
7559
|
-
});
|
|
7560
|
-
let stdout = "";
|
|
7561
|
-
let stderr = "";
|
|
7562
|
-
let isResolved = false;
|
|
7563
|
-
process2.stdout.on("data", (data) => {
|
|
7564
|
-
const chunk = data.toString();
|
|
7565
|
-
stdout += chunk;
|
|
7566
|
-
if (debug) {
|
|
7567
|
-
const preview = createMessagePreview(chunk);
|
|
7568
|
-
console.error(`[DELEGATE] stdout chunk received (${chunk.length} chars): ${preview}`);
|
|
7569
|
-
}
|
|
7570
|
-
});
|
|
7571
|
-
process2.stderr.on("data", (data) => {
|
|
7572
|
-
const chunk = data.toString();
|
|
7573
|
-
stderr += chunk;
|
|
7574
|
-
if (debug) {
|
|
7575
|
-
const preview = createMessagePreview(chunk);
|
|
7576
|
-
console.error(`[DELEGATE] stderr chunk received (${chunk.length} chars): ${preview}`);
|
|
7577
|
-
}
|
|
7578
|
-
});
|
|
7579
|
-
process2.on("close", (code) => {
|
|
7580
|
-
if (isResolved) return;
|
|
7581
|
-
isResolved = true;
|
|
7582
|
-
const duration = Date.now() - startTime;
|
|
7583
|
-
if (debug) {
|
|
7584
|
-
console.error(`[DELEGATE] Process completed with code ${code} in ${duration}ms`);
|
|
7585
|
-
console.error(`[DELEGATE] Duration: ${(duration / 1e3).toFixed(2)}s`);
|
|
7586
|
-
console.error(`[DELEGATE] Total stdout: ${stdout.length} chars`);
|
|
7587
|
-
console.error(`[DELEGATE] Total stderr: ${stderr.length} chars`);
|
|
7588
|
-
}
|
|
7589
|
-
if (code === 0) {
|
|
7590
|
-
const response = stdout.trim();
|
|
7591
|
-
if (!response) {
|
|
7592
|
-
if (debug) {
|
|
7593
|
-
console.error(`[DELEGATE] Task completed but returned empty response for session ${sessionId}`);
|
|
7594
|
-
}
|
|
7595
|
-
reject2(new Error("Delegate agent returned empty response"));
|
|
7596
|
-
return;
|
|
7597
|
-
}
|
|
7598
|
-
if (debug) {
|
|
7599
|
-
console.error(`[DELEGATE] Task completed successfully for session ${sessionId}`);
|
|
7600
|
-
console.error(`[DELEGATE] Response length: ${response.length} chars`);
|
|
7601
|
-
}
|
|
7602
|
-
if (tracer) {
|
|
7603
|
-
tracer.recordDelegationEvent("completed", {
|
|
7604
|
-
"delegation.session_id": sessionId,
|
|
7605
|
-
"delegation.duration_ms": duration,
|
|
7606
|
-
"delegation.response_length": response.length,
|
|
7607
|
-
"delegation.success": true
|
|
7608
|
-
});
|
|
7609
|
-
if (delegationSpan) {
|
|
7610
|
-
delegationSpan.setAttributes({
|
|
7611
|
-
"delegation.result.success": true,
|
|
7612
|
-
"delegation.result.response_length": response.length,
|
|
7613
|
-
"delegation.result.duration_ms": duration
|
|
7614
|
-
});
|
|
7615
|
-
delegationSpan.setStatus({ code: 1 });
|
|
7616
|
-
delegationSpan.end();
|
|
7617
|
-
}
|
|
7618
|
-
}
|
|
7619
|
-
resolve5(response);
|
|
7620
|
-
} else {
|
|
7621
|
-
const errorMessage = stderr.trim() || `Delegate process failed with exit code ${code}`;
|
|
7622
|
-
if (debug) {
|
|
7623
|
-
console.error(`[DELEGATE] Task failed for session ${sessionId} with code ${code}`);
|
|
7624
|
-
console.error(`[DELEGATE] Error message: ${errorMessage}`);
|
|
7625
|
-
}
|
|
7626
|
-
if (tracer) {
|
|
7627
|
-
tracer.recordDelegationEvent("failed", {
|
|
7628
|
-
"delegation.session_id": sessionId,
|
|
7629
|
-
"delegation.duration_ms": duration,
|
|
7630
|
-
"delegation.exit_code": code,
|
|
7631
|
-
"delegation.error_message": errorMessage,
|
|
7632
|
-
"delegation.success": false
|
|
7633
|
-
});
|
|
7634
|
-
if (delegationSpan) {
|
|
7635
|
-
delegationSpan.setAttributes({
|
|
7636
|
-
"delegation.result.success": false,
|
|
7637
|
-
"delegation.result.exit_code": code,
|
|
7638
|
-
"delegation.result.error": errorMessage,
|
|
7639
|
-
"delegation.result.duration_ms": duration
|
|
7640
|
-
});
|
|
7641
|
-
delegationSpan.setStatus({ code: 2, message: errorMessage });
|
|
7642
|
-
delegationSpan.end();
|
|
7643
|
-
}
|
|
7644
|
-
}
|
|
7645
|
-
reject2(new Error(`Delegation failed: ${errorMessage}`));
|
|
7646
|
-
}
|
|
7647
|
-
});
|
|
7648
|
-
process2.on("error", (error) => {
|
|
7649
|
-
if (isResolved) return;
|
|
7650
|
-
isResolved = true;
|
|
7651
|
-
const duration = Date.now() - startTime;
|
|
7652
|
-
if (debug) {
|
|
7653
|
-
console.error(`[DELEGATE] Process spawn error after ${duration}ms:`, error);
|
|
7654
|
-
console.error(`[DELEGATE] Session ${sessionId} failed during process creation`);
|
|
7655
|
-
console.error(`[DELEGATE] Error type: ${error.code || "unknown"}`);
|
|
7656
|
-
}
|
|
7657
|
-
reject2(new Error(`Failed to start delegate process: ${error.message}`));
|
|
7658
|
-
});
|
|
7659
|
-
setTimeout(() => {
|
|
7660
|
-
if (isResolved) return;
|
|
7661
|
-
isResolved = true;
|
|
7662
|
-
const duration = Date.now() - startTime;
|
|
7663
|
-
if (debug) {
|
|
7664
|
-
console.error(`[DELEGATE] Process timeout after ${(duration / 1e3).toFixed(2)}s (limit: ${timeout}s)`);
|
|
7665
|
-
console.error(`[DELEGATE] Terminating session ${sessionId} due to timeout`);
|
|
7666
|
-
console.error(`[DELEGATE] Partial stdout: ${stdout.substring(0, 500)}${stdout.length > 500 ? "..." : ""}`);
|
|
7667
|
-
console.error(`[DELEGATE] Partial stderr: ${stderr.substring(0, 500)}${stderr.length > 500 ? "..." : ""}`);
|
|
7668
|
-
}
|
|
7669
|
-
process2.kill("SIGTERM");
|
|
7670
|
-
setTimeout(() => {
|
|
7671
|
-
if (!process2.killed) {
|
|
7672
|
-
if (debug) {
|
|
7673
|
-
console.error(`[DELEGATE] Force killing process ${sessionId} after graceful timeout`);
|
|
7674
|
-
}
|
|
7675
|
-
process2.kill("SIGKILL");
|
|
7676
|
-
}
|
|
7677
|
-
}, 5e3);
|
|
7678
|
-
reject2(new Error(`Delegation timed out after ${timeout} seconds`));
|
|
7679
|
-
}, timeout * 1e3);
|
|
7680
|
-
});
|
|
7681
|
-
} catch (error) {
|
|
7682
|
-
const duration = Date.now() - startTime;
|
|
7683
|
-
if (debug) {
|
|
7684
|
-
console.error(`[DELEGATE] Error in delegate function after ${duration}ms:`, error);
|
|
7685
|
-
console.error(`[DELEGATE] Session ${sessionId} failed during setup`);
|
|
7686
|
-
console.error(`[DELEGATE] Error stack: ${error.stack}`);
|
|
7687
|
-
}
|
|
7688
|
-
throw new Error(`Delegation setup failed: ${error.message}`);
|
|
7689
|
-
}
|
|
7690
|
-
}
|
|
7691
|
-
var init_delegate = __esm({
|
|
7692
|
-
"src/delegate.js"() {
|
|
7693
|
-
"use strict";
|
|
7694
|
-
init_utils();
|
|
7695
|
-
init_common();
|
|
7696
|
-
}
|
|
7697
|
-
});
|
|
7698
|
-
|
|
7699
7873
|
// src/tools/vercel.js
|
|
7700
7874
|
import { tool } from "ai";
|
|
7701
7875
|
var searchTool, queryTool, extractTool, delegateTool;
|
|
@@ -7868,21 +8042,50 @@ var init_vercel = __esm({
|
|
|
7868
8042
|
name: "delegate",
|
|
7869
8043
|
description: delegateDescription,
|
|
7870
8044
|
inputSchema: delegateSchema,
|
|
7871
|
-
execute: async ({ task }) => {
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
8045
|
+
execute: async ({ task, currentIteration, maxIterations, parentSessionId, path: path7, provider, model, tracer }) => {
|
|
8046
|
+
if (!task || typeof task !== "string") {
|
|
8047
|
+
throw new Error("Task parameter is required and must be a non-empty string");
|
|
8048
|
+
}
|
|
8049
|
+
if (task.trim().length === 0) {
|
|
8050
|
+
throw new Error("Task parameter cannot be empty or whitespace only");
|
|
8051
|
+
}
|
|
8052
|
+
if (currentIteration !== void 0 && (typeof currentIteration !== "number" || currentIteration < 0)) {
|
|
8053
|
+
throw new Error("currentIteration must be a non-negative number");
|
|
8054
|
+
}
|
|
8055
|
+
if (maxIterations !== void 0 && (typeof maxIterations !== "number" || maxIterations < 1)) {
|
|
8056
|
+
throw new Error("maxIterations must be a positive number");
|
|
8057
|
+
}
|
|
8058
|
+
if (parentSessionId !== void 0 && parentSessionId !== null && typeof parentSessionId !== "string") {
|
|
8059
|
+
throw new TypeError("parentSessionId must be a string, null, or undefined");
|
|
7885
8060
|
}
|
|
8061
|
+
if (path7 !== void 0 && path7 !== null && typeof path7 !== "string") {
|
|
8062
|
+
throw new TypeError("path must be a string, null, or undefined");
|
|
8063
|
+
}
|
|
8064
|
+
if (provider !== void 0 && provider !== null && typeof provider !== "string") {
|
|
8065
|
+
throw new TypeError("provider must be a string, null, or undefined");
|
|
8066
|
+
}
|
|
8067
|
+
if (model !== void 0 && model !== null && typeof model !== "string") {
|
|
8068
|
+
throw new TypeError("model must be a string, null, or undefined");
|
|
8069
|
+
}
|
|
8070
|
+
if (debug) {
|
|
8071
|
+
console.error(`Executing delegate with task: "${task.substring(0, 100)}${task.length > 100 ? "..." : ""}"`);
|
|
8072
|
+
if (parentSessionId) {
|
|
8073
|
+
console.error(`Parent session: ${parentSessionId}`);
|
|
8074
|
+
}
|
|
8075
|
+
}
|
|
8076
|
+
const result = await delegate({
|
|
8077
|
+
task,
|
|
8078
|
+
timeout,
|
|
8079
|
+
debug,
|
|
8080
|
+
currentIteration: currentIteration || 0,
|
|
8081
|
+
maxIterations: maxIterations || 30,
|
|
8082
|
+
parentSessionId,
|
|
8083
|
+
path: path7,
|
|
8084
|
+
provider,
|
|
8085
|
+
model,
|
|
8086
|
+
tracer
|
|
8087
|
+
});
|
|
8088
|
+
return result;
|
|
7886
8089
|
}
|
|
7887
8090
|
});
|
|
7888
8091
|
};
|
|
@@ -8711,7 +8914,7 @@ var init_bashPermissions = __esm({
|
|
|
8711
8914
|
});
|
|
8712
8915
|
|
|
8713
8916
|
// src/agent/bashExecutor.js
|
|
8714
|
-
import { spawn as
|
|
8917
|
+
import { spawn as spawn2 } from "child_process";
|
|
8715
8918
|
import { resolve, join } from "path";
|
|
8716
8919
|
import { existsSync } from "fs";
|
|
8717
8920
|
async function executeBashCommand(command, options = {}) {
|
|
@@ -8748,14 +8951,14 @@ async function executeBashCommand(command, options = {}) {
|
|
|
8748
8951
|
console.log(`[BashExecutor] Working directory: "${cwd}"`);
|
|
8749
8952
|
console.log(`[BashExecutor] Timeout: ${timeout}ms`);
|
|
8750
8953
|
}
|
|
8751
|
-
return new Promise((
|
|
8954
|
+
return new Promise((resolve6, reject2) => {
|
|
8752
8955
|
const processEnv = {
|
|
8753
8956
|
...process.env,
|
|
8754
8957
|
...env
|
|
8755
8958
|
};
|
|
8756
8959
|
const args = parseCommandForExecution(command);
|
|
8757
8960
|
if (!args || args.length === 0) {
|
|
8758
|
-
|
|
8961
|
+
resolve6({
|
|
8759
8962
|
success: false,
|
|
8760
8963
|
error: "Failed to parse command",
|
|
8761
8964
|
stdout: "",
|
|
@@ -8768,7 +8971,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
8768
8971
|
return;
|
|
8769
8972
|
}
|
|
8770
8973
|
const [cmd, ...cmdArgs] = args;
|
|
8771
|
-
const child =
|
|
8974
|
+
const child = spawn2(cmd, cmdArgs, {
|
|
8772
8975
|
cwd,
|
|
8773
8976
|
env: processEnv,
|
|
8774
8977
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -8838,7 +9041,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
8838
9041
|
success = false;
|
|
8839
9042
|
error = `Command exited with code ${code}`;
|
|
8840
9043
|
}
|
|
8841
|
-
|
|
9044
|
+
resolve6({
|
|
8842
9045
|
success,
|
|
8843
9046
|
error,
|
|
8844
9047
|
stdout: stdout.trim(),
|
|
@@ -8858,7 +9061,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
8858
9061
|
if (debug) {
|
|
8859
9062
|
console.log(`[BashExecutor] Spawn error:`, error);
|
|
8860
9063
|
}
|
|
8861
|
-
|
|
9064
|
+
resolve6({
|
|
8862
9065
|
success: false,
|
|
8863
9066
|
error: `Failed to execute command: ${error.message}`,
|
|
8864
9067
|
stdout: "",
|
|
@@ -9130,6 +9333,283 @@ Command failed with exit code ${result.exitCode}`;
|
|
|
9130
9333
|
}
|
|
9131
9334
|
});
|
|
9132
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
|
+
|
|
9133
9613
|
// src/tools/langchain.js
|
|
9134
9614
|
var init_langchain = __esm({
|
|
9135
9615
|
"src/tools/langchain.js"() {
|
|
@@ -9279,8 +9759,10 @@ var init_tools = __esm({
|
|
|
9279
9759
|
"use strict";
|
|
9280
9760
|
init_vercel();
|
|
9281
9761
|
init_bash();
|
|
9762
|
+
init_edit();
|
|
9282
9763
|
init_langchain();
|
|
9283
9764
|
init_common();
|
|
9765
|
+
init_edit();
|
|
9284
9766
|
init_system_message();
|
|
9285
9767
|
init_vercel();
|
|
9286
9768
|
init_bash();
|
|
@@ -9297,7 +9779,7 @@ var init_tools = __esm({
|
|
|
9297
9779
|
});
|
|
9298
9780
|
|
|
9299
9781
|
// src/utils/file-lister.js
|
|
9300
|
-
import
|
|
9782
|
+
import fs5 from "fs";
|
|
9301
9783
|
import path4 from "path";
|
|
9302
9784
|
import { promisify as promisify6 } from "util";
|
|
9303
9785
|
import { exec as exec4 } from "child_process";
|
|
@@ -9307,10 +9789,10 @@ async function listFilesByLevel(options) {
|
|
|
9307
9789
|
maxFiles = 100,
|
|
9308
9790
|
respectGitignore = true
|
|
9309
9791
|
} = options;
|
|
9310
|
-
if (!
|
|
9792
|
+
if (!fs5.existsSync(directory)) {
|
|
9311
9793
|
throw new Error(`Directory does not exist: ${directory}`);
|
|
9312
9794
|
}
|
|
9313
|
-
const gitDirExists =
|
|
9795
|
+
const gitDirExists = fs5.existsSync(path4.join(directory, ".git"));
|
|
9314
9796
|
if (gitDirExists && respectGitignore) {
|
|
9315
9797
|
try {
|
|
9316
9798
|
return await listFilesUsingGit(directory, maxFiles);
|
|
@@ -9341,7 +9823,7 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
|
|
|
9341
9823
|
while (queue.length > 0 && result.length < maxFiles) {
|
|
9342
9824
|
const { dir, level } = queue.shift();
|
|
9343
9825
|
try {
|
|
9344
|
-
const entries =
|
|
9826
|
+
const entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
9345
9827
|
const files = entries.filter((entry) => entry.isFile());
|
|
9346
9828
|
for (const file of files) {
|
|
9347
9829
|
if (result.length >= maxFiles) break;
|
|
@@ -9366,11 +9848,11 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
|
|
|
9366
9848
|
}
|
|
9367
9849
|
function loadGitignorePatterns(directory) {
|
|
9368
9850
|
const gitignorePath = path4.join(directory, ".gitignore");
|
|
9369
|
-
if (!
|
|
9851
|
+
if (!fs5.existsSync(gitignorePath)) {
|
|
9370
9852
|
return [];
|
|
9371
9853
|
}
|
|
9372
9854
|
try {
|
|
9373
|
-
const content =
|
|
9855
|
+
const content = fs5.readFileSync(gitignorePath, "utf8");
|
|
9374
9856
|
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
9375
9857
|
} catch (error) {
|
|
9376
9858
|
console.error(`Warning: Could not read .gitignore: ${error.message}`);
|
|
@@ -9397,8 +9879,8 @@ var init_file_lister = __esm({
|
|
|
9397
9879
|
});
|
|
9398
9880
|
|
|
9399
9881
|
// src/agent/simpleTelemetry.js
|
|
9400
|
-
import { existsSync as
|
|
9401
|
-
import { dirname } from "path";
|
|
9882
|
+
import { existsSync as existsSync3, mkdirSync, createWriteStream } from "fs";
|
|
9883
|
+
import { dirname as dirname2 } from "path";
|
|
9402
9884
|
function initializeSimpleTelemetryFromOptions(options) {
|
|
9403
9885
|
const telemetry = new SimpleTelemetry({
|
|
9404
9886
|
serviceName: "probe-agent",
|
|
@@ -9425,8 +9907,8 @@ var init_simpleTelemetry = __esm({
|
|
|
9425
9907
|
}
|
|
9426
9908
|
initializeFileExporter() {
|
|
9427
9909
|
try {
|
|
9428
|
-
const dir =
|
|
9429
|
-
if (!
|
|
9910
|
+
const dir = dirname2(this.filePath);
|
|
9911
|
+
if (!existsSync3(dir)) {
|
|
9430
9912
|
mkdirSync(dir, { recursive: true });
|
|
9431
9913
|
}
|
|
9432
9914
|
this.stream = createWriteStream(this.filePath, { flags: "a" });
|
|
@@ -9490,20 +9972,20 @@ var init_simpleTelemetry = __esm({
|
|
|
9490
9972
|
}
|
|
9491
9973
|
async flush() {
|
|
9492
9974
|
if (this.stream) {
|
|
9493
|
-
return new Promise((
|
|
9494
|
-
this.stream.once("drain",
|
|
9975
|
+
return new Promise((resolve6) => {
|
|
9976
|
+
this.stream.once("drain", resolve6);
|
|
9495
9977
|
if (!this.stream.writableNeedDrain) {
|
|
9496
|
-
|
|
9978
|
+
resolve6();
|
|
9497
9979
|
}
|
|
9498
9980
|
});
|
|
9499
9981
|
}
|
|
9500
9982
|
}
|
|
9501
9983
|
async shutdown() {
|
|
9502
9984
|
if (this.stream) {
|
|
9503
|
-
return new Promise((
|
|
9985
|
+
return new Promise((resolve6) => {
|
|
9504
9986
|
this.stream.end(() => {
|
|
9505
9987
|
console.log(`[SimpleTelemetry] File stream closed: ${this.filePath}`);
|
|
9506
|
-
|
|
9988
|
+
resolve6();
|
|
9507
9989
|
});
|
|
9508
9990
|
});
|
|
9509
9991
|
}
|
|
@@ -10466,7 +10948,7 @@ var init_escape = __esm({
|
|
|
10466
10948
|
});
|
|
10467
10949
|
|
|
10468
10950
|
// node_modules/minimatch/dist/esm/index.js
|
|
10469
|
-
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;
|
|
10470
10952
|
var init_esm = __esm({
|
|
10471
10953
|
"node_modules/minimatch/dist/esm/index.js"() {
|
|
10472
10954
|
import_brace_expansion = __toESM(require_brace_expansion(), 1);
|
|
@@ -10539,8 +11021,8 @@ var init_esm = __esm({
|
|
|
10539
11021
|
win32: { sep: "\\" },
|
|
10540
11022
|
posix: { sep: "/" }
|
|
10541
11023
|
};
|
|
10542
|
-
|
|
10543
|
-
minimatch.sep =
|
|
11024
|
+
sep2 = defaultPlatform === "win32" ? path5.win32.sep : path5.posix.sep;
|
|
11025
|
+
minimatch.sep = sep2;
|
|
10544
11026
|
GLOBSTAR = Symbol("globstar **");
|
|
10545
11027
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
10546
11028
|
qmark2 = "[^/]";
|
|
@@ -13302,10 +13784,10 @@ var init_esm3 = __esm({
|
|
|
13302
13784
|
* Return a void Promise that resolves once the stream ends.
|
|
13303
13785
|
*/
|
|
13304
13786
|
async promise() {
|
|
13305
|
-
return new Promise((
|
|
13787
|
+
return new Promise((resolve6, reject2) => {
|
|
13306
13788
|
this.on(DESTROYED, () => reject2(new Error("stream destroyed")));
|
|
13307
13789
|
this.on("error", (er) => reject2(er));
|
|
13308
|
-
this.on("end", () =>
|
|
13790
|
+
this.on("end", () => resolve6());
|
|
13309
13791
|
});
|
|
13310
13792
|
}
|
|
13311
13793
|
/**
|
|
@@ -13329,7 +13811,7 @@ var init_esm3 = __esm({
|
|
|
13329
13811
|
return Promise.resolve({ done: false, value: res });
|
|
13330
13812
|
if (this[EOF])
|
|
13331
13813
|
return stop();
|
|
13332
|
-
let
|
|
13814
|
+
let resolve6;
|
|
13333
13815
|
let reject2;
|
|
13334
13816
|
const onerr = (er) => {
|
|
13335
13817
|
this.off("data", ondata);
|
|
@@ -13343,19 +13825,19 @@ var init_esm3 = __esm({
|
|
|
13343
13825
|
this.off("end", onend);
|
|
13344
13826
|
this.off(DESTROYED, ondestroy);
|
|
13345
13827
|
this.pause();
|
|
13346
|
-
|
|
13828
|
+
resolve6({ value, done: !!this[EOF] });
|
|
13347
13829
|
};
|
|
13348
13830
|
const onend = () => {
|
|
13349
13831
|
this.off("error", onerr);
|
|
13350
13832
|
this.off("data", ondata);
|
|
13351
13833
|
this.off(DESTROYED, ondestroy);
|
|
13352
13834
|
stop();
|
|
13353
|
-
|
|
13835
|
+
resolve6({ done: true, value: void 0 });
|
|
13354
13836
|
};
|
|
13355
13837
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
13356
13838
|
return new Promise((res2, rej) => {
|
|
13357
13839
|
reject2 = rej;
|
|
13358
|
-
|
|
13840
|
+
resolve6 = res2;
|
|
13359
13841
|
this.once(DESTROYED, ondestroy);
|
|
13360
13842
|
this.once("error", onerr);
|
|
13361
13843
|
this.once("end", onend);
|
|
@@ -14335,9 +14817,9 @@ var init_esm4 = __esm({
|
|
|
14335
14817
|
if (this.#asyncReaddirInFlight) {
|
|
14336
14818
|
await this.#asyncReaddirInFlight;
|
|
14337
14819
|
} else {
|
|
14338
|
-
let
|
|
14820
|
+
let resolve6 = () => {
|
|
14339
14821
|
};
|
|
14340
|
-
this.#asyncReaddirInFlight = new Promise((res) =>
|
|
14822
|
+
this.#asyncReaddirInFlight = new Promise((res) => resolve6 = res);
|
|
14341
14823
|
try {
|
|
14342
14824
|
for (const e of await this.#fs.promises.readdir(fullpath, {
|
|
14343
14825
|
withFileTypes: true
|
|
@@ -14350,7 +14832,7 @@ var init_esm4 = __esm({
|
|
|
14350
14832
|
children.provisional = 0;
|
|
14351
14833
|
}
|
|
14352
14834
|
this.#asyncReaddirInFlight = void 0;
|
|
14353
|
-
|
|
14835
|
+
resolve6();
|
|
14354
14836
|
}
|
|
14355
14837
|
return children.slice(0, children.provisional);
|
|
14356
14838
|
}
|
|
@@ -14580,8 +15062,8 @@ var init_esm4 = __esm({
|
|
|
14580
15062
|
*
|
|
14581
15063
|
* @internal
|
|
14582
15064
|
*/
|
|
14583
|
-
constructor(cwd = process.cwd(), pathImpl,
|
|
14584
|
-
this.#fs = fsFromOption(
|
|
15065
|
+
constructor(cwd = process.cwd(), pathImpl, sep3, { nocase, childrenCacheSize = 16 * 1024, fs: fs7 = defaultFS } = {}) {
|
|
15066
|
+
this.#fs = fsFromOption(fs7);
|
|
14585
15067
|
if (cwd instanceof URL || cwd.startsWith("file://")) {
|
|
14586
15068
|
cwd = fileURLToPath4(cwd);
|
|
14587
15069
|
}
|
|
@@ -14591,7 +15073,7 @@ var init_esm4 = __esm({
|
|
|
14591
15073
|
this.#resolveCache = new ResolveCache();
|
|
14592
15074
|
this.#resolvePosixCache = new ResolveCache();
|
|
14593
15075
|
this.#children = new ChildrenCache(childrenCacheSize);
|
|
14594
|
-
const split = cwdPath.substring(this.rootPath.length).split(
|
|
15076
|
+
const split = cwdPath.substring(this.rootPath.length).split(sep3);
|
|
14595
15077
|
if (split.length === 1 && !split[0]) {
|
|
14596
15078
|
split.pop();
|
|
14597
15079
|
}
|
|
@@ -15139,8 +15621,8 @@ var init_esm4 = __esm({
|
|
|
15139
15621
|
/**
|
|
15140
15622
|
* @internal
|
|
15141
15623
|
*/
|
|
15142
|
-
newRoot(
|
|
15143
|
-
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 });
|
|
15144
15626
|
}
|
|
15145
15627
|
/**
|
|
15146
15628
|
* Return true if the provided path string is an absolute path
|
|
@@ -15168,8 +15650,8 @@ var init_esm4 = __esm({
|
|
|
15168
15650
|
/**
|
|
15169
15651
|
* @internal
|
|
15170
15652
|
*/
|
|
15171
|
-
newRoot(
|
|
15172
|
-
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 });
|
|
15173
15655
|
}
|
|
15174
15656
|
/**
|
|
15175
15657
|
* Return true if the provided path string is an absolute path
|
|
@@ -16309,7 +16791,7 @@ import { exec as exec5 } from "child_process";
|
|
|
16309
16791
|
import { promisify as promisify7 } from "util";
|
|
16310
16792
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
16311
16793
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
16312
|
-
import
|
|
16794
|
+
import fs6 from "fs";
|
|
16313
16795
|
import { promises as fsPromises } from "fs";
|
|
16314
16796
|
import path6 from "path";
|
|
16315
16797
|
function isSessionCancelled(sessionId) {
|
|
@@ -16369,6 +16851,20 @@ function createWrappedTools(baseTools) {
|
|
|
16369
16851
|
baseTools.bashTool.execute
|
|
16370
16852
|
);
|
|
16371
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
|
+
}
|
|
16372
16868
|
return wrappedTools;
|
|
16373
16869
|
}
|
|
16374
16870
|
var toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
|
|
@@ -16379,9 +16875,9 @@ var init_probeTool = __esm({
|
|
|
16379
16875
|
init_esm5();
|
|
16380
16876
|
toolCallEmitter = new EventEmitter2();
|
|
16381
16877
|
activeToolExecutions = /* @__PURE__ */ new Map();
|
|
16382
|
-
wrapToolWithEmitter = (
|
|
16878
|
+
wrapToolWithEmitter = (tool4, toolName, baseExecute) => {
|
|
16383
16879
|
return {
|
|
16384
|
-
...
|
|
16880
|
+
...tool4,
|
|
16385
16881
|
// Spread schema, description etc.
|
|
16386
16882
|
execute: async (params) => {
|
|
16387
16883
|
const debug = process.env.DEBUG === "1";
|
|
@@ -16616,8 +17112,10 @@ var init_index = __esm({
|
|
|
16616
17112
|
init_file_lister();
|
|
16617
17113
|
init_system_message();
|
|
16618
17114
|
init_common();
|
|
17115
|
+
init_edit();
|
|
16619
17116
|
init_vercel();
|
|
16620
17117
|
init_bash();
|
|
17118
|
+
init_edit();
|
|
16621
17119
|
init_ProbeAgent();
|
|
16622
17120
|
init_simpleTelemetry();
|
|
16623
17121
|
init_probeTool();
|
|
@@ -16699,8 +17197,8 @@ function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
|
|
|
16699
17197
|
function hasOtherToolTags(xmlString, validTools = []) {
|
|
16700
17198
|
const defaultTools = ["search", "query", "extract", "listFiles", "searchFiles", "implement", "attempt_completion"];
|
|
16701
17199
|
const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
|
|
16702
|
-
for (const
|
|
16703
|
-
if (
|
|
17200
|
+
for (const tool4 of toolsToCheck) {
|
|
17201
|
+
if (tool4 !== "attempt_completion" && xmlString.includes(`<${tool4}`)) {
|
|
16704
17202
|
return true;
|
|
16705
17203
|
}
|
|
16706
17204
|
}
|
|
@@ -16738,6 +17236,10 @@ function createTools(configOptions) {
|
|
|
16738
17236
|
if (configOptions.enableBash) {
|
|
16739
17237
|
tools2.bashTool = bashTool(configOptions);
|
|
16740
17238
|
}
|
|
17239
|
+
if (configOptions.allowEdit) {
|
|
17240
|
+
tools2.editTool = editTool(configOptions);
|
|
17241
|
+
tools2.createTool = createTool(configOptions);
|
|
17242
|
+
}
|
|
16741
17243
|
return tools2;
|
|
16742
17244
|
}
|
|
16743
17245
|
function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
@@ -16838,7 +17340,7 @@ function createMockProvider() {
|
|
|
16838
17340
|
provider: "mock",
|
|
16839
17341
|
// Mock the doGenerate method used by Vercel AI SDK
|
|
16840
17342
|
doGenerate: async ({ messages, tools: tools2 }) => {
|
|
16841
|
-
await new Promise((
|
|
17343
|
+
await new Promise((resolve6) => setTimeout(resolve6, 10));
|
|
16842
17344
|
return {
|
|
16843
17345
|
text: "This is a mock response for testing",
|
|
16844
17346
|
toolCalls: [],
|
|
@@ -28825,16 +29327,6 @@ var init_parser2 = __esm({
|
|
|
28825
29327
|
this.subgraph = this.RULE("subgraph", () => {
|
|
28826
29328
|
this.CONSUME(SubgraphKeyword);
|
|
28827
29329
|
this.OR([
|
|
28828
|
-
{
|
|
28829
|
-
ALT: () => {
|
|
28830
|
-
this.CONSUME(Identifier, { LABEL: "subgraphId" });
|
|
28831
|
-
this.OPTION(() => {
|
|
28832
|
-
this.CONSUME1(SquareOpen);
|
|
28833
|
-
this.SUBRULE(this.nodeContent);
|
|
28834
|
-
this.CONSUME1(SquareClose);
|
|
28835
|
-
});
|
|
28836
|
-
}
|
|
28837
|
-
},
|
|
28838
29330
|
{
|
|
28839
29331
|
ALT: () => {
|
|
28840
29332
|
this.CONSUME(QuotedString, { LABEL: "subgraphTitleQ" });
|
|
@@ -28846,6 +29338,33 @@ var init_parser2 = __esm({
|
|
|
28846
29338
|
this.SUBRULE2(this.nodeContent);
|
|
28847
29339
|
this.CONSUME2(SquareClose);
|
|
28848
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
|
+
}
|
|
28849
29368
|
}
|
|
28850
29369
|
]);
|
|
28851
29370
|
this.CONSUME(Newline);
|
|
@@ -29449,7 +29968,6 @@ var init_semantics = __esm({
|
|
|
29449
29968
|
const last2 = allChildren[allChildren.length - 1];
|
|
29450
29969
|
const isSlash = (t) => t.image === "/" || t.image === "\\";
|
|
29451
29970
|
if (isSlash(first2) && isSlash(last2)) {
|
|
29452
|
-
continue;
|
|
29453
29971
|
}
|
|
29454
29972
|
}
|
|
29455
29973
|
const opens = ch.RoundOpen || [];
|
|
@@ -29929,13 +30447,24 @@ function mapFlowchartParserError(err, text) {
|
|
|
29929
30447
|
length: len
|
|
29930
30448
|
};
|
|
29931
30449
|
}
|
|
29932
|
-
if (tokType === "QuotedString") {
|
|
30450
|
+
if (tokType === "QuotedString" || tokType === "SquareOpen" || tokType === "SquareClose") {
|
|
29933
30451
|
const context = err?.context;
|
|
29934
30452
|
const inLinkRule = context?.ruleStack?.includes("linkTextInline") || context?.ruleStack?.includes("link") || false;
|
|
29935
30453
|
const lineContent = allLines[Math.max(0, line - 1)] || "";
|
|
29936
30454
|
const beforeQuote = lineContent.slice(0, Math.max(0, column - 1));
|
|
29937
30455
|
const hasLinkBefore = beforeQuote.match(/--\s*$|==\s*$|-\.\s*$|-\.-\s*$|\[\s*$/);
|
|
29938
30456
|
if (inLinkRule || hasLinkBefore) {
|
|
30457
|
+
if (tokType === "SquareOpen" || tokType === "SquareClose") {
|
|
30458
|
+
return {
|
|
30459
|
+
line,
|
|
30460
|
+
column,
|
|
30461
|
+
severity: "error",
|
|
30462
|
+
code: "FL-EDGE-LABEL-BRACKET",
|
|
30463
|
+
message: "Square brackets [ ] are not supported inside inline edge labels.",
|
|
30464
|
+
hint: "Use HTML entities [ and ] inside |...|, e.g., --|run: [aggregate]|-->",
|
|
30465
|
+
length: len
|
|
30466
|
+
};
|
|
30467
|
+
}
|
|
29939
30468
|
const quotedText = found.startsWith('"') ? found.slice(1, -1) : found;
|
|
29940
30469
|
return {
|
|
29941
30470
|
line,
|
|
@@ -30029,7 +30558,7 @@ function mapFlowchartParserError(err, text) {
|
|
|
30029
30558
|
}
|
|
30030
30559
|
}
|
|
30031
30560
|
}
|
|
30032
|
-
if (tokType === "QuotedString") {
|
|
30561
|
+
if (tokType === "QuotedString" || tokType === "SquareOpen" || tokType === "SquareClose") {
|
|
30033
30562
|
return {
|
|
30034
30563
|
line,
|
|
30035
30564
|
column,
|
|
@@ -30050,7 +30579,7 @@ function mapFlowchartParserError(err, text) {
|
|
|
30050
30579
|
return { line, column, severity: "error", code: "FL-NODE-UNCLOSED-BRACKET", message: "Unclosed '['. Add a matching ']' before the arrow or newline.", hint: "Example: A[Label] --> B", length: 1 };
|
|
30051
30580
|
}
|
|
30052
30581
|
if (expecting(err, "RoundClose")) {
|
|
30053
|
-
if (tokType === "QuotedString") {
|
|
30582
|
+
if (tokType === "QuotedString" || tokType === "SquareOpen" || tokType === "SquareClose") {
|
|
30054
30583
|
return {
|
|
30055
30584
|
line,
|
|
30056
30585
|
column,
|
|
@@ -30089,7 +30618,7 @@ function mapFlowchartParserError(err, text) {
|
|
|
30089
30618
|
return { line, column, severity: "error", code: "FL-NODE-UNCLOSED-BRACKET", message: "Unclosed '('. Add a matching ')'.", hint: "Example: B(Label)", length: 1 };
|
|
30090
30619
|
}
|
|
30091
30620
|
if (expecting(err, "DiamondClose")) {
|
|
30092
|
-
if (tokType === "QuotedString") {
|
|
30621
|
+
if (tokType === "QuotedString" || tokType === "SquareOpen" || tokType === "SquareClose") {
|
|
30093
30622
|
return {
|
|
30094
30623
|
line,
|
|
30095
30624
|
column,
|
|
@@ -30232,16 +30761,19 @@ function mapFlowchartParserError(err, text) {
|
|
|
30232
30761
|
const subgraphIdx = lineStr.indexOf("subgraph");
|
|
30233
30762
|
if (subgraphIdx !== -1) {
|
|
30234
30763
|
const afterSubgraph = lineStr.slice(subgraphIdx + 8).trim();
|
|
30235
|
-
if (afterSubgraph && !afterSubgraph.startsWith('"') && !afterSubgraph.startsWith("'")
|
|
30236
|
-
|
|
30237
|
-
|
|
30238
|
-
|
|
30239
|
-
|
|
30240
|
-
|
|
30241
|
-
|
|
30242
|
-
|
|
30243
|
-
|
|
30244
|
-
|
|
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
|
+
}
|
|
30245
30777
|
}
|
|
30246
30778
|
}
|
|
30247
30779
|
}
|
|
@@ -30935,6 +31467,111 @@ function validateFlowchart(text, options = {}) {
|
|
|
30935
31467
|
}
|
|
30936
31468
|
}
|
|
30937
31469
|
}
|
|
31470
|
+
{
|
|
31471
|
+
const byLine = /* @__PURE__ */ new Map();
|
|
31472
|
+
const collect = (arr) => {
|
|
31473
|
+
for (const e of arr || []) {
|
|
31474
|
+
if (e && (e.code === "FL-LABEL-PARENS-UNQUOTED" || e.code === "FL-LABEL-AT-IN-UNQUOTED")) {
|
|
31475
|
+
const ln = e.line ?? 0;
|
|
31476
|
+
const col = e.column ?? 1;
|
|
31477
|
+
const list = byLine.get(ln) || [];
|
|
31478
|
+
list.push({ start: col, end: col });
|
|
31479
|
+
byLine.set(ln, list);
|
|
31480
|
+
}
|
|
31481
|
+
}
|
|
31482
|
+
};
|
|
31483
|
+
collect(prevErrors);
|
|
31484
|
+
collect(errs);
|
|
31485
|
+
const lines2 = text2.split(/\r?\n/);
|
|
31486
|
+
for (let ii = 0; ii < lines2.length; ii++) {
|
|
31487
|
+
const raw = lines2[ii] || "";
|
|
31488
|
+
if (!raw.includes("[") || !raw.includes("]"))
|
|
31489
|
+
continue;
|
|
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
|
+
}
|
|
31570
|
+
}
|
|
31571
|
+
i++;
|
|
31572
|
+
}
|
|
31573
|
+
}
|
|
31574
|
+
}
|
|
30938
31575
|
const dblEsc = (text2.match(/\\\"/g) || []).length;
|
|
30939
31576
|
const dq = (text2.match(/\"/g) || []).length - dblEsc;
|
|
30940
31577
|
const sq = (text2.match(/'/g) || []).length;
|
|
@@ -33279,6 +33916,21 @@ function computeFixes(text, errors, level = "safe") {
|
|
|
33279
33916
|
}
|
|
33280
33917
|
continue;
|
|
33281
33918
|
}
|
|
33919
|
+
if (is("FL-EDGE-LABEL-BRACKET", e)) {
|
|
33920
|
+
const lineText = lineTextAt(text, e.line);
|
|
33921
|
+
const firstBar = lineText.indexOf("|");
|
|
33922
|
+
const secondBar = firstBar >= 0 ? lineText.indexOf("|", firstBar + 1) : -1;
|
|
33923
|
+
if (firstBar >= 0 && secondBar > firstBar) {
|
|
33924
|
+
const before = lineText.slice(0, firstBar + 1);
|
|
33925
|
+
const label = lineText.slice(firstBar + 1, secondBar);
|
|
33926
|
+
const after = lineText.slice(secondBar);
|
|
33927
|
+
const fixedLabel = label.replace(/\[/g, "[").replace(/\]/g, "]");
|
|
33928
|
+
const fixedLine = before + fixedLabel + after;
|
|
33929
|
+
const finalLine = fixedLine.replace(/\[([^\]]*)\]/g, (m, seg) => "[" + String(seg).replace(/`/g, "") + "]");
|
|
33930
|
+
edits.push({ start: { line: e.line, column: 1 }, end: { line: e.line, column: lineText.length + 1 }, newText: finalLine });
|
|
33931
|
+
}
|
|
33932
|
+
continue;
|
|
33933
|
+
}
|
|
33282
33934
|
if (is("FL-EDGE-LABEL-BACKTICK", e)) {
|
|
33283
33935
|
const lineText = lineTextAt(text, e.line);
|
|
33284
33936
|
const re = /^(.*?--)\s*([^|>]+?)\s*(-->|==>|\.->|->)(.*)$/;
|
|
@@ -42402,7 +43054,7 @@ var require_bk = __commonJS({
|
|
|
42402
43054
|
return xs;
|
|
42403
43055
|
}
|
|
42404
43056
|
function buildBlockGraph(g, layering, root2, reverseSep) {
|
|
42405
|
-
var blockGraph = new Graph(), graphLabel = g.graph(), sepFn =
|
|
43057
|
+
var blockGraph = new Graph(), graphLabel = g.graph(), sepFn = sep3(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
|
|
42406
43058
|
_.forEach(layering, function(layer) {
|
|
42407
43059
|
var u;
|
|
42408
43060
|
_.forEach(layer, function(v) {
|
|
@@ -42492,7 +43144,7 @@ var require_bk = __commonJS({
|
|
|
42492
43144
|
alignCoordinates(xss, smallestWidth);
|
|
42493
43145
|
return balance(xss, g.graph().align);
|
|
42494
43146
|
}
|
|
42495
|
-
function
|
|
43147
|
+
function sep3(nodeSep, edgeSep, reverseSep) {
|
|
42496
43148
|
return function(g, v, w) {
|
|
42497
43149
|
var vLabel = g.node(v);
|
|
42498
43150
|
var wLabel = g.node(w);
|
|
@@ -49786,7 +50438,7 @@ var require_compile = __commonJS({
|
|
|
49786
50438
|
const schOrFunc = root2.refs[ref];
|
|
49787
50439
|
if (schOrFunc)
|
|
49788
50440
|
return schOrFunc;
|
|
49789
|
-
let _sch =
|
|
50441
|
+
let _sch = resolve6.call(this, root2, ref);
|
|
49790
50442
|
if (_sch === void 0) {
|
|
49791
50443
|
const schema = (_a = root2.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
49792
50444
|
const { schemaId } = this.opts;
|
|
@@ -49813,7 +50465,7 @@ var require_compile = __commonJS({
|
|
|
49813
50465
|
function sameSchemaEnv(s1, s2) {
|
|
49814
50466
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
49815
50467
|
}
|
|
49816
|
-
function
|
|
50468
|
+
function resolve6(root2, ref) {
|
|
49817
50469
|
let sch;
|
|
49818
50470
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
49819
50471
|
ref = sch;
|
|
@@ -50388,7 +51040,7 @@ var require_fast_uri = __commonJS({
|
|
|
50388
51040
|
}
|
|
50389
51041
|
return uri;
|
|
50390
51042
|
}
|
|
50391
|
-
function
|
|
51043
|
+
function resolve6(baseURI, relativeURI, options) {
|
|
50392
51044
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
50393
51045
|
const resolved = resolveComponent(parse6(baseURI, schemelessOptions), parse6(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
50394
51046
|
schemelessOptions.skipEscape = true;
|
|
@@ -50615,7 +51267,7 @@ var require_fast_uri = __commonJS({
|
|
|
50615
51267
|
var fastUri = {
|
|
50616
51268
|
SCHEMES,
|
|
50617
51269
|
normalize: normalize2,
|
|
50618
|
-
resolve:
|
|
51270
|
+
resolve: resolve6,
|
|
50619
51271
|
resolveComponent,
|
|
50620
51272
|
equal,
|
|
50621
51273
|
serialize,
|
|
@@ -54633,15 +55285,15 @@ Provide only the corrected Mermaid diagram within a mermaid code block. Do not a
|
|
|
54633
55285
|
});
|
|
54634
55286
|
|
|
54635
55287
|
// src/agent/mcp/config.js
|
|
54636
|
-
import { readFileSync, existsSync as
|
|
54637
|
-
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";
|
|
54638
55290
|
import { homedir } from "os";
|
|
54639
55291
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
54640
55292
|
function loadMCPConfigurationFromPath(configPath) {
|
|
54641
55293
|
if (!configPath) {
|
|
54642
55294
|
throw new Error("Config path is required");
|
|
54643
55295
|
}
|
|
54644
|
-
if (!
|
|
55296
|
+
if (!existsSync4(configPath)) {
|
|
54645
55297
|
throw new Error(`MCP configuration file not found: ${configPath}`);
|
|
54646
55298
|
}
|
|
54647
55299
|
try {
|
|
@@ -54670,7 +55322,7 @@ function loadMCPConfiguration() {
|
|
|
54670
55322
|
].filter(Boolean);
|
|
54671
55323
|
let config = null;
|
|
54672
55324
|
for (const configPath of configPaths) {
|
|
54673
|
-
if (
|
|
55325
|
+
if (existsSync4(configPath)) {
|
|
54674
55326
|
try {
|
|
54675
55327
|
const content = readFileSync(configPath, "utf8");
|
|
54676
55328
|
config = JSON.parse(content);
|
|
@@ -54773,7 +55425,7 @@ var init_config = __esm({
|
|
|
54773
55425
|
"src/agent/mcp/config.js"() {
|
|
54774
55426
|
"use strict";
|
|
54775
55427
|
__filename4 = fileURLToPath6(import.meta.url);
|
|
54776
|
-
__dirname4 =
|
|
55428
|
+
__dirname4 = dirname3(__filename4);
|
|
54777
55429
|
DEFAULT_CONFIG = {
|
|
54778
55430
|
mcpServers: {
|
|
54779
55431
|
// Example probe server configuration
|
|
@@ -54962,12 +55614,12 @@ var init_client = __esm({
|
|
|
54962
55614
|
const toolsResponse = await client.listTools();
|
|
54963
55615
|
const toolCount = toolsResponse?.tools?.length || 0;
|
|
54964
55616
|
if (toolsResponse && toolsResponse.tools) {
|
|
54965
|
-
for (const
|
|
54966
|
-
const qualifiedName = `${name}_${
|
|
55617
|
+
for (const tool4 of toolsResponse.tools) {
|
|
55618
|
+
const qualifiedName = `${name}_${tool4.name}`;
|
|
54967
55619
|
this.tools.set(qualifiedName, {
|
|
54968
|
-
...
|
|
55620
|
+
...tool4,
|
|
54969
55621
|
serverName: name,
|
|
54970
|
-
originalName:
|
|
55622
|
+
originalName: tool4.name
|
|
54971
55623
|
});
|
|
54972
55624
|
if (this.debug) {
|
|
54973
55625
|
console.error(`[MCP DEBUG] Registered tool: ${qualifiedName}`);
|
|
@@ -54990,13 +55642,13 @@ var init_client = __esm({
|
|
|
54990
55642
|
* @param {Object} args - Tool arguments
|
|
54991
55643
|
*/
|
|
54992
55644
|
async callTool(toolName, args) {
|
|
54993
|
-
const
|
|
54994
|
-
if (!
|
|
55645
|
+
const tool4 = this.tools.get(toolName);
|
|
55646
|
+
if (!tool4) {
|
|
54995
55647
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
54996
55648
|
}
|
|
54997
|
-
const clientInfo = this.clients.get(
|
|
55649
|
+
const clientInfo = this.clients.get(tool4.serverName);
|
|
54998
55650
|
if (!clientInfo) {
|
|
54999
|
-
throw new Error(`Server ${
|
|
55651
|
+
throw new Error(`Server ${tool4.serverName} not connected`);
|
|
55000
55652
|
}
|
|
55001
55653
|
try {
|
|
55002
55654
|
if (this.debug) {
|
|
@@ -55010,7 +55662,7 @@ var init_client = __esm({
|
|
|
55010
55662
|
});
|
|
55011
55663
|
const result = await Promise.race([
|
|
55012
55664
|
clientInfo.client.callTool({
|
|
55013
|
-
name:
|
|
55665
|
+
name: tool4.originalName,
|
|
55014
55666
|
arguments: args
|
|
55015
55667
|
}),
|
|
55016
55668
|
timeoutPromise
|
|
@@ -55033,11 +55685,11 @@ var init_client = __esm({
|
|
|
55033
55685
|
*/
|
|
55034
55686
|
getTools() {
|
|
55035
55687
|
const tools2 = {};
|
|
55036
|
-
for (const [name,
|
|
55688
|
+
for (const [name, tool4] of this.tools.entries()) {
|
|
55037
55689
|
tools2[name] = {
|
|
55038
|
-
description:
|
|
55039
|
-
inputSchema:
|
|
55040
|
-
serverName:
|
|
55690
|
+
description: tool4.description,
|
|
55691
|
+
inputSchema: tool4.inputSchema,
|
|
55692
|
+
serverName: tool4.serverName
|
|
55041
55693
|
};
|
|
55042
55694
|
}
|
|
55043
55695
|
return tools2;
|
|
@@ -55048,10 +55700,10 @@ var init_client = __esm({
|
|
|
55048
55700
|
*/
|
|
55049
55701
|
getVercelTools() {
|
|
55050
55702
|
const tools2 = {};
|
|
55051
|
-
for (const [name,
|
|
55703
|
+
for (const [name, tool4] of this.tools.entries()) {
|
|
55052
55704
|
tools2[name] = {
|
|
55053
|
-
description:
|
|
55054
|
-
inputSchema:
|
|
55705
|
+
description: tool4.description,
|
|
55706
|
+
inputSchema: tool4.inputSchema,
|
|
55055
55707
|
execute: async (args) => {
|
|
55056
55708
|
const result = await this.callTool(name, args);
|
|
55057
55709
|
if (result.content && result.content[0]) {
|
|
@@ -55100,9 +55752,9 @@ var init_client = __esm({
|
|
|
55100
55752
|
});
|
|
55101
55753
|
|
|
55102
55754
|
// src/agent/mcp/xmlBridge.js
|
|
55103
|
-
function mcpToolToXmlDefinition(name,
|
|
55104
|
-
const description =
|
|
55105
|
-
const inputSchema =
|
|
55755
|
+
function mcpToolToXmlDefinition(name, tool4) {
|
|
55756
|
+
const description = tool4.description || "MCP tool";
|
|
55757
|
+
const inputSchema = tool4.inputSchema || tool4.parameters || {};
|
|
55106
55758
|
let paramDocs = "";
|
|
55107
55759
|
if (inputSchema.properties) {
|
|
55108
55760
|
paramDocs = "\n\nParameters (provide as JSON object):";
|
|
@@ -55281,8 +55933,8 @@ var init_xmlBridge = __esm({
|
|
|
55281
55933
|
const vercelTools = this.mcpManager.getVercelTools();
|
|
55282
55934
|
this.mcpTools = vercelTools;
|
|
55283
55935
|
const toolCount = Object.keys(vercelTools).length;
|
|
55284
|
-
for (const [name,
|
|
55285
|
-
this.xmlDefinitions[name] = mcpToolToXmlDefinition(name,
|
|
55936
|
+
for (const [name, tool4] of Object.entries(vercelTools)) {
|
|
55937
|
+
this.xmlDefinitions[name] = mcpToolToXmlDefinition(name, tool4);
|
|
55286
55938
|
}
|
|
55287
55939
|
if (toolCount === 0) {
|
|
55288
55940
|
console.error("[MCP INFO] MCP initialization complete: 0 tools loaded");
|
|
@@ -55329,14 +55981,14 @@ var init_xmlBridge = __esm({
|
|
|
55329
55981
|
console.error(`[MCP DEBUG] Executing MCP tool: ${toolName}`);
|
|
55330
55982
|
console.error(`[MCP DEBUG] Parameters:`, JSON.stringify(params, null, 2));
|
|
55331
55983
|
}
|
|
55332
|
-
const
|
|
55333
|
-
if (!
|
|
55984
|
+
const tool4 = this.mcpTools[toolName];
|
|
55985
|
+
if (!tool4) {
|
|
55334
55986
|
console.error(`[MCP ERROR] Unknown MCP tool: ${toolName}`);
|
|
55335
55987
|
console.error(`[MCP ERROR] Available tools: ${this.getToolNames().join(", ")}`);
|
|
55336
55988
|
throw new Error(`Unknown MCP tool: ${toolName}`);
|
|
55337
55989
|
}
|
|
55338
55990
|
try {
|
|
55339
|
-
const result = await
|
|
55991
|
+
const result = await tool4.execute(params);
|
|
55340
55992
|
if (this.debug) {
|
|
55341
55993
|
console.error(`[MCP DEBUG] Tool ${toolName} executed successfully`);
|
|
55342
55994
|
}
|
|
@@ -55390,22 +56042,636 @@ var init_mcp = __esm({
|
|
|
55390
56042
|
}
|
|
55391
56043
|
});
|
|
55392
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
|
+
|
|
55393
56659
|
// src/agent/ProbeAgent.js
|
|
55394
56660
|
var ProbeAgent_exports = {};
|
|
55395
56661
|
__export(ProbeAgent_exports, {
|
|
55396
56662
|
ProbeAgent: () => ProbeAgent
|
|
55397
56663
|
});
|
|
55398
56664
|
import dotenv2 from "dotenv";
|
|
55399
|
-
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
55400
|
-
import { createOpenAI } from "@ai-sdk/openai";
|
|
55401
|
-
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
55402
|
-
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";
|
|
55403
56669
|
import { streamText } from "ai";
|
|
55404
56670
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
55405
56671
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
55406
|
-
import { existsSync as
|
|
56672
|
+
import { existsSync as existsSync5 } from "fs";
|
|
55407
56673
|
import { readFile, stat } from "fs/promises";
|
|
55408
|
-
import { resolve as
|
|
56674
|
+
import { resolve as resolve4, isAbsolute as isAbsolute2, dirname as dirname4 } from "path";
|
|
55409
56675
|
var MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
|
|
55410
56676
|
var init_ProbeAgent = __esm({
|
|
55411
56677
|
"src/agent/ProbeAgent.js"() {
|
|
@@ -55422,8 +56688,17 @@ var init_ProbeAgent = __esm({
|
|
|
55422
56688
|
init_schemaUtils();
|
|
55423
56689
|
init_xmlParsingUtils();
|
|
55424
56690
|
init_mcp();
|
|
56691
|
+
init_RetryManager();
|
|
56692
|
+
init_FallbackManager();
|
|
55425
56693
|
dotenv2.config();
|
|
55426
|
-
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
|
+
})();
|
|
55427
56702
|
MAX_HISTORY_MESSAGES = 100;
|
|
55428
56703
|
MAX_IMAGE_FILE_SIZE = 20 * 1024 * 1024;
|
|
55429
56704
|
ProbeAgent = class _ProbeAgent {
|
|
@@ -55434,6 +56709,7 @@ var init_ProbeAgent = __esm({
|
|
|
55434
56709
|
* @param {string} [options.customPrompt] - Custom prompt to replace the default system message
|
|
55435
56710
|
* @param {string} [options.promptType] - Predefined prompt type (architect, code-review, support)
|
|
55436
56711
|
* @param {boolean} [options.allowEdit=false] - Allow the use of the 'implement' tool
|
|
56712
|
+
* @param {boolean} [options.enableDelegate=false] - Enable the delegate tool for task distribution to subagents
|
|
55437
56713
|
* @param {string} [options.path] - Search directory path
|
|
55438
56714
|
* @param {string} [options.provider] - Force specific AI provider
|
|
55439
56715
|
* @param {string} [options.model] - Override model name
|
|
@@ -55449,17 +56725,36 @@ var init_ProbeAgent = __esm({
|
|
|
55449
56725
|
* @param {Array} [options.mcpServers] - Deprecated, use mcpConfig instead
|
|
55450
56726
|
* @param {Object} [options.storageAdapter] - Custom storage adapter for history management
|
|
55451
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
|
|
55452
56740
|
*/
|
|
55453
56741
|
constructor(options = {}) {
|
|
55454
56742
|
this.sessionId = options.sessionId || randomUUID4();
|
|
55455
56743
|
this.customPrompt = options.customPrompt || null;
|
|
55456
56744
|
this.promptType = options.promptType || "code-explorer";
|
|
55457
56745
|
this.allowEdit = !!options.allowEdit;
|
|
56746
|
+
this.enableDelegate = !!options.enableDelegate;
|
|
55458
56747
|
this.debug = options.debug || process.env.DEBUG === "1";
|
|
55459
56748
|
this.cancelled = false;
|
|
55460
56749
|
this.tracer = options.tracer || null;
|
|
55461
56750
|
this.outline = !!options.outline;
|
|
55462
|
-
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
|
+
})();
|
|
55463
56758
|
this.maxIterations = options.maxIterations || null;
|
|
55464
56759
|
this.disableMermaidValidation = !!options.disableMermaidValidation;
|
|
55465
56760
|
this.disableJsonValidation = !!options.disableJsonValidation;
|
|
@@ -55500,6 +56795,10 @@ var init_ProbeAgent = __esm({
|
|
|
55500
56795
|
this.mcpServers = options.mcpServers || null;
|
|
55501
56796
|
this.mcpBridge = null;
|
|
55502
56797
|
this._mcpInitialized = false;
|
|
56798
|
+
this.retryConfig = options.retry || {};
|
|
56799
|
+
this.retryManager = null;
|
|
56800
|
+
this.fallbackConfig = options.fallback || null;
|
|
56801
|
+
this.fallbackManager = null;
|
|
55503
56802
|
this.initializeModel();
|
|
55504
56803
|
}
|
|
55505
56804
|
/**
|
|
@@ -55584,6 +56883,14 @@ var init_ProbeAgent = __esm({
|
|
|
55584
56883
|
if (this.enableBash && wrappedTools.bashToolInstance) {
|
|
55585
56884
|
this.toolImplementations.bash = wrappedTools.bashToolInstance;
|
|
55586
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
|
+
}
|
|
55587
56894
|
this.wrappedTools = wrappedTools;
|
|
55588
56895
|
if (this.debug) {
|
|
55589
56896
|
console.error("\n[DEBUG] ========================================");
|
|
@@ -55634,36 +56941,147 @@ var init_ProbeAgent = __esm({
|
|
|
55634
56941
|
if (forceProvider) {
|
|
55635
56942
|
if (forceProvider === "anthropic" && anthropicApiKey) {
|
|
55636
56943
|
this.initializeAnthropicModel(anthropicApiKey, anthropicApiUrl, modelName);
|
|
56944
|
+
this.initializeFallbackManager(forceProvider, modelName);
|
|
55637
56945
|
return;
|
|
55638
56946
|
} else if (forceProvider === "openai" && openaiApiKey) {
|
|
55639
56947
|
this.initializeOpenAIModel(openaiApiKey, openaiApiUrl, modelName);
|
|
56948
|
+
this.initializeFallbackManager(forceProvider, modelName);
|
|
55640
56949
|
return;
|
|
55641
56950
|
} else if (forceProvider === "google" && googleApiKey) {
|
|
55642
56951
|
this.initializeGoogleModel(googleApiKey, googleApiUrl, modelName);
|
|
56952
|
+
this.initializeFallbackManager(forceProvider, modelName);
|
|
55643
56953
|
return;
|
|
55644
56954
|
} else if (forceProvider === "bedrock" && (awsAccessKeyId && awsSecretAccessKey && awsRegion || awsApiKey)) {
|
|
55645
56955
|
this.initializeBedrockModel(awsAccessKeyId, awsSecretAccessKey, awsRegion, awsSessionToken, awsApiKey, awsBedrockBaseUrl, modelName);
|
|
56956
|
+
this.initializeFallbackManager(forceProvider, modelName);
|
|
55646
56957
|
return;
|
|
55647
56958
|
}
|
|
55648
56959
|
console.warn(`WARNING: Forced provider "${forceProvider}" selected but required API key is missing or invalid! Falling back to auto-detection.`);
|
|
55649
56960
|
}
|
|
55650
56961
|
if (anthropicApiKey) {
|
|
55651
56962
|
this.initializeAnthropicModel(anthropicApiKey, anthropicApiUrl, modelName);
|
|
56963
|
+
this.initializeFallbackManager("anthropic", modelName);
|
|
55652
56964
|
} else if (openaiApiKey) {
|
|
55653
56965
|
this.initializeOpenAIModel(openaiApiKey, openaiApiUrl, modelName);
|
|
56966
|
+
this.initializeFallbackManager("openai", modelName);
|
|
55654
56967
|
} else if (googleApiKey) {
|
|
55655
56968
|
this.initializeGoogleModel(googleApiKey, googleApiUrl, modelName);
|
|
56969
|
+
this.initializeFallbackManager("google", modelName);
|
|
55656
56970
|
} else if (awsAccessKeyId && awsSecretAccessKey && awsRegion || awsApiKey) {
|
|
55657
56971
|
this.initializeBedrockModel(awsAccessKeyId, awsSecretAccessKey, awsRegion, awsSessionToken, awsApiKey, awsBedrockBaseUrl, modelName);
|
|
56972
|
+
this.initializeFallbackManager("bedrock", modelName);
|
|
55658
56973
|
} else {
|
|
55659
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.");
|
|
55660
56975
|
}
|
|
55661
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
|
+
}
|
|
55662
57080
|
/**
|
|
55663
57081
|
* Initialize Anthropic model
|
|
55664
57082
|
*/
|
|
55665
57083
|
initializeAnthropicModel(apiKey, apiUrl, modelName) {
|
|
55666
|
-
this.provider =
|
|
57084
|
+
this.provider = createAnthropic2({
|
|
55667
57085
|
apiKey,
|
|
55668
57086
|
...apiUrl && { baseURL: apiUrl }
|
|
55669
57087
|
});
|
|
@@ -55677,7 +57095,7 @@ var init_ProbeAgent = __esm({
|
|
|
55677
57095
|
* Initialize OpenAI model
|
|
55678
57096
|
*/
|
|
55679
57097
|
initializeOpenAIModel(apiKey, apiUrl, modelName) {
|
|
55680
|
-
this.provider =
|
|
57098
|
+
this.provider = createOpenAI2({
|
|
55681
57099
|
compatibility: "strict",
|
|
55682
57100
|
apiKey,
|
|
55683
57101
|
...apiUrl && { baseURL: apiUrl }
|
|
@@ -55692,7 +57110,7 @@ var init_ProbeAgent = __esm({
|
|
|
55692
57110
|
* Initialize Google model
|
|
55693
57111
|
*/
|
|
55694
57112
|
initializeGoogleModel(apiKey, apiUrl, modelName) {
|
|
55695
|
-
this.provider =
|
|
57113
|
+
this.provider = createGoogleGenerativeAI2({
|
|
55696
57114
|
apiKey,
|
|
55697
57115
|
...apiUrl && { baseURL: apiUrl }
|
|
55698
57116
|
});
|
|
@@ -55722,7 +57140,7 @@ var init_ProbeAgent = __esm({
|
|
|
55722
57140
|
if (baseURL) {
|
|
55723
57141
|
config.baseURL = baseURL;
|
|
55724
57142
|
}
|
|
55725
|
-
this.provider =
|
|
57143
|
+
this.provider = createAmazonBedrock2(config);
|
|
55726
57144
|
this.model = modelName || "anthropic.claude-sonnet-4-20250514-v1:0";
|
|
55727
57145
|
this.apiType = "bedrock";
|
|
55728
57146
|
if (this.debug) {
|
|
@@ -55767,7 +57185,7 @@ var init_ProbeAgent = __esm({
|
|
|
55767
57185
|
let resolvedPath = imagePath;
|
|
55768
57186
|
if (!imagePath.includes("/") && !imagePath.includes("\\")) {
|
|
55769
57187
|
for (const dir of listFilesDirectories) {
|
|
55770
|
-
const potentialPath =
|
|
57188
|
+
const potentialPath = resolve4(dir, imagePath);
|
|
55771
57189
|
const loaded = await this.loadImageIfValid(potentialPath);
|
|
55772
57190
|
if (loaded) {
|
|
55773
57191
|
if (this.debug) {
|
|
@@ -55792,7 +57210,7 @@ var init_ProbeAgent = __esm({
|
|
|
55792
57210
|
let match2;
|
|
55793
57211
|
while ((match2 = fileHeaderPattern.exec(content)) !== null) {
|
|
55794
57212
|
const filePath = match2[1].trim();
|
|
55795
|
-
const dir =
|
|
57213
|
+
const dir = dirname4(filePath);
|
|
55796
57214
|
if (dir && dir !== ".") {
|
|
55797
57215
|
directories.push(dir);
|
|
55798
57216
|
if (this.debug) {
|
|
@@ -55836,21 +57254,21 @@ var init_ProbeAgent = __esm({
|
|
|
55836
57254
|
}
|
|
55837
57255
|
const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
|
|
55838
57256
|
let absolutePath;
|
|
55839
|
-
let
|
|
55840
|
-
if (
|
|
57257
|
+
let isPathAllowed2 = false;
|
|
57258
|
+
if (isAbsolute2(imagePath)) {
|
|
55841
57259
|
absolutePath = imagePath;
|
|
55842
|
-
|
|
57260
|
+
isPathAllowed2 = allowedDirs.some((dir) => absolutePath.startsWith(resolve4(dir)));
|
|
55843
57261
|
} else {
|
|
55844
57262
|
for (const dir of allowedDirs) {
|
|
55845
|
-
const resolvedPath =
|
|
55846
|
-
if (resolvedPath.startsWith(
|
|
57263
|
+
const resolvedPath = resolve4(dir, imagePath);
|
|
57264
|
+
if (resolvedPath.startsWith(resolve4(dir))) {
|
|
55847
57265
|
absolutePath = resolvedPath;
|
|
55848
|
-
|
|
57266
|
+
isPathAllowed2 = true;
|
|
55849
57267
|
break;
|
|
55850
57268
|
}
|
|
55851
57269
|
}
|
|
55852
57270
|
}
|
|
55853
|
-
if (!
|
|
57271
|
+
if (!isPathAllowed2) {
|
|
55854
57272
|
if (this.debug) {
|
|
55855
57273
|
console.log(`[DEBUG] Image path outside allowed directories: ${imagePath}`);
|
|
55856
57274
|
}
|
|
@@ -56049,6 +57467,18 @@ ${attemptCompletionToolDefinition}
|
|
|
56049
57467
|
`;
|
|
56050
57468
|
if (this.allowEdit) {
|
|
56051
57469
|
toolDefinitions += `${implementToolDefinition}
|
|
57470
|
+
`;
|
|
57471
|
+
toolDefinitions += `${editToolDefinition}
|
|
57472
|
+
`;
|
|
57473
|
+
toolDefinitions += `${createToolDefinition}
|
|
57474
|
+
`;
|
|
57475
|
+
}
|
|
57476
|
+
if (this.enableBash) {
|
|
57477
|
+
toolDefinitions += `${bashToolDefinition}
|
|
57478
|
+
`;
|
|
57479
|
+
}
|
|
57480
|
+
if (this.enableDelegate) {
|
|
57481
|
+
toolDefinitions += `${delegateToolDefinition}
|
|
56052
57482
|
`;
|
|
56053
57483
|
}
|
|
56054
57484
|
let xmlToolGuidelines = `
|
|
@@ -56112,7 +57542,7 @@ Available Tools:
|
|
|
56112
57542
|
- extract: Extract specific code blocks or lines from files.
|
|
56113
57543
|
- listFiles: List files and directories in a specified location.
|
|
56114
57544
|
- searchFiles: Find files matching a glob pattern with recursive search capability.
|
|
56115
|
-
${this.allowEdit ? "- implement: Implement a feature or fix a bug using aider.\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" : ""}
|
|
56116
57546
|
- attempt_completion: Finalize the task and provide the result to the user.
|
|
56117
57547
|
- attempt_complete: Quick completion using previous response (shorthand).
|
|
56118
57548
|
`;
|
|
@@ -56126,7 +57556,10 @@ Follow these instructions carefully:
|
|
|
56126
57556
|
6. You MUST respond with exactly ONE tool call per message, using the specified XML format, until the task is complete.
|
|
56127
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.
|
|
56128
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.
|
|
56129
|
-
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` : ""}
|
|
56130
57563
|
</instructions>
|
|
56131
57564
|
`;
|
|
56132
57565
|
const predefinedPrompts = {
|
|
@@ -56378,7 +57811,7 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
56378
57811
|
try {
|
|
56379
57812
|
const executeAIRequest = async () => {
|
|
56380
57813
|
const messagesForAI = this.prepareMessagesWithImages(currentMessages);
|
|
56381
|
-
const result = await
|
|
57814
|
+
const result = await this.streamTextWithRetryAndFallback({
|
|
56382
57815
|
model: this.provider(this.model),
|
|
56383
57816
|
messages: messagesForAI,
|
|
56384
57817
|
maxTokens: maxResponseTokens,
|
|
@@ -56430,7 +57863,13 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
56430
57863
|
"attempt_completion"
|
|
56431
57864
|
];
|
|
56432
57865
|
if (this.allowEdit) {
|
|
56433
|
-
validTools.push("implement");
|
|
57866
|
+
validTools.push("implement", "edit", "create");
|
|
57867
|
+
}
|
|
57868
|
+
if (this.enableBash) {
|
|
57869
|
+
validTools.push("bash");
|
|
57870
|
+
}
|
|
57871
|
+
if (this.enableDelegate) {
|
|
57872
|
+
validTools.push("delegate");
|
|
56434
57873
|
}
|
|
56435
57874
|
const nativeTools = validTools;
|
|
56436
57875
|
const parsedTool = this.mcpBridge ? parseHybridXmlToolCall(assistantResponseContent, nativeTools, this.mcpBridge) : parseXmlToolCallWithThinking(assistantResponseContent, validTools);
|
|
@@ -56545,11 +57984,21 @@ ${toolResultContent}
|
|
|
56545
57984
|
...toolParams,
|
|
56546
57985
|
currentIteration,
|
|
56547
57986
|
maxIterations,
|
|
57987
|
+
parentSessionId: this.sessionId,
|
|
57988
|
+
// Pass parent session ID for tracking
|
|
57989
|
+
path: this.searchPath,
|
|
57990
|
+
// Inherit search path
|
|
57991
|
+
provider: this.provider,
|
|
57992
|
+
// Inherit AI provider
|
|
57993
|
+
model: this.model,
|
|
57994
|
+
// Inherit model
|
|
56548
57995
|
debug: this.debug,
|
|
56549
57996
|
tracer: this.tracer
|
|
56550
57997
|
};
|
|
56551
57998
|
if (this.debug) {
|
|
56552
57999
|
console.log(`[DEBUG] Executing delegate tool at iteration ${currentIteration}/${maxIterations}`);
|
|
58000
|
+
console.log(`[DEBUG] Parent session: ${this.sessionId}`);
|
|
58001
|
+
console.log(`[DEBUG] Inherited config: path=${this.searchPath}, provider=${this.provider}, model=${this.model}`);
|
|
56553
58002
|
console.log(`[DEBUG] Delegate task: ${toolParams.task?.substring(0, 100)}...`);
|
|
56554
58003
|
}
|
|
56555
58004
|
if (this.tracer) {
|
|
@@ -57140,6 +58589,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
57140
58589
|
customPrompt: this.customPrompt,
|
|
57141
58590
|
promptType: this.promptType,
|
|
57142
58591
|
allowEdit: this.allowEdit,
|
|
58592
|
+
enableDelegate: this.enableDelegate,
|
|
57143
58593
|
path: this.allowedFolders[0],
|
|
57144
58594
|
// Use first allowed folder as primary path
|
|
57145
58595
|
allowedFolders: [...this.allowedFolders],
|
|
@@ -57330,8 +58780,8 @@ import {
|
|
|
57330
58780
|
ListToolsRequestSchema,
|
|
57331
58781
|
McpError
|
|
57332
58782
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
57333
|
-
import { readFileSync as readFileSync2, existsSync as
|
|
57334
|
-
import { resolve as
|
|
58783
|
+
import { readFileSync as readFileSync2, existsSync as existsSync6 } from "fs";
|
|
58784
|
+
import { resolve as resolve5 } from "path";
|
|
57335
58785
|
|
|
57336
58786
|
// src/agent/acp/server.js
|
|
57337
58787
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
@@ -57590,8 +59040,8 @@ var ACPConnection = class extends EventEmitter4 {
|
|
|
57590
59040
|
if (params !== null) {
|
|
57591
59041
|
message.params = params;
|
|
57592
59042
|
}
|
|
57593
|
-
return new Promise((
|
|
57594
|
-
this.pendingRequests.set(id, { resolve:
|
|
59043
|
+
return new Promise((resolve6, reject2) => {
|
|
59044
|
+
this.pendingRequests.set(id, { resolve: resolve6, reject: reject2 });
|
|
57595
59045
|
this.sendMessage(message);
|
|
57596
59046
|
setTimeout(() => {
|
|
57597
59047
|
if (this.pendingRequests.has(id)) {
|
|
@@ -57896,6 +59346,7 @@ var ACPServer = class {
|
|
|
57896
59346
|
provider: this.options.provider,
|
|
57897
59347
|
model: this.options.model,
|
|
57898
59348
|
allowEdit: this.options.allowEdit,
|
|
59349
|
+
enableDelegate: this.options.enableDelegate,
|
|
57899
59350
|
debug: this.options.debug,
|
|
57900
59351
|
enableMcp: this.options.enableMcp,
|
|
57901
59352
|
mcpConfig: this.options.mcpConfig,
|
|
@@ -58004,8 +59455,8 @@ dotenv3.config();
|
|
|
58004
59455
|
function readInputContent(input) {
|
|
58005
59456
|
if (!input) return null;
|
|
58006
59457
|
try {
|
|
58007
|
-
const resolvedPath =
|
|
58008
|
-
if (
|
|
59458
|
+
const resolvedPath = resolve5(input);
|
|
59459
|
+
if (existsSync6(resolvedPath)) {
|
|
58009
59460
|
return readFileSync2(resolvedPath, "utf-8").trim();
|
|
58010
59461
|
}
|
|
58011
59462
|
} catch (error) {
|
|
@@ -58013,7 +59464,7 @@ function readInputContent(input) {
|
|
|
58013
59464
|
return input;
|
|
58014
59465
|
}
|
|
58015
59466
|
function readFromStdin() {
|
|
58016
|
-
return new Promise((
|
|
59467
|
+
return new Promise((resolve6, reject2) => {
|
|
58017
59468
|
let data = "";
|
|
58018
59469
|
let hasReceivedData = false;
|
|
58019
59470
|
let dataChunks = [];
|
|
@@ -58038,7 +59489,7 @@ function readFromStdin() {
|
|
|
58038
59489
|
if (!trimmed && dataChunks.length === 0) {
|
|
58039
59490
|
reject2(new Error("No input received from stdin"));
|
|
58040
59491
|
} else {
|
|
58041
|
-
|
|
59492
|
+
resolve6(trimmed);
|
|
58042
59493
|
}
|
|
58043
59494
|
});
|
|
58044
59495
|
process.stdin.on("error", (error) => {
|
|
@@ -58070,6 +59521,7 @@ function parseArgs() {
|
|
|
58070
59521
|
provider: null,
|
|
58071
59522
|
model: null,
|
|
58072
59523
|
allowEdit: false,
|
|
59524
|
+
enableDelegate: false,
|
|
58073
59525
|
verbose: false,
|
|
58074
59526
|
help: false,
|
|
58075
59527
|
maxIterations: null,
|
|
@@ -58104,6 +59556,10 @@ function parseArgs() {
|
|
|
58104
59556
|
config.verbose = true;
|
|
58105
59557
|
} else if (arg === "--allow-edit") {
|
|
58106
59558
|
config.allowEdit = true;
|
|
59559
|
+
} else if (arg === "--enable-delegate") {
|
|
59560
|
+
config.enableDelegate = true;
|
|
59561
|
+
} else if (arg === "--no-delegate") {
|
|
59562
|
+
config.enableDelegate = false;
|
|
58107
59563
|
} else if (arg === "--path" && i + 1 < args.length) {
|
|
58108
59564
|
config.path = args[++i];
|
|
58109
59565
|
} else if (arg === "--allowed-folders" && i + 1 < args.length) {
|
|
@@ -58175,6 +59631,7 @@ Options:
|
|
|
58175
59631
|
--provider <name> Force AI provider: anthropic, openai, google
|
|
58176
59632
|
--model <name> Override model name
|
|
58177
59633
|
--allow-edit Enable code modification capabilities
|
|
59634
|
+
--enable-delegate Enable delegate tool for task distribution to subagents
|
|
58178
59635
|
--verbose Enable verbose output
|
|
58179
59636
|
--outline Use outline-xml format for code search results
|
|
58180
59637
|
--mcp Run as MCP server
|
|
@@ -58455,6 +59912,7 @@ async function main() {
|
|
|
58455
59912
|
model: config.model,
|
|
58456
59913
|
path: config.path,
|
|
58457
59914
|
allowEdit: config.allowEdit,
|
|
59915
|
+
enableDelegate: config.enableDelegate,
|
|
58458
59916
|
debug: config.verbose
|
|
58459
59917
|
});
|
|
58460
59918
|
await server.start();
|
|
@@ -58557,7 +60015,7 @@ async function main() {
|
|
|
58557
60015
|
bashConfig.timeout = timeout;
|
|
58558
60016
|
}
|
|
58559
60017
|
if (config.bashWorkingDir) {
|
|
58560
|
-
if (!
|
|
60018
|
+
if (!existsSync6(config.bashWorkingDir)) {
|
|
58561
60019
|
console.error(`Error: Bash working directory does not exist: ${config.bashWorkingDir}`);
|
|
58562
60020
|
process.exit(1);
|
|
58563
60021
|
}
|
|
@@ -58573,6 +60031,7 @@ async function main() {
|
|
|
58573
60031
|
promptType: config.prompt,
|
|
58574
60032
|
customPrompt: systemPrompt,
|
|
58575
60033
|
allowEdit: config.allowEdit,
|
|
60034
|
+
enableDelegate: config.enableDelegate,
|
|
58576
60035
|
debug: config.verbose,
|
|
58577
60036
|
tracer: appTracer,
|
|
58578
60037
|
outline: config.outline,
|