@probelabs/probe 0.6.0-rc201 → 0.6.0-rc203
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 +31 -1
- package/bin/binaries/probe-v0.6.0-rc203-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc203-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc203-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc203-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc203-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.d.ts +11 -1
- package/build/agent/ProbeAgent.js +310 -14
- package/build/agent/index.js +8615 -394
- package/build/agent/probeTool.js +2 -2
- package/build/agent/schemaUtils.js +37 -18
- package/build/agent/shared/prompts.js +17 -0
- package/build/agent/skills/formatting.js +23 -0
- package/build/agent/skills/parser.js +162 -0
- package/build/agent/skills/registry.js +185 -0
- package/build/agent/skills/tools.js +65 -0
- package/build/agent/tools.js +44 -0
- package/build/delegate.js +27 -7
- package/build/tools/common.js +17 -4
- package/build/tools/system-message.js +4 -4
- package/build/tools/vercel.js +243 -36
- package/cjs/agent/ProbeAgent.cjs +14990 -7892
- package/cjs/index.cjs +15003 -7905
- package/index.d.ts +8 -0
- package/package.json +2 -1
- package/scripts/postinstall.js +10 -4
- package/src/agent/ProbeAgent.d.ts +11 -1
- package/src/agent/ProbeAgent.js +310 -14
- package/src/agent/index.js +21 -1
- package/src/agent/probeTool.js +2 -2
- package/src/agent/schemaUtils.js +37 -18
- package/src/agent/shared/prompts.js +17 -0
- package/src/agent/skills/formatting.js +23 -0
- package/src/agent/skills/parser.js +162 -0
- package/src/agent/skills/registry.js +185 -0
- package/src/agent/skills/tools.js +65 -0
- package/src/agent/tools.js +44 -0
- package/src/delegate.js +27 -7
- package/src/tools/common.js +17 -4
- package/src/tools/system-message.js +4 -4
- package/src/tools/vercel.js +243 -36
- package/bin/binaries/probe-v0.6.0-rc201-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc201-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc201-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc201-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc201-x86_64-unknown-linux-musl.tar.gz +0 -0
package/build/delegate.js
CHANGED
|
@@ -173,11 +173,18 @@ const delegationManager = new DelegationManager();
|
|
|
173
173
|
* @param {number} [options.maxIterations=30] - Maximum tool iterations allowed
|
|
174
174
|
* @param {string} [options.parentSessionId=null] - Parent session ID for tracking
|
|
175
175
|
* @param {string} [options.path] - Search directory path (inherited from parent)
|
|
176
|
+
* @param {string[]} [options.allowedFolders] - Allowed folders (inherited from parent)
|
|
176
177
|
* @param {string} [options.provider] - AI provider (inherited from parent)
|
|
177
178
|
* @param {string} [options.model] - AI model (inherited from parent)
|
|
178
179
|
* @param {Object} [options.tracer=null] - Telemetry tracer instance
|
|
179
180
|
* @param {boolean} [options.enableBash=false] - Enable bash tool (inherited from parent)
|
|
180
181
|
* @param {Object} [options.bashConfig] - Bash configuration (inherited from parent)
|
|
182
|
+
* @param {string} [options.architectureFileName] - Architecture context filename to embed from repo root
|
|
183
|
+
* @param {string} [options.promptType='code-researcher'] - Prompt type for the subagent
|
|
184
|
+
* @param {Array<string>|null} [options.allowedTools] - Allowed tools for the subagent (null = default)
|
|
185
|
+
* @param {boolean} [options.disableTools=false] - Disable all tools for the subagent
|
|
186
|
+
* @param {boolean} [options.searchDelegate] - Use delegated search in the subagent
|
|
187
|
+
* @param {Object|string} [options.schema] - Optional JSON schema to enforce response format
|
|
181
188
|
* @returns {Promise<string>} The response from the delegate agent
|
|
182
189
|
*/
|
|
183
190
|
export async function delegate({
|
|
@@ -189,10 +196,17 @@ export async function delegate({
|
|
|
189
196
|
tracer = null,
|
|
190
197
|
parentSessionId = null,
|
|
191
198
|
path = null,
|
|
199
|
+
allowedFolders = null,
|
|
192
200
|
provider = null,
|
|
193
201
|
model = null,
|
|
194
202
|
enableBash = false,
|
|
195
|
-
bashConfig = null
|
|
203
|
+
bashConfig = null,
|
|
204
|
+
architectureFileName = null,
|
|
205
|
+
promptType = 'code-researcher',
|
|
206
|
+
allowedTools = null,
|
|
207
|
+
disableTools = false,
|
|
208
|
+
searchDelegate = undefined,
|
|
209
|
+
schema = null
|
|
196
210
|
}) {
|
|
197
211
|
if (!task || typeof task !== 'string') {
|
|
198
212
|
throw new Error('Task parameter is required and must be a string');
|
|
@@ -226,7 +240,7 @@ export async function delegate({
|
|
|
226
240
|
console.error(`[DELEGATE] Remaining iterations for subagent: ${remainingIterations}`);
|
|
227
241
|
console.error(`[DELEGATE] Timeout configured: ${timeout} seconds`);
|
|
228
242
|
console.error(`[DELEGATE] Global active delegations: ${stats.globalActive}/${stats.maxConcurrent}`);
|
|
229
|
-
console.error(`[DELEGATE] Using ProbeAgent SDK with
|
|
243
|
+
console.error(`[DELEGATE] Using ProbeAgent SDK with ${promptType} prompt`);
|
|
230
244
|
}
|
|
231
245
|
// Create a new ProbeAgent instance for the delegated task
|
|
232
246
|
// IMPORTANT: We pass both path and cwd set to the same value (workspace root)
|
|
@@ -234,24 +248,29 @@ export async function delegate({
|
|
|
234
248
|
// affect the subagent's path resolution - subagents always work from workspace root.
|
|
235
249
|
const subagent = new ProbeAgent({
|
|
236
250
|
sessionId,
|
|
237
|
-
promptType
|
|
238
|
-
enableDelegate: false,
|
|
251
|
+
promptType, // Clean prompt, not inherited from parent
|
|
252
|
+
enableDelegate: false, // Explicitly disable delegation to prevent recursion
|
|
239
253
|
disableMermaidValidation: true, // Faster processing
|
|
240
254
|
disableJsonValidation: true, // Simpler responses
|
|
241
255
|
maxIterations: remainingIterations,
|
|
242
256
|
debug,
|
|
243
257
|
tracer,
|
|
244
258
|
path, // Workspace root (from delegateTool)
|
|
259
|
+
allowedFolders, // Inherit allowed folders to keep architecture context root consistent
|
|
245
260
|
cwd: path, // Explicitly set cwd to workspace root to prevent path doubling
|
|
246
261
|
provider, // Inherit from parent
|
|
247
262
|
model, // Inherit from parent
|
|
248
263
|
enableBash, // Inherit from parent
|
|
249
|
-
bashConfig
|
|
264
|
+
bashConfig, // Inherit from parent
|
|
265
|
+
architectureFileName,
|
|
266
|
+
allowedTools,
|
|
267
|
+
disableTools,
|
|
268
|
+
searchDelegate
|
|
250
269
|
});
|
|
251
270
|
|
|
252
271
|
if (debug) {
|
|
253
272
|
console.error(`[DELEGATE] Created subagent with session ${sessionId}`);
|
|
254
|
-
console.error(`[DELEGATE] Subagent config: promptType
|
|
273
|
+
console.error(`[DELEGATE] Subagent config: promptType=${promptType}, enableDelegate=false, maxIterations=${remainingIterations}`);
|
|
255
274
|
}
|
|
256
275
|
|
|
257
276
|
// Set up timeout with proper cleanup
|
|
@@ -269,7 +288,8 @@ export async function delegate({
|
|
|
269
288
|
});
|
|
270
289
|
|
|
271
290
|
// Execute the task with timeout
|
|
272
|
-
const
|
|
291
|
+
const answerOptions = schema ? { schema } : undefined;
|
|
292
|
+
const answerPromise = answerOptions ? subagent.answer(task, [], answerOptions) : subagent.answer(task);
|
|
273
293
|
const response = await Promise.race([answerPromise, timeoutPromise]);
|
|
274
294
|
|
|
275
295
|
// Clear timeout immediately after race completes to prevent memory leak
|
package/build/tools/common.js
CHANGED
|
@@ -30,6 +30,14 @@ export const delegateSchema = z.object({
|
|
|
30
30
|
task: z.string().describe('The task to delegate to a subagent. Be specific about what needs to be accomplished.')
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
+
export const listSkillsSchema = z.object({
|
|
34
|
+
filter: z.string().optional().describe('Optional substring filter to match skill names or descriptions.')
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
export const useSkillSchema = z.object({
|
|
38
|
+
name: z.string().describe('Skill name to load and activate.')
|
|
39
|
+
});
|
|
40
|
+
|
|
33
41
|
export const bashSchema = z.object({
|
|
34
42
|
command: z.string().describe('The bash command to execute'),
|
|
35
43
|
workingDirectory: z.string().optional().describe('Directory to execute the command in (optional)'),
|
|
@@ -103,7 +111,8 @@ export const attemptCompletionSchema = {
|
|
|
103
111
|
|
|
104
112
|
export const searchToolDefinition = `
|
|
105
113
|
## search
|
|
106
|
-
Description: Search code in the repository
|
|
114
|
+
Description: Search code in the repository. You may provide a free-form question about the code or a concise Elasticsearch-style keyword query (field based queries, e.g. "filename:..." NOT supported).
|
|
115
|
+
Note: This tool may internally use a dedicated search subagent when search delegation is enabled. This is separate from the "delegate" tool and does not require an explicit delegate call.
|
|
107
116
|
|
|
108
117
|
You need to focus on main keywords when constructing the query, and always use elastic search syntax like OR AND and brackets to group keywords.
|
|
109
118
|
|
|
@@ -113,7 +122,7 @@ You need to focus on main keywords when constructing the query, and always use e
|
|
|
113
122
|
- Once data is returned, it's cached and won't return on next runs (this is expected behavior)
|
|
114
123
|
|
|
115
124
|
Parameters:
|
|
116
|
-
- query: (required) Search query
|
|
125
|
+
- query: (required) Search query. Free-form questions are accepted, but for best results prefer Elasticsearch-style syntax with quotes for exact matches ("functionName"), AND/OR for boolean logic, - for negation, + for important terms.
|
|
117
126
|
- path: (optional, default: '.') Path to search in. All dependencies located in /dep folder, under language sub folders, like this: "/dep/go/github.com/owner/repo", "/dep/js/package_name", or "/dep/rust/cargo_name" etc.
|
|
118
127
|
|
|
119
128
|
**Workflow:** Always start with search, then use extract for detailed context when needed.
|
|
@@ -319,7 +328,7 @@ User: Check system info
|
|
|
319
328
|
</examples>
|
|
320
329
|
`;
|
|
321
330
|
|
|
322
|
-
export const searchDescription = 'Search code in the repository
|
|
331
|
+
export const 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.';
|
|
323
332
|
export const queryDescription = 'Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.';
|
|
324
333
|
export const 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.';
|
|
325
334
|
export const 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.';
|
|
@@ -332,6 +341,8 @@ export const DEFAULT_VALID_TOOLS = [
|
|
|
332
341
|
'query',
|
|
333
342
|
'extract',
|
|
334
343
|
'delegate',
|
|
344
|
+
'listSkills',
|
|
345
|
+
'useSkill',
|
|
335
346
|
'listFiles',
|
|
336
347
|
'searchFiles',
|
|
337
348
|
'implement',
|
|
@@ -366,6 +377,8 @@ function getValidParamsForTool(toolName) {
|
|
|
366
377
|
query: querySchema,
|
|
367
378
|
extract: extractSchema,
|
|
368
379
|
delegate: delegateSchema,
|
|
380
|
+
listSkills: listSkillsSchema,
|
|
381
|
+
useSkill: useSkillSchema,
|
|
369
382
|
bash: bashSchema,
|
|
370
383
|
attempt_completion: attemptCompletionSchema,
|
|
371
384
|
edit: editSchema,
|
|
@@ -628,4 +641,4 @@ export function resolveTargetPath(target, cwd) {
|
|
|
628
641
|
}
|
|
629
642
|
|
|
630
643
|
return filePart + suffix;
|
|
631
|
-
}
|
|
644
|
+
}
|
|
@@ -11,7 +11,7 @@ You are Probe, a specialized code intelligence assistant. Your objective is to a
|
|
|
11
11
|
1. **Tool-First Always:** Immediately use tools for any code-related query. Do not guess or use general knowledge.
|
|
12
12
|
2. **Mandatory Path:** ALL tool calls (\`search\`, \`query\`, \`extract\`) MUST include the \`path\` argument. Use \`"."\` for the whole project, specific directories/files (e.g., \`"src/api"\`, \`"pkg/utils/helpers.py"\`), or dependency syntax (e.g., \`"go:github.com/gin-gonic/gin"\`, \`"js:@ai-sdk/anthropic"\`, \`"rust:serde"\`).
|
|
13
13
|
3. **Start with \`search\`:**
|
|
14
|
-
* **
|
|
14
|
+
* **Free-form is OK, keywords are better:** You may ask a free-form question about the code, but for best results use Elasticsearch-style keywords, boolean operators (\`AND\`, \`OR\`, \`NOT\`), and exact phrases (\`""\`).
|
|
15
15
|
* **Iterate if Needed:** If initial results are too broad or insufficient, **repeat the exact same \`search\` query** to get the next page of results (pagination). Reuse the \`sessionID\` if provided by the previous identical search. If results are irrelevant, refine the keywords (add terms, use \`NOT\`, try synonyms).
|
|
16
16
|
4. **Analyze & Refine:** Review \`search\` results (snippets, file paths).
|
|
17
17
|
* Use \`query\` if you need code based on *structure* (AST patterns) within specific files/directories identified by \`search\`.
|
|
@@ -23,8 +23,8 @@ You are Probe, a specialized code intelligence assistant. Your objective is to a
|
|
|
23
23
|
|
|
24
24
|
* \`search\`
|
|
25
25
|
* **Purpose:** Find relevant code snippets/files using keyword-based search (like Elasticsearch). Locate named symbols. Search project code or dependencies.
|
|
26
|
-
* **Syntax:** \`query\` (Elasticsearch-like
|
|
27
|
-
* **Features:** Returns snippets/paths. Supports pagination (repeat query). Caching via \`sessionID\` (reuse if returned). Use \`exact\` flag when you need precise matching of terms.
|
|
26
|
+
* **Syntax:** \`query\` (free-form question or Elasticsearch-like keywords: \`AND\`, \`OR\`, \`NOT\`, \`""\` exact phrases), \`path\` (Mandatory: \`"."\`, \`"path/to/dir"\`, \`"path/to/file.ext"\`, \`"go:pkg"\`, \`"js:npm_module"\`, \`"rust:crate"\`), \`exact\` (Optional: Set to \`true\` for case-insensitive exact matching without tokenization).
|
|
27
|
+
* **Features:** Returns snippets/paths. Supports pagination (repeat query). Caching via \`sessionID\` (reuse if returned). Use \`exact\` flag when you need precise matching of terms. This tool may internally delegate code discovery when configured; this is not the same as the \`delegate\` tool and requires no explicit call.
|
|
28
28
|
* \`query\`
|
|
29
29
|
* **Purpose:** Find code by its *structure* (AST patterns) within specific files/directories, typically after \`search\`.
|
|
30
30
|
* **Syntax:** \`pattern\` (ast-grep pattern), \`language\` (e.g., "go", "python").
|
|
@@ -124,4 +124,4 @@ For GitHub-compatible mermaid diagrams, avoid single quotes and parentheses in n
|
|
|
124
124
|
- **requirement**: system requirements, traceability
|
|
125
125
|
- **packet**: network protocols, data packets
|
|
126
126
|
- **zenuml**: UML sequence diagrams
|
|
127
|
-
</mermaid-instructions>`
|
|
127
|
+
</mermaid-instructions>`
|
package/build/tools/vercel.js
CHANGED
|
@@ -10,6 +10,125 @@ import { extract } from '../extract.js';
|
|
|
10
10
|
import { delegate } from '../delegate.js';
|
|
11
11
|
import { searchSchema, querySchema, extractSchema, delegateSchema, searchDescription, queryDescription, extractDescription, delegateDescription, parseTargets, parseAndResolvePaths, resolveTargetPath } from './common.js';
|
|
12
12
|
|
|
13
|
+
const CODE_SEARCH_SCHEMA = {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
targets: {
|
|
17
|
+
type: 'array',
|
|
18
|
+
items: { type: 'string' },
|
|
19
|
+
description: 'List of file targets like "path/to/file.ext#Symbol" or "path/to/file.ext:line" or "path/to/file.ext:start-end".'
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
required: ['targets'],
|
|
23
|
+
additionalProperties: false
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function normalizeTargets(targets) {
|
|
27
|
+
if (!Array.isArray(targets)) return [];
|
|
28
|
+
const seen = new Set();
|
|
29
|
+
const normalized = [];
|
|
30
|
+
|
|
31
|
+
for (const target of targets) {
|
|
32
|
+
if (typeof target !== 'string') continue;
|
|
33
|
+
const trimmed = target.trim();
|
|
34
|
+
if (!trimmed || seen.has(trimmed)) continue;
|
|
35
|
+
seen.add(trimmed);
|
|
36
|
+
normalized.push(trimmed);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return normalized;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function extractJsonSnippet(text) {
|
|
43
|
+
const jsonBlockMatch = text.match(/```json\s*([\s\S]*?)```/i);
|
|
44
|
+
if (jsonBlockMatch) {
|
|
45
|
+
return jsonBlockMatch[1].trim();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const anyBlockMatch = text.match(/```\s*([\s\S]*?)```/);
|
|
49
|
+
if (anyBlockMatch) {
|
|
50
|
+
return anyBlockMatch[1].trim();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const firstBrace = text.indexOf('{');
|
|
54
|
+
const lastBrace = text.lastIndexOf('}');
|
|
55
|
+
if (firstBrace !== -1 && lastBrace > firstBrace) {
|
|
56
|
+
return text.slice(firstBrace, lastBrace + 1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const firstBracket = text.indexOf('[');
|
|
60
|
+
const lastBracket = text.lastIndexOf(']');
|
|
61
|
+
if (firstBracket !== -1 && lastBracket > firstBracket) {
|
|
62
|
+
return text.slice(firstBracket, lastBracket + 1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function fallbackTargetsFromText(text) {
|
|
69
|
+
const candidates = [];
|
|
70
|
+
const lines = text.split(/\r?\n/);
|
|
71
|
+
|
|
72
|
+
for (const line of lines) {
|
|
73
|
+
let cleaned = line.trim();
|
|
74
|
+
if (!cleaned) continue;
|
|
75
|
+
cleaned = cleaned.replace(/^[-*•\d.)\s]+/, '').trim();
|
|
76
|
+
if (!cleaned) continue;
|
|
77
|
+
const token = cleaned.split(/\s+/)[0];
|
|
78
|
+
if (/[#:]|[/\\]|\\./.test(token)) {
|
|
79
|
+
candidates.push(token);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return candidates;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function parseDelegatedTargets(rawResponse) {
|
|
87
|
+
if (!rawResponse || typeof rawResponse !== 'string') return [];
|
|
88
|
+
const trimmed = rawResponse.trim();
|
|
89
|
+
|
|
90
|
+
const tryParse = (text) => {
|
|
91
|
+
try {
|
|
92
|
+
return JSON.parse(text);
|
|
93
|
+
} catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
let parsed = tryParse(trimmed);
|
|
99
|
+
if (!parsed) {
|
|
100
|
+
const snippet = extractJsonSnippet(trimmed);
|
|
101
|
+
if (snippet) {
|
|
102
|
+
parsed = tryParse(snippet);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (parsed) {
|
|
107
|
+
if (Array.isArray(parsed)) {
|
|
108
|
+
return normalizeTargets(parsed);
|
|
109
|
+
}
|
|
110
|
+
if (Array.isArray(parsed.targets)) {
|
|
111
|
+
return normalizeTargets(parsed.targets);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return normalizeTargets(fallbackTargetsFromText(trimmed));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, allowTests }) {
|
|
119
|
+
return [
|
|
120
|
+
'You are a code-search subagent. Your ONLY job is to return ALL relevant code locations.',
|
|
121
|
+
'Use ONLY the search tool. Do NOT answer the question or explain anything.',
|
|
122
|
+
'Return ONLY valid JSON with this shape: {"targets": ["path/to/file.ext#Symbol", "path/to/file.ext:line", "path/to/file.ext:start-end"]}.',
|
|
123
|
+
'Prefer #Symbol when a function/class name is clear; otherwise use line numbers.',
|
|
124
|
+
`Search query: ${searchQuery}`,
|
|
125
|
+
`Search path(s): ${searchPath}`,
|
|
126
|
+
`Options: exact=${exact ? 'true' : 'false'}, language=${language || 'auto'}, allow_tests=${allowTests ? 'true' : 'false'}.`,
|
|
127
|
+
'Run additional searches only if needed to capture all relevant locations.',
|
|
128
|
+
'Deduplicate targets.'
|
|
129
|
+
].join('\n');
|
|
130
|
+
}
|
|
131
|
+
|
|
13
132
|
/**
|
|
14
133
|
* Search tool generator
|
|
15
134
|
*
|
|
@@ -20,58 +139,138 @@ import { searchSchema, querySchema, extractSchema, delegateSchema, searchDescrip
|
|
|
20
139
|
* @returns {Object} Configured search tool
|
|
21
140
|
*/
|
|
22
141
|
export const searchTool = (options = {}) => {
|
|
23
|
-
const {
|
|
142
|
+
const {
|
|
143
|
+
sessionId,
|
|
144
|
+
maxTokens = 10000,
|
|
145
|
+
debug = false,
|
|
146
|
+
outline = false,
|
|
147
|
+
searchDelegate = false
|
|
148
|
+
} = options;
|
|
24
149
|
|
|
25
150
|
return tool({
|
|
26
151
|
name: 'search',
|
|
27
|
-
description:
|
|
152
|
+
description: searchDelegate
|
|
153
|
+
? `${searchDescription} (delegates code search to a subagent and returns extracted code blocks)`
|
|
154
|
+
: searchDescription,
|
|
28
155
|
inputSchema: searchSchema,
|
|
29
156
|
execute: async ({ query: searchQuery, path, allow_tests, exact, maxTokens: paramMaxTokens, language }) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const effectiveMaxTokens = paramMaxTokens || maxTokens;
|
|
157
|
+
// Use parameter maxTokens if provided, otherwise use the default
|
|
158
|
+
const effectiveMaxTokens = paramMaxTokens || maxTokens;
|
|
33
159
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
160
|
+
// Parse and resolve paths (supports comma-separated and relative paths)
|
|
161
|
+
let searchPaths;
|
|
162
|
+
if (path) {
|
|
163
|
+
searchPaths = parseAndResolvePaths(path, options.cwd);
|
|
164
|
+
}
|
|
39
165
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
166
|
+
// Default to cwd or '.' if no paths provided
|
|
167
|
+
if (!searchPaths || searchPaths.length === 0) {
|
|
168
|
+
searchPaths = [options.cwd || '.'];
|
|
169
|
+
}
|
|
44
170
|
|
|
45
|
-
|
|
46
|
-
|
|
171
|
+
// Join paths with space for CLI (probe search supports multiple paths)
|
|
172
|
+
const searchPath = searchPaths.join(' ');
|
|
173
|
+
|
|
174
|
+
const searchOptions = {
|
|
175
|
+
query: searchQuery,
|
|
176
|
+
path: searchPath,
|
|
177
|
+
cwd: options.cwd, // Working directory for resolving relative paths
|
|
178
|
+
allowTests: allow_tests ?? true,
|
|
179
|
+
exact,
|
|
180
|
+
json: false,
|
|
181
|
+
maxTokens: effectiveMaxTokens,
|
|
182
|
+
session: sessionId, // Pass session ID if provided
|
|
183
|
+
language // Pass language parameter if provided
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Add outline format if enabled
|
|
187
|
+
if (outline) {
|
|
188
|
+
searchOptions.format = 'outline-xml';
|
|
189
|
+
}
|
|
47
190
|
|
|
191
|
+
const runRawSearch = async () => {
|
|
48
192
|
if (debug) {
|
|
49
193
|
console.error(`Executing search with query: "${searchQuery}", path: "${searchPath}", exact: ${exact ? 'true' : 'false'}, language: ${language || 'all'}, session: ${sessionId || 'none'}`);
|
|
50
194
|
}
|
|
195
|
+
return await search(searchOptions);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
if (!searchDelegate) {
|
|
199
|
+
try {
|
|
200
|
+
return await runRawSearch();
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error('Error executing search command:', error);
|
|
203
|
+
return `Error executing search command: ${error.message}`;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
51
206
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
path: searchPath
|
|
55
|
-
|
|
56
|
-
|
|
207
|
+
try {
|
|
208
|
+
if (debug) {
|
|
209
|
+
console.error(`Delegating search with query: "${searchQuery}", path: "${searchPath}"`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const delegateTask = buildSearchDelegateTask({
|
|
213
|
+
searchQuery,
|
|
214
|
+
searchPath,
|
|
57
215
|
exact,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
216
|
+
language,
|
|
217
|
+
allowTests: allow_tests ?? true
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const runDelegation = () => delegate({
|
|
221
|
+
task: delegateTask,
|
|
222
|
+
debug,
|
|
223
|
+
parentSessionId: sessionId,
|
|
224
|
+
path: options.allowedFolders?.[0] || options.cwd || '.',
|
|
225
|
+
allowedFolders: options.allowedFolders,
|
|
226
|
+
provider: options.provider || null,
|
|
227
|
+
model: options.model || null,
|
|
228
|
+
tracer: options.tracer || null,
|
|
229
|
+
enableBash: false,
|
|
230
|
+
bashConfig: null,
|
|
231
|
+
architectureFileName: options.architectureFileName || null,
|
|
232
|
+
promptType: 'code-searcher',
|
|
233
|
+
allowedTools: ['search', 'attempt_completion'],
|
|
234
|
+
searchDelegate: false,
|
|
235
|
+
schema: CODE_SEARCH_SCHEMA
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const delegateResult = options.tracer?.withSpan
|
|
239
|
+
? await options.tracer.withSpan('search.delegate', runDelegation, {
|
|
240
|
+
'search.query': searchQuery,
|
|
241
|
+
'search.path': searchPath
|
|
242
|
+
})
|
|
243
|
+
: await runDelegation();
|
|
244
|
+
|
|
245
|
+
const targets = parseDelegatedTargets(delegateResult);
|
|
246
|
+
if (!targets.length) {
|
|
247
|
+
if (debug) {
|
|
248
|
+
console.error('Delegated search returned no targets; falling back to raw search');
|
|
249
|
+
}
|
|
250
|
+
return await runRawSearch();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const effectiveCwd = options.cwd || '.';
|
|
254
|
+
const resolvedTargets = targets.map(target => resolveTargetPath(target, effectiveCwd));
|
|
255
|
+
const extractOptions = {
|
|
256
|
+
files: resolvedTargets,
|
|
257
|
+
cwd: effectiveCwd,
|
|
258
|
+
allowTests: allow_tests ?? true
|
|
62
259
|
};
|
|
63
260
|
|
|
64
|
-
// Add outline format if enabled
|
|
65
261
|
if (outline) {
|
|
66
|
-
|
|
262
|
+
extractOptions.format = 'xml';
|
|
67
263
|
}
|
|
68
264
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return results;
|
|
265
|
+
return await extract(extractOptions);
|
|
72
266
|
} catch (error) {
|
|
73
|
-
console.error('
|
|
74
|
-
|
|
267
|
+
console.error('Delegated search failed, falling back to raw search:', error);
|
|
268
|
+
try {
|
|
269
|
+
return await runRawSearch();
|
|
270
|
+
} catch (fallbackError) {
|
|
271
|
+
console.error('Error executing search command:', fallbackError);
|
|
272
|
+
return `Error executing search command: ${fallbackError.message}`;
|
|
273
|
+
}
|
|
75
274
|
}
|
|
76
275
|
}
|
|
77
276
|
});
|
|
@@ -250,16 +449,17 @@ export const extractTool = (options = {}) => {
|
|
|
250
449
|
* @param {string[]} [options.allowedFolders] - Allowed folders for workspace isolation
|
|
251
450
|
* @param {boolean} [options.enableBash=false] - Enable bash tool for sub-agents
|
|
252
451
|
* @param {Object} [options.bashConfig] - Bash configuration (allow/deny patterns)
|
|
452
|
+
* @param {string} [options.architectureFileName] - Architecture context filename to embed from repo root
|
|
253
453
|
* @returns {Object} Configured delegate tool
|
|
254
454
|
*/
|
|
255
455
|
export const delegateTool = (options = {}) => {
|
|
256
|
-
const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig } = options;
|
|
456
|
+
const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName } = options;
|
|
257
457
|
|
|
258
458
|
return tool({
|
|
259
459
|
name: 'delegate',
|
|
260
460
|
description: delegateDescription,
|
|
261
461
|
inputSchema: delegateSchema,
|
|
262
|
-
execute: async ({ task, currentIteration, maxIterations, parentSessionId, path, provider, model, tracer }) => {
|
|
462
|
+
execute: async ({ task, currentIteration, maxIterations, parentSessionId, path, provider, model, tracer, searchDelegate }) => {
|
|
263
463
|
// Validate required parameters - throw errors for consistency
|
|
264
464
|
if (!task || typeof task !== 'string') {
|
|
265
465
|
throw new Error('Task parameter is required and must be a non-empty string');
|
|
@@ -295,6 +495,10 @@ export const delegateTool = (options = {}) => {
|
|
|
295
495
|
throw new TypeError('model must be a string, null, or undefined');
|
|
296
496
|
}
|
|
297
497
|
|
|
498
|
+
if (searchDelegate !== undefined && typeof searchDelegate !== 'boolean') {
|
|
499
|
+
throw new TypeError('searchDelegate must be a boolean if provided');
|
|
500
|
+
}
|
|
501
|
+
|
|
298
502
|
// Determine the path to pass to the subagent
|
|
299
503
|
// NOTE: Delegation intentionally uses DIFFERENT priority than other tools.
|
|
300
504
|
//
|
|
@@ -331,14 +535,17 @@ export const delegateTool = (options = {}) => {
|
|
|
331
535
|
maxIterations: maxIterations || 30,
|
|
332
536
|
parentSessionId,
|
|
333
537
|
path: effectivePath,
|
|
538
|
+
allowedFolders,
|
|
334
539
|
provider,
|
|
335
540
|
model,
|
|
336
541
|
tracer,
|
|
337
542
|
enableBash,
|
|
338
|
-
bashConfig
|
|
543
|
+
bashConfig,
|
|
544
|
+
architectureFileName,
|
|
545
|
+
searchDelegate
|
|
339
546
|
});
|
|
340
547
|
|
|
341
548
|
return result;
|
|
342
549
|
}
|
|
343
550
|
});
|
|
344
|
-
};
|
|
551
|
+
};
|