@probelabs/probe 0.6.0-rc209 → 0.6.0-rc211
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-rc211-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc211-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc211-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc211-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc211-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +100 -7
- package/build/agent/bashCommandUtils.js +98 -12
- package/build/agent/bashPermissions.js +207 -1
- package/build/agent/index.js +911 -90
- package/build/agent/probeTool.js +11 -2
- package/build/agent/tools.js +8 -0
- package/build/delegate.js +11 -2
- package/build/index.js +6 -1
- package/build/search.js +2 -2
- package/build/tools/analyzeAll.js +624 -0
- package/build/tools/common.js +149 -85
- package/build/tools/langchain.js +1 -1
- package/build/tools/vercel.js +66 -4
- package/cjs/agent/ProbeAgent.cjs +9841 -6642
- package/cjs/index.cjs +9955 -6750
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +100 -7
- package/src/agent/bashCommandUtils.js +98 -12
- package/src/agent/bashPermissions.js +207 -1
- package/src/agent/probeTool.js +11 -2
- package/src/agent/tools.js +8 -0
- package/src/delegate.js +11 -2
- package/src/index.js +6 -1
- package/src/search.js +2 -2
- package/src/tools/analyzeAll.js +624 -0
- package/src/tools/common.js +149 -85
- package/src/tools/langchain.js +1 -1
- package/src/tools/vercel.js +66 -4
- package/bin/binaries/probe-v0.6.0-rc209-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc209-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc209-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc209-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc209-x86_64-unknown-linux-musl.tar.gz +0 -0
package/build/agent/index.js
CHANGED
|
@@ -3346,8 +3346,8 @@ async function search(options) {
|
|
|
3346
3346
|
}
|
|
3347
3347
|
}
|
|
3348
3348
|
if (!options.maxTokens) {
|
|
3349
|
-
options.maxTokens =
|
|
3350
|
-
cliArgs.push("--max-tokens", "
|
|
3349
|
+
options.maxTokens = 2e4;
|
|
3350
|
+
cliArgs.push("--max-tokens", "20000");
|
|
3351
3351
|
}
|
|
3352
3352
|
if (!options.timeout) {
|
|
3353
3353
|
options.timeout = 30;
|
|
@@ -3764,7 +3764,10 @@ async function delegate({
|
|
|
3764
3764
|
disableTools = false,
|
|
3765
3765
|
searchDelegate = void 0,
|
|
3766
3766
|
schema = null,
|
|
3767
|
-
enableTasks = false
|
|
3767
|
+
enableTasks = false,
|
|
3768
|
+
enableMcp = false,
|
|
3769
|
+
mcpConfig = null,
|
|
3770
|
+
mcpConfigPath = null
|
|
3768
3771
|
}) {
|
|
3769
3772
|
if (!task || typeof task !== "string") {
|
|
3770
3773
|
throw new Error("Task parameter is required and must be a string");
|
|
@@ -3820,8 +3823,14 @@ async function delegate({
|
|
|
3820
3823
|
allowedTools,
|
|
3821
3824
|
disableTools,
|
|
3822
3825
|
searchDelegate,
|
|
3823
|
-
enableTasks
|
|
3826
|
+
enableTasks,
|
|
3824
3827
|
// Inherit from parent (subagent gets isolated TaskManager)
|
|
3828
|
+
enableMcp,
|
|
3829
|
+
// Inherit from parent (subagent creates own MCPXmlBridge)
|
|
3830
|
+
mcpConfig,
|
|
3831
|
+
// Inherit from parent
|
|
3832
|
+
mcpConfigPath
|
|
3833
|
+
// Inherit from parent
|
|
3825
3834
|
});
|
|
3826
3835
|
if (debug) {
|
|
3827
3836
|
console.error(`[DELEGATE] Created subagent with session ${sessionId}`);
|
|
@@ -4023,6 +4032,447 @@ var init_delegate = __esm({
|
|
|
4023
4032
|
}
|
|
4024
4033
|
});
|
|
4025
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
|
+
|
|
4026
4476
|
// node_modules/zod/v3/helpers/util.js
|
|
4027
4477
|
var util, objectUtil, ZodParsedType, getParsedType;
|
|
4028
4478
|
var init_util2 = __esm({
|
|
@@ -8895,6 +9345,7 @@ function getValidParamsForTool(toolName) {
|
|
|
8895
9345
|
query: querySchema,
|
|
8896
9346
|
extract: extractSchema,
|
|
8897
9347
|
delegate: delegateSchema,
|
|
9348
|
+
analyze_all: analyzeAllSchema,
|
|
8898
9349
|
listSkills: listSkillsSchema,
|
|
8899
9350
|
useSkill: useSkillSchema,
|
|
8900
9351
|
bash: bashSchema,
|
|
@@ -8919,76 +9370,84 @@ function getValidParamsForTool(toolName) {
|
|
|
8919
9370
|
return [];
|
|
8920
9371
|
}
|
|
8921
9372
|
function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
8922
|
-
|
|
8923
|
-
|
|
8924
|
-
|
|
8925
|
-
const
|
|
8926
|
-
|
|
8927
|
-
|
|
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;
|
|
8928
9381
|
}
|
|
8929
|
-
|
|
8930
|
-
|
|
8931
|
-
|
|
8932
|
-
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
|
|
8936
|
-
|
|
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;
|
|
8937
9395
|
}
|
|
8938
|
-
|
|
8939
|
-
|
|
8940
|
-
|
|
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;
|
|
8941
9415
|
}
|
|
8942
|
-
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
|
|
8947
|
-
|
|
8948
|
-
|
|
8949
|
-
|
|
8950
|
-
const paramCloseTag = `</${paramName}>`;
|
|
8951
|
-
const paramOpenIndex = innerContent.indexOf(paramOpenTag);
|
|
8952
|
-
if (paramOpenIndex === -1) {
|
|
8953
|
-
continue;
|
|
8954
|
-
}
|
|
8955
|
-
let paramCloseIndex = innerContent.indexOf(paramCloseTag, paramOpenIndex + paramOpenTag.length);
|
|
8956
|
-
if (paramCloseIndex === -1) {
|
|
8957
|
-
let nextTagIndex = innerContent.length;
|
|
8958
|
-
for (const nextParam of validParams) {
|
|
8959
|
-
const nextOpenTag = `<${nextParam}>`;
|
|
8960
|
-
const nextIndex = innerContent.indexOf(nextOpenTag, paramOpenIndex + paramOpenTag.length);
|
|
8961
|
-
if (nextIndex !== -1 && nextIndex < nextTagIndex) {
|
|
8962
|
-
nextTagIndex = nextIndex;
|
|
8963
|
-
}
|
|
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;
|
|
8964
9424
|
}
|
|
8965
|
-
paramCloseIndex = nextTagIndex;
|
|
8966
9425
|
}
|
|
8967
|
-
|
|
8968
|
-
paramOpenIndex + paramOpenTag.length,
|
|
8969
|
-
paramCloseIndex
|
|
8970
|
-
).trim();
|
|
8971
|
-
if (paramValue.toLowerCase() === "true") {
|
|
8972
|
-
paramValue = true;
|
|
8973
|
-
} else if (paramValue.toLowerCase() === "false") {
|
|
8974
|
-
paramValue = false;
|
|
8975
|
-
} else if (!isNaN(paramValue) && paramValue.trim() !== "") {
|
|
8976
|
-
const num = Number(paramValue);
|
|
8977
|
-
if (Number.isFinite(num)) {
|
|
8978
|
-
paramValue = num;
|
|
8979
|
-
}
|
|
8980
|
-
}
|
|
8981
|
-
params[paramName] = paramValue;
|
|
9426
|
+
paramCloseIndex = nextTagIndex;
|
|
8982
9427
|
}
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
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;
|
|
8987
9440
|
}
|
|
8988
9441
|
}
|
|
8989
|
-
|
|
9442
|
+
params[paramName] = paramValue;
|
|
8990
9443
|
}
|
|
8991
|
-
|
|
9444
|
+
if (toolName === "attempt_completion") {
|
|
9445
|
+
params["result"] = innerContent.trim();
|
|
9446
|
+
if (params.command) {
|
|
9447
|
+
delete params.command;
|
|
9448
|
+
}
|
|
9449
|
+
}
|
|
9450
|
+
return { toolName, params };
|
|
8992
9451
|
}
|
|
8993
9452
|
function createMessagePreview(message, charsPerSide = 200) {
|
|
8994
9453
|
if (message === null || message === void 0) {
|
|
@@ -9113,7 +9572,7 @@ function resolveTargetPath(target, cwd) {
|
|
|
9113
9572
|
}
|
|
9114
9573
|
return filePart + suffix;
|
|
9115
9574
|
}
|
|
9116
|
-
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;
|
|
9117
9576
|
var init_common = __esm({
|
|
9118
9577
|
"src/tools/common.js"() {
|
|
9119
9578
|
"use strict";
|
|
@@ -9150,6 +9609,10 @@ var init_common = __esm({
|
|
|
9150
9609
|
timeout: external_exports.number().optional().describe("Command timeout in milliseconds (optional)"),
|
|
9151
9610
|
env: external_exports.record(external_exports.string()).optional().describe("Additional environment variables (optional)")
|
|
9152
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
|
+
});
|
|
9153
9616
|
attemptCompletionSchema = {
|
|
9154
9617
|
// Custom validation that requires result parameter but allows direct XML response
|
|
9155
9618
|
safeParse: (params) => {
|
|
@@ -9359,6 +9822,51 @@ Usage Example:
|
|
|
9359
9822
|
<attempt_completion>
|
|
9360
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.
|
|
9361
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>
|
|
9362
9870
|
`;
|
|
9363
9871
|
bashToolDefinition = `
|
|
9364
9872
|
## bash
|
|
@@ -9419,11 +9927,13 @@ User: Check system info
|
|
|
9419
9927
|
queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
|
|
9420
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.";
|
|
9421
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.';
|
|
9422
9931
|
DEFAULT_VALID_TOOLS = [
|
|
9423
9932
|
"search",
|
|
9424
9933
|
"query",
|
|
9425
9934
|
"extract",
|
|
9426
9935
|
"delegate",
|
|
9936
|
+
"analyze_all",
|
|
9427
9937
|
"listSkills",
|
|
9428
9938
|
"useSkill",
|
|
9429
9939
|
"listFiles",
|
|
@@ -9541,7 +10051,7 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
9541
10051
|
"Deduplicate targets. Do NOT explain or answer - ONLY return the JSON targets."
|
|
9542
10052
|
].join("\n");
|
|
9543
10053
|
}
|
|
9544
|
-
var CODE_SEARCH_SCHEMA, searchTool, queryTool, extractTool, delegateTool;
|
|
10054
|
+
var CODE_SEARCH_SCHEMA, searchTool, queryTool, extractTool, delegateTool, analyzeAllTool;
|
|
9545
10055
|
var init_vercel = __esm({
|
|
9546
10056
|
"src/tools/vercel.js"() {
|
|
9547
10057
|
"use strict";
|
|
@@ -9549,6 +10059,7 @@ var init_vercel = __esm({
|
|
|
9549
10059
|
init_query();
|
|
9550
10060
|
init_extract();
|
|
9551
10061
|
init_delegate();
|
|
10062
|
+
init_analyzeAll();
|
|
9552
10063
|
init_common();
|
|
9553
10064
|
init_error_types();
|
|
9554
10065
|
CODE_SEARCH_SCHEMA = {
|
|
@@ -9566,7 +10077,7 @@ var init_vercel = __esm({
|
|
|
9566
10077
|
searchTool = (options = {}) => {
|
|
9567
10078
|
const {
|
|
9568
10079
|
sessionId,
|
|
9569
|
-
maxTokens =
|
|
10080
|
+
maxTokens = 2e4,
|
|
9570
10081
|
debug = false,
|
|
9571
10082
|
outline = false,
|
|
9572
10083
|
searchDelegate = false
|
|
@@ -9791,7 +10302,7 @@ var init_vercel = __esm({
|
|
|
9791
10302
|
});
|
|
9792
10303
|
};
|
|
9793
10304
|
delegateTool = (options = {}) => {
|
|
9794
|
-
const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName } = options;
|
|
10305
|
+
const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null } = options;
|
|
9795
10306
|
return tool2({
|
|
9796
10307
|
name: "delegate",
|
|
9797
10308
|
description: delegateDescription,
|
|
@@ -9850,12 +10361,54 @@ var init_vercel = __esm({
|
|
|
9850
10361
|
enableBash,
|
|
9851
10362
|
bashConfig,
|
|
9852
10363
|
architectureFileName,
|
|
9853
|
-
searchDelegate
|
|
10364
|
+
searchDelegate,
|
|
10365
|
+
enableMcp,
|
|
10366
|
+
mcpConfig,
|
|
10367
|
+
mcpConfigPath
|
|
9854
10368
|
});
|
|
9855
10369
|
return result;
|
|
9856
10370
|
}
|
|
9857
10371
|
});
|
|
9858
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
|
+
};
|
|
9859
10412
|
}
|
|
9860
10413
|
});
|
|
9861
10414
|
|
|
@@ -10377,6 +10930,38 @@ function parseSimpleCommand(command) {
|
|
|
10377
10930
|
isComplex: false
|
|
10378
10931
|
};
|
|
10379
10932
|
}
|
|
10933
|
+
const stripQuotedContent = (str) => {
|
|
10934
|
+
let result = "";
|
|
10935
|
+
let inQuotes2 = false;
|
|
10936
|
+
let quoteChar2 = "";
|
|
10937
|
+
for (let i = 0; i < str.length; i++) {
|
|
10938
|
+
const char = str[i];
|
|
10939
|
+
const nextChar = str[i + 1];
|
|
10940
|
+
if (!inQuotes2 && char === "\\" && nextChar !== void 0) {
|
|
10941
|
+
i++;
|
|
10942
|
+
continue;
|
|
10943
|
+
}
|
|
10944
|
+
if (inQuotes2 && quoteChar2 === '"' && char === "\\" && nextChar !== void 0) {
|
|
10945
|
+
i++;
|
|
10946
|
+
continue;
|
|
10947
|
+
}
|
|
10948
|
+
if (!inQuotes2 && (char === '"' || char === "'")) {
|
|
10949
|
+
inQuotes2 = true;
|
|
10950
|
+
quoteChar2 = char;
|
|
10951
|
+
continue;
|
|
10952
|
+
}
|
|
10953
|
+
if (inQuotes2 && char === quoteChar2) {
|
|
10954
|
+
inQuotes2 = false;
|
|
10955
|
+
quoteChar2 = "";
|
|
10956
|
+
continue;
|
|
10957
|
+
}
|
|
10958
|
+
if (!inQuotes2) {
|
|
10959
|
+
result += char;
|
|
10960
|
+
}
|
|
10961
|
+
}
|
|
10962
|
+
return result;
|
|
10963
|
+
};
|
|
10964
|
+
const strippedForOperators = stripQuotedContent(trimmed);
|
|
10380
10965
|
const complexPatterns = [
|
|
10381
10966
|
/\|/,
|
|
10382
10967
|
// Pipes
|
|
@@ -10402,7 +10987,7 @@ function parseSimpleCommand(command) {
|
|
|
10402
10987
|
// Brace expansion like {a,b} or {1..10} (but not find {} placeholders)
|
|
10403
10988
|
];
|
|
10404
10989
|
for (const pattern of complexPatterns) {
|
|
10405
|
-
if (pattern.test(
|
|
10990
|
+
if (pattern.test(strippedForOperators)) {
|
|
10406
10991
|
return {
|
|
10407
10992
|
success: false,
|
|
10408
10993
|
error: "Complex shell commands with pipes, operators, or redirections are not supported for security reasons",
|
|
@@ -10417,17 +11002,17 @@ function parseSimpleCommand(command) {
|
|
|
10417
11002
|
let current = "";
|
|
10418
11003
|
let inQuotes = false;
|
|
10419
11004
|
let quoteChar = "";
|
|
10420
|
-
let escaped = false;
|
|
10421
11005
|
for (let i = 0; i < trimmed.length; i++) {
|
|
10422
11006
|
const char = trimmed[i];
|
|
10423
11007
|
const nextChar = i + 1 < trimmed.length ? trimmed[i + 1] : "";
|
|
10424
|
-
if (
|
|
10425
|
-
current +=
|
|
10426
|
-
|
|
11008
|
+
if (!inQuotes && char === "\\" && nextChar) {
|
|
11009
|
+
current += nextChar;
|
|
11010
|
+
i++;
|
|
10427
11011
|
continue;
|
|
10428
11012
|
}
|
|
10429
|
-
if (char === "\\" &&
|
|
10430
|
-
|
|
11013
|
+
if (inQuotes && quoteChar === '"' && char === "\\" && nextChar) {
|
|
11014
|
+
current += nextChar;
|
|
11015
|
+
i++;
|
|
10431
11016
|
continue;
|
|
10432
11017
|
}
|
|
10433
11018
|
if (!inQuotes && (char === '"' || char === "'")) {
|
|
@@ -10760,8 +11345,97 @@ var init_bashPermissions = __esm({
|
|
|
10760
11345
|
});
|
|
10761
11346
|
return result;
|
|
10762
11347
|
}
|
|
11348
|
+
/**
|
|
11349
|
+
* Split a complex command into component commands by operators
|
|
11350
|
+
*
|
|
11351
|
+
* ## Escape Handling (Security-Critical)
|
|
11352
|
+
*
|
|
11353
|
+
* This function intentionally PRESERVES escape sequences (both backslash AND
|
|
11354
|
+
* escaped character) in the output. This is step 1 of a 2-step parsing process:
|
|
11355
|
+
*
|
|
11356
|
+
* 1. _splitComplexCommand: Splits by operators, PRESERVES escapes → `echo "test\" && b"`
|
|
11357
|
+
* 2. parseCommand: Interprets escapes in each component → args: ['test" && b']
|
|
11358
|
+
*
|
|
11359
|
+
* This differs from stripQuotedContent() in bashCommandUtils.js which REMOVES
|
|
11360
|
+
* escapes entirely (for operator detection only).
|
|
11361
|
+
*
|
|
11362
|
+
* The security rationale: if we stripped escapes here, `\"` would become `"`,
|
|
11363
|
+
* potentially causing incorrect quote boundary detection and allowing operator
|
|
11364
|
+
* injection. By preserving escapes, parseCommand() can correctly interpret them.
|
|
11365
|
+
*
|
|
11366
|
+
* See bashCommandUtils.js module header for the full escape handling architecture.
|
|
11367
|
+
*
|
|
11368
|
+
* @private
|
|
11369
|
+
* @param {string} command - Complex command to split
|
|
11370
|
+
* @returns {string[]} Array of component commands (with escapes preserved)
|
|
11371
|
+
*/
|
|
11372
|
+
_splitComplexCommand(command) {
|
|
11373
|
+
const components = [];
|
|
11374
|
+
let current = "";
|
|
11375
|
+
let inQuotes = false;
|
|
11376
|
+
let quoteChar = "";
|
|
11377
|
+
let i = 0;
|
|
11378
|
+
while (i < command.length) {
|
|
11379
|
+
const char = command[i];
|
|
11380
|
+
const nextChar = command[i + 1] || "";
|
|
11381
|
+
if (!inQuotes && char === "\\") {
|
|
11382
|
+
current += char;
|
|
11383
|
+
if (nextChar) {
|
|
11384
|
+
current += nextChar;
|
|
11385
|
+
i += 2;
|
|
11386
|
+
} else {
|
|
11387
|
+
i++;
|
|
11388
|
+
}
|
|
11389
|
+
continue;
|
|
11390
|
+
}
|
|
11391
|
+
if (inQuotes && quoteChar === '"' && char === "\\" && nextChar) {
|
|
11392
|
+
current += char + nextChar;
|
|
11393
|
+
i += 2;
|
|
11394
|
+
continue;
|
|
11395
|
+
}
|
|
11396
|
+
if (!inQuotes && (char === '"' || char === "'")) {
|
|
11397
|
+
inQuotes = true;
|
|
11398
|
+
quoteChar = char;
|
|
11399
|
+
current += char;
|
|
11400
|
+
i++;
|
|
11401
|
+
continue;
|
|
11402
|
+
}
|
|
11403
|
+
if (inQuotes && char === quoteChar) {
|
|
11404
|
+
inQuotes = false;
|
|
11405
|
+
quoteChar = "";
|
|
11406
|
+
current += char;
|
|
11407
|
+
i++;
|
|
11408
|
+
continue;
|
|
11409
|
+
}
|
|
11410
|
+
if (!inQuotes) {
|
|
11411
|
+
if (char === "&" && nextChar === "&" || char === "|" && nextChar === "|") {
|
|
11412
|
+
if (current.trim()) {
|
|
11413
|
+
components.push(current.trim());
|
|
11414
|
+
}
|
|
11415
|
+
current = "";
|
|
11416
|
+
i += 2;
|
|
11417
|
+
continue;
|
|
11418
|
+
}
|
|
11419
|
+
if (char === "|") {
|
|
11420
|
+
if (current.trim()) {
|
|
11421
|
+
components.push(current.trim());
|
|
11422
|
+
}
|
|
11423
|
+
current = "";
|
|
11424
|
+
i++;
|
|
11425
|
+
continue;
|
|
11426
|
+
}
|
|
11427
|
+
}
|
|
11428
|
+
current += char;
|
|
11429
|
+
i++;
|
|
11430
|
+
}
|
|
11431
|
+
if (current.trim()) {
|
|
11432
|
+
components.push(current.trim());
|
|
11433
|
+
}
|
|
11434
|
+
return components;
|
|
11435
|
+
}
|
|
10763
11436
|
/**
|
|
10764
11437
|
* Check a complex command against complex patterns in allow/deny lists
|
|
11438
|
+
* Also supports auto-allowing commands where all components are individually allowed
|
|
10765
11439
|
* @private
|
|
10766
11440
|
* @param {string} command - Complex command to check
|
|
10767
11441
|
* @returns {Object} Permission result
|
|
@@ -10816,6 +11490,85 @@ var init_bashPermissions = __esm({
|
|
|
10816
11490
|
return result;
|
|
10817
11491
|
}
|
|
10818
11492
|
}
|
|
11493
|
+
const components = this._splitComplexCommand(command);
|
|
11494
|
+
if (this.debug) {
|
|
11495
|
+
console.log(`[BashPermissions] Checking ${components.length} command components: ${JSON.stringify(components)}`);
|
|
11496
|
+
}
|
|
11497
|
+
if (components.length > 1) {
|
|
11498
|
+
const componentResults = [];
|
|
11499
|
+
let allAllowed = true;
|
|
11500
|
+
let deniedComponent = null;
|
|
11501
|
+
let deniedReason = null;
|
|
11502
|
+
for (const component of components) {
|
|
11503
|
+
const parsed = parseCommand(component);
|
|
11504
|
+
if (parsed.error || parsed.isComplex) {
|
|
11505
|
+
if (this.debug) {
|
|
11506
|
+
console.log(`[BashPermissions] Component "${component}" is complex or has error: ${parsed.error}`);
|
|
11507
|
+
}
|
|
11508
|
+
allAllowed = false;
|
|
11509
|
+
deniedComponent = component;
|
|
11510
|
+
deniedReason = parsed.error || "Component contains nested complex constructs";
|
|
11511
|
+
break;
|
|
11512
|
+
}
|
|
11513
|
+
if (matchesAnyPattern(parsed, this.denyPatterns)) {
|
|
11514
|
+
if (this.debug) {
|
|
11515
|
+
console.log(`[BashPermissions] Component "${component}" matches deny pattern`);
|
|
11516
|
+
}
|
|
11517
|
+
allAllowed = false;
|
|
11518
|
+
deniedComponent = component;
|
|
11519
|
+
deniedReason = "Component matches deny pattern";
|
|
11520
|
+
break;
|
|
11521
|
+
}
|
|
11522
|
+
if (!matchesAnyPattern(parsed, this.allowPatterns)) {
|
|
11523
|
+
if (this.debug) {
|
|
11524
|
+
console.log(`[BashPermissions] Component "${component}" not in allow list`);
|
|
11525
|
+
}
|
|
11526
|
+
allAllowed = false;
|
|
11527
|
+
deniedComponent = component;
|
|
11528
|
+
deniedReason = "Component not in allow list";
|
|
11529
|
+
break;
|
|
11530
|
+
}
|
|
11531
|
+
componentResults.push({ component, parsed, allowed: true });
|
|
11532
|
+
}
|
|
11533
|
+
if (allAllowed) {
|
|
11534
|
+
if (this.debug) {
|
|
11535
|
+
console.log(`[BashPermissions] ALLOWED - all ${components.length} components passed individual checks`);
|
|
11536
|
+
}
|
|
11537
|
+
const result = {
|
|
11538
|
+
allowed: true,
|
|
11539
|
+
command,
|
|
11540
|
+
isComplex: true,
|
|
11541
|
+
allowedByComponents: true,
|
|
11542
|
+
components: componentResults
|
|
11543
|
+
};
|
|
11544
|
+
this.recordBashEvent("permission.allowed", {
|
|
11545
|
+
command,
|
|
11546
|
+
isComplex: true,
|
|
11547
|
+
allowedByComponents: true,
|
|
11548
|
+
componentCount: components.length
|
|
11549
|
+
});
|
|
11550
|
+
return result;
|
|
11551
|
+
} else {
|
|
11552
|
+
if (this.debug) {
|
|
11553
|
+
console.log(`[BashPermissions] DENIED - component "${deniedComponent}" failed: ${deniedReason}`);
|
|
11554
|
+
}
|
|
11555
|
+
const result = {
|
|
11556
|
+
allowed: false,
|
|
11557
|
+
reason: `Component "${deniedComponent}" not allowed: ${deniedReason}`,
|
|
11558
|
+
command,
|
|
11559
|
+
isComplex: true,
|
|
11560
|
+
failedComponent: deniedComponent
|
|
11561
|
+
};
|
|
11562
|
+
this.recordBashEvent("permission.denied", {
|
|
11563
|
+
command,
|
|
11564
|
+
reason: "component_not_allowed",
|
|
11565
|
+
failedComponent: deniedComponent,
|
|
11566
|
+
componentReason: deniedReason,
|
|
11567
|
+
isComplex: true
|
|
11568
|
+
});
|
|
11569
|
+
return result;
|
|
11570
|
+
}
|
|
11571
|
+
}
|
|
10819
11572
|
if (this.debug) {
|
|
10820
11573
|
console.log(`[BashPermissions] DENIED - no matching complex pattern found`);
|
|
10821
11574
|
}
|
|
@@ -18565,6 +19318,13 @@ function createWrappedTools(baseTools) {
|
|
|
18565
19318
|
baseTools.delegateTool.execute
|
|
18566
19319
|
);
|
|
18567
19320
|
}
|
|
19321
|
+
if (baseTools.analyzeAllTool) {
|
|
19322
|
+
wrappedTools.analyzeAllToolInstance = wrapToolWithEmitter(
|
|
19323
|
+
baseTools.analyzeAllTool,
|
|
19324
|
+
"analyze_all",
|
|
19325
|
+
baseTools.analyzeAllTool.execute
|
|
19326
|
+
);
|
|
19327
|
+
}
|
|
18568
19328
|
if (baseTools.bashTool) {
|
|
18569
19329
|
wrappedTools.bashToolInstance = wrapToolWithEmitter(
|
|
18570
19330
|
baseTools.bashTool,
|
|
@@ -19471,6 +20231,9 @@ function createTools(configOptions) {
|
|
|
19471
20231
|
if (configOptions.enableDelegate && isToolAllowed("delegate")) {
|
|
19472
20232
|
tools2.delegateTool = delegateTool(configOptions);
|
|
19473
20233
|
}
|
|
20234
|
+
if (isToolAllowed("analyze_all")) {
|
|
20235
|
+
tools2.analyzeAllTool = analyzeAllTool(configOptions);
|
|
20236
|
+
}
|
|
19474
20237
|
if (configOptions.enableBash && isToolAllowed("bash")) {
|
|
19475
20238
|
tools2.bashTool = bashTool(configOptions);
|
|
19476
20239
|
}
|
|
@@ -67393,14 +68156,14 @@ function calculateCompactionStats(originalMessages, compactedMessages) {
|
|
|
67393
68156
|
const compactedCount = compactedMessages.length;
|
|
67394
68157
|
const removed = originalCount - compactedCount;
|
|
67395
68158
|
const reductionPercent = originalCount > 0 ? (removed / originalCount * 100).toFixed(1) : 0;
|
|
67396
|
-
const
|
|
68159
|
+
const estimateTokens2 = (msgs) => {
|
|
67397
68160
|
return msgs.reduce((sum, msg) => {
|
|
67398
68161
|
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
67399
68162
|
return sum + Math.ceil(content.length / 4);
|
|
67400
68163
|
}, 0);
|
|
67401
68164
|
};
|
|
67402
|
-
const originalTokens =
|
|
67403
|
-
const compactedTokens =
|
|
68165
|
+
const originalTokens = estimateTokens2(originalMessages);
|
|
68166
|
+
const compactedTokens = estimateTokens2(compactedMessages);
|
|
67404
68167
|
const tokensSaved = originalTokens - compactedTokens;
|
|
67405
68168
|
return {
|
|
67406
68169
|
originalCount,
|
|
@@ -67481,7 +68244,7 @@ async function truncateIfNeeded(content, tokenCounter, sessionId, maxTokens) {
|
|
|
67481
68244
|
if (tokenCount <= limit) {
|
|
67482
68245
|
return { truncated: false, content };
|
|
67483
68246
|
}
|
|
67484
|
-
const maxChars = limit *
|
|
68247
|
+
const maxChars = limit * CHARS_PER_TOKEN2;
|
|
67485
68248
|
const truncatedContent = content.substring(0, maxChars);
|
|
67486
68249
|
let tempFilePath = null;
|
|
67487
68250
|
let fileError = null;
|
|
@@ -67520,12 +68283,12 @@ ${truncatedContent}
|
|
|
67520
68283
|
error: fileError || void 0
|
|
67521
68284
|
};
|
|
67522
68285
|
}
|
|
67523
|
-
var DEFAULT_MAX_OUTPUT_TOKENS,
|
|
68286
|
+
var DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN2;
|
|
67524
68287
|
var init_outputTruncator = __esm({
|
|
67525
68288
|
"src/agent/outputTruncator.js"() {
|
|
67526
68289
|
"use strict";
|
|
67527
68290
|
DEFAULT_MAX_OUTPUT_TOKENS = 2e4;
|
|
67528
|
-
|
|
68291
|
+
CHARS_PER_TOKEN2 = 4;
|
|
67529
68292
|
}
|
|
67530
68293
|
});
|
|
67531
68294
|
|
|
@@ -69385,6 +70148,9 @@ var init_ProbeAgent = __esm({
|
|
|
69385
70148
|
if (this.enableDelegate && wrappedTools.delegateToolInstance && isToolAllowed("delegate")) {
|
|
69386
70149
|
this.toolImplementations.delegate = wrappedTools.delegateToolInstance;
|
|
69387
70150
|
}
|
|
70151
|
+
if (wrappedTools.analyzeAllToolInstance && isToolAllowed("analyze_all")) {
|
|
70152
|
+
this.toolImplementations.analyze_all = wrappedTools.analyzeAllToolInstance;
|
|
70153
|
+
}
|
|
69388
70154
|
if (isToolAllowed("listFiles")) {
|
|
69389
70155
|
this.toolImplementations.listFiles = listFilesToolInstance;
|
|
69390
70156
|
}
|
|
@@ -70584,6 +71350,10 @@ Workspace: ${this.allowedFolders.join(", ")}`;
|
|
|
70584
71350
|
}
|
|
70585
71351
|
if (this.enableDelegate && isToolAllowed("delegate")) {
|
|
70586
71352
|
toolDefinitions += `${delegateToolDefinition}
|
|
71353
|
+
`;
|
|
71354
|
+
}
|
|
71355
|
+
if (isToolAllowed("analyze_all")) {
|
|
71356
|
+
toolDefinitions += `${analyzeAllToolDefinition}
|
|
70587
71357
|
`;
|
|
70588
71358
|
}
|
|
70589
71359
|
let toolExamples = "";
|
|
@@ -70647,6 +71417,9 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
|
|
|
70647
71417
|
if (this.enableDelegate && isToolAllowed("delegate")) {
|
|
70648
71418
|
availableToolsList += "- delegate: Delegate big distinct tasks to specialized probe subagents.\n";
|
|
70649
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
|
+
}
|
|
70650
71423
|
if (this.enableBash && isToolAllowed("bash")) {
|
|
70651
71424
|
availableToolsList += "- bash: Execute bash commands for system operations.\n";
|
|
70652
71425
|
}
|
|
@@ -71033,6 +71806,9 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
71033
71806
|
let lastFormatErrorType = null;
|
|
71034
71807
|
let sameFormatErrorCount = 0;
|
|
71035
71808
|
const MAX_REPEATED_FORMAT_ERRORS = 3;
|
|
71809
|
+
let lastNoToolResponse = null;
|
|
71810
|
+
let sameResponseCount = 0;
|
|
71811
|
+
const MAX_REPEATED_IDENTICAL_RESPONSES = 3;
|
|
71036
71812
|
while (currentIteration < maxIterations && !completionAttempted) {
|
|
71037
71813
|
currentIteration++;
|
|
71038
71814
|
if (this.cancelled) throw new Error("Request was cancelled by the user");
|
|
@@ -71070,11 +71846,11 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
71070
71846
|
let maxResponseTokens = this.maxResponseTokens;
|
|
71071
71847
|
if (!maxResponseTokens) {
|
|
71072
71848
|
maxResponseTokens = 4e3;
|
|
71073
|
-
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-")) {
|
|
71074
71850
|
maxResponseTokens = 8192;
|
|
71075
|
-
} else if (this.model.startsWith("gpt-4o")) {
|
|
71851
|
+
} else if (this.model && this.model.startsWith("gpt-4o")) {
|
|
71076
71852
|
maxResponseTokens = 8192;
|
|
71077
|
-
} else if (this.model.startsWith("gemini")) {
|
|
71853
|
+
} else if (this.model && this.model.startsWith("gemini")) {
|
|
71078
71854
|
maxResponseTokens = 32e3;
|
|
71079
71855
|
}
|
|
71080
71856
|
}
|
|
@@ -71514,6 +72290,26 @@ ${errorXml}
|
|
|
71514
72290
|
}
|
|
71515
72291
|
break;
|
|
71516
72292
|
}
|
|
72293
|
+
if (lastNoToolResponse !== null && assistantResponseContent === lastNoToolResponse) {
|
|
72294
|
+
sameResponseCount++;
|
|
72295
|
+
if (sameResponseCount >= MAX_REPEATED_IDENTICAL_RESPONSES) {
|
|
72296
|
+
let cleanedResponse = assistantResponseContent;
|
|
72297
|
+
cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "").trim();
|
|
72298
|
+
cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*$/gi, "").trim();
|
|
72299
|
+
const hasSubstantialContent = cleanedResponse.length > 50 && !cleanedResponse.includes("<api_call>") && !cleanedResponse.includes("<tool_name>") && !cleanedResponse.includes("<function>");
|
|
72300
|
+
if (hasSubstantialContent) {
|
|
72301
|
+
if (this.debug) {
|
|
72302
|
+
console.log(`[DEBUG] Same response repeated ${sameResponseCount} times - accepting as final answer (${cleanedResponse.length} chars)`);
|
|
72303
|
+
}
|
|
72304
|
+
finalResult = cleanedResponse;
|
|
72305
|
+
completionAttempted = true;
|
|
72306
|
+
break;
|
|
72307
|
+
}
|
|
72308
|
+
}
|
|
72309
|
+
} else {
|
|
72310
|
+
lastNoToolResponse = assistantResponseContent;
|
|
72311
|
+
sameResponseCount = 1;
|
|
72312
|
+
}
|
|
71517
72313
|
currentMessages.push({ role: "assistant", content: assistantResponseContent });
|
|
71518
72314
|
const unrecognizedTool = detectUnrecognizedToolCall(assistantResponseContent, validTools);
|
|
71519
72315
|
let reminderContent;
|
|
@@ -71586,10 +72382,35 @@ Or if your previous response already contains a complete, direct answer (not a t
|
|
|
71586
72382
|
|
|
71587
72383
|
Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant message as the final answer. Only use this if that message was already a valid, complete response to the user's question.`;
|
|
71588
72384
|
}
|
|
71589
|
-
currentMessages.
|
|
71590
|
-
|
|
71591
|
-
|
|
71592
|
-
|
|
72385
|
+
const prevUserMsgIndex = currentMessages.length - 2;
|
|
72386
|
+
const prevUserMsg = currentMessages[prevUserMsgIndex];
|
|
72387
|
+
const isExistingReminder = prevUserMsg && prevUserMsg.role === "user" && (prevUserMsg.content.includes("Please use one of the available tools") || prevUserMsg.content.includes("<tool_result>"));
|
|
72388
|
+
if (isExistingReminder && sameResponseCount > 1) {
|
|
72389
|
+
const prevAssistantIndex = prevUserMsgIndex - 1;
|
|
72390
|
+
const hasSystemMessage2 = currentMessages.length > 0 && currentMessages[0].role === "system";
|
|
72391
|
+
const minValidIndex = hasSystemMessage2 ? 1 : 0;
|
|
72392
|
+
const canSafelyRemove = prevAssistantIndex >= minValidIndex && currentMessages[prevAssistantIndex] && currentMessages[prevAssistantIndex].role === "assistant" && currentMessages.length - 2 >= (hasSystemMessage2 ? 2 : 1);
|
|
72393
|
+
if (canSafelyRemove) {
|
|
72394
|
+
currentMessages.splice(prevAssistantIndex, 2);
|
|
72395
|
+
if (this.debug) {
|
|
72396
|
+
console.log(`[DEBUG] Removed duplicate assistant+reminder pair (iteration ${currentIteration}, same response #${sameResponseCount})`);
|
|
72397
|
+
}
|
|
72398
|
+
} else if (this.debug) {
|
|
72399
|
+
console.log(`[DEBUG] Skipped deduplication: pattern validation failed (prevAssistantIndex=${prevAssistantIndex}, arrayLength=${currentMessages.length})`);
|
|
72400
|
+
}
|
|
72401
|
+
const iterationHint = `
|
|
72402
|
+
|
|
72403
|
+
(Attempt #${sameResponseCount}: Your previous ${sameResponseCount} responses were identical. If you have a complete answer, use <attempt_complete></attempt_complete> to finalize it.)`;
|
|
72404
|
+
currentMessages.push({
|
|
72405
|
+
role: "user",
|
|
72406
|
+
content: reminderContent + iterationHint
|
|
72407
|
+
});
|
|
72408
|
+
} else {
|
|
72409
|
+
currentMessages.push({
|
|
72410
|
+
role: "user",
|
|
72411
|
+
content: reminderContent
|
|
72412
|
+
});
|
|
72413
|
+
}
|
|
71593
72414
|
if (this.debug) {
|
|
71594
72415
|
if (unrecognizedTool) {
|
|
71595
72416
|
console.log(`[DEBUG] Unrecognized tool '${unrecognizedTool}' used. Providing error feedback.`);
|