@probelabs/probe 0.6.0-rc210 → 0.6.0-rc212

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.
Files changed (32) hide show
  1. package/bin/binaries/probe-v0.6.0-rc212-aarch64-apple-darwin.tar.gz +0 -0
  2. package/bin/binaries/probe-v0.6.0-rc212-aarch64-unknown-linux-musl.tar.gz +0 -0
  3. package/bin/binaries/probe-v0.6.0-rc212-x86_64-apple-darwin.tar.gz +0 -0
  4. package/bin/binaries/probe-v0.6.0-rc212-x86_64-pc-windows-msvc.zip +0 -0
  5. package/bin/binaries/probe-v0.6.0-rc212-x86_64-unknown-linux-musl.tar.gz +0 -0
  6. package/build/agent/ProbeAgent.js +19 -3
  7. package/build/agent/index.js +639 -75
  8. package/build/agent/probeTool.js +11 -2
  9. package/build/agent/tools.js +8 -0
  10. package/build/index.js +6 -1
  11. package/build/search.js +2 -2
  12. package/build/tools/analyzeAll.js +624 -0
  13. package/build/tools/common.js +149 -85
  14. package/build/tools/langchain.js +1 -1
  15. package/build/tools/vercel.js +61 -2
  16. package/cjs/agent/ProbeAgent.cjs +9698 -6756
  17. package/cjs/index.cjs +9702 -6754
  18. package/package.json +1 -1
  19. package/src/agent/ProbeAgent.js +19 -3
  20. package/src/agent/probeTool.js +11 -2
  21. package/src/agent/tools.js +8 -0
  22. package/src/index.js +6 -1
  23. package/src/search.js +2 -2
  24. package/src/tools/analyzeAll.js +624 -0
  25. package/src/tools/common.js +149 -85
  26. package/src/tools/langchain.js +1 -1
  27. package/src/tools/vercel.js +61 -2
  28. package/bin/binaries/probe-v0.6.0-rc210-aarch64-apple-darwin.tar.gz +0 -0
  29. package/bin/binaries/probe-v0.6.0-rc210-aarch64-unknown-linux-musl.tar.gz +0 -0
  30. package/bin/binaries/probe-v0.6.0-rc210-x86_64-apple-darwin.tar.gz +0 -0
  31. package/bin/binaries/probe-v0.6.0-rc210-x86_64-pc-windows-msvc.zip +0 -0
  32. package/bin/binaries/probe-v0.6.0-rc210-x86_64-unknown-linux-musl.tar.gz +0 -0
@@ -3346,8 +3346,8 @@ async function search(options) {
3346
3346
  }
3347
3347
  }
3348
3348
  if (!options.maxTokens) {
3349
- options.maxTokens = 1e4;
3350
- cliArgs.push("--max-tokens", "10000");
3349
+ options.maxTokens = 2e4;
3350
+ cliArgs.push("--max-tokens", "20000");
3351
3351
  }
3352
3352
  if (!options.timeout) {
3353
3353
  options.timeout = 30;
@@ -4032,6 +4032,447 @@ var init_delegate = __esm({
4032
4032
  }
4033
4033
  });
4034
4034
 
