@probelabs/probe 0.6.0-rc280 → 0.6.0-rc282
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-rc282-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc282-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc282-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc282-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc282-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +18 -9
- package/build/agent/index.js +65 -12
- package/build/tools/common.js +1 -1
- package/build/tools/vercel.js +67 -8
- package/cjs/agent/ProbeAgent.cjs +67 -14
- package/cjs/index.cjs +68 -15
- package/package.json +2 -2
- package/src/agent/ProbeAgent.js +18 -9
- package/src/tools/common.js +1 -1
- package/src/tools/vercel.js +67 -8
- 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
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -2876,7 +2876,7 @@ ${searchToolDesc1}
|
|
|
2876
2876
|
- searchFiles: Find files by name patterns`;
|
|
2877
2877
|
|
|
2878
2878
|
if (this.enableBash) {
|
|
2879
|
-
systemPrompt += `\n- bash: Execute bash commands for system operations
|
|
2879
|
+
systemPrompt += `\n- bash: Execute bash commands for system operations (building, running tests, git, etc.). NEVER use bash for code exploration (no grep, cat, find, head, tail) — always use search and extract tools instead, they are faster and more accurate.`;
|
|
2880
2880
|
}
|
|
2881
2881
|
|
|
2882
2882
|
const searchGuidance1 = this.searchDelegate
|
|
@@ -2942,7 +2942,7 @@ ${searchToolDesc2}
|
|
|
2942
2942
|
- searchFiles: Find files by name patterns`;
|
|
2943
2943
|
|
|
2944
2944
|
if (this.enableBash) {
|
|
2945
|
-
systemPrompt += `\n- bash: Execute bash commands for system operations
|
|
2945
|
+
systemPrompt += `\n- bash: Execute bash commands for system operations (building, running tests, git, etc.). NEVER use bash for code exploration (no grep, cat, find, head, tail) — always use search and extract tools instead, they are faster and more accurate.`;
|
|
2946
2946
|
}
|
|
2947
2947
|
|
|
2948
2948
|
const searchGuidance2 = this.searchDelegate
|
|
@@ -3018,7 +3018,8 @@ Follow these instructions carefully:
|
|
|
3018
3018
|
3. You should always prefer the search tool for code-related questions.${this.searchDelegate ? ' Ask natural language questions — 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 — do NOT try keyword variations manually. Read full files only if really necessary.'}
|
|
3019
3019
|
4. Ensure to get really deep and understand the full picture before answering.
|
|
3020
3020
|
5. Once the task is fully completed, use the attempt_completion tool to provide the final result.
|
|
3021
|
-
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.'}
|
|
3021
|
+
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.'}
|
|
3022
|
+
7. NEVER use bash for code exploration (no grep, cat, find, head, tail, awk, sed) — always use search and extract tools instead. Bash is only for system operations like building, running tests, or git commands.${this.allowEdit ? `
|
|
3022
3023
|
7. When modifying files, choose the appropriate tool:
|
|
3023
3024
|
- Use 'edit' for all code modifications:
|
|
3024
3025
|
* PREFERRED: Use start_line (and optionally end_line) for line-targeted editing — 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.
|
|
@@ -3035,22 +3036,30 @@ Follow these instructions carefully:
|
|
|
3035
3036
|
// Use predefined prompts from shared module (imported at top of file)
|
|
3036
3037
|
let systemMessage = '';
|
|
3037
3038
|
|
|
3038
|
-
//
|
|
3039
|
-
if (this.customPrompt) {
|
|
3039
|
+
// Build system message from predefined prompt + optional custom prompt
|
|
3040
|
+
if (this.customPrompt && this.promptType && predefinedPrompts[this.promptType]) {
|
|
3041
|
+
// Both: use predefined as base, append custom wrapped in tag
|
|
3042
|
+
systemMessage = "<role>" + predefinedPrompts[this.promptType] + "</role>";
|
|
3043
|
+
systemMessage += commonInstructions;
|
|
3044
|
+
systemMessage += "\n<custom-instructions>\n" + this.customPrompt + "\n</custom-instructions>";
|
|
3045
|
+
if (this.debug) {
|
|
3046
|
+
console.log(`[DEBUG] Using predefined prompt: ${this.promptType} + custom prompt`);
|
|
3047
|
+
}
|
|
3048
|
+
} else if (this.customPrompt) {
|
|
3049
|
+
// Only custom prompt
|
|
3040
3050
|
systemMessage = "<role>" + this.customPrompt + "</role>";
|
|
3041
3051
|
if (this.debug) {
|
|
3042
3052
|
console.log(`[DEBUG] Using custom prompt`);
|
|
3043
3053
|
}
|
|
3044
|
-
}
|
|
3045
|
-
|
|
3046
|
-
else if (this.promptType && predefinedPrompts[this.promptType]) {
|
|
3054
|
+
} else if (this.promptType && predefinedPrompts[this.promptType]) {
|
|
3055
|
+
// Only predefined prompt
|
|
3047
3056
|
systemMessage = "<role>" + predefinedPrompts[this.promptType] + "</role>";
|
|
3048
3057
|
if (this.debug) {
|
|
3049
3058
|
console.log(`[DEBUG] Using predefined prompt: ${this.promptType}`);
|
|
3050
3059
|
}
|
|
3051
3060
|
systemMessage += commonInstructions;
|
|
3052
3061
|
} else {
|
|
3053
|
-
//
|
|
3062
|
+
// Default: code explorer
|
|
3054
3063
|
systemMessage = "<role>" + predefinedPrompts['code-explorer'] + "</role>";
|
|
3055
3064
|
if (this.debug) {
|
|
3056
3065
|
console.log(`[DEBUG] Using default prompt: code explorer`);
|
package/build/agent/index.js
CHANGED
|
@@ -9185,13 +9185,19 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
9185
9185
|
"- listFiles: Understand directory structure to find where relevant code might live.",
|
|
9186
9186
|
"",
|
|
9187
9187
|
"CRITICAL - How probe search works (do NOT ignore):",
|
|
9188
|
-
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting.",
|
|
9188
|
+
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically.",
|
|
9189
9189
|
'- Searching "allowed_ips" ALREADY matches "AllowedIPs", "allowedIps", "allowed_ips", etc. Do NOT manually try case/style variations.',
|
|
9190
9190
|
'- Searching "getUserData" ALREADY matches "get", "user", "data" and their variations.',
|
|
9191
|
-
"- NEVER repeat the same search query \u2014 you will get the same results.",
|
|
9191
|
+
"- NEVER repeat the same search query \u2014 you will get the same results. Changing the path does NOT change this.",
|
|
9192
9192
|
"- NEVER search trivial variations of the same keyword (e.g., AllowedIPs then allowedIps then allowed_ips). This is wasteful \u2014 probe handles it.",
|
|
9193
|
-
"- If a search returns no results, the term likely does not exist
|
|
9194
|
-
"- If 2-3
|
|
9193
|
+
"- If a search returns no results, the term likely does not exist. Try a genuinely DIFFERENT keyword or concept, not a variation.",
|
|
9194
|
+
"- If 2-3 searches return no results for a concept, STOP searching for it and move on. Do NOT keep retrying.",
|
|
9195
|
+
"",
|
|
9196
|
+
"When to use exact=true:",
|
|
9197
|
+
"- Use exact=true when searching for a KNOWN symbol name (function, type, variable, struct).",
|
|
9198
|
+
"- exact=true matches the literal string only \u2014 no stemming, no splitting.",
|
|
9199
|
+
'- This is ideal for precise lookups: exact=true "ForwardMessage", exact=true "SessionLimiter", exact=true "ThrottleRetryLimit".',
|
|
9200
|
+
"- Do NOT use exact=true for exploratory/conceptual queries \u2014 use the default for those.",
|
|
9195
9201
|
"",
|
|
9196
9202
|
"GOOD search strategy (do this):",
|
|
9197
9203
|
' Query: "How does authentication work and how are sessions managed?"',
|
|
@@ -9200,10 +9206,18 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
9200
9206
|
' \u2192 search "allowlist middleware" (one search, probe handles IP/ip/Ip variations)',
|
|
9201
9207
|
' Query: "How does BM25 scoring work with SIMD optimization?"',
|
|
9202
9208
|
' \u2192 search "BM25 scoring" \u2192 search "SIMD optimization" (two different concepts)',
|
|
9209
|
+
' Query: "Find ForwardMessage and SessionLimiter functions"',
|
|
9210
|
+
' \u2192 search exact=true "ForwardMessage" \u2192 search exact=true "SessionLimiter" (known symbols, use exact)',
|
|
9211
|
+
' Query: "Find ThrottleRetryLimit usage"',
|
|
9212
|
+
' \u2192 search exact=true "ThrottleRetryLimit" (one search, if no results the symbol does not exist \u2014 stop)',
|
|
9203
9213
|
"",
|
|
9204
9214
|
"BAD search strategy (never do this):",
|
|
9205
|
-
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG:
|
|
9206
|
-
' \u2192 search "
|
|
9215
|
+
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG: case/style variations, probe handles them)',
|
|
9216
|
+
' \u2192 search "limitDRL" \u2192 search "LimitDRL" (WRONG: case variation of same term)',
|
|
9217
|
+
' \u2192 search "throttle_retry_limit" after searching "ThrottleRetryLimit" (WRONG: snake_case variation, probe handles it)',
|
|
9218
|
+
' \u2192 search "ThrottleRetryLimit" path=tyk \u2192 search "ThrottleRetryLimit" path=gateway \u2192 search "ThrottleRetryLimit" path=apidef (WRONG: same query on different paths hoping for different results)',
|
|
9219
|
+
' \u2192 search "func (k *RateLimitAndQuotaCheck) handleRateLimitFailure" (WRONG: do not search full function signatures, just use exact=true "handleRateLimitFailure")',
|
|
9220
|
+
' \u2192 search "ForwardMessage" \u2192 search "ForwardMessage" \u2192 search "ForwardMessage" (WRONG: repeating the exact same query)',
|
|
9207
9221
|
' \u2192 search "error handling" \u2192 search "error handling" \u2192 search "error handling" (WRONG: repeating exact same query)',
|
|
9208
9222
|
"",
|
|
9209
9223
|
"Keyword tips:",
|
|
@@ -9212,12 +9226,13 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
9212
9226
|
'- To bypass stopword filtering: wrap terms in quotes ("return", "struct") or set exact=true. Both disable stemming and splitting too.',
|
|
9213
9227
|
"- Multiple words without operators use OR logic: foo bar = foo OR bar. Use AND explicitly if you need both: foo AND bar.",
|
|
9214
9228
|
'- camelCase terms are split: getUserData becomes "get", "user", "data" \u2014 so one search covers all naming styles.',
|
|
9229
|
+
'- Do NOT search for full function signatures like "func (r *Type) Method(args)". Just search for the method name with exact=true.',
|
|
9215
9230
|
"",
|
|
9216
9231
|
"Strategy:",
|
|
9217
9232
|
"1. Analyze the query - identify key concepts, entities, and relationships",
|
|
9218
|
-
"2. Run ONE focused search per concept
|
|
9233
|
+
"2. Run ONE focused search per concept. For known symbol names use exact=true. For concepts use default (exact=false).",
|
|
9219
9234
|
"3. If a search returns results, use extract to verify relevance",
|
|
9220
|
-
"4.
|
|
9235
|
+
"4. If a search returns NO results, the term does not exist in the codebase. Do NOT retry with variations, different paths, or longer strings. Move on.",
|
|
9221
9236
|
"5. Combine all relevant targets in your final response",
|
|
9222
9237
|
"",
|
|
9223
9238
|
`Query: ${searchQuery}`,
|
|
@@ -9538,6 +9553,36 @@ var init_vercel = __esm({
|
|
|
9538
9553
|
} else if (targets) {
|
|
9539
9554
|
const parsedTargets = parseTargets(targets);
|
|
9540
9555
|
extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
9556
|
+
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
9557
|
+
extractFiles = extractFiles.map((target) => {
|
|
9558
|
+
const { filePart, suffix } = splitTargetSuffix(target);
|
|
9559
|
+
if (existsSync(filePart)) return target;
|
|
9560
|
+
const cwdPrefix = effectiveCwd.endsWith("/") ? effectiveCwd : effectiveCwd + "/";
|
|
9561
|
+
const relativePart = filePart.startsWith(cwdPrefix) ? filePart.slice(cwdPrefix.length) : null;
|
|
9562
|
+
if (relativePart) {
|
|
9563
|
+
for (const folder of options.allowedFolders) {
|
|
9564
|
+
const candidate = folder + "/" + relativePart;
|
|
9565
|
+
if (existsSync(candidate)) {
|
|
9566
|
+
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} \u2192 ${candidate}`);
|
|
9567
|
+
return candidate + suffix;
|
|
9568
|
+
}
|
|
9569
|
+
}
|
|
9570
|
+
}
|
|
9571
|
+
for (const folder of options.allowedFolders) {
|
|
9572
|
+
const folderPrefix = folder.endsWith("/") ? folder : folder + "/";
|
|
9573
|
+
const wsParent = folderPrefix.replace(/[^/]+\/$/, "");
|
|
9574
|
+
if (filePart.startsWith(wsParent)) {
|
|
9575
|
+
const tail = filePart.slice(wsParent.length);
|
|
9576
|
+
const candidate = folderPrefix + tail;
|
|
9577
|
+
if (candidate !== filePart && existsSync(candidate)) {
|
|
9578
|
+
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} \u2192 ${candidate}`);
|
|
9579
|
+
return candidate + suffix;
|
|
9580
|
+
}
|
|
9581
|
+
}
|
|
9582
|
+
}
|
|
9583
|
+
return target;
|
|
9584
|
+
});
|
|
9585
|
+
}
|
|
9541
9586
|
let effectiveFormat = format;
|
|
9542
9587
|
if (outline && format === "outline-xml") {
|
|
9543
9588
|
effectiveFormat = "xml";
|
|
@@ -84097,7 +84142,7 @@ ${searchToolDesc1}
|
|
|
84097
84142
|
- searchFiles: Find files by name patterns`;
|
|
84098
84143
|
if (this.enableBash) {
|
|
84099
84144
|
systemPrompt += `
|
|
84100
|
-
- bash: Execute bash commands for system operations
|
|
84145
|
+
- bash: Execute bash commands for system operations (building, running tests, git, etc.). NEVER use bash for code exploration (no grep, cat, find, head, tail) \u2014 always use search and extract tools instead, they are faster and more accurate.`;
|
|
84101
84146
|
}
|
|
84102
84147
|
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.";
|
|
84103
84148
|
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";
|
|
@@ -84152,7 +84197,7 @@ ${searchToolDesc2}
|
|
|
84152
84197
|
- searchFiles: Find files by name patterns`;
|
|
84153
84198
|
if (this.enableBash) {
|
|
84154
84199
|
systemPrompt += `
|
|
84155
|
-
- bash: Execute bash commands for system operations
|
|
84200
|
+
- bash: Execute bash commands for system operations (building, running tests, git, etc.). NEVER use bash for code exploration (no grep, cat, find, head, tail) \u2014 always use search and extract tools instead, they are faster and more accurate.`;
|
|
84156
84201
|
}
|
|
84157
84202
|
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.";
|
|
84158
84203
|
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";
|
|
@@ -84218,7 +84263,8 @@ Follow these instructions carefully:
|
|
|
84218
84263
|
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."}
|
|
84219
84264
|
4. Ensure to get really deep and understand the full picture before answering.
|
|
84220
84265
|
5. Once the task is fully completed, use the attempt_completion tool to provide the final result.
|
|
84221
|
-
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."}
|
|
84266
|
+
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."}
|
|
84267
|
+
7. NEVER use bash for code exploration (no grep, cat, find, head, tail, awk, sed) \u2014 always use search and extract tools instead. Bash is only for system operations like building, running tests, or git commands.${this.allowEdit ? `
|
|
84222
84268
|
7. When modifying files, choose the appropriate tool:
|
|
84223
84269
|
- Use 'edit' for all code modifications:
|
|
84224
84270
|
* 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.
|
|
@@ -84232,7 +84278,14 @@ Follow these instructions carefully:
|
|
|
84232
84278
|
</instructions>
|
|
84233
84279
|
`;
|
|
84234
84280
|
let systemMessage = "";
|
|
84235
|
-
if (this.customPrompt) {
|
|
84281
|
+
if (this.customPrompt && this.promptType && predefinedPrompts[this.promptType]) {
|
|
84282
|
+
systemMessage = "<role>" + predefinedPrompts[this.promptType] + "</role>";
|
|
84283
|
+
systemMessage += commonInstructions;
|
|
84284
|
+
systemMessage += "\n<custom-instructions>\n" + this.customPrompt + "\n</custom-instructions>";
|
|
84285
|
+
if (this.debug) {
|
|
84286
|
+
console.log(`[DEBUG] Using predefined prompt: ${this.promptType} + custom prompt`);
|
|
84287
|
+
}
|
|
84288
|
+
} else if (this.customPrompt) {
|
|
84236
84289
|
systemMessage = "<role>" + this.customPrompt + "</role>";
|
|
84237
84290
|
if (this.debug) {
|
|
84238
84291
|
console.log(`[DEBUG] Using custom prompt`);
|
package/build/tools/common.js
CHANGED
|
@@ -154,7 +154,7 @@ export const searchDelegateDescription = 'Search code in the repository by askin
|
|
|
154
154
|
export const queryDescription = 'Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.';
|
|
155
155
|
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. Line numbers from output can be used with edit start_line/end_line for precise editing.';
|
|
156
156
|
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.';
|
|
157
|
-
export const bashDescription = 'Execute bash commands for system exploration and
|
|
157
|
+
export const bashDescription = 'Execute bash commands for system operations: building, running tests, git, package management, etc. NEVER use for code exploration (no grep, cat, find, head, tail) — use search and extract tools instead. Secure by default with built-in allow/deny lists.';
|
|
158
158
|
export const analyzeAllDescription = 'Answer questions that require analyzing ALL matching data in the codebase. Use for aggregate questions like "What features exist?", "List all API endpoints", "Count TODO comments". The AI automatically plans the search strategy, processes all results via map-reduce, and synthesizes a comprehensive answer. WARNING: Slower than search - only use when you need complete coverage.';
|
|
159
159
|
|
|
160
160
|
|
package/build/tools/vercel.js
CHANGED
|
@@ -144,13 +144,19 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
144
144
|
'- listFiles: Understand directory structure to find where relevant code might live.',
|
|
145
145
|
'',
|
|
146
146
|
'CRITICAL - How probe search works (do NOT ignore):',
|
|
147
|
-
'- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting.',
|
|
147
|
+
'- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically.',
|
|
148
148
|
'- Searching "allowed_ips" ALREADY matches "AllowedIPs", "allowedIps", "allowed_ips", etc. Do NOT manually try case/style variations.',
|
|
149
149
|
'- Searching "getUserData" ALREADY matches "get", "user", "data" and their variations.',
|
|
150
|
-
'- NEVER repeat the same search query — you will get the same results.',
|
|
150
|
+
'- NEVER repeat the same search query — you will get the same results. Changing the path does NOT change this.',
|
|
151
151
|
'- NEVER search trivial variations of the same keyword (e.g., AllowedIPs then allowedIps then allowed_ips). This is wasteful — probe handles it.',
|
|
152
|
-
'- If a search returns no results, the term likely does not exist
|
|
153
|
-
'- If 2-3
|
|
152
|
+
'- If a search returns no results, the term likely does not exist. Try a genuinely DIFFERENT keyword or concept, not a variation.',
|
|
153
|
+
'- If 2-3 searches return no results for a concept, STOP searching for it and move on. Do NOT keep retrying.',
|
|
154
|
+
'',
|
|
155
|
+
'When to use exact=true:',
|
|
156
|
+
'- Use exact=true when searching for a KNOWN symbol name (function, type, variable, struct).',
|
|
157
|
+
'- exact=true matches the literal string only — no stemming, no splitting.',
|
|
158
|
+
'- This is ideal for precise lookups: exact=true "ForwardMessage", exact=true "SessionLimiter", exact=true "ThrottleRetryLimit".',
|
|
159
|
+
'- Do NOT use exact=true for exploratory/conceptual queries — use the default for those.',
|
|
154
160
|
'',
|
|
155
161
|
'GOOD search strategy (do this):',
|
|
156
162
|
' Query: "How does authentication work and how are sessions managed?"',
|
|
@@ -159,10 +165,18 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
159
165
|
' → search "allowlist middleware" (one search, probe handles IP/ip/Ip variations)',
|
|
160
166
|
' Query: "How does BM25 scoring work with SIMD optimization?"',
|
|
161
167
|
' → search "BM25 scoring" → search "SIMD optimization" (two different concepts)',
|
|
168
|
+
' Query: "Find ForwardMessage and SessionLimiter functions"',
|
|
169
|
+
' → search exact=true "ForwardMessage" → search exact=true "SessionLimiter" (known symbols, use exact)',
|
|
170
|
+
' Query: "Find ThrottleRetryLimit usage"',
|
|
171
|
+
' → search exact=true "ThrottleRetryLimit" (one search, if no results the symbol does not exist — stop)',
|
|
162
172
|
'',
|
|
163
173
|
'BAD search strategy (never do this):',
|
|
164
|
-
' → search "AllowedIPs" → search "allowedIps" → search "allowed_ips" (WRONG:
|
|
165
|
-
' → search "
|
|
174
|
+
' → search "AllowedIPs" → search "allowedIps" → search "allowed_ips" (WRONG: case/style variations, probe handles them)',
|
|
175
|
+
' → search "limitDRL" → search "LimitDRL" (WRONG: case variation of same term)',
|
|
176
|
+
' → search "throttle_retry_limit" after searching "ThrottleRetryLimit" (WRONG: snake_case variation, probe handles it)',
|
|
177
|
+
' → search "ThrottleRetryLimit" path=tyk → search "ThrottleRetryLimit" path=gateway → search "ThrottleRetryLimit" path=apidef (WRONG: same query on different paths hoping for different results)',
|
|
178
|
+
' → search "func (k *RateLimitAndQuotaCheck) handleRateLimitFailure" (WRONG: do not search full function signatures, just use exact=true "handleRateLimitFailure")',
|
|
179
|
+
' → search "ForwardMessage" → search "ForwardMessage" → search "ForwardMessage" (WRONG: repeating the exact same query)',
|
|
166
180
|
' → search "error handling" → search "error handling" → search "error handling" (WRONG: repeating exact same query)',
|
|
167
181
|
'',
|
|
168
182
|
'Keyword tips:',
|
|
@@ -171,12 +185,13 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
171
185
|
'- To bypass stopword filtering: wrap terms in quotes ("return", "struct") or set exact=true. Both disable stemming and splitting too.',
|
|
172
186
|
'- Multiple words without operators use OR logic: foo bar = foo OR bar. Use AND explicitly if you need both: foo AND bar.',
|
|
173
187
|
'- camelCase terms are split: getUserData becomes "get", "user", "data" — so one search covers all naming styles.',
|
|
188
|
+
'- Do NOT search for full function signatures like "func (r *Type) Method(args)". Just search for the method name with exact=true.',
|
|
174
189
|
'',
|
|
175
190
|
'Strategy:',
|
|
176
191
|
'1. Analyze the query - identify key concepts, entities, and relationships',
|
|
177
|
-
'2. Run ONE focused search per concept
|
|
192
|
+
'2. Run ONE focused search per concept. For known symbol names use exact=true. For concepts use default (exact=false).',
|
|
178
193
|
'3. If a search returns results, use extract to verify relevance',
|
|
179
|
-
'4.
|
|
194
|
+
'4. If a search returns NO results, the term does not exist in the codebase. Do NOT retry with variations, different paths, or longer strings. Move on.',
|
|
180
195
|
'5. Combine all relevant targets in your final response',
|
|
181
196
|
'',
|
|
182
197
|
`Query: ${searchQuery}`,
|
|
@@ -570,6 +585,50 @@ export const extractTool = (options = {}) => {
|
|
|
570
585
|
// Resolve relative paths in targets against cwd
|
|
571
586
|
extractFiles = parsedTargets.map(target => resolveTargetPath(target, effectiveCwd));
|
|
572
587
|
|
|
588
|
+
// Auto-fix: if resolved paths don't exist, try allowedFolders subdirs
|
|
589
|
+
// Handles when search returns relative paths (e.g., "gateway/file.go") and
|
|
590
|
+
// model constructs wrong absolute paths (e.g., /workspace/gateway/file.go
|
|
591
|
+
// instead of /workspace/tyk/gateway/file.go)
|
|
592
|
+
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
593
|
+
extractFiles = extractFiles.map(target => {
|
|
594
|
+
const { filePart, suffix } = splitTargetSuffix(target);
|
|
595
|
+
if (existsSync(filePart)) return target;
|
|
596
|
+
|
|
597
|
+
// Try resolving the relative tail against each allowedFolder
|
|
598
|
+
const cwdPrefix = (effectiveCwd.endsWith('/') ? effectiveCwd : effectiveCwd + '/');
|
|
599
|
+
const relativePart = filePart.startsWith(cwdPrefix)
|
|
600
|
+
? filePart.slice(cwdPrefix.length)
|
|
601
|
+
: null;
|
|
602
|
+
|
|
603
|
+
if (relativePart) {
|
|
604
|
+
for (const folder of options.allowedFolders) {
|
|
605
|
+
const candidate = folder + '/' + relativePart;
|
|
606
|
+
if (existsSync(candidate)) {
|
|
607
|
+
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} → ${candidate}`);
|
|
608
|
+
return candidate + suffix;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Try stripping workspace prefix and resolving against allowedFolders
|
|
614
|
+
// e.g., /tmp/visor-workspaces/abc/gateway/file.go → try each folder + gateway/file.go
|
|
615
|
+
for (const folder of options.allowedFolders) {
|
|
616
|
+
const folderPrefix = folder.endsWith('/') ? folder : folder + '/';
|
|
617
|
+
const wsParent = folderPrefix.replace(/[^/]+\/$/, '');
|
|
618
|
+
if (filePart.startsWith(wsParent)) {
|
|
619
|
+
const tail = filePart.slice(wsParent.length);
|
|
620
|
+
const candidate = folderPrefix + tail;
|
|
621
|
+
if (candidate !== filePart && existsSync(candidate)) {
|
|
622
|
+
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} → ${candidate}`);
|
|
623
|
+
return candidate + suffix;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
return target;
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
|
|
573
632
|
// Apply format mapping for outline-xml to xml
|
|
574
633
|
let effectiveFormat = format;
|
|
575
634
|
if (outline && format === 'outline-xml') {
|
package/cjs/agent/ProbeAgent.cjs
CHANGED
|
@@ -4205,7 +4205,7 @@ var init_NormalizedSchema = __esm({
|
|
|
4205
4205
|
if (this.isDocumentSchema()) {
|
|
4206
4206
|
return member([15, 0], memberName);
|
|
4207
4207
|
}
|
|
4208
|
-
throw new Error(`@smithy/core/schema - ${this.getName(true)} has no
|
|
4208
|
+
throw new Error(`@smithy/core/schema - ${this.getName(true)} has no member=${memberName}.`);
|
|
4209
4209
|
}
|
|
4210
4210
|
getMemberSchemas() {
|
|
4211
4211
|
const buffer = {};
|
|
@@ -5996,7 +5996,7 @@ var init_EventStreamSerde = __esm({
|
|
|
5996
5996
|
throw new Error("@smithy/core/event-streams - non-struct member not supported in event stream union.");
|
|
5997
5997
|
}
|
|
5998
5998
|
}
|
|
5999
|
-
const messageSerialization = serializer.flush();
|
|
5999
|
+
const messageSerialization = serializer.flush() ?? new Uint8Array();
|
|
6000
6000
|
const body = typeof messageSerialization === "string" ? (this.serdeContext?.utf8Decoder ?? import_util_utf8.fromUtf8)(messageSerialization) : messageSerialization;
|
|
6001
6001
|
return {
|
|
6002
6002
|
body,
|
|
@@ -36563,13 +36563,19 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
36563
36563
|
"- listFiles: Understand directory structure to find where relevant code might live.",
|
|
36564
36564
|
"",
|
|
36565
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.",
|
|
36566
|
+
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically.",
|
|
36567
36567
|
'- Searching "allowed_ips" ALREADY matches "AllowedIPs", "allowedIps", "allowed_ips", etc. Do NOT manually try case/style variations.',
|
|
36568
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.",
|
|
36569
|
+
"- NEVER repeat the same search query \u2014 you will get the same results. Changing the path does NOT change this.",
|
|
36570
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
|
|
36572
|
-
"- If 2-3
|
|
36571
|
+
"- If a search returns no results, the term likely does not exist. Try a genuinely DIFFERENT keyword or concept, not a variation.",
|
|
36572
|
+
"- If 2-3 searches return no results for a concept, STOP searching for it and move on. Do NOT keep retrying.",
|
|
36573
|
+
"",
|
|
36574
|
+
"When to use exact=true:",
|
|
36575
|
+
"- Use exact=true when searching for a KNOWN symbol name (function, type, variable, struct).",
|
|
36576
|
+
"- exact=true matches the literal string only \u2014 no stemming, no splitting.",
|
|
36577
|
+
'- This is ideal for precise lookups: exact=true "ForwardMessage", exact=true "SessionLimiter", exact=true "ThrottleRetryLimit".',
|
|
36578
|
+
"- Do NOT use exact=true for exploratory/conceptual queries \u2014 use the default for those.",
|
|
36573
36579
|
"",
|
|
36574
36580
|
"GOOD search strategy (do this):",
|
|
36575
36581
|
' Query: "How does authentication work and how are sessions managed?"',
|
|
@@ -36578,10 +36584,18 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
36578
36584
|
' \u2192 search "allowlist middleware" (one search, probe handles IP/ip/Ip variations)',
|
|
36579
36585
|
' Query: "How does BM25 scoring work with SIMD optimization?"',
|
|
36580
36586
|
' \u2192 search "BM25 scoring" \u2192 search "SIMD optimization" (two different concepts)',
|
|
36587
|
+
' Query: "Find ForwardMessage and SessionLimiter functions"',
|
|
36588
|
+
' \u2192 search exact=true "ForwardMessage" \u2192 search exact=true "SessionLimiter" (known symbols, use exact)',
|
|
36589
|
+
' Query: "Find ThrottleRetryLimit usage"',
|
|
36590
|
+
' \u2192 search exact=true "ThrottleRetryLimit" (one search, if no results the symbol does not exist \u2014 stop)',
|
|
36581
36591
|
"",
|
|
36582
36592
|
"BAD search strategy (never do this):",
|
|
36583
|
-
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG:
|
|
36584
|
-
' \u2192 search "
|
|
36593
|
+
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG: case/style variations, probe handles them)',
|
|
36594
|
+
' \u2192 search "limitDRL" \u2192 search "LimitDRL" (WRONG: case variation of same term)',
|
|
36595
|
+
' \u2192 search "throttle_retry_limit" after searching "ThrottleRetryLimit" (WRONG: snake_case variation, probe handles it)',
|
|
36596
|
+
' \u2192 search "ThrottleRetryLimit" path=tyk \u2192 search "ThrottleRetryLimit" path=gateway \u2192 search "ThrottleRetryLimit" path=apidef (WRONG: same query on different paths hoping for different results)',
|
|
36597
|
+
' \u2192 search "func (k *RateLimitAndQuotaCheck) handleRateLimitFailure" (WRONG: do not search full function signatures, just use exact=true "handleRateLimitFailure")',
|
|
36598
|
+
' \u2192 search "ForwardMessage" \u2192 search "ForwardMessage" \u2192 search "ForwardMessage" (WRONG: repeating the exact same query)',
|
|
36585
36599
|
' \u2192 search "error handling" \u2192 search "error handling" \u2192 search "error handling" (WRONG: repeating exact same query)',
|
|
36586
36600
|
"",
|
|
36587
36601
|
"Keyword tips:",
|
|
@@ -36590,12 +36604,13 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
36590
36604
|
'- To bypass stopword filtering: wrap terms in quotes ("return", "struct") or set exact=true. Both disable stemming and splitting too.',
|
|
36591
36605
|
"- Multiple words without operators use OR logic: foo bar = foo OR bar. Use AND explicitly if you need both: foo AND bar.",
|
|
36592
36606
|
'- camelCase terms are split: getUserData becomes "get", "user", "data" \u2014 so one search covers all naming styles.',
|
|
36607
|
+
'- Do NOT search for full function signatures like "func (r *Type) Method(args)". Just search for the method name with exact=true.',
|
|
36593
36608
|
"",
|
|
36594
36609
|
"Strategy:",
|
|
36595
36610
|
"1. Analyze the query - identify key concepts, entities, and relationships",
|
|
36596
|
-
"2. Run ONE focused search per concept
|
|
36611
|
+
"2. Run ONE focused search per concept. For known symbol names use exact=true. For concepts use default (exact=false).",
|
|
36597
36612
|
"3. If a search returns results, use extract to verify relevance",
|
|
36598
|
-
"4.
|
|
36613
|
+
"4. If a search returns NO results, the term does not exist in the codebase. Do NOT retry with variations, different paths, or longer strings. Move on.",
|
|
36599
36614
|
"5. Combine all relevant targets in your final response",
|
|
36600
36615
|
"",
|
|
36601
36616
|
`Query: ${searchQuery}`,
|
|
@@ -36918,6 +36933,36 @@ var init_vercel = __esm({
|
|
|
36918
36933
|
} else if (targets) {
|
|
36919
36934
|
const parsedTargets = parseTargets(targets);
|
|
36920
36935
|
extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
36936
|
+
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
36937
|
+
extractFiles = extractFiles.map((target) => {
|
|
36938
|
+
const { filePart, suffix } = splitTargetSuffix(target);
|
|
36939
|
+
if ((0, import_fs4.existsSync)(filePart)) return target;
|
|
36940
|
+
const cwdPrefix = effectiveCwd.endsWith("/") ? effectiveCwd : effectiveCwd + "/";
|
|
36941
|
+
const relativePart = filePart.startsWith(cwdPrefix) ? filePart.slice(cwdPrefix.length) : null;
|
|
36942
|
+
if (relativePart) {
|
|
36943
|
+
for (const folder of options.allowedFolders) {
|
|
36944
|
+
const candidate = folder + "/" + relativePart;
|
|
36945
|
+
if ((0, import_fs4.existsSync)(candidate)) {
|
|
36946
|
+
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} \u2192 ${candidate}`);
|
|
36947
|
+
return candidate + suffix;
|
|
36948
|
+
}
|
|
36949
|
+
}
|
|
36950
|
+
}
|
|
36951
|
+
for (const folder of options.allowedFolders) {
|
|
36952
|
+
const folderPrefix = folder.endsWith("/") ? folder : folder + "/";
|
|
36953
|
+
const wsParent = folderPrefix.replace(/[^/]+\/$/, "");
|
|
36954
|
+
if (filePart.startsWith(wsParent)) {
|
|
36955
|
+
const tail = filePart.slice(wsParent.length);
|
|
36956
|
+
const candidate = folderPrefix + tail;
|
|
36957
|
+
if (candidate !== filePart && (0, import_fs4.existsSync)(candidate)) {
|
|
36958
|
+
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} \u2192 ${candidate}`);
|
|
36959
|
+
return candidate + suffix;
|
|
36960
|
+
}
|
|
36961
|
+
}
|
|
36962
|
+
}
|
|
36963
|
+
return target;
|
|
36964
|
+
});
|
|
36965
|
+
}
|
|
36921
36966
|
let effectiveFormat = format2;
|
|
36922
36967
|
if (outline && format2 === "outline-xml") {
|
|
36923
36968
|
effectiveFormat = "xml";
|
|
@@ -111043,7 +111088,7 @@ ${searchToolDesc1}
|
|
|
111043
111088
|
- searchFiles: Find files by name patterns`;
|
|
111044
111089
|
if (this.enableBash) {
|
|
111045
111090
|
systemPrompt += `
|
|
111046
|
-
- bash: Execute bash commands for system operations
|
|
111091
|
+
- bash: Execute bash commands for system operations (building, running tests, git, etc.). NEVER use bash for code exploration (no grep, cat, find, head, tail) \u2014 always use search and extract tools instead, they are faster and more accurate.`;
|
|
111047
111092
|
}
|
|
111048
111093
|
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
111094
|
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";
|
|
@@ -111098,7 +111143,7 @@ ${searchToolDesc2}
|
|
|
111098
111143
|
- searchFiles: Find files by name patterns`;
|
|
111099
111144
|
if (this.enableBash) {
|
|
111100
111145
|
systemPrompt += `
|
|
111101
|
-
- bash: Execute bash commands for system operations
|
|
111146
|
+
- bash: Execute bash commands for system operations (building, running tests, git, etc.). NEVER use bash for code exploration (no grep, cat, find, head, tail) \u2014 always use search and extract tools instead, they are faster and more accurate.`;
|
|
111102
111147
|
}
|
|
111103
111148
|
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
111149
|
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";
|
|
@@ -111164,7 +111209,8 @@ Follow these instructions carefully:
|
|
|
111164
111209
|
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."}
|
|
111165
111210
|
4. Ensure to get really deep and understand the full picture before answering.
|
|
111166
111211
|
5. Once the task is fully completed, use the attempt_completion tool to provide the final result.
|
|
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."}
|
|
111212
|
+
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."}
|
|
111213
|
+
7. NEVER use bash for code exploration (no grep, cat, find, head, tail, awk, sed) \u2014 always use search and extract tools instead. Bash is only for system operations like building, running tests, or git commands.${this.allowEdit ? `
|
|
111168
111214
|
7. When modifying files, choose the appropriate tool:
|
|
111169
111215
|
- Use 'edit' for all code modifications:
|
|
111170
111216
|
* 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.
|
|
@@ -111178,7 +111224,14 @@ Follow these instructions carefully:
|
|
|
111178
111224
|
</instructions>
|
|
111179
111225
|
`;
|
|
111180
111226
|
let systemMessage = "";
|
|
111181
|
-
if (this.customPrompt) {
|
|
111227
|
+
if (this.customPrompt && this.promptType && predefinedPrompts[this.promptType]) {
|
|
111228
|
+
systemMessage = "<role>" + predefinedPrompts[this.promptType] + "</role>";
|
|
111229
|
+
systemMessage += commonInstructions;
|
|
111230
|
+
systemMessage += "\n<custom-instructions>\n" + this.customPrompt + "\n</custom-instructions>";
|
|
111231
|
+
if (this.debug) {
|
|
111232
|
+
console.log(`[DEBUG] Using predefined prompt: ${this.promptType} + custom prompt`);
|
|
111233
|
+
}
|
|
111234
|
+
} else if (this.customPrompt) {
|
|
111182
111235
|
systemMessage = "<role>" + this.customPrompt + "</role>";
|
|
111183
111236
|
if (this.debug) {
|
|
111184
111237
|
console.log(`[DEBUG] Using custom prompt`);
|
package/cjs/index.cjs
CHANGED
|
@@ -6063,7 +6063,7 @@ var init_NormalizedSchema = __esm({
|
|
|
6063
6063
|
if (this.isDocumentSchema()) {
|
|
6064
6064
|
return member([15, 0], memberName);
|
|
6065
6065
|
}
|
|
6066
|
-
throw new Error(`@smithy/core/schema - ${this.getName(true)} has no
|
|
6066
|
+
throw new Error(`@smithy/core/schema - ${this.getName(true)} has no member=${memberName}.`);
|
|
6067
6067
|
}
|
|
6068
6068
|
getMemberSchemas() {
|
|
6069
6069
|
const buffer = {};
|
|
@@ -7854,7 +7854,7 @@ var init_EventStreamSerde = __esm({
|
|
|
7854
7854
|
throw new Error("@smithy/core/event-streams - non-struct member not supported in event stream union.");
|
|
7855
7855
|
}
|
|
7856
7856
|
}
|
|
7857
|
-
const messageSerialization = serializer.flush();
|
|
7857
|
+
const messageSerialization = serializer.flush() ?? new Uint8Array();
|
|
7858
7858
|
const body = typeof messageSerialization === "string" ? (this.serdeContext?.utf8Decoder ?? import_util_utf8.fromUtf8)(messageSerialization) : messageSerialization;
|
|
7859
7859
|
return {
|
|
7860
7860
|
body,
|
|
@@ -36422,7 +36422,7 @@ var init_common2 = __esm({
|
|
|
36422
36422
|
queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
|
|
36423
36423
|
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.";
|
|
36424
36424
|
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.";
|
|
36425
|
-
bashDescription = "Execute bash commands for system exploration and
|
|
36425
|
+
bashDescription = "Execute bash commands for system operations: building, running tests, git, package management, etc. NEVER use for code exploration (no grep, cat, find, head, tail) \u2014 use search and extract tools instead. Secure by default with built-in allow/deny lists.";
|
|
36426
36426
|
analyzeAllDescription = 'Answer questions that require analyzing ALL matching data in the codebase. Use for aggregate questions like "What features exist?", "List all API endpoints", "Count TODO comments". The AI automatically plans the search strategy, processes all results via map-reduce, and synthesizes a comprehensive answer. WARNING: Slower than search - only use when you need complete coverage.';
|
|
36427
36427
|
}
|
|
36428
36428
|
});
|
|
@@ -108200,7 +108200,7 @@ ${searchToolDesc1}
|
|
|
108200
108200
|
- searchFiles: Find files by name patterns`;
|
|
108201
108201
|
if (this.enableBash) {
|
|
108202
108202
|
systemPrompt += `
|
|
108203
|
-
- bash: Execute bash commands for system operations
|
|
108203
|
+
- bash: Execute bash commands for system operations (building, running tests, git, etc.). NEVER use bash for code exploration (no grep, cat, find, head, tail) \u2014 always use search and extract tools instead, they are faster and more accurate.`;
|
|
108204
108204
|
}
|
|
108205
108205
|
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.";
|
|
108206
108206
|
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";
|
|
@@ -108255,7 +108255,7 @@ ${searchToolDesc2}
|
|
|
108255
108255
|
- searchFiles: Find files by name patterns`;
|
|
108256
108256
|
if (this.enableBash) {
|
|
108257
108257
|
systemPrompt += `
|
|
108258
|
-
- bash: Execute bash commands for system operations
|
|
108258
|
+
- bash: Execute bash commands for system operations (building, running tests, git, etc.). NEVER use bash for code exploration (no grep, cat, find, head, tail) \u2014 always use search and extract tools instead, they are faster and more accurate.`;
|
|
108259
108259
|
}
|
|
108260
108260
|
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.";
|
|
108261
108261
|
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";
|
|
@@ -108321,7 +108321,8 @@ Follow these instructions carefully:
|
|
|
108321
108321
|
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."}
|
|
108322
108322
|
4. Ensure to get really deep and understand the full picture before answering.
|
|
108323
108323
|
5. Once the task is fully completed, use the attempt_completion tool to provide the final result.
|
|
108324
|
-
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."}
|
|
108324
|
+
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."}
|
|
108325
|
+
7. NEVER use bash for code exploration (no grep, cat, find, head, tail, awk, sed) \u2014 always use search and extract tools instead. Bash is only for system operations like building, running tests, or git commands.${this.allowEdit ? `
|
|
108325
108326
|
7. When modifying files, choose the appropriate tool:
|
|
108326
108327
|
- Use 'edit' for all code modifications:
|
|
108327
108328
|
* 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.
|
|
@@ -108335,7 +108336,14 @@ Follow these instructions carefully:
|
|
|
108335
108336
|
</instructions>
|
|
108336
108337
|
`;
|
|
108337
108338
|
let systemMessage = "";
|
|
108338
|
-
if (this.customPrompt) {
|
|
108339
|
+
if (this.customPrompt && this.promptType && predefinedPrompts[this.promptType]) {
|
|
108340
|
+
systemMessage = "<role>" + predefinedPrompts[this.promptType] + "</role>";
|
|
108341
|
+
systemMessage += commonInstructions;
|
|
108342
|
+
systemMessage += "\n<custom-instructions>\n" + this.customPrompt + "\n</custom-instructions>";
|
|
108343
|
+
if (this.debug) {
|
|
108344
|
+
console.log(`[DEBUG] Using predefined prompt: ${this.promptType} + custom prompt`);
|
|
108345
|
+
}
|
|
108346
|
+
} else if (this.customPrompt) {
|
|
108339
108347
|
systemMessage = "<role>" + this.customPrompt + "</role>";
|
|
108340
108348
|
if (this.debug) {
|
|
108341
108349
|
console.log(`[DEBUG] Using custom prompt`);
|
|
@@ -110717,13 +110725,19 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
110717
110725
|
"- listFiles: Understand directory structure to find where relevant code might live.",
|
|
110718
110726
|
"",
|
|
110719
110727
|
"CRITICAL - How probe search works (do NOT ignore):",
|
|
110720
|
-
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting.",
|
|
110728
|
+
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically.",
|
|
110721
110729
|
'- Searching "allowed_ips" ALREADY matches "AllowedIPs", "allowedIps", "allowed_ips", etc. Do NOT manually try case/style variations.',
|
|
110722
110730
|
'- Searching "getUserData" ALREADY matches "get", "user", "data" and their variations.',
|
|
110723
|
-
"- NEVER repeat the same search query \u2014 you will get the same results.",
|
|
110731
|
+
"- NEVER repeat the same search query \u2014 you will get the same results. Changing the path does NOT change this.",
|
|
110724
110732
|
"- NEVER search trivial variations of the same keyword (e.g., AllowedIPs then allowedIps then allowed_ips). This is wasteful \u2014 probe handles it.",
|
|
110725
|
-
"- If a search returns no results, the term likely does not exist
|
|
110726
|
-
"- If 2-3
|
|
110733
|
+
"- If a search returns no results, the term likely does not exist. Try a genuinely DIFFERENT keyword or concept, not a variation.",
|
|
110734
|
+
"- If 2-3 searches return no results for a concept, STOP searching for it and move on. Do NOT keep retrying.",
|
|
110735
|
+
"",
|
|
110736
|
+
"When to use exact=true:",
|
|
110737
|
+
"- Use exact=true when searching for a KNOWN symbol name (function, type, variable, struct).",
|
|
110738
|
+
"- exact=true matches the literal string only \u2014 no stemming, no splitting.",
|
|
110739
|
+
'- This is ideal for precise lookups: exact=true "ForwardMessage", exact=true "SessionLimiter", exact=true "ThrottleRetryLimit".',
|
|
110740
|
+
"- Do NOT use exact=true for exploratory/conceptual queries \u2014 use the default for those.",
|
|
110727
110741
|
"",
|
|
110728
110742
|
"GOOD search strategy (do this):",
|
|
110729
110743
|
' Query: "How does authentication work and how are sessions managed?"',
|
|
@@ -110732,10 +110746,18 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
110732
110746
|
' \u2192 search "allowlist middleware" (one search, probe handles IP/ip/Ip variations)',
|
|
110733
110747
|
' Query: "How does BM25 scoring work with SIMD optimization?"',
|
|
110734
110748
|
' \u2192 search "BM25 scoring" \u2192 search "SIMD optimization" (two different concepts)',
|
|
110749
|
+
' Query: "Find ForwardMessage and SessionLimiter functions"',
|
|
110750
|
+
' \u2192 search exact=true "ForwardMessage" \u2192 search exact=true "SessionLimiter" (known symbols, use exact)',
|
|
110751
|
+
' Query: "Find ThrottleRetryLimit usage"',
|
|
110752
|
+
' \u2192 search exact=true "ThrottleRetryLimit" (one search, if no results the symbol does not exist \u2014 stop)',
|
|
110735
110753
|
"",
|
|
110736
110754
|
"BAD search strategy (never do this):",
|
|
110737
|
-
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG:
|
|
110738
|
-
' \u2192 search "
|
|
110755
|
+
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG: case/style variations, probe handles them)',
|
|
110756
|
+
' \u2192 search "limitDRL" \u2192 search "LimitDRL" (WRONG: case variation of same term)',
|
|
110757
|
+
' \u2192 search "throttle_retry_limit" after searching "ThrottleRetryLimit" (WRONG: snake_case variation, probe handles it)',
|
|
110758
|
+
' \u2192 search "ThrottleRetryLimit" path=tyk \u2192 search "ThrottleRetryLimit" path=gateway \u2192 search "ThrottleRetryLimit" path=apidef (WRONG: same query on different paths hoping for different results)',
|
|
110759
|
+
' \u2192 search "func (k *RateLimitAndQuotaCheck) handleRateLimitFailure" (WRONG: do not search full function signatures, just use exact=true "handleRateLimitFailure")',
|
|
110760
|
+
' \u2192 search "ForwardMessage" \u2192 search "ForwardMessage" \u2192 search "ForwardMessage" (WRONG: repeating the exact same query)',
|
|
110739
110761
|
' \u2192 search "error handling" \u2192 search "error handling" \u2192 search "error handling" (WRONG: repeating exact same query)',
|
|
110740
110762
|
"",
|
|
110741
110763
|
"Keyword tips:",
|
|
@@ -110744,12 +110766,13 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
110744
110766
|
'- To bypass stopword filtering: wrap terms in quotes ("return", "struct") or set exact=true. Both disable stemming and splitting too.',
|
|
110745
110767
|
"- Multiple words without operators use OR logic: foo bar = foo OR bar. Use AND explicitly if you need both: foo AND bar.",
|
|
110746
110768
|
'- camelCase terms are split: getUserData becomes "get", "user", "data" \u2014 so one search covers all naming styles.',
|
|
110769
|
+
'- Do NOT search for full function signatures like "func (r *Type) Method(args)". Just search for the method name with exact=true.',
|
|
110747
110770
|
"",
|
|
110748
110771
|
"Strategy:",
|
|
110749
110772
|
"1. Analyze the query - identify key concepts, entities, and relationships",
|
|
110750
|
-
"2. Run ONE focused search per concept
|
|
110773
|
+
"2. Run ONE focused search per concept. For known symbol names use exact=true. For concepts use default (exact=false).",
|
|
110751
110774
|
"3. If a search returns results, use extract to verify relevance",
|
|
110752
|
-
"4.
|
|
110775
|
+
"4. If a search returns NO results, the term does not exist in the codebase. Do NOT retry with variations, different paths, or longer strings. Move on.",
|
|
110753
110776
|
"5. Combine all relevant targets in your final response",
|
|
110754
110777
|
"",
|
|
110755
110778
|
`Query: ${searchQuery}`,
|
|
@@ -111072,6 +111095,36 @@ var init_vercel = __esm({
|
|
|
111072
111095
|
} else if (targets) {
|
|
111073
111096
|
const parsedTargets = parseTargets(targets);
|
|
111074
111097
|
extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
111098
|
+
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
111099
|
+
extractFiles = extractFiles.map((target) => {
|
|
111100
|
+
const { filePart, suffix } = splitTargetSuffix(target);
|
|
111101
|
+
if ((0, import_fs11.existsSync)(filePart)) return target;
|
|
111102
|
+
const cwdPrefix = effectiveCwd.endsWith("/") ? effectiveCwd : effectiveCwd + "/";
|
|
111103
|
+
const relativePart = filePart.startsWith(cwdPrefix) ? filePart.slice(cwdPrefix.length) : null;
|
|
111104
|
+
if (relativePart) {
|
|
111105
|
+
for (const folder of options.allowedFolders) {
|
|
111106
|
+
const candidate = folder + "/" + relativePart;
|
|
111107
|
+
if ((0, import_fs11.existsSync)(candidate)) {
|
|
111108
|
+
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} \u2192 ${candidate}`);
|
|
111109
|
+
return candidate + suffix;
|
|
111110
|
+
}
|
|
111111
|
+
}
|
|
111112
|
+
}
|
|
111113
|
+
for (const folder of options.allowedFolders) {
|
|
111114
|
+
const folderPrefix = folder.endsWith("/") ? folder : folder + "/";
|
|
111115
|
+
const wsParent = folderPrefix.replace(/[^/]+\/$/, "");
|
|
111116
|
+
if (filePart.startsWith(wsParent)) {
|
|
111117
|
+
const tail = filePart.slice(wsParent.length);
|
|
111118
|
+
const candidate = folderPrefix + tail;
|
|
111119
|
+
if (candidate !== filePart && (0, import_fs11.existsSync)(candidate)) {
|
|
111120
|
+
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} \u2192 ${candidate}`);
|
|
111121
|
+
return candidate + suffix;
|
|
111122
|
+
}
|
|
111123
|
+
}
|
|
111124
|
+
}
|
|
111125
|
+
return target;
|
|
111126
|
+
});
|
|
111127
|
+
}
|
|
111075
111128
|
let effectiveFormat = format2;
|
|
111076
111129
|
if (outline && format2 === "outline-xml") {
|
|
111077
111130
|
effectiveFormat = "xml";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@probelabs/probe",
|
|
3
|
-
"version": "0.6.0-
|
|
3
|
+
"version": "0.6.0-rc282",
|
|
4
4
|
"description": "Node.js wrapper for the probe code search tool",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"@ai-sdk/amazon-bedrock": "^1.0.8",
|
|
77
77
|
"@ai-sdk/anthropic": "^2.0.8",
|
|
78
|
-
"@ai-sdk/google": "^
|
|
78
|
+
"@ai-sdk/google": "^3.0.37",
|
|
79
79
|
"@ai-sdk/openai": "^2.0.10",
|
|
80
80
|
"@anthropic-ai/claude-agent-sdk": "^0.1.46",
|
|
81
81
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
package/src/agent/ProbeAgent.js
CHANGED
|
@@ -2876,7 +2876,7 @@ ${searchToolDesc1}
|
|
|
2876
2876
|
- searchFiles: Find files by name patterns`;
|
|
2877
2877
|
|
|
2878
2878
|
if (this.enableBash) {
|
|
2879
|
-
systemPrompt += `\n- bash: Execute bash commands for system operations
|
|
2879
|
+
systemPrompt += `\n- bash: Execute bash commands for system operations (building, running tests, git, etc.). NEVER use bash for code exploration (no grep, cat, find, head, tail) — always use search and extract tools instead, they are faster and more accurate.`;
|
|
2880
2880
|
}
|
|
2881
2881
|
|
|
2882
2882
|
const searchGuidance1 = this.searchDelegate
|
|
@@ -2942,7 +2942,7 @@ ${searchToolDesc2}
|
|
|
2942
2942
|
- searchFiles: Find files by name patterns`;
|
|
2943
2943
|
|
|
2944
2944
|
if (this.enableBash) {
|
|
2945
|
-
systemPrompt += `\n- bash: Execute bash commands for system operations
|
|
2945
|
+
systemPrompt += `\n- bash: Execute bash commands for system operations (building, running tests, git, etc.). NEVER use bash for code exploration (no grep, cat, find, head, tail) — always use search and extract tools instead, they are faster and more accurate.`;
|
|
2946
2946
|
}
|
|
2947
2947
|
|
|
2948
2948
|
const searchGuidance2 = this.searchDelegate
|
|
@@ -3018,7 +3018,8 @@ Follow these instructions carefully:
|
|
|
3018
3018
|
3. You should always prefer the search tool for code-related questions.${this.searchDelegate ? ' Ask natural language questions — 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 — do NOT try keyword variations manually. Read full files only if really necessary.'}
|
|
3019
3019
|
4. Ensure to get really deep and understand the full picture before answering.
|
|
3020
3020
|
5. Once the task is fully completed, use the attempt_completion tool to provide the final result.
|
|
3021
|
-
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.'}
|
|
3021
|
+
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.'}
|
|
3022
|
+
7. NEVER use bash for code exploration (no grep, cat, find, head, tail, awk, sed) — always use search and extract tools instead. Bash is only for system operations like building, running tests, or git commands.${this.allowEdit ? `
|
|
3022
3023
|
7. When modifying files, choose the appropriate tool:
|
|
3023
3024
|
- Use 'edit' for all code modifications:
|
|
3024
3025
|
* PREFERRED: Use start_line (and optionally end_line) for line-targeted editing — 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.
|
|
@@ -3035,22 +3036,30 @@ Follow these instructions carefully:
|
|
|
3035
3036
|
// Use predefined prompts from shared module (imported at top of file)
|
|
3036
3037
|
let systemMessage = '';
|
|
3037
3038
|
|
|
3038
|
-
//
|
|
3039
|
-
if (this.customPrompt) {
|
|
3039
|
+
// Build system message from predefined prompt + optional custom prompt
|
|
3040
|
+
if (this.customPrompt && this.promptType && predefinedPrompts[this.promptType]) {
|
|
3041
|
+
// Both: use predefined as base, append custom wrapped in tag
|
|
3042
|
+
systemMessage = "<role>" + predefinedPrompts[this.promptType] + "</role>";
|
|
3043
|
+
systemMessage += commonInstructions;
|
|
3044
|
+
systemMessage += "\n<custom-instructions>\n" + this.customPrompt + "\n</custom-instructions>";
|
|
3045
|
+
if (this.debug) {
|
|
3046
|
+
console.log(`[DEBUG] Using predefined prompt: ${this.promptType} + custom prompt`);
|
|
3047
|
+
}
|
|
3048
|
+
} else if (this.customPrompt) {
|
|
3049
|
+
// Only custom prompt
|
|
3040
3050
|
systemMessage = "<role>" + this.customPrompt + "</role>";
|
|
3041
3051
|
if (this.debug) {
|
|
3042
3052
|
console.log(`[DEBUG] Using custom prompt`);
|
|
3043
3053
|
}
|
|
3044
|
-
}
|
|
3045
|
-
|
|
3046
|
-
else if (this.promptType && predefinedPrompts[this.promptType]) {
|
|
3054
|
+
} else if (this.promptType && predefinedPrompts[this.promptType]) {
|
|
3055
|
+
// Only predefined prompt
|
|
3047
3056
|
systemMessage = "<role>" + predefinedPrompts[this.promptType] + "</role>";
|
|
3048
3057
|
if (this.debug) {
|
|
3049
3058
|
console.log(`[DEBUG] Using predefined prompt: ${this.promptType}`);
|
|
3050
3059
|
}
|
|
3051
3060
|
systemMessage += commonInstructions;
|
|
3052
3061
|
} else {
|
|
3053
|
-
//
|
|
3062
|
+
// Default: code explorer
|
|
3054
3063
|
systemMessage = "<role>" + predefinedPrompts['code-explorer'] + "</role>";
|
|
3055
3064
|
if (this.debug) {
|
|
3056
3065
|
console.log(`[DEBUG] Using default prompt: code explorer`);
|
package/src/tools/common.js
CHANGED
|
@@ -154,7 +154,7 @@ export const searchDelegateDescription = 'Search code in the repository by askin
|
|
|
154
154
|
export const queryDescription = 'Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.';
|
|
155
155
|
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. Line numbers from output can be used with edit start_line/end_line for precise editing.';
|
|
156
156
|
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.';
|
|
157
|
-
export const bashDescription = 'Execute bash commands for system exploration and
|
|
157
|
+
export const bashDescription = 'Execute bash commands for system operations: building, running tests, git, package management, etc. NEVER use for code exploration (no grep, cat, find, head, tail) — use search and extract tools instead. Secure by default with built-in allow/deny lists.';
|
|
158
158
|
export const analyzeAllDescription = 'Answer questions that require analyzing ALL matching data in the codebase. Use for aggregate questions like "What features exist?", "List all API endpoints", "Count TODO comments". The AI automatically plans the search strategy, processes all results via map-reduce, and synthesizes a comprehensive answer. WARNING: Slower than search - only use when you need complete coverage.';
|
|
159
159
|
|
|
160
160
|
|
package/src/tools/vercel.js
CHANGED
|
@@ -144,13 +144,19 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
144
144
|
'- listFiles: Understand directory structure to find where relevant code might live.',
|
|
145
145
|
'',
|
|
146
146
|
'CRITICAL - How probe search works (do NOT ignore):',
|
|
147
|
-
'- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting.',
|
|
147
|
+
'- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically.',
|
|
148
148
|
'- Searching "allowed_ips" ALREADY matches "AllowedIPs", "allowedIps", "allowed_ips", etc. Do NOT manually try case/style variations.',
|
|
149
149
|
'- Searching "getUserData" ALREADY matches "get", "user", "data" and their variations.',
|
|
150
|
-
'- NEVER repeat the same search query — you will get the same results.',
|
|
150
|
+
'- NEVER repeat the same search query — you will get the same results. Changing the path does NOT change this.',
|
|
151
151
|
'- NEVER search trivial variations of the same keyword (e.g., AllowedIPs then allowedIps then allowed_ips). This is wasteful — probe handles it.',
|
|
152
|
-
'- If a search returns no results, the term likely does not exist
|
|
153
|
-
'- If 2-3
|
|
152
|
+
'- If a search returns no results, the term likely does not exist. Try a genuinely DIFFERENT keyword or concept, not a variation.',
|
|
153
|
+
'- If 2-3 searches return no results for a concept, STOP searching for it and move on. Do NOT keep retrying.',
|
|
154
|
+
'',
|
|
155
|
+
'When to use exact=true:',
|
|
156
|
+
'- Use exact=true when searching for a KNOWN symbol name (function, type, variable, struct).',
|
|
157
|
+
'- exact=true matches the literal string only — no stemming, no splitting.',
|
|
158
|
+
'- This is ideal for precise lookups: exact=true "ForwardMessage", exact=true "SessionLimiter", exact=true "ThrottleRetryLimit".',
|
|
159
|
+
'- Do NOT use exact=true for exploratory/conceptual queries — use the default for those.',
|
|
154
160
|
'',
|
|
155
161
|
'GOOD search strategy (do this):',
|
|
156
162
|
' Query: "How does authentication work and how are sessions managed?"',
|
|
@@ -159,10 +165,18 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
159
165
|
' → search "allowlist middleware" (one search, probe handles IP/ip/Ip variations)',
|
|
160
166
|
' Query: "How does BM25 scoring work with SIMD optimization?"',
|
|
161
167
|
' → search "BM25 scoring" → search "SIMD optimization" (two different concepts)',
|
|
168
|
+
' Query: "Find ForwardMessage and SessionLimiter functions"',
|
|
169
|
+
' → search exact=true "ForwardMessage" → search exact=true "SessionLimiter" (known symbols, use exact)',
|
|
170
|
+
' Query: "Find ThrottleRetryLimit usage"',
|
|
171
|
+
' → search exact=true "ThrottleRetryLimit" (one search, if no results the symbol does not exist — stop)',
|
|
162
172
|
'',
|
|
163
173
|
'BAD search strategy (never do this):',
|
|
164
|
-
' → search "AllowedIPs" → search "allowedIps" → search "allowed_ips" (WRONG:
|
|
165
|
-
' → search "
|
|
174
|
+
' → search "AllowedIPs" → search "allowedIps" → search "allowed_ips" (WRONG: case/style variations, probe handles them)',
|
|
175
|
+
' → search "limitDRL" → search "LimitDRL" (WRONG: case variation of same term)',
|
|
176
|
+
' → search "throttle_retry_limit" after searching "ThrottleRetryLimit" (WRONG: snake_case variation, probe handles it)',
|
|
177
|
+
' → search "ThrottleRetryLimit" path=tyk → search "ThrottleRetryLimit" path=gateway → search "ThrottleRetryLimit" path=apidef (WRONG: same query on different paths hoping for different results)',
|
|
178
|
+
' → search "func (k *RateLimitAndQuotaCheck) handleRateLimitFailure" (WRONG: do not search full function signatures, just use exact=true "handleRateLimitFailure")',
|
|
179
|
+
' → search "ForwardMessage" → search "ForwardMessage" → search "ForwardMessage" (WRONG: repeating the exact same query)',
|
|
166
180
|
' → search "error handling" → search "error handling" → search "error handling" (WRONG: repeating exact same query)',
|
|
167
181
|
'',
|
|
168
182
|
'Keyword tips:',
|
|
@@ -171,12 +185,13 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
171
185
|
'- To bypass stopword filtering: wrap terms in quotes ("return", "struct") or set exact=true. Both disable stemming and splitting too.',
|
|
172
186
|
'- Multiple words without operators use OR logic: foo bar = foo OR bar. Use AND explicitly if you need both: foo AND bar.',
|
|
173
187
|
'- camelCase terms are split: getUserData becomes "get", "user", "data" — so one search covers all naming styles.',
|
|
188
|
+
'- Do NOT search for full function signatures like "func (r *Type) Method(args)". Just search for the method name with exact=true.',
|
|
174
189
|
'',
|
|
175
190
|
'Strategy:',
|
|
176
191
|
'1. Analyze the query - identify key concepts, entities, and relationships',
|
|
177
|
-
'2. Run ONE focused search per concept
|
|
192
|
+
'2. Run ONE focused search per concept. For known symbol names use exact=true. For concepts use default (exact=false).',
|
|
178
193
|
'3. If a search returns results, use extract to verify relevance',
|
|
179
|
-
'4.
|
|
194
|
+
'4. If a search returns NO results, the term does not exist in the codebase. Do NOT retry with variations, different paths, or longer strings. Move on.',
|
|
180
195
|
'5. Combine all relevant targets in your final response',
|
|
181
196
|
'',
|
|
182
197
|
`Query: ${searchQuery}`,
|
|
@@ -570,6 +585,50 @@ export const extractTool = (options = {}) => {
|
|
|
570
585
|
// Resolve relative paths in targets against cwd
|
|
571
586
|
extractFiles = parsedTargets.map(target => resolveTargetPath(target, effectiveCwd));
|
|
572
587
|
|
|
588
|
+
// Auto-fix: if resolved paths don't exist, try allowedFolders subdirs
|
|
589
|
+
// Handles when search returns relative paths (e.g., "gateway/file.go") and
|
|
590
|
+
// model constructs wrong absolute paths (e.g., /workspace/gateway/file.go
|
|
591
|
+
// instead of /workspace/tyk/gateway/file.go)
|
|
592
|
+
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
593
|
+
extractFiles = extractFiles.map(target => {
|
|
594
|
+
const { filePart, suffix } = splitTargetSuffix(target);
|
|
595
|
+
if (existsSync(filePart)) return target;
|
|
596
|
+
|
|
597
|
+
// Try resolving the relative tail against each allowedFolder
|
|
598
|
+
const cwdPrefix = (effectiveCwd.endsWith('/') ? effectiveCwd : effectiveCwd + '/');
|
|
599
|
+
const relativePart = filePart.startsWith(cwdPrefix)
|
|
600
|
+
? filePart.slice(cwdPrefix.length)
|
|
601
|
+
: null;
|
|
602
|
+
|
|
603
|
+
if (relativePart) {
|
|
604
|
+
for (const folder of options.allowedFolders) {
|
|
605
|
+
const candidate = folder + '/' + relativePart;
|
|
606
|
+
if (existsSync(candidate)) {
|
|
607
|
+
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} → ${candidate}`);
|
|
608
|
+
return candidate + suffix;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Try stripping workspace prefix and resolving against allowedFolders
|
|
614
|
+
// e.g., /tmp/visor-workspaces/abc/gateway/file.go → try each folder + gateway/file.go
|
|
615
|
+
for (const folder of options.allowedFolders) {
|
|
616
|
+
const folderPrefix = folder.endsWith('/') ? folder : folder + '/';
|
|
617
|
+
const wsParent = folderPrefix.replace(/[^/]+\/$/, '');
|
|
618
|
+
if (filePart.startsWith(wsParent)) {
|
|
619
|
+
const tail = filePart.slice(wsParent.length);
|
|
620
|
+
const candidate = folderPrefix + tail;
|
|
621
|
+
if (candidate !== filePart && existsSync(candidate)) {
|
|
622
|
+
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} → ${candidate}`);
|
|
623
|
+
return candidate + suffix;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
return target;
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
|
|
573
632
|
// Apply format mapping for outline-xml to xml
|
|
574
633
|
let effectiveFormat = format;
|
|
575
634
|
if (outline && format === 'outline-xml') {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|