fix(attachments): 优化附件状态同步逻辑,修复 files 覆盖问题

This commit is contained in:
Wenjie Zhang 2026-02-25 11:42:31 +08:00
parent 7bfde7cc2c
commit 80f97cc2d9
2 changed files with 20 additions and 6 deletions

View File

@ -658,6 +658,11 @@ async def update_thread(
) )
# ================================
# > === 附件管理分组 ===
# ================================
@chat.post("/thread/{thread_id}/attachments", response_model=AttachmentResponse) @chat.post("/thread/{thread_id}/attachments", response_model=AttachmentResponse)
async def upload_thread_attachment( async def upload_thread_attachment(
thread_id: str, thread_id: str,

View File

@ -2,6 +2,7 @@ import uuid
from datetime import UTC, datetime from datetime import UTC, datetime
from fastapi import HTTPException, UploadFile from fastapi import HTTPException, UploadFile
from langgraph.types import Command
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from src.agents import agent_manager from src.agents import agent_manager
@ -78,26 +79,34 @@ async def _sync_thread_attachment_state(
graph = await agent.get_graph() graph = await agent.get_graph()
config = {"configurable": {"thread_id": thread_id, "user_id": str(user_id)}} config = {"configurable": {"thread_id": thread_id, "user_id": str(user_id)}}
# 先获取现有 state保留非附件文件
state = await graph.aget_state(config) state = await graph.aget_state(config)
state_values = getattr(state, "values", {}) if state else {} state_values = getattr(state, "values", {}) if state else {}
existing_files = state_values.get("files", {}) if isinstance(state_values, dict) else {} existing_files = state_values.get("files", {}) if isinstance(state_values, dict) else {}
if not isinstance(existing_files, dict): if not isinstance(existing_files, dict):
existing_files = {} existing_files = {}
attachment_files = _build_state_files(attachments) # 保留非 /attachments/ 开头的现有文件(如 Agent 创建的 a.md
merged_files = { merged_files = {
path: file_data path: file_data
for path, file_data in existing_files.items() for path, file_data in existing_files.items()
if isinstance(path, str) and not path.startswith("/attachments/") if isinstance(path, str) and not path.startswith("/attachments/")
} }
# 添加附件文件
attachment_files = _build_state_files(attachments)
merged_files.update(attachment_files) merged_files.update(attachment_files)
# 使用 Command 确保 reducer 被正确应用
await graph.aupdate_state( await graph.aupdate_state(
config=config, config=config,
values={ values=Command(
"attachments": attachments, update={
"files": merged_files, "attachments": attachments,
}, "files": merged_files,
}
),
) )
except Exception as e: except Exception as e:
logger.warning(f"Failed to sync attachment state for thread {thread_id}: {e}") logger.warning(f"Failed to sync attachment state for thread {thread_id}: {e}")
@ -260,7 +269,7 @@ async def upload_thread_attachment_view(
"uploaded_at": utc_isoformat(), "uploaded_at": utc_isoformat(),
"truncated": conversion.truncated, "truncated": conversion.truncated,
"file_path": file_path, # 用于 StateBackend前端不返回此字段 "file_path": file_path, # 用于 StateBackend前端不返回此字段
"minio_url": minio_url, "minio_url": minio_url, # 暂未使用
} }
await conv_repo.add_attachment(conversation.id, attachment_record) await conv_repo.add_attachment(conversation.id, attachment_record)
all_attachments = await conv_repo.get_attachments(conversation.id) all_attachments = await conv_repo.get_attachments(conversation.id)