clink-cli 0.2.1__py3-none-any.whl

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 (141) hide show
  1. clink/__init__.py +19 -0
  2. clink/agents/__init__.py +30 -0
  3. clink/agents/base.py +70 -0
  4. clink/agents/claude.py +7 -0
  5. clink/agents/codex.py +7 -0
  6. clink/agents/gemini.py +7 -0
  7. clink/allowed_roots.py +356 -0
  8. clink/backend.py +765 -0
  9. clink/cli.py +594 -0
  10. clink/constants.py +78 -0
  11. clink/contracts.py +167 -0
  12. clink/files.py +70 -0
  13. clink/generation.py +274 -0
  14. clink/generation_capabilities.py +207 -0
  15. clink/generation_contracts.py +214 -0
  16. clink/generation_policy.py +174 -0
  17. clink/models.py +243 -0
  18. clink/native.py +409 -0
  19. clink/native_adapters.py +244 -0
  20. clink/native_contracts.py +68 -0
  21. clink/native_generation.py +421 -0
  22. clink/native_generation_claude_policy.py +59 -0
  23. clink/native_generation_contracts.py +264 -0
  24. clink/native_generation_families.py +218 -0
  25. clink/native_generation_family_policy.py +14 -0
  26. clink/native_generation_files.py +153 -0
  27. clink/native_generation_policy.py +82 -0
  28. clink/native_policy.py +86 -0
  29. clink/parsers/__init__.py +34 -0
  30. clink/parsers/agy.py +53 -0
  31. clink/parsers/agy_native.py +161 -0
  32. clink/parsers/agy_native_generation.py +189 -0
  33. clink/parsers/base.py +209 -0
  34. clink/parsers/claude.py +104 -0
  35. clink/parsers/claude_native.py +113 -0
  36. clink/parsers/claude_native_generation.py +346 -0
  37. clink/parsers/codex.py +172 -0
  38. clink/parsers/codex_generation.py +212 -0
  39. clink/parsers/codex_native.py +236 -0
  40. clink/parsers/codex_native_generation.py +367 -0
  41. clink/parsers/gemini.py +110 -0
  42. clink/parsers/grok.py +63 -0
  43. clink/parsers/grok_native.py +91 -0
  44. clink/parsers/grok_native_generation.py +157 -0
  45. clink/policy.py +180 -0
  46. clink/registry.py +544 -0
  47. clink/resources/CODEX-LICENSE +201 -0
  48. clink/resources/CODEX-NOTICE +6 -0
  49. clink/resources/PROVENANCE.md +16 -0
  50. clink/resources/codex-0.166.0-models-direct.json +1284 -0
  51. clink/resources/codex-0.166.0-models-generation.json +1269 -0
  52. clink/resources/native-agy-1.4.12-admission.json +746 -0
  53. clink/resources/native-claude-2.1.304-admission.json +99 -0
  54. clink/resources/native-generation-claude-2.1.304-admission.json +277 -0
  55. clink/resources/native-generation-codex-0.166.0-admission.json +309 -0
  56. clink/resources/native-generation-grok-1.0.70-admission.json +329 -0
  57. clink/resources/native-grok-1.0.70-admission.json +644 -0
  58. clink/runner.py +303 -0
  59. clink/setup.py +399 -0
  60. clink/tasks.py +695 -0
  61. clink_cli-0.2.1.dist-info/METADATA +225 -0
  62. clink_cli-0.2.1.dist-info/RECORD +141 -0
  63. clink_cli-0.2.1.dist-info/WHEEL +5 -0
  64. clink_cli-0.2.1.dist-info/entry_points.txt +3 -0
  65. clink_cli-0.2.1.dist-info/licenses/LICENSE +197 -0
  66. clink_cli-0.2.1.dist-info/licenses/clink/resources/CODEX-LICENSE +201 -0
  67. clink_cli-0.2.1.dist-info/licenses/clink/resources/CODEX-NOTICE +6 -0
  68. clink_cli-0.2.1.dist-info/top_level.txt +7 -0
  69. conf/__init__.py +1 -0
  70. conf/cli_clients/agy.json +40 -0
  71. conf/cli_clients/claude.json +39 -0
  72. conf/cli_clients/codex.json +40 -0
  73. conf/cli_clients/gemini.json +23 -0
  74. conf/cli_clients/grok.json +40 -0
  75. config.py +40 -0
  76. server.py +896 -0
  77. systemprompts/__init__.py +35 -0
  78. systemprompts/analyze_prompt.py +87 -0
  79. systemprompts/chat_prompt.py +57 -0
  80. systemprompts/clink/codex_codereviewer.txt +8 -0
  81. systemprompts/clink/default.txt +8 -0
  82. systemprompts/clink/default_codereviewer.txt +8 -0
  83. systemprompts/clink/default_planner.txt +7 -0
  84. systemprompts/clink/native_codereviewer.txt +1 -0
  85. systemprompts/clink/native_default.txt +1 -0
  86. systemprompts/clink/native_planner.txt +1 -0
  87. systemprompts/codereview_prompt.py +91 -0
  88. systemprompts/consensus_prompt.py +120 -0
  89. systemprompts/debug_prompt.py +150 -0
  90. systemprompts/docgen_prompt.py +252 -0
  91. systemprompts/generate_code_prompt.py +181 -0
  92. systemprompts/planner_prompt.py +127 -0
  93. systemprompts/precommit_prompt.py +179 -0
  94. systemprompts/refactor_prompt.py +323 -0
  95. systemprompts/secaudit_prompt.py +420 -0
  96. systemprompts/testgen_prompt.py +133 -0
  97. systemprompts/thinkdeep_prompt.py +55 -0
  98. systemprompts/tracer_prompt.py +145 -0
  99. tools/__init__.py +43 -0
  100. tools/analyze.py +583 -0
  101. tools/apilookup.py +97 -0
  102. tools/challenge.py +198 -0
  103. tools/chat.py +187 -0
  104. tools/clink.py +130 -0
  105. tools/codereview.py +724 -0
  106. tools/consensus.py +790 -0
  107. tools/debug.py +573 -0
  108. tools/docgen.py +577 -0
  109. tools/listmodels.py +48 -0
  110. tools/models.py +373 -0
  111. tools/planner.py +533 -0
  112. tools/precommit.py +776 -0
  113. tools/refactor.py +645 -0
  114. tools/secaudit.py +685 -0
  115. tools/shared/__init__.py +19 -0
  116. tools/shared/base_models.py +167 -0
  117. tools/shared/base_tool.py +659 -0
  118. tools/shared/exceptions.py +20 -0
  119. tools/shared/schema_builders.py +159 -0
  120. tools/simple/__init__.py +18 -0
  121. tools/simple/base.py +539 -0
  122. tools/testgen.py +513 -0
  123. tools/thinkdeep.py +586 -0
  124. tools/tracer.py +763 -0
  125. tools/version.py +53 -0
  126. tools/workflow/__init__.py +22 -0
  127. tools/workflow/base.py +448 -0
  128. tools/workflow/schema_builders.py +166 -0
  129. tools/workflow/workflow_mixin.py +1195 -0
  130. utils/__init__.py +21 -0
  131. utils/call_state.py +349 -0
  132. utils/client_info.py +293 -0
  133. utils/consensus_manifest.py +131 -0
  134. utils/conversation_memory.py +582 -0
  135. utils/env.py +111 -0
  136. utils/file_types.py +271 -0
  137. utils/file_utils.py +803 -0
  138. utils/image_utils.py +94 -0
  139. utils/security_config.py +163 -0
  140. utils/storage_backend.py +177 -0
  141. utils/token_utils.py +54 -0
