-
Notifications
You must be signed in to change notification settings - Fork 0
Code Review Bench PR #27749 - refactor(models): Refine MessageAgentThought SQLAlchemy typing #11
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
base: base_pr_27749_20260125_2703
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -1,8 +1,10 @@ | ||||||||
| import json | ||||||||
| import logging | ||||||||
| import uuid | ||||||||
| from decimal import Decimal | ||||||||
| from typing import Union, cast | ||||||||
|
|
||||||||
| from pydantic import BaseModel | ||||||||
| from sqlalchemy import select | ||||||||
|
|
||||||||
| from core.agent.entities import AgentEntity, AgentToolEntity | ||||||||
|
|
@@ -41,11 +43,28 @@ | |||||||
| from core.tools.utils.dataset_retriever_tool import DatasetRetrieverTool | ||||||||
| from extensions.ext_database import db | ||||||||
| from factories import file_factory | ||||||||
| from models.enums import CreatorUserRole | ||||||||
| from models.model import Conversation, Message, MessageAgentThought, MessageFile | ||||||||
|
|
||||||||
| logger = logging.getLogger(__name__) | ||||||||
|
|
||||||||
|
|
||||||||
| 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') | ||||||||
|
|
||||||||
|
|
||||||||
| class BaseAgentRunner(AppRunner): | ||||||||
| def __init__( | ||||||||
| self, | ||||||||
|
|
@@ -289,27 +308,28 @@ def create_agent_thought( | |||||||
| thought = MessageAgentThought( | ||||||||
| message_id=message_id, | ||||||||
| message_chain_id=None, | ||||||||
| tool_process_data=None, | ||||||||
| thought="", | ||||||||
| tool=tool_name, | ||||||||
| tool_labels_str="{}", | ||||||||
| tool_meta_str="{}", | ||||||||
| tool_input=tool_input, | ||||||||
| message=message, | ||||||||
| message_token=0, | ||||||||
| message_unit_price=0, | ||||||||
| message_price_unit=0, | ||||||||
| message_unit_price=Decimal(0), | ||||||||
| message_price_unit=Decimal("0.001"), | ||||||||
| message_files=json.dumps(messages_ids) if messages_ids else "", | ||||||||
| answer="", | ||||||||
| observation="", | ||||||||
| answer_token=0, | ||||||||
| answer_unit_price=0, | ||||||||
| answer_price_unit=0, | ||||||||
| answer_unit_price=Decimal("0.001"), | ||||||||
| answer_price_unit=Decimal(0), | ||||||||
| tokens=0, | ||||||||
| total_price=0, | ||||||||
| position=self.agent_thought_count + 1, | ||||||||
| currency="USD", | ||||||||
| latency=0, | ||||||||
| created_by_role="account", | ||||||||
| created_by_role=CreatorUserRole.ACCOUNT, | ||||||||
| created_by=self.user_id, | ||||||||
| ) | ||||||||
|
|
||||||||
|
|
@@ -342,7 +362,8 @@ def save_agent_thought( | |||||||
| raise ValueError("agent thought not found") | ||||||||
|
|
||||||||
| if thought: | ||||||||
| agent_thought.thought += thought | ||||||||
| existing_thought = agent_thought.thought or "" | ||||||||
| agent_thought.thought = f"{existing_thought}{thought}" | ||||||||
|
|
||||||||
| if tool_name: | ||||||||
| agent_thought.tool = tool_name | ||||||||
|
|
@@ -440,21 +461,30 @@ def organize_agent_history(self, prompt_messages: list[PromptMessage]) -> list[P | |||||||
| agent_thoughts: list[MessageAgentThought] = message.agent_thoughts | ||||||||
| if agent_thoughts: | ||||||||
| for agent_thought in agent_thoughts: | ||||||||
| tools = agent_thought.tool | ||||||||
| if tools: | ||||||||
| tools = tools.split(";") | ||||||||
| tool_names_raw = agent_thought.tool | ||||||||
| if tool_names_raw: | ||||||||
| tool_names = tool_names_raw.split(";") | ||||||||
| tool_calls: list[AssistantPromptMessage.ToolCall] = [] | ||||||||
| tool_call_response: list[ToolPromptMessage] = [] | ||||||||
| try: | ||||||||
| tool_inputs = json.loads(agent_thought.tool_input) | ||||||||
| except Exception: | ||||||||
| tool_inputs = {tool: {} for tool in tools} | ||||||||
| try: | ||||||||
| tool_responses = json.loads(agent_thought.observation) | ||||||||
| except Exception: | ||||||||
| tool_responses = dict.fromkeys(tools, agent_thought.observation) | ||||||||
|
|
||||||||
| for tool in tools: | ||||||||
| tool_input_payload = agent_thought.tool_input | ||||||||
| if tool_input_payload: | ||||||||
| try: | ||||||||
| tool_inputs = json.loads(tool_input_payload) | ||||||||
| except Exception: | ||||||||
| tool_inputs = {tool: {} for tool in tool_names} | ||||||||
| else: | ||||||||
| tool_inputs = {tool: {} for tool in tool_names} | ||||||||
|
|
||||||||
| 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) | ||||||||
|
|
||||||||
| for tool in tool_names: | ||||||||
| # generate a uuid for tool call | ||||||||
| tool_call_id = str(uuid.uuid4()) | ||||||||
| tool_calls.append( | ||||||||
|
|
@@ -469,7 +499,7 @@ def organize_agent_history(self, prompt_messages: list[PromptMessage]) -> list[P | |||||||
| ) | ||||||||
| tool_call_response.append( | ||||||||
| ToolPromptMessage( | ||||||||
| content=tool_responses.get(tool, agent_thought.observation), | ||||||||
| content=str(tool_inputs.get(tool, agent_thought.observation)), | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚨 Bug: ToolPromptMessage uses tool_inputs instead of tool_responsesThe This corrupts the agent's conversation history, causing the LLM to see tool inputs where it should see tool results. This will lead to incorrect agent behavior in multi-turn conversations that reference prior tool usage. The original code using Was this helpful? React with 👍 / 👎
Suggested change
|
||||||||
| name=tool, | ||||||||
| tool_call_id=tool_call_id, | ||||||||
| ) | ||||||||
|
|
@@ -484,7 +514,7 @@ def organize_agent_history(self, prompt_messages: list[PromptMessage]) -> list[P | |||||||
| *tool_call_response, | ||||||||
| ] | ||||||||
| ) | ||||||||
| if not tools: | ||||||||
| if not tool_names_raw: | ||||||||
| result.append(AssistantPromptMessage(content=agent_thought.thought)) | ||||||||
| else: | ||||||||
| if message.answer: | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The initial values for
answer_unit_priceandanswer_price_unitare swapped compared to theirmessage_*counterparts:The semantics of
*_unit_price(the cost per token) and*_price_unit(the denomination, e.g., per 1000 tokens) should be consistent between message and answer. The model'sserver_defaultforanswer_price_unitissa.text("0.001"), confirming thatprice_unitshould be0.001, not0.These values are later overwritten by actual LLM usage data (
llm_usage.completion_unit_price/llm_usage.completion_price_unit), so the impact is limited to the brief window between creation and the update. However, if the update fails or is skipped, the swapped defaults would result in incorrect cost calculations.Was this helpful? React with 👍 / 👎