Refactor
This commit is contained in:
@@ -14,9 +14,9 @@ import os
|
|||||||
# These values are used in server responses and for tracking releases
|
# These values are used in server responses and for tracking releases
|
||||||
# IMPORTANT: This is the single source of truth for version and author info
|
# IMPORTANT: This is the single source of truth for version and author info
|
||||||
# Semantic versioning: MAJOR.MINOR.PATCH
|
# Semantic versioning: MAJOR.MINOR.PATCH
|
||||||
__version__ = "5.0.0"
|
__version__ = "5.0.1"
|
||||||
# Last update date in ISO format
|
# Last update date in ISO format
|
||||||
__updated__ = "2025-06-17"
|
__updated__ = "2025-06-18"
|
||||||
# Primary maintainer
|
# Primary maintainer
|
||||||
__author__ = "Fahad Gilani"
|
__author__ = "Fahad Gilani"
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class TestPrecommitTool:
|
|||||||
assert len(result) == 1
|
assert len(result) == 1
|
||||||
response = json.loads(result[0].text)
|
response = json.loads(result[0].text)
|
||||||
assert response["status"] == "error"
|
assert response["status"] == "error"
|
||||||
assert "must be absolute" in response["content"]
|
assert "must be FULL absolute paths" in response["content"]
|
||||||
assert "./relative/path" in response["content"]
|
assert "./relative/path" in response["content"]
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ class TestAbsolutePathValidation:
|
|||||||
assert len(result) == 1
|
assert len(result) == 1
|
||||||
response = json.loads(result[0].text)
|
response = json.loads(result[0].text)
|
||||||
assert response["status"] == "error"
|
assert response["status"] == "error"
|
||||||
assert "must be absolute" in response["content"]
|
assert "must be FULL absolute paths" in response["content"]
|
||||||
assert "./relative/path.py" in response["content"]
|
assert "./relative/path.py" in response["content"]
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -397,7 +397,7 @@ class TestAbsolutePathValidation:
|
|||||||
assert len(result) == 1
|
assert len(result) == 1
|
||||||
response = json.loads(result[0].text)
|
response = json.loads(result[0].text)
|
||||||
assert response["status"] == "error"
|
assert response["status"] == "error"
|
||||||
assert "must be absolute" in response["content"]
|
assert "must be FULL absolute paths" in response["content"]
|
||||||
assert "../parent/file.py" in response["content"]
|
assert "../parent/file.py" in response["content"]
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -414,7 +414,7 @@ class TestAbsolutePathValidation:
|
|||||||
assert len(result) == 1
|
assert len(result) == 1
|
||||||
response = json.loads(result[0].text)
|
response = json.loads(result[0].text)
|
||||||
assert response["status"] == "error"
|
assert response["status"] == "error"
|
||||||
assert "must be absolute" in response["content"]
|
assert "must be FULL absolute paths" in response["content"]
|
||||||
assert "src/main.py" in response["content"]
|
assert "src/main.py" in response["content"]
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -426,7 +426,7 @@ class TestAbsolutePathValidation:
|
|||||||
assert len(result) == 1
|
assert len(result) == 1
|
||||||
response = json.loads(result[0].text)
|
response = json.loads(result[0].text)
|
||||||
assert response["status"] == "error"
|
assert response["status"] == "error"
|
||||||
assert "must be absolute" in response["content"]
|
assert "must be FULL absolute paths" in response["content"]
|
||||||
assert "./local/file.py" in response["content"]
|
assert "./local/file.py" in response["content"]
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -443,7 +443,7 @@ class TestAbsolutePathValidation:
|
|||||||
assert len(result) == 1
|
assert len(result) == 1
|
||||||
response = json.loads(result[0].text)
|
response = json.loads(result[0].text)
|
||||||
assert response["status"] == "error"
|
assert response["status"] == "error"
|
||||||
assert "must be absolute" in response["content"]
|
assert "must be FULL absolute paths" in response["content"]
|
||||||
assert "code.py" in response["content"]
|
assert "code.py" in response["content"]
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -459,7 +459,7 @@ class TestAbsolutePathValidation:
|
|||||||
assert len(result) == 1
|
assert len(result) == 1
|
||||||
response = json.loads(result[0].text)
|
response = json.loads(result[0].text)
|
||||||
assert response["status"] == "error"
|
assert response["status"] == "error"
|
||||||
assert "must be absolute" in response["content"]
|
assert "must be FULL absolute paths" in response["content"]
|
||||||
assert "src/main.py" in response["content"]
|
assert "src/main.py" in response["content"]
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
|||||||
@@ -19,62 +19,69 @@ from .base import BaseTool, ToolRequest
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Field descriptions to avoid duplication between Pydantic and JSON schema
|
||||||
|
CONSENSUS_FIELD_DESCRIPTIONS = {
|
||||||
|
"prompt": (
|
||||||
|
"Description of what to get consensus on, testing objectives, and specific scope/focus areas. "
|
||||||
|
"Be as detailed as possible about the proposal, plan, or idea you want multiple perspectives on."
|
||||||
|
),
|
||||||
|
"models": (
|
||||||
|
"List of model configurations for consensus analysis. Each model can have a specific stance and custom instructions. "
|
||||||
|
"Example: [{'model': 'o3', 'stance': 'for', 'stance_prompt': 'Focus on benefits and opportunities...'}, "
|
||||||
|
"{'model': 'flash', 'stance': 'against', 'stance_prompt': 'Identify risks and challenges...'}]. "
|
||||||
|
"Maximum 2 instances per model+stance combination."
|
||||||
|
),
|
||||||
|
"files": "Optional files or directories for additional context (must be FULL absolute paths - DO NOT SHORTEN)",
|
||||||
|
"images": (
|
||||||
|
"Optional images showing expected UI changes, design requirements, "
|
||||||
|
"or visual references for the consensus analysis"
|
||||||
|
),
|
||||||
|
"focus_areas": "Specific aspects to focus on (e.g., 'performance', 'security', 'user experience')",
|
||||||
|
"model_config_model": "Model name to use (e.g., 'o3', 'flash', 'pro')",
|
||||||
|
"model_config_stance": (
|
||||||
|
"Stance for this model. Supportive: 'for', 'support', 'favor'. "
|
||||||
|
"Critical: 'against', 'oppose', 'critical'. Neutral: 'neutral'. "
|
||||||
|
"Defaults to 'neutral'."
|
||||||
|
),
|
||||||
|
"model_config_stance_prompt": (
|
||||||
|
"Custom stance-specific instructions for this model. "
|
||||||
|
"If provided, this will be used instead of the default stance prompt. "
|
||||||
|
"Should be clear, specific instructions about how this model should approach the analysis."
|
||||||
|
),
|
||||||
|
"model_config_stance_schema": "Stance for this model: supportive ('for', 'support', 'favor'), critical ('against', 'oppose', 'critical'), or 'neutral'",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ModelConfig(BaseModel):
|
class ModelConfig(BaseModel):
|
||||||
"""Enhanced model configuration for consensus tool"""
|
"""Enhanced model configuration for consensus tool"""
|
||||||
|
|
||||||
model: str = Field(..., description="Model name to use (e.g., 'o3', 'flash', 'pro')")
|
model: str = Field(..., description=CONSENSUS_FIELD_DESCRIPTIONS["model_config_model"])
|
||||||
stance: Optional[str] = Field(
|
stance: Optional[str] = Field(
|
||||||
default="neutral",
|
default="neutral",
|
||||||
description=(
|
description=CONSENSUS_FIELD_DESCRIPTIONS["model_config_stance"],
|
||||||
"Stance for this model. Supportive: 'for', 'support', 'favor'. "
|
|
||||||
"Critical: 'against', 'oppose', 'critical'. Neutral: 'neutral'. "
|
|
||||||
"Defaults to 'neutral'."
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
stance_prompt: Optional[str] = Field(
|
stance_prompt: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description=(
|
description=CONSENSUS_FIELD_DESCRIPTIONS["model_config_stance_prompt"],
|
||||||
"Custom stance-specific instructions for this model. "
|
|
||||||
"If provided, this will be used instead of the default stance prompt. "
|
|
||||||
"Should be clear, specific instructions about how this model should approach the analysis."
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ConsensusRequest(ToolRequest):
|
class ConsensusRequest(ToolRequest):
|
||||||
"""Request model for consensus tool"""
|
"""Request model for consensus tool"""
|
||||||
|
|
||||||
prompt: str = Field(
|
prompt: str = Field(..., description=CONSENSUS_FIELD_DESCRIPTIONS["prompt"])
|
||||||
...,
|
models: list[ModelConfig] = Field(..., description=CONSENSUS_FIELD_DESCRIPTIONS["models"])
|
||||||
description=(
|
|
||||||
"Description of what to get consensus on, testing objectives, and specific scope/focus areas. "
|
|
||||||
"Be as detailed as possible about the proposal, plan, or idea you want multiple perspectives on."
|
|
||||||
),
|
|
||||||
)
|
|
||||||
models: list[ModelConfig] = Field(
|
|
||||||
...,
|
|
||||||
description=(
|
|
||||||
"List of model configurations for consensus analysis. Each model can have a specific stance and custom instructions. "
|
|
||||||
"Example: [{'model': 'o3', 'stance': 'for', 'stance_prompt': 'Focus on benefits and opportunities...'}, "
|
|
||||||
"{'model': 'flash', 'stance': 'against', 'stance_prompt': 'Identify risks and challenges...'}]. "
|
|
||||||
"Maximum 2 instances per model+stance combination."
|
|
||||||
),
|
|
||||||
)
|
|
||||||
files: Optional[list[str]] = Field(
|
files: Optional[list[str]] = Field(
|
||||||
default_factory=list,
|
default_factory=list,
|
||||||
description="Optional files or directories for additional context (must be FULL absolute paths - DO NOT SHORTEN)",
|
description=CONSENSUS_FIELD_DESCRIPTIONS["files"],
|
||||||
)
|
)
|
||||||
images: Optional[list[str]] = Field(
|
images: Optional[list[str]] = Field(
|
||||||
default_factory=list,
|
default_factory=list,
|
||||||
description=(
|
description=CONSENSUS_FIELD_DESCRIPTIONS["images"],
|
||||||
"Optional images showing expected UI changes, design requirements, "
|
|
||||||
"or visual references for the consensus analysis"
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
focus_areas: Optional[list[str]] = Field(
|
focus_areas: Optional[list[str]] = Field(
|
||||||
default_factory=list,
|
default_factory=list,
|
||||||
description="Specific aspects to focus on (e.g., 'performance', 'security', 'user experience')",
|
description=CONSENSUS_FIELD_DESCRIPTIONS["focus_areas"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@field_validator("models")
|
@field_validator("models")
|
||||||
@@ -111,10 +118,7 @@ class ConsensusTool(BaseTool):
|
|||||||
"properties": {
|
"properties": {
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": (
|
"description": CONSENSUS_FIELD_DESCRIPTIONS["prompt"],
|
||||||
"Description of what to get consensus on, testing objectives, and specific scope/focus areas. "
|
|
||||||
"Be as detailed as possible about the proposal, plan, or idea you want multiple perspectives on."
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
"models": {
|
"models": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
@@ -123,45 +127,37 @@ class ConsensusTool(BaseTool):
|
|||||||
"properties": {
|
"properties": {
|
||||||
"model": {
|
"model": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Model name to use (e.g., 'o3', 'flash', 'pro')",
|
"description": CONSENSUS_FIELD_DESCRIPTIONS["model_config_model"],
|
||||||
},
|
},
|
||||||
"stance": {
|
"stance": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["for", "support", "favor", "against", "oppose", "critical", "neutral"],
|
"enum": ["for", "support", "favor", "against", "oppose", "critical", "neutral"],
|
||||||
"description": "Stance for this model: supportive ('for', 'support', 'favor'), critical ('against', 'oppose', 'critical'), or 'neutral'",
|
"description": CONSENSUS_FIELD_DESCRIPTIONS["model_config_stance_schema"],
|
||||||
"default": "neutral",
|
"default": "neutral",
|
||||||
},
|
},
|
||||||
"stance_prompt": {
|
"stance_prompt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Custom stance-specific instructions for this model. If provided, this will be used instead of the default stance prompt.",
|
"description": CONSENSUS_FIELD_DESCRIPTIONS["model_config_stance_prompt"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"required": ["model"],
|
"required": ["model"],
|
||||||
},
|
},
|
||||||
"description": (
|
"description": CONSENSUS_FIELD_DESCRIPTIONS["models"],
|
||||||
"List of model configurations for consensus analysis. Each model can have a specific stance and custom instructions. "
|
|
||||||
"Example: [{'model': 'o3', 'stance': 'for', 'stance_prompt': 'Focus on benefits and opportunities...'}, "
|
|
||||||
"{'model': 'flash', 'stance': 'against', 'stance_prompt': 'Identify risks and challenges...'}]. "
|
|
||||||
"Maximum 2 instances per model+stance combination."
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": "Optional files or directories for additional context (must be FULL absolute paths - DO NOT SHORTEN)",
|
"description": CONSENSUS_FIELD_DESCRIPTIONS["files"],
|
||||||
},
|
},
|
||||||
"images": {
|
"images": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": (
|
"description": CONSENSUS_FIELD_DESCRIPTIONS["images"],
|
||||||
"Optional images showing expected UI changes, design requirements, "
|
|
||||||
"or visual references for the consensus analysis"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
"focus_areas": {
|
"focus_areas": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": "Specific aspects to focus on (e.g., 'performance', 'security', 'user experience')",
|
"description": CONSENSUS_FIELD_DESCRIPTIONS["focus_areas"],
|
||||||
},
|
},
|
||||||
"temperature": {
|
"temperature": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
|
|||||||
@@ -26,62 +26,65 @@ from .base import BaseTool, ToolRequest
|
|||||||
# Conservative fallback for token limits
|
# Conservative fallback for token limits
|
||||||
DEFAULT_CONTEXT_WINDOW = 200_000
|
DEFAULT_CONTEXT_WINDOW = 200_000
|
||||||
|
|
||||||
|
# Field descriptions to avoid duplication between Pydantic and JSON schema
|
||||||
|
PRECOMMIT_FIELD_DESCRIPTIONS = {
|
||||||
|
"path": "Starting directory to search for git repositories (must be FULL absolute paths - DO NOT SHORTEN).",
|
||||||
|
"prompt": (
|
||||||
|
"The original user request description for the changes. Provides critical context for the review. "
|
||||||
|
"If original request is limited or not available, you MUST study the changes carefully, think deeply "
|
||||||
|
"about the implementation intent, analyze patterns across all modifications, infer the logic and "
|
||||||
|
"requirements from the code changes and provide a thorough starting point."
|
||||||
|
),
|
||||||
|
"compare_to": (
|
||||||
|
"Optional: A git ref (branch, tag, commit hash) to compare against. If not provided, reviews local "
|
||||||
|
"staged and unstaged changes."
|
||||||
|
),
|
||||||
|
"include_staged": "Include staged changes in the review. Only applies if 'compare_to' is not set.",
|
||||||
|
"include_unstaged": "Include uncommitted (unstaged) changes in the review. Only applies if 'compare_to' is not set.",
|
||||||
|
"focus_on": "Specific aspects to focus on (e.g., 'logic for user authentication', 'database query efficiency').",
|
||||||
|
"review_type": "Type of review to perform on the changes.",
|
||||||
|
"severity_filter": "Minimum severity level to report on the changes.",
|
||||||
|
"max_depth": "Maximum depth to search for nested git repositories to prevent excessive recursion.",
|
||||||
|
"temperature": "Temperature for the response (0.0 to 1.0). Lower values are more focused and deterministic.",
|
||||||
|
"thinking_mode": "Thinking depth mode for the assistant.",
|
||||||
|
"files": (
|
||||||
|
"Optional files or directories to provide as context (must be FULL absolute paths - DO NOT SHORTEN). "
|
||||||
|
"These files are not part of the changes but provide helpful context like configs, docs, or related code."
|
||||||
|
),
|
||||||
|
"images": (
|
||||||
|
"Optional images showing expected UI changes, design requirements, or visual references for the changes "
|
||||||
|
"being validated"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class PrecommitRequest(ToolRequest):
|
class PrecommitRequest(ToolRequest):
|
||||||
"""Request model for precommit tool"""
|
"""Request model for precommit tool"""
|
||||||
|
|
||||||
path: str = Field(
|
path: str = Field(..., description=PRECOMMIT_FIELD_DESCRIPTIONS["path"])
|
||||||
...,
|
prompt: Optional[str] = Field(None, description=PRECOMMIT_FIELD_DESCRIPTIONS["prompt"])
|
||||||
description="Starting directory to search for git repositories (must be FULL absolute paths - DO NOT SHORTEN).",
|
compare_to: Optional[str] = Field(None, description=PRECOMMIT_FIELD_DESCRIPTIONS["compare_to"])
|
||||||
)
|
include_staged: bool = Field(True, description=PRECOMMIT_FIELD_DESCRIPTIONS["include_staged"])
|
||||||
prompt: Optional[str] = Field(
|
include_unstaged: bool = Field(True, description=PRECOMMIT_FIELD_DESCRIPTIONS["include_unstaged"])
|
||||||
None,
|
focus_on: Optional[str] = Field(None, description=PRECOMMIT_FIELD_DESCRIPTIONS["focus_on"])
|
||||||
description="The original user request description for the changes. Provides critical context for the review. If original request is limited or not available, you MUST study the changes carefully, think deeply about the implementation intent, analyze patterns across all modifications, infer the logic and requirements from the code changes and provide a thorough starting point.",
|
|
||||||
)
|
|
||||||
compare_to: Optional[str] = Field(
|
|
||||||
None,
|
|
||||||
description="Optional: A git ref (branch, tag, commit hash) to compare against. If not provided, reviews local staged and unstaged changes.",
|
|
||||||
)
|
|
||||||
include_staged: bool = Field(
|
|
||||||
True,
|
|
||||||
description="Include staged changes in the review. Only applies if 'compare_to' is not set.",
|
|
||||||
)
|
|
||||||
include_unstaged: bool = Field(
|
|
||||||
True,
|
|
||||||
description="Include uncommitted (unstaged) changes in the review. Only applies if 'compare_to' is not set.",
|
|
||||||
)
|
|
||||||
focus_on: Optional[str] = Field(
|
|
||||||
None,
|
|
||||||
description="Specific aspects to focus on (e.g., 'logic for user authentication', 'database query efficiency').",
|
|
||||||
)
|
|
||||||
review_type: Literal["full", "security", "performance", "quick"] = Field(
|
review_type: Literal["full", "security", "performance", "quick"] = Field(
|
||||||
"full", description="Type of review to perform on the changes."
|
"full", description=PRECOMMIT_FIELD_DESCRIPTIONS["review_type"]
|
||||||
)
|
)
|
||||||
severity_filter: Literal["critical", "high", "medium", "low", "all"] = Field(
|
severity_filter: Literal["critical", "high", "medium", "low", "all"] = Field(
|
||||||
"all",
|
"all", description=PRECOMMIT_FIELD_DESCRIPTIONS["severity_filter"]
|
||||||
description="Minimum severity level to report on the changes.",
|
|
||||||
)
|
|
||||||
max_depth: int = Field(
|
|
||||||
5,
|
|
||||||
description="Maximum depth to search for nested git repositories to prevent excessive recursion.",
|
|
||||||
)
|
)
|
||||||
|
max_depth: int = Field(5, description=PRECOMMIT_FIELD_DESCRIPTIONS["max_depth"])
|
||||||
temperature: Optional[float] = Field(
|
temperature: Optional[float] = Field(
|
||||||
None,
|
None,
|
||||||
description="Temperature for the response (0.0 to 1.0). Lower values are more focused and deterministic.",
|
description=PRECOMMIT_FIELD_DESCRIPTIONS["temperature"],
|
||||||
ge=0.0,
|
ge=0.0,
|
||||||
le=1.0,
|
le=1.0,
|
||||||
)
|
)
|
||||||
thinking_mode: Optional[Literal["minimal", "low", "medium", "high", "max"]] = Field(
|
thinking_mode: Optional[Literal["minimal", "low", "medium", "high", "max"]] = Field(
|
||||||
None, description="Thinking depth mode for the assistant."
|
None, description=PRECOMMIT_FIELD_DESCRIPTIONS["thinking_mode"]
|
||||||
)
|
|
||||||
files: Optional[list[str]] = Field(
|
|
||||||
None,
|
|
||||||
description="Optional files or directories to provide as context (must be FULL absolute paths - DO NOT SHORTEN). These files are not part of the changes but provide helpful context like configs, docs, or related code.",
|
|
||||||
)
|
|
||||||
images: Optional[list[str]] = Field(
|
|
||||||
None,
|
|
||||||
description="Optional images showing expected UI changes, design requirements, or visual references for the changes being validated",
|
|
||||||
)
|
)
|
||||||
|
files: Optional[list[str]] = Field(None, description=PRECOMMIT_FIELD_DESCRIPTIONS["files"])
|
||||||
|
images: Optional[list[str]] = Field(None, description=PRECOMMIT_FIELD_DESCRIPTIONS["images"])
|
||||||
|
|
||||||
|
|
||||||
class Precommit(BaseTool):
|
class Precommit(BaseTool):
|
||||||
@@ -116,68 +119,68 @@ class Precommit(BaseTool):
|
|||||||
"properties": {
|
"properties": {
|
||||||
"path": {
|
"path": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Starting directory to search for git repositories (must be FULL absolute paths - DO NOT SHORTEN).",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["path"],
|
||||||
},
|
},
|
||||||
"model": self.get_model_field_schema(),
|
"model": self.get_model_field_schema(),
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The original user request description for the changes. Provides critical context for the review. If original request is limited or not available, you MUST study the changes carefully, think deeply about the implementation intent, analyze patterns across all modifications, infer the logic and requirements from the code changes and provide a thorough starting point.",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["prompt"],
|
||||||
},
|
},
|
||||||
"compare_to": {
|
"compare_to": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Optional: A git ref (branch, tag, commit hash) to compare against. If not provided, reviews local staged and unstaged changes.",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["compare_to"],
|
||||||
},
|
},
|
||||||
"include_staged": {
|
"include_staged": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": True,
|
"default": True,
|
||||||
"description": "Include staged changes in the review. Only applies if 'compare_to' is not set.",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["include_staged"],
|
||||||
},
|
},
|
||||||
"include_unstaged": {
|
"include_unstaged": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": True,
|
"default": True,
|
||||||
"description": "Include uncommitted (unstaged) changes in the review. Only applies if 'compare_to' is not set.",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["include_unstaged"],
|
||||||
},
|
},
|
||||||
"focus_on": {
|
"focus_on": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Specific aspects to focus on (e.g., 'logic for user authentication', 'database query efficiency').",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["focus_on"],
|
||||||
},
|
},
|
||||||
"review_type": {
|
"review_type": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["full", "security", "performance", "quick"],
|
"enum": ["full", "security", "performance", "quick"],
|
||||||
"default": "full",
|
"default": "full",
|
||||||
"description": "Type of review to perform on the changes.",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["review_type"],
|
||||||
},
|
},
|
||||||
"severity_filter": {
|
"severity_filter": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["critical", "high", "medium", "low", "all"],
|
"enum": ["critical", "high", "medium", "low", "all"],
|
||||||
"default": "all",
|
"default": "all",
|
||||||
"description": "Minimum severity level to report on the changes.",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["severity_filter"],
|
||||||
},
|
},
|
||||||
"max_depth": {
|
"max_depth": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"default": 5,
|
"default": 5,
|
||||||
"description": "Maximum depth to search for nested git repositories to prevent excessive recursion.",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["max_depth"],
|
||||||
},
|
},
|
||||||
"temperature": {
|
"temperature": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"description": "Temperature for the response (0.0 to 1.0). Lower values are more focused and deterministic.",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["temperature"],
|
||||||
"minimum": 0,
|
"minimum": 0,
|
||||||
"maximum": 1,
|
"maximum": 1,
|
||||||
},
|
},
|
||||||
"thinking_mode": {
|
"thinking_mode": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["minimal", "low", "medium", "high", "max"],
|
"enum": ["minimal", "low", "medium", "high", "max"],
|
||||||
"description": "Thinking depth mode for the assistant.",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["thinking_mode"],
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": "Optional files or directories to provide as context (must be FULL absolute paths - DO NOT SHORTEN). These files are not part of the changes but provide helpful context like configs, docs, or related code.",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["files"],
|
||||||
},
|
},
|
||||||
"images": {
|
"images": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": "Optional images showing expected UI changes, design requirements, or visual references for the changes being validated",
|
"description": PRECOMMIT_FIELD_DESCRIPTIONS["images"],
|
||||||
},
|
},
|
||||||
"use_websearch": {
|
"use_websearch": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@@ -27,6 +27,18 @@ from .base import BaseTool, ToolRequest
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Field descriptions to avoid duplication between Pydantic and JSON schema
|
||||||
|
TESTGEN_FIELD_DESCRIPTIONS = {
|
||||||
|
"files": "Code files or directories to generate tests for (must be FULL absolute paths to real files / folders - DO NOT SHORTEN)",
|
||||||
|
"prompt": "Description of what to test, testing objectives, and specific scope/focus areas",
|
||||||
|
"test_examples": (
|
||||||
|
"Optional existing test files or directories to use as style/pattern reference (must be FULL absolute paths to real files / folders - DO NOT SHORTEN). "
|
||||||
|
"If not provided, the tool will determine the best testing approach based on the code structure. "
|
||||||
|
"For large test directories, only the smallest representative tests should be included to determine testing patterns. "
|
||||||
|
"If similar tests exist for the code being tested, include those for the most relevant patterns."
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class TestGenerationRequest(ToolRequest):
|
class TestGenerationRequest(ToolRequest):
|
||||||
"""
|
"""
|
||||||
@@ -37,23 +49,9 @@ class TestGenerationRequest(ToolRequest):
|
|||||||
test examples for style consistency.
|
test examples for style consistency.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
files: list[str] = Field(
|
files: list[str] = Field(..., description=TESTGEN_FIELD_DESCRIPTIONS["files"])
|
||||||
...,
|
prompt: str = Field(..., description=TESTGEN_FIELD_DESCRIPTIONS["prompt"])
|
||||||
description="Code files or directories to generate tests for (must be FULL absolute paths to real files / folders - DO NOT SHORTEN)",
|
test_examples: Optional[list[str]] = Field(None, description=TESTGEN_FIELD_DESCRIPTIONS["test_examples"])
|
||||||
)
|
|
||||||
prompt: str = Field(
|
|
||||||
...,
|
|
||||||
description="Description of what to test, testing objectives, and specific scope/focus areas",
|
|
||||||
)
|
|
||||||
test_examples: Optional[list[str]] = Field(
|
|
||||||
None,
|
|
||||||
description=(
|
|
||||||
"Optional existing test files or directories to use as style/pattern reference (must be FULL absolute paths to real files / folders - DO NOT SHORTEN). "
|
|
||||||
"If not provided, the tool will determine the best testing approach based on the code structure. "
|
|
||||||
"For large test directories, only the smallest representative tests should be included to determine testing patterns. "
|
|
||||||
"If similar tests exist for the code being tested, include those for the most relevant patterns."
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TestGenerationTool(BaseTool):
|
class TestGenerationTool(BaseTool):
|
||||||
@@ -91,22 +89,17 @@ class TestGenerationTool(BaseTool):
|
|||||||
"files": {
|
"files": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": "Code files or directories to generate tests for (must be FULL absolute paths to real files / folders - DO NOT SHORTEN)",
|
"description": TESTGEN_FIELD_DESCRIPTIONS["files"],
|
||||||
},
|
},
|
||||||
"model": self.get_model_field_schema(),
|
"model": self.get_model_field_schema(),
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Description of what to test, testing objectives, and specific scope/focus areas",
|
"description": TESTGEN_FIELD_DESCRIPTIONS["prompt"],
|
||||||
},
|
},
|
||||||
"test_examples": {
|
"test_examples": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": (
|
"description": TESTGEN_FIELD_DESCRIPTIONS["test_examples"],
|
||||||
"Optional existing test files or directories to use as style/pattern reference (must be FULL absolute paths to real files / folders - DO NOT SHORTEN). "
|
|
||||||
"If not provided, the tool will determine the best testing approach based on the code structure. "
|
|
||||||
"For large test directories, only the smallest representative tests will be included to determine testing patterns. "
|
|
||||||
"If similar tests exist for the code being tested, include those for the most relevant patterns."
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
"thinking_mode": {
|
"thinking_mode": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@@ -14,29 +14,29 @@ from systemprompts import THINKDEEP_PROMPT
|
|||||||
|
|
||||||
from .base import BaseTool, ToolRequest
|
from .base import BaseTool, ToolRequest
|
||||||
|
|
||||||
|
# Field descriptions to avoid duplication between Pydantic and JSON schema
|
||||||
|
THINKDEEP_FIELD_DESCRIPTIONS = {
|
||||||
|
"prompt": (
|
||||||
|
"Your current thinking/analysis to extend and validate. IMPORTANT: Before using this tool, Claude MUST "
|
||||||
|
"first think hard and establish a deep understanding of the topic and question by thinking through all "
|
||||||
|
"relevant details, context, constraints, and implications. Share these extended thoughts and ideas in "
|
||||||
|
"the prompt so the model has comprehensive information to work with for the best analysis."
|
||||||
|
),
|
||||||
|
"problem_context": "Additional context about the problem or goal. Be as expressive as possible.",
|
||||||
|
"focus_areas": "Specific aspects to focus on (architecture, performance, security, etc.)",
|
||||||
|
"files": "Optional file paths or directories for additional context (must be FULL absolute paths to real files / folders - DO NOT SHORTEN)",
|
||||||
|
"images": "Optional images for visual analysis - diagrams, charts, system architectures, or any visual information to analyze",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ThinkDeepRequest(ToolRequest):
|
class ThinkDeepRequest(ToolRequest):
|
||||||
"""Request model for thinkdeep tool"""
|
"""Request model for thinkdeep tool"""
|
||||||
|
|
||||||
prompt: str = Field(
|
prompt: str = Field(..., description=THINKDEEP_FIELD_DESCRIPTIONS["prompt"])
|
||||||
...,
|
problem_context: Optional[str] = Field(None, description=THINKDEEP_FIELD_DESCRIPTIONS["problem_context"])
|
||||||
description="Your current thinking/analysis to extend and validate. IMPORTANT: Before using this tool, Claude MUST first think hard and establish a deep understanding of the topic and question by thinking through all relevant details, context, constraints, and implications. Share these extended thoughts and ideas in the prompt so the model has comprehensive information to work with for the best analysis.",
|
focus_areas: Optional[list[str]] = Field(None, description=THINKDEEP_FIELD_DESCRIPTIONS["focus_areas"])
|
||||||
)
|
files: Optional[list[str]] = Field(None, description=THINKDEEP_FIELD_DESCRIPTIONS["files"])
|
||||||
problem_context: Optional[str] = Field(
|
images: Optional[list[str]] = Field(None, description=THINKDEEP_FIELD_DESCRIPTIONS["images"])
|
||||||
None, description="Additional context about the problem or goal. Be as expressive as possible."
|
|
||||||
)
|
|
||||||
focus_areas: Optional[list[str]] = Field(
|
|
||||||
None,
|
|
||||||
description="Specific aspects to focus on (architecture, performance, security, etc.)",
|
|
||||||
)
|
|
||||||
files: Optional[list[str]] = Field(
|
|
||||||
None,
|
|
||||||
description="Optional file paths or directories for additional context (must be FULL absolute paths to real files / folders - DO NOT SHORTEN)",
|
|
||||||
)
|
|
||||||
images: Optional[list[str]] = Field(
|
|
||||||
None,
|
|
||||||
description="Optional images for visual analysis - diagrams, charts, system architectures, or any visual information to analyze",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ThinkDeepTool(BaseTool):
|
class ThinkDeepTool(BaseTool):
|
||||||
@@ -64,33 +64,27 @@ class ThinkDeepTool(BaseTool):
|
|||||||
"properties": {
|
"properties": {
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": (
|
"description": THINKDEEP_FIELD_DESCRIPTIONS["prompt"],
|
||||||
"Your current thinking/analysis to extend and validate. IMPORTANT: Before using this tool, "
|
|
||||||
"Claude MUST first think deeply and establish a deep understanding of the topic and question "
|
|
||||||
"by thinking through all relevant details, context, constraints, and implications. Share "
|
|
||||||
"these extended thoughts and ideas in the prompt so the model has comprehensive information "
|
|
||||||
"to work with for the best analysis."
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
"model": self.get_model_field_schema(),
|
"model": self.get_model_field_schema(),
|
||||||
"problem_context": {
|
"problem_context": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Additional context about the problem or goal. Be as expressive as possible.",
|
"description": THINKDEEP_FIELD_DESCRIPTIONS["problem_context"],
|
||||||
},
|
},
|
||||||
"focus_areas": {
|
"focus_areas": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": "Specific aspects to focus on (architecture, performance, security, etc.)",
|
"description": THINKDEEP_FIELD_DESCRIPTIONS["focus_areas"],
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": "Optional file paths or directories for additional context (must be FULL absolute paths to real files / folders - DO NOT SHORTEN)",
|
"description": THINKDEEP_FIELD_DESCRIPTIONS["files"],
|
||||||
},
|
},
|
||||||
"images": {
|
"images": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": "Optional images for visual analysis - diagrams, charts, system architectures, or any visual information to analyze",
|
"description": THINKDEEP_FIELD_DESCRIPTIONS["images"],
|
||||||
},
|
},
|
||||||
"temperature": {
|
"temperature": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
|
|||||||
@@ -12,6 +12,27 @@ from pydantic import Field
|
|||||||
|
|
||||||
from .base import BaseTool, ToolRequest
|
from .base import BaseTool, ToolRequest
|
||||||
|
|
||||||
|
# Field descriptions to avoid duplication between Pydantic and JSON schema
|
||||||
|
TRACER_FIELD_DESCRIPTIONS = {
|
||||||
|
"prompt": (
|
||||||
|
"Detailed description of what to trace and WHY you need this analysis. Include context about what "
|
||||||
|
"you're trying to understand, debug, or analyze. For precision mode: describe the specific "
|
||||||
|
"method/function and what aspect of its execution flow you need to understand. For dependencies "
|
||||||
|
"mode: describe the class/module and what relationships you need to map. Example: 'I need to "
|
||||||
|
"understand how BookingManager.finalizeInvoice method is called throughout the system and what "
|
||||||
|
"side effects it has, as I'm debugging payment processing issues' rather than just "
|
||||||
|
"'BookingManager finalizeInvoice method'"
|
||||||
|
),
|
||||||
|
"trace_mode": (
|
||||||
|
"Trace mode: 'precision' (for methods/functions - shows execution flow and usage patterns) or "
|
||||||
|
"'dependencies' (for classes/modules/protocols - shows structural relationships)"
|
||||||
|
),
|
||||||
|
"images": (
|
||||||
|
"Optional images of system architecture diagrams, flow charts, or visual references to help "
|
||||||
|
"understand the tracing context"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class TracerRequest(ToolRequest):
|
class TracerRequest(ToolRequest):
|
||||||
"""
|
"""
|
||||||
@@ -20,32 +41,9 @@ class TracerRequest(ToolRequest):
|
|||||||
This model defines the parameters for generating analysis prompts.
|
This model defines the parameters for generating analysis prompts.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
prompt: str = Field(
|
prompt: str = Field(..., description=TRACER_FIELD_DESCRIPTIONS["prompt"])
|
||||||
...,
|
trace_mode: Literal["precision", "dependencies"] = Field(..., description=TRACER_FIELD_DESCRIPTIONS["trace_mode"])
|
||||||
description=(
|
images: list[str] = Field(default_factory=list, description=TRACER_FIELD_DESCRIPTIONS["images"])
|
||||||
"Detailed description of what to trace and WHY you need this analysis. Include context about what "
|
|
||||||
"you're trying to understand, debug, or analyze. For precision mode: describe the specific "
|
|
||||||
"method/function and what aspect of its execution flow you need to understand. For dependencies "
|
|
||||||
"mode: describe the class/module and what relationships you need to map. Example: 'I need to "
|
|
||||||
"understand how BookingManager.finalizeInvoice method is called throughout the system and what "
|
|
||||||
"side effects it has, as I'm debugging payment processing issues' rather than just "
|
|
||||||
"'BookingManager finalizeInvoice method'"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
trace_mode: Literal["precision", "dependencies"] = Field(
|
|
||||||
...,
|
|
||||||
description=(
|
|
||||||
"Trace mode: 'precision' (for methods/functions - shows execution flow and usage patterns) or "
|
|
||||||
"'dependencies' (for classes/modules/protocols - shows structural relationships)"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
images: list[str] = Field(
|
|
||||||
default_factory=list,
|
|
||||||
description=(
|
|
||||||
"Optional images of system architecture diagrams, flow charts, or visual references to help "
|
|
||||||
"understand the tracing context"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TracerTool(BaseTool):
|
class TracerTool(BaseTool):
|
||||||
@@ -79,25 +77,17 @@ class TracerTool(BaseTool):
|
|||||||
"properties": {
|
"properties": {
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": (
|
"description": TRACER_FIELD_DESCRIPTIONS["prompt"],
|
||||||
"Detailed description of what to trace and WHY you need this analysis. Include context "
|
|
||||||
"about what you're trying to understand, debug, or analyze. For precision mode: describe "
|
|
||||||
"the specific method/function and what aspect of its execution flow you need to understand. "
|
|
||||||
"For dependencies mode: describe the class/module and what relationships you need to map. "
|
|
||||||
"Example: 'I need to understand how BookingManager.finalizeInvoice method is called "
|
|
||||||
"throughout the system and what side effects it has, as I'm debugging payment processing "
|
|
||||||
"issues' rather than just 'BookingManager finalizeInvoice method'"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
"trace_mode": {
|
"trace_mode": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["precision", "dependencies"],
|
"enum": ["precision", "dependencies"],
|
||||||
"description": "Trace mode: 'precision' (for methods/functions - shows execution flow and usage patterns) or 'dependencies' (for classes/modules/protocols - shows structural relationships)",
|
"description": TRACER_FIELD_DESCRIPTIONS["trace_mode"],
|
||||||
},
|
},
|
||||||
"images": {
|
"images": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": "Optional images of system architecture diagrams, flow charts, or visual references to help understand the tracing context",
|
"description": TRACER_FIELD_DESCRIPTIONS["images"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"required": ["prompt", "trace_mode"],
|
"required": ["prompt", "trace_mode"],
|
||||||
|
|||||||
Reference in New Issue
Block a user