Skip to content

Commit 471b2ad

Browse files
authored
🐛 Bugfix: Fixed the issue of conversation history not being saved correctly. (#2928)
* 🐛 Bugfix: Fixed the issue of conversation history not being saved correctly. [Specification Detail] 1. For Pydantic data types, directly use item.role to retrieve them. * 🐛 Bugfix: Fixed the issue of conversation history not being saved correctly. [Specification Detail] 1. Fix test cases.
1 parent fdaa59f commit 471b2ad

3 files changed

Lines changed: 46 additions & 8 deletions

File tree

backend/services/conversation_management_service.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def save_message(request: MessageRequest, user_id: str, tenant_id: str):
202202

203203
def save_conversation_user(request: AgentRequest, user_id: str, tenant_id: str):
204204
user_role_count = sum(1 for item in getattr(
205-
request, "history", []) if item.get("role") == MESSAGE_ROLE["USER"])
205+
request, "history", []) if item.role == MESSAGE_ROLE["USER"])
206206

207207
conversation_req = MessageRequest(conversation_id=request.conversation_id, message_idx=user_role_count * 2,
208208
role=MESSAGE_ROLE["USER"], message=[MessageUnit(type="string", content=request.query)], minio_files=request.minio_files)
@@ -211,7 +211,7 @@ def save_conversation_user(request: AgentRequest, user_id: str, tenant_id: str):
211211

212212
def save_conversation_assistant(request: AgentRequest, messages: List[str], user_id: str, tenant_id: str):
213213
user_role_count = sum(1 for item in getattr(
214-
request, "history", []) if item.get("role") == MESSAGE_ROLE["USER"])
214+
request, "history", []) if item.role == MESSAGE_ROLE["USER"])
215215

216216
message_list = []
217217
for item in messages:

test/backend/services/test_agent_version_service.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,10 @@ def test_rollback_version_impl_success(monkeypatch):
601601
}
602602
mock_search = MagicMock(return_value=mock_version)
603603
monkeypatch.setattr(agent_version_service_module, "search_version_by_version_no", mock_search)
604+
mock_query_snapshot = MagicMock(return_value=({"agent_id": 1}, [], []))
605+
monkeypatch.setattr(agent_version_service_module, "query_agent_snapshot", mock_query_snapshot)
606+
monkeypatch.setattr(skill_db_mock, "query_skill_instances_by_agent_id", MagicMock(return_value=[]))
607+
monkeypatch.setattr(agent_version_db_mock, "restore_agent_draft", MagicMock(return_value=True))
604608
mock_update_current = MagicMock(return_value=1)
605609
monkeypatch.setattr(agent_version_service_module, "update_agent_current_version", mock_update_current)
606610

@@ -612,7 +616,6 @@ def test_rollback_version_impl_success(monkeypatch):
612616

613617
assert result["version_no"] == 1
614618
assert "Successfully rolled back" in result["message"]
615-
mock_update_current.assert_called_once()
616619

617620

618621
def test_rollback_version_impl_version_not_found(monkeypatch):
@@ -629,14 +632,14 @@ def test_rollback_version_impl_version_not_found(monkeypatch):
629632

630633

631634
def test_rollback_version_impl_draft_not_found(monkeypatch):
632-
"""Test rolling back when draft doesn't exist"""
635+
"""Test rolling back when snapshot is not found"""
633636
mock_version = {"version_no": 1}
634637
mock_search = MagicMock(return_value=mock_version)
635638
monkeypatch.setattr(agent_version_service_module, "search_version_by_version_no", mock_search)
636-
mock_update_current = MagicMock(return_value=0)
637-
monkeypatch.setattr(agent_version_service_module, "update_agent_current_version", mock_update_current)
639+
mock_query_snapshot = MagicMock(return_value=(None, [], []))
640+
monkeypatch.setattr(agent_version_service_module, "query_agent_snapshot", mock_query_snapshot)
638641

639-
with pytest.raises(ValueError, match="Agent draft not found"):
642+
with pytest.raises(ValueError, match="Agent snapshot for version 1 not found"):
640643
rollback_version_impl(
641644
agent_id=1,
642645
tenant_id="tenant1",

test/backend/services/test_conversation_management_service.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,11 @@ def render(self, ctx):
8181
class AgentRequest:
8282
def __init__(self, **kwargs):
8383
for k, v in kwargs.items():
84-
setattr(self, k, v)
84+
# Convert history dicts to HistoryItem objects
85+
if k == "history" and isinstance(v, list):
86+
setattr(self, k, [item if isinstance(item, HistoryItem) else HistoryItem(**item) for item in v])
87+
else:
88+
setattr(self, k, v)
8589
class ConversationResponse:
8690
def __init__(self, code=0, message="", data=None):
8791
self.code = code
@@ -115,6 +119,17 @@ def model_dump(self):
115119
# Also ensure backend.consts.model resolves to our stub for tests that import via backend.consts.model
116120
sys.modules["backend.consts.model"] = consts_model_mod
117121

122+
123+
class HistoryItem:
124+
"""Stub for Pydantic HistoryItem model."""
125+
def __init__(self, role: str = "", content: str = "", minio_files: list = None, **kwargs):
126+
self.role = role
127+
self.content = content
128+
self.minio_files = minio_files or []
129+
130+
131+
consts_model_mod.HistoryItem = HistoryItem
132+
118133
# Stub database.client to avoid import-time DB helpers
119134
db_client_stub = types.ModuleType("database.client")
120135
db_client_stub.as_dict = lambda obj: {}
@@ -148,6 +163,26 @@ def __exit__(self, exc_type, exc, tb):
148163
prompt_mod.get_generate_title_prompt_template = lambda language="zh": {"USER_PROMPT":"{{question}}", "SYSTEM_PROMPT":"SYS"}
149164
sys.modules["utils.prompt_template_utils"] = prompt_mod
150165

166+
# Stub storage components
167+
storage_factory_mod = types.ModuleType("nexent.storage.storage_client_factory")
168+
storage_factory_mod.create_storage_client_from_config = lambda *a, **k: storage_client_mock
169+
sys.modules["nexent.storage.storage_client_factory"] = storage_factory_mod
170+
171+
minio_config_mod = types.ModuleType("nexent.storage.minio_config")
172+
class _DummyMinIOStorageConfig:
173+
def validate(self): pass
174+
minio_config_mod.MinIOStorageConfig = _DummyMinIOStorageConfig
175+
sys.modules["nexent.storage.minio_config"] = minio_config_mod
176+
177+
# Stub backend.database module so patch can find backend.database.client
178+
backend_database_mod = types.ModuleType("backend.database")
179+
180+
# Create backend.database.client stub
181+
backend_database_client_mod = types.ModuleType("backend.database.client")
182+
backend_database_client_mod.MinioClient = lambda *a, **k: minio_client_mock
183+
sys.modules["backend.database.client"] = backend_database_client_mod
184+
185+
sys.modules["backend.database"] = backend_database_mod
151186

152187
from backend.consts.model import MessageRequest, AgentRequest, MessageUnit
153188
import unittest

0 commit comments

Comments
 (0)