@probelabs/probe 0.6.0-rc284 → 0.6.0-rc285

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 (38) hide show
  1. package/bin/binaries/{probe-v0.6.0-rc284-aarch64-apple-darwin.tar.gz → probe-v0.6.0-rc285-aarch64-apple-darwin.tar.gz} +0 -0
  2. package/bin/binaries/probe-v0.6.0-rc285-aarch64-unknown-linux-musl.tar.gz +0 -0
  3. package/bin/binaries/probe-v0.6.0-rc285-x86_64-apple-darwin.tar.gz +0 -0
  4. package/bin/binaries/probe-v0.6.0-rc285-x86_64-pc-windows-msvc.zip +0 -0
  5. package/bin/binaries/probe-v0.6.0-rc285-x86_64-unknown-linux-musl.tar.gz +0 -0
  6. package/build/agent/ProbeAgent.d.ts +1 -1
  7. package/build/agent/ProbeAgent.js +333 -486
  8. package/build/agent/contextCompactor.js +17 -10
  9. package/build/agent/index.js +301 -702
  10. package/build/agent/schemaUtils.js +10 -11
  11. package/build/agent/shared/prompts.js +2 -2
  12. package/build/agent/tasks/taskTool.js +3 -3
  13. package/build/agent/tools.js +0 -2
  14. package/build/index.js +0 -2
  15. package/build/tools/analyzeAll.js +4 -4
  16. package/build/tools/common.js +55 -55
  17. package/build/tools/index.js +0 -1
  18. package/build/tools/vercel.js +3 -3
  19. package/cjs/agent/ProbeAgent.cjs +292 -758
  20. package/cjs/index.cjs +293 -814
  21. package/package.json +1 -1
  22. package/src/agent/ProbeAgent.d.ts +1 -1
  23. package/src/agent/ProbeAgent.js +333 -486
  24. package/src/agent/contextCompactor.js +17 -10
  25. package/src/agent/index.js +8 -2
  26. package/src/agent/schemaUtils.js +10 -11
  27. package/src/agent/shared/prompts.js +2 -2
  28. package/src/agent/tasks/taskTool.js +3 -3
  29. package/src/agent/tools.js +0 -2
  30. package/src/index.js +0 -2
  31. package/src/tools/analyzeAll.js +4 -4
  32. package/src/tools/common.js +55 -55
  33. package/src/tools/index.js +0 -1
  34. package/src/tools/vercel.js +3 -3
  35. package/bin/binaries/probe-v0.6.0-rc284-aarch64-unknown-linux-musl.tar.gz +0 -0
  36. package/bin/binaries/probe-v0.6.0-rc284-x86_64-apple-darwin.tar.gz +0 -0
  37. package/bin/binaries/probe-v0.6.0-rc284-x86_64-pc-windows-msvc.zip +0 -0
  38. package/bin/binaries/probe-v0.6.0-rc284-x86_64-unknown-linux-musl.tar.gz +0 -0
package/cjs/index.cjs CHANGED
@@ -26682,7 +26682,7 @@ For each pending/in_progress task, either:
26682
26682
  - Complete it: call task tool with action="complete", id="task-X"
26683
26683
  - Cancel it: call task tool with action="update", id="task-X", status="cancelled"
26684
26684
 
26685
- After all tasks are resolved, call attempt_completion again.`;
26685
+ After all tasks are resolved, provide your final answer.`;
26686
26686
  }
