fix(multi-agent): 多智能体模式下侧边栏只加载对应模式的对话记录

后端 get_conversation_list / web_terminal / conversation路由 增加 multi_agent_mode 查询参数:
- multi_agent_mode=1 仅返回 multi_agent_mode 对话
- multi_agent_mode=0 仅返回常规对话
- 不传则不过滤

前端 loadConversationsList / loadWorkspaceConversations 根据 this.multiAgentMode 自动带参
This commit is contained in:
JOJO 2026-07-12 12:20:18 +08:00
parent 811974d6e7
commit 8e5d4f05d9
5 changed files with 40 additions and 11 deletions

View File

@ -393,10 +393,10 @@ class WebTerminal(MainTerminal):
"message": f"加载对话异常: {e}" "message": f"加载对话异常: {e}"
} }
def get_conversations_list(self, limit: int = 20, offset: int = 0, non_empty: bool = False) -> Dict: def get_conversations_list(self, limit: int = 20, offset: int = 0, non_empty: bool = False, multi_agent_mode: Optional[bool] = None) -> Dict:
"""获取对话列表Web版本""" """获取对话列表Web版本"""
try: try:
result = self.context_manager.get_conversation_list(limit=limit, offset=offset, non_empty=non_empty) result = self.context_manager.get_conversation_list(limit=limit, offset=offset, non_empty=non_empty, multi_agent_mode=multi_agent_mode)
return { return {
"success": True, "success": True,
"data": result "data": result

View File

@ -525,6 +525,14 @@ def get_conversations(terminal: WebTerminal, workspace: UserWorkspace, username:
limit = request.args.get('limit', 20, type=int) limit = request.args.get('limit', 20, type=int)
offset = request.args.get('offset', 0, type=int) offset = request.args.get('offset', 0, type=int)
non_empty = request.args.get('non_empty', '0') in ('1', 'true', 'True') non_empty = request.args.get('non_empty', '0') in ('1', 'true', 'True')
# multi_agent_mode: '1' 仅多智能体模式对话;'0' 仅常规对话;未传 None 不过滤
ma_param = request.args.get('multi_agent_mode', None)
if ma_param in ('1', 'true', 'True'):
multi_agent_filter: Optional[bool] = True
elif ma_param in ('0', 'false', 'False'):
multi_agent_filter = False
else:
multi_agent_filter = None
target_workspace_id = request.args.get('workspace_id', '', type=str).strip() target_workspace_id = request.args.get('workspace_id', '', type=str).strip()
# 限制参数范围 # 限制参数范围
@ -541,7 +549,7 @@ def get_conversations(terminal: WebTerminal, workspace: UserWorkspace, username:
except RuntimeError as exc: except RuntimeError as exc:
return jsonify({"success": False, "error": str(exc)}), 503 return jsonify({"success": False, "error": str(exc)}), 503
result = terminal.get_conversations_list(limit=limit, offset=offset, non_empty=non_empty) result = terminal.get_conversations_list(limit=limit, offset=offset, non_empty=non_empty, multi_agent_mode=multi_agent_filter)
cm = getattr(getattr(terminal, "context_manager", None), "conversation_manager", None) cm = getattr(getattr(terminal, "context_manager", None), "conversation_manager", None)
write_host_workspace_debug( write_host_workspace_debug(
"sidebar-debug-api", "sidebar-debug-api",

View File

@ -14,7 +14,9 @@ export const loadMethods = {
const requestSeq = ++this.conversationListRequestSeq; const requestSeq = ++this.conversationListRequestSeq;
this.conversationsLoading = true; this.conversationsLoading = true;
try { try {
const response = await fetch(`/api/conversations?limit=${queryLimit}&offset=${queryOffset}`); // 多智能体模式下只加载多智能体对话记录;常规模式排除多智能体对话
const maParam = this.multiAgentMode ? '&multi_agent_mode=1' : '&multi_agent_mode=0';
const response = await fetch(`/api/conversations?limit=${queryLimit}&offset=${queryOffset}${maParam}`);
const data = await response.json(); const data = await response.json();
if (data.success) { if (data.success) {
@ -284,7 +286,8 @@ export const loadMethods = {
if (group.loading || group.loadingMore) return; if (group.loading || group.loadingMore) return;
group.loading = true; group.loading = true;
try { try {
const response = await fetch(`/api/conversations?workspace_id=${encodeURIComponent(workspaceId)}&limit=${group.limit}&offset=${group.offset}`); const maParam = this.multiAgentMode ? '&multi_agent_mode=1' : '&multi_agent_mode=0';
const response = await fetch(`/api/conversations?workspace_id=${encodeURIComponent(workspaceId)}&limit=${group.limit}&offset=${group.offset}${maParam}`);
const data = await response.json(); const data = await response.json();
if (data.success) { if (data.success) {
const items = (data.data?.conversations || []).map((conv: any) => ({ const items = (data.data?.conversations || []).map((conv: any) => ({

View File

@ -325,9 +325,9 @@ class ConversationMixin:
except Exception as e: except Exception as e:
print(f"⌘ 自动保存异常: {e}") print(f"⌘ 自动保存异常: {e}")
def get_conversation_list(self, limit: int = 50, offset: int = 0, non_empty: bool = False) -> Dict: def get_conversation_list(self, limit: int = 50, offset: int = 0, non_empty: bool = False, multi_agent_mode: Optional[bool] = None) -> Dict:
"""获取对话列表""" """获取对话列表"""
return self.conversation_manager.get_conversation_list(limit=limit, offset=offset, non_empty=non_empty) return self.conversation_manager.get_conversation_list(limit=limit, offset=offset, non_empty=non_empty, multi_agent_mode=multi_agent_mode)
def delete_conversation_by_id(self, conversation_id: str) -> bool: def delete_conversation_by_id(self, conversation_id: str) -> bool:
"""删除指定对话""" """删除指定对话"""

View File

@ -47,7 +47,7 @@ class ConversationMetadata:
class ListSearchMixin: class ListSearchMixin:
"""ConversationManager list search mixin 能力 mixin。""" """ConversationManager list search mixin 能力 mixin。"""
def get_conversation_list(self, limit: int = 50, offset: int = 0, non_empty: bool = False) -> Dict: def get_conversation_list(self, limit: int = 50, offset: int = 0, non_empty: bool = False, multi_agent_mode: Optional[bool] = None) -> Dict:
""" """
获取对话列表 获取对话列表
@ -55,14 +55,26 @@ class ListSearchMixin:
limit: 限制数量 limit: 限制数量
offset: 偏移量 offset: 偏移量
non_empty: 仅返回有内容total_messages > 0的对话分页基于过滤后的结果 non_empty: 仅返回有内容total_messages > 0的对话分页基于过滤后的结果
multi_agent_mode: 若为 True 仅返回多智能体模式对话若为 False 仅返回常规对话None 不过滤
Returns: Returns:
Dict: 包含对话列表和统计信息 Dict: 包含对话列表和统计信息
""" """
t0 = time.perf_counter() t0 = time.perf_counter()
if perf_log: if perf_log:
perf_log("get_conversation_list enter", extra={"limit": limit, "offset": offset, "non_empty": non_empty}) perf_log("get_conversation_list enter", extra={"limit": limit, "offset": offset, "non_empty": non_empty, "multi_agent_mode": multi_agent_mode})
try: try:
def _filter_by_multi_agent(items):
"""按 multi_agent_mode 元数据过滤。"""
if multi_agent_mode is None:
return items
result = []
for conv_id, meta in items:
conv_ma = bool(meta.get("multi_agent_mode", False))
if conv_ma == multi_agent_mode:
result.append((conv_id, meta))
return result
if non_empty: if non_empty:
# 过滤模式:全量加载后剔除空对话,再在过滤结果上分页, # 过滤模式:全量加载后剔除空对话,再在过滤结果上分页,
# 保证 total / has_more 与"有内容对话"的真实数量一致。 # 保证 total / has_more 与"有内容对话"的真实数量一致。
@ -76,6 +88,8 @@ class ListSearchMixin:
item for item in sorted_conversations item for item in sorted_conversations
if (item[1].get("total_messages", 0) or 0) > 0 if (item[1].get("total_messages", 0) or 0) > 0
] ]
if multi_agent_mode is not None:
sorted_conversations = _filter_by_multi_agent(sorted_conversations)
total = len(sorted_conversations) total = len(sorted_conversations)
conversations = sorted_conversations[offset:offset + limit] conversations = sorted_conversations[offset:offset + limit]
else: else:
@ -91,8 +105,11 @@ class ListSearchMixin:
reverse=True reverse=True
) )
if multi_agent_mode is not None:
sorted_conversations = _filter_by_multi_agent(sorted_conversations)
# 分页 # 分页
total = max(len(sorted_conversations), total_files) total = max(len(sorted_conversations), total_files if multi_agent_mode is None else len(sorted_conversations))
conversations = sorted_conversations[offset:offset+limit] conversations = sorted_conversations[offset:offset+limit]
# 格式化结果 # 格式化结果
@ -108,7 +125,8 @@ class ListSearchMixin:
"thinking_mode": metadata.get("thinking_mode", False), "thinking_mode": metadata.get("thinking_mode", False),
"total_messages": metadata.get("total_messages", 0), "total_messages": metadata.get("total_messages", 0),
"total_tools": metadata.get("total_tools", 0), "total_tools": metadata.get("total_tools", 0),
"status": metadata.get("status", "active") "status": metadata.get("status", "active"),
"multi_agent_mode": bool(metadata.get("multi_agent_mode", False))
}) })
elapsed_ms = (time.perf_counter() - t0) * 1000 elapsed_ms = (time.perf_counter() - t0) * 1000