@probelabs/probe 0.6.0-rc278 → 0.6.0-rc280
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/binaries/probe-v0.6.0-rc280-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc280-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc280-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc280-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc280-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +114 -28
- package/build/agent/dsl/environment.js +1 -0
- package/build/agent/index.js +248 -87
- package/build/delegate.js +62 -23
- package/build/downloader.js +28 -25
- package/build/tools/analyzeAll.js +10 -10
- package/build/tools/common.js +4 -3
- package/build/tools/vercel.js +72 -10
- package/cjs/agent/ProbeAgent.cjs +251 -88
- package/cjs/index.cjs +248 -87
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +114 -28
- package/src/agent/dsl/environment.js +1 -0
- package/src/delegate.js +62 -23
- package/src/downloader.js +28 -25
- package/src/tools/analyzeAll.js +10 -10
- package/src/tools/common.js +4 -3
- package/src/tools/vercel.js +72 -10
- package/bin/binaries/probe-v0.6.0-rc278-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc278-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc278-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc278-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc278-x86_64-unknown-linux-musl.tar.gz +0 -0
package/cjs/agent/ProbeAgent.cjs
CHANGED
|
@@ -29663,9 +29663,7 @@ async function acquireFileLock(lockPath, version2) {
|
|
|
29663
29663
|
};
|
|
29664
29664
|
try {
|
|
29665
29665
|
await import_fs_extra2.default.writeFile(lockPath, JSON.stringify(lockData), { flag: "wx" });
|
|
29666
|
-
|
|
29667
|
-
console.log(`Acquired file lock: ${lockPath}`);
|
|
29668
|
-
}
|
|
29666
|
+
console.log(`Acquired file lock: ${lockPath}`);
|
|
29669
29667
|
return true;
|
|
29670
29668
|
} catch (error2) {
|
|
29671
29669
|
if (error2.code === "EEXIST") {
|
|
@@ -29673,15 +29671,11 @@ async function acquireFileLock(lockPath, version2) {
|
|
|
29673
29671
|
const existingLock = JSON.parse(await import_fs_extra2.default.readFile(lockPath, "utf-8"));
|
|
29674
29672
|
const lockAge = Date.now() - existingLock.timestamp;
|
|
29675
29673
|
if (lockAge > LOCK_TIMEOUT_MS) {
|
|
29676
|
-
|
|
29677
|
-
console.log(`Removing stale lock file (age: ${Math.round(lockAge / 1e3)}s, pid: ${existingLock.pid})`);
|
|
29678
|
-
}
|
|
29674
|
+
console.log(`Removing stale lock file (age: ${Math.round(lockAge / 1e3)}s, pid: ${existingLock.pid})`);
|
|
29679
29675
|
await import_fs_extra2.default.remove(lockPath);
|
|
29680
29676
|
return false;
|
|
29681
29677
|
}
|
|
29682
|
-
|
|
29683
|
-
console.log(`Download in progress by process ${existingLock.pid}, waiting...`);
|
|
29684
|
-
}
|
|
29678
|
+
console.log(`Download in progress by process ${existingLock.pid}, waiting...`);
|
|
29685
29679
|
return false;
|
|
29686
29680
|
} catch (readError) {
|
|
29687
29681
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
@@ -29722,36 +29716,36 @@ async function releaseFileLock(lockPath) {
|
|
|
29722
29716
|
}
|
|
29723
29717
|
async function waitForFileLock(lockPath, binaryPath) {
|
|
29724
29718
|
const startTime = Date.now();
|
|
29719
|
+
let lastStatusTime = startTime;
|
|
29720
|
+
console.log(`Waiting for file lock to clear: ${lockPath}`);
|
|
29725
29721
|
while (Date.now() - startTime < MAX_LOCK_WAIT_MS) {
|
|
29726
29722
|
if (await import_fs_extra2.default.pathExists(binaryPath)) {
|
|
29727
|
-
|
|
29728
|
-
|
|
29729
|
-
}
|
|
29723
|
+
const waitedSeconds = Math.round((Date.now() - startTime) / 1e3);
|
|
29724
|
+
console.log(`Binary now available at ${binaryPath}, download completed by another process (waited ${waitedSeconds}s)`);
|
|
29730
29725
|
return true;
|
|
29731
29726
|
}
|
|
29732
29727
|
const lockExists = await import_fs_extra2.default.pathExists(lockPath);
|
|
29733
29728
|
if (!lockExists) {
|
|
29734
|
-
|
|
29735
|
-
console.log(`Lock file removed but binary not found - download may have failed`);
|
|
29736
|
-
}
|
|
29729
|
+
console.log(`Lock file removed but binary not found - download may have failed`);
|
|
29737
29730
|
return false;
|
|
29738
29731
|
}
|
|
29739
29732
|
try {
|
|
29740
29733
|
const lockData = JSON.parse(await import_fs_extra2.default.readFile(lockPath, "utf-8"));
|
|
29741
29734
|
const lockAge = Date.now() - lockData.timestamp;
|
|
29742
29735
|
if (lockAge > LOCK_TIMEOUT_MS) {
|
|
29743
|
-
|
|
29744
|
-
console.log(`Lock expired (age: ${Math.round(lockAge / 1e3)}s), will retry download`);
|
|
29745
|
-
}
|
|
29736
|
+
console.log(`Lock expired (age: ${Math.round(lockAge / 1e3)}s), will retry download`);
|
|
29746
29737
|
return false;
|
|
29747
29738
|
}
|
|
29748
29739
|
} catch {
|
|
29749
29740
|
}
|
|
29741
|
+
if (Date.now() - lastStatusTime >= 15e3) {
|
|
29742
|
+
const elapsedSeconds = Math.round((Date.now() - startTime) / 1e3);
|
|
29743
|
+
console.log(`Still waiting for file lock (${elapsedSeconds}s/${MAX_LOCK_WAIT_MS / 1e3}s max)`);
|
|
29744
|
+
lastStatusTime = Date.now();
|
|
29745
|
+
}
|
|
29750
29746
|
await new Promise((resolve8) => setTimeout(resolve8, LOCK_POLL_INTERVAL_MS));
|
|
29751
29747
|
}
|
|
29752
|
-
|
|
29753
|
-
console.log(`Timeout waiting for file lock`);
|
|
29754
|
-
}
|
|
29748
|
+
console.log(`Timeout waiting for file lock after ${MAX_LOCK_WAIT_MS / 1e3}s`);
|
|
29755
29749
|
return false;
|
|
29756
29750
|
}
|
|
29757
29751
|
async function withDownloadLock(version2, downloadFn) {
|
|
@@ -29765,9 +29759,7 @@ async function withDownloadLock(version2, downloadFn) {
|
|
|
29765
29759
|
}
|
|
29766
29760
|
downloadLocks.delete(lockKey);
|
|
29767
29761
|
} else {
|
|
29768
|
-
|
|
29769
|
-
console.log(`Download already in progress in this process for version ${lockKey}, waiting...`);
|
|
29770
|
-
}
|
|
29762
|
+
console.log(`Download already in progress in this process for version ${lockKey}, waiting...`);
|
|
29771
29763
|
try {
|
|
29772
29764
|
return await lock.promise;
|
|
29773
29765
|
} catch (error2) {
|
|
@@ -29777,10 +29769,16 @@ async function withDownloadLock(version2, downloadFn) {
|
|
|
29777
29769
|
}
|
|
29778
29770
|
}
|
|
29779
29771
|
}
|
|
29772
|
+
let timeoutId = null;
|
|
29780
29773
|
const downloadPromise = Promise.race([
|
|
29781
29774
|
downloadFn(),
|
|
29782
29775
|
new Promise(
|
|
29783
|
-
(_, reject2) =>
|
|
29776
|
+
(_, reject2) => {
|
|
29777
|
+
timeoutId = setTimeout(() => reject2(new Error(`Download timeout after ${LOCK_TIMEOUT_MS / 1e3}s`)), LOCK_TIMEOUT_MS);
|
|
29778
|
+
if (timeoutId.unref) {
|
|
29779
|
+
timeoutId.unref();
|
|
29780
|
+
}
|
|
29781
|
+
}
|
|
29784
29782
|
)
|
|
29785
29783
|
]);
|
|
29786
29784
|
downloadLocks.set(lockKey, {
|
|
@@ -29791,6 +29789,9 @@ async function withDownloadLock(version2, downloadFn) {
|
|
|
29791
29789
|
const result = await downloadPromise;
|
|
29792
29790
|
return result;
|
|
29793
29791
|
} finally {
|
|
29792
|
+
if (timeoutId) {
|
|
29793
|
+
clearTimeout(timeoutId);
|
|
29794
|
+
}
|
|
29794
29795
|
downloadLocks.delete(lockKey);
|
|
29795
29796
|
}
|
|
29796
29797
|
}
|
|
@@ -31241,12 +31242,17 @@ async function delegate({
|
|
|
31241
31242
|
mcpConfigPath = null,
|
|
31242
31243
|
delegationManager = null,
|
|
31243
31244
|
// Optional per-instance manager, falls back to default singleton
|
|
31244
|
-
concurrencyLimiter = null
|
|
31245
|
+
concurrencyLimiter = null,
|
|
31245
31246
|
// Optional global AI concurrency limiter
|
|
31247
|
+
parentAbortSignal = null
|
|
31248
|
+
// Optional AbortSignal from parent to cancel this delegation
|
|
31246
31249
|
}) {
|
|
31247
31250
|
if (!task || typeof task !== "string") {
|
|
31248
31251
|
throw new Error("Task parameter is required and must be a string");
|
|
31249
31252
|
}
|
|
31253
|
+
if (parentAbortSignal?.aborted) {
|
|
31254
|
+
throw new Error("Delegation cancelled: parent operation was aborted");
|
|
31255
|
+
}
|
|
31250
31256
|
const hasExplicitTimeout = Object.prototype.hasOwnProperty.call(arguments?.[0] ?? {}, "timeout");
|
|
31251
31257
|
if (!hasExplicitTimeout) {
|
|
31252
31258
|
const envTimeoutMs = parseInt(process.env.DELEGATION_TIMEOUT_MS || "", 10);
|
|
@@ -31331,12 +31337,37 @@ async function delegate({
|
|
|
31331
31337
|
}
|
|
31332
31338
|
const timeoutPromise = new Promise((_, reject2) => {
|
|
31333
31339
|
timeoutId = setTimeout(() => {
|
|
31340
|
+
subagent.cancel();
|
|
31334
31341
|
reject2(new Error(`Delegation timed out after ${timeout} seconds`));
|
|
31335
31342
|
}, timeout * 1e3);
|
|
31336
31343
|
});
|
|
31344
|
+
let parentAbortHandler;
|
|
31345
|
+
const parentAbortPromise = new Promise((_, reject2) => {
|
|
31346
|
+
if (parentAbortSignal) {
|
|
31347
|
+
if (parentAbortSignal.aborted) {
|
|
31348
|
+
subagent.cancel();
|
|
31349
|
+
reject2(new Error("Delegation cancelled: parent operation was aborted"));
|
|
31350
|
+
return;
|
|
31351
|
+
}
|
|
31352
|
+
parentAbortHandler = () => {
|
|
31353
|
+
subagent.cancel();
|
|
31354
|
+
reject2(new Error("Delegation cancelled: parent operation was aborted"));
|
|
31355
|
+
};
|
|
31356
|
+
parentAbortSignal.addEventListener("abort", parentAbortHandler, { once: true });
|
|
31357
|
+
}
|
|
31358
|
+
});
|
|
31337
31359
|
const answerOptions = schema ? { schema } : void 0;
|
|
31338
31360
|
const answerPromise = answerOptions ? subagent.answer(task, [], answerOptions) : subagent.answer(task);
|
|
31339
|
-
const
|
|
31361
|
+
const racers = [answerPromise, timeoutPromise];
|
|
31362
|
+
if (parentAbortSignal) racers.push(parentAbortPromise);
|
|
31363
|
+
let response;
|
|
31364
|
+
try {
|
|
31365
|
+
response = await Promise.race(racers);
|
|
31366
|
+
} finally {
|
|
31367
|
+
if (parentAbortHandler && parentAbortSignal) {
|
|
31368
|
+
parentAbortSignal.removeEventListener("abort", parentAbortHandler);
|
|
31369
|
+
}
|
|
31370
|
+
}
|
|
31340
31371
|
if (timeoutId !== null) {
|
|
31341
31372
|
clearTimeout(timeoutId);
|
|
31342
31373
|
timeoutId = null;
|
|
@@ -31492,10 +31523,9 @@ var init_delegate = __esm({
|
|
|
31492
31523
|
if (this.tryAcquire(parentSessionId)) {
|
|
31493
31524
|
return true;
|
|
31494
31525
|
}
|
|
31495
|
-
|
|
31496
|
-
console.error(`[DelegationManager] Slot unavailable (${this.globalActive}/${this.maxConcurrent}), queuing... (queue size: ${this.waitQueue.length}, timeout: ${effectiveTimeout}ms)`);
|
|
31497
|
-
}
|
|
31526
|
+
console.error(`[DelegationManager] Slot unavailable (${this.globalActive}/${this.maxConcurrent}), queuing... (queue size: ${this.waitQueue.length + 1}, timeout: ${effectiveTimeout}ms)`);
|
|
31498
31527
|
return new Promise((resolve8, reject2) => {
|
|
31528
|
+
const queuedAt = Date.now();
|
|
31499
31529
|
const entry = {
|
|
31500
31530
|
resolve: null,
|
|
31501
31531
|
// Will be wrapped below
|
|
@@ -31503,20 +31533,23 @@ var init_delegate = __esm({
|
|
|
31503
31533
|
// Will be wrapped below
|
|
31504
31534
|
parentSessionId,
|
|
31505
31535
|
debug,
|
|
31506
|
-
queuedAt
|
|
31507
|
-
timeoutId: null
|
|
31536
|
+
queuedAt,
|
|
31537
|
+
timeoutId: null,
|
|
31538
|
+
reminderId: null
|
|
31508
31539
|
};
|
|
31509
31540
|
let settled = false;
|
|
31510
31541
|
entry.resolve = (value) => {
|
|
31511
31542
|
if (settled) return;
|
|
31512
31543
|
settled = true;
|
|
31513
31544
|
if (entry.timeoutId) clearTimeout(entry.timeoutId);
|
|
31545
|
+
if (entry.reminderId) clearInterval(entry.reminderId);
|
|
31514
31546
|
resolve8(value);
|
|
31515
31547
|
};
|
|
31516
31548
|
entry.reject = (error2) => {
|
|
31517
31549
|
if (settled) return;
|
|
31518
31550
|
settled = true;
|
|
31519
31551
|
if (entry.timeoutId) clearTimeout(entry.timeoutId);
|
|
31552
|
+
if (entry.reminderId) clearInterval(entry.reminderId);
|
|
31520
31553
|
reject2(error2);
|
|
31521
31554
|
};
|
|
31522
31555
|
if (effectiveTimeout > 0) {
|
|
@@ -31528,6 +31561,13 @@ var init_delegate = __esm({
|
|
|
31528
31561
|
entry.reject(new Error(`Delegation queue timeout: waited ${effectiveTimeout}ms for an available slot`));
|
|
31529
31562
|
}, effectiveTimeout);
|
|
31530
31563
|
}
|
|
31564
|
+
entry.reminderId = setInterval(() => {
|
|
31565
|
+
const waitedSeconds = Math.round((Date.now() - queuedAt) / 1e3);
|
|
31566
|
+
console.error(`[DelegationManager] Still waiting for slot (${waitedSeconds}s). ${this.globalActive}/${this.maxConcurrent} active, ${this.waitQueue.length} queued.`);
|
|
31567
|
+
}, 15e3);
|
|
31568
|
+
if (entry.reminderId.unref) {
|
|
31569
|
+
entry.reminderId.unref();
|
|
31570
|
+
}
|
|
31531
31571
|
this.waitQueue.push(entry);
|
|
31532
31572
|
});
|
|
31533
31573
|
}
|
|
@@ -31566,18 +31606,14 @@ var init_delegate = __esm({
|
|
|
31566
31606
|
const sessionData = this.sessionDelegations.get(parentSessionId);
|
|
31567
31607
|
const sessionCount = sessionData?.count || 0;
|
|
31568
31608
|
if (sessionCount >= this.maxPerSession) {
|
|
31569
|
-
|
|
31570
|
-
console.error(`[DelegationManager] Session limit (${this.maxPerSession}) reached for queued item, rejecting`);
|
|
31571
|
-
}
|
|
31609
|
+
console.error(`[DelegationManager] Session limit (${this.maxPerSession}) reached for queued item, rejecting`);
|
|
31572
31610
|
toReject.push({ reject: reject2, error: new Error(`Maximum delegations per session (${this.maxPerSession}) reached for session ${parentSessionId}`) });
|
|
31573
31611
|
continue;
|
|
31574
31612
|
}
|
|
31575
31613
|
}
|
|
31576
31614
|
this._incrementCounters(parentSessionId);
|
|
31577
|
-
|
|
31578
|
-
|
|
31579
|
-
console.error(`[DelegationManager] Granted slot from queue (waited ${waitTime}ms). Active: ${this.globalActive}/${this.maxConcurrent}`);
|
|
31580
|
-
}
|
|
31615
|
+
const waitTime = Date.now() - queuedAt;
|
|
31616
|
+
console.error(`[DelegationManager] Granted slot from queue (waited ${waitTime}ms). Active: ${this.globalActive}/${this.maxConcurrent}`);
|
|
31581
31617
|
toResolve.push(resolve8);
|
|
31582
31618
|
}
|
|
31583
31619
|
if (toResolve.length > 0 || toReject.length > 0) {
|
|
@@ -31627,6 +31663,9 @@ var init_delegate = __esm({
|
|
|
31627
31663
|
if (entry.timeoutId) {
|
|
31628
31664
|
clearTimeout(entry.timeoutId);
|
|
31629
31665
|
}
|
|
31666
|
+
if (entry.reminderId) {
|
|
31667
|
+
clearInterval(entry.reminderId);
|
|
31668
|
+
}
|
|
31630
31669
|
if (entry.reject) {
|
|
31631
31670
|
entry.reject(new Error("DelegationManager was cleaned up"));
|
|
31632
31671
|
}
|
|
@@ -31749,8 +31788,9 @@ Instructions:
|
|
|
31749
31788
|
promptType: "code-researcher",
|
|
31750
31789
|
allowedTools: ["extract"],
|
|
31751
31790
|
maxIterations: 5,
|
|
31752
|
-
delegationManager: options.delegationManager
|
|
31791
|
+
delegationManager: options.delegationManager,
|
|
31753
31792
|
// Per-instance delegation limits
|
|
31793
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
31754
31794
|
// timeout removed - inherit default from delegate (300s)
|
|
31755
31795
|
});
|
|
31756
31796
|
return { chunk, result };
|
|
@@ -31770,16 +31810,12 @@ async function processChunksParallel(chunks, extractionPrompt, maxWorkers, optio
|
|
|
31770
31810
|
return result;
|
|
31771
31811
|
});
|
|
31772
31812
|
active.add(promise);
|
|
31773
|
-
|
|
31774
|
-
console.error(`[analyze_all] Started processing chunk ${chunk.id}/${chunk.total}`);
|
|
31775
|
-
}
|
|
31813
|
+
console.error(`[analyze_all] Started processing chunk ${chunk.id}/${chunk.total}`);
|
|
31776
31814
|
}
|
|
31777
31815
|
if (active.size > 0) {
|
|
31778
31816
|
const result = await Promise.race(active);
|
|
31779
31817
|
results.push(result);
|
|
31780
|
-
|
|
31781
|
-
console.error(`[analyze_all] Completed chunk ${result.chunk.id}/${result.chunk.total}`);
|
|
31782
|
-
}
|
|
31818
|
+
console.error(`[analyze_all] Completed chunk ${result.chunk.id}/${result.chunk.total}`);
|
|
31783
31819
|
}
|
|
31784
31820
|
}
|
|
31785
31821
|
results.sort((a5, b5) => a5.chunk.id - b5.chunk.id);
|
|
@@ -31849,8 +31885,9 @@ Organize all findings into clear categories with items listed under each.${compl
|
|
|
31849
31885
|
promptType: "code-researcher",
|
|
31850
31886
|
allowedTools: [],
|
|
31851
31887
|
maxIterations: 5,
|
|
31852
|
-
delegationManager: options.delegationManager
|
|
31888
|
+
delegationManager: options.delegationManager,
|
|
31853
31889
|
// Per-instance delegation limits
|
|
31890
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
31854
31891
|
// timeout removed - inherit default from delegate (300s)
|
|
31855
31892
|
});
|
|
31856
31893
|
return result;
|
|
@@ -31914,8 +31951,9 @@ CRITICAL: Do NOT guess keywords. Actually run searches and see what returns resu
|
|
|
31914
31951
|
promptType: "code-researcher",
|
|
31915
31952
|
// Full tool access for exploration and experimentation
|
|
31916
31953
|
maxIterations: 15,
|
|
31917
|
-
delegationManager: options.delegationManager
|
|
31954
|
+
delegationManager: options.delegationManager,
|
|
31918
31955
|
// Per-instance delegation limits
|
|
31956
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
31919
31957
|
// timeout removed - inherit default from delegate (300s)
|
|
31920
31958
|
});
|
|
31921
31959
|
const plan = parsePlanningResult(stripResultTags(result));
|
|
@@ -31972,8 +32010,9 @@ When done, use the attempt_completion tool with your answer as the result.`;
|
|
|
31972
32010
|
promptType: "code-researcher",
|
|
31973
32011
|
allowedTools: [],
|
|
31974
32012
|
maxIterations: 5,
|
|
31975
|
-
delegationManager: options.delegationManager
|
|
32013
|
+
delegationManager: options.delegationManager,
|
|
31976
32014
|
// Per-instance delegation limits
|
|
32015
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
31977
32016
|
// timeout removed - inherit default from delegate (300s)
|
|
31978
32017
|
});
|
|
31979
32018
|
return stripResultTags(result);
|
|
@@ -36269,14 +36308,14 @@ function resolveTargetPath(target, cwd) {
|
|
|
36269
36308
|
}
|
|
36270
36309
|
return filePart + suffix;
|
|
36271
36310
|
}
|
|
36272
|
-
var import_path5, searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, listFilesSchema, searchFilesSchema, readImageSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, searchDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription;
|
|
36311
|
+
var import_path5, searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, listFilesSchema, searchFilesSchema, readImageSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, searchDescription, searchDelegateDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription;
|
|
36273
36312
|
var init_common2 = __esm({
|
|
36274
36313
|
"src/tools/common.js"() {
|
|
36275
36314
|
"use strict";
|
|
36276
36315
|
init_zod();
|
|
36277
36316
|
import_path5 = require("path");
|
|
36278
36317
|
searchSchema = external_exports.object({
|
|
36279
|
-
query: external_exports.string().describe("Search query
|
|
36318
|
+
query: external_exports.string().describe("Search query \u2014 natural language questions or Elasticsearch-style keywords both work. For keywords: use quotes for exact phrases, AND/OR for boolean logic, - for negation. Probe handles stemming and camelCase/snake_case splitting automatically, so do NOT try case or style variations of the same keyword."),
|
|
36280
36319
|
path: external_exports.string().optional().default(".").describe('Path to search in. For dependencies use "go:github.com/owner/repo", "js:package_name", or "rust:cargo_name" etc.'),
|
|
36281
36320
|
exact: external_exports.boolean().optional().default(false).describe('Default (false) enables stemming and keyword splitting for exploratory search - "getUserData" matches "get", "user", "data", etc. Set true for precise symbol lookup where "getUserData" matches only "getUserData". Use true when you know the exact symbol name.'),
|
|
36282
36321
|
maxTokens: external_exports.number().nullable().optional().describe("Maximum tokens to return. Default is 20000. Set to null for unlimited results."),
|
|
@@ -36284,7 +36323,7 @@ var init_common2 = __esm({
|
|
|
36284
36323
|
nextPage: external_exports.boolean().optional().default(false).describe("Set to true when requesting the next page of results. Requires passing the same session ID from the previous search output.")
|
|
36285
36324
|
});
|
|
36286
36325
|
searchAllSchema = external_exports.object({
|
|
36287
|
-
query: external_exports.string().describe("Search query
|
|
36326
|
+
query: external_exports.string().describe("Search query \u2014 natural language questions or Elasticsearch-style keywords both work. For keywords: use quotes for exact phrases, AND/OR for boolean logic, - for negation. Probe handles stemming and camelCase/snake_case splitting automatically, so do NOT try case or style variations of the same keyword."),
|
|
36288
36327
|
path: external_exports.string().optional().default(".").describe("Path to search in."),
|
|
36289
36328
|
exact: external_exports.boolean().optional().default(false).describe("Use exact matching instead of stemming."),
|
|
36290
36329
|
maxTokensPerPage: external_exports.number().optional().default(2e4).describe("Tokens per page when paginating. Default 20000."),
|
|
@@ -36339,7 +36378,8 @@ var init_common2 = __esm({
|
|
|
36339
36378
|
clearOutputBuffer: external_exports.boolean().optional().default(true).describe("Clear the output buffer from previous execute_plan calls"),
|
|
36340
36379
|
clearSessionStore: external_exports.boolean().optional().default(false).describe("Clear the session store (persisted data across execute_plan calls)")
|
|
36341
36380
|
});
|
|
36342
|
-
searchDescription =
|
|
36381
|
+
searchDescription = 'Search code in the repository. Free-form questions are accepted, but Elasticsearch-style keyword queries work best. Use this tool first for any code-related questions. NOTE: By default, search handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically \u2014 do NOT manually try keyword variations like "getAllUsers" then "get_all_users" then "GetAllUsers". One search covers all variations.';
|
|
36382
|
+
searchDelegateDescription = 'Search code in the repository by asking a question. Accepts natural language questions (e.g., "How does authentication work?", "Where is the user validation logic?"). A specialized subagent breaks down your question into targeted keyword searches and returns extracted code blocks. Do NOT formulate keyword queries yourself \u2014 just ask the question naturally.';
|
|
36343
36383
|
queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
|
|
36344
36384
|
extractDescription = "Extract code blocks from files based on file paths and optional line numbers. Use this tool to see complete context after finding relevant files. Line numbers from output can be used with edit start_line/end_line for precise editing.";
|
|
36345
36385
|
delegateDescription = "Automatically delegate big distinct tasks to specialized probe subagents within the agentic loop. Used by AI agents to break down complex requests into focused, parallel tasks.";
|
|
@@ -36522,11 +36562,41 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
36522
36562
|
"- extract: Verify code snippets to ensure targets are actually relevant before including them.",
|
|
36523
36563
|
"- listFiles: Understand directory structure to find where relevant code might live.",
|
|
36524
36564
|
"",
|
|
36525
|
-
"
|
|
36565
|
+
"CRITICAL - How probe search works (do NOT ignore):",
|
|
36566
|
+
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting.",
|
|
36567
|
+
'- Searching "allowed_ips" ALREADY matches "AllowedIPs", "allowedIps", "allowed_ips", etc. Do NOT manually try case/style variations.',
|
|
36568
|
+
'- Searching "getUserData" ALREADY matches "get", "user", "data" and their variations.',
|
|
36569
|
+
"- NEVER repeat the same search query \u2014 you will get the same results.",
|
|
36570
|
+
"- NEVER search trivial variations of the same keyword (e.g., AllowedIPs then allowedIps then allowed_ips). This is wasteful \u2014 probe handles it.",
|
|
36571
|
+
"- If a search returns no results, the term likely does not exist in that path. Try a genuinely DIFFERENT keyword or concept, not a variation.",
|
|
36572
|
+
"- If 2-3 consecutive searches return no results for a concept, STOP searching for it and move on.",
|
|
36573
|
+
"",
|
|
36574
|
+
"GOOD search strategy (do this):",
|
|
36575
|
+
' Query: "How does authentication work and how are sessions managed?"',
|
|
36576
|
+
' \u2192 search "authentication" \u2192 search "session management" (two different concepts)',
|
|
36577
|
+
' Query: "Find the IP allowlist middleware"',
|
|
36578
|
+
' \u2192 search "allowlist middleware" (one search, probe handles IP/ip/Ip variations)',
|
|
36579
|
+
' Query: "How does BM25 scoring work with SIMD optimization?"',
|
|
36580
|
+
' \u2192 search "BM25 scoring" \u2192 search "SIMD optimization" (two different concepts)',
|
|
36581
|
+
"",
|
|
36582
|
+
"BAD search strategy (never do this):",
|
|
36583
|
+
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG: these are trivial case variations, probe handles them)',
|
|
36584
|
+
' \u2192 search "CIDR" \u2192 search "cidr" \u2192 search "Cidr" \u2192 search "*cidr*" (WRONG: same keyword repeated with variations)',
|
|
36585
|
+
' \u2192 search "error handling" \u2192 search "error handling" \u2192 search "error handling" (WRONG: repeating exact same query)',
|
|
36586
|
+
"",
|
|
36587
|
+
"Keyword tips:",
|
|
36588
|
+
"- Common programming keywords are filtered as stopwords when unquoted: function, class, return, new, struct, impl, var, let, const, etc.",
|
|
36589
|
+
'- Avoid searching for these alone \u2014 combine with a specific term (e.g., "middleware function" is fine, "function" alone is too generic).',
|
|
36590
|
+
'- To bypass stopword filtering: wrap terms in quotes ("return", "struct") or set exact=true. Both disable stemming and splitting too.',
|
|
36591
|
+
"- Multiple words without operators use OR logic: foo bar = foo OR bar. Use AND explicitly if you need both: foo AND bar.",
|
|
36592
|
+
'- camelCase terms are split: getUserData becomes "get", "user", "data" \u2014 so one search covers all naming styles.',
|
|
36593
|
+
"",
|
|
36594
|
+
"Strategy:",
|
|
36526
36595
|
"1. Analyze the query - identify key concepts, entities, and relationships",
|
|
36527
|
-
|
|
36528
|
-
"3.
|
|
36529
|
-
"4.
|
|
36596
|
+
"2. Run ONE focused search per concept with the most natural keyword. Trust probe to handle variations.",
|
|
36597
|
+
"3. If a search returns results, use extract to verify relevance",
|
|
36598
|
+
"4. Only try a different keyword if the first one returned irrelevant results (not if it returned no results \u2014 that means the concept is absent)",
|
|
36599
|
+
"5. Combine all relevant targets in your final response",
|
|
36530
36600
|
"",
|
|
36531
36601
|
`Query: ${searchQuery}`,
|
|
36532
36602
|
`Search path(s): ${searchPath}`,
|
|
@@ -36579,9 +36649,12 @@ var init_vercel = __esm({
|
|
|
36579
36649
|
}
|
|
36580
36650
|
return result;
|
|
36581
36651
|
};
|
|
36652
|
+
const previousSearches = /* @__PURE__ */ new Set();
|
|
36653
|
+
const paginationCounts = /* @__PURE__ */ new Map();
|
|
36654
|
+
const MAX_PAGES_PER_QUERY = 3;
|
|
36582
36655
|
return (0, import_ai.tool)({
|
|
36583
36656
|
name: "search",
|
|
36584
|
-
description: searchDelegate ?
|
|
36657
|
+
description: searchDelegate ? searchDelegateDescription : searchDescription,
|
|
36585
36658
|
inputSchema: searchSchema,
|
|
36586
36659
|
execute: async ({ query: searchQuery, path: path9, allow_tests, exact, maxTokens: paramMaxTokens, language, session, nextPage }) => {
|
|
36587
36660
|
const effectiveMaxTokens = paramMaxTokens || maxTokens;
|
|
@@ -36619,6 +36692,26 @@ var init_vercel = __esm({
|
|
|
36619
36692
|
return await search(searchOptions);
|
|
36620
36693
|
};
|
|
36621
36694
|
if (!searchDelegate) {
|
|
36695
|
+
const searchKey = `${searchQuery}::${searchPath}::${exact || false}`;
|
|
36696
|
+
if (!nextPage) {
|
|
36697
|
+
if (previousSearches.has(searchKey)) {
|
|
36698
|
+
if (debug) {
|
|
36699
|
+
console.error(`[DEDUP] Blocked duplicate search: "${searchQuery}" in "${searchPath}"`);
|
|
36700
|
+
}
|
|
36701
|
+
return "DUPLICATE SEARCH BLOCKED: You already searched for this exact query in this path. Do NOT repeat the same search. If you need more results, set nextPage=true with the session ID from the previous search. Otherwise, try a genuinely different keyword, use extract to examine results you already found, or use attempt_completion if you have enough information.";
|
|
36702
|
+
}
|
|
36703
|
+
previousSearches.add(searchKey);
|
|
36704
|
+
paginationCounts.set(searchKey, 0);
|
|
36705
|
+
} else {
|
|
36706
|
+
const pageCount = (paginationCounts.get(searchKey) || 0) + 1;
|
|
36707
|
+
paginationCounts.set(searchKey, pageCount);
|
|
36708
|
+
if (pageCount > MAX_PAGES_PER_QUERY) {
|
|
36709
|
+
if (debug) {
|
|
36710
|
+
console.error(`[DEDUP] Blocked excessive pagination (page ${pageCount}/${MAX_PAGES_PER_QUERY}): "${searchQuery}" in "${searchPath}"`);
|
|
36711
|
+
}
|
|
36712
|
+
return `PAGINATION LIMIT REACHED: You have already retrieved ${MAX_PAGES_PER_QUERY} pages of results for this query. You have enough results \u2014 use extract to examine specific files, or use attempt_completion to return your findings.`;
|
|
36713
|
+
}
|
|
36714
|
+
}
|
|
36622
36715
|
try {
|
|
36623
36716
|
const result = maybeAnnotate(await runRawSearch());
|
|
36624
36717
|
if (options.fileTracker && typeof result === "string") {
|
|
@@ -36657,7 +36750,8 @@ var init_vercel = __esm({
|
|
|
36657
36750
|
promptType: "code-searcher",
|
|
36658
36751
|
allowedTools: ["search", "extract", "listFiles", "attempt_completion"],
|
|
36659
36752
|
searchDelegate: false,
|
|
36660
|
-
schema: CODE_SEARCH_SCHEMA
|
|
36753
|
+
schema: CODE_SEARCH_SCHEMA,
|
|
36754
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
36661
36755
|
});
|
|
36662
36756
|
const delegateResult = options.tracer?.withSpan ? await options.tracer.withSpan("search.delegate", runDelegation, {
|
|
36663
36757
|
"search.query": searchQuery,
|
|
@@ -36871,7 +36965,7 @@ var init_vercel = __esm({
|
|
|
36871
36965
|
name: "delegate",
|
|
36872
36966
|
description: delegateDescription,
|
|
36873
36967
|
inputSchema: delegateSchema,
|
|
36874
|
-
execute: async ({ task, currentIteration, maxIterations, parentSessionId, path: path9, provider, model, tracer, searchDelegate }) => {
|
|
36968
|
+
execute: async ({ task, currentIteration, maxIterations, parentSessionId, path: path9, provider, model, tracer, searchDelegate, parentAbortSignal }) => {
|
|
36875
36969
|
if (!task || typeof task !== "string") {
|
|
36876
36970
|
throw new Error("Task parameter is required and must be a non-empty string");
|
|
36877
36971
|
}
|
|
@@ -36929,8 +37023,9 @@ var init_vercel = __esm({
|
|
|
36929
37023
|
enableMcp,
|
|
36930
37024
|
mcpConfig,
|
|
36931
37025
|
mcpConfigPath,
|
|
36932
|
-
delegationManager
|
|
37026
|
+
delegationManager,
|
|
36933
37027
|
// Per-instance delegation limits
|
|
37028
|
+
parentAbortSignal
|
|
36934
37029
|
});
|
|
36935
37030
|
return result;
|
|
36936
37031
|
}
|
|
@@ -36968,8 +37063,9 @@ var init_vercel = __esm({
|
|
|
36968
37063
|
provider: options.provider,
|
|
36969
37064
|
model: options.model,
|
|
36970
37065
|
tracer: options.tracer,
|
|
36971
|
-
delegationManager
|
|
37066
|
+
delegationManager,
|
|
36972
37067
|
// Per-instance delegation limits
|
|
37068
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
36973
37069
|
});
|
|
36974
37070
|
return result;
|
|
36975
37071
|
} catch (error2) {
|
|
@@ -49487,6 +49583,7 @@ function generateSandboxGlobals(options) {
|
|
|
49487
49583
|
executing.add(p5);
|
|
49488
49584
|
results.push(p5);
|
|
49489
49585
|
if (executing.size >= mapConcurrency) {
|
|
49586
|
+
console.error(`[map] Concurrency limit reached (${executing.size}/${mapConcurrency}), waiting for a slot...`);
|
|
49490
49587
|
await Promise.race(executing);
|
|
49491
49588
|
}
|
|
49492
49589
|
}
|
|
@@ -108714,9 +108811,24 @@ __export(ProbeAgent_exports, {
|
|
|
108714
108811
|
ENGINE_ACTIVITY_TIMEOUT_DEFAULT: () => ENGINE_ACTIVITY_TIMEOUT_DEFAULT,
|
|
108715
108812
|
ENGINE_ACTIVITY_TIMEOUT_MAX: () => ENGINE_ACTIVITY_TIMEOUT_MAX,
|
|
108716
108813
|
ENGINE_ACTIVITY_TIMEOUT_MIN: () => ENGINE_ACTIVITY_TIMEOUT_MIN,
|
|
108717
|
-
ProbeAgent: () => ProbeAgent
|
|
108814
|
+
ProbeAgent: () => ProbeAgent,
|
|
108815
|
+
debugLogToolResults: () => debugLogToolResults,
|
|
108816
|
+
debugTruncate: () => debugTruncate
|
|
108718
108817
|
});
|
|
108719
108818
|
module.exports = __toCommonJS(ProbeAgent_exports);
|
|
108819
|
+
function debugTruncate(s5, limit = 200) {
|
|
108820
|
+
if (s5.length <= limit) return s5;
|
|
108821
|
+
const half = Math.floor(limit / 2);
|
|
108822
|
+
return s5.substring(0, half) + ` ... [${s5.length} chars] ... ` + s5.substring(s5.length - half);
|
|
108823
|
+
}
|
|
108824
|
+
function debugLogToolResults(toolResults) {
|
|
108825
|
+
if (!toolResults || toolResults.length === 0) return;
|
|
108826
|
+
for (const tr of toolResults) {
|
|
108827
|
+
const argsStr = JSON.stringify(tr.args || {});
|
|
108828
|
+
const resultStr = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result || "");
|
|
108829
|
+
console.log(`[DEBUG] tool: ${tr.toolName} | args: ${debugTruncate(argsStr)} | result: ${debugTruncate(resultStr)}`);
|
|
108830
|
+
}
|
|
108831
|
+
}
|
|
108720
108832
|
var import_dotenv2, import_anthropic2, import_openai2, import_google2, import_ai6, import_crypto9, import_events4, import_fs15, import_promises6, import_path18, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
|
|
108721
108833
|
var init_ProbeAgent = __esm({
|
|
108722
108834
|
"src/agent/ProbeAgent.js"() {
|
|
@@ -108835,6 +108947,7 @@ var init_ProbeAgent = __esm({
|
|
|
108835
108947
|
this.enableExecutePlan = !!options.enableExecutePlan;
|
|
108836
108948
|
this.debug = options.debug || process.env.DEBUG === "1";
|
|
108837
108949
|
this.cancelled = false;
|
|
108950
|
+
this._abortController = new AbortController();
|
|
108838
108951
|
this.tracer = options.tracer || null;
|
|
108839
108952
|
this.outline = !!options.outline;
|
|
108840
108953
|
this.searchDelegate = options.searchDelegate !== void 0 ? !!options.searchDelegate : true;
|
|
@@ -108863,6 +108976,7 @@ var init_ProbeAgent = __esm({
|
|
|
108863
108976
|
this.completionPrompt = options.completionPrompt || null;
|
|
108864
108977
|
this.thinkingEffort = options.thinkingEffort || null;
|
|
108865
108978
|
const effectiveAllowedTools = options.disableTools ? [] : options.allowedTools;
|
|
108979
|
+
this._rawAllowedTools = options.allowedTools;
|
|
108866
108980
|
this.allowedTools = this._parseAllowedTools(effectiveAllowedTools);
|
|
108867
108981
|
this.storageAdapter = options.storageAdapter || new InMemoryStorageAdapter();
|
|
108868
108982
|
this.hooks = new HookManager();
|
|
@@ -109005,6 +109119,16 @@ var init_ProbeAgent = __esm({
|
|
|
109005
109119
|
_filterMcpTools(mcpToolNames) {
|
|
109006
109120
|
return mcpToolNames.filter((toolName) => this._isMcpToolAllowed(toolName));
|
|
109007
109121
|
}
|
|
109122
|
+
/**
|
|
109123
|
+
* Check if query tool was explicitly listed in allowedTools (not via wildcard).
|
|
109124
|
+
* Query (ast-grep) is excluded by default because models struggle with AST pattern syntax.
|
|
109125
|
+
* @returns {boolean}
|
|
109126
|
+
* @private
|
|
109127
|
+
*/
|
|
109128
|
+
_isQueryExplicitlyAllowed() {
|
|
109129
|
+
if (!this._rawAllowedTools) return false;
|
|
109130
|
+
return Array.isArray(this._rawAllowedTools) && this._rawAllowedTools.includes("query");
|
|
109131
|
+
}
|
|
109008
109132
|
/**
|
|
109009
109133
|
* Check if tracer is AppTracer (expects sessionId as first param) vs SimpleAppTracer
|
|
109010
109134
|
* @returns {boolean} - True if tracer is AppTracer style (requires sessionId)
|
|
@@ -109280,6 +109404,8 @@ var init_ProbeAgent = __esm({
|
|
|
109280
109404
|
searchDelegateModel: this.searchDelegateModel,
|
|
109281
109405
|
delegationManager: this.delegationManager,
|
|
109282
109406
|
// Per-instance delegation limits
|
|
109407
|
+
parentAbortSignal: this._abortController.signal,
|
|
109408
|
+
// Propagate cancellation to delegations
|
|
109283
109409
|
outputBuffer: this._outputBuffer,
|
|
109284
109410
|
concurrencyLimiter: this.concurrencyLimiter,
|
|
109285
109411
|
// Global AI concurrency limiter
|
|
@@ -109296,7 +109422,7 @@ var init_ProbeAgent = __esm({
|
|
|
109296
109422
|
if (wrappedTools.searchToolInstance && isToolAllowed("search")) {
|
|
109297
109423
|
this.toolImplementations.search = wrappedTools.searchToolInstance;
|
|
109298
109424
|
}
|
|
109299
|
-
if (wrappedTools.queryToolInstance && isToolAllowed("query")) {
|
|
109425
|
+
if (wrappedTools.queryToolInstance && isToolAllowed("query") && this._isQueryExplicitlyAllowed()) {
|
|
109300
109426
|
this.toolImplementations.query = wrappedTools.queryToolInstance;
|
|
109301
109427
|
}
|
|
109302
109428
|
if (wrappedTools.extractToolInstance && isToolAllowed("extract")) {
|
|
@@ -109727,6 +109853,15 @@ var init_ProbeAgent = __esm({
|
|
|
109727
109853
|
}
|
|
109728
109854
|
const controller = new AbortController();
|
|
109729
109855
|
const timeoutState = { timeoutId: null };
|
|
109856
|
+
if (this._abortController.signal.aborted) {
|
|
109857
|
+
controller.abort();
|
|
109858
|
+
} else {
|
|
109859
|
+
const onAgentAbort = () => controller.abort();
|
|
109860
|
+
this._abortController.signal.addEventListener("abort", onAgentAbort, { once: true });
|
|
109861
|
+
controller.signal.addEventListener("abort", () => {
|
|
109862
|
+
this._abortController.signal.removeEventListener("abort", onAgentAbort);
|
|
109863
|
+
}, { once: true });
|
|
109864
|
+
}
|
|
109730
109865
|
if (this.maxOperationTimeout && this.maxOperationTimeout > 0) {
|
|
109731
109866
|
timeoutState.timeoutId = setTimeout(() => {
|
|
109732
109867
|
controller.abort();
|
|
@@ -110030,7 +110165,8 @@ var init_ProbeAgent = __esm({
|
|
|
110030
110165
|
allowEdit: this.allowEdit,
|
|
110031
110166
|
allowedTools: allowedToolsForDelegate,
|
|
110032
110167
|
debug: this.debug,
|
|
110033
|
-
tracer: this.tracer
|
|
110168
|
+
tracer: this.tracer,
|
|
110169
|
+
parentAbortSignal: this._abortController.signal
|
|
110034
110170
|
};
|
|
110035
110171
|
if (this.debug) {
|
|
110036
110172
|
console.log(`[DEBUG] Executing delegate tool`);
|
|
@@ -110225,12 +110361,13 @@ var init_ProbeAgent = __esm({
|
|
|
110225
110361
|
const toolMap = {
|
|
110226
110362
|
search: {
|
|
110227
110363
|
schema: searchSchema,
|
|
110228
|
-
description: "Search code in the repository using keyword queries with Elasticsearch syntax."
|
|
110229
|
-
},
|
|
110230
|
-
query: {
|
|
110231
|
-
schema: querySchema,
|
|
110232
|
-
description: "Search code using ast-grep structural pattern matching."
|
|
110364
|
+
description: this.searchDelegate ? "Search code in the repository by asking a question. Accepts natural language questions \u2014 a subagent breaks them into targeted keyword searches and returns extracted code blocks. Do NOT formulate keyword queries yourself." : "Search code in the repository using keyword queries with Elasticsearch syntax. Handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically \u2014 do NOT try keyword variations manually."
|
|
110233
110365
|
},
|
|
110366
|
+
// query tool (ast-grep) removed from AI-facing tools — models struggle with pattern syntax
|
|
110367
|
+
// query: {
|
|
110368
|
+
// schema: querySchema,
|
|
110369
|
+
// description: 'Search code using ast-grep structural pattern matching.'
|
|
110370
|
+
// },
|
|
110234
110371
|
extract: {
|
|
110235
110372
|
schema: extractSchema,
|
|
110236
110373
|
description: "Extract code blocks from files based on file paths and optional line numbers."
|
|
@@ -110898,25 +111035,27 @@ ${this.architectureContext.content}
|
|
|
110898
111035
|
} else {
|
|
110899
111036
|
systemPrompt += predefinedPrompts["code-explorer"] + "\n\n";
|
|
110900
111037
|
}
|
|
111038
|
+
const searchToolDesc1 = this.searchDelegate ? '- search: Ask natural language questions to find code (e.g., "How does authentication work?"). A subagent handles keyword searches and returns extracted code blocks. Do NOT formulate keyword queries \u2014 just ask questions.' : "- search: Find code patterns using keyword queries with Elasticsearch syntax. Handles stemming and case variations automatically \u2014 do NOT try manual keyword variations.";
|
|
110901
111039
|
systemPrompt += `You have access to powerful code search and analysis tools through MCP:
|
|
110902
|
-
|
|
111040
|
+
${searchToolDesc1}
|
|
110903
111041
|
- extract: Extract specific code sections with context
|
|
110904
|
-
- query: Use AST patterns for structural code matching
|
|
110905
111042
|
- listFiles: Browse directory contents
|
|
110906
111043
|
- searchFiles: Find files by name patterns`;
|
|
110907
111044
|
if (this.enableBash) {
|
|
110908
111045
|
systemPrompt += `
|
|
110909
111046
|
- bash: Execute bash commands for system operations`;
|
|
110910
111047
|
}
|
|
110911
|
-
const
|
|
110912
|
-
const
|
|
111048
|
+
const searchGuidance1 = this.searchDelegate ? "1. Start with search \u2014 ask a question about what you want to understand. It returns extracted code blocks directly." : "1. Start with search to find relevant code patterns. One search per concept is usually enough \u2014 probe handles stemming and case variations.";
|
|
111049
|
+
const extractGuidance1 = this.searchDelegate ? "2. Use extract only if you need more context or a full file" : "2. Use extract to get detailed context when needed";
|
|
110913
111050
|
systemPrompt += `
|
|
110914
111051
|
|
|
110915
111052
|
When exploring code:
|
|
110916
|
-
${
|
|
110917
|
-
${
|
|
111053
|
+
${searchGuidance1}
|
|
111054
|
+
${extractGuidance1}
|
|
110918
111055
|
3. Prefer focused, specific searches over broad queries
|
|
110919
|
-
4.
|
|
111056
|
+
4. Do NOT repeat the same search or try trivial keyword variations \u2014 probe handles stemming and case variations automatically
|
|
111057
|
+
5. If 2-3 consecutive searches return no results for a concept, stop searching for it \u2014 the term likely does not exist in that codebase
|
|
111058
|
+
6. Combine multiple tools to build complete understanding`;
|
|
110920
111059
|
if (this.allowedFolders && this.allowedFolders.length > 0) {
|
|
110921
111060
|
systemPrompt += `
|
|
110922
111061
|
|
|
@@ -110951,25 +111090,27 @@ Workspace: ${this.allowedFolders.join(", ")}`;
|
|
|
110951
111090
|
} else {
|
|
110952
111091
|
systemPrompt += predefinedPrompts["code-explorer"] + "\n\n";
|
|
110953
111092
|
}
|
|
111093
|
+
const searchToolDesc2 = this.searchDelegate ? '- search: Ask natural language questions to find code (e.g., "How does authentication work?"). A subagent handles keyword searches and returns extracted code blocks. Do NOT formulate keyword queries \u2014 just ask questions.' : "- search: Find code patterns using keyword queries with Elasticsearch syntax. Handles stemming and case variations automatically \u2014 do NOT try manual keyword variations.";
|
|
110954
111094
|
systemPrompt += `You have access to powerful code search and analysis tools through MCP:
|
|
110955
|
-
|
|
111095
|
+
${searchToolDesc2}
|
|
110956
111096
|
- extract: Extract specific code sections with context
|
|
110957
|
-
- query: Use AST patterns for structural code matching
|
|
110958
111097
|
- listFiles: Browse directory contents
|
|
110959
111098
|
- searchFiles: Find files by name patterns`;
|
|
110960
111099
|
if (this.enableBash) {
|
|
110961
111100
|
systemPrompt += `
|
|
110962
111101
|
- bash: Execute bash commands for system operations`;
|
|
110963
111102
|
}
|
|
110964
|
-
const
|
|
110965
|
-
const
|
|
111103
|
+
const searchGuidance2 = this.searchDelegate ? "1. Start with search \u2014 ask a question about what you want to understand. It returns extracted code blocks directly." : "1. Start with search to find relevant code patterns. One search per concept is usually enough \u2014 probe handles stemming and case variations.";
|
|
111104
|
+
const extractGuidance2 = this.searchDelegate ? "2. Use extract only if you need more context or a full file" : "2. Use extract to get detailed context when needed";
|
|
110966
111105
|
systemPrompt += `
|
|
110967
111106
|
|
|
110968
111107
|
When exploring code:
|
|
110969
|
-
${
|
|
110970
|
-
${
|
|
111108
|
+
${searchGuidance2}
|
|
111109
|
+
${extractGuidance2}
|
|
110971
111110
|
3. Prefer focused, specific searches over broad queries
|
|
110972
|
-
4.
|
|
111111
|
+
4. Do NOT repeat the same search or try trivial keyword variations \u2014 probe handles stemming and case variations automatically
|
|
111112
|
+
5. If 2-3 consecutive searches return no results for a concept, stop searching for it \u2014 the term likely does not exist in that codebase
|
|
111113
|
+
6. Combine multiple tools to build complete understanding`;
|
|
110973
111114
|
if (this.allowedFolders && this.allowedFolders.length > 0) {
|
|
110974
111115
|
systemPrompt += `
|
|
110975
111116
|
|
|
@@ -111020,10 +111161,10 @@ Workspace: ${this.allowedFolders.join(", ")}`;
|
|
|
111020
111161
|
Follow these instructions carefully:
|
|
111021
111162
|
1. Analyze the user's request.
|
|
111022
111163
|
2. Use the available tools step-by-step to fulfill the request.
|
|
111023
|
-
3. You should always prefer the search tool for code-related questions.${this.searchDelegate ? "
|
|
111164
|
+
3. You should always prefer the search tool for code-related questions.${this.searchDelegate ? " Ask natural language questions \u2014 the search subagent handles keyword formulation and returns extracted code blocks. Use extract only to expand context or read full files." : " Search handles stemming and case variations automatically \u2014 do NOT try keyword variations manually. Read full files only if really necessary."}
|
|
111024
111165
|
4. Ensure to get really deep and understand the full picture before answering.
|
|
111025
111166
|
5. Once the task is fully completed, use the attempt_completion tool to provide the final result.
|
|
111026
|
-
6. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results
|
|
111167
|
+
6. ${this.searchDelegate ? "Ask clear, specific questions when searching. Each search should target a distinct concept or question." : "Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results."}${this.allowEdit ? `
|
|
111027
111168
|
7. When modifying files, choose the appropriate tool:
|
|
111028
111169
|
- Use 'edit' for all code modifications:
|
|
111029
111170
|
* PREFERRED: Use start_line (and optionally end_line) for line-targeted editing \u2014 this is the safest and most precise approach.${this.hashLines ? ' Use the line:hash references from extract/search output (e.g. "42:ab") for integrity verification.' : ""} Always use extract first to see line numbers${this.hashLines ? " and hashes" : ""}, then edit by line reference.
|
|
@@ -111347,6 +111488,10 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
111347
111488
|
completionResult = result;
|
|
111348
111489
|
completionAttempted = true;
|
|
111349
111490
|
}, toolContext);
|
|
111491
|
+
if (this.debug) {
|
|
111492
|
+
const toolNames = Object.keys(tools2);
|
|
111493
|
+
console.log(`[DEBUG] Agent tools registered (${toolNames.length}): ${toolNames.join(", ")}`);
|
|
111494
|
+
}
|
|
111350
111495
|
let maxResponseTokens = this.maxResponseTokens;
|
|
111351
111496
|
if (!maxResponseTokens) {
|
|
111352
111497
|
maxResponseTokens = 4e3;
|
|
@@ -111386,6 +111531,7 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
111386
111531
|
}
|
|
111387
111532
|
if (this.debug) {
|
|
111388
111533
|
console.log(`[DEBUG] Step ${currentIteration}/${maxIterations} finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
|
|
111534
|
+
debugLogToolResults(toolResults);
|
|
111389
111535
|
}
|
|
111390
111536
|
}
|
|
111391
111537
|
};
|
|
@@ -111542,6 +111688,7 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
111542
111688
|
}
|
|
111543
111689
|
if (this.debug) {
|
|
111544
111690
|
console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
|
|
111691
|
+
debugLogToolResults(toolResults);
|
|
111545
111692
|
}
|
|
111546
111693
|
}
|
|
111547
111694
|
};
|
|
@@ -112252,6 +112399,9 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
112252
112399
|
* Clean up resources (including MCP connections)
|
|
112253
112400
|
*/
|
|
112254
112401
|
async cleanup() {
|
|
112402
|
+
if (!this._abortController.signal.aborted) {
|
|
112403
|
+
this._abortController.abort();
|
|
112404
|
+
}
|
|
112255
112405
|
if (this.mcpBridge) {
|
|
112256
112406
|
try {
|
|
112257
112407
|
await this.mcpBridge.cleanup();
|
|
@@ -112275,14 +112425,25 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
112275
112425
|
this.clearHistory();
|
|
112276
112426
|
}
|
|
112277
112427
|
/**
|
|
112278
|
-
* Cancel the current request
|
|
112428
|
+
* Cancel the current request and all in-flight delegations.
|
|
112429
|
+
* Aborts the internal AbortController so streamText, subagents,
|
|
112430
|
+
* and any code checking the signal will stop.
|
|
112279
112431
|
*/
|
|
112280
112432
|
cancel() {
|
|
112281
112433
|
this.cancelled = true;
|
|
112434
|
+
this._abortController.abort();
|
|
112282
112435
|
if (this.debug) {
|
|
112283
112436
|
console.log(`[DEBUG] Agent cancelled for session ${this.sessionId}`);
|
|
112284
112437
|
}
|
|
112285
112438
|
}
|
|
112439
|
+
/**
|
|
112440
|
+
* Get the abort signal for this agent.
|
|
112441
|
+
* Delegations and subagents should check this signal.
|
|
112442
|
+
* @returns {AbortSignal}
|
|
112443
|
+
*/
|
|
112444
|
+
get abortSignal() {
|
|
112445
|
+
return this._abortController.signal;
|
|
112446
|
+
}
|
|
112286
112447
|
};
|
|
112287
112448
|
}
|
|
112288
112449
|
});
|
|
@@ -112292,7 +112453,9 @@ init_ProbeAgent();
|
|
|
112292
112453
|
ENGINE_ACTIVITY_TIMEOUT_DEFAULT,
|
|
112293
112454
|
ENGINE_ACTIVITY_TIMEOUT_MAX,
|
|
112294
112455
|
ENGINE_ACTIVITY_TIMEOUT_MIN,
|
|
112295
|
-
ProbeAgent
|
|
112456
|
+
ProbeAgent,
|
|
112457
|
+
debugLogToolResults,
|
|
112458
|
+
debugTruncate
|
|
112296
112459
|
});
|
|
112297
112460
|
/*! Bundled license information:
|
|
112298
112461
|
|