refactor(models): Refine MessageAgentThought SQLAlchemy typing#162
Conversation
Review Summary by QodoRefine MessageAgentThought SQLAlchemy typing and improve agent data handling
WalkthroughsDescription• Refine MessageAgentThought SQLAlchemy model with proper type annotations - Convert to TypeBase inheritance for consistency - Add Mapped type hints for all columns - Use Decimal type for numeric price fields • Improve agent thought data handling and validation - Add AgentThoughtValidation Pydantic model for data validation - Fix string concatenation logic in save_agent_thought method - Use CreatorUserRole enum instead of string literal • Enhance tool data processing in organize_agent_history method - Improve null-safety checks for tool input and observation payloads - Add explicit null handling before JSON parsing - Fix tool response content assignment bug • Update test fixtures to remove manual id assignment - Leverage auto-generated UUID defaults in model Diagramflowchart LR
A["MessageAgentThought Model"] -->|"Add Mapped type hints"| B["Proper SQLAlchemy Typing"]
A -->|"Use Decimal type"| C["Numeric Price Fields"]
A -->|"Inherit TypeBase"| D["Consistent Base Class"]
E["Agent Thought Processing"] -->|"Add validation model"| F["AgentThoughtValidation"]
E -->|"Improve null-safety"| G["Better Error Handling"]
E -->|"Fix string logic"| H["Correct Concatenation"]
I["Test Fixtures"] -->|"Remove manual IDs"| J["Use Auto-Generated UUIDs"]
File Changes1. api/models/model.py
|
Code Review by Qodo
1. Pydantic v1 Config used
|
| 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') | ||
|
|
There was a problem hiding this comment.
1. Pydantic v1 config used 📘 Rule violation ✓ Correctness
AgentThoughtValidation uses Pydantic v1-style class Config and allows extra fields, which weakens validation and violates the required Pydantic v2 configuration pattern. This can permit unexpected/unvalidated data to pass through persistence logic.
Agent Prompt
## Issue description
`AgentThoughtValidation` is implemented with Pydantic v1-style `class Config` and sets `extra = "allow"`, which violates the requirement to use Pydantic v2 configuration (`ConfigDict`) and to forbid undeclared fields by default.
## Issue Context
The compliance requirement mandates Pydantic v2 patterns for DTO/data validation and `ConfigDict(extra='forbid')` by default to prevent unexpected fields.
## Fix Focus Areas
- api/core/agent/base_agent_runner.py[52-66]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| ) | ||
| tool_call_response.append( | ||
| ToolPromptMessage( | ||
| content=tool_responses.get(tool, agent_thought.observation), | ||
| content=str(tool_inputs.get(tool, agent_thought.observation)), | ||
| name=tool, | ||
| tool_call_id=tool_call_id, | ||
| ) |
There was a problem hiding this comment.
2. Tool output uses inputs 🐞 Bug ✓ Correctness
BaseAgentRunner.organize_agent_history populates ToolPromptMessage.content from tool_inputs instead of the tool observation payload, so reconstructed history feeds the LLM the tool arguments rather than the tool results. This can break follow-up reasoning because prior tool call outputs are missing/incorrect in the prompt history.
Agent Prompt
### Issue description
`BaseAgentRunner.organize_agent_history()` builds `ToolPromptMessage` instances with `content` sourced from `tool_inputs` (the tool arguments) instead of `tool_responses` (the tool observations/outputs). This causes reconstructed conversation history to provide the LLM incorrect tool-role messages.
### Issue Context
Elsewhere, tool-role messages are constructed from tool invocation results (see `fc_agent_runner.py`), and `MessageAgentThought.observation` is treated as tool outputs (see `tool_outputs_dict` and `AgentService.get_agent_logs`).
### Fix Focus Areas
- api/core/agent/base_agent_runner.py[487-506]
### Suggested change
Replace:
- `content=str(tool_inputs.get(tool, agent_thought.observation))`
With something equivalent to:
- `content=str(tool_responses.get(tool, agent_thought.observation))`
Optionally keep the same fallback behavior if `tool_responses` is not a dict (defensive cast) and ensure `tool_responses` is always defined for the loop.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Benchmark PR from agentic-review-benchmarks#11