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/thinkdeep.py ADDED
@@ -0,0 +1,586 @@
1
+ """
2
+ ThinkDeep Workflow Tool - Extended Reasoning with Systematic Investigation
3
+
4
+ This tool provides step-by-step deep thinking capabilities using a systematic workflow approach.
5
+ It enables comprehensive analysis of complex problems with expert validation at completion.
6
+
7
+ Key Features:
8
+ - Systematic step-by-step thinking process
9
+ - Multi-step analysis with evidence gathering
10
+ - Confidence-based investigation flow
11
+ - Expert analysis integration with external models
12
+ - Support for focused analysis areas (architecture, performance, security, etc.)
13
+ - Confidence-based workflow optimization
14
+ """
15
+
16
+ import logging
17
+ from typing import TYPE_CHECKING, Any, Optional
18
+
19
+ from pydantic import Field
20
+
21
+ if TYPE_CHECKING:
22
+ from tools.models import ToolModelCategory
23
+
24
+ from config import TEMPERATURE_CREATIVE
25
+ from systemprompts import THINKDEEP_PROMPT
26
+ from tools.shared.base_models import WorkflowRequest
27
+
28
+ from .workflow.base import WorkflowTool
29
+
30
+ logger = logging.getLogger(__name__)
31
+
32
+
33
+ class ThinkDeepWorkflowRequest(WorkflowRequest):
34
+ """Request model for thinkdeep workflow tool with comprehensive investigation capabilities"""
35
+
36
+ # Core workflow parameters
37
+ step: str = Field(description="Current work step content and findings")
38
+ step_number: int = Field(description="Current step number (starts at 1)", ge=1)
39
+ total_steps: int = Field(description="Estimated total steps needed", ge=1)
40
+ next_step_required: bool = Field(description="Whether another step is needed")
41
+ findings: str = Field(
42
+ description="Discoveries: insights, connections, implications, evidence. "
43
+ "Document contradictions to earlier assumptions. Update past findings."
44
+ )
45
+
46
+ # Investigation tracking
47
+ files_checked: list[str] = Field(
48
+ default_factory=list,
49
+ description="All files examined (absolute paths). Include ruled-out files.",
50
+ )
51
+ relevant_files: list[str] = Field(
52
+ default_factory=list,
53
+ description="Files relevant to problem/goal (absolute paths). Include root cause, solution, key insights.",
54
+ )
55
+ relevant_context: list[str] = Field(
56
+ default_factory=list,
57
+ description="Key concepts/methods: 'concept_name' or 'ClassName.methodName'. Focus on core insights, decision points.",
58
+ )
59
+ hypothesis: Optional[str] = Field(
60
+ default=None,
61
+ description="Current theory based on evidence. Revise in later steps.",
62
+ )
63
+
64
+ # Analysis metadata
65
+ issues_found: list[dict] = Field(
66
+ default_factory=list,
67
+ description="Issues with dict: 'severity' (critical/high/medium/low), 'description'.",
68
+ )
69
+ confidence: str = Field(
70
+ default="low",
71
+ description="exploring/low/medium/high/very_high/almost_certain/certain. CRITICAL: 'certain' PREVENTS external validation.",
72
+ )
73
+
74
+ # Expert analysis configuration - keep these fields available for configuring the final assistant model
75
+ # in expert analysis (commented out exclude=True)
76
+ temperature: Optional[float] = Field(
77
+ default=None,
78
+ description="Creative thinking temp (0-1, default 0.7)",
79
+ ge=0.0,
80
+ le=1.0,
81
+ )
82
+ thinking_mode: Optional[str] = Field(
83
+ default=None,
84
+ description="Depth: minimal/low/medium/high/max. Default 'high'.",
85
+ )
86
+ # Context files and investigation scope
87
+ problem_context: Optional[str] = Field(
88
+ default=None,
89
+ description="Additional context about problem/goal. Be expressive.",
90
+ )
91
+ focus_areas: Optional[list[str]] = Field(
92
+ default=None,
93
+ description="Focus aspects (architecture, performance, security, etc.)",
94
+ )
95
+
96
+
97
+ class ThinkDeepTool(WorkflowTool):
98
+ """
99
+ ThinkDeep Workflow Tool - Systematic Deep Thinking Analysis
100
+
101
+ Provides comprehensive step-by-step thinking capabilities with expert validation.
102
+ Uses workflow architecture for systematic investigation and analysis.
103
+ """
104
+
105
+ name = "thinkdeep"
106
+ description = (
107
+ "Performs multi-stage investigation and reasoning for complex problem analysis. "
108
+ "Use for architecture decisions, complex bugs, performance challenges, and security analysis. "
109
+ "Provides systematic hypothesis testing, evidence-based investigation, and expert validation."
110
+ )
111
+
112
+ def __init__(self):
113
+ """Initialize the ThinkDeep workflow tool"""
114
+ super().__init__()
115
+ # Storage for request parameters to use in expert analysis
116
+ self.stored_request_params = {}
117
+
118
+ def get_name(self) -> str:
119
+ """Return the tool name"""
120
+ return self.name
121
+
122
+ def get_description(self) -> str:
123
+ """Return the tool description"""
124
+ return self.description
125
+
126
+ def get_model_category(self) -> "ToolModelCategory":
127
+ """Return the model category for this tool"""
128
+ from tools.models import ToolModelCategory
129
+
130
+ return ToolModelCategory.EXTENDED_REASONING
131
+
132
+ def get_workflow_request_model(self):
133
+ """Return the workflow request model for this tool"""
134
+ return ThinkDeepWorkflowRequest
135
+
136
+ def get_input_schema(self) -> dict[str, Any]:
137
+ """Generate input schema using WorkflowSchemaBuilder with thinkdeep-specific overrides."""
138
+ from .workflow.schema_builders import WorkflowSchemaBuilder
139
+
140
+ # ThinkDeep workflow-specific field overrides
141
+ thinkdeep_field_overrides = {
142
+ "problem_context": {
143
+ "type": "string",
144
+ "description": "Additional context about problem/goal. Be expressive.",
145
+ },
146
+ "focus_areas": {
147
+ "type": "array",
148
+ "items": {"type": "string"},
149
+ "description": "Focus aspects (architecture, performance, security, etc.)",
150
+ },
151
+ }
152
+
153
+ # Use WorkflowSchemaBuilder with thinkdeep-specific tool fields
154
+ return WorkflowSchemaBuilder.build_schema(
155
+ tool_specific_fields=thinkdeep_field_overrides,
156
+ model_field_schema=self.get_model_field_schema(),
157
+ auto_mode=self.is_effective_auto_mode(),
158
+ tool_name=self.get_name(),
159
+ )
160
+
161
+ def get_system_prompt(self) -> str:
162
+ """Return the system prompt for this workflow tool"""
163
+ return THINKDEEP_PROMPT
164
+
165
+ def get_default_temperature(self) -> float:
166
+ """Return default temperature for deep thinking"""
167
+ return TEMPERATURE_CREATIVE
168
+
169
+ def get_default_thinking_mode(self) -> str:
170
+ """Return default thinking mode for thinkdeep"""
171
+ from config import DEFAULT_THINKING_MODE_THINKDEEP
172
+
173
+ return DEFAULT_THINKING_MODE_THINKDEEP
174
+
175
+ def customize_workflow_response(self, response_data: dict, request, **kwargs) -> dict:
176
+ """
177
+ Customize the workflow response for thinkdeep-specific needs
178
+ """
179
+ # Store request parameters for later use in expert analysis
180
+ self.stored_request_params = {}
181
+ try:
182
+ self.stored_request_params["temperature"] = request.temperature
183
+ except AttributeError:
184
+ self.stored_request_params["temperature"] = None
185
+
186
+ try:
187
+ self.stored_request_params["thinking_mode"] = request.thinking_mode
188
+ except AttributeError:
189
+ self.stored_request_params["thinking_mode"] = None
190
+
191
+ # Add thinking-specific context to response
192
+ response_data.update(
193
+ {
194
+ "thinking_status": {
195
+ "current_step": request.step_number,
196
+ "total_steps": request.total_steps,
197
+ "files_checked": len(request.files_checked),
198
+ "relevant_files": len(request.relevant_files),
199
+ "thinking_confidence": request.confidence,
200
+ "analysis_focus": request.focus_areas or ["general"],
201
+ }
202
+ }
203
+ )
204
+
205
+ # Add thinking_complete field for final steps (test expects this)
206
+ if not request.next_step_required:
207
+ response_data["thinking_complete"] = True
208
+
209
+ # Add complete_thinking summary (test expects this)
210
+ response_data["complete_thinking"] = {
211
+ "steps_completed": len(self.work_history),
212
+ "final_confidence": request.confidence,
213
+ "relevant_context": list(self.consolidated_findings.relevant_context),
214
+ "key_findings": self.consolidated_findings.findings,
215
+ "issues_identified": self.consolidated_findings.issues_found,
216
+ "files_analyzed": list(self.consolidated_findings.relevant_files),
217
+ }
218
+
219
+ # Add thinking-specific completion message based on confidence
220
+ if request.confidence == "certain":
221
+ response_data["completion_message"] = (
222
+ "Deep thinking analysis is complete with high certainty. "
223
+ "All aspects have been thoroughly considered and conclusions are definitive."
224
+ )
225
+ elif not request.next_step_required and not self.get_request_use_assistant_model(request):
226
+ response_data["completion_message"] = (
227
+ "Deep thinking analysis is complete. Present the caller's findings; expert validation was disabled."
228
+ )
229
+ elif not request.next_step_required:
230
+ response_data["completion_message"] = (
231
+ "Deep thinking analysis phase complete. Expert validation will provide additional insights and recommendations."
232
+ )
233
+
234
+ return response_data
235
+
236
+ def should_skip_expert_analysis(self, request, consolidated_findings) -> bool:
237
+ """
238
+ ThinkDeep tool skips expert analysis when the CLI agent has "certain" confidence.
239
+ """
240
+ return request.confidence == "certain" and not request.next_step_required
241
+
242
+ def get_completion_status(self) -> str:
243
+ """ThinkDeep tools use thinking-specific status."""
244
+ return "deep_thinking_complete_ready_for_implementation"
245
+
246
+ def get_completion_data_key(self) -> str:
247
+ """ThinkDeep uses 'complete_thinking' key."""
248
+ return "complete_thinking"
249
+
250
+ def get_final_analysis_from_request(self, request):
251
+ """ThinkDeep tools use 'findings' field."""
252
+ return request.findings
253
+
254
+ def get_skip_expert_analysis_status(self) -> str:
255
+ """Status when skipping expert analysis for certain confidence."""
256
+ return "skipped_due_to_certain_thinking_confidence"
257
+
258
+ def get_skip_reason(self) -> str:
259
+ """Reason for skipping expert analysis."""
260
+ return "Expressed 'certain' confidence in the deep thinking analysis - no additional validation needed"
261
+
262
+ def get_completion_message(self) -> str:
263
+ """Message for completion without expert analysis."""
264
+ return "Deep thinking analysis complete with certain confidence. Proceed with implementation based on the analysis."
265
+
266
+ def customize_expert_analysis_prompt(self, base_prompt: str, request, file_content: str = "") -> str:
267
+ """
268
+ Customize the expert analysis prompt for deep thinking validation
269
+ """
270
+ thinking_context = f"""
271
+ DEEP THINKING ANALYSIS VALIDATION
272
+
273
+ You are reviewing a comprehensive deep thinking analysis completed through systematic investigation.
274
+ Your role is to validate the thinking process, identify any gaps, challenge assumptions, and provide
275
+ additional insights or alternative perspectives.
276
+
277
+ ANALYSIS SCOPE:
278
+ - Problem Context: {self._get_problem_context(request)}
279
+ - Focus Areas: {', '.join(self._get_focus_areas(request))}
280
+ - Investigation Confidence: {request.confidence}
281
+ - Steps Completed: {request.step_number} of {request.total_steps}
282
+
283
+ THINKING SUMMARY:
284
+ {request.findings}
285
+
286
+ KEY INSIGHTS AND CONTEXT:
287
+ {', '.join(request.relevant_context) if request.relevant_context else 'No specific context identified'}
288
+
289
+ VALIDATION OBJECTIVES:
290
+ 1. Assess the depth and quality of the thinking process
291
+ 2. Identify any logical gaps, missing considerations, or flawed assumptions
292
+ 3. Suggest alternative approaches or perspectives not considered
293
+ 4. Validate the conclusions and recommendations
294
+ 5. Provide actionable next steps for implementation
295
+
296
+ Be thorough but constructive in your analysis. Challenge the thinking where appropriate,
297
+ but also acknowledge strong insights and valid conclusions.
298
+ """
299
+
300
+ if file_content:
301
+ thinking_context += f"\n\nFILE CONTEXT:\n{file_content}"
302
+
303
+ return f"{thinking_context}\n\n{base_prompt}"
304
+
305
+ def get_expert_analysis_instructions(self) -> str:
306
+ """
307
+ Return instructions for expert analysis specific to deep thinking validation
308
+ """
309
+ return (
310
+ "DEEP THINKING ANALYSIS IS COMPLETE. You MUST now summarize and present ALL thinking insights, "
311
+ "alternative approaches considered, risks and trade-offs identified, and final recommendations. "
312
+ "Clearly prioritize the top solutions or next steps that emerged from the analysis. "
313
+ "Provide concrete, actionable guidance based on the deep thinking—make it easy for the user to "
314
+ "understand exactly what to do next and how to implement the best solution."
315
+ )
316
+
317
+ # Override hook methods to use stored request parameters for expert analysis
318
+
319
+ def get_request_temperature(self, request) -> float:
320
+ """Use stored temperature from initial request."""
321
+ try:
322
+ stored_params = self.stored_request_params
323
+ if stored_params and stored_params.get("temperature") is not None:
324
+ return stored_params["temperature"]
325
+ except AttributeError:
326
+ pass
327
+ return super().get_request_temperature(request)
328
+
329
+ def get_request_thinking_mode(self, request) -> str:
330
+ """Use stored thinking mode from initial request."""
331
+ try:
332
+ stored_params = self.stored_request_params
333
+ if stored_params and stored_params.get("thinking_mode") is not None:
334
+ return stored_params["thinking_mode"]
335
+ except AttributeError:
336
+ pass
337
+ return super().get_request_thinking_mode(request)
338
+
339
+ def _get_problem_context(self, request) -> str:
340
+ """Get problem context from request. Override for custom context handling."""
341
+ try:
342
+ return request.problem_context or "General analysis"
343
+ except AttributeError:
344
+ return "General analysis"
345
+
346
+ def _get_focus_areas(self, request) -> list[str]:
347
+ """Get focus areas from request. Override for custom focus area handling."""
348
+ try:
349
+ return request.focus_areas or ["comprehensive analysis"]
350
+ except AttributeError:
351
+ return ["comprehensive analysis"]
352
+
353
+ def get_required_actions(
354
+ self, step_number: int, confidence: str, findings: str, total_steps: int, request=None
355
+ ) -> list[str]:
356
+ """
357
+ Return required actions for the current thinking step.
358
+ """
359
+ actions = []
360
+
361
+ if step_number == 1:
362
+ actions.extend(
363
+ [
364
+ "Begin systematic thinking analysis",
365
+ "Identify key aspects and assumptions to explore",
366
+ "Establish initial investigation approach",
367
+ ]
368
+ )
369
+ elif confidence == "low":
370
+ actions.extend(
371
+ [
372
+ "Continue gathering evidence and insights",
373
+ "Test initial hypotheses",
374
+ "Explore alternative perspectives",
375
+ ]
376
+ )
377
+ elif confidence == "medium":
378
+ actions.extend(
379
+ [
380
+ "Deepen analysis of promising approaches",
381
+ "Validate key assumptions",
382
+ "Consider implementation challenges",
383
+ ]
384
+ )
385
+ elif confidence == "high":
386
+ actions.extend(
387
+ [
388
+ "Refine and validate key findings",
389
+ "Explore edge cases and limitations",
390
+ "Document assumptions and trade-offs",
391
+ ]
392
+ )
393
+ elif confidence == "very_high":
394
+ actions.extend(
395
+ [
396
+ "Synthesize findings into cohesive recommendations",
397
+ "Validate conclusions against all evidence",
398
+ "Prepare comprehensive implementation guidance",
399
+ ]
400
+ )
401
+ elif confidence == "almost_certain":
402
+ actions.extend(
403
+ [
404
+ "Finalize recommendations with high confidence",
405
+ "Document any remaining minor uncertainties",
406
+ "Prepare for expert analysis or implementation",
407
+ ]
408
+ )
409
+ else: # certain
410
+ actions.append("Analysis complete - ready for implementation")
411
+
412
+ return actions
413
+
414
+ def should_call_expert_analysis(self, consolidated_findings, request=None) -> bool:
415
+ """
416
+ Determine if expert analysis should be called based on confidence and completion.
417
+ """
418
+ if request and not self.get_request_use_assistant_model(request):
419
+ return False
420
+ if request:
421
+ try:
422
+ # Don't call expert analysis if confidence is "certain"
423
+ if request.confidence == "certain":
424
+ return False
425
+ except AttributeError:
426
+ pass
427
+
428
+ # Call expert analysis if investigation is complete (when next_step_required is False)
429
+ if request:
430
+ try:
431
+ return not request.next_step_required
432
+ except AttributeError:
433
+ pass
434
+
435
+ # Fallback: call expert analysis if we have meaningful findings
436
+ return (
437
+ len(consolidated_findings.relevant_files) > 0
438
+ or len(consolidated_findings.findings) >= 2
439
+ or len(consolidated_findings.issues_found) > 0
440
+ )
441
+
442
+ def prepare_expert_analysis_context(self, consolidated_findings) -> str:
443
+ """
444
+ Prepare context for expert analysis specific to deep thinking.
445
+ """
446
+ context_parts = []
447
+
448
+ context_parts.append("DEEP THINKING ANALYSIS SUMMARY:")
449
+ context_parts.append(f"Steps completed: {len(consolidated_findings.findings)}")
450
+ context_parts.append(f"Final confidence: {consolidated_findings.confidence}")
451
+
452
+ if consolidated_findings.findings:
453
+ context_parts.append("\nKEY FINDINGS:")
454
+ for i, finding in enumerate(consolidated_findings.findings, 1):
455
+ context_parts.append(f"{i}. {finding}")
456
+
457
+ if consolidated_findings.relevant_context:
458
+ context_parts.append(f"\nRELEVANT CONTEXT:\n{', '.join(consolidated_findings.relevant_context)}")
459
+
460
+ # Get hypothesis from latest hypotheses entry if available
461
+ if consolidated_findings.hypotheses:
462
+ latest_hypothesis = consolidated_findings.hypotheses[-1].get("hypothesis", "")
463
+ if latest_hypothesis:
464
+ context_parts.append(f"\nFINAL HYPOTHESIS:\n{latest_hypothesis}")
465
+
466
+ if consolidated_findings.issues_found:
467
+ context_parts.append(f"\nISSUES IDENTIFIED: {len(consolidated_findings.issues_found)} issues")
468
+ for issue in consolidated_findings.issues_found:
469
+ context_parts.append(
470
+ f"- {issue.get('severity', 'unknown')}: {issue.get('description', 'No description')}"
471
+ )
472
+
473
+ return "\n".join(context_parts)
474
+
475
+ def get_step_guidance_message(self, request) -> str:
476
+ """
477
+ Generate guidance for the next step in thinking analysis
478
+ """
479
+ if request.next_step_required:
480
+ next_step_number = request.step_number + 1
481
+
482
+ if request.confidence == "certain":
483
+ guidance = (
484
+ f"Your thinking analysis confidence is CERTAIN. Consider if you truly need step {next_step_number} "
485
+ f"or if you should complete the analysis now with expert validation."
486
+ )
487
+ elif request.confidence == "almost_certain":
488
+ guidance = (
489
+ f"Your thinking analysis confidence is ALMOST_CERTAIN. For step {next_step_number}, consider: "
490
+ f"finalizing recommendations, documenting any minor uncertainties, or preparing for implementation."
491
+ )
492
+ elif request.confidence == "very_high":
493
+ guidance = (
494
+ f"Your thinking analysis confidence is VERY_HIGH. For step {next_step_number}, consider: "
495
+ f"synthesis of all findings, comprehensive validation, or creating implementation roadmap."
496
+ )
497
+ elif request.confidence == "high":
498
+ guidance = (
499
+ f"Your thinking analysis confidence is HIGH. For step {next_step_number}, consider: "
500
+ f"exploring edge cases, documenting trade-offs, or stress-testing key assumptions."
501
+ )
502
+ elif request.confidence == "medium":
503
+ guidance = (
504
+ f"Your thinking analysis confidence is MEDIUM. For step {next_step_number}, focus on: "
505
+ f"deepening insights, exploring alternative approaches, or gathering additional evidence."
506
+ )
507
+ else: # low or exploring
508
+ guidance = (
509
+ f"Your thinking analysis confidence is {request.confidence.upper()}. For step {next_step_number}, "
510
+ f"continue investigating: gather more evidence, test hypotheses, or explore different angles."
511
+ )
512
+
513
+ # Add specific thinking guidance based on progress
514
+ if request.step_number == 1:
515
+ guidance += (
516
+ " Consider: What are the key assumptions? What evidence supports or contradicts initial theories? "
517
+ "What alternative approaches exist?"
518
+ )
519
+ elif request.step_number >= request.total_steps // 2:
520
+ guidance += (
521
+ " Consider: Synthesis of findings, validation of conclusions, identification of implementation "
522
+ "challenges, and preparation for expert analysis."
523
+ )
524
+
525
+ return guidance
526
+ else:
527
+ return "Thinking analysis is ready for expert validation and final recommendations."
528
+
529
+ def format_final_response(self, assistant_response: str, request, **kwargs) -> dict:
530
+ """
531
+ Format the final response from the assistant for thinking analysis
532
+ """
533
+ response_data = {
534
+ "thinking_analysis": assistant_response,
535
+ "analysis_metadata": {
536
+ "total_steps_completed": request.step_number,
537
+ "final_confidence": request.confidence,
538
+ "files_analyzed": len(request.relevant_files),
539
+ "key_insights": len(request.relevant_context),
540
+ "issues_identified": len(request.issues_found),
541
+ },
542
+ }
543
+
544
+ # Add completion status
545
+ if request.confidence == "certain":
546
+ response_data["completion_status"] = "analysis_complete_with_certainty"
547
+ else:
548
+ response_data["completion_status"] = "analysis_complete_pending_validation"
549
+
550
+ return response_data
551
+
552
+ def format_step_response(
553
+ self,
554
+ assistant_response: str,
555
+ request,
556
+ status: str = "pause_for_thinkdeep",
557
+ continuation_id: Optional[str] = None,
558
+ **kwargs,
559
+ ) -> dict:
560
+ """
561
+ Format intermediate step responses for thinking workflow
562
+ """
563
+ response_data = super().format_step_response(assistant_response, request, status, continuation_id, **kwargs)
564
+
565
+ # Add thinking-specific step guidance
566
+ step_guidance = self.get_step_guidance_message(request)
567
+ response_data["thinking_guidance"] = step_guidance
568
+
569
+ # Add analysis progress indicators
570
+ response_data["analysis_progress"] = {
571
+ "step_completed": request.step_number,
572
+ "remaining_steps": max(0, request.total_steps - request.step_number),
573
+ "confidence_trend": request.confidence,
574
+ "investigation_depth": "expanding" if request.next_step_required else "finalizing",
575
+ }
576
+
577
+ return response_data
578
+
579
+ # Required abstract methods from BaseTool
580
+ def get_request_model(self):
581
+ """Return the thinkdeep workflow-specific request model."""
582
+ return ThinkDeepWorkflowRequest
583
+
584
+ async def prepare_prompt(self, request) -> str:
585
+ """Not used - workflow tools use execute_workflow()."""
586
+ return "" # Workflow tools use execute_workflow() directly