Skip to content

refactor(models): Refine MessageAgentThought SQLAlchemy typing#11

Open
tomerqodo wants to merge 2 commits intocopilot_full_base_refactormodels_refine_messageagentthought_sqlalchemy_typing_pr11from
copilot_full_head_refactormodels_refine_messageagentthought_sqlalchemy_typing_pr11
Open

refactor(models): Refine MessageAgentThought SQLAlchemy typing#11
tomerqodo wants to merge 2 commits intocopilot_full_base_refactormodels_refine_messageagentthought_sqlalchemy_typing_pr11from
copilot_full_head_refactormodels_refine_messageagentthought_sqlalchemy_typing_pr11

Conversation

@tomerqodo
Copy link
Copy Markdown

Benchmark PR from agentic-review-benchmarks#11

Copilot AI review requested due to automatic review settings January 25, 2026 22:51
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the MessageAgentThought SQLAlchemy model to use stricter typing with TypeBase (which extends MappedAsDataclass) instead of the plain Base class. The changes add comprehensive type annotations using Mapped[] for all fields, configure proper defaults, and adjust related code to work with the new model structure.

Changes:

  • Converted MessageAgentThought from Base to TypeBase with full Mapped[] type annotations for all fields
  • Updated field definitions with explicit default values and properly configured auto-generated ID field with init=False
  • Modified create_agent_thought and related methods in BaseAgentRunner to use correct types (Decimal for prices, proper enums)
  • Removed explicit id parameter from test fixtures since IDs are now auto-generated
  • Refactored organize_agent_history method to improve null handling and variable naming

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 10 comments.

File Description
api/models/model.py Converted MessageAgentThought to TypeBase with comprehensive Mapped[] type annotations, proper defaults, and field ordering for dataclass compatibility
api/core/agent/base_agent_runner.py Updated agent thought creation/manipulation to use Decimal types, CreatorUserRole enum, added AgentThoughtValidation model, and refactored organize_agent_history for better null safety
api/tests/test_containers_integration_tests/services/test_agent_service.py Removed explicit id assignments from MessageAgentThought instantiations in tests to work with auto-generated IDs

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

total_price=0,
position=self.agent_thought_count + 1,
currency="USD",
latency=0,
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type inconsistency: The field latency is defined as Mapped[float | None] in the model (line 1878 of model.py), but here it's being assigned an integer value 0. While Python will implicitly convert this, for type consistency and clarity, consider using 0.0 instead.

Suggested change
latency=0,
latency=0.0,

