@probelabs/probe 0.6.0-rc277 → 0.6.0-rc279
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-rc279-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc279-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc279-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc279-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/{probe-v0.6.0-rc277-x86_64-unknown-linux-musl.tar.gz → probe-v0.6.0-rc279-x86_64-unknown-linux-musl.tar.gz} +0 -0
- package/build/agent/ProbeAgent.js +63 -11
- package/build/agent/index.js +129 -33
- package/build/agent/shared/prompts.js +30 -8
- package/build/delegate.js +40 -11
- package/build/tools/analyzeAll.js +8 -4
- package/build/tools/vercel.js +7 -4
- package/cjs/agent/ProbeAgent.cjs +132 -34
- package/cjs/index.cjs +129 -33
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +63 -11
- package/src/agent/shared/prompts.js +30 -8
- package/src/delegate.js +40 -11
- package/src/tools/analyzeAll.js +8 -4
- package/src/tools/vercel.js +7 -4
- package/bin/binaries/probe-v0.6.0-rc277-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc277-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc277-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc277-x86_64-pc-windows-msvc.zip +0 -0
package/cjs/index.cjs
CHANGED
|
@@ -36120,7 +36120,7 @@ ${taskManager.formatTasksForPrompt()}`;
|
|
|
36120
36120
|
}
|
|
36121
36121
|
};
|
|
36122
36122
|
}
|
|
36123
|
-
var taskItemSchema, taskSchema, taskSystemPrompt
|
|
36123
|
+
var taskItemSchema, taskSchema, taskSystemPrompt;
|
|
36124
36124
|
var init_taskTool = __esm({
|
|
36125
36125
|
"src/agent/tasks/taskTool.js"() {
|
|
36126
36126
|
"use strict";
|
|
@@ -36181,11 +36181,6 @@ Tasks = logical units of work, not files or steps.
|
|
|
36181
36181
|
- Circular dependencies are rejected
|
|
36182
36182
|
- attempt_completion is blocked while tasks remain unresolved
|
|
36183
36183
|
`;
|
|
36184
|
-
taskGuidancePrompt = `Does this request have MULTIPLE DISTINCT GOALS?
|
|
36185
|
-
- "Do A AND B AND C" (multiple goals) \u2192 Create tasks for each goal
|
|
36186
|
-
- "Investigate/explain/find X" (single goal) \u2192 Skip tasks, just answer directly
|
|
36187
|
-
Multiple internal steps for ONE goal = NO tasks needed.
|
|
36188
|
-
If creating tasks, use the task tool with action="create" first.`;
|
|
36189
36184
|
}
|
|
36190
36185
|
});
|
|
36191
36186
|
|
|
@@ -82671,8 +82666,20 @@ If the solution is clear, you can jump to implementation right away. If not, ask
|
|
|
82671
82666
|
- Check imports and existing utilities before creating new helpers \u2014 the project may already have what you need.
|
|
82672
82667
|
|
|
82673
82668
|
# Task Planning
|
|
82674
|
-
|
|
82675
|
-
-
|
|
82669
|
+
When the request has **multiple distinct goals** (e.g. "Fix bug A AND add feature B"), use the task tool to track them:
|
|
82670
|
+
- Call the task tool with action="create" and a tasks array. Each task must have an "id" field.
|
|
82671
|
+
- Update task status to "in_progress" when starting and "completed" when done.
|
|
82672
|
+
- All tasks must be completed or cancelled before calling attempt_completion.
|
|
82673
|
+
- Stay flexible \u2014 add, remove, or reorganize tasks as your understanding changes.
|
|
82674
|
+
|
|
82675
|
+
Do NOT create tasks for single-goal requests, even complex ones. Multiple internal steps for one goal (search, read, analyze, implement) do not need tasks.
|
|
82676
|
+
|
|
82677
|
+
# Discovering Project Commands
|
|
82678
|
+
Before building or testing, determine the project's toolchain:
|
|
82679
|
+
- Check for Makefile, package.json (scripts), Cargo.toml, go.mod, pyproject.toml, or similar
|
|
82680
|
+
- Look for CI config (.github/workflows/, .gitlab-ci.yml) to see what commands CI runs
|
|
82681
|
+
- Read README for build/test instructions if the above are unclear
|
|
82682
|
+
- Common patterns: \`make build\`/\`make test\`, \`npm run build\`/\`npm test\`, \`cargo build\`/\`cargo test\`, \`go build ./...\`/\`go test ./...\`, \`python -m pytest\`
|
|
82676
82683
|
|
|
82677
82684
|
# During Implementation
|
|
82678
82685
|
- Always create a new branch before making changes to the codebase.
|
|
@@ -82683,12 +82690,22 @@ If the solution is clear, you can jump to implementation right away. If not, ask
|
|
|
82683
82690
|
- When editing files, keep edits focused and minimal. For changes spanning more than a few lines, prefer line-targeted editing (start_line/end_line) over text replacement (old_string) \u2014 it constrains scope and prevents accidental removal of adjacent content. Never include unrelated sections in an edit operation.
|
|
82684
82691
|
- After every significant change, verify the project still builds and passes linting. Do not wait until the end to discover breakage.
|
|
82685
82692
|
|
|
82686
|
-
#
|
|
82687
|
-
|
|
82688
|
-
-
|
|
82689
|
-
-
|
|
82690
|
-
-
|
|
82691
|
-
-
|
|
82693
|
+
# Writing Tests
|
|
82694
|
+
Every change must include tests. Before writing them:
|
|
82695
|
+
- Find existing test files for the module you changed \u2014 look in \`tests/\`, \`__tests__/\`, \`*_test.go\`, \`*.test.js\`, \`*.spec.ts\`, or co-located test modules (\`#[cfg(test)]\` in Rust).
|
|
82696
|
+
- Read those tests to understand the project's testing patterns: framework, assertion style, mocking approach, file naming, test organization.
|
|
82697
|
+
- Prefer extending an existing test file over creating a new one when your change is in the same module.
|
|
82698
|
+
- Write tests that cover the main path and important edge cases. Include a failing-input test when relevant.
|
|
82699
|
+
- When fixing a bug, write a failing test first that reproduces the bug, then fix the code to make it pass.
|
|
82700
|
+
|
|
82701
|
+
# Verify Changes
|
|
82702
|
+
Before committing or creating a PR, run through this checklist:
|
|
82703
|
+
1. **Build** \u2014 run the project-appropriate build command (go build, npm run build, cargo build, make, etc.). Fix any compilation errors.
|
|
82704
|
+
2. **Lint & typecheck** \u2014 run linter/formatter if the project has one (eslint, clippy, golangci-lint, etc.). Fix any new warnings.
|
|
82705
|
+
3. **Test** \u2014 run the full test suite (go test ./..., npm test, cargo test, make test, pytest, etc.). Fix any failures, including pre-existing tests you may have broken.
|
|
82706
|
+
4. **Review** \u2014 re-read your diff. Ensure no debug code, no unrelated changes, no secrets, no missing files.
|
|
82707
|
+
|
|
82708
|
+
Do NOT skip verification. Do NOT proceed to PR creation with a broken build or failing tests.
|
|
82692
82709
|
|
|
82693
82710
|
# GitHub Integration
|
|
82694
82711
|
- Use the \`gh\` CLI for all GitHub operations: issues, pull requests, checks, releases.
|
|
@@ -105948,8 +105965,23 @@ __export(ProbeAgent_exports, {
|
|
|
105948
105965
|
ENGINE_ACTIVITY_TIMEOUT_DEFAULT: () => ENGINE_ACTIVITY_TIMEOUT_DEFAULT,
|
|
105949
105966
|
ENGINE_ACTIVITY_TIMEOUT_MAX: () => ENGINE_ACTIVITY_TIMEOUT_MAX,
|
|
105950
105967
|
ENGINE_ACTIVITY_TIMEOUT_MIN: () => ENGINE_ACTIVITY_TIMEOUT_MIN,
|
|
105951
|
-
ProbeAgent: () => ProbeAgent
|
|
105968
|
+
ProbeAgent: () => ProbeAgent,
|
|
105969
|
+
debugLogToolResults: () => debugLogToolResults,
|
|
105970
|
+
debugTruncate: () => debugTruncate
|
|
105952
105971
|
});
|
|
105972
|
+
function debugTruncate(s5, limit = 200) {
|
|
105973
|
+
if (s5.length <= limit) return s5;
|
|
105974
|
+
const half = Math.floor(limit / 2);
|
|
105975
|
+
return s5.substring(0, half) + ` ... [${s5.length} chars] ... ` + s5.substring(s5.length - half);
|
|
105976
|
+
}
|
|
105977
|
+
function debugLogToolResults(toolResults) {
|
|
105978
|
+
if (!toolResults || toolResults.length === 0) return;
|
|
105979
|
+
for (const tr of toolResults) {
|
|
105980
|
+
const argsStr = JSON.stringify(tr.args || {});
|
|
105981
|
+
const resultStr = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result || "");
|
|
105982
|
+
console.log(`[DEBUG] tool: ${tr.toolName} | args: ${debugTruncate(argsStr)} | result: ${debugTruncate(resultStr)}`);
|
|
105983
|
+
}
|
|
105984
|
+
}
|
|
105953
105985
|
var import_dotenv, import_anthropic2, import_openai2, import_google2, import_ai4, import_crypto8, import_events4, import_fs10, import_promises6, import_path15, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
|
|
105954
105986
|
var init_ProbeAgent = __esm({
|
|
105955
105987
|
"src/agent/ProbeAgent.js"() {
|
|
@@ -106069,6 +106101,7 @@ var init_ProbeAgent = __esm({
|
|
|
106069
106101
|
this.enableExecutePlan = !!options.enableExecutePlan;
|
|
106070
106102
|
this.debug = options.debug || process.env.DEBUG === "1";
|
|
106071
106103
|
this.cancelled = false;
|
|
106104
|
+
this._abortController = new AbortController();
|
|
106072
106105
|
this.tracer = options.tracer || null;
|
|
106073
106106
|
this.outline = !!options.outline;
|
|
106074
106107
|
this.searchDelegate = options.searchDelegate !== void 0 ? !!options.searchDelegate : true;
|
|
@@ -106514,6 +106547,8 @@ var init_ProbeAgent = __esm({
|
|
|
106514
106547
|
searchDelegateModel: this.searchDelegateModel,
|
|
106515
106548
|
delegationManager: this.delegationManager,
|
|
106516
106549
|
// Per-instance delegation limits
|
|
106550
|
+
parentAbortSignal: this._abortController.signal,
|
|
106551
|
+
// Propagate cancellation to delegations
|
|
106517
106552
|
outputBuffer: this._outputBuffer,
|
|
106518
106553
|
concurrencyLimiter: this.concurrencyLimiter,
|
|
106519
106554
|
// Global AI concurrency limiter
|
|
@@ -106961,6 +106996,15 @@ var init_ProbeAgent = __esm({
|
|
|
106961
106996
|
}
|
|
106962
106997
|
const controller = new AbortController();
|
|
106963
106998
|
const timeoutState = { timeoutId: null };
|
|
106999
|
+
if (this._abortController.signal.aborted) {
|
|
107000
|
+
controller.abort();
|
|
107001
|
+
} else {
|
|
107002
|
+
const onAgentAbort = () => controller.abort();
|
|
107003
|
+
this._abortController.signal.addEventListener("abort", onAgentAbort, { once: true });
|
|
107004
|
+
controller.signal.addEventListener("abort", () => {
|
|
107005
|
+
this._abortController.signal.removeEventListener("abort", onAgentAbort);
|
|
107006
|
+
}, { once: true });
|
|
107007
|
+
}
|
|
106964
107008
|
if (this.maxOperationTimeout && this.maxOperationTimeout > 0) {
|
|
106965
107009
|
timeoutState.timeoutId = setTimeout(() => {
|
|
106966
107010
|
controller.abort();
|
|
@@ -107264,7 +107308,8 @@ var init_ProbeAgent = __esm({
|
|
|
107264
107308
|
allowEdit: this.allowEdit,
|
|
107265
107309
|
allowedTools: allowedToolsForDelegate,
|
|
107266
107310
|
debug: this.debug,
|
|
107267
|
-
tracer: this.tracer
|
|
107311
|
+
tracer: this.tracer,
|
|
107312
|
+
parentAbortSignal: this._abortController.signal
|
|
107268
107313
|
};
|
|
107269
107314
|
if (this.debug) {
|
|
107270
107315
|
console.log(`[DEBUG] Executing delegate tool`);
|
|
@@ -108426,12 +108471,6 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
108426
108471
|
});
|
|
108427
108472
|
const systemMessage = await this.getSystemMessage();
|
|
108428
108473
|
let userMessage = { role: "user", content: message.trim() };
|
|
108429
|
-
if (this.enableTasks) {
|
|
108430
|
-
userMessage.content = userMessage.content + "\n\n" + taskGuidancePrompt;
|
|
108431
|
-
if (this.debug) {
|
|
108432
|
-
console.log("[DEBUG] Task guidance injected into user message");
|
|
108433
|
-
}
|
|
108434
|
-
}
|
|
108435
108474
|
if (options.schema && !options._schemaFormatted) {
|
|
108436
108475
|
const schemaInstructions = generateSchemaInstructions(options.schema, { debug: this.debug });
|
|
108437
108476
|
userMessage.content = message.trim() + schemaInstructions;
|
|
@@ -108587,6 +108626,10 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
108587
108626
|
completionResult = result;
|
|
108588
108627
|
completionAttempted = true;
|
|
108589
108628
|
}, toolContext);
|
|
108629
|
+
if (this.debug) {
|
|
108630
|
+
const toolNames = Object.keys(tools2);
|
|
108631
|
+
console.log(`[DEBUG] Agent tools registered (${toolNames.length}): ${toolNames.join(", ")}`);
|
|
108632
|
+
}
|
|
108590
108633
|
let maxResponseTokens = this.maxResponseTokens;
|
|
108591
108634
|
if (!maxResponseTokens) {
|
|
108592
108635
|
maxResponseTokens = 4e3;
|
|
@@ -108626,6 +108669,7 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
108626
108669
|
}
|
|
108627
108670
|
if (this.debug) {
|
|
108628
108671
|
console.log(`[DEBUG] Step ${currentIteration}/${maxIterations} finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
|
|
108672
|
+
debugLogToolResults(toolResults);
|
|
108629
108673
|
}
|
|
108630
108674
|
}
|
|
108631
108675
|
};
|
|
@@ -108782,6 +108826,7 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
108782
108826
|
}
|
|
108783
108827
|
if (this.debug) {
|
|
108784
108828
|
console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
|
|
108829
|
+
debugLogToolResults(toolResults);
|
|
108785
108830
|
}
|
|
108786
108831
|
}
|
|
108787
108832
|
};
|
|
@@ -109492,6 +109537,9 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
109492
109537
|
* Clean up resources (including MCP connections)
|
|
109493
109538
|
*/
|
|
109494
109539
|
async cleanup() {
|
|
109540
|
+
if (!this._abortController.signal.aborted) {
|
|
109541
|
+
this._abortController.abort();
|
|
109542
|
+
}
|
|
109495
109543
|
if (this.mcpBridge) {
|
|
109496
109544
|
try {
|
|
109497
109545
|
await this.mcpBridge.cleanup();
|
|
@@ -109515,14 +109563,25 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
109515
109563
|
this.clearHistory();
|
|
109516
109564
|
}
|
|
109517
109565
|
/**
|
|
109518
|
-
* Cancel the current request
|
|
109566
|
+
* Cancel the current request and all in-flight delegations.
|
|
109567
|
+
* Aborts the internal AbortController so streamText, subagents,
|
|
109568
|
+
* and any code checking the signal will stop.
|
|
109519
109569
|
*/
|
|
109520
109570
|
cancel() {
|
|
109521
109571
|
this.cancelled = true;
|
|
109572
|
+
this._abortController.abort();
|
|
109522
109573
|
if (this.debug) {
|
|
109523
109574
|
console.log(`[DEBUG] Agent cancelled for session ${this.sessionId}`);
|
|
109524
109575
|
}
|
|
109525
109576
|
}
|
|
109577
|
+
/**
|
|
109578
|
+
* Get the abort signal for this agent.
|
|
109579
|
+
* Delegations and subagents should check this signal.
|
|
109580
|
+
* @returns {AbortSignal}
|
|
109581
|
+
*/
|
|
109582
|
+
get abortSignal() {
|
|
109583
|
+
return this._abortController.signal;
|
|
109584
|
+
}
|
|
109526
109585
|
};
|
|
109527
109586
|
}
|
|
109528
109587
|
});
|
|
@@ -109555,12 +109614,17 @@ async function delegate({
|
|
|
109555
109614
|
mcpConfigPath = null,
|
|
109556
109615
|
delegationManager = null,
|
|
109557
109616
|
// Optional per-instance manager, falls back to default singleton
|
|
109558
|
-
concurrencyLimiter = null
|
|
109617
|
+
concurrencyLimiter = null,
|
|
109559
109618
|
// Optional global AI concurrency limiter
|
|
109619
|
+
parentAbortSignal = null
|
|
109620
|
+
// Optional AbortSignal from parent to cancel this delegation
|
|
109560
109621
|
}) {
|
|
109561
109622
|
if (!task || typeof task !== "string") {
|
|
109562
109623
|
throw new Error("Task parameter is required and must be a string");
|
|
109563
109624
|
}
|
|
109625
|
+
if (parentAbortSignal?.aborted) {
|
|
109626
|
+
throw new Error("Delegation cancelled: parent operation was aborted");
|
|
109627
|
+
}
|
|
109564
109628
|
const hasExplicitTimeout = Object.prototype.hasOwnProperty.call(arguments?.[0] ?? {}, "timeout");
|
|
109565
109629
|
if (!hasExplicitTimeout) {
|
|
109566
109630
|
const envTimeoutMs = parseInt(process.env.DELEGATION_TIMEOUT_MS || "", 10);
|
|
@@ -109645,12 +109709,37 @@ async function delegate({
|
|
|
109645
109709
|
}
|
|
109646
109710
|
const timeoutPromise = new Promise((_, reject2) => {
|
|
109647
109711
|
timeoutId = setTimeout(() => {
|
|
109712
|
+
subagent.cancel();
|
|
109648
109713
|
reject2(new Error(`Delegation timed out after ${timeout} seconds`));
|
|
109649
109714
|
}, timeout * 1e3);
|
|
109650
109715
|
});
|
|
109716
|
+
let parentAbortHandler;
|
|
109717
|
+
const parentAbortPromise = new Promise((_, reject2) => {
|
|
109718
|
+
if (parentAbortSignal) {
|
|
109719
|
+
if (parentAbortSignal.aborted) {
|
|
109720
|
+
subagent.cancel();
|
|
109721
|
+
reject2(new Error("Delegation cancelled: parent operation was aborted"));
|
|
109722
|
+
return;
|
|
109723
|
+
}
|
|
109724
|
+
parentAbortHandler = () => {
|
|
109725
|
+
subagent.cancel();
|
|
109726
|
+
reject2(new Error("Delegation cancelled: parent operation was aborted"));
|
|
109727
|
+
};
|
|
109728
|
+
parentAbortSignal.addEventListener("abort", parentAbortHandler, { once: true });
|
|
109729
|
+
}
|
|
109730
|
+
});
|
|
109651
109731
|
const answerOptions = schema ? { schema } : void 0;
|
|
109652
109732
|
const answerPromise = answerOptions ? subagent.answer(task, [], answerOptions) : subagent.answer(task);
|
|
109653
|
-
const
|
|
109733
|
+
const racers = [answerPromise, timeoutPromise];
|
|
109734
|
+
if (parentAbortSignal) racers.push(parentAbortPromise);
|
|
109735
|
+
let response;
|
|
109736
|
+
try {
|
|
109737
|
+
response = await Promise.race(racers);
|
|
109738
|
+
} finally {
|
|
109739
|
+
if (parentAbortHandler && parentAbortSignal) {
|
|
109740
|
+
parentAbortSignal.removeEventListener("abort", parentAbortHandler);
|
|
109741
|
+
}
|
|
109742
|
+
}
|
|
109654
109743
|
if (timeoutId !== null) {
|
|
109655
109744
|
clearTimeout(timeoutId);
|
|
109656
109745
|
timeoutId = null;
|
|
@@ -110063,8 +110152,9 @@ Instructions:
|
|
|
110063
110152
|
promptType: "code-researcher",
|
|
110064
110153
|
allowedTools: ["extract"],
|
|
110065
110154
|
maxIterations: 5,
|
|
110066
|
-
delegationManager: options.delegationManager
|
|
110155
|
+
delegationManager: options.delegationManager,
|
|
110067
110156
|
// Per-instance delegation limits
|
|
110157
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
110068
110158
|
// timeout removed - inherit default from delegate (300s)
|
|
110069
110159
|
});
|
|
110070
110160
|
return { chunk, result };
|
|
@@ -110163,8 +110253,9 @@ Organize all findings into clear categories with items listed under each.${compl
|
|
|
110163
110253
|
promptType: "code-researcher",
|
|
110164
110254
|
allowedTools: [],
|
|
110165
110255
|
maxIterations: 5,
|
|
110166
|
-
delegationManager: options.delegationManager
|
|
110256
|
+
delegationManager: options.delegationManager,
|
|
110167
110257
|
// Per-instance delegation limits
|
|
110258
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
110168
110259
|
// timeout removed - inherit default from delegate (300s)
|
|
110169
110260
|
});
|
|
110170
110261
|
return result;
|
|
@@ -110228,8 +110319,9 @@ CRITICAL: Do NOT guess keywords. Actually run searches and see what returns resu
|
|
|
110228
110319
|
promptType: "code-researcher",
|
|
110229
110320
|
// Full tool access for exploration and experimentation
|
|
110230
110321
|
maxIterations: 15,
|
|
110231
|
-
delegationManager: options.delegationManager
|
|
110322
|
+
delegationManager: options.delegationManager,
|
|
110232
110323
|
// Per-instance delegation limits
|
|
110324
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
110233
110325
|
// timeout removed - inherit default from delegate (300s)
|
|
110234
110326
|
});
|
|
110235
110327
|
const plan = parsePlanningResult(stripResultTags(result));
|
|
@@ -110286,8 +110378,9 @@ When done, use the attempt_completion tool with your answer as the result.`;
|
|
|
110286
110378
|
promptType: "code-researcher",
|
|
110287
110379
|
allowedTools: [],
|
|
110288
110380
|
maxIterations: 5,
|
|
110289
|
-
delegationManager: options.delegationManager
|
|
110381
|
+
delegationManager: options.delegationManager,
|
|
110290
110382
|
// Per-instance delegation limits
|
|
110383
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
110291
110384
|
// timeout removed - inherit default from delegate (300s)
|
|
110292
110385
|
});
|
|
110293
110386
|
return stripResultTags(result);
|
|
@@ -110735,7 +110828,8 @@ var init_vercel = __esm({
|
|
|
110735
110828
|
promptType: "code-searcher",
|
|
110736
110829
|
allowedTools: ["search", "extract", "listFiles", "attempt_completion"],
|
|
110737
110830
|
searchDelegate: false,
|
|
110738
|
-
schema: CODE_SEARCH_SCHEMA
|
|
110831
|
+
schema: CODE_SEARCH_SCHEMA,
|
|
110832
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
110739
110833
|
});
|
|
110740
110834
|
const delegateResult = options.tracer?.withSpan ? await options.tracer.withSpan("search.delegate", runDelegation, {
|
|
110741
110835
|
"search.query": searchQuery,
|
|
@@ -110949,7 +111043,7 @@ var init_vercel = __esm({
|
|
|
110949
111043
|
name: "delegate",
|
|
110950
111044
|
description: delegateDescription,
|
|
110951
111045
|
inputSchema: delegateSchema,
|
|
110952
|
-
execute: async ({ task, currentIteration, maxIterations, parentSessionId, path: path9, provider, model, tracer, searchDelegate }) => {
|
|
111046
|
+
execute: async ({ task, currentIteration, maxIterations, parentSessionId, path: path9, provider, model, tracer, searchDelegate, parentAbortSignal }) => {
|
|
110953
111047
|
if (!task || typeof task !== "string") {
|
|
110954
111048
|
throw new Error("Task parameter is required and must be a non-empty string");
|
|
110955
111049
|
}
|
|
@@ -111007,8 +111101,9 @@ var init_vercel = __esm({
|
|
|
111007
111101
|
enableMcp,
|
|
111008
111102
|
mcpConfig,
|
|
111009
111103
|
mcpConfigPath,
|
|
111010
|
-
delegationManager
|
|
111104
|
+
delegationManager,
|
|
111011
111105
|
// Per-instance delegation limits
|
|
111106
|
+
parentAbortSignal
|
|
111012
111107
|
});
|
|
111013
111108
|
return result;
|
|
111014
111109
|
}
|
|
@@ -111046,8 +111141,9 @@ var init_vercel = __esm({
|
|
|
111046
111141
|
provider: options.provider,
|
|
111047
111142
|
model: options.model,
|
|
111048
111143
|
tracer: options.tracer,
|
|
111049
|
-
delegationManager
|
|
111144
|
+
delegationManager,
|
|
111050
111145
|
// Per-instance delegation limits
|
|
111146
|
+
parentAbortSignal: options.parentAbortSignal || null
|
|
111051
111147
|
});
|
|
111052
111148
|
return result;
|
|
111053
111149
|
} catch (error2) {
|
package/package.json
CHANGED
package/src/agent/ProbeAgent.js
CHANGED
|
@@ -104,7 +104,6 @@ import {
|
|
|
104
104
|
TaskManager,
|
|
105
105
|
createTaskTool,
|
|
106
106
|
taskSystemPrompt,
|
|
107
|
-
taskGuidancePrompt,
|
|
108
107
|
createTaskCompletionBlockedMessage
|
|
109
108
|
} from './tasks/index.js';
|
|
110
109
|
import { z } from 'zod';
|
|
@@ -126,6 +125,27 @@ const MAX_HISTORY_MESSAGES = 100;
|
|
|
126
125
|
// Maximum image file size (20MB) to prevent OOM attacks
|
|
127
126
|
const MAX_IMAGE_FILE_SIZE = 20 * 1024 * 1024;
|
|
128
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Truncate a string for debug logging, showing first and last portion.
|
|
130
|
+
*/
|
|
131
|
+
export function debugTruncate(s, limit = 200) {
|
|
132
|
+
if (s.length <= limit) return s;
|
|
133
|
+
const half = Math.floor(limit / 2);
|
|
134
|
+
return s.substring(0, half) + ` ... [${s.length} chars] ... ` + s.substring(s.length - half);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Log tool results details for debug output.
|
|
139
|
+
*/
|
|
140
|
+
export function debugLogToolResults(toolResults) {
|
|
141
|
+
if (!toolResults || toolResults.length === 0) return;
|
|
142
|
+
for (const tr of toolResults) {
|
|
143
|
+
const argsStr = JSON.stringify(tr.args || {});
|
|
144
|
+
const resultStr = typeof tr.result === 'string' ? tr.result : JSON.stringify(tr.result || '');
|
|
145
|
+
console.log(`[DEBUG] tool: ${tr.toolName} | args: ${debugTruncate(argsStr)} | result: ${debugTruncate(resultStr)}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
129
149
|
/**
|
|
130
150
|
* ProbeAgent class to handle AI interactions with code search capabilities
|
|
131
151
|
*/
|
|
@@ -194,6 +214,7 @@ export class ProbeAgent {
|
|
|
194
214
|
this.enableExecutePlan = !!options.enableExecutePlan;
|
|
195
215
|
this.debug = options.debug || process.env.DEBUG === '1';
|
|
196
216
|
this.cancelled = false;
|
|
217
|
+
this._abortController = new AbortController();
|
|
197
218
|
this.tracer = options.tracer || null;
|
|
198
219
|
this.outline = !!options.outline;
|
|
199
220
|
this.searchDelegate = options.searchDelegate !== undefined ? !!options.searchDelegate : true;
|
|
@@ -793,6 +814,7 @@ export class ProbeAgent {
|
|
|
793
814
|
searchDelegateProvider: this.searchDelegateProvider,
|
|
794
815
|
searchDelegateModel: this.searchDelegateModel,
|
|
795
816
|
delegationManager: this.delegationManager, // Per-instance delegation limits
|
|
817
|
+
parentAbortSignal: this._abortController.signal, // Propagate cancellation to delegations
|
|
796
818
|
outputBuffer: this._outputBuffer,
|
|
797
819
|
concurrencyLimiter: this.concurrencyLimiter, // Global AI concurrency limiter
|
|
798
820
|
isToolAllowed,
|
|
@@ -1363,6 +1385,19 @@ export class ProbeAgent {
|
|
|
1363
1385
|
const controller = new AbortController();
|
|
1364
1386
|
const timeoutState = { timeoutId: null };
|
|
1365
1387
|
|
|
1388
|
+
// Link agent-level abort to this operation's controller
|
|
1389
|
+
// so that cancel() / cleanup() stops the current streamText call
|
|
1390
|
+
if (this._abortController.signal.aborted) {
|
|
1391
|
+
controller.abort();
|
|
1392
|
+
} else {
|
|
1393
|
+
const onAgentAbort = () => controller.abort();
|
|
1394
|
+
this._abortController.signal.addEventListener('abort', onAgentAbort, { once: true });
|
|
1395
|
+
// Clean up listener when this controller aborts (from any source)
|
|
1396
|
+
controller.signal.addEventListener('abort', () => {
|
|
1397
|
+
this._abortController.signal.removeEventListener('abort', onAgentAbort);
|
|
1398
|
+
}, { once: true });
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1366
1401
|
// Set up overall operation timeout (default 5 minutes)
|
|
1367
1402
|
if (this.maxOperationTimeout && this.maxOperationTimeout > 0) {
|
|
1368
1403
|
timeoutState.timeoutId = setTimeout(() => {
|
|
@@ -1730,7 +1765,8 @@ export class ProbeAgent {
|
|
|
1730
1765
|
allowEdit: this.allowEdit,
|
|
1731
1766
|
allowedTools: allowedToolsForDelegate,
|
|
1732
1767
|
debug: this.debug,
|
|
1733
|
-
tracer: this.tracer
|
|
1768
|
+
tracer: this.tracer,
|
|
1769
|
+
parentAbortSignal: this._abortController.signal
|
|
1734
1770
|
};
|
|
1735
1771
|
|
|
1736
1772
|
if (this.debug) {
|
|
@@ -3153,14 +3189,6 @@ Follow these instructions carefully:
|
|
|
3153
3189
|
// Create user message with optional image support
|
|
3154
3190
|
let userMessage = { role: 'user', content: message.trim() };
|
|
3155
3191
|
|
|
3156
|
-
// START CHECKPOINT: Inject task guidance if tasks are enabled
|
|
3157
|
-
if (this.enableTasks) {
|
|
3158
|
-
userMessage.content = userMessage.content + '\n\n' + taskGuidancePrompt;
|
|
3159
|
-
if (this.debug) {
|
|
3160
|
-
console.log('[DEBUG] Task guidance injected into user message');
|
|
3161
|
-
}
|
|
3162
|
-
}
|
|
3163
|
-
|
|
3164
3192
|
// If schema is provided, prepend JSON format requirement to user message
|
|
3165
3193
|
if (options.schema && !options._schemaFormatted) {
|
|
3166
3194
|
const schemaInstructions = generateSchemaInstructions(options.schema, { debug: this.debug });
|
|
@@ -3378,6 +3406,11 @@ Follow these instructions carefully:
|
|
|
3378
3406
|
completionAttempted = true;
|
|
3379
3407
|
}, toolContext);
|
|
3380
3408
|
|
|
3409
|
+
if (this.debug) {
|
|
3410
|
+
const toolNames = Object.keys(tools);
|
|
3411
|
+
console.log(`[DEBUG] Agent tools registered (${toolNames.length}): ${toolNames.join(', ')}`);
|
|
3412
|
+
}
|
|
3413
|
+
|
|
3381
3414
|
let maxResponseTokens = this.maxResponseTokens;
|
|
3382
3415
|
if (!maxResponseTokens) {
|
|
3383
3416
|
maxResponseTokens = 4000;
|
|
@@ -3427,6 +3460,7 @@ Follow these instructions carefully:
|
|
|
3427
3460
|
|
|
3428
3461
|
if (this.debug) {
|
|
3429
3462
|
console.log(`[DEBUG] Step ${currentIteration}/${maxIterations} finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
|
|
3463
|
+
debugLogToolResults(toolResults);
|
|
3430
3464
|
}
|
|
3431
3465
|
}
|
|
3432
3466
|
};
|
|
@@ -3638,6 +3672,7 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
3638
3672
|
}
|
|
3639
3673
|
if (this.debug) {
|
|
3640
3674
|
console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
|
|
3675
|
+
debugLogToolResults(toolResults);
|
|
3641
3676
|
}
|
|
3642
3677
|
}
|
|
3643
3678
|
};
|
|
@@ -4554,6 +4589,11 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
4554
4589
|
* Clean up resources (including MCP connections)
|
|
4555
4590
|
*/
|
|
4556
4591
|
async cleanup() {
|
|
4592
|
+
// Abort any in-flight operations (delegations, streaming, etc.)
|
|
4593
|
+
if (!this._abortController.signal.aborted) {
|
|
4594
|
+
this._abortController.abort();
|
|
4595
|
+
}
|
|
4596
|
+
|
|
4557
4597
|
// Clean up MCP bridge
|
|
4558
4598
|
if (this.mcpBridge) {
|
|
4559
4599
|
try {
|
|
@@ -4583,12 +4623,24 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
4583
4623
|
}
|
|
4584
4624
|
|
|
4585
4625
|
/**
|
|
4586
|
-
* Cancel the current request
|
|
4626
|
+
* Cancel the current request and all in-flight delegations.
|
|
4627
|
+
* Aborts the internal AbortController so streamText, subagents,
|
|
4628
|
+
* and any code checking the signal will stop.
|
|
4587
4629
|
*/
|
|
4588
4630
|
cancel() {
|
|
4589
4631
|
this.cancelled = true;
|
|
4632
|
+
this._abortController.abort();
|
|
4590
4633
|
if (this.debug) {
|
|
4591
4634
|
console.log(`[DEBUG] Agent cancelled for session ${this.sessionId}`);
|
|
4592
4635
|
}
|
|
4593
4636
|
}
|
|
4637
|
+
|
|
4638
|
+
/**
|
|
4639
|
+
* Get the abort signal for this agent.
|
|
4640
|
+
* Delegations and subagents should check this signal.
|
|
4641
|
+
* @returns {AbortSignal}
|
|
4642
|
+
*/
|
|
4643
|
+
get abortSignal() {
|
|
4644
|
+
return this._abortController.signal;
|
|
4645
|
+
}
|
|
4594
4646
|
}
|
|
@@ -81,8 +81,20 @@ If the solution is clear, you can jump to implementation right away. If not, ask
|
|
|
81
81
|
- Check imports and existing utilities before creating new helpers — the project may already have what you need.
|
|
82
82
|
|
|
83
83
|
# Task Planning
|
|
84
|
-
|
|
85
|
-
-
|
|
84
|
+
When the request has **multiple distinct goals** (e.g. "Fix bug A AND add feature B"), use the task tool to track them:
|
|
85
|
+
- Call the task tool with action="create" and a tasks array. Each task must have an "id" field.
|
|
86
|
+
- Update task status to "in_progress" when starting and "completed" when done.
|
|
87
|
+
- All tasks must be completed or cancelled before calling attempt_completion.
|
|
88
|
+
- Stay flexible — add, remove, or reorganize tasks as your understanding changes.
|
|
89
|
+
|
|
90
|
+
Do NOT create tasks for single-goal requests, even complex ones. Multiple internal steps for one goal (search, read, analyze, implement) do not need tasks.
|
|
91
|
+
|
|
92
|
+
# Discovering Project Commands
|
|
93
|
+
Before building or testing, determine the project's toolchain:
|
|
94
|
+
- Check for Makefile, package.json (scripts), Cargo.toml, go.mod, pyproject.toml, or similar
|
|
95
|
+
- Look for CI config (.github/workflows/, .gitlab-ci.yml) to see what commands CI runs
|
|
96
|
+
- Read README for build/test instructions if the above are unclear
|
|
97
|
+
- Common patterns: \`make build\`/\`make test\`, \`npm run build\`/\`npm test\`, \`cargo build\`/\`cargo test\`, \`go build ./...\`/\`go test ./...\`, \`python -m pytest\`
|
|
86
98
|
|
|
87
99
|
# During Implementation
|
|
88
100
|
- Always create a new branch before making changes to the codebase.
|
|
@@ -93,12 +105,22 @@ If the solution is clear, you can jump to implementation right away. If not, ask
|
|
|
93
105
|
- When editing files, keep edits focused and minimal. For changes spanning more than a few lines, prefer line-targeted editing (start_line/end_line) over text replacement (old_string) — it constrains scope and prevents accidental removal of adjacent content. Never include unrelated sections in an edit operation.
|
|
94
106
|
- After every significant change, verify the project still builds and passes linting. Do not wait until the end to discover breakage.
|
|
95
107
|
|
|
96
|
-
#
|
|
97
|
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
108
|
+
# Writing Tests
|
|
109
|
+
Every change must include tests. Before writing them:
|
|
110
|
+
- Find existing test files for the module you changed — look in \`tests/\`, \`__tests__/\`, \`*_test.go\`, \`*.test.js\`, \`*.spec.ts\`, or co-located test modules (\`#[cfg(test)]\` in Rust).
|
|
111
|
+
- Read those tests to understand the project's testing patterns: framework, assertion style, mocking approach, file naming, test organization.
|
|
112
|
+
- Prefer extending an existing test file over creating a new one when your change is in the same module.
|
|
113
|
+
- Write tests that cover the main path and important edge cases. Include a failing-input test when relevant.
|
|
114
|
+
- When fixing a bug, write a failing test first that reproduces the bug, then fix the code to make it pass.
|
|
115
|
+
|
|
116
|
+
# Verify Changes
|
|
117
|
+
Before committing or creating a PR, run through this checklist:
|
|
118
|
+
1. **Build** — run the project-appropriate build command (go build, npm run build, cargo build, make, etc.). Fix any compilation errors.
|
|
119
|
+
2. **Lint & typecheck** — run linter/formatter if the project has one (eslint, clippy, golangci-lint, etc.). Fix any new warnings.
|
|
120
|
+
3. **Test** — run the full test suite (go test ./..., npm test, cargo test, make test, pytest, etc.). Fix any failures, including pre-existing tests you may have broken.
|
|
121
|
+
4. **Review** — re-read your diff. Ensure no debug code, no unrelated changes, no secrets, no missing files.
|
|
122
|
+
|
|
123
|
+
Do NOT skip verification. Do NOT proceed to PR creation with a broken build or failing tests.
|
|
102
124
|
|
|
103
125
|
# GitHub Integration
|
|
104
126
|
- Use the \`gh\` CLI for all GitHub operations: issues, pull requests, checks, releases.
|
package/src/delegate.js
CHANGED
|
@@ -386,12 +386,18 @@ export async function delegate({
|
|
|
386
386
|
mcpConfig = null,
|
|
387
387
|
mcpConfigPath = null,
|
|
388
388
|
delegationManager = null, // Optional per-instance manager, falls back to default singleton
|
|
389
|
-
concurrencyLimiter = null // Optional global AI concurrency limiter
|
|
389
|
+
concurrencyLimiter = null, // Optional global AI concurrency limiter
|
|
390
|
+
parentAbortSignal = null // Optional AbortSignal from parent to cancel this delegation
|
|
390
391
|
}) {
|
|
391
392
|
if (!task || typeof task !== 'string') {
|
|
392
393
|
throw new Error('Task parameter is required and must be a string');
|
|
393
394
|
}
|
|
394
395
|
|
|
396
|
+
// Check if parent has already been cancelled
|
|
397
|
+
if (parentAbortSignal?.aborted) {
|
|
398
|
+
throw new Error('Delegation cancelled: parent operation was aborted');
|
|
399
|
+
}
|
|
400
|
+
|
|
395
401
|
// Support runtime timeout override via environment variables when timeout not explicitly passed
|
|
396
402
|
// This allows operators to configure delegation timeouts without code changes
|
|
397
403
|
// Priority: DELEGATION_TIMEOUT_MS (milliseconds) > DELEGATION_TIMEOUT_SECONDS > DELEGATION_TIMEOUT (seconds)
|
|
@@ -481,24 +487,47 @@ export async function delegate({
|
|
|
481
487
|
console.error(`[DELEGATE] Subagent config: promptType=${promptType}, enableDelegate=false, maxIterations=${remainingIterations}`);
|
|
482
488
|
}
|
|
483
489
|
|
|
484
|
-
// Set up timeout
|
|
485
|
-
//
|
|
486
|
-
//
|
|
487
|
-
// This is acceptable since:
|
|
488
|
-
// 1. The promise will eventually resolve/reject and be garbage collected
|
|
489
|
-
// 2. The delegation slot is properly released on timeout
|
|
490
|
-
// 3. The parent receives timeout error and can handle it
|
|
491
|
-
// Future improvement: Add signal parameter to ProbeAgent.answer(task, [], { signal })
|
|
490
|
+
// Set up timeout and parent abort handling.
|
|
491
|
+
// When timeout fires or parent aborts, we cancel the subagent so it
|
|
492
|
+
// stops making API calls and releases resources promptly.
|
|
492
493
|
const timeoutPromise = new Promise((_, reject) => {
|
|
493
494
|
timeoutId = setTimeout(() => {
|
|
495
|
+
subagent.cancel();
|
|
494
496
|
reject(new Error(`Delegation timed out after ${timeout} seconds`));
|
|
495
497
|
}, timeout * 1000);
|
|
496
498
|
});
|
|
497
499
|
|
|
498
|
-
//
|
|
500
|
+
// Listen for parent abort signal
|
|
501
|
+
let parentAbortHandler;
|
|
502
|
+
const parentAbortPromise = new Promise((_, reject) => {
|
|
503
|
+
if (parentAbortSignal) {
|
|
504
|
+
if (parentAbortSignal.aborted) {
|
|
505
|
+
subagent.cancel();
|
|
506
|
+
reject(new Error('Delegation cancelled: parent operation was aborted'));
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
parentAbortHandler = () => {
|
|
510
|
+
subagent.cancel();
|
|
511
|
+
reject(new Error('Delegation cancelled: parent operation was aborted'));
|
|
512
|
+
};
|
|
513
|
+
parentAbortSignal.addEventListener('abort', parentAbortHandler, { once: true });
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
// Execute the task with timeout and parent abort
|
|
499
518
|
const answerOptions = schema ? { schema } : undefined;
|
|
500
519
|
const answerPromise = answerOptions ? subagent.answer(task, [], answerOptions) : subagent.answer(task);
|
|
501
|
-
const
|
|
520
|
+
const racers = [answerPromise, timeoutPromise];
|
|
521
|
+
if (parentAbortSignal) racers.push(parentAbortPromise);
|
|
522
|
+
let response;
|
|
523
|
+
try {
|
|
524
|
+
response = await Promise.race(racers);
|
|
525
|
+
} finally {
|
|
526
|
+
// Clean up parent abort listener to prevent memory leaks
|
|
527
|
+
if (parentAbortHandler && parentAbortSignal) {
|
|
528
|
+
parentAbortSignal.removeEventListener('abort', parentAbortHandler);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
502
531
|
|
|
503
532
|
// Clear timeout immediately after race completes to prevent memory leak
|
|
504
533
|
// Note: timeoutId is always set by this point (synchronous in Promise constructor)
|