tools/debug.py ADDED
@@ -0,0 +1,573 @@
1
+ """
2
+ Debug tool - Systematic root cause analysis and debugging assistance
3
+
4
+ This tool provides a structured workflow for investigating complex bugs and issues.
5
+ It guides you through systematic investigation steps with forced pauses between each step
6
+ to ensure thorough code examination before proceeding. The tool supports hypothesis evolution
7
+ and expert analysis integration for comprehensive debugging.
8
+
9
+ Key features:
10
+ - Step-by-step investigation workflow with progress tracking
11
+ - Context-aware file embedding (references during investigation, full content for analysis)
12
+ - Automatic conversation threading and history preservation
13
+ - Expert analysis integration with external models
14
+ - Support for visual debugging with image context
15
+ - Confidence-based workflow optimization
16
+ """
17
+
18
+ import logging
19
+ from typing import TYPE_CHECKING, Any, Optional
20
+
21
+ from pydantic import Field
22
+
23
+ if TYPE_CHECKING:
24
+ from tools.models import ToolModelCategory
25
+
26
+ from config import TEMPERATURE_ANALYTICAL
27
+ from systemprompts import DEBUG_ISSUE_PROMPT
28
+ from tools.shared.base_models import WorkflowRequest
29
+
30
+ from .workflow.base import WorkflowTool
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+ # Tool-specific field descriptions matching original debug tool
35
+ DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS = {
36
+ "step": (
37
+ "Investigation step. Step 1: State issue+direction. "
38
+ "Symptoms misleading; 'no bug' valid. Trace dependencies, verify hypotheses. "
39
+ "Use relevant_files for code; this for text only."
40
+ ),
41
+ "step_number": "Current step index (starts at 1). Build upon previous steps.",
42
+ "total_steps": (
43
+ "Estimated total steps needed to complete the investigation. Adjust as new findings emerge. "
44
+ "IMPORTANT: When continuation_id is provided (continuing a previous conversation), set this to 1 as we're not starting a new multi-step investigation."
45
+ ),
46
+ "next_step_required": (
47
+ "True if you plan to continue the investigation with another step. False means root cause is known or investigation is complete. "
48
+ "IMPORTANT: When continuation_id is provided (continuing a previous conversation), set this to False to immediately proceed with expert analysis."
49
+ ),
50
+ "findings": (
51
+ "Discoveries: clues, code/log evidence, disproven theories. Be specific. "
52
+ "If no bug found, document clearly as valid."
53
+ ),
54
+ "files_checked": "All examined files (absolute paths), including ruled-out ones.",
55
+ "relevant_files": "Files directly relevant to issue (absolute paths). Cause, trigger, or manifestation locations.",
56
+ "relevant_context": "Methods/functions central to issue: 'Class.method' or 'function'. Focus on inputs/branching/state.",
57
+ "hypothesis": (
58
+ "Concrete root cause theory from evidence. Can revise. "
59
+ "Valid: 'No bug found - user misunderstanding' or 'Symptoms unrelated to code' if supported."
60
+ ),
61
+ "confidence": (
62
+ "Your confidence in the hypothesis: exploring (starting out), low (early idea), medium (some evidence), "
63
+ "high (strong evidence), very_high (very strong evidence), almost_certain (nearly confirmed), "
64
+ "certain (100% confidence - root cause and fix are both confirmed locally with no need for external validation). "
65
+ "WARNING: Do NOT use 'certain' unless the issue can be fully resolved with a fix, use 'very_high' or 'almost_certain' instead when not 100% sure. "
66
+ "Using 'certain' means you have ABSOLUTE confidence locally and PREVENTS external model validation."
67
+ ),
68
+ "images": "Optional screenshots/visuals clarifying issue (absolute paths).",
69
+ }
70
+
71
+
72
+ class DebugInvestigationRequest(WorkflowRequest):
73
+ """Request model for debug investigation steps matching original debug tool exactly"""
74
+
75
+ # Required fields for each investigation step
76
+ step: str = Field(..., description=DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["step"])
77
+ step_number: int = Field(..., description=DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["step_number"])
78
+ total_steps: int = Field(..., description=DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["total_steps"])
79
+ next_step_required: bool = Field(..., description=DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["next_step_required"])
80
+
81
+ # Investigation tracking fields
82
+ findings: str = Field(..., description=DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["findings"])
83
+ files_checked: list[str] = Field(
84
+ default_factory=list, description=DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["files_checked"]
85
+ )
86
+ relevant_files: list[str] = Field(
87
+ default_factory=list, description=DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["relevant_files"]
88
+ )
89
+ relevant_context: list[str] = Field(
90
+ default_factory=list, description=DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["relevant_context"]
91
+ )
92
+ hypothesis: Optional[str] = Field(None, description=DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["hypothesis"])
93
+ confidence: Optional[str] = Field("low", description=DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["confidence"])
94
+
95
+ # Optional images for visual debugging
96
+ images: Optional[list[str]] = Field(default=None, description=DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["images"])
97
+
98
+ # Override inherited fields to exclude them from schema (except model which needs to be available)
99
+ temperature: Optional[float] = Field(default=None, exclude=True)
100
+ thinking_mode: Optional[str] = Field(default=None, exclude=True)
101
+
102
+
103
+ class DebugIssueTool(WorkflowTool):
104
+ """
105
+ Debug tool for systematic root cause analysis and issue investigation.
106
+
107
+ This tool implements a structured debugging workflow that guides users through
108
+ methodical investigation steps, ensuring thorough code examination and evidence
109
+ gathering before reaching conclusions. It supports complex debugging scenarios
110
+ including race conditions, memory leaks, performance issues, and integration problems.
111
+ """
112
+
113
+ def __init__(self):
114
+ super().__init__()
115
+ self.initial_issue = None
116
+
117
+ def get_name(self) -> str:
118
+ return "debug"
119
+
120
+ def get_description(self) -> str:
121
+ return (
122
+ "Performs systematic debugging and root cause analysis for any type of issue. "
123
+ "Use for complex bugs, mysterious errors, performance issues, race conditions, memory leaks, and integration problems. "
124
+ "Guides through structured investigation with hypothesis testing and expert analysis."
125
+ )
126
+
127
+ def get_system_prompt(self) -> str:
128
+ return DEBUG_ISSUE_PROMPT
129
+
130
+ def get_default_temperature(self) -> float:
131
+ return TEMPERATURE_ANALYTICAL
132
+
133
+ def get_model_category(self) -> "ToolModelCategory":
134
+ """Debug requires deep analysis and reasoning"""
135
+ from tools.models import ToolModelCategory
136
+
137
+ return ToolModelCategory.EXTENDED_REASONING
138
+
139
+ def get_workflow_request_model(self):
140
+ """Return the debug-specific request model."""
141
+ return DebugInvestigationRequest
142
+
143
+ def get_input_schema(self) -> dict[str, Any]:
144
+ """Generate input schema using WorkflowSchemaBuilder with debug-specific overrides."""
145
+ from .workflow.schema_builders import WorkflowSchemaBuilder
146
+
147
+ # Debug-specific field overrides
148
+ debug_field_overrides = {
149
+ "step": {
150
+ "type": "string",
151
+ "description": DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["step"],
152
+ },
153
+ "step_number": {
154
+ "type": "integer",
155
+ "minimum": 1,
156
+ "description": DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["step_number"],
157
+ },
158
+ "total_steps": {
159
+ "type": "integer",
160
+ "minimum": 1,
161
+ "description": DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["total_steps"],
162
+ },
163
+ "next_step_required": {
164
+ "type": "boolean",
165
+ "description": DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["next_step_required"],
166
+ },
167
+ "findings": {
168
+ "type": "string",
169
+ "description": DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["findings"],
170
+ },
171
+ "files_checked": {
172
+ "type": "array",
173
+ "items": {"type": "string"},
174
+ "description": DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["files_checked"],
175
+ },
176
+ "relevant_files": {
177
+ "type": "array",
178
+ "items": {"type": "string"},
179
+ "description": DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["relevant_files"],
180
+ },
181
+ "confidence": {
182
+ "type": "string",
183
+ "enum": ["exploring", "low", "medium", "high", "very_high", "almost_certain", "certain"],
184
+ "description": DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["confidence"],
185
+ },
186
+ "hypothesis": {
187
+ "type": "string",
188
+ "description": DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["hypothesis"],
189
+ },
190
+ "images": {
191
+ "type": "array",
192
+ "items": {"type": "string"},
193
+ "description": DEBUG_INVESTIGATION_FIELD_DESCRIPTIONS["images"],
194
+ },
195
+ }
196
+
197
+ # Use WorkflowSchemaBuilder with debug-specific tool fields
198
+ return WorkflowSchemaBuilder.build_schema(
199
+ tool_specific_fields=debug_field_overrides,
200
+ model_field_schema=self.get_model_field_schema(),
201
+ auto_mode=self.is_effective_auto_mode(),
202
+ tool_name=self.get_name(),
203
+ )
204
+
205
+ def get_required_actions(
206
+ self, step_number: int, confidence: str, findings: str, total_steps: int, request=None
207
+ ) -> list[str]:
208
+ """Define required actions for each investigation phase."""
209
+ if step_number == 1:
210
+ # Initial investigation tasks
211
+ return [
212
+ "Search for code related to the reported issue or symptoms",
213
+ "Examine relevant files and understand the current implementation",
214
+ "Understand the project structure and locate relevant modules",
215
+ "Identify how the affected functionality is supposed to work",
216
+ ]
217
+ elif confidence in ["exploring", "low"]:
218
+ # Need deeper investigation
219
+ return [
220
+ "Examine the specific files you've identified as relevant",
221
+ "Trace method calls and data flow through the system",
222
+ "Check for edge cases, boundary conditions, and assumptions in the code",
223
+ "Look for related configuration, dependencies, or external factors",
224
+ ]
225
+ elif confidence in ["medium", "high", "very_high"]:
226
+ # Close to root cause - need confirmation
227
+ return [
228
+ "Examine the exact code sections where you believe the issue occurs",
229
+ "Trace the execution path that leads to the failure",
230
+ "Verify your hypothesis with concrete code evidence",
231
+ "Check for any similar patterns elsewhere in the codebase",
232
+ ]
233
+ elif confidence == "almost_certain":
234
+ # Almost certain - final verification before conclusion
235
+ return [
236
+ "Finalize your root cause analysis with specific evidence",
237
+ "Document the complete chain of causation from symptom to root cause",
238
+ "Verify the minimal fix approach is correct",
239
+ "Consider if expert analysis would provide additional insights",
240
+ ]
241
+ else:
242
+ # General investigation needed
243
+ return [
244
+ "Continue examining the code paths identified in your hypothesis",
245
+ "Gather more evidence using appropriate investigation tools",
246
+ "Test edge cases and boundary conditions",
247
+ "Look for patterns that confirm or refute your theory",
248
+ ]
249
+
250
+ def should_call_expert_analysis(self, consolidated_findings, request=None) -> bool:
251
+ """
252
+ Decide when to call external model based on investigation completeness.
253
+
254
+ Don't call expert analysis if the CLI agent has certain confidence - trust their judgment.
255
+ """
256
+ # Check if user requested to skip assistant model
257
+ if request and not self.get_request_use_assistant_model(request):
258
+ return False
259
+
260
+ # Check if we have meaningful investigation data
261
+ return (
262
+ len(consolidated_findings.relevant_files) > 0
263
+ or len(consolidated_findings.findings) >= 2
264
+ or len(consolidated_findings.issues_found) > 0
265
+ )
266
+
267
+ def prepare_expert_analysis_context(self, consolidated_findings) -> str:
268
+ """Prepare context for external model call matching original debug tool format."""
269
+ context_parts = [
270
+ f"=== ISSUE DESCRIPTION ===\n{self.get_expert_initial_request(self.initial_issue, 'Investigation initiated')}\n=== END DESCRIPTION ==="
271
+ ]
272
+
273
+ # Add special note if confidence is almost_certain
274
+ if consolidated_findings.confidence == "almost_certain":
275
+ context_parts.append(
276
+ "\n=== IMPORTANT: ALMOST CERTAIN CONFIDENCE ===\n"
277
+ "The agent has reached 'almost_certain' confidence but has NOT confirmed the bug with 100% certainty. "
278
+ "Your role is to:\n"
279
+ "1. Validate the agent's hypothesis and investigation\n"
280
+ "2. Identify any missing evidence or overlooked aspects\n"
281
+ "3. Provide additional insights that could confirm or refute the hypothesis\n"
282
+ "4. Help finalize the root cause analysis with complete certainty\n"
283
+ "=== END IMPORTANT ==="
284
+ )
285
+
286
+ # Add investigation summary
287
+ investigation_summary = self._build_investigation_summary(consolidated_findings)
288
+ context_parts.append(f"\n=== AGENT'S INVESTIGATION FINDINGS ===\n{investigation_summary}\n=== END FINDINGS ===")
289
+
290
+ # Add error context if available
291
+ error_context = self._extract_error_context(consolidated_findings)
292
+ if error_context:
293
+ context_parts.append(f"\n=== ERROR CONTEXT/STACK TRACE ===\n{error_context}\n=== END CONTEXT ===")
294
+
295
+ # Add relevant methods/functions if available
296
+ if consolidated_findings.relevant_context:
297
+ methods_text = "\n".join(f"- {method}" for method in consolidated_findings.relevant_context)
298
+ context_parts.append(f"\n=== RELEVANT METHODS/FUNCTIONS ===\n{methods_text}\n=== END METHODS ===")
299
+
300
+ # Add hypothesis evolution if available
301
+ if consolidated_findings.hypotheses:
302
+ hypotheses_text = "\n".join(
303
+ f"Step {h['step']} ({h['confidence']} confidence): {h['hypothesis']}"
304
+ for h in consolidated_findings.hypotheses
305
+ )
306
+ context_parts.append(f"\n=== HYPOTHESIS EVOLUTION ===\n{hypotheses_text}\n=== END HYPOTHESES ===")
307
+
308
+ # Add images if available
309
+ if consolidated_findings.images:
310
+ images_text = "\n".join(f"- {img}" for img in consolidated_findings.images)
311
+ context_parts.append(
312
+ f"\n=== VISUAL DEBUGGING INFORMATION ===\n{images_text}\n=== END VISUAL INFORMATION ==="
313
+ )
314
+
315
+ # Declared file contents are loaded once by the shared bounded backend.
316
+ return "\n".join(context_parts)
317
+
318
+ def _build_investigation_summary(self, consolidated_findings) -> str:
319
+ """Prepare a comprehensive summary of the investigation."""
320
+ summary_parts = [
321
+ "=== SYSTEMATIC INVESTIGATION SUMMARY ===",
322
+ f"Total steps: {len(consolidated_findings.findings)}",
323
+ f"Files examined: {len(consolidated_findings.files_checked)}",
324
+ f"Relevant files identified: {len(consolidated_findings.relevant_files)}",
325
+ f"Methods/functions involved: {len(consolidated_findings.relevant_context)}",
326
+ "",
327
+ "=== INVESTIGATION PROGRESSION ===",
328
+ ]
329
+
330
+ for finding in consolidated_findings.findings:
331
+ summary_parts.append(finding)
332
+
333
+ return "\n".join(summary_parts)
334
+
335
+ def _extract_error_context(self, consolidated_findings) -> Optional[str]:
336
+ """Extract error context from investigation findings."""
337
+ error_patterns = ["error", "exception", "stack trace", "traceback", "failure"]
338
+ error_context_parts = []
339
+
340
+ for finding in consolidated_findings.findings:
341
+ if any(pattern in finding.lower() for pattern in error_patterns):
342
+ error_context_parts.append(finding)
343
+
344
+ return "\n".join(error_context_parts) if error_context_parts else None
345
+
346
+ def get_step_guidance(self, step_number: int, confidence: str, request) -> dict[str, Any]:
347
+ """
348
+ Provide step-specific guidance matching original debug tool behavior.
349
+
350
+ This method generates debug-specific guidance that's used by get_step_guidance_message().
351
+ """
352
+ # Generate the next steps instruction based on required actions
353
+ required_actions = self.get_required_actions(step_number, confidence, request.findings, request.total_steps)
354
+
355
+ if step_number == 1:
356
+ next_steps = (
357
+ f"MANDATORY: DO NOT call the {self.get_name()} tool again immediately. You MUST first investigate "
358
+ f"the codebase using appropriate tools. CRITICAL AWARENESS: The reported symptoms might be "
359
+ f"caused by issues elsewhere in the code, not where symptoms appear. Also, after thorough "
360
+ f"investigation, it's possible NO BUG EXISTS - the issue might be a misunderstanding or "
361
+ f"user expectation mismatch. Search broadly, examine implementations, understand the logic flow. "
362
+ f"Only call {self.get_name()} again AFTER gathering concrete evidence. When you call "
363
+ f"{self.get_name()} next time, "
364
+ f"use step_number: {step_number + 1} and report specific files examined and findings discovered."
365
+ )
366
+ elif confidence in ["exploring", "low"]:
367
+ next_steps = (
368
+ f"STOP! Do NOT call {self.get_name()} again yet. Based on your findings, you've identified potential areas "
369
+ f"but need concrete evidence. MANDATORY ACTIONS before calling {self.get_name()} step {step_number + 1}:\n"
370
+ + "\n".join(f"{i+1}. {action}" for i, action in enumerate(required_actions))
371
+ + f"\n\nOnly call {self.get_name()} again with step_number: {step_number + 1} AFTER "
372
+ + "completing these investigations."
373
+ )
374
+ elif confidence in ["medium", "high", "very_high"]:
375
+ next_steps = (
376
+ f"WAIT! Your hypothesis needs verification. DO NOT call {self.get_name()} immediately. REQUIRED ACTIONS:\n"
377
+ + "\n".join(f"{i+1}. {action}" for i, action in enumerate(required_actions))
378
+ + f"\n\nREMEMBER: If you cannot find concrete evidence of a bug causing the reported symptoms, "
379
+ f"'no bug found' is a valid conclusion. Consider suggesting discussion with your thought partner "
380
+ f"or engineering assistant for clarification. Document findings with specific file:line references, "
381
+ f"then call {self.get_name()} with step_number: {step_number + 1}."
382
+ )
383
+ elif confidence == "almost_certain":
384
+ next_steps = (
385
+ "ALMOST CERTAIN - Prepare for final analysis. REQUIRED ACTIONS:\n"
386
+ + "\n".join(f"{i+1}. {action}" for i, action in enumerate(required_actions))
387
+ + "\n\nIMPORTANT: You're almost certain about the root cause. If you have NOT found the bug with "
388
+ "100% certainty, consider setting next_step_required=false to invoke expert analysis. The expert "
389
+ "can validate your hypotheses and provide additional insights. If you ARE 100% certain and have "
390
+ "identified the exact bug and fix, proceed to confidence='certain'. Otherwise, let expert analysis "
391
+ "help finalize the investigation."
392
+ )
393
+ else:
394
+ next_steps = (
395
+ f"PAUSE INVESTIGATION. Before calling {self.get_name()} step {step_number + 1}, you MUST examine code. "
396
+ + "Required: "
397
+ + ", ".join(required_actions[:2])
398
+ + ". "
399
+ + f"Your next {self.get_name()} call (step_number: {step_number + 1}) must include "
400
+ f"NEW evidence from actual code examination, not just theories. If no bug evidence "
401
+ f"is found, suggesting "
402
+ f"collaboration with thought partner is valuable. NO recursive {self.get_name()} calls "
403
+ f"without investigation work!"
404
+ )
405
+
406
+ return {"next_steps": next_steps}
407
+
408
+ # Hook method overrides for debug-specific behavior
409
+
410
+ def prepare_step_data(self, request) -> dict:
411
+ """
412
+ Prepare debug-specific step data for processing.
413
+ """
414
+ step_data = {
415
+ "step": request.step,
416
+ "step_number": request.step_number,
417
+ "findings": request.findings,
418
+ "files_checked": request.files_checked,
419
+ "relevant_files": request.relevant_files,
420
+ "relevant_context": request.relevant_context,
421
+ "issues_found": [], # Debug tool doesn't use issues_found field
422
+ "confidence": request.confidence,
423
+ "hypothesis": request.hypothesis,
424
+ "images": request.images or [],
425
+ }
426
+ return step_data
427
+
428
+ def should_skip_expert_analysis(self, request, consolidated_findings) -> bool:
429
+ """
430
+ Debug tool skips expert analysis when agent has "certain" confidence.
431
+ """
432
+ return request.confidence == "certain" and not request.next_step_required
433
+
434
+ # Override inheritance hooks for debug-specific behavior
435
+
436
+ def get_completion_status(self) -> str:
437
+ """Debug tools use debug-specific status."""
438
+ return "certain_confidence_proceed_with_fix"
439
+
440
+ def get_completion_data_key(self) -> str:
441
+ """Debug uses 'complete_investigation' key."""
442
+ return "complete_investigation"
443
+
444
+ def get_final_analysis_from_request(self, request):
445
+ """Debug tools use 'hypothesis' field."""
446
+ return request.hypothesis
447
+
448
+ def get_confidence_level(self, request) -> str:
449
+ """Debug tools use 'certain' for high confidence."""
450
+ return "certain"
451
+
452
+ def get_completion_message(self) -> str:
453
+ """Debug-specific completion message."""
454
+ return (
455
+ "Investigation complete with CERTAIN confidence. You have identified the exact "
456
+ "root cause and a minimal fix. MANDATORY: Present the user with the root cause analysis "
457
+ "and IMMEDIATELY proceed with implementing the simple fix without requiring further "
458
+ "consultation. Focus on the precise, minimal change needed."
459
+ )
460
+
461
+ def get_skip_reason(self) -> str:
462
+ """Debug-specific skip reason."""
463
+ return "Identified exact root cause with minimal fix requirement locally"
464
+
465
+ def get_request_relevant_context(self, request) -> list:
466
+ """Get relevant_context for debug tool."""
467
+ try:
468
+ return request.relevant_context or []
469
+ except AttributeError:
470
+ return []
471
+
472
+ def get_skip_expert_analysis_status(self) -> str:
473
+ """Debug-specific expert analysis skip status."""
474
+ return "skipped_due_to_certain_confidence"
475
+
476
+ def prepare_work_summary(self) -> str:
477
+ """Debug-specific work summary."""
478
+ return self._build_investigation_summary(self.consolidated_findings)
479
+
480
+ def get_completion_next_steps_message(self, expert_analysis_used: bool = False) -> str:
481
+ """
482
+ Debug-specific completion message.
483
+
484
+ Args:
485
+ expert_analysis_used: True if expert analysis was successfully executed
486
+ """
487
+ base_message = (
488
+ "INVESTIGATION IS COMPLETE. YOU MUST now summarize and present ALL key findings, confirmed "
489
+ "hypotheses, and exact recommended fixes. Clearly identify the most likely root cause and "
490
+ "provide concrete, actionable implementation guidance. Highlight affected code paths and display "
491
+ "reasoning that led to this conclusion—make it easy for a developer to understand exactly where "
492
+ "the problem lies. Where necessary, show cause-and-effect / bug-trace call graph."
493
+ )
494
+
495
+ # Add expert analysis guidance only when expert analysis was actually used
496
+ if expert_analysis_used:
497
+ expert_guidance = self.get_expert_analysis_guidance()
498
+ if expert_guidance:
499
+ return f"{base_message}\n\n{expert_guidance}"
500
+
501
+ return base_message
502
+
503
+ def get_expert_analysis_guidance(self) -> str:
504
+ """
505
+ Get additional guidance for handling expert analysis results in debug context.
506
+
507
+ Returns:
508
+ Additional guidance text for validating and using expert analysis findings
509
+ """
510
+ return (
511
+ "IMPORTANT: Expert debugging analysis has been provided above. You MUST validate "
512
+ "the expert's root cause analysis and proposed fixes against your own investigation. "
513
+ "Ensure the expert's findings align with the evidence you've gathered and that the "
514
+ "recommended solutions address the actual problem, not just symptoms. If the expert "
515
+ "suggests a different root cause than you identified, carefully consider both perspectives "
516
+ "and present a balanced assessment to the user."
517
+ )
518
+
519
+ def get_step_guidance_message(self, request) -> str:
520
+ """
521
+ Debug-specific step guidance with detailed investigation instructions.
522
+ """
523
+ step_guidance = self.get_step_guidance(request.step_number, request.confidence, request)
524
+ return step_guidance["next_steps"]
525
+
526
+ def customize_workflow_response(self, response_data: dict, request) -> dict:
527
+ """
528
+ Customize response to match original debug tool format.
529
+ """
530
+ # Store initial issue on first step
531
+ if request.step_number == 1:
532
+ self.initial_issue = request.step
533
+
534
+ # Convert generic status names to debug-specific ones
535
+ tool_name = self.get_name()
536
+ status_mapping = {
537
+ f"{tool_name}_in_progress": "investigation_in_progress",
538
+ f"pause_for_{tool_name}": "pause_for_investigation",
539
+ f"{tool_name}_required": "investigation_required",
540
+ f"{tool_name}_complete": "investigation_complete",
541
+ }
542
+
543
+ if response_data["status"] in status_mapping:
544
+ response_data["status"] = status_mapping[response_data["status"]]
545
+
546
+ # Rename status field to match debug tool
547
+ if f"{tool_name}_status" in response_data:
548
+ response_data["investigation_status"] = response_data.pop(f"{tool_name}_status")
549
+ # Add debug-specific status fields
550
+ response_data["investigation_status"]["hypotheses_formed"] = len(self.consolidated_findings.hypotheses)
551
+
552
+ # Rename complete investigation data
553
+ if f"complete_{tool_name}" in response_data:
554
+ response_data["complete_investigation"] = response_data.pop(f"complete_{tool_name}")
555
+
556
+ # Map the completion flag to match original debug tool
557
+ if f"{tool_name}_complete" in response_data:
558
+ response_data["investigation_complete"] = response_data.pop(f"{tool_name}_complete")
559
+
560
+ # Map the required flag to match original debug tool
561
+ if f"{tool_name}_required" in response_data:
562
+ response_data["investigation_required"] = response_data.pop(f"{tool_name}_required")
563
+
564
+ return response_data
565
+
566
+ # Required abstract methods from BaseTool
567
+ def get_request_model(self):
568
+ """Return the debug-specific request model."""
569
+ return DebugInvestigationRequest
570
+
571
+ async def prepare_prompt(self, request) -> str:
572
+ """Not used - workflow tools use execute_workflow()."""
573
+ return "" # Workflow tools use execute_workflow() directly