Copilot uses AI. Check for mistakes.
tool_call_response.append(
ToolPromptMessage(
content=tool_responses.get(tool, agent_thought.observation),
content=str(tool_inputs.get(tool, agent_thought.observation)),
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical bug: The ToolPromptMessage content should use tool_responses.get(tool, ...) instead of tool_inputs.get(tool, ...). This will incorrectly send tool inputs as tool responses, causing the agent to receive the wrong information about tool execution results. The tool_responses dictionary was properly parsed from observation_payload on lines 478-485 but is not being used here.

Suggested change
content=str(tool_inputs.get(tool, agent_thought.observation)),
content=str(tool_responses.get(tool, agent_thought.observation)),

Copilot uses AI. Check for mistakes.
answer_unit_price=Decimal("0.001"),
answer_price_unit=Decimal(0),
tokens=0,
total_price=0,
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type mismatch: The field total_price is defined as Mapped[Decimal | None] in the model (line 1876 of model.py), but here it's being assigned an integer value 0. This should be Decimal(0) to match the expected type, maintaining consistency with other Decimal fields like message_unit_price and answer_unit_price.

Suggested change
total_price=0,
total_price=Decimal(0),

Copilot uses AI. Check for mistakes.
Comment on lines +319 to +320
message_unit_price=Decimal(0),
message_price_unit=Decimal("0.001"),
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential value swap: The values for message_unit_price and message_price_unit appear to be swapped. Typically, unit_price represents the cost per unit (e.g., per token) which should be a small value like 0.001, while the price_unit denomination would be 0 initially. Based on the model defaults (lines 1864-1867 in model.py), message_unit_price should be 0 or None (nullable), and message_price_unit should be Decimal("0.001") (non-nullable with default). Consider swapping these values to match the expected pattern.

Copilot uses AI. Check for mistakes.
Comment on lines +325 to +326
answer_unit_price=Decimal("0.001"),
answer_price_unit=Decimal(0),
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential value swap: The values for answer_unit_price and answer_price_unit appear to be swapped. Similar to the message fields above, answer_unit_price should typically be a small value like 0.001 or None (as it's nullable), while answer_price_unit should be 0 initially but defaults to Decimal("0.001") per the model definition. Based on the model defaults (lines 1871-1874 in model.py), consider swapping these values: answer_unit_price=Decimal(0) and answer_price_unit=Decimal("0.001").

Suggested change
answer_unit_price=Decimal("0.001"),
answer_price_unit=Decimal(0),
answer_unit_price=Decimal(0),
answer_price_unit=Decimal("0.001"),

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +65
class Config:
extra = "allow" # Pydantic v1 syntax - should use ConfigDict(extra='forbid')
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pydantic version inconsistency: The code uses Pydantic v1 syntax with class Config and extra = "allow", but the codebase has migrated to Pydantic v2 which uses model_config = ConfigDict(extra="allow"). For consistency with the rest of the codebase (see examples in api/core/mcp/types.py, api/core/app/app_config/features/more_like_this/manager.py, etc.), this should be updated to use the v2 syntax. Additionally, the comment mentions using extra='forbid', but the actual setting is extra='allow' - if validation is intended, consider whether 'forbid' would be more appropriate.

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +66
class AgentThoughtValidation(BaseModel):
"""
Validation model for agent thought data before database persistence.
"""

message_id: str
position: int
thought: str | None = None
tool: str | None = None
tool_input: str | None = None
observation: str | None = None

class Config:
extra = "allow" # Pydantic v1 syntax - should use ConfigDict(extra='forbid')

Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AgentThoughtValidation class is defined but never used anywhere in the codebase. If this validation model is not intended to be used yet, consider removing it to avoid dead code. If it's planned for future use, consider adding a TODO comment explaining the intended usage.

Copilot uses AI. Check for mistakes.
Comment on lines +478 to +486
observation_payload = agent_thought.observation
if observation_payload:
try:
tool_responses = json.loads(observation_payload)
except Exception:
tool_responses = dict.fromkeys(tool_names, observation_payload)
else:
tool_responses = dict.fromkeys(tool_names, observation_payload)

Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment to 'tool_responses' is unnecessary as it is redefined before this value is used.
This assignment to 'tool_responses' is unnecessary as it is redefined before this value is used.

Suggested change
observation_payload = agent_thought.observation
if observation_payload:
try:
tool_responses = json.loads(observation_payload)
except Exception:
tool_responses = dict.fromkeys(tool_names, observation_payload)
else:
tool_responses = dict.fromkeys(tool_names, observation_payload)

Copilot uses AI. Check for mistakes.
Comment on lines +478 to +486
observation_payload = agent_thought.observation
if observation_payload:
try:
tool_responses = json.loads(observation_payload)
except Exception:
tool_responses = dict.fromkeys(tool_names, observation_payload)
else:
tool_responses = dict.fromkeys(tool_names, observation_payload)

Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment to 'tool_responses' is unnecessary as it is redefined before this value is used.
This assignment to 'tool_responses' is unnecessary as it is redefined before this value is used.

Suggested change
observation_payload = agent_thought.observation
if observation_payload:
try:
tool_responses = json.loads(observation_payload)
except Exception:
tool_responses = dict.fromkeys(tool_names, observation_payload)
else:
tool_responses = dict.fromkeys(tool_names, observation_payload)

Copilot uses AI. Check for mistakes.
Comment on lines +478 to +486
observation_payload = agent_thought.observation
if observation_payload:
try:
tool_responses = json.loads(observation_payload)
except Exception:
tool_responses = dict.fromkeys(tool_names, observation_payload)
else:
tool_responses = dict.fromkeys(tool_names, observation_payload)

Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment to 'tool_responses' is unnecessary as it is redefined before this value is used.
This assignment to 'tool_responses' is unnecessary as it is redefined before this value is used.

Suggested change
observation_payload = agent_thought.observation
if observation_payload:
try:
tool_responses = json.loads(observation_payload)
except Exception:
tool_responses = dict.fromkeys(tool_names, observation_payload)
else:
tool_responses = dict.fromkeys(tool_names, observation_payload)

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants