@probelabs/probe 0.6.0-rc247 → 0.6.0-rc249
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-rc249-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc249-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc249-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc249-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc249-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +31 -7
- package/build/agent/dsl/environment.js +3 -1
- package/build/agent/index.js +86 -7
- package/build/tools/common.js +9 -0
- package/build/tools/executePlan.js +71 -3
- package/cjs/agent/ProbeAgent.cjs +7432 -9672
- package/cjs/index.cjs +7435 -9675
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +31 -7
- package/src/agent/dsl/environment.js +3 -1
- package/src/tools/common.js +9 -0
- package/src/tools/executePlan.js +71 -3
- package/bin/binaries/probe-v0.6.0-rc247-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc247-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc247-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc247-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc247-x86_64-unknown-linux-musl.tar.gz +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -85,7 +85,7 @@ import {
|
|
|
85
85
|
validateAndFixMermaidResponse,
|
|
86
86
|
tryAutoWrapForSimpleSchema
|
|
87
87
|
} from './schemaUtils.js';
|
|
88
|
-
import { removeThinkingTags } from './xmlParsingUtils.js';
|
|
88
|
+
import { removeThinkingTags, extractThinkingContent } from './xmlParsingUtils.js';
|
|
89
89
|
import { predefinedPrompts } from './shared/prompts.js';
|
|
90
90
|
import {
|
|
91
91
|
MCPXmlBridge,
|
|
@@ -2904,10 +2904,11 @@ Follow these instructions carefully:
|
|
|
2904
2904
|
// Track initial history length for storage
|
|
2905
2905
|
const oldHistoryLength = this.history.length;
|
|
2906
2906
|
|
|
2907
|
-
// Reset output buffer for this answer() call — but NOT during
|
|
2908
|
-
//
|
|
2909
|
-
//
|
|
2910
|
-
|
|
2907
|
+
// Reset output buffer for this answer() call — but NOT during recursive calls.
|
|
2908
|
+
// _schemaFormatted: recursive call to fix JSON formatting
|
|
2909
|
+
// _completionPromptProcessed: recursive call for completionPrompt follow-up
|
|
2910
|
+
// Both must preserve the output buffer so the parent call can append it.
|
|
2911
|
+
if (this._outputBuffer && !options?._schemaFormatted && !options?._completionPromptProcessed) {
|
|
2911
2912
|
this._outputBuffer.items = [];
|
|
2912
2913
|
}
|
|
2913
2914
|
|
|
@@ -3554,8 +3555,25 @@ Follow these instructions carefully:
|
|
|
3554
3555
|
continue; // Don't use broken response, continue the loop
|
|
3555
3556
|
}
|
|
3556
3557
|
|
|
3557
|
-
|
|
3558
|
-
|
|
3558
|
+
// Pre-strip thinking tags to avoid losing content at final cleanup stage
|
|
3559
|
+
const strippedContent = removeThinkingTags(prevContent);
|
|
3560
|
+
if (strippedContent.length > 50) {
|
|
3561
|
+
// Enough content outside thinking tags — use stripped version directly
|
|
3562
|
+
finalResult = strippedContent;
|
|
3563
|
+
if (this.debug) console.log(`[DEBUG] Using previous response (thinking-stripped) as completion: ${finalResult.substring(0, 100)}...`);
|
|
3564
|
+
} else {
|
|
3565
|
+
// Content was mostly/entirely inside thinking tags.
|
|
3566
|
+
// Extract thinking content and use it as the actual answer.
|
|
3567
|
+
const thinkingContent = extractThinkingContent(prevContent);
|
|
3568
|
+
if (thinkingContent && thinkingContent.length > 50) {
|
|
3569
|
+
finalResult = thinkingContent;
|
|
3570
|
+
if (this.debug) console.log(`[DEBUG] Previous response was mostly in thinking tags — using thinking content as completion: ${finalResult.substring(0, 100)}...`);
|
|
3571
|
+
} else {
|
|
3572
|
+
// Neither stripped nor thinking content is substantive — use raw as fallback
|
|
3573
|
+
finalResult = prevContent;
|
|
3574
|
+
if (this.debug) console.log(`[DEBUG] Using previous response as completion (raw): ${finalResult.substring(0, 100)}...`);
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3559
3577
|
} else {
|
|
3560
3578
|
finalResult = 'Error: No previous response found to use as completion.';
|
|
3561
3579
|
if (this.debug) console.log(`[DEBUG] No suitable previous response found for attempt_complete shorthand`);
|
|
@@ -4296,10 +4314,16 @@ After reviewing, provide your final answer using attempt_completion.`;
|
|
|
4296
4314
|
|
|
4297
4315
|
// Make a follow-up call with the completion prompt
|
|
4298
4316
|
// Pass _completionPromptProcessed to prevent infinite loops
|
|
4317
|
+
// Save output buffer — the recursive answer() must not destroy DSL output() content
|
|
4318
|
+
const savedOutputItems = this._outputBuffer ? [...this._outputBuffer.items] : [];
|
|
4299
4319
|
const completionResult = await this.answer(completionPromptMessage, [], {
|
|
4300
4320
|
...options,
|
|
4301
4321
|
_completionPromptProcessed: true
|
|
4302
4322
|
});
|
|
4323
|
+
// Restore output buffer so the parent call can append it to the final result
|
|
4324
|
+
if (this._outputBuffer) {
|
|
4325
|
+
this._outputBuffer.items = savedOutputItems;
|
|
4326
|
+
}
|
|
4303
4327
|
|
|
4304
4328
|
// Update finalResult with the result from the completion prompt
|
|
4305
4329
|
finalResult = completionResult;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
searchSchema,
|
|
11
|
+
searchAllSchema,
|
|
11
12
|
querySchema,
|
|
12
13
|
extractSchema,
|
|
13
14
|
bashSchema,
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
// Map of native tool names to their Zod schemas
|
|
17
18
|
const NATIVE_TOOL_SCHEMAS = {
|
|
18
19
|
search: searchSchema,
|
|
20
|
+
searchAll: searchAllSchema,
|
|
19
21
|
query: querySchema,
|
|
20
22
|
extract: extractSchema,
|
|
21
23
|
bash: bashSchema,
|
|
@@ -23,7 +25,7 @@ const NATIVE_TOOL_SCHEMAS = {
|
|
|
23
25
|
|
|
24
26
|
// Tools that are inherently async (make network/LLM calls)
|
|
25
27
|
const ALWAYS_ASYNC = new Set([
|
|
26
|
-
'search', 'query', 'extract', 'listFiles', 'searchFiles', 'bash',
|
|
28
|
+
'search', 'searchAll', 'query', 'extract', 'listFiles', 'searchFiles', 'bash',
|
|
27
29
|
'LLM', 'map',
|
|
28
30
|
]);
|
|
29
31
|
|
package/build/agent/index.js
CHANGED
|
@@ -9905,7 +9905,7 @@ function resolveTargetPath(target, cwd) {
|
|
|
9905
9905
|
}
|
|
9906
9906
|
return filePart + suffix;
|
|
9907
9907
|
}
|
|
9908
|
-
var searchSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, analyzeAllToolDefinition, bashToolDefinition, googleSearchToolDefinition, urlContextToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription, DEFAULT_VALID_TOOLS;
|
|
9908
|
+
var searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, analyzeAllToolDefinition, bashToolDefinition, googleSearchToolDefinition, urlContextToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription, DEFAULT_VALID_TOOLS;
|
|
9909
9909
|
var init_common = __esm({
|
|
9910
9910
|
"src/tools/common.js"() {
|
|
9911
9911
|
"use strict";
|
|
@@ -9916,9 +9916,17 @@ var init_common = __esm({
|
|
|
9916
9916
|
query: external_exports.string().describe("Search query with Elasticsearch syntax. Use quotes for exact matches, AND/OR for boolean logic, - for negation."),
|
|
9917
9917
|
path: external_exports.string().optional().default(".").describe('Path to search in. For dependencies use "go:github.com/owner/repo", "js:package_name", or "rust:cargo_name" etc.'),
|
|
9918
9918
|
exact: external_exports.boolean().optional().default(false).describe('Default (false) enables stemming and keyword splitting for exploratory search - "getUserData" matches "get", "user", "data", etc. Set true for precise symbol lookup where "getUserData" matches only "getUserData". Use true when you know the exact symbol name.'),
|
|
9919
|
+
maxTokens: external_exports.number().nullable().optional().describe("Maximum tokens to return. Default is 20000. Set to null for unlimited results."),
|
|
9919
9920
|
session: external_exports.string().optional().describe("Session ID for result caching and pagination. Pass the session ID from a previous search to get additional results (next page). Results already shown in a session are automatically excluded. Omit for a fresh search."),
|
|
9920
9921
|
nextPage: external_exports.boolean().optional().default(false).describe("Set to true when requesting the next page of results. Requires passing the same session ID from the previous search output.")
|
|
9921
9922
|
});
|
|
9923
|
+
searchAllSchema = external_exports.object({
|
|
9924
|
+
query: external_exports.string().describe("Search query with Elasticsearch syntax. Use quotes for exact matches, AND/OR for boolean logic, - for negation."),
|
|
9925
|
+
path: external_exports.string().optional().default(".").describe("Path to search in."),
|
|
9926
|
+
exact: external_exports.boolean().optional().default(false).describe("Use exact matching instead of stemming."),
|
|
9927
|
+
maxTokensPerPage: external_exports.number().optional().default(2e4).describe("Tokens per page when paginating. Default 20000."),
|
|
9928
|
+
maxPages: external_exports.number().optional().default(50).describe("Maximum pages to retrieve. Default 50 (safety limit).")
|
|
9929
|
+
});
|
|
9922
9930
|
querySchema = external_exports.object({
|
|
9923
9931
|
pattern: external_exports.string().describe("AST pattern to search for. Use $NAME for variable names, $$$PARAMS for parameter lists, etc."),
|
|
9924
9932
|
path: external_exports.string().optional().default(".").describe("Path to search in"),
|
|
@@ -22110,12 +22118,14 @@ var init_environment = __esm({
|
|
|
22110
22118
|
init_common();
|
|
22111
22119
|
NATIVE_TOOL_SCHEMAS = {
|
|
22112
22120
|
search: searchSchema,
|
|
22121
|
+
searchAll: searchAllSchema,
|
|
22113
22122
|
query: querySchema,
|
|
22114
22123
|
extract: extractSchema,
|
|
22115
22124
|
bash: bashSchema
|
|
22116
22125
|
};
|
|
22117
22126
|
ALWAYS_ASYNC = /* @__PURE__ */ new Set([
|
|
22118
22127
|
"search",
|
|
22128
|
+
"searchAll",
|
|
22119
22129
|
"query",
|
|
22120
22130
|
"extract",
|
|
22121
22131
|
"listFiles",
|
|
@@ -28992,6 +29002,7 @@ function buildToolImplementations(configOptions) {
|
|
|
28992
29002
|
if (!searchPaths || searchPaths.length === 0) {
|
|
28993
29003
|
searchPaths = [cwd || "."];
|
|
28994
29004
|
}
|
|
29005
|
+
const maxTokens = params.maxTokens !== void 0 ? params.maxTokens : 2e4;
|
|
28995
29006
|
return await search({
|
|
28996
29007
|
query: params.query,
|
|
28997
29008
|
path: searchPaths.join(" "),
|
|
@@ -28999,7 +29010,7 @@ function buildToolImplementations(configOptions) {
|
|
|
28999
29010
|
allowTests: true,
|
|
29000
29011
|
exact: params.exact || false,
|
|
29001
29012
|
json: false,
|
|
29002
|
-
maxTokens
|
|
29013
|
+
maxTokens,
|
|
29003
29014
|
session: sessionId,
|
|
29004
29015
|
timeout: 60
|
|
29005
29016
|
});
|
|
@@ -29008,6 +29019,56 @@ function buildToolImplementations(configOptions) {
|
|
|
29008
29019
|
}
|
|
29009
29020
|
}
|
|
29010
29021
|
};
|
|
29022
|
+
tools2.searchAll = {
|
|
29023
|
+
execute: async (params) => {
|
|
29024
|
+
try {
|
|
29025
|
+
let searchPaths;
|
|
29026
|
+
if (params.path) {
|
|
29027
|
+
searchPaths = parseAndResolvePaths(params.path, cwd);
|
|
29028
|
+
}
|
|
29029
|
+
if (!searchPaths || searchPaths.length === 0) {
|
|
29030
|
+
searchPaths = [cwd || "."];
|
|
29031
|
+
}
|
|
29032
|
+
const pathStr = searchPaths.join(" ");
|
|
29033
|
+
const maxTokensPerPage = params.maxTokensPerPage || 2e4;
|
|
29034
|
+
const maxPages = params.maxPages || 50;
|
|
29035
|
+
let allResults = "";
|
|
29036
|
+
let pageCount = 0;
|
|
29037
|
+
while (pageCount < maxPages) {
|
|
29038
|
+
const pageResult = await search({
|
|
29039
|
+
query: params.query,
|
|
29040
|
+
path: pathStr,
|
|
29041
|
+
cwd,
|
|
29042
|
+
allowTests: true,
|
|
29043
|
+
exact: params.exact || false,
|
|
29044
|
+
json: false,
|
|
29045
|
+
maxTokens: maxTokensPerPage,
|
|
29046
|
+
session: sessionId,
|
|
29047
|
+
timeout: 60
|
|
29048
|
+
});
|
|
29049
|
+
pageCount++;
|
|
29050
|
+
if (!pageResult || pageResult.trim().length === 0) {
|
|
29051
|
+
break;
|
|
29052
|
+
}
|
|
29053
|
+
if (pageResult.includes("All results retrieved") || pageResult.includes("No results found") || pageResult.includes("No matching code blocks found")) {
|
|
29054
|
+
if (pageResult.trim().length > 50) {
|
|
29055
|
+
allResults += (allResults ? "\n\n" : "") + pageResult;
|
|
29056
|
+
}
|
|
29057
|
+
break;
|
|
29058
|
+
}
|
|
29059
|
+
allResults += (allResults ? "\n\n" : "") + pageResult;
|
|
29060
|
+
}
|
|
29061
|
+
if (pageCount >= maxPages) {
|
|
29062
|
+
allResults += `
|
|
29063
|
+
|
|
29064
|
+
[Warning: Reached maximum page limit (${maxPages}). Some results may be omitted.]`;
|
|
29065
|
+
}
|
|
29066
|
+
return allResults || "No results found.";
|
|
29067
|
+
} catch (e) {
|
|
29068
|
+
return `SearchAll error: ${e.message}`;
|
|
29069
|
+
}
|
|
29070
|
+
}
|
|
29071
|
+
};
|
|
29011
29072
|
tools2.query = {
|
|
29012
29073
|
execute: async (params) => {
|
|
29013
29074
|
try {
|
|
@@ -29192,7 +29253,8 @@ ${lastError}
|
|
|
29192
29253
|
|
|
29193
29254
|
RULES REMINDER:
|
|
29194
29255
|
- search(query) is KEYWORD SEARCH \u2014 pass a search query, NOT a filename. Use extract(filepath) to read file contents.
|
|
29195
|
-
- search()
|
|
29256
|
+
- search() returns up to 20K tokens by default. Use search(query, path, {maxTokens: null}) for unlimited, or searchAll(query) to auto-paginate ALL results.
|
|
29257
|
+
- search(), searchAll(), query(), extract(), listFiles(), bash() all return STRINGS, not arrays.
|
|
29196
29258
|
- Use chunk(stringData) to split a string into an array of chunks.
|
|
29197
29259
|
- Use map(array, fn) only with arrays. Do NOT pass strings to map().
|
|
29198
29260
|
- Do NOT use .map(), .forEach(), .filter(), .join() \u2014 use for..of loops instead.
|
|
@@ -29493,7 +29555,8 @@ return table;
|
|
|
29493
29555
|
${funcList}
|
|
29494
29556
|
|
|
29495
29557
|
**Return types \u2014 IMPORTANT:**
|
|
29496
|
-
- \`search(query)\` \u2192 **keyword search** \u2014 pass a search query (e.g. "error handling"), NOT a filename. Returns a **string** (matching code snippets
|
|
29558
|
+
- \`search(query)\` \u2192 **keyword search** \u2014 pass a search query (e.g. "error handling"), NOT a filename. Returns a **string** (matching code snippets, up to 20K tokens by default). Use \`{maxTokens: null}\` for unlimited.
|
|
29559
|
+
- \`searchAll(query)\` \u2192 **exhaustive keyword search** \u2014 auto-paginates to retrieve ALL matching results. Returns a **string** (all matching code snippets concatenated). Use for bulk analysis.
|
|
29497
29560
|
- \`query(pattern)\` \u2192 **AST search** \u2014 pass a tree-sitter pattern. Returns a **string** (matching code elements).
|
|
29498
29561
|
- \`extract(targets)\` \u2192 **read file contents** \u2014 pass a file path like "src/main.js" or "src/main.js:42". Use this to read specific files found by listFiles(). Returns a **string**.
|
|
29499
29562
|
- \`listFiles(pattern)\` \u2192 **list files** \u2014 pass a glob pattern like "**/*.md". Returns an **array** of file path strings. Use directly with \`for (const f of listFiles("**/*.md"))\`.
|
|
@@ -83497,7 +83560,7 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
83497
83560
|
}
|
|
83498
83561
|
try {
|
|
83499
83562
|
const oldHistoryLength = this.history.length;
|
|
83500
|
-
if (this._outputBuffer && !options?._schemaFormatted) {
|
|
83563
|
+
if (this._outputBuffer && !options?._schemaFormatted && !options?._completionPromptProcessed) {
|
|
83501
83564
|
this._outputBuffer.items = [];
|
|
83502
83565
|
}
|
|
83503
83566
|
if (this.enableTasks) {
|
|
@@ -83942,8 +84005,20 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
83942
84005
|
completionAttempted = false;
|
|
83943
84006
|
continue;
|
|
83944
84007
|
}
|
|
83945
|
-
|
|
83946
|
-
if (
|
|
84008
|
+
const strippedContent = removeThinkingTags(prevContent);
|
|
84009
|
+
if (strippedContent.length > 50) {
|
|
84010
|
+
finalResult = strippedContent;
|
|
84011
|
+
if (this.debug) console.log(`[DEBUG] Using previous response (thinking-stripped) as completion: ${finalResult.substring(0, 100)}...`);
|
|
84012
|
+
} else {
|
|
84013
|
+
const thinkingContent = extractThinkingContent(prevContent);
|
|
84014
|
+
if (thinkingContent && thinkingContent.length > 50) {
|
|
84015
|
+
finalResult = thinkingContent;
|
|
84016
|
+
if (this.debug) console.log(`[DEBUG] Previous response was mostly in thinking tags \u2014 using thinking content as completion: ${finalResult.substring(0, 100)}...`);
|
|
84017
|
+
} else {
|
|
84018
|
+
finalResult = prevContent;
|
|
84019
|
+
if (this.debug) console.log(`[DEBUG] Using previous response as completion (raw): ${finalResult.substring(0, 100)}...`);
|
|
84020
|
+
}
|
|
84021
|
+
}
|
|
83947
84022
|
} else {
|
|
83948
84023
|
finalResult = "Error: No previous response found to use as completion.";
|
|
83949
84024
|
if (this.debug) console.log(`[DEBUG] No suitable previous response found for attempt_complete shorthand`);
|
|
@@ -84515,10 +84590,14 @@ ${finalResult}
|
|
|
84515
84590
|
</result>
|
|
84516
84591
|
|
|
84517
84592
|
After reviewing, provide your final answer using attempt_completion.`;
|
|
84593
|
+
const savedOutputItems = this._outputBuffer ? [...this._outputBuffer.items] : [];
|
|
84518
84594
|
const completionResult = await this.answer(completionPromptMessage, [], {
|
|
84519
84595
|
...options,
|
|
84520
84596
|
_completionPromptProcessed: true
|
|
84521
84597
|
});
|
|
84598
|
+
if (this._outputBuffer) {
|
|
84599
|
+
this._outputBuffer.items = savedOutputItems;
|
|
84600
|
+
}
|
|
84522
84601
|
finalResult = completionResult;
|
|
84523
84602
|
if (this.debug) {
|
|
84524
84603
|
console.log(`[DEBUG] Completion prompt finished. New result length: ${finalResult?.length || 0}`);
|
package/build/tools/common.js
CHANGED
|
@@ -13,10 +13,19 @@ export const searchSchema = z.object({
|
|
|
13
13
|
query: z.string().describe('Search query with Elasticsearch syntax. Use quotes for exact matches, AND/OR for boolean logic, - for negation.'),
|
|
14
14
|
path: z.string().optional().default('.').describe('Path to search in. For dependencies use "go:github.com/owner/repo", "js:package_name", or "rust:cargo_name" etc.'),
|
|
15
15
|
exact: z.boolean().optional().default(false).describe('Default (false) enables stemming and keyword splitting for exploratory search - "getUserData" matches "get", "user", "data", etc. Set true for precise symbol lookup where "getUserData" matches only "getUserData". Use true when you know the exact symbol name.'),
|
|
16
|
+
maxTokens: z.number().nullable().optional().describe('Maximum tokens to return. Default is 20000. Set to null for unlimited results.'),
|
|
16
17
|
session: z.string().optional().describe('Session ID for result caching and pagination. Pass the session ID from a previous search to get additional results (next page). Results already shown in a session are automatically excluded. Omit for a fresh search.'),
|
|
17
18
|
nextPage: z.boolean().optional().default(false).describe('Set to true when requesting the next page of results. Requires passing the same session ID from the previous search output.')
|
|
18
19
|
});
|
|
19
20
|
|
|
21
|
+
export const searchAllSchema = z.object({
|
|
22
|
+
query: z.string().describe('Search query with Elasticsearch syntax. Use quotes for exact matches, AND/OR for boolean logic, - for negation.'),
|
|
23
|
+
path: z.string().optional().default('.').describe('Path to search in.'),
|
|
24
|
+
exact: z.boolean().optional().default(false).describe('Use exact matching instead of stemming.'),
|
|
25
|
+
maxTokensPerPage: z.number().optional().default(20000).describe('Tokens per page when paginating. Default 20000.'),
|
|
26
|
+
maxPages: z.number().optional().default(50).describe('Maximum pages to retrieve. Default 50 (safety limit).')
|
|
27
|
+
});
|
|
28
|
+
|
|
20
29
|
export const querySchema = z.object({
|
|
21
30
|
pattern: z.string().describe('AST pattern to search for. Use $NAME for variable names, $$$PARAMS for parameter lists, etc.'),
|
|
22
31
|
path: z.string().optional().default('.').describe('Path to search in'),
|
|
@@ -85,6 +85,8 @@ function buildToolImplementations(configOptions) {
|
|
|
85
85
|
if (!searchPaths || searchPaths.length === 0) {
|
|
86
86
|
searchPaths = [cwd || '.'];
|
|
87
87
|
}
|
|
88
|
+
// Allow maxTokens to be passed through (null = unlimited, undefined = default 20000)
|
|
89
|
+
const maxTokens = params.maxTokens !== undefined ? params.maxTokens : 20000;
|
|
88
90
|
return await search({
|
|
89
91
|
query: params.query,
|
|
90
92
|
path: searchPaths.join(' '),
|
|
@@ -92,7 +94,7 @@ function buildToolImplementations(configOptions) {
|
|
|
92
94
|
allowTests: true,
|
|
93
95
|
exact: params.exact || false,
|
|
94
96
|
json: false,
|
|
95
|
-
maxTokens
|
|
97
|
+
maxTokens,
|
|
96
98
|
session: sessionId,
|
|
97
99
|
timeout: 60,
|
|
98
100
|
});
|
|
@@ -102,6 +104,70 @@ function buildToolImplementations(configOptions) {
|
|
|
102
104
|
},
|
|
103
105
|
};
|
|
104
106
|
|
|
107
|
+
// searchAll: auto-paginating search that retrieves ALL results
|
|
108
|
+
// Calls search() repeatedly with same sessionId until no more results
|
|
109
|
+
tools.searchAll = {
|
|
110
|
+
execute: async (params) => {
|
|
111
|
+
try {
|
|
112
|
+
let searchPaths;
|
|
113
|
+
if (params.path) {
|
|
114
|
+
searchPaths = parseAndResolvePaths(params.path, cwd);
|
|
115
|
+
}
|
|
116
|
+
if (!searchPaths || searchPaths.length === 0) {
|
|
117
|
+
searchPaths = [cwd || '.'];
|
|
118
|
+
}
|
|
119
|
+
const pathStr = searchPaths.join(' ');
|
|
120
|
+
const maxTokensPerPage = params.maxTokensPerPage || 20000;
|
|
121
|
+
const maxPages = params.maxPages || 50; // Safety limit
|
|
122
|
+
|
|
123
|
+
let allResults = '';
|
|
124
|
+
let pageCount = 0;
|
|
125
|
+
|
|
126
|
+
while (pageCount < maxPages) {
|
|
127
|
+
const pageResult = await search({
|
|
128
|
+
query: params.query,
|
|
129
|
+
path: pathStr,
|
|
130
|
+
cwd,
|
|
131
|
+
allowTests: true,
|
|
132
|
+
exact: params.exact || false,
|
|
133
|
+
json: false,
|
|
134
|
+
maxTokens: maxTokensPerPage,
|
|
135
|
+
session: sessionId,
|
|
136
|
+
timeout: 60,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
pageCount++;
|
|
140
|
+
|
|
141
|
+
// Check if we got results
|
|
142
|
+
if (!pageResult || pageResult.trim().length === 0) {
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Check for "All results retrieved" or "No results found" signals
|
|
147
|
+
if (pageResult.includes('All results retrieved') ||
|
|
148
|
+
pageResult.includes('No results found') ||
|
|
149
|
+
pageResult.includes('No matching code blocks found')) {
|
|
150
|
+
// Include this final page if it has content beyond the message
|
|
151
|
+
if (pageResult.trim().length > 50) {
|
|
152
|
+
allResults += (allResults ? '\n\n' : '') + pageResult;
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
allResults += (allResults ? '\n\n' : '') + pageResult;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (pageCount >= maxPages) {
|
|
161
|
+
allResults += `\n\n[Warning: Reached maximum page limit (${maxPages}). Some results may be omitted.]`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return allResults || 'No results found.';
|
|
165
|
+
} catch (e) {
|
|
166
|
+
return `SearchAll error: ${e.message}`;
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
|
|
105
171
|
tools.query = {
|
|
106
172
|
execute: async (params) => {
|
|
107
173
|
try {
|
|
@@ -345,7 +411,8 @@ ${lastError}
|
|
|
345
411
|
|
|
346
412
|
RULES REMINDER:
|
|
347
413
|
- search(query) is KEYWORD SEARCH — pass a search query, NOT a filename. Use extract(filepath) to read file contents.
|
|
348
|
-
- search()
|
|
414
|
+
- search() returns up to 20K tokens by default. Use search(query, path, {maxTokens: null}) for unlimited, or searchAll(query) to auto-paginate ALL results.
|
|
415
|
+
- search(), searchAll(), query(), extract(), listFiles(), bash() all return STRINGS, not arrays.
|
|
349
416
|
- Use chunk(stringData) to split a string into an array of chunks.
|
|
350
417
|
- Use map(array, fn) only with arrays. Do NOT pass strings to map().
|
|
351
418
|
- Do NOT use .map(), .forEach(), .filter(), .join() — use for..of loops instead.
|
|
@@ -684,7 +751,8 @@ return table;
|
|
|
684
751
|
${funcList}
|
|
685
752
|
|
|
686
753
|
**Return types — IMPORTANT:**
|
|
687
|
-
- \`search(query)\` → **keyword search** — pass a search query (e.g. "error handling"), NOT a filename. Returns a **string** (matching code snippets
|
|
754
|
+
- \`search(query)\` → **keyword search** — pass a search query (e.g. "error handling"), NOT a filename. Returns a **string** (matching code snippets, up to 20K tokens by default). Use \`{maxTokens: null}\` for unlimited.
|
|
755
|
+
- \`searchAll(query)\` → **exhaustive keyword search** — auto-paginates to retrieve ALL matching results. Returns a **string** (all matching code snippets concatenated). Use for bulk analysis.
|
|
688
756
|
- \`query(pattern)\` → **AST search** — pass a tree-sitter pattern. Returns a **string** (matching code elements).
|
|
689
757
|
- \`extract(targets)\` → **read file contents** — pass a file path like "src/main.js" or "src/main.js:42". Use this to read specific files found by listFiles(). Returns a **string**.
|
|
690
758
|
- \`listFiles(pattern)\` → **list files** — pass a glob pattern like "**/*.md". Returns an **array** of file path strings. Use directly with \`for (const f of listFiles("**/*.md"))\`.
|