diff --git a/src/agents/common/middlewares/attachment_middleware.py b/src/agents/common/middlewares/attachment_middleware.py index 5c6136e8..663cb0d8 100644 --- a/src/agents/common/middlewares/attachment_middleware.py +++ b/src/agents/common/middlewares/attachment_middleware.py @@ -18,7 +18,6 @@ class AttachmentState(AgentState): """扩展 AgentState 以支持附件""" attachments: NotRequired[list[dict]] - files: NotRequired[dict[str, str]] # {"/attachments/xxx/file.md": content} def _build_attachment_prompt(attachments: Sequence[dict]) -> str | None: diff --git a/src/services/conversation_service.py b/src/services/conversation_service.py index 3f44d101..e0ef33f1 100644 --- a/src/services/conversation_service.py +++ b/src/services/conversation_service.py @@ -84,19 +84,24 @@ async def _sync_thread_attachment_state( 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/") + # 仅对 /attachments 命名空间做增量更新,避免覆盖 agent 运行期生成的其它文件。 + next_attachment_files = _build_state_files(attachments) + prev_attachment_paths = { + path + for path in existing_files.keys() + if isinstance(path, str) and path.startswith("/attachments/") } - merged_files.update(attachment_files) + next_attachment_paths = set(next_attachment_files.keys()) + + file_updates: dict[str, dict | None] = {**next_attachment_files} + for removed_path in prev_attachment_paths - next_attachment_paths: + file_updates[removed_path] = None await graph.aupdate_state( config=config, values={ "attachments": attachments, - "files": merged_files, + "files": file_updates, }, ) except Exception as e: diff --git a/test/test_conversation_service_attachment_state.py b/test/test_conversation_service_attachment_state.py index fb04048a..5155f1ee 100644 --- a/test/test_conversation_service_attachment_state.py +++ b/test/test_conversation_service_attachment_state.py @@ -80,8 +80,8 @@ async def test_sync_thread_attachment_state_updates_graph(monkeypatch: pytest.Mo 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"] + assert captured["write_values"]["files"]["/attachments/old.md"] is None + assert "/work/result.md" not in captured["write_values"]["files"] @pytest.mark.asyncio