Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🤖 Refactor RootCause Model to Use Optional Types and Introduce Tests #1642

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 20 additions & 24 deletions src/seer/automation/autofix/components/root_cause/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ class RootCauseAnalysisItem(BaseModel):
id: int = -1
title: str
description: str
# unit_test: UnitTestSnippet | None = None
# reproduction: str | None = None
unit_test: Optional[UnitTestSnippet] = None
reproduction: Optional[str] = None
code_context: Optional[list[RootCauseRelevantContext]] = None

def to_markdown_string(self) -> str:
Expand All @@ -91,25 +91,25 @@ def to_markdown_string(self) -> str:
class RootCauseAnalysisItemPrompt(BaseModel):
title: str
description: str
# reproduction_instructions: str | None = None
# unit_test: UnitTestSnippetPrompt | None = None
relevant_code: Optional[RootCauseAnalysisRelevantContext]
unit_test: Optional[UnitTestSnippetPrompt] = None
reproduction_instructions: Optional[str] = None

@classmethod
def from_model(cls, model: RootCauseAnalysisItem):
return cls(
title=model.title,
description=model.description,
# reproduction_instructions=model.reproduction,
# unit_test=(
# UnitTestSnippetPrompt(
# file_path=model.unit_test.file_path,
# code_snippet=model.unit_test.snippet,
# description=model.unit_test.description,
# )
# if model.unit_test
# else None
# ),
reproduction_instructions=model.reproduction,
unit_test=(
UnitTestSnippetPrompt(
file_path=model.unit_test.file_path,
code_snippet=model.unit_test.snippet,
description=model.unit_test.description,
)
if model.unit_test
else None
),
relevant_code=(
RootCauseAnalysisRelevantContext(
snippets=[
Expand All @@ -131,16 +131,12 @@ def to_model(self):
return RootCauseAnalysisItem.model_validate(
{
**self.model_dump(),
# "reproduction": self.reproduction_instructions,
# "unit_test": (
# {
# "file_path": self.unit_test.file_path,
# "snippet": self.unit_test.code_snippet,
# "description": self.unit_test.description,
# }
# if self.unit_test
# else None
# ),
"reproduction": self.reproduction_instructions,
"unit_test": {
"file_path": self.unit_test.file_path,
"snippet": self.unit_test.code_snippet,
"description": self.unit_test.description,
} if self.unit_test else None,
"code_context": (
self.relevant_code.model_dump()["snippets"] if self.relevant_code else None
),
Expand Down
101 changes: 101 additions & 0 deletions tests/automation/autofix/components/test_root_cause.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
MultipleRootCauseAnalysisOutputPrompt,
RootCauseAnalysisItemPrompt,
RootCauseAnalysisRelevantContext,
RootCauseAnalysisItem,
RootCauseAnalysisRequest,
RootCauseRelevantCodeSnippet,
RootCauseRelevantContext,
Expand Down Expand Up @@ -329,6 +330,56 @@ def test_root_cause_line_numbers_file_not_found(self, component, mock_agent):
assert output.causes[0].code_context[0].snippet.start_line is None
assert output.causes[0].code_context[0].snippet.end_line is None

def test_root_cause_analysis_item_validation(self):
# Test that model validates without unit_test field
item = RootCauseAnalysisItem(
id=0,
title="Test Title",
description="Test Description",
code_context=None
)
assert item.model_dump() == {
"id": 0,
"title": "Test Title",
"description": "Test Description",
"code_context": None,
"unit_test": None,
"reproduction": None
}

# Test that prompt to_model() works without optional fields
prompt = RootCauseAnalysisItemPrompt(
title="Test Title",
description="Test Description",
relevant_code=None
)
model = prompt.to_model()
assert model.unit_test is None
assert model.reproduction is None

# Test with all optional fields present
snippet = RootCauseRelevantCodeSnippet(
file_path="test.py",
snippet="def test():\n pass"
)
context = RootCauseRelevantContext(
id=0,
title="Test Context",
description="Test Description",
snippet=snippet
)
item = RootCauseAnalysisItem(
id=0,
title="Test Title",
description="Test Description",
code_context=[context],
unit_test=None,
reproduction=None
)
assert item.model_dump()["code_context"] is not None
assert item.model_dump()["unit_test"] is None
assert item.model_dump()["reproduction"] is None

def test_root_cause_line_numbers_no_match(self, component, mock_agent):
mock_agent.return_value.run.side_effect = [
"Some root cause analysis",
Expand Down Expand Up @@ -377,3 +428,53 @@ def test_root_cause_line_numbers_no_match(self, component, mock_agent):
# Verify that the output is still generated but without line numbers
assert output.causes[0].code_context[0].snippet.start_line is None
assert output.causes[0].code_context[0].snippet.end_line is None

def test_root_cause_analysis_item_validation(self):
# Test that model validates without unit_test field
item = RootCauseAnalysisItem(
id=0,
title="Test Title",
description="Test Description",
code_context=None
)
assert item.model_dump() == {
"id": 0,
"title": "Test Title",
"description": "Test Description",
"code_context": None,
"unit_test": None,
"reproduction": None
}

# Test that prompt to_model() works without optional fields
prompt = RootCauseAnalysisItemPrompt(
title="Test Title",
description="Test Description",
relevant_code=None
)
model = prompt.to_model()
assert model.unit_test is None
assert model.reproduction is None

# Test with all optional fields present
snippet = RootCauseRelevantCodeSnippet(
file_path="test.py",
snippet="def test():\n pass"
)
context = RootCauseRelevantContext(
id=0,
title="Test Context",
description="Test Description",
snippet=snippet
)
item = RootCauseAnalysisItem(
id=0,
title="Test Title",
description="Test Description",
code_context=[context],
unit_test=None,
reproduction=None
)
assert item.model_dump()["code_context"] is not None
assert item.model_dump()["unit_test"] is None
assert item.model_dump()["reproduction"] is None
Loading