models.pyโข17.7 kB
"""
Data models for tool responses and interactions
"""
from enum import Enum
from typing import Any, Literal, Optional
from pydantic import BaseModel, Field
class ToolModelCategory(Enum):
"""Categories for tool model selection based on requirements."""
EXTENDED_REASONING = "extended_reasoning" # Requires deep thinking capabilities
FAST_RESPONSE = "fast_response" # Speed and cost efficiency preferred
BALANCED = "balanced" # Balance of capability and performance
class ContinuationOffer(BaseModel):
"""Offer for CLI agent to continue conversation when Gemini doesn't ask follow-up"""
continuation_id: str = Field(
..., description="Thread continuation ID for multi-turn conversations across different tools"
)
note: str = Field(..., description="Message explaining continuation opportunity to CLI agent")
remaining_turns: int = Field(..., description="Number of conversation turns remaining")
class ToolOutput(BaseModel):
"""Standardized output format for all tools"""
status: Literal[
"success",
"error",
"files_required_to_continue",
"full_codereview_required",
"focused_review_required",
"test_sample_needed",
"more_tests_required",
"refactor_analysis_complete",
"trace_complete",
"resend_prompt",
"code_too_large",
"continuation_available",
"no_bug_found",
] = "success"
content: Optional[str] = Field(None, description="The main content/response from the tool")
content_type: Literal["text", "markdown", "json"] = "text"
metadata: Optional[dict[str, Any]] = Field(default_factory=dict)
continuation_offer: Optional[ContinuationOffer] = Field(
None, description="Optional offer for Agent to continue conversation"
)
class FilesNeededRequest(BaseModel):
"""Request for missing files / code to continue"""
status: Literal["files_required_to_continue"] = "files_required_to_continue"
mandatory_instructions: str = Field(..., description="Critical instructions for Agent regarding required context")
files_needed: Optional[list[str]] = Field(
default_factory=list, description="Specific files that are needed for analysis"
)
suggested_next_action: Optional[dict[str, Any]] = Field(
None,
description="Suggested tool call with parameters after getting clarification",
)
class FullCodereviewRequired(BaseModel):
"""Request for full code review when scope is too large for quick review"""
status: Literal["full_codereview_required"] = "full_codereview_required"
important: Optional[str] = Field(None, description="Important message about escalation")
reason: Optional[str] = Field(None, description="Reason why full review is needed")
class FocusedReviewRequired(BaseModel):
"""Request for Agent to provide smaller, focused subsets of code for review"""
status: Literal["focused_review_required"] = "focused_review_required"
reason: str = Field(..., description="Why the current scope is too large for effective review")
suggestion: str = Field(
..., description="Suggested approach for breaking down the review into smaller, focused parts"
)
class TestSampleNeeded(BaseModel):
"""Request for additional test samples to determine testing framework"""
status: Literal["test_sample_needed"] = "test_sample_needed"
reason: str = Field(..., description="Reason why additional test samples are required")
class MoreTestsRequired(BaseModel):
"""Request for continuation to generate additional tests"""
status: Literal["more_tests_required"] = "more_tests_required"
pending_tests: str = Field(..., description="List of pending tests to be generated")
class RefactorOpportunity(BaseModel):
"""A single refactoring opportunity with precise targeting information"""
id: str = Field(..., description="Unique identifier for this refactoring opportunity")
type: Literal["decompose", "codesmells", "modernize", "organization"] = Field(
..., description="Type of refactoring"
)
severity: Literal["critical", "high", "medium", "low"] = Field(..., description="Severity level")
file: str = Field(..., description="Absolute path to the file")
start_line: int = Field(..., description="Starting line number")
end_line: int = Field(..., description="Ending line number")
context_start_text: str = Field(..., description="Exact text from start line for verification")
context_end_text: str = Field(..., description="Exact text from end line for verification")
issue: str = Field(..., description="Clear description of what needs refactoring")
suggestion: str = Field(..., description="Specific refactoring action to take")
rationale: str = Field(..., description="Why this improves the code")
code_to_replace: str = Field(..., description="Original code that should be changed")
replacement_code_snippet: str = Field(..., description="Refactored version of the code")
new_code_snippets: Optional[list[dict]] = Field(
default_factory=list, description="Additional code snippets to be added"
)
class RefactorAction(BaseModel):
"""Next action for Agent to implement refactoring"""
action_type: Literal["EXTRACT_METHOD", "SPLIT_CLASS", "MODERNIZE_SYNTAX", "REORGANIZE_CODE", "DECOMPOSE_FILE"] = (
Field(..., description="Type of action to perform")
)
target_file: str = Field(..., description="Absolute path to target file")
source_lines: str = Field(..., description="Line range (e.g., '45-67')")
description: str = Field(..., description="Step-by-step action description for CLI Agent")
class RefactorAnalysisComplete(BaseModel):
"""Complete refactor analysis with prioritized opportunities"""
status: Literal["refactor_analysis_complete"] = "refactor_analysis_complete"
refactor_opportunities: list[RefactorOpportunity] = Field(..., description="List of refactoring opportunities")
priority_sequence: list[str] = Field(..., description="Recommended order of refactoring IDs")
next_actions: list[RefactorAction] = Field(..., description="Specific actions for the agent to implement")
class CodeTooLargeRequest(BaseModel):
"""Request to reduce file selection due to size constraints"""
status: Literal["code_too_large"] = "code_too_large"
content: str = Field(..., description="Message explaining the size constraint")
content_type: Literal["text"] = "text"
metadata: dict[str, Any] = Field(default_factory=dict)
class ResendPromptRequest(BaseModel):
"""Request to resend prompt via file due to size limits"""
status: Literal["resend_prompt"] = "resend_prompt"
content: str = Field(..., description="Instructions for handling large prompt")
content_type: Literal["text"] = "text"
metadata: dict[str, Any] = Field(default_factory=dict)
class TraceEntryPoint(BaseModel):
"""Entry point information for trace analysis"""
file: str = Field(..., description="Absolute path to the file")
class_or_struct: str = Field(..., description="Class or module name")
method: str = Field(..., description="Method or function name")
signature: str = Field(..., description="Full method signature")
parameters: Optional[dict[str, Any]] = Field(default_factory=dict, description="Parameter values used in analysis")
class TraceTarget(BaseModel):
"""Target information for dependency analysis"""
file: str = Field(..., description="Absolute path to the file")
class_or_struct: str = Field(..., description="Class or module name")
method: str = Field(..., description="Method or function name")
signature: str = Field(..., description="Full method signature")
class CallPathStep(BaseModel):
"""A single step in the call path trace"""
from_info: dict[str, Any] = Field(..., description="Source location information", alias="from")
to: dict[str, Any] = Field(..., description="Target location information")
reason: str = Field(..., description="Reason for the call or dependency")
condition: Optional[str] = Field(None, description="Conditional logic if applicable")
ambiguous: bool = Field(False, description="Whether this call is ambiguous")
class BranchingPoint(BaseModel):
"""A branching point in the execution flow"""
file: str = Field(..., description="File containing the branching point")
method: str = Field(..., description="Method containing the branching point")
line: int = Field(..., description="Line number of the branching point")
condition: str = Field(..., description="Branching condition")
branches: list[str] = Field(..., description="Possible execution branches")
ambiguous: bool = Field(False, description="Whether the branching is ambiguous")
class SideEffect(BaseModel):
"""A side effect detected in the trace"""
type: str = Field(..., description="Type of side effect")
description: str = Field(..., description="Description of the side effect")
file: str = Field(..., description="File where the side effect occurs")
method: str = Field(..., description="Method where the side effect occurs")
line: int = Field(..., description="Line number of the side effect")
class UnresolvedDependency(BaseModel):
"""An unresolved dependency in the trace"""
reason: str = Field(..., description="Reason why the dependency is unresolved")
affected_file: str = Field(..., description="File affected by the unresolved dependency")
line: int = Field(..., description="Line number of the unresolved dependency")
class IncomingDependency(BaseModel):
"""An incoming dependency (what calls this target)"""
from_file: str = Field(..., description="Source file of the dependency")
from_class: str = Field(..., description="Source class of the dependency")
from_method: str = Field(..., description="Source method of the dependency")
line: int = Field(..., description="Line number of the dependency")
type: str = Field(..., description="Type of dependency")
class OutgoingDependency(BaseModel):
"""An outgoing dependency (what this target calls)"""
to_file: str = Field(..., description="Target file of the dependency")
to_class: str = Field(..., description="Target class of the dependency")
to_method: str = Field(..., description="Target method of the dependency")
line: int = Field(..., description="Line number of the dependency")
type: str = Field(..., description="Type of dependency")
class TypeDependency(BaseModel):
"""A type-level dependency (inheritance, imports, etc.)"""
dependency_type: str = Field(..., description="Type of dependency")
source_file: str = Field(..., description="Source file of the dependency")
source_entity: str = Field(..., description="Source entity (class, module)")
target: str = Field(..., description="Target entity")
class StateAccess(BaseModel):
"""State access information"""
file: str = Field(..., description="File where state is accessed")
method: str = Field(..., description="Method accessing the state")
access_type: str = Field(..., description="Type of access (reads, writes, etc.)")
state_entity: str = Field(..., description="State entity being accessed")
class TraceComplete(BaseModel):
"""Complete trace analysis response"""
status: Literal["trace_complete"] = "trace_complete"
trace_type: Literal["precision", "dependencies"] = Field(..., description="Type of trace performed")
# Precision mode fields
entry_point: Optional[TraceEntryPoint] = Field(None, description="Entry point for precision trace")
call_path: Optional[list[CallPathStep]] = Field(default_factory=list, description="Call path for precision trace")
branching_points: Optional[list[BranchingPoint]] = Field(default_factory=list, description="Branching points")
side_effects: Optional[list[SideEffect]] = Field(default_factory=list, description="Side effects detected")
unresolved: Optional[list[UnresolvedDependency]] = Field(
default_factory=list, description="Unresolved dependencies"
)
# Dependencies mode fields
target: Optional[TraceTarget] = Field(None, description="Target for dependency analysis")
incoming_dependencies: Optional[list[IncomingDependency]] = Field(
default_factory=list, description="Incoming dependencies"
)
outgoing_dependencies: Optional[list[OutgoingDependency]] = Field(
default_factory=list, description="Outgoing dependencies"
)
type_dependencies: Optional[list[TypeDependency]] = Field(default_factory=list, description="Type dependencies")
state_access: Optional[list[StateAccess]] = Field(default_factory=list, description="State access information")
class DiagnosticHypothesis(BaseModel):
"""A debugging hypothesis with context and next steps"""
rank: int = Field(..., description="Ranking of this hypothesis (1 = most likely)")
confidence: Literal["high", "medium", "low"] = Field(..., description="Confidence level")
hypothesis: str = Field(..., description="Description of the potential root cause")
reasoning: str = Field(..., description="Why this hypothesis is plausible")
next_step: str = Field(..., description="Suggested action to test/validate this hypothesis")
class StructuredDebugResponse(BaseModel):
"""Enhanced debug response with multiple hypotheses"""
summary: str = Field(..., description="Brief summary of the issue")
hypotheses: list[DiagnosticHypothesis] = Field(..., description="Ranked list of potential causes")
immediate_actions: list[str] = Field(
default_factory=list,
description="Immediate steps to take regardless of root cause",
)
additional_context_needed: Optional[list[str]] = Field(
default_factory=list,
description="Additional files or information that would help with analysis",
)
class DebugHypothesis(BaseModel):
"""A debugging hypothesis with detailed analysis"""
name: str = Field(..., description="Name/title of the hypothesis")
confidence: Literal["High", "Medium", "Low"] = Field(..., description="Confidence level")
root_cause: str = Field(..., description="Technical explanation of the root cause")
evidence: str = Field(..., description="Logs or code clues supporting this hypothesis")
correlation: str = Field(..., description="How symptoms map to the cause")
validation: str = Field(..., description="Quick test to confirm the hypothesis")
minimal_fix: str = Field(..., description="Smallest change to resolve the issue")
regression_check: str = Field(..., description="Why this fix is safe")
file_references: list[str] = Field(default_factory=list, description="File:line format for exact locations")
class DebugAnalysisComplete(BaseModel):
"""Complete debugging analysis with systematic investigation tracking"""
status: Literal["analysis_complete"] = "analysis_complete"
investigation_id: str = Field(..., description="Auto-generated unique ID for this investigation")
summary: str = Field(..., description="Brief description of the problem and its impact")
investigation_steps: list[str] = Field(..., description="Steps taken during the investigation")
hypotheses: list[DebugHypothesis] = Field(..., description="Ranked hypotheses with detailed analysis")
key_findings: list[str] = Field(..., description="Important discoveries made during analysis")
immediate_actions: list[str] = Field(..., description="Steps to take regardless of which hypothesis is correct")
recommended_tools: list[str] = Field(default_factory=list, description="Additional tools recommended for analysis")
prevention_strategy: Optional[str] = Field(
None, description="Targeted measures to prevent this exact issue from recurring"
)
investigation_summary: str = Field(
..., description="Comprehensive summary of the complete investigation process and conclusions"
)
class NoBugFound(BaseModel):
"""Response when thorough investigation finds no concrete evidence of a bug"""
status: Literal["no_bug_found"] = "no_bug_found"
summary: str = Field(..., description="Summary of what was thoroughly investigated")
investigation_steps: list[str] = Field(..., description="Steps taken during the investigation")
areas_examined: list[str] = Field(..., description="Code areas and potential failure points examined")
confidence_level: Literal["High", "Medium", "Low"] = Field(
..., description="Confidence level in the no-bug finding"
)
alternative_explanations: list[str] = Field(
..., description="Possible alternative explanations for reported symptoms"
)
recommended_questions: list[str] = Field(..., description="Questions to clarify the issue with the user")
next_steps: list[str] = Field(..., description="Suggested actions to better understand the reported issue")
# Registry mapping status strings to their corresponding Pydantic models
SPECIAL_STATUS_MODELS = {
"files_required_to_continue": FilesNeededRequest,
"full_codereview_required": FullCodereviewRequired,
"focused_review_required": FocusedReviewRequired,
"test_sample_needed": TestSampleNeeded,
"more_tests_required": MoreTestsRequired,
"refactor_analysis_complete": RefactorAnalysisComplete,
"trace_complete": TraceComplete,
"resend_prompt": ResendPromptRequest,
"code_too_large": CodeTooLargeRequest,
"analysis_complete": DebugAnalysisComplete,
"no_bug_found": NoBugFound,
}