4035
+ // src/tools/analyzeAll.js
4036
+ function estimateTokens(text) {
4037
+ if (!text) return 0;
4038
+ return Math.ceil(text.length / CHARS_PER_TOKEN);
4039
+ }
4040
+ function stripResultTags(text) {
4041
+ if (!text) return text;
4042
+ return text.replace(/^<result>\s*/i, "").replace(/\s*<\/result>$/i, "").trim();
4043
+ }
4044
+ function parsePlanningResult(planningResult) {
4045
+ const result = {
4046
+ searchQuery: null,
4047
+ aggregation: "summarize",
4048
+ extractionPrompt: null,
4049
+ reasoning: null
4050
+ };
4051
+ const queryMatch = planningResult.match(/SEARCH_QUERY:\s*(.+?)(?=\n[A-Z_]+:|$)/s);
4052
+ if (queryMatch) {
4053
+ result.searchQuery = queryMatch[1].trim();
4054
+ }
4055
+ const aggMatch = planningResult.match(/AGGREGATION:\s*(summarize|list_unique|count|group_by)/i);
4056
+ if (aggMatch) {
4057
+ result.aggregation = aggMatch[1].toLowerCase();
4058
+ }
4059
+ const extractMatch = planningResult.match(/EXTRACTION_PROMPT:\s*(.+?)(?=\n[A-Z_]+:|$)/s);
4060
+ if (extractMatch) {
4061
+ result.extractionPrompt = extractMatch[1].trim();
4062
+ }
4063
+ const reasoningMatch = planningResult.match(/REASONING:\s*(.+?)$/s);
4064
+ if (reasoningMatch) {
4065
+ result.reasoning = reasoningMatch[1].trim();
4066
+ }
4067
+ return result;
4068
+ }
4069
+ function chunkResults(searchResults, chunkSizeTokens) {
4070
+ const chunks = [];
4071
+ const chunkSizeChars = chunkSizeTokens * CHARS_PER_TOKEN;
4072
+ const fileBlocks = searchResults.split(/(?=^```)/m);
4073
+ let currentChunk = "";
4074
+ let currentTokens = 0;
4075
+ for (const block of fileBlocks) {
4076
+ const blockTokens = estimateTokens(block);
4077
+ if (blockTokens > chunkSizeTokens && currentChunk.length > 0) {
4078
+ chunks.push({
4079
+ id: chunks.length + 1,
4080
+ total: 0,
4081
+ content: currentChunk.trim(),
4082
+ estimatedTokens: currentTokens
4083
+ });
4084
+ currentChunk = "";
4085
+ currentTokens = 0;
4086
+ }
4087
+ if (currentTokens + blockTokens > chunkSizeTokens && currentChunk.length > 0) {
4088
+ chunks.push({
4089
+ id: chunks.length + 1,
4090
+ total: 0,
4091
+ content: currentChunk.trim(),
4092
+ estimatedTokens: currentTokens
4093
+ });
4094
+ currentChunk = "";
4095
+ currentTokens = 0;
4096
+ }
4097
+ currentChunk += block;
4098
+ currentTokens += blockTokens;
4099
+ }
4100
+ if (currentChunk.trim().length > 0) {
4101
+ chunks.push({
4102
+ id: chunks.length + 1,
4103
+ total: 0,
4104
+ content: currentChunk.trim(),
4105
+ estimatedTokens: currentTokens
4106
+ });
4107
+ }
4108
+ const totalChunks = chunks.length;
4109
+ for (const chunk of chunks) {
4110
+ chunk.total = totalChunks;
4111
+ }
4112
+ return chunks;
4113
+ }
4114
+ async function processChunk(chunk, extractionPrompt, options) {
4115
+ const task = `You are analyzing search results (chunk ${chunk.id} of ${chunk.total}).
4116
+
4117
+ Your task: ${extractionPrompt}
4118
+
4119
+ Search Results:
4120
+ ${chunk.content}
4121
+
4122
+ Instructions:
4123
+ - Extract ALL relevant information matching the analysis task
4124
+ - Be specific and include actual names, values, patterns found
4125
+ - Format as a structured list if multiple items found
4126
+ - If nothing relevant is found in this chunk, respond with "No relevant items found in this chunk."
4127
+ - Do NOT summarize the code - extract the specific information requested
4128
+ - IMPORTANT: When completing, always use the FULL format: <attempt_completion><result>YOUR ANSWER HERE</result></attempt_completion>
4129
+ - Do NOT use the shorthand <attempt_complete></attempt_complete> format`;
4130
+ try {
4131
+ const result = await delegate({
4132
+ task,
4133
+ debug: options.debug,
4134
+ parentSessionId: options.sessionId,
4135
+ path: options.path,
4136
+ allowedFolders: options.allowedFolders,
4137
+ provider: options.provider,
4138
+ model: options.model,
4139
+ tracer: options.tracer,
4140
+ enableBash: false,
4141
+ promptType: "code-researcher",
4142
+ allowedTools: ["extract"],
4143
+ maxIterations: 5,
4144
+ timeout: 120
4145
+ });
4146
+ return { chunk, result };
4147
+ } catch (error) {
4148
+ return { chunk, result: `Error processing chunk ${chunk.id}: ${error.message}` };
4149
+ }
4150
+ }
4151
+ async function processChunksParallel(chunks, extractionPrompt, maxWorkers, options) {
4152
+ const results = [];
4153
+ const queue = [...chunks];
4154
+ const active = /* @__PURE__ */ new Set();
4155
+ while (queue.length > 0 || active.size > 0) {
4156
+ while (active.size < maxWorkers && queue.length > 0) {
4157
+ const chunk = queue.shift();
4158
+ const promise = processChunk(chunk, extractionPrompt, options).then((result) => {
4159
+ active.delete(promise);
4160
+ return result;
4161
+ });
4162
+ active.add(promise);
4163
+ if (options.debug) {
4164
+ console.error(`[analyze_all] Started processing chunk ${chunk.id}/${chunk.total}`);
4165
+ }
4166
+ }
4167
+ if (active.size > 0) {
4168
+ const result = await Promise.race(active);
4169
+ results.push(result);
4170
+ if (options.debug) {
4171
+ console.error(`[analyze_all] Completed chunk ${result.chunk.id}/${result.chunk.total}`);
4172
+ }
4173
+ }
4174
+ }
4175
+ results.sort((a, b) => a.chunk.id - b.chunk.id);
4176
+ return results;
4177
+ }
4178
+ async function aggregateResults(chunkResults2, aggregation, extractionPrompt, options) {
4179
+ const meaningfulResults = chunkResults2.filter(
4180
+ (r) => r.result && !r.result.toLowerCase().includes("no relevant items found") && r.result.trim().length > 0
4181
+ );
4182
+ if (meaningfulResults.length === 0) {
4183
+ return "No relevant information found across all chunks.";
4184
+ }
4185
+ if (meaningfulResults.length === 1) {
4186
+ return stripResultTags(meaningfulResults[0].result);
4187
+ }
4188
+ const chunkSummaries = meaningfulResults.map((r) => `--- Chunk ${r.chunk.id} ---
4189
+ ${stripResultTags(r.result)}`).join("\n\n");
4190
+ const completionNote = `
4191
+
4192
+ IMPORTANT: When completing, always use the FULL format: <attempt_completion><result>YOUR ANSWER HERE</result></attempt_completion>`;
4193
+ const aggregationPrompts = {
4194
+ summarize: `Synthesize these analyses into a comprehensive summary. Combine related findings, remove redundancy, and present a coherent overview.
4195
+
4196
+ Original task: ${extractionPrompt}
4197
+
4198
+ Chunk analyses:
4199
+ ${chunkSummaries}
4200
+
4201
+ Provide a unified summary that captures all key findings.${completionNote}`,
4202
+ list_unique: `Combine these lists and remove duplicates. Create a single deduplicated list of all unique items found.
4203
+
4204
+ Original task: ${extractionPrompt}
4205
+
4206
+ Chunk analyses:
4207
+ ${chunkSummaries}
4208
+
4209
+ Return a deduplicated, organized list of all unique items. Group related items if helpful.${completionNote}`,
4210
+ count: `Count and aggregate the findings from these analyses. Provide total counts and breakdowns.
4211
+
4212
+ Original task: ${extractionPrompt}
4213
+
4214
+ Chunk analyses:
4215
+ ${chunkSummaries}
4216
+
4217
+ Provide accurate counts and a summary of all occurrences found.${completionNote}`,
4218
+ group_by: `Group and categorize all items from these analyses. Organize findings into logical categories.
4219
+
4220
+ Original task: ${extractionPrompt}
4221
+
4222
+ Chunk analyses:
4223
+ ${chunkSummaries}
4224
+
4225
+ Organize all findings into clear categories with items listed under each.${completionNote}`
4226
+ };
4227
+ const aggregationTask = aggregationPrompts[aggregation] || aggregationPrompts.summarize;
4228
+ try {
4229
+ const result = await delegate({
4230
+ task: aggregationTask,
4231
+ debug: options.debug,
4232
+ parentSessionId: options.sessionId,
4233
+ path: options.path,
4234
+ allowedFolders: options.allowedFolders,
4235
+ provider: options.provider,
4236
+ model: options.model,
4237
+ tracer: options.tracer,
4238
+ enableBash: false,
4239
+ promptType: "code-researcher",
4240
+ allowedTools: [],
4241
+ maxIterations: 5,
4242
+ timeout: 120
4243
+ });
4244
+ return result;
4245
+ } catch (error) {
4246
+ return `Aggregation failed (${error.message}). Raw results:
4247
+
4248
+ ${chunkSummaries}`;
4249
+ }
4250
+ }
4251
+ async function planAnalysis(question, path9, options) {
4252
+ if (options.debug) {
4253
+ console.error(`[analyze_all] Phase 1: Planning analysis strategy...`);
4254
+ }
4255
+ const planningTask = `Create an analysis plan for this question about a codebase:
4256
+
4257
+ "${question}"
4258
+
4259
+ Search scope: ${path9}
4260
+
4261
+ Use attempt_completion to output your plan in this EXACT format:
4262
+
4263
+ SEARCH_QUERY: <elasticsearch query using OR for multiple terms, quotes for exact phrases>
4264
+ AGGREGATION: <summarize | list_unique | count | group_by>
4265
+ EXTRACTION_PROMPT: <what to extract from each search result>
4266
+ REASONING: <brief explanation>
4267
+
4268
+ Example plan:
4269
+ SEARCH_QUERY: export OR function OR class OR tool
4270
+ AGGREGATION: list_unique
4271
+ EXTRACTION_PROMPT: Extract tool names and their purpose
4272
+ REASONING: Using list_unique to deduplicate tool definitions
4273
+
4274
+ IMPORTANT: Use attempt_completion immediately with your plan. Do NOT try to search or answer the question - just create the analysis plan.`;
4275
+ try {
4276
+ const result = await delegate({
4277
+ task: planningTask,
4278
+ debug: options.debug,
4279
+ parentSessionId: options.sessionId,
4280
+ path: path9,
4281
+ allowedFolders: [path9],
4282
+ provider: options.provider,
4283
+ model: options.model,
4284
+ tracer: options.tracer,
4285
+ enableBash: false,
4286
+ promptType: "code-researcher",
4287
+ allowedTools: [],
4288
+ // attempt_completion only (default tool)
4289
+ maxIterations: 3,
4290
+ timeout: 60
4291
+ });
4292
+ const plan = parsePlanningResult(stripResultTags(result));
4293
+ if (options.debug) {
4294
+ console.error(`[analyze_all] Planning complete:`);
4295
+ console.error(`[analyze_all] Search Query: ${plan.searchQuery}`);
4296
+ console.error(`[analyze_all] Aggregation: ${plan.aggregation}`);
4297
+ console.error(`[analyze_all] Extraction: ${plan.extractionPrompt?.substring(0, 100)}...`);
4298
+ }
4299
+ return plan;
4300
+ } catch (error) {
4301
+ throw new Error(`Planning phase failed: ${error.message}`);
4302
+ }
4303
+ }
4304
+ async function synthesizeAnswer(question, aggregatedData, plan, options) {
4305
+ if (options.debug) {
4306
+ console.error(`[analyze_all] Phase 3: Synthesizing final answer...`);
4307
+ }
4308
+ const synthesisTask = `You analyzed a codebase to answer this question:
4309
+
4310
+ "${question}"
4311
+
4312
+ Analysis Strategy Used:
4313
+ - Search Query: ${plan.searchQuery}
4314
+ - Aggregation Method: ${plan.aggregation}
4315
+ - Extraction Focus: ${plan.extractionPrompt}
4316
+
4317
+ Aggregated Analysis Results:
4318
+ ${aggregatedData}
4319
+
4320
+ Now provide a COMPREHENSIVE, DETAILED answer to the original question.
4321
+
4322
+ Your answer should:
4323
+ 1. **Directly answer the question** with a clear summary at the top
4324
+ 2. **Provide specific evidence** - include actual names, values, file locations where relevant
4325
+ 3. **Organize the information** logically (use categories, lists, or sections as appropriate)
4326
+ 4. **Note completeness** - mention if the analysis covered all relevant data or if there might be gaps
4327
+ 5. **Be thorough** - this is the final answer the user will see, make it complete and useful
4328
+
4329
+ Format your response as a well-structured document that fully answers: "${question}"
4330
+
4331
+ IMPORTANT: When completing, use the FULL format: <attempt_completion><result>YOUR ANSWER HERE</result></attempt_completion>`;
4332
+ try {
4333
+ const result = await delegate({
4334
+ task: synthesisTask,
4335
+ debug: options.debug,
4336
+ parentSessionId: options.sessionId,
4337
+ path: options.path,
4338
+ allowedFolders: options.allowedFolders,
4339
+ provider: options.provider,
4340
+ model: options.model,
4341
+ tracer: options.tracer,
4342
+ enableBash: false,
4343
+ promptType: "code-researcher",
4344
+ allowedTools: [],
4345
+ maxIterations: 5,
4346
+ timeout: 180
4347
+ });
4348
+ return stripResultTags(result);
4349
+ } catch (error) {
4350
+ return `Analysis Results for: "${question}"
4351
+
4352
+ ${aggregatedData}`;
4353
+ }
4354
+ }
4355
+ async function analyzeAll(options) {
4356
+ const {
4357
+ question,
4358
+ path: path9 = ".",
4359
+ sessionId,
4360
+ debug = false,
4361
+ cwd,
4362
+ allowedFolders,
4363
+ provider,
4364
+ model,
4365
+ tracer,
4366
+ chunkSizeTokens = DEFAULT_CHUNK_SIZE_TOKENS,
4367
+ maxChunks = MAX_CHUNKS
4368
+ } = options;
4369
+ if (!question) {
4370
+ throw new Error('The "question" parameter is required.');
4371
+ }
4372
+ const delegateOptions = {
4373
+ debug,
4374
+ sessionId,
4375
+ path: allowedFolders?.[0] || cwd || path9,
4376
+ allowedFolders,
4377
+ provider,
4378
+ model,
4379
+ tracer
4380
+ };
4381
+ if (debug) {
4382
+ console.error(`[analyze_all] Starting analysis`);
4383
+ console.error(`[analyze_all] Question: ${question}`);
4384
+ console.error(`[analyze_all] Path: ${path9}`);
4385
+ }
4386
+ const plan = await planAnalysis(question, path9, delegateOptions);
4387
+ if (!plan.searchQuery) {
4388
+ throw new Error("Planning phase failed to determine a search query.");
4389
+ }
4390
+ if (!plan.extractionPrompt) {
4391
+ throw new Error("Planning phase failed to determine an extraction prompt.");
4392
+ }
4393
+ if (debug) {
4394
+ console.error(`[analyze_all] Phase 2: Processing data with map-reduce...`);
4395
+ }
4396
+ const searchResults = await search({
4397
+ query: plan.searchQuery,
4398
+ path: path9,
4399
+ cwd,
4400
+ maxTokens: null,
4401
+ allowTests: true,
4402
+ session: sessionId
4403
+ });
4404
+ if (!searchResults || searchResults.trim().length === 0) {
4405
+ return `No data found matching the analysis plan for: "${question}"
4406
+
4407
+ Search query used: ${plan.searchQuery}
4408
+
4409
+ Try rephrasing your question or broadening the scope.`;
4410
+ }
4411
+ const totalTokens = estimateTokens(searchResults);
4412
+ if (debug) {
4413
+ console.error(`[analyze_all] Total search results: ~${totalTokens} tokens`);
4414
+ }
4415
+ let aggregatedData;
4416
+ if (totalTokens <= chunkSizeTokens) {
4417
+ if (debug) {
4418
+ console.error(`[analyze_all] Results fit in single chunk, processing directly`);
4419
+ }
4420
+ const singleChunk = {
4421
+ id: 1,
4422
+ total: 1,
4423
+ content: searchResults,
4424
+ estimatedTokens: totalTokens
4425
+ };
4426
+ const result = await processChunk(singleChunk, plan.extractionPrompt, delegateOptions);
4427
+ aggregatedData = stripResultTags(result.result);
4428
+ } else {
4429
+ const chunks = chunkResults(searchResults, chunkSizeTokens);
4430
+ if (debug) {
4431
+ console.error(`[analyze_all] Split into ${chunks.length} chunks`);
4432
+ }
4433
+ if (chunks.length > maxChunks) {
4434
+ console.error(`[analyze_all] Warning: Truncating from ${chunks.length} to ${maxChunks} chunks`);
4435
+ chunks.length = maxChunks;
4436
+ for (const chunk of chunks) {
4437
+ chunk.total = maxChunks;
4438
+ }
4439
+ }
4440
+ const chunkResultsProcessed = await processChunksParallel(
4441
+ chunks,
4442
+ plan.extractionPrompt,
4443
+ MAX_PARALLEL_WORKERS,
4444
+ delegateOptions
4445
+ );
4446
+ if (debug) {
4447
+ console.error(`[analyze_all] All ${chunks.length} chunks processed, starting aggregation`);
4448
+ }
4449
+ aggregatedData = await aggregateResults(
4450
+ chunkResultsProcessed,
4451
+ plan.aggregation,
4452
+ plan.extractionPrompt,
4453
+ delegateOptions
4454
+ );
4455
+ aggregatedData = stripResultTags(aggregatedData);
4456
+ }
4457
+ const finalAnswer = await synthesizeAnswer(question, aggregatedData, plan, delegateOptions);
4458
+ if (debug) {
4459
+ console.error(`[analyze_all] Analysis complete`);
4460
+ }
4461
+ return finalAnswer;
4462
+ }
4463
+ var DEFAULT_CHUNK_SIZE_TOKENS, MAX_PARALLEL_WORKERS, MAX_CHUNKS, CHARS_PER_TOKEN;
4464
+ var init_analyzeAll = __esm({
4465
+ "src/tools/analyzeAll.js"() {
4466
+ "use strict";
4467
+ init_search();
4468
+ init_delegate();
4469
+ DEFAULT_CHUNK_SIZE_TOKENS = 8e3;
4470
+ MAX_PARALLEL_WORKERS = 3;
4471
+ MAX_CHUNKS = 50;
4472
+ CHARS_PER_TOKEN = 4;
4473
+ }
4474
+ });
4475
+
4035
4476
  // node_modules/zod/v3/helpers/util.js
4036
4477
  var util, objectUtil, ZodParsedType, getParsedType;
4037
4478
  var init_util2 = __esm({
@@ -8904,6 +9345,7 @@ function getValidParamsForTool(toolName) {
8904
9345
  query: querySchema,
8905
9346
  extract: extractSchema,
8906
9347
  delegate: delegateSchema,
9348
+ analyze_all: analyzeAllSchema,
8907
9349
  listSkills: listSkillsSchema,
8908
9350
  useSkill: useSkillSchema,
8909
9351
  bash: bashSchema,
@@ -8928,76 +9370,84 @@ function getValidParamsForTool(toolName) {
8928
9370
  return [];
8929
9371
  }
8930
9372
  function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
8931
- for (const toolName of validTools) {
8932
- const openTag = `<${toolName}>`;
8933
- const closeTag = `</${toolName}>`;
8934
- const openIndex = xmlString.indexOf(openTag);
8935
- if (openIndex === -1) {
8936
- continue;
9373
+ let earliestToolName = null;
9374
+ let earliestOpenIndex = Infinity;
9375
+ for (const toolName2 of validTools) {
9376
+ const openTag2 = `<${toolName2}>`;
9377
+ const openIndex2 = xmlString.indexOf(openTag2);
9378
+ if (openIndex2 !== -1 && openIndex2 < earliestOpenIndex) {
9379
+ earliestOpenIndex = openIndex2;
9380
+ earliestToolName = toolName2;
8937
9381
  }
8938
- let closeIndex;
8939
- if (toolName === "attempt_completion") {
8940
- closeIndex = xmlString.lastIndexOf(closeTag);
8941
- if (closeIndex !== -1 && closeIndex <= openIndex + openTag.length) {
8942
- closeIndex = -1;
8943
- }
8944
- } else {
8945
- closeIndex = xmlString.indexOf(closeTag, openIndex + openTag.length);
9382
+ }
9383
+ if (earliestToolName === null) {
9384
+ return null;
9385
+ }
9386
+ const toolName = earliestToolName;
9387
+ const openTag = `<${toolName}>`;
9388
+ const closeTag = `</${toolName}>`;
9389
+ const openIndex = earliestOpenIndex;
9390
+ let closeIndex;
9391
+ if (toolName === "attempt_completion") {
9392
+ closeIndex = xmlString.lastIndexOf(closeTag);
9393
+ if (closeIndex !== -1 && closeIndex <= openIndex + openTag.length) {
9394
+ closeIndex = -1;
8946
9395
  }
8947
- let hasClosingTag = closeIndex !== -1;
8948
- if (closeIndex === -1) {
8949
- closeIndex = xmlString.length;
9396
+ } else {
9397
+ closeIndex = xmlString.indexOf(closeTag, openIndex + openTag.length);
9398
+ }
9399
+ let hasClosingTag = closeIndex !== -1;
9400
+ if (closeIndex === -1) {
9401
+ closeIndex = xmlString.length;
9402
+ }
9403
+ const innerContent = xmlString.substring(
9404
+ openIndex + openTag.length,
9405
+ closeIndex
9406
+ );
9407
+ const params = {};
9408
+ const validParams = getValidParamsForTool(toolName);
9409
+ for (const paramName of validParams) {
9410
+ const paramOpenTag = `<${paramName}>`;
9411
+ const paramCloseTag = `</${paramName}>`;
9412
+ const paramOpenIndex = innerContent.indexOf(paramOpenTag);
9413
+ if (paramOpenIndex === -1) {
9414
+ continue;
8950
9415
  }
8951
- const innerContent = xmlString.substring(
8952
- openIndex + openTag.length,
8953
- closeIndex
8954
- );
8955
- const params = {};
8956
- const validParams = getValidParamsForTool(toolName);
8957
- for (const paramName of validParams) {
8958
- const paramOpenTag = `<${paramName}>`;
8959
- const paramCloseTag = `</${paramName}>`;
8960
- const paramOpenIndex = innerContent.indexOf(paramOpenTag);
8961
- if (paramOpenIndex === -1) {
8962
- continue;
8963
- }
8964
- let paramCloseIndex = innerContent.indexOf(paramCloseTag, paramOpenIndex + paramOpenTag.length);
8965
- if (paramCloseIndex === -1) {
8966
- let nextTagIndex = innerContent.length;
8967
- for (const nextParam of validParams) {
8968
- const nextOpenTag = `<${nextParam}>`;
8969
- const nextIndex = innerContent.indexOf(nextOpenTag, paramOpenIndex + paramOpenTag.length);
8970
- if (nextIndex !== -1 && nextIndex < nextTagIndex) {
8971
- nextTagIndex = nextIndex;
8972
- }
8973
- }
8974
- paramCloseIndex = nextTagIndex;
8975
- }
8976
- let paramValue = innerContent.substring(
8977
- paramOpenIndex + paramOpenTag.length,
8978
- paramCloseIndex
8979
- ).trim();
8980
- if (paramValue.toLowerCase() === "true") {
8981
- paramValue = true;
8982
- } else if (paramValue.toLowerCase() === "false") {
8983
- paramValue = false;
8984
- } else if (!isNaN(paramValue) && paramValue.trim() !== "") {
8985
- const num = Number(paramValue);
8986
- if (Number.isFinite(num)) {
8987
- paramValue = num;
9416
+ let paramCloseIndex = innerContent.indexOf(paramCloseTag, paramOpenIndex + paramOpenTag.length);
9417
+ if (paramCloseIndex === -1) {
9418
+ let nextTagIndex = innerContent.length;
9419
+ for (const nextParam of validParams) {
9420
+ const nextOpenTag = `<${nextParam}>`;
9421
+ const nextIndex = innerContent.indexOf(nextOpenTag, paramOpenIndex + paramOpenTag.length);
9422
+ if (nextIndex !== -1 && nextIndex < nextTagIndex) {
9423
+ nextTagIndex = nextIndex;
8988
9424
  }
8989
9425
  }
8990
- params[paramName] = paramValue;
9426
+ paramCloseIndex = nextTagIndex;
8991
9427
  }
8992
- if (toolName === "attempt_completion") {
8993
- params["result"] = innerContent.trim();
8994
- if (params.command) {
8995
- delete params.command;
9428
+ let paramValue = innerContent.substring(
9429
+ paramOpenIndex + paramOpenTag.length,
9430
+ paramCloseIndex
9431
+ ).trim();
9432
+ if (paramValue.toLowerCase() === "true") {
9433
+ paramValue = true;
9434
+ } else if (paramValue.toLowerCase() === "false") {
9435
+ paramValue = false;
9436
+ } else if (!isNaN(paramValue) && paramValue.trim() !== "") {
9437
+ const num = Number(paramValue);
9438
+ if (Number.isFinite(num)) {
9439
+ paramValue = num;
8996
9440
  }
8997
9441
  }
8998
- return { toolName, params };
9442
+ params[paramName] = paramValue;
8999
9443
  }
9000
- return null;
9444
+ if (toolName === "attempt_completion") {
9445
+ params["result"] = innerContent.trim();
9446
+ if (params.command) {
9447
+ delete params.command;
9448
+ }
9449
+ }
9450
+ return { toolName, params };
9001
9451
  }
9002
9452
  function createMessagePreview(message, charsPerSide = 200) {
9003
9453
  if (message === null || message === void 0) {
@@ -9122,7 +9572,7 @@ function resolveTargetPath(target, cwd) {
9122
9572
  }
9123
9573
  return filePart + suffix;
9124
9574
  }
9125
- var searchSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, bashToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, DEFAULT_VALID_TOOLS;
9575
+ var searchSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, bashSchema, analyzeAllSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, analyzeAllToolDefinition, bashToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription, DEFAULT_VALID_TOOLS;
9126
9576
  var init_common = __esm({
9127
9577
  "src/tools/common.js"() {
9128
9578
  "use strict";
@@ -9159,6 +9609,10 @@ var init_common = __esm({
9159
9609
  timeout: external_exports.number().optional().describe("Command timeout in milliseconds (optional)"),
9160
9610
  env: external_exports.record(external_exports.string()).optional().describe("Additional environment variables (optional)")
9161
9611
  });
9612
+ analyzeAllSchema = external_exports.object({
9613
+ question: external_exports.string().min(1).describe('Free-form question to answer (e.g., "What features are customers using?", "List all API endpoints"). The AI will automatically plan the search strategy, process all matching data, and synthesize a comprehensive answer.'),
9614
+ path: external_exports.string().optional().default(".").describe("Directory path to search in")
9615
+ });
9162
9616
  attemptCompletionSchema = {
9163
9617
  // Custom validation that requires result parameter but allows direct XML response
9164
9618
  safeParse: (params) => {
@@ -9368,6 +9822,51 @@ Usage Example:
9368
9822
  <attempt_completion>
9369
9823
  I have refactored the search module according to the requirements and verified the tests pass. The module now uses the new BM25 ranking algorithm and has improved error handling.
9370
9824
  </attempt_completion>
9825
+ `;
9826
+ analyzeAllToolDefinition = `
9827
+ ## analyze_all
9828
+ Description: Intelligent bulk data analysis tool. Process ALL data matching your question using a 3-phase approach:
9829
+ 1. **PLANNING**: AI analyzes your question and determines the optimal search strategy
9830
+ 2. **PROCESSING**: Map-reduce processes all matching data in parallel chunks
9831
+ 3. **SYNTHESIS**: Comprehensive answer with evidence and organization
9832
+
9833
+ **Use this for questions requiring 100% data coverage:**
9834
+ - "What features are customers using?"
9835
+ - "List all API endpoints in the codebase"
9836
+ - "Summarize the error handling patterns"
9837
+ - "Count all TODO comments and their contexts"
9838
+
9839
+ **Do NOT use for:**
9840
+ - Simple searches where a sample is sufficient
9841
+ - Finding a specific function or class
9842
+ - Quick exploration (use search instead)
9843
+
9844
+ **WARNING:** Makes multiple LLM calls - slower and costlier than search.
9845
+
9846
+ Parameters:
9847
+ - question: (required) Free-form question to answer - the AI determines the best search strategy automatically
9848
+ - path: (optional) Directory to search in (default: current directory)
9849
+
9850
+ <examples>
9851
+
9852
+ User: What are all the different tools available in this codebase?
9853
+ <analyze_all>
9854
+ <question>What are all the different tools available in this codebase and what do they do?</question>
9855
+ <path>./src</path>
9856
+ </analyze_all>
9857
+
9858
+ User: I need to understand all the error handling patterns
9859
+ <analyze_all>
9860
+ <question>What error handling patterns are used throughout the codebase? Include examples.</question>
9861
+ </analyze_all>
9862
+
9863
+ User: Count and categorize all the environment variables
9864
+ <analyze_all>
9865
+ <question>What environment variables are used? Categorize them by purpose.</question>
9866
+ <path>./src</path>
9867
+ </analyze_all>
9868
+
9869
+ </examples>
9371
9870
  `;
9372
9871
  bashToolDefinition = `
9373
9872
  ## bash
@@ -9428,11 +9927,13 @@ User: Check system info
9428
9927
  queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
9429
9928
  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.";
9430
9929
  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.";
9930
+ 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.';
9431
9931
  DEFAULT_VALID_TOOLS = [
9432
9932
  "search",
9433
9933
  "query",
9434
9934
  "extract",
9435
9935
  "delegate",
9936
+ "analyze_all",
9436
9937
  "listSkills",
9437
9938
  "useSkill",
9438
9939
  "listFiles",
@@ -9550,7 +10051,7 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
9550
10051
  "Deduplicate targets. Do NOT explain or answer - ONLY return the JSON targets."
9551
10052
  ].join("\n");
9552
10053
  }
9553
- var CODE_SEARCH_SCHEMA, searchTool, queryTool, extractTool, delegateTool;
10054
+ var CODE_SEARCH_SCHEMA, searchTool, queryTool, extractTool, delegateTool, analyzeAllTool;
9554
10055
  var init_vercel = __esm({
9555
10056
  "src/tools/vercel.js"() {
9556
10057
  "use strict";
@@ -9558,6 +10059,7 @@ var init_vercel = __esm({
9558
10059
  init_query();
9559
10060
  init_extract();
9560
10061
  init_delegate();
10062
+ init_analyzeAll();
9561
10063
  init_common();
9562
10064
  init_error_types();
9563
10065
  CODE_SEARCH_SCHEMA = {
@@ -9575,7 +10077,7 @@ var init_vercel = __esm({
9575
10077
  searchTool = (options = {}) => {
9576
10078
  const {
9577
10079
  sessionId,
9578
- maxTokens = 1e4,
10080
+ maxTokens = 2e4,
9579
10081
  debug = false,
9580
10082
  outline = false,
9581
10083
  searchDelegate = false
@@ -9868,6 +10370,45 @@ var init_vercel = __esm({
9868
10370
  }
9869
10371
  });
9870
10372
  };
10373
+ analyzeAllTool = (options = {}) => {
10374
+ const { sessionId, debug = false } = options;
10375
+ return tool2({
10376
+ name: "analyze_all",
10377
+ description: analyzeAllDescription,
10378
+ inputSchema: analyzeAllSchema,
10379
+ execute: async ({ question, path: path9 }) => {
10380
+ try {
10381
+ let searchPath = path9 || ".";
10382
+ if (path9 && options.cwd) {
10383
+ const resolvedPaths = parseAndResolvePaths(path9, options.cwd);
10384
+ if (resolvedPaths.length > 0) {
10385
+ searchPath = resolvedPaths[0];
10386
+ }
10387
+ }
10388
+ if (debug) {
10389
+ console.error(`[analyze_all] Starting analysis`);
10390
+ console.error(`[analyze_all] Question: ${question}`);
10391
+ console.error(`[analyze_all] Path: ${searchPath}`);
10392
+ }
10393
+ const result = await analyzeAll({
10394
+ question,
10395
+ path: searchPath,
10396
+ sessionId,
10397
+ debug,
10398
+ cwd: options.cwd,
10399
+ allowedFolders: options.allowedFolders,
10400
+ provider: options.provider,
10401
+ model: options.model,
10402
+ tracer: options.tracer
10403
+ });
10404
+ return result;
10405
+ } catch (error) {
10406
+ console.error("Error executing analyze_all:", error);
10407
+ return formatErrorForAI(error);
10408
+ }
10409
+ }
10410
+ });
10411
+ };
9871
10412
  }
9872
10413
  });
9873
10414
 
@@ -18777,6 +19318,13 @@ function createWrappedTools(baseTools) {
18777
19318
  baseTools.delegateTool.execute
18778
19319
  );
18779
19320
  }
19321
+ if (baseTools.analyzeAllTool) {
19322
+ wrappedTools.analyzeAllToolInstance = wrapToolWithEmitter(
19323
+ baseTools.analyzeAllTool,
19324
+ "analyze_all",
19325
+ baseTools.analyzeAllTool.execute
19326
+ );
19327
+ }
18780
19328
  if (baseTools.bashTool) {
18781
19329
  wrappedTools.bashToolInstance = wrapToolWithEmitter(
18782
19330
  baseTools.bashTool,
@@ -19683,6 +20231,9 @@ function createTools(configOptions) {
19683
20231
  if (configOptions.enableDelegate && isToolAllowed("delegate")) {
19684
20232
  tools2.delegateTool = delegateTool(configOptions);
19685
20233
  }
20234
+ if (isToolAllowed("analyze_all")) {
20235
+ tools2.analyzeAllTool = analyzeAllTool(configOptions);
20236
+ }
19686
20237
  if (configOptions.enableBash && isToolAllowed("bash")) {
19687
20238
  tools2.bashTool = bashTool(configOptions);
19688
20239
  }
@@ -67605,14 +68156,14 @@ function calculateCompactionStats(originalMessages, compactedMessages) {
67605
68156
  const compactedCount = compactedMessages.length;
67606
68157
  const removed = originalCount - compactedCount;
67607
68158
  const reductionPercent = originalCount > 0 ? (removed / originalCount * 100).toFixed(1) : 0;
67608
- const estimateTokens = (msgs) => {
68159
+ const estimateTokens2 = (msgs) => {
67609
68160
  return msgs.reduce((sum, msg) => {
67610
68161
  const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
67611
68162
  return sum + Math.ceil(content.length / 4);
67612
68163
  }, 0);
67613
68164
  };
67614
- const originalTokens = estimateTokens(originalMessages);
67615
- const compactedTokens = estimateTokens(compactedMessages);
68165
+ const originalTokens = estimateTokens2(originalMessages);
68166
+ const compactedTokens = estimateTokens2(compactedMessages);
67616
68167
  const tokensSaved = originalTokens - compactedTokens;
67617
68168
  return {
67618
68169
  originalCount,
@@ -67693,7 +68244,7 @@ async function truncateIfNeeded(content, tokenCounter, sessionId, maxTokens) {
67693
68244
  if (tokenCount <= limit) {
67694
68245
  return { truncated: false, content };
67695
68246
  }
67696
- const maxChars = limit * CHARS_PER_TOKEN;
68247
+ const maxChars = limit * CHARS_PER_TOKEN2;
67697
68248
  const truncatedContent = content.substring(0, maxChars);
67698
68249
  let tempFilePath = null;
67699
68250
  let fileError = null;
@@ -67732,12 +68283,12 @@ ${truncatedContent}
67732
68283
  error: fileError || void 0
67733
68284
  };
67734
68285
  }
67735
- var DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN;
68286
+ var DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN2;
67736
68287
  var init_outputTruncator = __esm({
67737
68288
  "src/agent/outputTruncator.js"() {
67738
68289
  "use strict";
67739
68290
  DEFAULT_MAX_OUTPUT_TOKENS = 2e4;
67740
- CHARS_PER_TOKEN = 4;
68291
+ CHARS_PER_TOKEN2 = 4;
67741
68292
  }
67742
68293
  });
67743
68294
 
@@ -69597,6 +70148,9 @@ var init_ProbeAgent = __esm({
69597
70148
  if (this.enableDelegate && wrappedTools.delegateToolInstance && isToolAllowed("delegate")) {
69598
70149
  this.toolImplementations.delegate = wrappedTools.delegateToolInstance;
69599
70150
  }
70151
+ if (wrappedTools.analyzeAllToolInstance && isToolAllowed("analyze_all")) {
70152
+ this.toolImplementations.analyze_all = wrappedTools.analyzeAllToolInstance;
70153
+ }
69600
70154
  if (isToolAllowed("listFiles")) {
69601
70155
  this.toolImplementations.listFiles = listFilesToolInstance;
69602
70156
  }
@@ -70796,6 +71350,10 @@ Workspace: ${this.allowedFolders.join(", ")}`;
70796
71350
  }
70797
71351
  if (this.enableDelegate && isToolAllowed("delegate")) {
70798
71352
  toolDefinitions += `${delegateToolDefinition}
71353
+ `;
71354
+ }
71355
+ if (isToolAllowed("analyze_all")) {
71356
+ toolDefinitions += `${analyzeAllToolDefinition}
70799
71357
  `;
70800
71358
  }
70801
71359
  let toolExamples = "";
@@ -70859,6 +71417,9 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
70859
71417
  if (this.enableDelegate && isToolAllowed("delegate")) {
70860
71418
  availableToolsList += "- delegate: Delegate big distinct tasks to specialized probe subagents.\n";
70861
71419
  }
71420
+ if (isToolAllowed("analyze_all")) {
71421
+ availableToolsList += "- analyze_all: Process ALL data matching a query using map-reduce (for aggregate questions needing 100% coverage).\n";
71422
+ }
70862
71423
  if (this.enableBash && isToolAllowed("bash")) {
70863
71424
  availableToolsList += "- bash: Execute bash commands for system operations.\n";
70864
71425
  }
@@ -71285,11 +71846,11 @@ You are working with a repository located at: ${searchDirectory}
71285
71846
  let maxResponseTokens = this.maxResponseTokens;
71286
71847
  if (!maxResponseTokens) {
71287
71848
  maxResponseTokens = 4e3;
71288
- if (this.model.includes("opus") || this.model.includes("sonnet") || this.model.startsWith("gpt-4-")) {
71849
+ if (this.model && this.model.includes("opus") || this.model && this.model.includes("sonnet") || this.model && this.model.startsWith("gpt-4-")) {
71289
71850
  maxResponseTokens = 8192;
71290
- } else if (this.model.startsWith("gpt-4o")) {
71851
+ } else if (this.model && this.model.startsWith("gpt-4o")) {
71291
71852
  maxResponseTokens = 8192;
71292
- } else if (this.model.startsWith("gemini")) {
71853
+ } else if (this.model && this.model.startsWith("gemini")) {
71293
71854
  maxResponseTokens = 32e3;
71294
71855
  }
71295
71856
  }
@@ -71404,6 +71965,9 @@ You are working with a repository located at: ${searchDirectory}
71404
71965
  if (this.enableDelegate && this.allowedTools.isEnabled("delegate")) {
71405
71966
  validTools.push("delegate");
71406
71967
  }
71968
+ if (this.allowedTools.isEnabled("analyze_all")) {
71969
+ validTools.push("analyze_all");
71970
+ }
71407
71971
  if (this.enableTasks && this.allowedTools.isEnabled("task")) {
71408
71972
  validTools.push("task");
71409
71973
  }