diff --git a/src/services/conversation_service.py b/src/services/conversation_service.py index 2039599e..3f44d101 100644 --- a/src/services/conversation_service.py +++ b/src/services/conversation_service.py @@ -77,11 +77,26 @@ async def _sync_thread_attachment_state( return graph = await agent.get_graph() + config = {"configurable": {"thread_id": thread_id, "user_id": str(user_id)}} + state = await graph.aget_state(config) + state_values = getattr(state, "values", {}) if state else {} + existing_files = state_values.get("files", {}) if isinstance(state_values, dict) else {} + if not isinstance(existing_files, dict): + existing_files = {} + + attachment_files = _build_state_files(attachments) + merged_files = { + path: file_data + for path, file_data in existing_files.items() + if isinstance(path, str) and not path.startswith("/attachments/") + } + merged_files.update(attachment_files) + await graph.aupdate_state( - config={"configurable": {"thread_id": thread_id, "user_id": str(user_id)}}, + config=config, values={ "attachments": attachments, - "files": _build_state_files(attachments), + "files": merged_files, }, ) except Exception as e: diff --git a/test/test_conversation_service_attachment_state.py b/test/test_conversation_service_attachment_state.py index def2a918..fb04048a 100644 --- a/test/test_conversation_service_attachment_state.py +++ b/test/test_conversation_service_attachment_state.py @@ -37,11 +37,23 @@ def test_build_state_files_only_parsed_and_with_content(): @pytest.mark.asyncio async def test_sync_thread_attachment_state_updates_graph(monkeypatch: pytest.MonkeyPatch): captured: dict = {} + fake_state = SimpleNamespace( + values={ + "files": { + "/attachments/old.md": {"content": ["old"]}, + "/work/result.md": {"content": ["keep"]}, + } + } + ) class FakeGraph: + async def aget_state(self, config): + captured["read_config"] = config + return fake_state + async def aupdate_state(self, *, config, values): - captured["config"] = config - captured["values"] = values + captured["write_config"] = config + captured["write_values"] = values class FakeAgent: async def get_graph(self): @@ -64,9 +76,12 @@ async def test_sync_thread_attachment_state_updates_graph(monkeypatch: pytest.Mo attachments=attachments, ) - assert captured["config"] == {"configurable": {"thread_id": "thread-1", "user_id": "u1"}} - assert captured["values"]["attachments"] == attachments - assert "/attachments/resume.md" in captured["values"]["files"] + assert captured["read_config"] == {"configurable": {"thread_id": "thread-1", "user_id": "u1"}} + assert captured["write_config"] == {"configurable": {"thread_id": "thread-1", "user_id": "u1"}} + assert captured["write_values"]["attachments"] == attachments + assert "/attachments/resume.md" in captured["write_values"]["files"] + assert "/attachments/old.md" not in captured["write_values"]["files"] + assert "/work/result.md" in captured["write_values"]["files"] @pytest.mark.asyncio