/** * 文件作用:superAgent 会话与对话流状态 hook * 职责范围: * 1. 管理普通对话、标书任务会话和左侧列表状态 * 2. 处理流式消息、工具事件、checkpoint 事件 * 3. 处理新建会话、文件上传、发送消息和历史会话切换 * * 不负责: * - 渲染对话 UI * - 渲染右侧工作区 * - 管理登录弹窗 UI * * 维护说明: * - 标书任务身份由后端 session 加本地 tender session 标记共同维护 */ "use strict"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { message } from "antd"; import { cancelSuperAgentSession, createSuperAgentSession, deleteSuperAgentSession, respondSuperAgentCheckpointStream, sendSuperAgentChat, uploadSuperAgentFile, } from "../actions/api"; import { createResourceFileFromUpload } from "../actions/resourceLibrary"; import useSuperAgentSidebar from "./useSuperAgentSidebar"; import { TASK_STAGE, TASK_WELCOME_CONTENT, TASK_WELCOME_TITLE, TENDER_TASK_WELCOME_CONTENT, TENDER_TASK_WELCOME_TITLE, } from "../constants"; import { clearPendingEmptySession, clearActiveSessionId, getSuperAgentToolArguments, getSuperAgentToolCallId, getSuperAgentToolName, getSuperAgentToolResult, isSuperAgentQuestionTool, isSuperAgentRunLogTool, markTenderSessionId, markPendingEmptySession, removeTenderSessionId, resolveApiFolderId, saveActiveSessionId, } from "../utils/session"; import { createSuperAgentTraceId, summarizeSuperAgentPayload, superAgentError, superAgentLog, superAgentWarn, } from "../utils/debugLog"; import { mergeCheckpointEventData, } from "../utils/workspace"; import { normalizeCheckpoint } from "../utils/checkpoint"; import { isWorkflowBodyText } from "../utils/tenderWorkflow"; const getActionData = (res) => { const payload = res?.payload ?? res; return payload?.data ?? payload; }; const ensureActionSuccess = (res, fallbackMessage) => { const payload = res?.payload ?? res; if (payload?.success === false) { throw new Error(payload?.message || payload?.error || fallbackMessage); } return getActionData(res); }; const buildSessionParams = (sessionId) => ({ sessionId, ":sessionId": sessionId, }); const hasFilePathPrefix = (filePath = "") => { return /^(https?:)?\/\//i.test(filePath) || /^(data|blob):/i.test(filePath); }; const buildQiniuFilePath = (filePath = "") => { const cleanFilePath = String(filePath || "").trim(); if (!cleanFilePath || hasFilePathPrefix(cleanFilePath)) return cleanFilePath; const qiniuDomain = window?.env?.FS_QINIU_DOMAIN || ""; const cleanDomain = String(qiniuDomain || "").replace(/\/+$/, ""); if (!cleanDomain) return cleanFilePath; return `${cleanDomain}/${cleanFilePath.replace(/^\/+/, "")}`; }; //[文件上下文] 上传文件只向智能体传递访问地址,不附加固定业务文案。 const buildUploadedFileReference = (fileList = []) => { return fileList .map((file) => { const fileName = file?.name || file?.originalFilename || "未命名文件"; const rawFilePath = file?.url || file?.path || file?.objectKey || file?.localPath || ""; const filePath = buildQiniuFilePath(rawFilePath); if (!filePath) return ""; return `(文件名:${fileName},文件路径:${filePath})`; }) .filter(Boolean) .join("\n"); }; const useSuperAgentChat = ({ currentUserId, openAuthModal, setWorkspaceOpen, actions, dispatch, }) => { const [routeType, setRouteType] = useState("chat"); const [inputValue, setInputValue] = useState(""); const { sidebarTree, taskList, ordinaryChatList, isLoadingSidebar, collapsedFolderMap, loadSidebar, patchSessionInTree, removeSessionFromTree, toggleFolderCollapsed, handleCreateFolder, handleRenameFolder, handleDeleteFolder, handleRenameSession, handleMoveSession, } = useSuperAgentSidebar({ currentUserId, actions, dispatch }); const [activeTaskId, setActiveTaskId] = useState(""); const [taskStage, setTaskStage] = useState(TASK_STAGE.IDLE); const [conversationMessages, setConversationMessages] = useState([]); const [activeSessionId, setActiveSessionId] = useState(""); const isLoadingSessions = isLoadingSidebar; const [isUploadingFile, setIsUploadingFile] = useState(false); const [uploadProgress, setUploadProgress] = useState(null); const [isStreamingAnswer, setIsStreamingAnswer] = useState(false); const [isCreatingChat, setIsCreatingChat] = useState(false); const [isCreatingTask, setIsCreatingTask] = useState(false); const [uploadedFileList, setUploadedFileList] = useState([]); const [agentCategory, setAgentCategory] = useState("全部应用"); const [agentKeyword, setAgentKeyword] = useState(""); /** 任务大厅已选类型:null 表示尚未选择;tender 表示已进入标书引导 */ const [selectedTaskType, setSelectedTaskType] = useState(null); const chatAbortControllerRef = useRef(null); const streamingMessageKeyRef = useRef(""); const chatRunPromiseRef = useRef(Promise.resolve()); const chatRunActiveRef = useRef(false); const creatingSessionRef = useRef(false); const sidebarRefreshTimerRef = useRef(null); const artifactProgressSessionRef = useRef(""); const taskProgressUpsertAtRef = useRef(0); const taskProgressPendingRef = useRef(null); const taskProgressTimerRef = useRef(null); const activeSessionIdRef = useRef(""); useEffect(() => { activeSessionIdRef.current = activeSessionId; }, [activeSessionId]); const activeTask = useMemo( () => taskList.find((task) => task.id === activeTaskId) || null, [activeTaskId, taskList] ); const activeChat = useMemo( () => ordinaryChatList.find((chat) => { const chatId = chat.id || chat.chatId; return chatId === activeSessionId; }) || null, [activeSessionId, ordinaryChatList] ); const findSessionTypeById = (sessionId) => { if (!sessionId) return ""; const matchedTask = taskList.find((task) => { const taskId = task.id || task.chatId; return taskId === sessionId; }); if (matchedTask) return "task"; const matchedChat = ordinaryChatList.find((chat) => { const chatId = chat.id || chat.chatId; return chatId === sessionId; }); if (matchedChat) return "conversation"; return ""; }; const terminalCheckpointStatuses = new Set([ "confirmed", "edited", "completed", "done", "success", "cancelled", "canceled", ]); const isTaskRoute = routeType === "task"; const isAgentRoute = routeType === "agents"; const isResourceLibraryRoute = routeType === "assets"; const breadcrumbTitle = isAgentRoute ? "发现智能体" : isResourceLibraryRoute ? "资源库" : isTaskRoute ? activeTask?.title || "新任务" : activeChat?.title || "新对话"; const updateTaskById = (taskId, patch) => { if (!taskId) return; patchSessionInTree(taskId, { ...patch, updatedAt: Date.now() }); }; const updateActiveTask = (patch) => { if (!activeTaskId) return; updateTaskById(activeTaskId, patch); }; const isDefaultSessionTitle = (title) => { const value = String(title || "").trim().toLowerCase(); return ( !value || value === "新对话" || value === "未命名任务" || value === "new session" ); }; const buildInstantSessionTitle = (text) => { const title = String(text || "").replace(/\s+/g, " ").trim(); if (!title) return ""; return title.length > 24 ? `${title.slice(0, 24)}...` : title; }; const patchSessionTitleAfterUserMessage = ({ sessionId, isTaskSession = false, text = "", }) => { if (!sessionId) return; const currentSessionList = isTaskSession ? taskList : ordinaryChatList; const currentSession = currentSessionList.find((item) => { const itemId = item.id || item.chatId; return itemId === sessionId; }); if (currentSession && !isDefaultSessionTitle(currentSession.title)) return; const title = buildInstantSessionTitle(text); if (!title) return; patchSessionInTree(sessionId, { title, time: Date.now(), updatedAt: Date.now(), }); }; const addAssistantMessage = (messageData) => { setConversationMessages((prev) => [ ...prev, { key: `assistant_${Date.now()}_${prev.length}`, role: "assistant", ...messageData, }, ]); }; const upsertAssistantMessage = (messageData) => { const messageKey = messageData?.key; if (!messageKey) { addAssistantMessage(messageData); return; } setConversationMessages((prev) => { const hasMessage = prev.some((item) => item.key === messageKey); if (!hasMessage) { return [ ...prev, { role: "assistant", ...messageData, }, ]; } const shouldSyncBodyCheckpoint = messageData.type === "taskProgress" && messageData.task; return prev.map((item) => { if (item.key === messageKey) return { ...item, ...messageData }; if (!shouldSyncBodyCheckpoint || item.type !== "checkpoint") return item; const checkpoint = item?.checkpoint?.checkpoint || item?.checkpoint || {}; const uiType = String(checkpoint.ui_type || checkpoint.uiType || ""); if (uiType !== "tree-markdown") return item; const nextTask = { ...(item.task || {}), ...messageData.task, }; return { ...item, task: nextTask, checkpoint: { ...(item.checkpoint || {}), task: nextTask, }, }; }); }); }; const addUserMessage = (content, fileList = [], messageSessionId = "") => { clearPendingEmptySession(activeSessionId || activeTaskId); setConversationMessages((prev) => [ ...prev, { key: `user_${Date.now()}_${prev.length}`, role: "user", content, files: fileList, sessionId: messageSessionId || activeSessionId || activeTaskId, }, ]); }; const updateConversationMessage = (messageKey, updater) => { setConversationMessages((prev) => prev.map((item) => { if (item.key !== messageKey) return item; const patch = typeof updater === "function" ? updater(item) : updater; return { ...item, ...patch }; }) ); }; const removeConversationMessage = (messageKey) => { if (!messageKey) return; setConversationMessages((prev) => prev.filter((item) => item.key !== messageKey)); }; useEffect(() => { return () => { if (chatAbortControllerRef.current) { chatAbortControllerRef.current.abort(); } if (sidebarRefreshTimerRef.current) { window.clearTimeout(sidebarRefreshTimerRef.current); } if (taskProgressTimerRef.current) { window.clearTimeout(taskProgressTimerRef.current); } }; }, []); const removeSidebarSessionLocally = (sessionId, itemType) => { if (!sessionId) return; clearPendingEmptySession(sessionId); if (itemType === "task") { removeTenderSessionId(sessionId); } removeSessionFromTree(sessionId); }; const clearActiveSidebarSession = (sessionId, shouldForce = false) => { if (!shouldForce && activeSessionId !== sessionId) return; clearActiveSessionId(sessionId); setActiveSessionId(""); setActiveTaskId(""); setTaskStage(TASK_STAGE.IDLE); setConversationMessages([]); setUploadedFileList([]); setRouteType("chat"); setWorkspaceOpen(false); }; const createAndActivateSession = async ({ isTaskSession = false, sessionKind, folderId = null, title = "", shouldResetMessages = false, } = {}) => { if (!currentUserId) { openAuthModal("login"); throw new Error("请先登录后再使用飞小尚超级智能体"); } const sessionType = sessionKind || (isTaskSession ? "task" : "conversation"); const requestBody = { type: sessionType, reuse_empty: true }; const apiFolderId = resolveApiFolderId(folderId); if (apiFolderId) requestBody.folder_id = apiFolderId; if (title) requestBody.title = title; const session = await dispatch(createSuperAgentSession({ query: { userId: currentUserId }, body: requestBody, })).then((res) => ensureActionSuccess(res, "创建超级智能体会话失败")); const sessionData = session?.data || session; const nextSessionId = sessionData?.session_id || sessionData?.id; if (!nextSessionId) throw new Error("创建会话失败,后端未返回 session_id"); const returnedType = sessionData?.session_kind || (sessionData?.type === "task" || sessionData?.type === "conversation" ? sessionData.type : sessionType); const isReused = Boolean(sessionData?.reused); superAgentLog("chat.session", "create_or_reuse.done", { sessionId: nextSessionId, reused: isReused, sessionType: returnedType, folderId: apiFolderId, }); if (isReused) { const tipText = returnedType === "task" ? "已有未开始的任务,已为您定位" : "已有未开始的对话,已为您定位"; message.info(tipText); } setActiveSessionId(nextSessionId); saveActiveSessionId(nextSessionId); setWorkspaceOpen(false); setUploadedFileList([]); markPendingEmptySession(nextSessionId, returnedType, apiFolderId); if (shouldResetMessages) setConversationMessages([]); if (returnedType === "task") { markTenderSessionId(nextSessionId); setActiveTaskId(nextSessionId); } else { removeTenderSessionId(nextSessionId); setActiveTaskId(""); } await loadSidebar({ silent: true }); return nextSessionId; }; const getCurrentSessionType = () => { if (!activeSessionId) return ""; const sidebarSessionType = findSessionTypeById(activeSessionId); if (sidebarSessionType) return sidebarSessionType; if (activeTaskId && activeSessionId === activeTaskId) return "task"; return "conversation"; }; const ensureActiveSession = async (options = {}) => { const shouldCreateTaskSession = options.isTaskSession === undefined ? isTaskRoute : options.isTaskSession; const expectedSessionType = shouldCreateTaskSession ? "task" : "conversation"; const currentSessionType = getCurrentSessionType(); if (activeSessionId && currentSessionType === expectedSessionType) { return activeSessionId; } return createAndActivateSession({ isTaskSession: shouldCreateTaskSession }); }; const appendStreamingText = (messageKey, text) => { if (!text) return; updateConversationMessage(messageKey, (item) => ({ title: item.title || "飞小尚", content: `${item.content || ""}${text}`, })); }; //[合并实时日志事件,使用事件 id 去重并累计询问、命令次数] const updateRunLogFromEvent = (messageKey, eventName, eventData = {}) => { updateConversationMessage(messageKey, (item) => { const currentRunLog = item.runLog || {}; const startedAt = currentRunLog.startedAt || Date.now(); const toolName = getSuperAgentToolName(eventData) || "工具"; const eventId = getSuperAgentToolCallId(eventData); const handledEventIds = Array.isArray(currentRunLog.handledEventIds) ? currentRunLog.handledEventIds : []; const currentEntries = Array.isArray(currentRunLog.entries) ? currentRunLog.entries : []; const shouldCountTool = eventName === "tool_start" && isSuperAgentRunLogTool(toolName); const fallbackRunningEntry = currentEntries.find( (entry) => entry.name === toolName && entry.status === "running" ); const countKey = eventId || fallbackRunningEntry?.id || `${toolName}_${handledEventIds.length + 1}`; const matchedIndex = currentEntries.findIndex((entry) => { if (eventId) return entry.id === eventId; return entry.id === countKey || (entry.name === toolName && entry.status === "running"); }); const isResultEvent = eventName === "tool_result" || eventName === "tool_end"; const isNewTool = shouldCountTool && matchedIndex < 0 && !handledEventIds.includes(countKey); const isQuestion = isNewTool && isSuperAgentQuestionTool(toolName); let nextEntries = currentEntries; if (isNewTool) { nextEntries = [ ...currentEntries, { id: countKey, name: toolName, kind: isQuestion ? "question" : "command", status: "running", arguments: getSuperAgentToolArguments(eventData), result: "", }, ]; } if (isResultEvent) { if (matchedIndex >= 0) { nextEntries = nextEntries.map((entry, index) => index === matchedIndex ? { ...entry, status: "done", result: getSuperAgentToolResult(eventData), } : entry ); } else if (isSuperAgentRunLogTool(toolName)) { nextEntries = [ ...nextEntries, { id: countKey, name: toolName, kind: isSuperAgentQuestionTool(toolName) ? "question" : "command", status: "done", arguments: getSuperAgentToolArguments(eventData), result: getSuperAgentToolResult(eventData), }, ]; } } return { runLog: { ...currentRunLog, startedAt, status: "running", questionCount: Number(currentRunLog.questionCount || 0) + (isQuestion ? 1 : 0), commandCount: Number(currentRunLog.commandCount || 0) + (isNewTool && !isQuestion ? 1 : 0), elapsedMs: Date.now() - startedAt, handledEventIds: isNewTool ? [...handledEventIds, countKey] : handledEventIds, entries: nextEntries, }, }; }); }; //[结束当前运行日志并记录本轮处理耗时] const finishRunLog = (runLog = null) => { if (!runLog) return null; const startedAt = Number(runLog.startedAt || 0); return { ...runLog, status: "done", elapsedMs: startedAt ? Date.now() - startedAt : Number(runLog.elapsedMs || 0), entries: (runLog.entries || []).map((entry) => ({ ...entry, status: "done", })), }; }; const clearWaitingNoticeMessages = () => { setConversationMessages((prev) => prev.filter((item) => !item.isWaitingNotice) ); }; const normalizeProgressEventData = (eventData = {}) => { const task = eventData.task || eventData.data?.task || eventData; return { task_type: task?.task_type || task?.taskType || "", status: task?.status || "", stage: task?.stage || eventData.stage || "", progress: Number(task?.progress ?? eventData.progress ?? 0), section_id: task?.section_id || task?.sectionId || eventData.section_id || eventData.sectionId || "", section_title: task?.section_title || task?.sectionTitle || eventData.section_title || eventData.sectionTitle || "", done: Number(task?.done ?? eventData.done ?? 0), total: Number(task?.total ?? eventData.total ?? 0), }; }; const scheduleSidebarRefresh = useCallback(() => { if (sidebarRefreshTimerRef.current) { window.clearTimeout(sidebarRefreshTimerRef.current); } //[done 后延迟刷新侧栏,避免与对话收尾同一帧抢布局] sidebarRefreshTimerRef.current = window.setTimeout(() => { sidebarRefreshTimerRef.current = null; loadSidebar({ silent: true }); }, 1800); }, [loadSidebar]); const upsertTaskProgressMessage = (sessionId, progressData, options = {}) => { if (!sessionId) return; const progress = Math.max(0, Math.min(100, Number(progressData.progress || 0))); const stageText = progressData.stage || "任务处理中"; const statusText = progressData.status || "running"; const normalizedTask = { ...progressData, stage: stageText, progress, status: statusText, }; updateTaskById(sessionId, { stage: stageText, progress, status: statusText, taskType: progressData.task_type || "", }); if (options.suppressMessage) return; const flushProgressMessage = (taskPayload) => { upsertAssistantMessage({ key: `session_progress_${sessionId}`, role: "assistant", type: "taskProgress", title: "正文生成", task: taskPayload, sessionId, }); }; const isTerminal = progress >= 100 || ["reviewing", "writed", "completed", "failed", "cancelled", "error"].includes( String(statusText || "").toLowerCase() ); const now = Date.now(); if (isTerminal || now - taskProgressUpsertAtRef.current >= 800) { taskProgressUpsertAtRef.current = now; taskProgressPendingRef.current = null; flushProgressMessage(normalizedTask); return; } //[进度卡节流:合并短时间内的多次 progress 事件] taskProgressPendingRef.current = normalizedTask; if (!taskProgressTimerRef.current) { taskProgressTimerRef.current = window.setTimeout(() => { taskProgressTimerRef.current = null; const pending = taskProgressPendingRef.current; if (!pending) return; taskProgressPendingRef.current = null; taskProgressUpsertAtRef.current = Date.now(); flushProgressMessage(pending); }, 800); } }; const extractEventText = (data) => { if (!data || typeof data !== "object") return ""; return ( data.content || data.text || data.message || data.delta || data.chunk || data.token || data?.choices?.[0]?.delta?.content || data?.choices?.[0]?.text || data?.data?.content || data?.data?.text || "" ); }; const handleSuperAgentEvent = (eventPayload, assistantMessageKey, options = {}) => { const eventName = eventPayload?.event || "message"; const eventData = eventPayload?.data || {}; const eventText = extractEventText(eventData); superAgentLog("chat.event", "handle", { sessionId: options.sessionId, assistantMessageKey, eventName, checkpointId: eventData?.checkpoint_id || eventData?.checkpointId || eventData?.checkpoint?.checkpoint_id || eventData?.checkpoint?.checkpointId, checkpointType: eventData?.checkpoint_type || eventData?.checkpoint?.checkpoint_type || eventData?.checkpoint?.type, progress: eventData?.progress ?? eventData?.task?.progress, status: eventData?.status ?? eventData?.task?.status, textLen: eventText?.length || 0, data: summarizeSuperAgentPayload(eventData), }); if (["text", "token", "content", "delta", "chunk"].includes(eventName)) { if (eventText) clearWaitingNoticeMessages(); appendStreamingText(assistantMessageKey, eventText); return; } if (["thinking", "reasoning", "thought", "tool_start", "tool_result", "tool_end"].includes(eventName)) { updateRunLogFromEvent(assistantMessageKey, eventName, eventData); return; } if (eventName === "progress") { const progressData = normalizeProgressEventData(eventData); const sectionTitle = progressData.section_title || progressData.stage || "正文"; const doneText = progressData.done && progressData.total ? `(${progressData.done}/${progressData.total})` : ""; clearWaitingNoticeMessages(); const progress = Math.max(0, Math.min(100, Number(progressData.progress || 0))); const statusText = progressData.status || "running"; const normalizedStatus = String(statusText).toLowerCase(); const isArtifactProgress = progressData.task_type === "artifact_build"; const isArtifactCompleted = isArtifactProgress && !["failed", "cancelled", "error"].includes(normalizedStatus) && (progress >= 100 || ["reviewing", "writed", "completed", "done", "success"].includes( normalizedStatus )); if (isArtifactProgress) { artifactProgressSessionRef.current = options.sessionId; } if (isArtifactCompleted) { } updateConversationMessage(assistantMessageKey, (item) => ({ title: progress >= 100 ? "正文生成完成" : `正在生成:${sectionTitle}`, loadingText: progress >= 100 ? `正文已生成完成${doneText},可点击按钮打开正文工作区` : `正文生成中${doneText},可点击按钮打开正文工作区`, task: { ...progressData, progress, status: statusText, }, })); //[正文进度使用独立进度卡session_progress_渲染,流式消息不转为taskProgress避免重复卡片] upsertTaskProgressMessage(options.sessionId, progressData); return; } if (eventName === "checkpoint") { const checkpointData = eventData.checkpoint || eventData.data?.checkpoint || eventData; const taskData = eventData.task || eventData.data?.task || checkpointData.task || null; clearWaitingNoticeMessages(); const checkpointId = checkpointData.checkpoint_id || checkpointData.checkpointId || checkpointData.id || ""; setConversationMessages((prev) => { const existingCheckpoint = prev.find((item) => { const itemCheckpointId = item?.checkpoint?.checkpoint_id || item?.checkpoint?.checkpointId || item?.checkpoint?.id || ""; return checkpointId && itemCheckpointId === checkpointId; }); const buildCheckpointCard = (item, mergedCheckpointData) => { const normalizedCheckpoint = normalizeCheckpoint(mergedCheckpointData); const localStatus = String(item?.checkpointStatus || "").toLowerCase(); const keepsLocalStatus = localStatus === "running" || localStatus === "submitting" || terminalCheckpointStatuses.has(localStatus); return { type: "checkpoint", title: normalizedCheckpoint.title, content: normalizedCheckpoint.description, checkpoint: normalizedCheckpoint, task: taskData, sessionId: options.sessionId, checkpointStatus: keepsLocalStatus ? localStatus : normalizedCheckpoint.checkpoint_status, loadingText: "", }; }; const canRemoveStreamingMessage = (item = {}) => { if (!item || item.key !== assistantMessageKey) return false; if (String(item.content || "").trim()) return false; if (item.runLog) return false; return true; }; const buildCheckpointKey = (fallbackItem = {}) => { if (fallbackItem.key && fallbackItem.type === "checkpoint") return fallbackItem.key; if (checkpointId && options.sessionId) { return `state_checkpoint_${options.sessionId}_${checkpointId}`; } return `checkpoint_${assistantMessageKey}`; }; if (existingCheckpoint && existingCheckpoint.key !== assistantMessageKey) { const mergedCheckpointData = mergeCheckpointEventData( existingCheckpoint, checkpointData ); const checkpointCard = buildCheckpointCard( existingCheckpoint, mergedCheckpointData ); return prev .filter((item) => !canRemoveStreamingMessage(item)) .map((item) => item.key === existingCheckpoint.key ? { ...item, ...checkpointCard } : item ); } const currentItem = prev.find((item) => item.key === assistantMessageKey) || {}; const mergedCheckpointData = mergeCheckpointEventData(currentItem, checkpointData); const checkpointCard = buildCheckpointCard(currentItem, mergedCheckpointData); const shouldReplaceCurrentItem = canRemoveStreamingMessage(currentItem); if (shouldReplaceCurrentItem) { return prev.map((item) => item.key === assistantMessageKey ? { ...item, ...checkpointCard } : item ); } const nextCheckpointCard = { ...checkpointCard, key: buildCheckpointKey(currentItem), role: "assistant", }; const hasCheckpointCard = prev.some((item) => item.key === nextCheckpointCard.key); if (hasCheckpointCard) { return prev.map((item) => item.key === nextCheckpointCard.key ? { ...item, ...nextCheckpointCard } : item ); } return [...prev, nextCheckpointCard]; }); return; } if (eventName === "checkpoint_done") { const checkpointId = eventData.checkpoint_id || eventData.checkpointId || eventData.id; setConversationMessages((prev) => prev.map((item) => { const itemCheckpointId = item?.checkpoint?.checkpoint_id || item?.checkpoint?.checkpointId || item?.checkpoint?.id; if (!checkpointId || itemCheckpointId !== checkpointId) return item; const localStatus = String(item.checkpointStatus || "").toLowerCase(); if (terminalCheckpointStatuses.has(localStatus)) return item; return { ...item, checkpointStatus: "running", }; }) ); return; } if (eventName === "done") { if (artifactProgressSessionRef.current === options.sessionId) { artifactProgressSessionRef.current = ""; } clearWaitingNoticeMessages(); updateConversationMessage(assistantMessageKey, (item) => { //[旁路答疑或正常流式:已有正文则保留;checkpoint 卡片本身不算失败] if (item.type === "checkpoint") { return { title: item.title || "需要确认", loadingText: "", runLog: finishRunLog(item.runLog), }; } const hasAnswerContent = Boolean(item.content || eventText); if (!hasAnswerContent) { if (options.allowEmptyDone) { return { title: "飞小尚", content: "已确认,正在继续推进任务。", runLog: finishRunLog(item.runLog), }; } return { title: "处理失败", content: "超级智能体未返回有效内容,请检查服务连接或稍后重试。", runLog: finishRunLog(item.runLog), }; } const answerContent = item.content || eventText; //[旁路答疑:若模型误吐标书流程文案,替换为简短提示,避免弹出流程卡] if ( (options.sideQa || item.sideQa) && isWorkflowBodyText(answerContent) ) { return { title: "飞小尚", content: "当前仍在确认卡片旁路答疑阶段,我只能回答与当前任务/卡片相关的简单问题,不会重新展示标书生成流程。请继续提问,或点击上方确认卡片按钮推进任务。", loadingText: "", sideQa: true, runLog: finishRunLog(item.runLog), }; } return { title: item.title || "飞小尚", content: answerContent, loadingText: "", sideQa: Boolean(options.sideQa || item.sideQa), runLog: finishRunLog(item.runLog), }; }); scheduleSidebarRefresh(); return; } if (eventName === "error") { if (artifactProgressSessionRef.current === options.sessionId) { artifactProgressSessionRef.current = ""; } clearWaitingNoticeMessages(); updateConversationMessage(assistantMessageKey, (item) => ({ title: "处理失败", content: eventText || eventData.error || "超级智能体处理失败,请稍后重试。", runLog: finishRunLog(item.runLog), })); return; } if (eventText) clearWaitingNoticeMessages(); if (eventText) appendStreamingText(assistantMessageKey, eventText); }; const executeMessageToAgent = async (messageText, options = {}) => { const content = String(messageText || "").trim(); if (!content) return; const traceId = createSuperAgentTraceId("send"); let nextAbortController = null; try { const sessionId = options.sessionId || (await ensureActiveSession({ isTaskSession: options.isTaskSession })); superAgentLog("chat.send", "start", { traceId, sessionId, currentUserId, isStreamingAnswer, content, options, }); if (!options.skipUserMessage) { clearPendingEmptySession(sessionId); const hasUserDisplayText = Object.prototype.hasOwnProperty.call( options, "userDisplayText" ); const userDisplayText = hasUserDisplayText ? options.userDisplayText : content; addUserMessage(userDisplayText, options.userFiles || [], sessionId); patchSessionTitleAfterUserMessage({ sessionId, isTaskSession: Boolean(options.isTaskSession), text: userDisplayText || content, }); } if (chatAbortControllerRef.current) chatAbortControllerRef.current.abort(); nextAbortController = new AbortController(); chatAbortControllerRef.current = nextAbortController; setIsStreamingAnswer(true); const runChatOnce = async ({ chatMessage, assistantTitle, loadingText, allowEmptyDone = false, }) => { const assistantMessageKey = `assistant_stream_${Date.now()}_${Math.random()}`; const runState = { hasCheckpoint: false, hasError: false, }; const sideQa = Boolean(options.sideQa); streamingMessageKeyRef.current = assistantMessageKey; setConversationMessages((prev) => [ ...prev, { key: assistantMessageKey, role: "assistant", type: "plain", title: assistantTitle, loadingText, content: "", sessionId, sideQa, }, ]); superAgentLog("chat.send", "run.start", { traceId, sessionId, assistantMessageKey, assistantTitle, allowEmptyDone, sideQa, chatMessage, }); await sendSuperAgentChat({ sessionId, userId: currentUserId, message: chatMessage, displayContent: options.displayContent || chatMessage, attachmentIds: options.attachmentIds || [], signal: nextAbortController.signal, onEvent: (eventPayload) => { const eventName = eventPayload?.event || "message"; if (eventName === "checkpoint") { runState.hasCheckpoint = true; } if (eventName === "error") { runState.hasError = true; } handleSuperAgentEvent(eventPayload, assistantMessageKey, { allowEmptyDone, sideQa, sessionId, isTaskSession: options.isTaskSession, restoreContentOnDone: options.restoreContentOnDone, }); }, }); //[部分服务不会发送 done 事件;本轮进度仍由 useStream 业务事件维护] if (artifactProgressSessionRef.current === sessionId) { artifactProgressSessionRef.current = ""; } superAgentLog("chat.send", "run.done", { traceId, sessionId, assistantMessageKey, runState, }); return runState; }; const firstRunState = await runChatOnce({ chatMessage: content, assistantTitle: options.waitingTitle || "飞小尚", loadingText: options.waitingText || "正在输出", allowEmptyDone: options.autoContinueOnce, }); const shouldAutoContinue = options.autoContinueOnce && !firstRunState.hasCheckpoint && !firstRunState.hasError; if (shouldAutoContinue) { superAgentWarn("chat.send", "auto_continue", { traceId, sessionId, autoContinueMessage: options.autoContinueMessage || "继续", firstRunState, }); await runChatOnce({ chatMessage: options.autoContinueMessage || "继续", assistantTitle: "飞小尚", loadingText: "正在输出", }); } } catch (error) { superAgentError("chat.send", "error", { traceId, error, messageText: content, options, }); if (error?.name !== "AbortError") { message.error(error?.message || "超级智能体请求失败"); } if (options.throwOnError) { throw error; } } finally { if (chatAbortControllerRef.current !== nextAbortController) return; superAgentLog("chat.send", "finish", { traceId, messageText: content, options, }); setIsStreamingAnswer(false); chatAbortControllerRef.current = null; streamingMessageKeyRef.current = ""; } }; const sendMessageToAgent = (messageText, options = {}) => { const content = String(messageText || "").trim(); if (!content) return Promise.resolve(); if (chatRunActiveRef.current && !options.allowWhileStreaming) { superAgentWarn("chat.send", "skip.streaming", { messageText: content, options, }); return Promise.resolve(); } const previousRun = chatRunPromiseRef.current.catch(() => undefined); const nextRun = chatRunActiveRef.current ? previousRun.then(() => executeMessageToAgent(content, options)) : executeMessageToAgent(content, options); chatRunActiveRef.current = true; let trackedRun; trackedRun = Promise.resolve(nextRun).finally(() => { if (chatRunPromiseRef.current === trackedRun) { chatRunActiveRef.current = false; } }); chatRunPromiseRef.current = trackedRun; return trackedRun; }; /** * 功能:提交 checkpoint action 并直接消费 respond SSE * 使用场景:确认、修改、重新生成等 checkpoint 操作 * * 入参: * - sessionId 当前任务会话 ID * - respondBody checkpoint/respond 请求体 * - actionText 前端展示文案 * * 返回:本次 SSE 是否收到事件、是否收到错误事件 * * 注意:respond 接口本身会恢复 LangGraph 中断,不再额外调用 /api/chat。 */ const respondCheckpointToAgent = async ({ sessionId, respondBody, actionText = {}, onFirstEvent, }) => { if (!sessionId) { throw new Error("当前任务会话不存在,请重新选择任务后再操作"); } const traceId = createSuperAgentTraceId("checkpoint_respond"); const assistantMessageKey = `assistant_checkpoint_${Date.now()}_${Math.random()}`; const runState = { hasEvent: false, hasError: false, errorMessage: "", }; let nextAbortController = null; try { if (chatAbortControllerRef.current) chatAbortControllerRef.current.abort(); nextAbortController = new AbortController(); chatAbortControllerRef.current = nextAbortController; streamingMessageKeyRef.current = assistantMessageKey; setIsStreamingAnswer(true); setConversationMessages((prev) => [ ...prev, { key: assistantMessageKey, role: "assistant", type: "plain", title: actionText.title || "飞小尚正在继续处理", loadingText: actionText.loadingText || "正在请求 AI 继续推进任务,请稍候", content: "", sessionId, }, ]); superAgentLog("chat.checkpoint", "respond.start", { traceId, sessionId, respondBody, }); await respondSuperAgentCheckpointStream({ body: respondBody, userId: currentUserId, sessionId, signal: nextAbortController.signal, onEvent: (eventPayload) => { const eventName = eventPayload?.event || "message"; if (eventName === "error") { runState.hasError = true; runState.errorMessage = eventPayload?.data?.message || eventPayload?.data?.error || eventPayload?.data?.content || "提交确认结果失败"; } else { runState.hasEvent = true; if (!runState.firstEventFired && onFirstEvent) { runState.firstEventFired = true; onFirstEvent(); } } handleSuperAgentEvent(eventPayload, assistantMessageKey, { allowEmptyDone: true, sessionId, isTaskSession: true, }); }, }); if (artifactProgressSessionRef.current === sessionId) { artifactProgressSessionRef.current = ""; } superAgentLog("chat.checkpoint", "respond.done", { traceId, sessionId, runState, }); return runState; } catch (error) { superAgentError("chat.checkpoint", "respond.error", { traceId, sessionId, respondBody, runState, error, }); if (error?.name !== "AbortError") { updateConversationMessage(assistantMessageKey, (item) => ({ title: "处理失败", content: error?.message || "提交确认后继续推进失败", runLog: finishRunLog(item.runLog), })); } throw error; } finally { if (chatAbortControllerRef.current !== nextAbortController) return; setIsStreamingAnswer(false); chatAbortControllerRef.current = null; streamingMessageKeyRef.current = ""; } }; const handleStopAnswer = () => { const currentAbortController = chatAbortControllerRef.current; const streamingMessageKey = streamingMessageKeyRef.current; if (!currentAbortController) return; superAgentWarn("chat.send", "abort", { streamingMessageKey, }); currentAbortController.abort(); chatAbortControllerRef.current = null; streamingMessageKeyRef.current = ""; setIsStreamingAnswer(false); if (!streamingMessageKey) return; updateConversationMessage(streamingMessageKey, (item) => { const hasContent = Boolean(item.content); return { title: hasContent ? item.title || "飞小尚" : "已停止生成", content: hasContent ? item.content : "已停止生成。", loadingText: "", runLog: { ...(item.runLog || {}), status: "stopped" }, }; }); }; //[显式停止按钮:中止SSE + 通知后端取消任务] const handleStopAndCancel = () => { handleStopAnswer(); const sessionId = activeSessionId || activeTaskId; if (sessionId && currentUserId) { cancelSuperAgentSession({ sessionId, userId: currentUserId }).catch((error) => { superAgentWarn("chat.stop", "cancel_failed", { sessionId, error: error?.message, }); }); } }; const startTaskConversation = () => { setRouteType("task"); setTaskStage(activeTask?.stage || TASK_STAGE.IDLE); setWorkspaceOpen(false); if (!conversationMessages.length) { addAssistantMessage({ type: "taskStart", title: TASK_WELCOME_TITLE, content: TASK_WELCOME_CONTENT, }); } return activeSessionId || activeTaskId; }; const resetRouteView = (nextRouteType) => { setRouteType(nextRouteType); setWorkspaceOpen(false); setActiveSessionId(""); setActiveTaskId(""); clearActiveSessionId(); setConversationMessages([]); setTaskStage(TASK_STAGE.IDLE); setUploadedFileList([]); setSelectedTaskType(null); }; const buildEmptyTaskStartMessage = () => ({ key: `assistant_task_start_${Date.now()}`, role: "assistant", type: "taskStart", title: TASK_WELCOME_TITLE, content: TASK_WELCOME_CONTENT, }); const enterTenderTaskGuide = () => { setSelectedTaskType("tender"); setConversationMessages((prev) => { const hasTaskStart = prev.some((item) => item?.type === "taskStart"); if (!hasTaskStart) { return [ { key: `assistant_task_start_${Date.now()}`, role: "assistant", type: "taskStart", title: TENDER_TASK_WELCOME_TITLE, content: TENDER_TASK_WELCOME_CONTENT, taskType: "tender", }, ...prev, ]; } return prev.map((item) => item?.type === "taskStart" ? { ...item, title: TENDER_TASK_WELCOME_TITLE, content: TENDER_TASK_WELCOME_CONTENT, taskType: "tender", } : item ); }); }; const handleSelectTaskType = (taskKey) => { if (taskKey === "tender") { //[投标文件:与「新对话」快捷入口一致,走对话引导,不直接出静态流程卡] // handleTenderQuickStart 定义在后方,此处仅作类型兜底;UI 点击应直接调 handleTenderQuickStart setSelectedTaskType("tender"); return; } message.info("该任务类型即将上线,敬请期待"); }; const handleCreateNewChat = async () => { if (creatingSessionRef.current || isCreatingChat || isCreatingTask) return; try { creatingSessionRef.current = true; setIsCreatingChat(true); resetRouteView("chat"); await createAndActivateSession({ isTaskSession: false, shouldResetMessages: true }); } catch (error) { message.error(error?.message || "创建新对话失败"); } finally { setIsCreatingChat(false); creatingSessionRef.current = false; } }; const handleCreateNewTask = async () => { if (creatingSessionRef.current || isCreatingChat || isCreatingTask) return; try { creatingSessionRef.current = true; setIsCreatingTask(true); resetRouteView("task"); await createAndActivateSession({ isTaskSession: true, shouldResetMessages: true }); setRouteType("task"); setTaskStage(TASK_STAGE.IDLE); addAssistantMessage({ type: "taskStart", title: TASK_WELCOME_TITLE, content: TASK_WELCOME_CONTENT, }); } catch (error) { message.error(error?.message || "创建新任务失败"); } finally { setIsCreatingTask(false); creatingSessionRef.current = false; } }; const handleCreateSessionInFolder = async (realm, folderId) => { if (creatingSessionRef.current || isCreatingChat || isCreatingTask) return; const isTaskRealm = realm === "task"; // 普通对话不挂文件夹;folderId 仅对任务生效;虚拟默认 → null const targetFolderId = isTaskRealm ? resolveApiFolderId(folderId) : null; try { creatingSessionRef.current = true; if (isTaskRealm) setIsCreatingTask(true); else setIsCreatingChat(true); if (isTaskRealm) { resetRouteView("task"); await createAndActivateSession({ isTaskSession: true, folderId: targetFolderId, shouldResetMessages: true, }); setRouteType("task"); setTaskStage(TASK_STAGE.IDLE); addAssistantMessage({ type: "taskStart", title: TASK_WELCOME_TITLE, content: TASK_WELCOME_CONTENT, }); } else { resetRouteView("chat"); await createAndActivateSession({ isTaskSession: false, folderId: null, shouldResetMessages: true, }); } } catch (error) { message.error(error?.message || "创建会话失败"); } finally { setIsCreatingChat(false); setIsCreatingTask(false); creatingSessionRef.current = false; } }; const openAgentSquare = () => { setRouteType("agents"); setWorkspaceOpen(false); }; const openResourceLibrary = () => { setRouteType("assets"); setWorkspaceOpen(false); }; const handleTenderQuickStart = () => { //[新任务 / 新对话入口统一:发起对话引导,由 AI 回复后再渲染流程/上传卡] setSelectedTaskType("tender"); if (!isTaskRoute) { startTaskConversation(); } else { setRouteType("task"); } setTaskStage(TASK_STAGE.BASIC_INFO); sendMessageToAgent("我要生成投标文件,请引导我上传招标文件并开始标书生成流程。", { isTaskSession: true, }); }; const handleUploadFile = (uploadPayload) => { const file = uploadPayload?.file || uploadPayload; const fileName = file?.name || ""; if (isUploadingFile) { message.warning("文件正在上传,请稍候"); return false; } if (!file || !fileName) { message.warning("请选择要上传的文件"); return false; } const currentSessionType = getCurrentSessionType(); //[选中文件后直接上传到当前会话;无会话时沿用当前页面类型创建会话] performUpload(file, fileName, currentSessionType); return false; }; //[执行上传文件的实际逻辑] const performUpload = (file, fileName, currentSessionType) => { const currentSessionId = activeSessionId || activeTaskId; const shouldCreateSession = !currentSessionId; const shouldUseTaskSession = currentSessionType === "task" || (shouldCreateSession && isTaskRoute); const shouldCreateNewTask = shouldCreateSession && shouldUseTaskSession; superAgentLog("chat.upload", "perform.start", { fileName, currentSessionId, currentSessionType, shouldCreateSession, shouldUseTaskSession, shouldCreateNewTask, file, }); if (shouldCreateNewTask) { startTaskConversation(); setSelectedTaskType("tender"); updateActiveTask({ title: fileName.replace(/\.[^.]+$/, "") || "AI 标书任务", fileName, stage: TASK_STAGE.BASIC_INFO, }); setTaskStage(TASK_STAGE.BASIC_INFO); } else if (shouldUseTaskSession) { setSelectedTaskType("tender"); } const uploadAndStart = async () => { setIsUploadingFile(true); setUploadProgress({ fileName, loaded: 0, total: Number(file?.size || 0), percent: 0, status: "preparing", }); try { const sessionId = currentSessionId || (await createAndActivateSession({ isTaskSession: shouldUseTaskSession, title: shouldUseTaskSession ? fileName.replace(/\.[^.]+$/, "") || "AI 标书任务" : "", })); superAgentLog("chat.upload", "session.ready", { sessionId, fileName, shouldUseTaskSession, }); const uploadResult = await uploadSuperAgentFile({ sessionId, userId: currentUserId, file, onProgress: (progress) => { setUploadProgress({ fileName, ...progress, status: "uploading", }); }, }); setUploadProgress((previous) => ({ ...previous, percent: 100, status: "processing", })); const uploadData = uploadResult?.data || uploadResult || {}; try { await createResourceFileFromUpload(uploadData); } catch (resourceError) { superAgentWarn("chat.upload", "resource_library_save_failed", { fileName, error: resourceError?.message, }); message.warning("文件已上传,但保存到资源库失败"); } const uploadedFileName = uploadData.filename || uploadData.original_filename || uploadData.originalFilename || fileName; const rawUploadedFilePath = uploadData.path || uploadData.url || uploadData.object_key || uploadData.objectKey || ""; const uploadedFilePath = buildQiniuFilePath(rawUploadedFilePath); const uploadedLocalPath = uploadData.local_path || uploadData.localPath || ""; const uploadedFileStorage = uploadData.storage || ""; const normalizedUploadedFileStorage = uploadedFileStorage || uploadData.storage_provider || uploadData.storageProvider || ""; superAgentLog("chat.upload", "upload.done", { sessionId, uploadedFileName, uploadedFilePath, uploadedLocalPath, uploadedFileStorage: normalizedUploadedFileStorage, uploadResult, }); const uploadedFile = { id: `${sessionId}_${uploadedFileName}_${Date.now()}`, attachmentId: uploadData.id || "", name: uploadedFileName, url: uploadedFilePath, objectKey: uploadData.object_key || uploadData.objectKey || "", localPath: uploadedLocalPath, storage: normalizedUploadedFileStorage, }; if (shouldCreateNewTask) { updateActiveTask({ title: uploadedFileName.replace(/\.[^.]+$/, "") || "AI 标书任务", fileName: uploadedFileName, filePath: uploadedFilePath, localPath: uploadedLocalPath, fileStorage: normalizedUploadedFileStorage, }); } setUploadedFileList((prev) => [...prev, uploadedFile]); message.success("文件上传成功,请输入指令后发送"); } catch (error) { superAgentError("chat.upload", "error", { fileName, currentSessionType, error, }); message.error(error?.message || "上传文件失败"); } finally { setIsUploadingFile(false); setUploadProgress(null); } }; uploadAndStart(); }; const handleRemoveUploadedFile = (fileId) => { setUploadedFileList((prev) => prev.filter((file) => file.id !== fileId)); }; const confirmBasicInfo = () => { superAgentLog("chat.confirm", "basic_info", { activeSessionId, activeTaskId }); setTaskStage(TASK_STAGE.SCORE); sendMessageToAgent("我确认基本信息无误,请继续解析评分点。", { isTaskSession: true, allowWhileStreaming: true, waitingTitle: "飞小尚正在解析评分点", waitingText: "已收到基本信息确认,正在分析评分点,请稍候", }); }; const confirmScoreItems = () => { superAgentLog("chat.confirm", "score_items", { activeSessionId, activeTaskId }); setTaskStage(TASK_STAGE.CATALOG); sendMessageToAgent("我确认评分点,请继续生成投标文件大纲。", { isTaskSession: true, allowWhileStreaming: true, waitingTitle: "飞小尚正在生成大纲", waitingText: "已收到评分点确认,正在生成投标文件大纲,请稍候", }); }; const confirmCatalog = () => { superAgentLog("chat.confirm", "catalog", { activeSessionId, activeTaskId }); setTaskStage(TASK_STAGE.CONTENT); sendMessageToAgent("我确认大纲,请继续生成投标文件正文。", { isTaskSession: true, allowWhileStreaming: true, taskAction: "continue_generation", restoreContentOnDone: true, waitingTitle: "飞小尚正在生成正文", waitingText: "已收到大纲确认,正在生成正文内容,请稍候", }); }; const handleSend = () => { const userInput = inputValue.trim(); const currentFileList = uploadedFileList; const fileReferenceText = buildUploadedFileReference(currentFileList); const finalMessage = [fileReferenceText, userInput].filter(Boolean).join("\n"); if (!finalMessage || isStreamingAnswer) return; superAgentLog("chat.input", "send", { currentSessionType: getCurrentSessionType(), uploadedFileCount: currentFileList.length, hasTaskKeyword: userInput.includes("标书") || userInput.includes("投标") || userInput.includes("招标"), finalMessage, }); setInputValue(""); setUploadedFileList([]); if (!currentFileList.length && userInput.includes("发现智能体")) { addUserMessage(userInput); openAgentSquare(); return; } const currentSessionType = getCurrentSessionType(); const hasTaskKeyword = userInput.includes("标书") || userInput.includes("投标") || userInput.includes("招标"); const shouldUseTaskSession = currentSessionType === "task" || isTaskRoute; if (shouldUseTaskSession) { startTaskConversation(); if (hasTaskKeyword || currentFileList.length > 0) { setSelectedTaskType("tender"); } } sendMessageToAgent(finalMessage, { isTaskSession: shouldUseTaskSession, userDisplayText: userInput, userFiles: currentFileList, //[文件引用写入历史展示字段,刷新或切换会话后才能还原文件标签] displayContent: finalMessage, attachmentIds: Array.from( new Set(currentFileList.map((file) => file.attachmentId).filter(Boolean)) ), }); }; const handleSelectTask = async (task) => { activeSessionIdRef.current = task.id; setActiveTaskId(task.id); setActiveSessionId(task.id); saveActiveSessionId(task.id); setRouteType("task"); setTaskStage(task.stage || TASK_STAGE.IDLE); setWorkspaceOpen(false); setUploadedFileList([]); setSelectedTaskType(null); setConversationMessages([]); //[useStream 是唯一会话恢复来源,stream.messages 负责在当前 thread 完成快照加载后还原消息] setConversationMessages([buildEmptyTaskStartMessage()]); return { success: true }; }; const handleSelectChat = async (chat) => { const sessionId = chat.id || chat.chatId; activeSessionIdRef.current = sessionId; setActiveSessionId(sessionId); saveActiveSessionId(sessionId); setActiveTaskId(""); setRouteType("chat"); setTaskStage(TASK_STAGE.IDLE); setWorkspaceOpen(false); setUploadedFileList([]); setSelectedTaskType(null); setConversationMessages([]); //[useStream 是唯一会话恢复来源,stream.messages 负责在当前 thread 完成快照加载后还原消息] return { success: true }; }; const handleDeleteSidebarSession = async (item, itemType) => { const sessionId = item?.id || item?.chatId; if (!sessionId) { message.error("删除失败,缺少会话 ID"); return; } try { await dispatch(deleteSuperAgentSession({ params: buildSessionParams(sessionId), query: { userId: currentUserId }, })).then((res) => ensureActionSuccess(res, "删除超级智能体会话失败")); removeSidebarSessionLocally(sessionId, itemType); clearActiveSidebarSession(sessionId); await loadSidebar({ silent: true }); message.success("删除成功"); } catch (error) { message.error(error?.message || "删除超级智能体会话失败"); } }; const handleDeleteSidebarSessionItem = (session) => { const sessionKind = session?.sessionKind || session?.type || "conversation"; return handleDeleteSidebarSession(session, sessionKind === "task" ? "task" : "chat"); }; return { routeType, inputValue, setInputValue, taskList, activeTaskId, activeTask, taskStage, setTaskStage, conversationMessages, uploadedFileList, uploadProgress, ordinaryChatList, sidebarTree, collapsedFolderMap, activeSessionId, isLoadingSessions, isUploadingFile, isStreamingAnswer, isCreatingChat, isCreatingTask, agentCategory, setAgentCategory, agentKeyword, setAgentKeyword, isTaskRoute, isAgentRoute, isResourceLibraryRoute, breadcrumbTitle, selectedTaskType, addUserMessage, upsertAssistantMessage, updateTaskById, updateActiveTask, updateConversationMessage, removeConversationMessage, createAndActivateSession, sendMessageToAgent, respondCheckpointToAgent, handleStopAnswer, handleStopAndCancel, handleCreateNewChat, handleCreateNewTask, openAgentSquare, openResourceLibrary, handleSelectTaskType, handleTenderQuickStart, handleUploadFile, handleRemoveUploadedFile, confirmBasicInfo, confirmScoreItems, confirmCatalog, handleSend, handleSelectTask, handleSelectChat, handleDeleteSidebarSession, handleCreateFolder, handleRenameFolder, handleDeleteFolder, handleCreateSessionInFolder, handleDeleteSidebarSessionItem, handleRenameSession, handleMoveSession, toggleFolderCollapsed, loadSidebar, }; }; export default useSuperAgentChat;