26687
26687
  function createTaskTool(options = {}) {
26688
26688
  const { taskManager, tracer, debug = false } = options;
@@ -26932,13 +26932,13 @@ Tasks = logical units of work, not files or steps.
26932
26932
 
26933
26933
  1. **Plan**: Call task tool with action="create" and a tasks array up front
26934
26934
  2. **Execute**: Update status to "in_progress" / "completed" as you work. Add, split, or cancel tasks as you learn more.
26935
- 3. **Finish**: All tasks must be "completed" or "cancelled" before calling attempt_completion.
26935
+ 3. **Finish**: All tasks must be "completed" or "cancelled" before providing your final answer.
26936
26936
 
26937
26937
  ## Rules
26938
26938
 
26939
26939
  - Dependencies are enforced: a task cannot start until its dependencies are completed
26940
26940
  - Circular dependencies are rejected
26941
- - attempt_completion is blocked while tasks remain unresolved
26941
+ - Completion is blocked while tasks remain unresolved
26942
26942
  `;
26943
26943
  }
26944
26944
  });
@@ -27017,6 +27017,34 @@ function createMessagePreview(message, charsPerSide = 200) {
27017
27017
  const end = message.substring(message.length - charsPerSide);
27018
27018
  return `${start}...${end}`;
27019
27019
  }
27020
+ function detectStuckResponse(response) {
27021
+ if (!response || typeof response !== "string") {
27022
+ return false;
27023
+ }
27024
+ const stuckPatterns = [
27025
+ /\bi\s+cannot\s+proceed\b/i,
27026
+ /\bi\s+can['']t\s+(?:proceed|continue|move\s+forward)\b/i,
27027
+ /\bunable\s+to\s+(?:proceed|continue|complete)\b/i,
27028
+ /\bblocked\b.*\b(?:proceed|continue)\b/i,
27029
+ /\bneed\s+(?:the|an?)\s+\w+(?:\s+\w+)?\s+to\s+(?:proceed|continue)\b/i,
27030
+ /\brequire[sd]?\s+(?:the|an?)\s+\w+\b.*\bto\s+(?:proceed|continue)\b/i,
27031
+ /\bmissing\s+(?:required|necessary|essential)\b/i,
27032
+ /\bdeadlock\b/i,
27033
+ /\bwe\s+are\s+in\s+a\s+loop\b/i,
27034
+ /\bstuck\s+in\s+a\s+loop\b/i,
27035
+ /\bi\s+(?:have|['']ve)\s+(?:explained|stated|mentioned)\s+(?:this|the\s+situation|it)\s+(?:multiple|several)\s+times\b/i,
27036
+ /\bi\s+(?:cannot|can['']t|could\s+not|couldn['']t)\s+(?:find|locate|get|retrieve|obtain)\s+(?:the|this|that|an?)\b/i,
27037
+ /\bno\s+way\s+to\s+(?:find|get|obtain|retrieve)\b/i,
27038
+ /\bi\s+(?:have|['']ve)\s+exhausted\s+(?:all|my)\s+(?:available\s+)?(?:options|methods|approaches)\b/i,
27039
+ /\bneither\s+of\s+these\s+methods\b/i
27040
+ ];
27041
+ for (const pattern of stuckPatterns) {
27042
+ if (pattern.test(response)) {
27043
+ return true;
27044
+ }
27045
+ }
27046
+ return false;
27047
+ }
27020
27048
  function parseTargets(targets) {
27021
27049
  if (!targets || typeof targets !== "string") {
27022
27050
  return [];
@@ -27053,7 +27081,7 @@ function resolveTargetPath(target, cwd) {
27053
27081
  }
27054
27082
  return filePart + suffix;
27055
27083
  }
27056
- var import_path5, searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, listFilesSchema, searchFilesSchema, readImageSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, attemptCompletionSchema, searchDescription, searchDelegateDescription, queryDescription, extractDescription, delegateDescription, bashDescription, analyzeAllDescription;
27084
+ var import_path5, searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, listFilesSchema, searchFilesSchema, readImageSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, searchDescription, searchDelegateDescription, queryDescription, extractDescription, delegateDescription, bashDescription, analyzeAllDescription;
27057
27085
  var init_common = __esm({
27058
27086
  "src/tools/common.js"() {
27059
27087
  "use strict";
@@ -27123,58 +27151,6 @@ var init_common = __esm({
27123
27151
  clearOutputBuffer: external_exports2.boolean().optional().default(true).describe("Clear the output buffer from previous execute_plan calls"),
27124
27152
  clearSessionStore: external_exports2.boolean().optional().default(false).describe("Clear the session store (persisted data across execute_plan calls)")
27125
27153
  });
27126
- attemptCompletionSchema = {
27127
- // Custom validation that requires result parameter but allows direct XML response
27128
- safeParse: (params) => {
27129
- if (!params || typeof params !== "object") {
27130
- return {
27131
- success: false,
27132
- error: {
27133
- issues: [{
27134
- code: "invalid_type",
27135
- expected: "object",
27136
- received: typeof params,
27137
- path: [],
27138
- message: "Expected object"
27139
- }]
27140
- }
27141
- };
27142
- }
27143
- if (!("result" in params)) {
27144
- return {
27145
- success: false,
27146
- error: {
27147
- issues: [{
27148
- code: "invalid_type",
27149
- expected: "string",
27150
- received: "undefined",
27151
- path: ["result"],
27152
- message: "Required"
27153
- }]
27154
- }
27155
- };
27156
- }
27157
- if (typeof params.result !== "string") {
27158
- return {
27159
- success: false,
27160
- error: {
27161
- issues: [{
27162
- code: "invalid_type",
27163
- expected: "string",
27164
- received: typeof params.result,
27165
- path: ["result"],
27166
- message: "Expected string"
27167
- }]
27168
- }
27169
- };
27170
- }
27171
- const filteredData = { result: params.result };
27172
- return {
27173
- success: true,
27174
- data: filteredData
27175
- };
27176
- }
27177
- };
27178
27154
  searchDescription = 'Search code in the repository. Free-form questions are accepted, but Elasticsearch-style keyword queries work best. Use this tool first for any code-related questions. NOTE: By default, search handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically \u2014 do NOT manually try keyword variations like "getAllUsers" then "get_all_users" then "GetAllUsers". One search covers all variations.';
27179
27155
  searchDelegateDescription = 'Search code in the repository by asking a question. Accepts natural language questions (e.g., "How does authentication work?", "Where is the user validation logic?"). A specialized subagent breaks down your question into targeted keyword searches and returns extracted code blocks. Do NOT formulate keyword queries yourself \u2014 just ask the question naturally.';
27180
27156
  queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
@@ -71535,68 +71511,9 @@ var require_ajv = __commonJS({
71535
71511
  });
71536
71512
 
71537
71513
  // src/agent/schemaUtils.js
71538
- var schemaUtils_exports = {};
71539
- __export(schemaUtils_exports, {
71540
- JsonFixingAgent: () => JsonFixingAgent,
71541
- MermaidFixingAgent: () => MermaidFixingAgent,
71542
- cleanSchemaResponse: () => cleanSchemaResponse,
71543
- createJsonCorrectionPrompt: () => createJsonCorrectionPrompt,
71544
- createMermaidCorrectionPrompt: () => createMermaidCorrectionPrompt,
71545
- createSchemaDefinitionCorrectionPrompt: () => createSchemaDefinitionCorrectionPrompt,
71546
- decodeHtmlEntities: () => decodeHtmlEntities,
71547
- extractMermaidFromJson: () => extractMermaidFromJson,
71548
- extractMermaidFromMarkdown: () => extractMermaidFromMarkdown,
71549
- generateExampleFromSchema: () => generateExampleFromSchema,
71550
- generateSchemaInstructions: () => generateSchemaInstructions,
71551
- isJsonSchema: () => isJsonSchema,
71552
- isJsonSchemaDefinition: () => isJsonSchemaDefinition,
71553
- isMermaidSchema: () => isMermaidSchema,
71554
- isSimpleTextWrapperSchema: () => isSimpleTextWrapperSchema,
71555
- processSchemaResponse: () => processSchemaResponse,
71556
- replaceMermaidDiagramsInJson: () => replaceMermaidDiagramsInJson,
71557
- replaceMermaidDiagramsInMarkdown: () => replaceMermaidDiagramsInMarkdown,
71558
- sanitizeMarkdownEscapesInJson: () => sanitizeMarkdownEscapesInJson,
71559
- tryAutoWrapForSimpleSchema: () => tryAutoWrapForSimpleSchema,
71560
- tryExtractValidJsonPrefix: () => tryExtractValidJsonPrefix,
71561
- tryMaidAutoFix: () => tryMaidAutoFix,
71562
- validateAndFixMermaidResponse: () => validateAndFixMermaidResponse,
71563
- validateJsonResponse: () => validateJsonResponse,
71564
- validateMermaidDiagram: () => validateMermaidDiagram,
71565
- validateMermaidResponse: () => validateMermaidResponse,
71566
- validateXmlResponse: () => validateXmlResponse
71567
- });
71568
- function generateExampleFromSchema(schema, options = {}) {
71569
- const { debug = false } = options;
71570
- try {
71571
- const parsedSchema = typeof schema === "string" ? JSON.parse(schema) : schema;
71572
- if (parsedSchema.type !== "object" || !parsedSchema.properties) {
71573
- return null;
71574
- }
71575
- const exampleObj = {};
71576
- for (const [key, value] of Object.entries(parsedSchema.properties)) {
71577
- if (value.type === "boolean") {
71578
- exampleObj[key] = false;
71579
- } else if (value.type === "number") {
71580
- exampleObj[key] = 0;
71581
- } else if (value.type === "string") {
71582
- exampleObj[key] = value.description || "your answer here";
71583
- } else if (value.type === "array") {
71584
- exampleObj[key] = [];
71585
- } else {
71586
- exampleObj[key] = {};
71587
- }
71588
- }
71589
- return exampleObj;
71590
- } catch (e) {
71591
- if (debug) {
71592
- console.error("[DEBUG] generateExampleFromSchema: Failed to parse schema:", e.message);
71593
- }
71594
- return null;
71595
- }
71596
- }
71597
71514
  function generateSchemaInstructions(schema, options = {}) {
71598
71515
  const { debug = false } = options;
71599
- let instructions = "\n\nIMPORTANT: When you provide your final answer using attempt_completion, you MUST format it as valid JSON matching this schema:\n\n";
71516
+ let instructions = "\n\nIMPORTANT: When you provide your final answer, you MUST format it as valid JSON matching this schema:\n\n";
71600
71517
  try {
71601
71518
  const parsedSchema = typeof schema === "string" ? JSON.parse(schema) : schema;
71602
71519
  instructions += `${JSON.stringify(parsedSchema, null, 2)}
@@ -71610,7 +71527,7 @@ function generateSchemaInstructions(schema, options = {}) {
71610
71527
 
71611
71528
  `;
71612
71529
  }
71613
- instructions += "Your response inside attempt_completion must be ONLY valid JSON - no plain text, no explanations, no markdown.\n\nIMPORTANT: First complete the requested analysis/task thoroughly, then provide your final answer in the JSON format above.";
71530
+ instructions += "Your final response must be ONLY valid JSON - no plain text, no explanations, no markdown.\n\nIMPORTANT: First complete the requested analysis/task thoroughly, then provide your final answer in the JSON format above.";
71614
71531
  return instructions;
71615
71532
  }
71616
71533
  function enforceNoAdditionalProperties(schema) {
@@ -72107,65 +72024,6 @@ function tryExtractValidJsonPrefix(response, options = {}) {
72107
72024
  return null;
72108
72025
  }
72109
72026
  }
72110
- function validateXmlResponse(response) {
72111
- const xmlPattern = /<\/?[\w\s="'.-]+>/g;
72112
- const tags = response.match(xmlPattern);
72113
- if (!tags) {
72114
- return { isValid: false, error: "No XML tags found" };
72115
- }
72116
- if (response.includes("<") && response.includes(">")) {
72117
- return { isValid: true };
72118
- }
72119
- return { isValid: false, error: "Invalid XML structure" };
72120
- }
72121
- function processSchemaResponse(response, schema, options = {}) {
72122
- const { validateJson = false, validateXml = false, debug = false } = options;
72123
- if (debug) {
72124
- console.log(`[DEBUG] Schema processing: Starting with response length ${response.length}`);
72125
- console.log(`[DEBUG] Schema processing: Schema type detection...`);
72126
- if (isJsonSchema(schema)) {
72127
- console.log(`[DEBUG] Schema processing: Detected JSON schema`);
72128
- } else {
72129
- console.log(`[DEBUG] Schema processing: Non-JSON schema detected`);
72130
- }
72131
- }
72132
- const cleanStart = Date.now();
72133
- const cleaned = cleanSchemaResponse(response);
72134
- const cleanTime = Date.now() - cleanStart;
72135
- const result = { cleaned };
72136
- if (debug) {
72137
- console.log(`[DEBUG] Schema processing: Cleaning completed in ${cleanTime}ms`);
72138
- result.debug = {
72139
- originalLength: response.length,
72140
- cleanedLength: cleaned.length,
72141
- wasModified: response !== cleaned,
72142
- cleaningTimeMs: cleanTime,
72143
- removedContent: response !== cleaned ? {
72144
- before: response.substring(0, 100) + (response.length > 100 ? "..." : ""),
72145
- after: cleaned.substring(0, 100) + (cleaned.length > 100 ? "..." : "")
72146
- } : null
72147
- };
72148
- if (response !== cleaned) {
72149
- console.log(`[DEBUG] Schema processing: Response was modified during cleaning`);
72150
- console.log(`[DEBUG] Schema processing: Original length: ${response.length}, cleaned length: ${cleaned.length}`);
72151
- } else {
72152
- console.log(`[DEBUG] Schema processing: Response unchanged during cleaning`);
72153
- }
72154
- }
72155
- if (validateJson) {
72156
- if (debug) {
72157
- console.log(`[DEBUG] Schema processing: Running JSON validation...`);
72158
- }
72159
- result.jsonValidation = validateJsonResponse(cleaned, { debug });
72160
- }
72161
- if (validateXml) {
72162
- if (debug) {
72163
- console.log(`[DEBUG] Schema processing: Running XML validation...`);
72164
- }
72165
- result.xmlValidation = validateXmlResponse(cleaned);
72166
- }
72167
- return result;
72168
- }
72169
72027
  function isJsonSchema(schema) {
72170
72028
  if (!schema || typeof schema !== "string") {
72171
72029
  return false;
@@ -72307,18 +72165,18 @@ function createJsonCorrectionPrompt(invalidResponse, schema, errorOrValidation,
72307
72165
  const strengthLevels = [
72308
72166
  {
72309
72167
  prefix: "CRITICAL JSON ERROR:",
72310
- instruction: "You MUST fix this and respond using attempt_completion with ONLY valid JSON as the result.",
72311
- emphasis: "Use attempt_completion with ONLY the corrected JSON in the result field. No explanatory text, no markdown, no code blocks."
72168
+ instruction: "You MUST fix this and respond with ONLY valid JSON.",
72169
+ emphasis: "Respond with ONLY the corrected JSON. No explanatory text, no markdown, no code blocks."
72312
72170
  },
72313
72171
  {
72314
72172
  prefix: "URGENT - JSON PARSING FAILED:",
72315
- instruction: "This is your second chance. Use attempt_completion with valid JSON that can be parsed by JSON.parse().",
72316
- emphasis: "ABSOLUTELY NO explanatory text or formatting. Use attempt_completion with ONLY raw JSON in the result."
72173
+ instruction: "This is your second chance. Respond with valid JSON that can be parsed by JSON.parse().",
72174
+ emphasis: "ABSOLUTELY NO explanatory text or formatting. Respond with ONLY raw JSON."
72317
72175
  },
72318
72176
  {
72319
72177
  prefix: "FINAL ATTEMPT - CRITICAL JSON ERROR:",
72320
- instruction: "This is the final retry. You MUST use attempt_completion with ONLY raw JSON in the result field.",
72321
- emphasis: 'CORRECT: <attempt_completion><result>{"key": "value"}</result></attempt_completion>\nWRONG: Here is the JSON: {"key": "value"}\nWRONG: ```json{"key": "value"}```'
72178
+ instruction: "This is the final retry. You MUST respond with ONLY raw JSON.",
72179
+ emphasis: 'CORRECT: {"key": "value"}\nWRONG: Here is the JSON: {"key": "value"}\nWRONG: ```json{"key": "value"}```'
72322
72180
  }
72323
72181
  ];
72324
72182
  const level = Math.min(retryCount, strengthLevels.length - 1);
@@ -72372,28 +72230,6 @@ ${currentLevel.example}
72372
72230
  Return ONLY the JSON data object/array that follows the schema structure. NO schema definitions, NO explanations, NO markdown formatting.`;
72373
72231
  return prompt;
72374
72232
  }
72375
- function isMermaidSchema(schema) {
72376
- if (!schema || typeof schema !== "string") {
72377
- return false;
72378
- }
72379
- const trimmedSchema = schema.trim().toLowerCase();
72380
- const mermaidIndicators = [
72381
- trimmedSchema.includes("mermaid"),
72382
- trimmedSchema.includes("diagram"),
72383
- trimmedSchema.includes("flowchart"),
72384
- trimmedSchema.includes("sequence"),
72385
- trimmedSchema.includes("gantt"),
72386
- trimmedSchema.includes("pie chart"),
72387
- trimmedSchema.includes("state diagram"),
72388
- trimmedSchema.includes("class diagram"),
72389
- trimmedSchema.includes("entity relationship"),
72390
- trimmedSchema.includes("user journey"),
72391
- trimmedSchema.includes("git graph"),
72392
- trimmedSchema.includes("requirement diagram"),
72393
- trimmedSchema.includes("c4 context")
72394
- ];
72395
- return mermaidIndicators.some((indicator) => indicator);
72396
- }
72397
72233
  function extractMermaidFromJson(response) {
72398
72234
  if (!response || typeof response !== "string") {
72399
72235
  return { diagrams: [], jsonPaths: [], parsedJson: null };
@@ -72525,28 +72361,6 @@ ${modifiedJsonString}
72525
72361
  }
72526
72362
  return modifiedJsonString;
72527
72363
  }
72528
- function replaceMermaidDiagramsInMarkdown(originalResponse, correctedDiagrams) {
72529
- if (!originalResponse || typeof originalResponse !== "string") {
72530
- return originalResponse;
72531
- }
72532
- if (!correctedDiagrams || correctedDiagrams.length === 0) {
72533
- return originalResponse;
72534
- }
72535
- const hasJsonDiagrams = correctedDiagrams.some((d) => d.isInJson);
72536
- if (hasJsonDiagrams) {
72537
- return replaceMermaidDiagramsInJson(originalResponse, correctedDiagrams);
72538
- }
72539
- let modifiedResponse = originalResponse;
72540
- const sortedDiagrams = [...correctedDiagrams].sort((a, b) => b.startIndex - a.startIndex);
72541
- for (const diagram of sortedDiagrams) {
72542
- const attributesStr = diagram.attributes ? ` ${diagram.attributes}` : "";
72543
- const newCodeBlock = `\`\`\`mermaid${attributesStr}
72544
- ${diagram.content}
72545
- \`\`\``;
72546
- modifiedResponse = modifiedResponse.slice(0, diagram.startIndex) + newCodeBlock + modifiedResponse.slice(diagram.endIndex);
72547
- }
72548
- return modifiedResponse;
72549
- }
72550
72364
  function replaceSingleMermaidDiagramInResponse(response, originalDiagram, newContent) {
72551
72365
  if (!originalDiagram) {
72552
72366
  return response;
@@ -72631,45 +72445,6 @@ async function validateMermaidResponse(response) {
72631
72445
  errors: errors.length > 0 ? errors : void 0
72632
72446
  };
72633
72447
  }
72634
- function createMermaidCorrectionPrompt(invalidResponse, schema, errors, diagrams) {
72635
- let prompt = `Your previous response contains invalid Mermaid diagrams that cannot be parsed. Here's what you returned:
72636
-
72637
- ${invalidResponse}
72638
-
72639
- Validation Errors:`;
72640
- errors.forEach((error40, index) => {
72641
- prompt += `
72642
- ${index + 1}. ${error40}`;
72643
- });
72644
- if (diagrams && diagrams.length > 0) {
72645
- prompt += `
72646
-
72647
- Diagram Details:`;
72648
- diagrams.forEach((diagramResult, index) => {
72649
- if (!diagramResult.isValid) {
72650
- prompt += `
72651
-
72652
- Diagram ${index + 1}:`;
72653
- const diagramContent = diagramResult.content || diagramResult.diagram || "";
72654
- prompt += `
72655
- - Content: ${diagramContent.substring(0, 100)}${diagramContent.length > 100 ? "..." : ""}`;
72656
- prompt += `
72657
- - Error: ${diagramResult.error}`;
72658
- if (diagramResult.detailedError && diagramResult.detailedError !== diagramResult.error) {
72659
- prompt += `
72660
- - Details: ${diagramResult.detailedError}`;
72661
- }
72662
- }
72663
- });
72664
- }
72665
- prompt += `
72666
-
72667
- Please correct your response to include valid Mermaid diagrams that match this schema:
72668
- ${schema}
72669
-
72670
- Ensure all Mermaid diagrams are properly formatted within \`\`\`mermaid code blocks and follow correct Mermaid syntax.`;
72671
- return prompt;
72672
- }
72673
72448
  async function tryMaidAutoFix(diagramContent, options = {}) {
72674
72449
  const { debug = false } = options;
72675
72450
  try {
@@ -72979,7 +72754,7 @@ async function validateAndFixMermaidResponse(response, options = {}) {
72979
72754
  };
72980
72755
  }
72981
72756
  }
72982
- var import_ajv, HTML_ENTITY_MAP, sessionIdCounter, JsonFixingAgent, MermaidFixingAgent;
72757
+ var import_ajv, HTML_ENTITY_MAP, sessionIdCounter, MermaidFixingAgent;
72983
72758
  var init_schemaUtils = __esm({
72984
72759
  "src/agent/schemaUtils.js"() {
72985
72760
  "use strict";
@@ -72997,172 +72772,6 @@ var init_schemaUtils = __esm({
72997
72772
  "&nbsp;": " "
72998
72773
  };
72999
72774
  sessionIdCounter = 0;
73000
- JsonFixingAgent = class {
73001
- constructor(options = {}) {
73002
- this.ProbeAgent = null;
73003
- this.options = {
73004
- sessionId: options.sessionId || `json-fixer-${Date.now()}-${sessionIdCounter++}`,
73005
- path: options.path || process.cwd(),
73006
- provider: options.provider,
73007
- model: options.model,
73008
- debug: options.debug,
73009
- tracer: options.tracer,
73010
- // Set to false since we're only fixing JSON syntax, not implementing code
73011
- allowEdit: false
73012
- };
73013
- }
73014
- /**
73015
- * Get the specialized prompt for JSON fixing
73016
- */
73017
- getJsonFixingPrompt() {
73018
- return `You are a world-class JSON syntax correction specialist. Your expertise lies in analyzing and fixing JSON syntax errors while preserving the original data structure and intent.
73019
-
73020
- CORE RESPONSIBILITIES:
73021
- - Analyze JSON for syntax errors and structural issues
73022
- - Fix syntax errors while maintaining the original data's semantic meaning
73023
- - Ensure JSON follows proper RFC 8259 specification
73024
- - Handle all JSON structures: objects, arrays, primitives, nested structures
73025
-
73026
- JSON SYNTAX RULES:
73027
- 1. **Property names**: Must be enclosed in double quotes
73028
- 2. **String values**: Must use double quotes (not single quotes)
73029
- 3. **Numbers**: Can be integers or decimals, no quotes needed
73030
- 4. **Booleans**: true or false (lowercase, no quotes)
73031
- 5. **Null**: null (lowercase, no quotes)
73032
- 6. **Arrays**: Comma-separated values in square brackets [...]
73033
- 7. **Objects**: Comma-separated key-value pairs in curly braces {...}
73034
- 8. **No trailing commas**: Last item in array/object must not have a trailing comma
73035
- 9. **Escape sequences**: Special characters must be escaped (\\n, \\t, \\", \\\\, etc.)
73036
-
73037
- COMMON ERRORS TO FIX:
73038
- 1. **Unquoted property names**: {name: "value"} \u2192 {"name": "value"}
73039
- 2. **Single quotes**: {'key': 'value'} \u2192 {"key": "value"}
73040
- 3. **Trailing commas**: {"a": 1,} \u2192 {"a": 1}
73041
- 4. **Unquoted strings**: {key: value} \u2192 {"key": "value"}
73042
- 5. **Missing commas**: {"a": 1 "b": 2} \u2192 {"a": 1, "b": 2}
73043
- 6. **Extra commas**: {"a": 1,, "b": 2} \u2192 {"a": 1, "b": 2}
73044
- 7. **Unclosed brackets/braces**: {"key": "value" \u2192 {"key": "value"}
73045
- 8. **Invalid escape sequences**: Fix or remove
73046
- 9. **Comments**: Remove // or /* */ comments (not allowed in JSON)
73047
- 10. **Undefined values**: Replace undefined with null
73048
-
73049
- FIXING METHODOLOGY:
73050
- 1. **Identify the error location** from the error message
73051
- 2. **Analyze the context** around the error
73052
- 3. **Apply the appropriate fix** based on JSON syntax rules
73053
- 4. **Preserve data intent** - never change the meaning of the data
73054
- 5. **Validate the result** - ensure it's parseable JSON
73055
-
73056
- CRITICAL RULES:
73057
- - ALWAYS output only the corrected JSON
73058
- - NEVER add explanations, comments, or additional text
73059
- - NEVER wrap in markdown code blocks (no \`\`\`json)
73060
- - PRESERVE the original data structure and values
73061
- - FIX only syntax errors, don't modify the data itself
73062
- - ENSURE the output is valid, parseable JSON
73063
-
73064
- When presented with broken JSON, analyze it thoroughly and provide the corrected version that maintains the original intent while fixing all syntax issues.`;
73065
- }
73066
- /**
73067
- * Initialize the ProbeAgent if not already done
73068
- */
73069
- async initializeAgent() {
73070
- if (!this.ProbeAgent) {
73071
- const { ProbeAgent: ProbeAgent2 } = await Promise.resolve().then(() => (init_ProbeAgent(), ProbeAgent_exports));
73072
- this.ProbeAgent = ProbeAgent2;
73073
- }
73074
- if (!this.agent) {
73075
- this.agent = new this.ProbeAgent({
73076
- sessionId: this.options.sessionId,
73077
- customPrompt: this.getJsonFixingPrompt(),
73078
- path: this.options.path,
73079
- provider: this.options.provider,
73080
- model: this.options.model,
73081
- debug: this.options.debug,
73082
- tracer: this.options.tracer,
73083
- allowEdit: this.options.allowEdit,
73084
- maxIterations: 5,
73085
- // Allow multiple iterations for JSON fixing
73086
- disableJsonValidation: true
73087
- // CRITICAL: Disable JSON validation in nested agent to prevent infinite recursion
73088
- });
73089
- }
73090
- return this.agent;
73091
- }
73092
- /**
73093
- * Fix invalid JSON using the specialized agent
73094
- * @param {string} invalidJson - The broken JSON string
73095
- * @param {string} schema - The original schema for context
73096
- * @param {Object} validationResult - Validation result with error details
73097
- * @param {number} attemptNumber - Current attempt number (for logging)
73098
- * @returns {Promise<string>} - The corrected JSON
73099
- */
73100
- async fixJson(invalidJson, schema, validationResult, attemptNumber = 1) {
73101
- await this.initializeAgent();
73102
- let errorContext = validationResult.error;
73103
- if (validationResult.enhancedError) {
73104
- errorContext = validationResult.enhancedError;
73105
- }
73106
- let schemaErrorDetails = "";
73107
- if (validationResult.errorSummary) {
73108
- schemaErrorDetails = `
73109
-
73110
- Schema Validation Errors:
73111
- ${validationResult.errorSummary}`;
73112
- } else if (validationResult.schemaErrors && validationResult.schemaErrors.length > 0) {
73113
- const errors = validationResult.schemaErrors.map((err) => {
73114
- const path9 = err.instancePath || "(root)";
73115
- return ` ${path9}: ${err.message}`;
73116
- }).join("\n");
73117
- schemaErrorDetails = `
73118
-
73119
- Schema Validation Errors:
73120
- ${errors}`;
73121
- }
73122
- const prompt = `Fix the following invalid JSON.
73123
-
73124
- Error: ${errorContext}${schemaErrorDetails}
73125
-
73126
- Invalid JSON:
73127
- ${invalidJson}
73128
-
73129
- Expected schema structure:
73130
- ${schema}
73131
-
73132
- ${schemaErrorDetails ? "CRITICAL: Pay special attention to the schema validation errors above. The JSON may be syntactically valid but does not conform to the required schema. Make sure to:\n- Include all required fields\n- Use correct data types\n- Remove any additional properties not defined in the schema (if additionalProperties is false)\n- Ensure all values match their schema constraints\n\n" : ""}Provide only the corrected JSON without any markdown formatting or explanations.`;
73133
- try {
73134
- if (this.options.debug) {
73135
- console.log(`[DEBUG] JSON fixing: Attempt ${attemptNumber} to fix JSON with separate agent`);
73136
- }
73137
- const result = await this.agent.answer(prompt, []);
73138
- const cleaned = cleanSchemaResponse(result);
73139
- if (this.options.debug) {
73140
- console.log(`[DEBUG] JSON fixing: Agent returned ${cleaned.length} chars`);
73141
- }
73142
- return cleaned;
73143
- } catch (error40) {
73144
- if (this.options.debug) {
73145
- console.error(`[DEBUG] JSON fixing failed: ${error40.message}`);
73146
- }
73147
- throw new Error(`Failed to fix JSON: ${error40.message}`);
73148
- }
73149
- }
73150
- /**
73151
- * Get token usage information from the specialized agent
73152
- * @returns {Object} - Token usage statistics
73153
- */
73154
- getTokenUsage() {
73155
- return this.agent ? this.agent.getTokenUsage() : null;
73156
- }
73157
- /**
73158
- * Cancel any ongoing operations
73159
- */
73160
- cancel() {
73161
- if (this.agent) {
73162
- this.agent.cancel();
73163
- }
73164
- }
73165
- };
73166
72775
  MermaidFixingAgent = class {
73167
72776
  constructor(options = {}) {
73168
72777
  this.ProbeAgent = null;
@@ -73406,7 +73015,7 @@ When reviewing code:
73406
73015
  "code-review-template": `You are going to perform code review according to provided user rules. Ensure to review only code provided in diff and latest commit, if provided. However you still need to fully understand how modified code works, and read dependencies if something is not clear.`,
73407
73016
  "engineer": `You are a senior engineer focused on software architecture and design.
73408
73017
  Before jumping on the task you first analyse the user request in detail, and try to provide an elegant and concise solution.
73409
- If the solution is clear, you can jump to implementation right away. If not, ask the user a clarification question by calling the attempt_completion tool with the required details.
73018
+ If the solution is clear, you can jump to implementation right away. If not, ask the user a clarification question with the required details.
73410
73019
 
73411
73020
  # Tone and Style
73412
73021
  - Be concise and direct. Explain your approach briefly before implementing, then let the code speak for itself.
@@ -73429,7 +73038,7 @@ If the solution is clear, you can jump to implementation right away. If not, ask
73429
73038
  When the request has **multiple distinct goals** (e.g. "Fix bug A AND add feature B"), use the task tool to track them:
73430
73039
  - Call the task tool with action="create" and a tasks array. Each task must have an "id" field.
73431
73040
  - Update task status to "in_progress" when starting and "completed" when done.
73432
- - All tasks must be completed or cancelled before calling attempt_completion.
73041
+ - All tasks must be completed or cancelled before providing your final answer.
73433
73042
  - Stay flexible \u2014 add, remove, or reorganize tasks as your understanding changes.
73434
73043
 
73435
73044
  Do NOT create tasks for single-goal requests, even complex ones. Multiple internal steps for one goal (search, read, analyze, implement) do not need tasks.
@@ -82686,9 +82295,15 @@ function messageContainsCompletion(msg) {
82686
82295
  }
82687
82296
  if (Array.isArray(msg.content)) {
82688
82297
  if (msg.content.some((p) => p.type === "tool-call" && p.toolName === "attempt_completion")) return true;
82298
+ const hasToolCalls = msg.content.some((p) => p.type === "tool-call");
82299
+ const hasText = msg.content.some((p) => p.type === "text" && p.text?.trim());
82300
+ if (!hasToolCalls && hasText) return true;
82689
82301
  }
82690
82302
  const text = typeof msg.content === "string" ? msg.content : "";
82691
- return text.includes("attempt_completion");
82303
+ if (text.includes("attempt_completion")) return true;
82304
+ const hasNoToolCalls = !Array.isArray(msg.toolInvocations) && !Array.isArray(msg.tool_calls);
82305
+ if (hasNoToolCalls && text.trim().length > 0) return true;
82306
+ return false;
82692
82307
  }
82693
82308
  function identifyMessageSegments(messages) {
82694
82309
  const segments = [];
@@ -96738,8 +96353,8 @@ function debugTruncate(s, limit = 200) {
96738
96353
  function debugLogToolResults(toolResults) {
96739
96354
  if (!toolResults || toolResults.length === 0) return;
96740
96355
  for (const tr of toolResults) {
96741
- const argsStr = JSON.stringify(tr.args || {});
96742
- const resultStr = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result || "");
96356
+ const argsStr = tr.args != null ? JSON.stringify(tr.args) : "<no args>";
96357
+ const resultStr = tr.result != null ? typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result) : "<no result>";
96743
96358
  console.log(`[DEBUG] tool: ${tr.toolName} | args: ${debugTruncate(argsStr)} | result: ${debugTruncate(resultStr)}`);
96744
96359
  }
96745
96360
  }
@@ -96846,7 +96461,7 @@ var init_ProbeAgent = __esm({
96846
96461
  * @param {Array<Object>} [options.fallback.providers] - List of provider configurations for custom fallback
96847
96462
  * @param {boolean} [options.fallback.stopOnSuccess=true] - Stop on first success
96848
96463
  * @param {number} [options.fallback.maxTotalAttempts=10] - Maximum total attempts across all providers
96849
- * @param {string} [options.completionPrompt] - Custom prompt to run after attempt_completion for validation/review (runs before mermaid/JSON validation)
96464
+ * @param {string} [options.completionPrompt] - Custom prompt to run after completion for validation/review (runs before mermaid/JSON validation)
96850
96465
  * @param {number} [options.maxOutputTokens] - Maximum tokens for tool output before truncation (default: 20000, can also be set via PROBE_MAX_OUTPUT_TOKENS env var)
96851
96466
  * @param {number} [options.requestTimeout] - Timeout in ms for AI requests (default: 120000 or REQUEST_TIMEOUT env var). Used to abort hung requests.
96852
96467
  * @param {number} [options.maxOperationTimeout] - Maximum timeout in ms for the entire operation including all retries and fallbacks (default: 300000 or MAX_OPERATION_TIMEOUT env var). This is the absolute maximum time for streamTextWithRetryAndFallback.
@@ -97998,12 +97613,11 @@ var init_ProbeAgent = __esm({
97998
97613
  * - Delegate tool param injection
97999
97614
  *
98000
97615
  * @param {Object} options - Options from the answer() call
98001
- * @param {Function} onComplete - Callback when attempt_completion is called (receives result string)
98002
97616
  * @param {Object} context - Execution context { maxIterations, currentMessages }
98003
97617
  * @returns {Object} Tools object for streamText()
98004
97618
  * @private
98005
97619
  */
98006
- _buildNativeTools(options, onComplete, context = {}) {
97620
+ _buildNativeTools(options, context = {}) {
98007
97621
  const { maxIterations = 30 } = context;
98008
97622
  const nativeTools = {};
98009
97623
  const isToolAllowed = (toolName) => this.allowedTools.isEnabled(toolName);
@@ -98153,16 +97767,6 @@ var init_ProbeAgent = __esm({
98153
97767
  });
98154
97768
  };
98155
97769
  if (options._disableTools) {
98156
- nativeTools.attempt_completion = (0, import_ai4.tool)({
98157
- description: "Signal task completion and provide the final result to the user",
98158
- inputSchema: external_exports2.object({
98159
- result: external_exports2.string().describe("The final result to present to the user")
98160
- }),
98161
- execute: async ({ result }) => {
98162
- onComplete(result);
98163
- return result;
98164
- }
98165
- });
98166
97770
  return nativeTools;
98167
97771
  }
98168
97772
  for (const [toolName, toolImpl] of Object.entries(this.toolImplementations)) {
@@ -98173,28 +97777,6 @@ var init_ProbeAgent = __esm({
98173
97777
  nativeTools[toolName] = wrapTool(toolName, schema, description, toolImpl.execute);
98174
97778
  }
98175
97779
  }
98176
- nativeTools.attempt_completion = (0, import_ai4.tool)({
98177
- description: "Signal task completion and provide the final result to the user",
98178
- inputSchema: external_exports2.object({
98179
- result: external_exports2.string().describe("The final result to present to the user")
98180
- }),
98181
- execute: async ({ result }) => {
98182
- if (this.enableTasks && this.taskManager && this.taskManager.hasIncompleteTasks()) {
98183
- const incompleteTasks = this.taskManager.getIncompleteTasks();
98184
- const highIterationCount = (context.currentIteration || 0) > maxIterations * 0.7;
98185
- if (!highIterationCount) {
98186
- const taskSummary = this.taskManager.getTaskSummary();
98187
- const blockedMessage = createTaskCompletionBlockedMessage(taskSummary);
98188
- if (this.debug) {
98189
- console.log("[DEBUG] Task checkpoint: Blocking completion due to incomplete tasks");
98190
- }
98191
- return blockedMessage;
98192
- }
98193
- }
98194
- onComplete(result);
98195
- return result;
98196
- }
98197
- });
98198
97780
  if (this.mcpBridge && !options._disableTools) {
98199
97781
  const mcpTools = this.mcpBridge.getVercelTools(this._filterMcpTools(this.mcpBridge.getToolNames()));
98200
97782
  for (const [name15, mcpTool] of Object.entries(mcpTools)) {
@@ -99078,7 +98660,7 @@ Follow these instructions carefully:
99078
98660
  2. Use the available tools step-by-step to fulfill the request.
99079
98661
  3. You should always prefer the search tool for code-related questions.${this.searchDelegate ? " Ask natural language questions \u2014 the search subagent handles keyword formulation and returns extracted code blocks. Use extract only to expand context or read full files." : " Search handles stemming and case variations automatically \u2014 do NOT try keyword variations manually. Read full files only if really necessary."}
99080
98662
  4. Ensure to get really deep and understand the full picture before answering.
99081
- 5. Once the task is fully completed, use the attempt_completion tool to provide the final result.
98663
+ 5. Once the task is fully completed, provide your final answer directly as text.
99082
98664
  6. ${this.searchDelegate ? "Ask clear, specific questions when searching. Each search should target a distinct concept or question." : "Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results."}
99083
98665
  7. NEVER use bash for code exploration (no grep, cat, find, head, tail, awk, sed) \u2014 always use search and extract tools instead. Bash is only for system operations like building, running tests, or git commands.${this.allowEdit ? `
99084
98666
  7. When modifying files, choose the appropriate tool:
@@ -99256,7 +98838,7 @@ You are working with a workspace. Available paths: ${workspaceDesc}
99256
98838
  });
99257
98839
  const systemMessage = await this.getSystemMessage();
99258
98840
  let userMessage = { role: "user", content: message.trim() };
99259
- if (options.schema && !options._schemaFormatted) {
98841
+ if (options.schema && !options._schemaFormatted && !options._disableTools) {
99260
98842
  const schemaInstructions = generateSchemaInstructions(options.schema, { debug: this.debug });
99261
98843
  userMessage.content = message.trim() + schemaInstructions;
99262
98844
  }
@@ -99289,7 +98871,6 @@ You are working with a workspace. Available paths: ${workspaceDesc}
99289
98871
  ];
99290
98872
  }
99291
98873
  let currentIteration = 0;
99292
- let completionAttempted = false;
99293
98874
  let finalResult = "I was unable to complete your request due to reaching the maximum number of tool iterations.";
99294
98875
  const baseMaxIterations = options._maxIterationsOverride || this.maxIterations || MAX_TOOL_ITERATIONS;
99295
98876
  const maxIterations = options._maxIterationsOverride ? baseMaxIterations : options.schema ? baseMaxIterations + 4 : baseMaxIterations;
@@ -99405,12 +98986,8 @@ You are working with a workspace. Available paths: ${workspaceDesc}
99405
98986
  console.log(`[DEBUG] Schema provided, using extended iteration limit: ${maxIterations} (base: ${baseMaxIterations})`);
99406
98987
  }
99407
98988
  }
99408
- let completionResult = null;
99409
98989
  const toolContext = { maxIterations, currentIteration: 0, currentMessages };
99410
- const tools2 = this._buildNativeTools(options, (result) => {
99411
- completionResult = result;
99412
- completionAttempted = true;
99413
- }, toolContext);
98990
+ const tools2 = this._buildNativeTools(options, toolContext);
99414
98991
  if (this.debug) {
99415
98992
  const toolNames = Object.keys(tools2);
99416
98993
  console.log(`[DEBUG] Agent tools registered (${toolNames.length}): ${toolNames.join(", ")}`);
@@ -99424,6 +99001,8 @@ You are working with a workspace. Available paths: ${workspaceDesc}
99424
99001
  maxResponseTokens = 32e3;
99425
99002
  }
99426
99003
  }
99004
+ let completionPromptInjected = false;
99005
+ let preCompletionResult = null;
99427
99006
  let compactionAttempted = false;
99428
99007
  while (true) {
99429
99008
  try {
@@ -99432,19 +99011,103 @@ You are working with a workspace. Available paths: ${workspaceDesc}
99432
99011
  model: this.provider ? this.provider(this.model) : this.model,
99433
99012
  messages: messagesForAI,
99434
99013
  tools: tools2,
99435
- stopWhen: (0, import_ai4.stepCountIs)(maxIterations),
99014
+ stopWhen: ({ steps }) => {
99015
+ if (steps.length >= maxIterations) return true;
99016
+ const lastStep = steps[steps.length - 1];
99017
+ const modelWantsToStop = lastStep?.finishReason === "stop" && (!lastStep?.toolCalls || lastStep.toolCalls.length === 0);
99018
+ if (modelWantsToStop) {
99019
+ if (this.enableTasks && this.taskManager?.hasIncompleteTasks()) {
99020
+ const highIterationCount = steps.length > maxIterations * 0.7;
99021
+ if (!highIterationCount) return false;
99022
+ }
99023
+ if (this.completionPrompt && !options._completionPromptProcessed && !completionPromptInjected) {
99024
+ preCompletionResult = lastStep.text || null;
99025
+ return false;
99026
+ }
99027
+ }
99028
+ let trailingNoTool = 0;
99029
+ for (let i = steps.length - 1; i >= 0; i--) {
99030
+ if (!steps[i].toolCalls?.length) trailingNoTool++;
99031
+ else break;
99032
+ }
99033
+ if (trailingNoTool >= 5) return true;
99034
+ if (trailingNoTool >= 3) {
99035
+ const recentTexts = steps.slice(-3).map((s) => s.text);
99036
+ if (recentTexts.every((t) => t && t === recentTexts[0])) return true;
99037
+ if (recentTexts.every((t) => detectStuckResponse(t))) return true;
99038
+ }
99039
+ return false;
99040
+ },
99041
+ prepareStep: ({ steps, stepNumber }) => {
99042
+ if (stepNumber === maxIterations - 1) {
99043
+ return {
99044
+ toolChoice: "none"
99045
+ };
99046
+ }
99047
+ const lastStep = steps[steps.length - 1];
99048
+ const modelJustStopped = lastStep?.finishReason === "stop" && (!lastStep?.toolCalls || lastStep.toolCalls.length === 0);
99049
+ if (modelJustStopped) {
99050
+ if (this.enableTasks && this.taskManager?.hasIncompleteTasks()) {
99051
+ const taskSummary = this.taskManager.getTaskSummary();
99052
+ const blockedMessage = createTaskCompletionBlockedMessage(taskSummary);
99053
+ return {
99054
+ userMessage: blockedMessage
99055
+ };
99056
+ }
99057
+ if (this.completionPrompt && !options._completionPromptProcessed && !completionPromptInjected) {
99058
+ completionPromptInjected = true;
99059
+ const resultToReview = lastStep.text || preCompletionResult || "";
99060
+ if (this.debug) {
99061
+ console.log("[DEBUG] Injecting completion prompt into main loop via prepareStep...");
99062
+ }
99063
+ if (this.tracer) {
99064
+ this.tracer.recordEvent("completion_prompt.started", {
99065
+ "completion_prompt.original_result_length": resultToReview.length
99066
+ });
99067
+ }
99068
+ const completionPromptMessage = `${this.completionPrompt}
99069
+
99070
+ Here is the result to review:
99071
+ <result>
99072
+ ${resultToReview}
99073
+ </result>
99074
+
99075
+ Double-check your response based on the criteria above. If everything looks good, respond with your previous answer exactly as-is. If something needs to be fixed or is missing, do it now, then respond with the COMPLETE updated answer (everything you did in total, not just the fix).`;
99076
+ return {
99077
+ userMessage: completionPromptMessage
99078
+ };
99079
+ }
99080
+ }
99081
+ return void 0;
99082
+ },
99436
99083
  maxTokens: maxResponseTokens,
99437
99084
  temperature: 0.3,
99438
- onStepFinish: ({ toolResults, text, finishReason, usage }) => {
99085
+ onStepFinish: (stepResult) => {
99086
+ const { toolResults, toolCalls, text, reasoningText, finishReason, usage } = stepResult;
99439
99087
  currentIteration++;
99440
99088
  toolContext.currentIteration = currentIteration;
99441
99089
  if (this.tracer) {
99442
- this.tracer.addEvent("iteration.step", {
99090
+ const stepEvent = {
99443
99091
  "iteration": currentIteration,
99444
99092
  "max_iterations": maxIterations,
99445
99093
  "finish_reason": finishReason,
99446
99094
  "has_tool_calls": !!(toolResults && toolResults.length > 0)
99447
- });
99095
+ };
99096
+ if (text) {
99097
+ stepEvent["ai.text"] = text.substring(0, 1e4);
99098
+ stepEvent["ai.text.length"] = text.length;
99099
+ }
99100
+ if (reasoningText) {
99101
+ stepEvent["ai.reasoning"] = reasoningText.substring(0, 1e4);
99102
+ stepEvent["ai.reasoning.length"] = reasoningText.length;
99103
+ }
99104
+ if (toolCalls && toolCalls.length > 0) {
99105
+ stepEvent["ai.tool_calls"] = toolCalls.map((tc) => ({
99106
+ name: tc.toolName,
99107
+ args: JSON.stringify(tc.args || {}).substring(0, 2e3)
99108
+ }));
99109
+ }
99110
+ this.tracer.addEvent("iteration.step", stepEvent);
99448
99111
  }
99449
99112
  if (usage) {
99450
99113
  this.tokenCounter.recordUsage(usage);
@@ -99454,10 +99117,32 @@ You are working with a workspace. Available paths: ${workspaceDesc}
99454
99117
  }
99455
99118
  if (this.debug) {
99456
99119
  console.log(`[DEBUG] Step ${currentIteration}/${maxIterations} finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
99120
+ if (text) {
99121
+ console.log(`[DEBUG] model text: ${debugTruncate(text)}`);
99122
+ }
99123
+ if (reasoningText) {
99124
+ console.log(`[DEBUG] reasoning: ${debugTruncate(reasoningText)}`);
99125
+ }
99457
99126
  debugLogToolResults(toolResults);
99458
99127
  }
99459
99128
  }
99460
99129
  };
99130
+ const hasActiveTools = Object.keys(tools2).length > 0;
99131
+ if (options.schema && !hasActiveTools) {
99132
+ try {
99133
+ const parsedSchema = typeof options.schema === "string" ? JSON.parse(options.schema) : options.schema;
99134
+ if (isJsonSchema(options.schema)) {
99135
+ streamOptions.output = import_ai4.Output.object({ schema: (0, import_ai4.jsonSchema)(parsedSchema) });
99136
+ if (this.debug) {
99137
+ console.log(`[DEBUG] Native JSON schema output enabled (no active tools)`);
99138
+ }
99139
+ }
99140
+ } catch (e) {
99141
+ if (this.debug) {
99142
+ console.log(`[DEBUG] Failed to set native JSON schema output: ${e.message}`);
99143
+ }
99144
+ }
99145
+ }
99461
99146
  const providerOpts = this._buildThinkingProviderOptions(maxResponseTokens);
99462
99147
  if (providerOpts) {
99463
99148
  streamOptions.providerOptions = providerOpts;
@@ -99467,7 +99152,7 @@ You are working with a workspace. Available paths: ${workspaceDesc}
99467
99152
  const finalText = await result.text;
99468
99153
  if (this.debug) {
99469
99154
  const steps = await result.steps;
99470
- console.log(`[DEBUG] streamText completed: ${steps?.length || 0} steps, finalText=${finalText?.length || 0} chars, completion=${!!completionResult}`);
99155
+ console.log(`[DEBUG] streamText completed: ${steps?.length || 0} steps, finalText=${finalText?.length || 0} chars`);
99471
99156
  }
99472
99157
  const usage = await result.usage;
99473
99158
  if (usage) {
@@ -99491,18 +99176,24 @@ You are working with a workspace. Available paths: ${workspaceDesc}
99491
99176
  } else {
99492
99177
  aiResult = await executeAIRequest();
99493
99178
  }
99494
- if (completionResult) {
99495
- finalResult = completionResult;
99496
- if (options.onStream && finalResult) {
99497
- const chunkSize = 50;
99498
- for (let i = 0; i < finalResult.length; i += chunkSize) {
99499
- const chunk = finalResult.slice(i, Math.min(i + chunkSize, finalResult.length));
99500
- options.onStream(chunk);
99179
+ if (options.schema && streamOptions.output) {
99180
+ try {
99181
+ const outputObject = await aiResult.result.output;
99182
+ if (outputObject) {
99183
+ finalResult = JSON.stringify(outputObject);
99184
+ } else if (aiResult.finalText) {
99185
+ finalResult = aiResult.finalText;
99186
+ }
99187
+ } catch (e) {
99188
+ if (this.debug) {
99189
+ console.log(`[DEBUG] Native JSON output failed, falling back to text: ${e.message}`);
99190
+ }
99191
+ if (aiResult.finalText) {
99192
+ finalResult = aiResult.finalText;
99501
99193
  }
99502
99194
  }
99503
99195
  } else if (aiResult.finalText) {
99504
99196
  finalResult = aiResult.finalText;
99505
- completionAttempted = true;
99506
99197
  }
99507
99198
  const resultMessages = await aiResult.result.response?.messages;
99508
99199
  if (resultMessages) {
@@ -99510,6 +99201,75 @@ You are working with a workspace. Available paths: ${workspaceDesc}
99510
99201
  currentMessages.push(msg);
99511
99202
  }
99512
99203
  }
99204
+ if (this.completionPrompt && !options._completionPromptProcessed && !completionPromptInjected && finalResult) {
99205
+ completionPromptInjected = true;
99206
+ preCompletionResult = finalResult;
99207
+ if (this.debug) {
99208
+ console.log("[DEBUG] Injecting completion prompt as post-streamText follow-up pass...");
99209
+ }
99210
+ if (this.tracer) {
99211
+ this.tracer.recordEvent("completion_prompt.started", {
99212
+ "completion_prompt.original_result_length": finalResult.length
99213
+ });
99214
+ }
99215
+ const completionPromptMessage = `${this.completionPrompt}
99216
+
99217
+ Here is the result to review:
99218
+ <result>
99219
+ ${finalResult}
99220
+ </result>
99221
+
99222
+ Double-check your response based on the criteria above. If everything looks good, respond with your previous answer exactly as-is. If something needs to be fixed or is missing, do it now, then respond with the COMPLETE updated answer (everything you did in total, not just the fix).`;
99223
+ currentMessages.push({ role: "user", content: completionPromptMessage });
99224
+ const completionMaxIterations = 5;
99225
+ const completionStreamOptions = {
99226
+ model: this.provider ? this.provider(this.model) : this.model,
99227
+ messages: this.prepareMessagesWithImages(currentMessages),
99228
+ tools: tools2,
99229
+ stopWhen: (0, import_ai4.stepCountIs)(completionMaxIterations),
99230
+ maxTokens: maxResponseTokens,
99231
+ temperature: 0.3,
99232
+ onStepFinish: ({ toolResults, text, finishReason, usage }) => {
99233
+ if (usage) {
99234
+ this.tokenCounter.recordUsage(usage);
99235
+ }
99236
+ if (options.onStream && text) {
99237
+ options.onStream(text);
99238
+ }
99239
+ if (this.debug) {
99240
+ console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
99241
+ }
99242
+ }
99243
+ };
99244
+ const providerOpts2 = this._buildThinkingProviderOptions(maxResponseTokens);
99245
+ if (providerOpts2) {
99246
+ completionStreamOptions.providerOptions = providerOpts2;
99247
+ }
99248
+ try {
99249
+ const cpResult = await this.streamTextWithRetryAndFallback(completionStreamOptions);
99250
+ const cpFinalText = await cpResult.text;
99251
+ const cpUsage = await cpResult.usage;
99252
+ if (cpUsage) {
99253
+ this.tokenCounter.recordUsage(cpUsage, cpResult.experimental_providerMetadata);
99254
+ }
99255
+ const cpMessages = await cpResult.response?.messages;
99256
+ if (cpMessages) {
99257
+ for (const msg of cpMessages) {
99258
+ currentMessages.push(msg);
99259
+ }
99260
+ }
99261
+ if (cpFinalText && cpFinalText.trim().length > 0) {
99262
+ finalResult = cpFinalText;
99263
+ }
99264
+ if (this.debug) {
99265
+ console.log(`[DEBUG] Completion prompt follow-up produced ${cpFinalText?.length || 0} chars (using ${cpFinalText && cpFinalText.trim().length > 0 ? "updated" : "original"} result)`);
99266
+ }
99267
+ } catch (cpError) {
99268
+ if (this.debug) {
99269
+ console.log(`[DEBUG] Completion prompt follow-up failed: ${cpError.message}, keeping original result`);
99270
+ }
99271
+ }
99272
+ }
99513
99273
  break;
99514
99274
  } catch (error40) {
99515
99275
  if (!compactionAttempted && handleContextLimitError) {
@@ -99539,17 +99299,13 @@ You are working with a workspace. Available paths: ${workspaceDesc}
99539
99299
  continue;
99540
99300
  }
99541
99301
  }
99542
- if (completionResult) {
99543
- finalResult = completionResult;
99544
- break;
99545
- }
99546
99302
  console.error(`Error during streamText:`, error40);
99547
99303
  finalResult = `Error: Failed to get response from AI model. ${error40.message}`;
99548
99304
  throw new Error(finalResult);
99549
99305
  }
99550
99306
  }
99551
- if (currentIteration >= maxIterations && !completionAttempted) {
99552
- console.warn(`[WARN] Max tool iterations (${maxIterations}) reached for session ${this.sessionId}. Returning current error state.`);
99307
+ if (currentIteration >= maxIterations) {
99308
+ console.warn(`[WARN] Max tool iterations (${maxIterations}) reached for session ${this.sessionId}.`);
99553
99309
  }
99554
99310
  this.history = currentMessages.map((msg) => ({ ...msg }));
99555
99311
  if (this.history.length > MAX_HISTORY_MESSAGES) {
@@ -99572,279 +99328,17 @@ You are working with a workspace. Available paths: ${workspaceDesc}
99572
99328
  } catch (error40) {
99573
99329
  console.error(`[ERROR] Failed to save messages to storage:`, error40);
99574
99330
  }
99575
- if (completionAttempted && this.completionPrompt && !options._completionPromptProcessed) {
99576
- if (this.debug) {
99577
- console.log("[DEBUG] Running completion prompt as continuation of current session...");
99578
- }
99579
- try {
99580
- const originalResult = finalResult;
99581
- if (this.tracer) {
99582
- this.tracer.recordEvent("completion_prompt.started", {
99583
- "completion_prompt.original_result_length": finalResult?.length || 0
99584
- });
99585
- }
99586
- const completionPromptMessage = `${this.completionPrompt}
99587
-
99588
- Here is the result to review:
99589
- <result>
99590
- ${finalResult}
99591
- </result>
99592
-
99593
- Double-check your response based on the criteria above. If everything looks good, respond with your previous answer exactly as-is using attempt_completion. If something needs to be fixed or is missing, do it now, then respond with the COMPLETE updated answer (everything you did in total, not just the fix) using attempt_completion.`;
99594
- currentMessages.push({ role: "user", content: completionPromptMessage });
99595
- completionResult = null;
99596
- completionAttempted = false;
99597
- const completionMaxIterations = 5;
99598
- const completionStreamOptions = {
99599
- model: this.provider ? this.provider(this.model) : this.model,
99600
- messages: this.prepareMessagesWithImages(currentMessages),
99601
- tools: tools2,
99602
- stopWhen: (0, import_ai4.stepCountIs)(completionMaxIterations),
99603
- maxTokens: maxResponseTokens,
99604
- temperature: 0.3,
99605
- onStepFinish: ({ toolResults, text, finishReason, usage }) => {
99606
- if (usage) {
99607
- this.tokenCounter.recordUsage(usage);
99608
- }
99609
- if (options.onStream && text) {
99610
- options.onStream(text);
99611
- }
99612
- if (this.debug) {
99613
- console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
99614
- debugLogToolResults(toolResults);
99615
- }
99616
- }
99617
- };
99618
- const providerOpts = this._buildThinkingProviderOptions(maxResponseTokens);
99619
- if (providerOpts) {
99620
- completionStreamOptions.providerOptions = providerOpts;
99621
- }
99622
- const cpResult = await this.streamTextWithRetryAndFallback(completionStreamOptions);
99623
- const cpFinalText = await cpResult.text;
99624
- const cpUsage = await cpResult.usage;
99625
- if (cpUsage) {
99626
- this.tokenCounter.recordUsage(cpUsage, cpResult.experimental_providerMetadata);
99627
- }
99628
- const cpMessages = await cpResult.response?.messages;
99629
- if (cpMessages) {
99630
- for (const msg of cpMessages) {
99631
- currentMessages.push(msg);
99632
- }
99633
- }
99634
- if (completionResult) {
99635
- finalResult = completionResult;
99636
- completionAttempted = true;
99637
- } else if (cpFinalText && cpFinalText.trim().length > 0) {
99638
- finalResult = cpFinalText;
99639
- completionAttempted = true;
99640
- } else {
99641
- finalResult = originalResult;
99642
- completionAttempted = true;
99643
- if (this.debug) {
99644
- console.log("[DEBUG] Completion prompt returned empty result, keeping original.");
99645
- }
99646
- }
99647
- if (this.debug) {
99648
- console.log(`[DEBUG] Completion prompt finished. Final result length: ${finalResult?.length || 0}`);
99649
- }
99650
- if (this.tracer) {
99651
- this.tracer.recordEvent("completion_prompt.completed", {
99652
- "completion_prompt.final_result_length": finalResult?.length || 0,
99653
- "completion_prompt.used_original": finalResult === originalResult
99654
- });
99655
- }
99656
- } catch (error40) {
99657
- console.error("[ERROR] Completion prompt failed:", error40);
99658
- if (this.tracer) {
99659
- this.tracer.recordEvent("completion_prompt.error", {
99660
- "completion_prompt.error": error40.message
99661
- });
99662
- }
99663
- }
99331
+ if (completionPromptInjected && this.tracer) {
99332
+ this.tracer.recordEvent("completion_prompt.completed", {
99333
+ "completion_prompt.final_result_length": finalResult?.length || 0,
99334
+ "completion_prompt.used_original": preCompletionResult && finalResult === preCompletionResult
99335
+ });
99664
99336
  }
99665
- const reachedMaxIterations = currentIteration >= maxIterations && !completionAttempted;
99666
- if (options.schema && !options._schemaFormatted && !completionAttempted && !reachedMaxIterations) {
99667
- if (this.debug) {
99668
- console.log("[DEBUG] Schema provided, applying automatic formatting...");
99669
- }
99337
+ if (options.schema && !options._schemaFormatted && !options._skipValidation) {
99670
99338
  try {
99671
- const schemaPrompt = `CRITICAL: You MUST respond with ONLY valid JSON DATA that conforms to this schema structure. DO NOT return the schema definition itself.
99672
-
99673
- Schema to follow (this is just the structure - provide ACTUAL DATA):
99674
- ${options.schema}
99675
-
99676
- REQUIREMENTS:
99677
- - Return ONLY the JSON object/array with REAL DATA that matches the schema structure
99678
- - DO NOT return the schema definition itself (no "$schema", "$id", "type", "properties", etc.)
99679
- - NO additional text, explanations, or markdown formatting
99680
- - NO code blocks or backticks
99681
- - The JSON must be parseable by JSON.parse()
99682
- - Fill in actual values that make sense based on your previous response content
99683
-
99684
- EXAMPLE:
99685
- If schema defines {type: "object", properties: {name: {type: "string"}, age: {type: "number"}}}
99686
- Return: {"name": "John Doe", "age": 25}
99687
- NOT: {"type": "object", "properties": {"name": {"type": "string"}}}
99688
-
99689
- Convert your previous response content into actual JSON data that follows this schema structure.`;
99690
- finalResult = await this.answer(schemaPrompt, [], {
99691
- ...options,
99692
- _schemaFormatted: true,
99693
- _completionPromptProcessed: true
99694
- // Prevent cascading completion prompts in retry calls
99695
- });
99696
99339
  if (!this.disableMermaidValidation) {
99697
- try {
99698
- if (this.debug) {
99699
- console.log(`[DEBUG] Mermaid validation: Starting enhanced mermaid validation...`);
99700
- }
99701
- if (this.tracer) {
99702
- this.tracer.recordMermaidValidationEvent("schema_processing_started", {
99703
- "mermaid_validation.context": "schema_processing",
99704
- "mermaid_validation.response_length": finalResult.length
99705
- });
99706
- }
99707
- const mermaidValidation = await validateAndFixMermaidResponse(finalResult, {
99708
- debug: this.debug,
99709
- path: this.workspaceRoot || this.allowedFolders[0],
99710
- provider: this.clientApiProvider,
99711
- model: this.model,
99712
- tracer: this.tracer
99713
- });
99714
- if (mermaidValidation.wasFixed) {
99715
- finalResult = mermaidValidation.fixedResponse;
99716
- if (this.debug) {
99717
- console.log(`[DEBUG] Mermaid validation: Diagrams successfully fixed`);
99718
- if (mermaidValidation.performanceMetrics) {
99719
- const metrics = mermaidValidation.performanceMetrics;
99720
- console.log(`[DEBUG] Mermaid validation: Performance - total: ${metrics.totalTimeMs}ms, AI fixing: ${metrics.aiFixingTimeMs}ms`);
99721
- console.log(`[DEBUG] Mermaid validation: Results - ${metrics.diagramsFixed}/${metrics.diagramsProcessed} diagrams fixed`);
99722
- }
99723
- if (mermaidValidation.fixingResults) {
99724
- mermaidValidation.fixingResults.forEach((fixResult, index) => {
99725
- if (fixResult.wasFixed) {
99726
- const method = fixResult.fixedWithHtmlDecoding ? "HTML entity decoding" : "AI correction";
99727
- const time3 = fixResult.aiFixingTimeMs ? ` in ${fixResult.aiFixingTimeMs}ms` : "";
99728
- console.log(`[DEBUG] Mermaid validation: Fixed diagram ${fixResult.diagramIndex + 1} with ${method}${time3}`);
99729
- console.log(`[DEBUG] Mermaid validation: Original error: ${fixResult.originalError}`);
99730
- } else {
99731
- console.log(`[DEBUG] Mermaid validation: Failed to fix diagram ${fixResult.diagramIndex + 1}: ${fixResult.fixingError}`);
99732
- }
99733
- });
99734
- }
99735
- }
99736
- } else if (this.debug) {
99737
- console.log(`[DEBUG] Mermaid validation: No fixes needed or fixes unsuccessful`);
99738
- if (mermaidValidation.diagrams?.length > 0) {
99739
- console.log(`[DEBUG] Mermaid validation: Found ${mermaidValidation.diagrams.length} diagrams, all valid: ${mermaidValidation.isValid}`);
99740
- }
99741
- }
99742
- } catch (error40) {
99743
- if (this.debug) {
99744
- console.log(`[DEBUG] Mermaid validation: Process failed with error: ${error40.message}`);
99745
- console.log(`[DEBUG] Mermaid validation: Stack trace: ${error40.stack}`);
99746
- }
99747
- }
99748
- } else if (this.debug) {
99749
- console.log(`[DEBUG] Mermaid validation: Skipped due to disableMermaidValidation option`);
99750
- }
99751
- finalResult = cleanSchemaResponse(finalResult);
99752
- if (isJsonSchema(options.schema)) {
99753
99340
  if (this.debug) {
99754
- console.log(`[DEBUG] JSON validation: Starting validation process for schema response`);
99755
- console.log(`[DEBUG] JSON validation: Cleaned response length: ${finalResult.length} chars`);
99756
- }
99757
- if (this.tracer) {
99758
- this.tracer.recordJsonValidationEvent("started", {
99759
- "json_validation.response_length": finalResult.length,
99760
- "json_validation.schema_type": "JSON"
99761
- });
99762
- }
99763
- let validation = validateJsonResponse(finalResult, { debug: this.debug, schema: options.schema });
99764
- let retryCount = 0;
99765
- const maxRetries = 3;
99766
- if (validation.isValid && isJsonSchemaDefinition(finalResult, { debug: this.debug })) {
99767
- if (this.debug) {
99768
- console.log(`[DEBUG] JSON validation: Response is a JSON schema definition instead of data, needs correction...`);
99769
- }
99770
- validation = {
99771
- isValid: false,
99772
- error: "Response is a JSON schema definition instead of actual data",
99773
- enhancedError: "Response is a JSON schema definition instead of actual data. Please return data that conforms to the schema, not the schema itself."
99774
- };
99775
- }
99776
- if (!validation.isValid) {
99777
- if (this.debug) {
99778
- console.log(`[DEBUG] JSON validation: Starting separate JsonFixingAgent session...`);
99779
- }
99780
- const { JsonFixingAgent: JsonFixingAgent2 } = await Promise.resolve().then(() => (init_schemaUtils(), schemaUtils_exports));
99781
- const jsonFixer = new JsonFixingAgent2({
99782
- path: this.workspaceRoot || this.allowedFolders[0],
99783
- provider: this.clientApiProvider,
99784
- model: this.model,
99785
- debug: this.debug,
99786
- tracer: this.tracer
99787
- });
99788
- let currentResult = finalResult;
99789
- let currentValidation = validation;
99790
- while (!currentValidation.isValid && retryCount < maxRetries) {
99791
- if (this.debug) {
99792
- console.log(`[DEBUG] JSON validation: Validation failed (attempt ${retryCount + 1}/${maxRetries}):`, currentValidation.error);
99793
- console.log(`[DEBUG] JSON validation: Invalid response sample: ${currentResult.substring(0, 300)}${currentResult.length > 300 ? "..." : ""}`);
99794
- }
99795
- try {
99796
- currentResult = await jsonFixer.fixJson(
99797
- currentResult,
99798
- options.schema,
99799
- currentValidation,
99800
- retryCount + 1
99801
- );
99802
- currentValidation = validateJsonResponse(currentResult, { debug: this.debug, schema: options.schema });
99803
- retryCount++;
99804
- if (this.debug) {
99805
- if (!currentValidation.isValid && retryCount < maxRetries) {
99806
- console.log(`[DEBUG] JSON validation: Still invalid after correction ${retryCount}, retrying...`);
99807
- console.log(`[DEBUG] JSON validation: Corrected response sample: ${currentResult.substring(0, 300)}${currentResult.length > 300 ? "..." : ""}`);
99808
- } else if (currentValidation.isValid) {
99809
- console.log(`[DEBUG] JSON validation: Successfully corrected after ${retryCount} attempts with JsonFixingAgent`);
99810
- }
99811
- }
99812
- } catch (error40) {
99813
- if (this.debug) {
99814
- console.error(`[DEBUG] JSON validation: JsonFixingAgent error on attempt ${retryCount + 1}:`, error40.message);
99815
- }
99816
- break;
99817
- }
99818
- }
99819
- finalResult = currentResult;
99820
- validation = currentValidation;
99821
- if (!validation.isValid && this.debug) {
99822
- console.log(`[DEBUG] JSON validation: Still invalid after ${maxRetries} correction attempts with JsonFixingAgent:`, validation.error);
99823
- console.log(`[DEBUG] JSON validation: Final invalid response: ${finalResult.substring(0, 500)}${finalResult.length > 500 ? "..." : ""}`);
99824
- } else if (validation.isValid && this.debug) {
99825
- console.log(`[DEBUG] JSON validation: Final validation successful`);
99826
- }
99827
- }
99828
- if (this.tracer) {
99829
- this.tracer.recordJsonValidationEvent("completed", {
99830
- "json_validation.success": validation.isValid,
99831
- "json_validation.retry_count": retryCount,
99832
- "json_validation.max_retries": maxRetries,
99833
- "json_validation.final_response_length": finalResult.length,
99834
- "json_validation.error": validation.isValid ? null : validation.error
99835
- });
99836
- }
99837
- }
99838
- } catch (error40) {
99839
- console.error("[ERROR] Schema formatting failed:", error40);
99840
- }
99841
- } else if (reachedMaxIterations && options.schema && this.debug) {
99842
- console.log("[DEBUG] Skipping schema formatting due to max iterations reached without completion");
99843
- } else if (completionAttempted && options.schema && !options._schemaFormatted && !options._skipValidation) {
99844
- try {
99845
- if (!this.disableMermaidValidation) {
99846
- if (this.debug) {
99847
- console.log(`[DEBUG] Mermaid validation: Validating attempt_completion result BEFORE schema cleaning...`);
99341
+ console.log(`[DEBUG] Mermaid validation: Validating result BEFORE schema cleaning...`);
99848
99342
  }
99849
99343
  const mermaidValidation = await validateAndFixMermaidResponse(finalResult, {
99850
99344
  debug: this.debug,
@@ -99856,55 +99350,51 @@ Convert your previous response content into actual JSON data that follows this s
99856
99350
  if (mermaidValidation.wasFixed) {
99857
99351
  finalResult = mermaidValidation.fixedResponse;
99858
99352
  if (this.debug) {
99859
- console.log(`[DEBUG] Mermaid validation: attempt_completion diagrams fixed`);
99353
+ console.log(`[DEBUG] Mermaid validation: Diagrams fixed`);
99860
99354
  if (mermaidValidation.performanceMetrics) {
99861
99355
  console.log(`[DEBUG] Mermaid validation: Fixed in ${mermaidValidation.performanceMetrics.totalTimeMs}ms`);
99862
99356
  }
99863
99357
  }
99864
99358
  } else if (this.debug) {
99865
- console.log(`[DEBUG] Mermaid validation: attempt_completion result validation completed (no fixes needed)`);
99359
+ console.log(`[DEBUG] Mermaid validation: Completed (no fixes needed)`);
99866
99360
  }
99867
99361
  } else if (this.debug) {
99868
- console.log(`[DEBUG] Mermaid validation: Skipped for attempt_completion result due to disableMermaidValidation option`);
99362
+ console.log(`[DEBUG] Mermaid validation: Skipped due to disableMermaidValidation option`);
99869
99363
  }
99870
99364
  finalResult = cleanSchemaResponse(finalResult);
99871
99365
  if (isJsonSchema(options.schema)) {
99872
99366
  if (this.debug) {
99873
- console.log(`[DEBUG] JSON validation: Starting validation process for attempt_completion result`);
99367
+ console.log(`[DEBUG] JSON validation: Starting validation process`);
99874
99368
  console.log(`[DEBUG] JSON validation: Response length: ${finalResult.length} chars`);
99875
99369
  }
99876
99370
  if (this.tracer) {
99877
- this.tracer.recordJsonValidationEvent("attempt_completion_started", {
99371
+ this.tracer.recordJsonValidationEvent("started", {
99878
99372
  "json_validation.response_length": finalResult.length,
99879
- "json_validation.schema_type": "JSON",
99880
- "json_validation.context": "attempt_completion"
99373
+ "json_validation.schema_type": "JSON"
99881
99374
  });
99882
99375
  }
99883
- let validation = validateJsonResponse(finalResult, { debug: this.debug });
99376
+ let validation = validateJsonResponse(finalResult, { debug: this.debug, schema: options.schema });
99884
99377
  let retryCount = 0;
99885
99378
  const maxRetries = 3;
99886
99379
  if (validation.isValid && isJsonSchemaDefinition(finalResult, { debug: this.debug })) {
99887
99380
  if (this.debug) {
99888
- console.log(`[DEBUG] JSON validation: attempt_completion response is a JSON schema definition instead of data, correcting...`);
99381
+ console.log(`[DEBUG] JSON validation: Response is a JSON schema definition instead of data, correcting...`);
99889
99382
  }
99890
99383
  const schemaDefinitionPrompt = createSchemaDefinitionCorrectionPrompt(
99891
99384
  finalResult,
99892
99385
  options.schema,
99893
99386
  0
99894
99387
  );
99895
- const { schema: _unusedSchema1, ...schemaDefCorrectionOptions } = options;
99896
99388
  finalResult = await this.answer(schemaDefinitionPrompt, [], {
99897
- ...schemaDefCorrectionOptions,
99389
+ ...options,
99898
99390
  _schemaFormatted: true,
99899
99391
  _skipValidation: true,
99900
- // Skip validation in recursive correction calls to prevent loops
99392
+ _disableTools: true,
99901
99393
  _completionPromptProcessed: true,
99902
- // Prevent cascading completion prompts in retry calls
99903
99394
  _maxIterationsOverride: 3
99904
- // Correction should complete in 1-2 iterations (issue #447)
99905
99395
  });
99906
99396
  finalResult = cleanSchemaResponse(finalResult);
99907
- validation = validateJsonResponse(finalResult);
99397
+ validation = validateJsonResponse(finalResult, { debug: this.debug, schema: options.schema });
99908
99398
  retryCount = 1;
99909
99399
  }
99910
99400
  if (!validation.isValid) {
@@ -99914,20 +99404,16 @@ Convert your previous response content into actual JSON data that follows this s
99914
99404
  console.log(`[DEBUG] JSON validation: Auto-wrapped plain text for simple schema`);
99915
99405
  }
99916
99406
  finalResult = autoWrapped;
99917
- validation = validateJsonResponse(finalResult, { debug: this.debug });
99407
+ validation = validateJsonResponse(finalResult, { debug: this.debug, schema: options.schema });
99918
99408
  }
99919
99409
  }
99920
99410
  while (!validation.isValid && retryCount < maxRetries) {
99921
99411
  if (this.debug) {
99922
- console.log(`[DEBUG] JSON validation: attempt_completion validation failed (attempt ${retryCount + 1}/${maxRetries}):`, validation.error);
99923
- console.log(`[DEBUG] JSON validation: Invalid response sample: ${finalResult.substring(0, 300)}${finalResult.length > 300 ? "..." : ""}`);
99412
+ console.log(`[DEBUG] JSON validation: Validation failed (attempt ${retryCount + 1}/${maxRetries}):`, validation.error);
99924
99413
  }
99925
99414
  let correctionPrompt;
99926
99415
  try {
99927
99416
  if (isJsonSchemaDefinition(finalResult, { debug: this.debug })) {
99928
- if (this.debug) {
99929
- console.log(`[DEBUG] JSON validation: attempt_completion response is still a schema definition, using specialized correction`);
99930
- }
99931
99417
  correctionPrompt = createSchemaDefinitionCorrectionPrompt(
99932
99418
  finalResult,
99933
99419
  options.schema,
@@ -99949,47 +99435,43 @@ Convert your previous response content into actual JSON data that follows this s
99949
99435
  retryCount
99950
99436
  );
99951
99437
  }
99952
- const { schema: _unusedSchema2, ...correctionOptions } = options;
99953
99438
  finalResult = await this.answer(correctionPrompt, [], {
99954
- ...correctionOptions,
99439
+ ...options,
99955
99440
  _schemaFormatted: true,
99956
99441
  _skipValidation: true,
99957
- // Skip validation in recursive correction calls to prevent loops
99958
99442
  _disableTools: true,
99959
- // Only allow attempt_completion - prevent AI from using search/query tools
99960
99443
  _completionPromptProcessed: true,
99961
- // Prevent cascading completion prompts in retry calls
99962
99444
  _maxIterationsOverride: 3
99963
- // Correction should complete in 1-2 iterations (issue #447)
99964
99445
  });
99965
99446
  finalResult = cleanSchemaResponse(finalResult);
99966
- validation = validateJsonResponse(finalResult, { debug: this.debug });
99447
+ validation = validateJsonResponse(finalResult, { debug: this.debug, schema: options.schema });
99967
99448
  retryCount++;
99968
99449
  if (this.debug) {
99969
99450
  if (validation.isValid) {
99970
- console.log(`[DEBUG] JSON validation: attempt_completion correction successful on attempt ${retryCount}`);
99451
+ console.log(`[DEBUG] JSON validation: Correction successful on attempt ${retryCount}`);
99971
99452
  } else {
99972
- console.log(`[DEBUG] JSON validation: attempt_completion correction failed on attempt ${retryCount}: ${validation.error}`);
99453
+ console.log(`[DEBUG] JSON validation: Correction failed on attempt ${retryCount}: ${validation.error}`);
99973
99454
  }
99974
99455
  }
99975
99456
  }
99976
99457
  if (this.tracer) {
99977
- this.tracer.recordJsonValidationEvent("attempt_completion_completed", {
99458
+ this.tracer.recordJsonValidationEvent("completed", {
99978
99459
  "json_validation.success": validation.isValid,
99979
99460
  "json_validation.retry_count": retryCount,
99980
- "json_validation.final_response_length": finalResult.length
99461
+ "json_validation.max_retries": maxRetries,
99462
+ "json_validation.final_response_length": finalResult.length,
99463
+ "json_validation.error": validation.isValid ? null : validation.error
99981
99464
  });
99982
99465
  }
99983
99466
  if (!validation.isValid && this.debug) {
99984
- console.log(`[DEBUG] JSON validation: attempt_completion result validation failed after ${maxRetries} attempts: ${validation.error}`);
99985
- console.log(`[DEBUG] JSON validation: Final attempt_completion response: ${finalResult.substring(0, 500)}${finalResult.length > 500 ? "..." : ""}`);
99467
+ console.log(`[DEBUG] JSON validation: Failed after ${maxRetries} attempts: ${validation.error}`);
99986
99468
  } else if (validation.isValid && this.debug) {
99987
- console.log(`[DEBUG] JSON validation: attempt_completion result validation successful`);
99469
+ console.log(`[DEBUG] JSON validation: Final validation successful`);
99988
99470
  }
99989
99471
  }
99990
99472
  } catch (error40) {
99991
99473
  if (this.debug) {
99992
- console.log(`[DEBUG] attempt_completion result cleanup failed: ${error40.message}`);
99474
+ console.log(`[DEBUG] Schema validation/cleanup failed: ${error40.message}`);
99993
99475
  }
99994
99476
  }
99995
99477
  }
@@ -100930,7 +100412,7 @@ Instructions:
100930
100412
  - Format as a structured list if multiple items found
100931
100413
  - If nothing relevant is found in this chunk, respond with "No relevant items found in this chunk."
100932
100414
  - Do NOT summarize the code - extract the specific information requested
100933
- - When done, use the attempt_completion tool with your answer as the result.`;
100415
+ - When done, provide your final answer directly.`;
100934
100416
  try {
100935
100417
  const result = await delegate({
100936
100418
  task,
@@ -100992,7 +100474,7 @@ async function aggregateResults(chunkResults2, aggregation, extractionPrompt, op
100992
100474
  ${stripResultTags(r.result)}`).join("\n\n");
100993
100475
  const completionNote = `
100994
100476
 
100995
- When done, use the attempt_completion tool with your answer as the result.`;
100477
+ When done, provide your final answer directly.`;
100996
100478
  const aggregationPrompts = {
100997
100479
  summarize: `Synthesize these analyses into a comprehensive summary. Combine related findings, remove redundancy, and present a coherent overview.
100998
100480
 
@@ -101086,7 +100568,7 @@ For example, if looking for customer data:
101086
100568
  STEP 3: CREATE THE FINAL PLAN
101087
100569
  Based on your experiments, output the BEST search strategy.
101088
100570
 
101089
- Use attempt_completion with this EXACT format:
100571
+ Provide your answer in this EXACT format:
101090
100572
 
101091
100573
  SEARCH_QUERY: <the query that WORKED in your experiments - use OR for multiple terms>
101092
100574
  AGGREGATION: <summarize | list_unique | count | group_by>
@@ -101152,7 +100634,7 @@ Your answer should:
101152
100634
 
101153
100635
  Format your response as a well-structured document that fully answers: "${question}"
101154
100636
 
101155
- When done, use the attempt_completion tool with your answer as the result.`;
100637
+ When done, provide your final answer directly.`;
101156
100638
  try {
101157
100639
  const result = await delegate({
101158
100640
  task: synthesisTask,
@@ -101702,7 +101184,7 @@ var init_vercel = __esm({
101702
101184
  if (debug) {
101703
101185
  console.error(`[DEDUP] Blocked duplicate search: "${searchQuery}" (path: "${searchPath}")`);
101704
101186
  }
101705
- return "DUPLICATE SEARCH BLOCKED: You already searched for this exact query. Changing the path does NOT give different results \u2014 probe searches recursively. Do NOT repeat the same search. Try a genuinely different keyword, use extract to examine results you already found, or use attempt_completion if you have enough information.";
101187
+ return "DUPLICATE SEARCH BLOCKED: You already searched for this exact query. Changing the path does NOT give different results \u2014 probe searches recursively. Do NOT repeat the same search. Try a genuinely different keyword, use extract to examine results you already found, or provide your final answer if you have enough information.";
101706
101188
  }
101707
101189
  previousSearches.add(searchKey);
101708
101190
  paginationCounts.set(searchKey, 0);
@@ -101713,7 +101195,7 @@ var init_vercel = __esm({
101713
101195
  if (debug) {
101714
101196
  console.error(`[DEDUP] Blocked excessive pagination (page ${pageCount}/${MAX_PAGES_PER_QUERY}): "${searchQuery}" in "${searchPath}"`);
101715
101197
  }
101716
- return `PAGINATION LIMIT REACHED: You have already retrieved ${MAX_PAGES_PER_QUERY} pages of results for this query. You have enough results \u2014 use extract to examine specific files, or use attempt_completion to return your findings.`;
101198
+ return `PAGINATION LIMIT REACHED: You have already retrieved ${MAX_PAGES_PER_QUERY} pages of results for this query. You have enough results \u2014 use extract to examine specific files, or provide your final answer with your findings.`;
101717
101199
  }
101718
101200
  }
101719
101201
  try {
@@ -101752,7 +101234,7 @@ var init_vercel = __esm({
101752
101234
  bashConfig: null,
101753
101235
  architectureFileName: options.architectureFileName || null,
101754
101236
  promptType: "code-searcher",
101755
- allowedTools: ["search", "extract", "listFiles", "attempt_completion"],
101237
+ allowedTools: ["search", "extract", "listFiles"],
101756
101238
  searchDelegate: false,
101757
101239
  schema: CODE_SEARCH_SCHEMA,
101758
101240
  parentAbortSignal: options.parentAbortSignal || null
@@ -103334,7 +102816,6 @@ For GitHub-compatible mermaid diagrams, avoid single quotes and parentheses in n
103334
102816
  var tools_exports = {};
103335
102817
  __export(tools_exports, {
103336
102818
  DEFAULT_SYSTEM_MESSAGE: () => DEFAULT_SYSTEM_MESSAGE,
103337
- attemptCompletionSchema: () => attemptCompletionSchema,
103338
102819
  bashDescription: () => bashDescription,
103339
102820
  bashSchema: () => bashSchema,
103340
102821
  bashTool: () => bashTool,
@@ -103982,7 +103463,6 @@ __export(index_exports, {
103982
103463
  TaskManager: () => TaskManager,
103983
103464
  analyzeAllSchema: () => analyzeAllSchema,
103984
103465
  analyzeAllTool: () => analyzeAllTool,
103985
- attemptCompletionSchema: () => attemptCompletionSchema,
103986
103466
  bashSchema: () => bashSchema,
103987
103467
  bashTool: () => bashTool,
103988
103468
  cleanupExecutePlanSchema: () => cleanupExecutePlanSchema,
@@ -104069,7 +103549,6 @@ init_index();
104069
103549
  TaskManager,
104070
103550
  analyzeAllSchema,
104071
103551
  analyzeAllTool,
104072
- attemptCompletionSchema,
104073
103552
  bashSchema,
104074
103553
  bashTool,
104075
103554
  cleanupExecutePlanSchema,