@ai-group/chat-sdk 3.6.8 → 3.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -103,14 +103,13 @@ var deduplicateMessages = (messageItems) => {
|
|
|
103
103
|
});
|
|
104
104
|
const botTextGroups = /* @__PURE__ */ new Map();
|
|
105
105
|
uniqueIdMessages.forEach((messageItem) => {
|
|
106
|
-
|
|
107
|
-
if (messageItem.role !== "bot" || !eventId || typeof messageItem.text !== "string")
|
|
106
|
+
if (messageItem.role !== "bot" || !messageItem.invocationId || typeof messageItem.text !== "string")
|
|
108
107
|
return;
|
|
109
108
|
const normalizedText = messageItem.text.replace(/\s+/g, " ").trim();
|
|
110
109
|
if (!normalizedText)
|
|
111
110
|
return;
|
|
112
111
|
const fileKey = (messageItem.fileData || []).map((file) => file.fileUri).join("|");
|
|
113
|
-
const groupKey = `${
|
|
112
|
+
const groupKey = `${messageItem.invocationId}\0${Boolean(
|
|
114
113
|
messageItem.thought
|
|
115
114
|
)}\0${fileKey}`;
|
|
116
115
|
const group = botTextGroups.get(groupKey) || [];
|
|
@@ -119,6 +118,8 @@ var deduplicateMessages = (messageItems) => {
|
|
|
119
118
|
});
|
|
120
119
|
const redundantMessageIds = /* @__PURE__ */ new Set();
|
|
121
120
|
botTextGroups.forEach((group) => {
|
|
121
|
+
if (group.length <= 1)
|
|
122
|
+
return;
|
|
122
123
|
const completeTexts = [];
|
|
123
124
|
[...group].sort((a, b) => b.normalizedText.length - a.normalizedText.length).forEach(({ messageItem, normalizedText }) => {
|
|
124
125
|
if (completeTexts.some(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/hooks/useADKChat.ts"],
|
|
4
|
-
"sourcesContent": ["import { useEffect, useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n fetchEventSource,\n EventStreamContentType,\n} from \"@microsoft/fetch-event-source\";\nimport { message } from \"antd\";\nimport { v4 } from \"uuid\";\nimport { SESSION_PAGE_SIZE, API_SUCCESS_CODE } from \"@/constants\";\nimport {\n SuccessCode,\n ErrorCode,\n DebugOptions,\n FunctionCall,\n SendContent,\n SessionData,\n AgentRunRequest,\n Event,\n FunctionResponse,\n IMessage,\n Part,\n} from \"@/types\";\nimport {\n fetchAppConfig,\n fetchSessionList,\n fetchSessionDetail,\n closeSession,\n updateSessionTitle,\n addFeedback,\n type ChatConfig,\n} from \"@/services/api\";\nimport { safeJsonParse } from \"@/utils\";\n\nconst combineTextParts = (parts: Part[]) => {\n const result: Part[] = [];\n let combinedTextPart: Part | undefined;\n\n // eslint-disable-next-line no-restricted-syntax\n for (const part of parts) {\n // 纯文本 part(没有 fileData 等其他字段)才合并\n const isPureText = part.text && !part.fileData;\n if (isPureText) {\n // 如果没有 combined 或 combined 思考类型跟当前 part 不同,则创建新的合并引用\n if (!combinedTextPart || combinedTextPart.thought !== part.thought) {\n combinedTextPart = { ...part };\n result.push(combinedTextPart);\n } else {\n combinedTextPart.text =\n (combinedTextPart.text || \"\") + (part.text || \"\");\n }\n } else {\n combinedTextPart = undefined;\n result.push(part);\n }\n }\n return result;\n};\n\nconst DEFAULT_SESSION_EVENTS_POLLING_INTERVAL = 10000;\n\n/**\n * 从 event + part 构建非文本 IMessage(functionCall / functionResponse / executableCode 等)。\n */\nconst buildNonTextMessage = (\n event: Event,\n part: Part,\n role: \"user\" | \"bot\" = \"bot\",\n): IMessage => {\n const msg: IMessage = {\n id: v4(),\n author: event.author,\n invocationId: event.invocationId,\n eventId: event.id,\n timestamp: event.timestamp,\n isLike: event.isLike || 0,\n role,\n modelCode: event.modelCode,\n usageMetadata: event.usageMetadata,\n finishReason: event.finishReason,\n raw: event,\n };\n\n if (part.inlineData) {\n msg.inlineData = {\n displayName: part.inlineData.displayName,\n data: part.inlineData.data,\n mimeType: part.inlineData.mimeType,\n };\n } else if (part.fileData) {\n msg.fileData = [part.fileData];\n } else if (part.functionCall) {\n msg.functionCall = part.functionCall;\n } else if (part.functionResponse) {\n msg.functionResponse = part.functionResponse;\n } else if (part.executableCode) {\n msg.executableCode = part.executableCode;\n } else if (part.codeExecutionResult) {\n msg.codeExecutionResult = part.codeExecutionResult;\n } else if (part.text) {\n msg.text = part.text;\n msg.thought = part.thought;\n }\n\n return msg;\n};\n\nconst getMessageEventId = (messageItem: IMessage) =>\n messageItem.eventId || messageItem.raw?.id;\n\nconst deduplicateMessages = (messageItems: IMessage[]) => {\n const seenMessageIds = new Set<string>();\n let hasDuplicate = false;\n\n const uniqueIdMessages = messageItems.filter((messageItem) => {\n if (seenMessageIds.has(messageItem.id)) {\n hasDuplicate = true;\n return false;\n }\n seenMessageIds.add(messageItem.id);\n return true;\n });\n\n // 机器人文本消息去重:同一事件、同一思考类型、同一文件列表的文本消息,如果文本内容包含关系,则保留最长的文本消息,去掉被包含的短文本消息。\n const botTextGroups = new Map<\n string,\n Array<{ messageItem: IMessage; normalizedText: string }>\n >();\n uniqueIdMessages.forEach((messageItem) => {\n const eventId = getMessageEventId(messageItem);\n if (\n messageItem.role !== \"bot\" ||\n !eventId ||\n typeof messageItem.text !== \"string\"\n )\n return;\n\n const normalizedText = messageItem.text.replace(/\\s+/g, \" \").trim();\n if (!normalizedText) return;\n\n const fileKey = (messageItem.fileData || [])\n .map((file) => file.fileUri)\n .join(\"|\");\n const groupKey = `${eventId}\\u0000${Boolean(\n messageItem.thought,\n )}\\u0000${fileKey}`;\n const group = botTextGroups.get(groupKey) || [];\n group.push({ messageItem, normalizedText });\n botTextGroups.set(groupKey, group);\n });\n\n const redundantMessageIds = new Set<string>();\n botTextGroups.forEach((group) => {\n const completeTexts: string[] = [];\n [...group]\n .sort((a, b) => b.normalizedText.length - a.normalizedText.length)\n .forEach(({ messageItem, normalizedText }) => {\n if (\n completeTexts.some((completeText) =>\n completeText.includes(normalizedText),\n )\n ) {\n redundantMessageIds.add(messageItem.id);\n hasDuplicate = true;\n return;\n }\n completeTexts.push(normalizedText);\n });\n });\n\n return hasDuplicate\n ? uniqueIdMessages.filter(\n (messageItem) => !redundantMessageIds.has(messageItem.id),\n )\n : messageItems;\n};\n\nconst mapSessionMessages = (sessionEvents: any[]): IMessage[] => {\n const mapped: IMessage[] = [];\n sessionEvents.forEach((item) => {\n if (!item || !item.content || !Array.isArray(item.content.parts)) return;\n // 后端为异步任务插入的用户事件仅用于关联任务,不在页面展示。\n if (\n item.author === \"user\" &&\n item.content.parts.some((part: any) => part.task)\n )\n return;\n // functionResponse 的 user 事件仅用于配对 functionCall,不作为独立消息展示\n if (\n item.content.role === \"user\" &&\n item.content.parts.every((part: any) => !part || part.functionResponse)\n )\n return;\n\n const role =\n (item.content.role || \"\").toLowerCase() === \"user\" ? \"user\" : \"bot\";\n const parts = item.content.parts.filter((part: any) => {\n if (!part) return false;\n return Boolean(\n part.text ||\n part.inlineData ||\n part.functionCall ||\n part.functionResponse ||\n part.fileData ||\n part.executableCode ||\n part.codeExecutionResult ||\n part.errorMessage,\n );\n });\n if (parts.length === 0) return;\n\n const textParts = parts.filter(\n (part: any) => part.text || part.errorMessage || part.inlineData,\n );\n const fileDataParts = parts.filter((part: any) => part.fileData);\n const otherParts = parts.filter(\n (part: any) =>\n !part.text && !part.errorMessage && !part.inlineData && !part.fileData,\n );\n\n // 使用确定性 ID:同一服务端事件 + 同一 part 类型始终生成相同 ID,\n // 确保多次 mapSessionMessages 调用产生的消息可以被 id 去重正确识别。\n let partCounter = 0;\n\n if (textParts.length > 0 || fileDataParts.length > 0) {\n const messageItem: IMessage = {\n id: `session-event:${item.id}:${partCounter++}`,\n author: item.author,\n invocationId: item.invocationId,\n eventId: item.id,\n timestamp: item.timestamp,\n isLike: item.isLike,\n role,\n modelCode: item.modelCode,\n usageMetadata: item.usageMetadata,\n finishReason: item.finishReason,\n raw: item,\n };\n\n textParts.forEach((part: any) => {\n if (part.inlineData) {\n messageItem.inlineData = {\n displayName: part.inlineData.displayName,\n data: part.inlineData.data,\n mimeType: part.inlineData.mimeType,\n };\n }\n if (part.text) {\n messageItem.text =\n (messageItem.text ? `${messageItem.text}\\n` : \"\") + part.text;\n if (typeof part.thought !== \"undefined\")\n messageItem.thought = part.thought;\n }\n if (part.errorMessage) {\n messageItem.text =\n (messageItem.text ? `${messageItem.text}\\n` : \"\") +\n part.errorMessage;\n }\n });\n\n if (fileDataParts.length > 0) {\n messageItem.fileData = fileDataParts.map((part: any) => ({\n displayName: part.fileData.displayName || \"\",\n fileUri: part.fileData.fileUri,\n mimeType: part.fileData.mimeType,\n }));\n }\n mapped.push(messageItem);\n }\n\n otherParts.forEach((part: any) => {\n const messageItem: IMessage = {\n id: `session-event:${item.id}:${partCounter++}`,\n author: item.author,\n invocationId: item.invocationId,\n eventId: item.id,\n timestamp: item.timestamp,\n isLike: item.isLike,\n role,\n modelCode: item.modelCode,\n usageMetadata: item.usageMetadata,\n finishReason: item.finishReason,\n raw: item,\n };\n\n if (part.functionCall) messageItem.functionCall = part.functionCall;\n if (part.executableCode) messageItem.executableCode = part.executableCode;\n if (part.codeExecutionResult)\n messageItem.codeExecutionResult = part.codeExecutionResult;\n if (part.functionResponse) {\n const functionCallMessage = mapped.find(\n (currentMessage) =>\n currentMessage.functionCall?.id === part.functionResponse?.id,\n );\n if (functionCallMessage) {\n functionCallMessage.functionResponse = part.functionResponse;\n }\n return;\n }\n mapped.push(messageItem);\n });\n });\n return mapped;\n};\n\nconst insertMissingSessionEvents = (\n currentMessages: IMessage[],\n sessionEvents: any[],\n removedInvocationIds?: Set<string>,\n) => {\n const renderedEventIds = new Set(\n currentMessages.map(getMessageEventId).filter(Boolean),\n );\n\n // 从所有 sessionEvents 中提取 functionResponse,配对到 currentMessages 中缺少响应的 functionCall\n // (functionResponse 事件的 role 为 user,不应作为独立消息展示,仅用于补齐工具调用状态)\n let nextMessages = [...currentMessages];\n const fnResMap = new Map<string, any>();\n sessionEvents.forEach((event) => {\n if (event.content?.role !== \"user\" || !Array.isArray(event.content?.parts))\n return;\n event.content.parts.forEach((p: any) => {\n if (p.functionResponse?.id) {\n fnResMap.set(p.functionResponse.id, p.functionResponse);\n }\n });\n });\n if (fnResMap.size > 0) {\n let paired = false;\n nextMessages = nextMessages.map((msg) => {\n if (msg.functionCall && !msg.functionResponse) {\n const callId = msg.functionCall.id;\n if (callId && fnResMap.has(callId)) {\n paired = true;\n return { ...msg, functionResponse: fnResMap.get(callId) };\n }\n }\n return msg;\n });\n if (!paired) nextMessages = currentMessages;\n }\n\n const missingEvents = sessionEvents.filter((event) => {\n const parts = event.content?.parts;\n const canRender =\n Boolean(event.id) &&\n event.content?.role === \"model\" &&\n Array.isArray(parts) &&\n parts.length > 0;\n if (!canRender || renderedEventIds.has(event.id)) return false;\n\n // reChat 截断后,忽略被删除的 invocationId 对应的旧 bot 消息\n if (\n removedInvocationIds &&\n removedInvocationIds.size > 0 &&\n event.invocationId &&\n removedInvocationIds.has(event.invocationId)\n ) {\n return false;\n }\n\n return true;\n });\n if (missingEvents.length === 0) return nextMessages;\n\n const missingMessages = mapSessionMessages(missingEvents);\n if (missingMessages.length === 0) return nextMessages;\n\n const eventOrder = new Map(\n sessionEvents.map((event, index) => [event.id, index]),\n );\n const getMessageOrder = (messageItem: IMessage) => {\n const eventId = getMessageEventId(messageItem);\n if (eventId && eventOrder.has(eventId)) return eventOrder.get(eventId)!;\n\n const timestamp = messageItem.timestamp ?? messageItem.raw?.timestamp;\n if (timestamp !== undefined) {\n const nextEventIndex = sessionEvents.findIndex(\n (event) => (event.timestamp || 0) > timestamp,\n );\n return nextEventIndex < 0\n ? sessionEvents.length + 0.5\n : nextEventIndex - 0.5;\n }\n return Number.POSITIVE_INFINITY;\n };\n\n // nextMessages 已在上方 functionResponse 配对阶段创建,此处直接复用\n missingMessages.forEach((messageItem) => {\n const targetOrder = getMessageOrder(messageItem);\n let insertIndex = nextMessages.findIndex((currentMessage) => {\n const currentOrder = getMessageOrder(currentMessage);\n return Number.isFinite(currentOrder) && currentOrder > targetOrder;\n });\n if (insertIndex < 0) insertIndex = nextMessages.length;\n nextMessages.splice(insertIndex, 0, messageItem);\n });\n return nextMessages;\n};\n\n// 后台会话连接状态\ninterface BackgroundSession {\n ctrl: AbortController;\n messages: IMessage[];\n loading: boolean;\n textMsgRef: IMessage | null;\n}\n\nfunction useADKChat({\n url = window.location.origin,\n token,\n config = {},\n type: _type = \"agentDebug\",\n enabled = true, // ← 新增: 是否启用 Hook\n strategies,\n onError,\n onMessage,\n onSuccess,\n onStream,\n}: DebugOptions) {\n const [loading, setLoadingState] = useState(false);\n const loadingRef = useRef(false);\n const setLoading = useCallback((nextLoading: boolean) => {\n loadingRef.current = nextLoading;\n setLoadingState(nextLoading);\n }, []);\n const [sessionLoading, setSessionLoading] = useState(false);\n const sendingRef = useRef(false); // 同步锁,防止快速重复点击\n const ctrl = useRef<AbortController | null>(null);\n const tokenRef = useRef(token);\n tokenRef.current = token;\n // 应用配置\n const { appNo, showFirstSession } = config || {};\n const pollSessionEvents = config?.session?.pollSessionEvents ?? true;\n const sessionEventsPollingInterval = Math.max(\n config?.session?.sessionEventsPollingInterval ??\n DEFAULT_SESSION_EVENTS_POLLING_INTERVAL,\n 1000,\n );\n const [appInfo, setAppInfo] = useState<ChatConfig | null>(null);\n // 初始化完成\n const [initialized, setInitialized] = useState(false);\n // 会话记录\n const [sessionList, setSessionList] = useState<SessionData[]>([]);\n // 当前会话\n const [currentSessionId, setCurrentSessionId] = useState<string>(() => v4());\n // 会话分页设置\n const [sessionPagination, setSessionPagination] = useState({\n total: 0,\n pageNum: 1,\n pageSize: SESSION_PAGE_SIZE,\n });\n // 开场白\n const [prologue, setPrologue] = useState<string>(\"\");\n // 建议问题\n const [suggestedQuestions, setSuggestedQuestions] = useState<string[]>([]);\n const [messages, setMessages] = useState<IMessage[]>([]);\n const pendingSessionEventsRef = useRef<{\n sessionId: string;\n events: any[];\n } | null>(null);\n const sessionDetailLoadingRef = useRef(false);\n // 用户自定义业务参数 (stateDelta),每次发送请求时携带\n const stateDeltaRef = useRef<Record<string, any> | undefined>(undefined);\n // reChat 截断消息时记录被删除的 invocationId,防止轮询把旧 bot 回复补回\n const reChatRemovedInvocationIdsRef = useRef<Set<string>>(new Set());\n\n // ===== 多会话后台连接管理 =====\n const backgroundRef = useRef<Map<string, BackgroundSession>>(new Map());\n const messagesRef = useRef<IMessage[]>(messages);\n messagesRef.current = messages;\n const currentSessionIdRef = useRef<string>(currentSessionId);\n currentSessionIdRef.current = currentSessionId;\n // 合并消息\n const mergedMessages = useMemo(() => {\n const fnResMap: Record<string, FunctionResponse> = {};\n const uniqueMessages = deduplicateMessages(messages);\n uniqueMessages.forEach((msg) => {\n if (msg.functionResponse) {\n fnResMap[msg?.functionResponse?.id || \"\"] = msg.functionResponse;\n }\n });\n return uniqueMessages.map((msg) => {\n if (msg.functionCall) {\n return {\n ...msg,\n functionResponse: fnResMap[msg?.functionCall?.id || \"\"],\n };\n }\n return msg;\n });\n }, [messages]);\n const textMsgRef = useRef<IMessage>(null);\n const eventDataRef = useRef<Map<string, any>>(new Map());\n const flushPendingSessionEvents = useCallback(() => {\n const pending = pendingSessionEventsRef.current;\n // 仅在用户正在发送或流式文本拼接时跳过 flush,\n // loading 状态不应阻塞轮询补入(异步任务完成的消息需要在 loading 期间也能补入)\n const replyInProgress = sendingRef.current || textMsgRef.current !== null;\n if (\n !pending ||\n replyInProgress ||\n pending.sessionId !== currentSessionIdRef.current\n )\n return;\n\n pendingSessionEventsRef.current = null;\n\n // 使用 functional update 在同一个 setMessages 回调中完成 diff + 写入,\n // 避免双重调用和 loading 闪烁。仅在有实际新消息时才触发 loading 状态。\n setMessages((prev) => {\n const nextMessages = insertMissingSessionEvents(\n prev,\n pending.events,\n reChatRemovedInvocationIdsRef.current,\n );\n if (nextMessages === prev) return prev; // 无变化,不触发 re-render\n messagesRef.current = nextMessages;\n return nextMessages;\n });\n }, []);\n\n const syncSessionEvents = useCallback(\n (events: any[], targetSessionId: string) => {\n if (targetSessionId !== currentSessionIdRef.current) return;\n pendingSessionEventsRef.current = {\n sessionId: targetSessionId,\n events,\n };\n flushPendingSessionEvents();\n },\n [flushPendingSessionEvents],\n );\n\n useEffect(() => {\n pendingSessionEventsRef.current = null;\n }, [currentSessionId]);\n\n useEffect(() => {\n if (!loading) flushPendingSessionEvents();\n }, [flushPendingSessionEvents, loading]);\n\n // 插入消息\n const insertMessage = useCallback((msg: IMessage) => {\n setMessages((prev) => {\n const lastMessage = prev[prev.length - 1];\n if (lastMessage?.isLoading) {\n return [...prev.slice(0, -1), msg, lastMessage];\n }\n return [...prev, msg];\n });\n }, []);\n\n // 初始化开场白预设置问题\n const insertSuggestedQuestions = useCallback(\n (suggested_questions: string[] = []) => {\n if (!suggested_questions?.length) return;\n // 无消息内容 且 有建议问题时\n setSuggestedQuestions((prev) =>\n messages.length === 0 ? suggested_questions : prev,\n );\n },\n [messages.length],\n );\n\n // 初始化开场白\n const insertPrologue = useCallback((prologueText: string) => {\n if (prologueText) {\n setPrologue(prologueText);\n }\n }, []);\n\n // 更新消息\n const updateMessage = useCallback((msg: IMessage) => {\n setMessages((prev) => {\n return prev.map((m) => {\n if (m.id === msg.id) {\n return msg;\n }\n return m;\n });\n });\n }, []);\n\n const withEventMeta = useCallback((msg: IMessage, event: Event): IMessage => {\n return {\n ...msg,\n modelCode: event.modelCode ?? msg.modelCode,\n usageMetadata: event.usageMetadata ?? msg.usageMetadata,\n finishReason: event.finishReason ?? msg.finishReason,\n raw: {\n ...(msg.raw || {}),\n ...event,\n },\n };\n }, []);\n\n const updateLastBotEventMeta = useCallback(\n (event: Event) => {\n if (!event.modelCode && !event.usageMetadata && !event.finishReason)\n return;\n\n setMessages((prev) => {\n const next = [...prev];\n const index = next.findLastIndex((msg) => msg.role === \"bot\");\n if (index < 0) return prev;\n\n next[index] = withEventMeta(next[index], event);\n return next;\n });\n },\n [withEventMeta],\n );\n\n // 存储事件\n const storeEvents = useCallback((part: Part | null, event: any) => {\n let title = \"\";\n\n if (part == null && event.actions?.artifactDelta) {\n title += \"eventAction: artifact\";\n } else if (part) {\n if (part.text) {\n title += `text:${part.text}`;\n } else if (part.functionCall) {\n title += `functionCall:${part.functionCall.name}`;\n } else if (part.functionResponse) {\n title += `functionResponse:${part.functionResponse.name}`;\n } else if (part.executableCode) {\n title += `executableCode:${part.executableCode.code?.slice(0, 10)}`;\n } else if (part.codeExecutionResult) {\n title += `codeExecutionResult:${part.codeExecutionResult.outcome}`;\n } else if (part.errorMessage) {\n title += `errorMessage:${part.errorMessage}`;\n }\n }\n\n const updatedEvent = { ...event, title };\n\n const newEventData = new Map(eventDataRef.current);\n newEventData.set(event.id, updatedEvent);\n eventDataRef.current = newEventData;\n }, []);\n\n // 存储消息\n const storeMessage = useCallback(\n (part: Part | null, event: Event, role: \"user\" | \"bot\") => {\n if (!part || Object.keys(part).length === 0) return;\n\n const msg = buildNonTextMessage(event, part, role);\n\n // groundingMetadata 仅在前台 SSE 场景需要\n if (\n part.text &&\n event?.groundingMetadata?.searchEntryPoint?.renderedContent\n ) {\n msg.renderedContent =\n event.groundingMetadata.searchEntryPoint.renderedContent;\n }\n\n insertMessage(msg);\n },\n [insertMessage],\n );\n\n // 处理消息部分(关键更新)\n const processPart = useCallback(\n (event: Event, part: Part, ignore: boolean = false) => {\n const renderedContent =\n event.groundingMetadata?.searchEntryPoint?.renderedContent;\n if (part.text) {\n if (ignore) return;\n const newChunk = part.text;\n\n if (\n !textMsgRef.current ||\n textMsgRef.current.thought !== part.thought\n ) {\n const newMessage: IMessage = {\n id: v4(),\n author: event.author,\n invocationId: event.invocationId,\n eventId: event.id,\n timestamp: event.timestamp,\n role: \"bot\",\n text: newChunk,\n isLike: event.isLike || 0,\n thought: part.thought,\n modelCode: event.modelCode,\n usageMetadata: event.usageMetadata,\n finishReason: event.finishReason,\n raw: event,\n };\n\n if (renderedContent) {\n newMessage.renderedContent = renderedContent;\n }\n\n textMsgRef.current = newMessage;\n // 存储原数据\n storeEvents(part, event);\n // 插入消息\n insertMessage(newMessage);\n } else {\n if (renderedContent) {\n textMsgRef.current = {\n ...textMsgRef.current,\n renderedContent,\n };\n }\n textMsgRef.current = {\n ...withEventMeta(textMsgRef.current, event),\n text: (textMsgRef.current.text || \"\") + newChunk,\n };\n updateMessage(textMsgRef.current);\n if (event.partial === false) {\n storeEvents(part, event);\n textMsgRef.current = null;\n }\n }\n } else {\n textMsgRef.current = null;\n storeEvents(part, event);\n storeMessage(part, event, \"bot\");\n }\n },\n [storeEvents, storeMessage, insertMessage, updateMessage, withEventMeta],\n );\n\n // 处理建议类消息\n const processFollowupPart = useCallback(\n (event: Event) => {\n // 获取建议类消息的文本内容\n const part = event?.content?.parts?.[0] || null;\n const text = part?.text || \"\";\n storeEvents(part, event);\n if (text) {\n setSuggestedQuestions((prev) => [...prev, text]);\n }\n },\n [storeEvents],\n );\n\n // 处理错误消息\n const processErrorMessage = useCallback(\n (chunkJson: any) => {\n storeEvents(null, chunkJson);\n insertMessage({\n id: v4(),\n text: chunkJson.errorMessage,\n role: \"bot\",\n });\n },\n [storeEvents, insertMessage],\n );\n\n // 处理动作和制品\n const processActionArtifact = useCallback(\n (event: any) => {\n if (event.actions && event.actions.artifactDelta) {\n storeEvents(null, event);\n storeMessage(null, event, \"bot\");\n }\n },\n [storeEvents, storeMessage],\n );\n\n // 发送消息请求\n const sendMessageRequest = useCallback(\n (values: AgentRunRequest) => {\n return new Promise<void>((resolve) => {\n const targetSessionId = values.sessionId || currentSessionIdRef.current;\n\n // 只 abort 同一 session 的旧连接\n if (targetSessionId === currentSessionIdRef.current && ctrl.current) {\n ctrl.current.abort();\n }\n const newCtrl = new AbortController();\n if (targetSessionId === currentSessionIdRef.current) {\n setLoading(true);\n ctrl.current = newCtrl;\n }\n\n // 当 signal 被外部 abort(stopChat)时,确保外层 Promise 被 resolve\n // 否则 startChat 中的 await 会永远挂起,sendingRef 无法重置为 false\n newCtrl.signal.addEventListener(\n \"abort\",\n () => {\n resolve();\n },\n { once: true },\n );\n\n const requestUrl = `${url}/api/gateway-web/openApi/v1/aizt/app/${appNo}/sendMsgStreaming`;\n\n // 后台流式文本拼接\n let bgTextMsg: IMessage | null = null;\n\n fetchEventSource(requestUrl, {\n method: \"POST\",\n signal: newCtrl.signal,\n body: JSON.stringify(values),\n openWhenHidden: true,\n headers: {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": \"no-cache\",\n stream: \"true\",\n Authorization: `Bearer ${tokenRef.current}`,\n },\n async onopen(response) {\n if (\n response.ok &&\n response.headers.get(\"content-type\") === EventStreamContentType\n ) {\n // everything's good\n } else if (response.status === 401 || response.status === 403) {\n setLoading(false);\n onError?.({\n code: ErrorCode.AUTH_ERROR,\n message:\n response.status === 401\n ? \"认证失败,token 无效或已过期\"\n : \"无权限访问该资源\",\n });\n resolve();\n } else if (\n response.status >= 400 &&\n response.status < 500 &&\n response.status !== 429\n ) {\n resolve();\n } else {\n resolve();\n }\n },\n onmessage: (event) => {\n const rawData = safeJsonParse(event.data, {});\n\n // 处理新的数据格式: { data: {...}, result: {...} }\n let chunkJson: Event = rawData;\n if (rawData.data && rawData.result) {\n // 转换为旧格式\n chunkJson = {\n ...rawData.data,\n content: rawData.data,\n invocationId: rawData.result.invocationId,\n sessionId: rawData.result.sessionId,\n id:\n rawData.data.id ||\n rawData.result.id ||\n rawData.result.eventId ||\n rawData.result.invocationId,\n };\n }\n\n if (chunkJson.error) {\n message.warning(chunkJson.error);\n return;\n }\n\n // 判断是否为后台 session\n const isBackground =\n currentSessionIdRef.current !== targetSessionId;\n\n if (isBackground) {\n // 后台 session:更新 backgroundRef 中的消息\n const bg = backgroundRef.current.get(targetSessionId);\n if (!bg) return;\n\n if (chunkJson.content) {\n if (chunkJson.content.role === \"followup\") return;\n for (const part of combineTextParts(chunkJson.content.parts)) {\n const isPureText = part.text && !part.fileData;\n if (isPureText) {\n if (chunkJson?.partial === false) continue;\n const newChunk = part.text || \"\";\n if (!bgTextMsg || bgTextMsg?.thought !== part.thought) {\n const newMessage: IMessage = {\n id: v4(),\n author: chunkJson.author,\n invocationId: chunkJson.invocationId,\n eventId: chunkJson.id,\n timestamp: chunkJson.timestamp,\n role: \"bot\",\n text: newChunk,\n thought: part.thought,\n };\n bgTextMsg = newMessage;\n bg.messages = [...bg.messages, newMessage];\n } else {\n bgTextMsg = {\n ...bgTextMsg,\n text: (bgTextMsg.text || \"\") + newChunk,\n };\n bg.messages = bg.messages.map((m) =>\n m.id === bgTextMsg!.id ? bgTextMsg! : m,\n );\n if (chunkJson.finishReason === \"stop\") {\n bgTextMsg = null;\n }\n }\n } else {\n bgTextMsg = null;\n bg.messages = [\n ...bg.messages,\n buildNonTextMessage(chunkJson, part),\n ];\n }\n }\n } else if (chunkJson.errorMessage) {\n bg.messages = [\n ...bg.messages,\n { id: v4(), text: chunkJson.errorMessage, role: \"bot\" },\n ];\n }\n bg.textMsgRef = bgTextMsg;\n return;\n }\n\n // 前台 session:正常处理\n onStream?.(chunkJson);\n updateLastBotEventMeta(chunkJson);\n if (chunkJson.content) {\n // 建议类消息单独处理\n if (chunkJson.content.role === \"followup\") {\n processFollowupPart(chunkJson);\n return;\n }\n // eslint-disable-next-line no-restricted-syntax\n for (const part of combineTextParts(chunkJson.content.parts)) {\n // partial为 false 时忽略该条消息文本\n processPart(chunkJson, part, chunkJson?.partial === false);\n }\n } else if (chunkJson.errorMessage) {\n processErrorMessage(chunkJson);\n } else if (chunkJson.actions) {\n processActionArtifact(chunkJson);\n }\n },\n onclose: () => {\n const isBackground =\n currentSessionIdRef.current !== targetSessionId;\n if (isBackground) {\n const bg = backgroundRef.current.get(targetSessionId);\n if (bg) {\n bg.loading = false;\n bg.textMsgRef = null;\n }\n // 如果该后台会话已被恢复到前台(backgroundRef 中已删除),\n // 需要更新前台 loading 状态\n if (\n !backgroundRef.current.has(targetSessionId) &&\n currentSessionIdRef.current === targetSessionId\n ) {\n setLoading(false);\n textMsgRef.current = null;\n }\n } else {\n setLoading(false);\n if (textMsgRef.current) {\n onMessage?.(textMsgRef.current?.text || \"\", textMsgRef.current);\n }\n textMsgRef.current = null;\n ctrl.current = null;\n }\n resolve();\n },\n onerror: (error) => {\n const isBackground =\n currentSessionIdRef.current !== targetSessionId;\n if (isBackground) {\n const bg = backgroundRef.current.get(targetSessionId);\n if (bg) bg.loading = false;\n // 同上:后台会话已恢复到前台时同步 loading 状态\n if (\n !backgroundRef.current.has(targetSessionId) &&\n currentSessionIdRef.current === targetSessionId\n ) {\n setLoading(false);\n ctrl.current = null;\n }\n } else {\n setLoading(false);\n ctrl.current = null;\n }\n resolve();\n console.error(\"EventSource failed:\", error);\n throw error;\n },\n });\n });\n },\n [\n processActionArtifact,\n processErrorMessage,\n processPart,\n updateLastBotEventMeta,\n ],\n );\n\n // 发送会话\n const startChat = async ({\n text = \"\",\n files = [],\n functionResponse,\n }: SendContent) => {\n if (loadingRef.current || sendingRef.current) return;\n if (!text.trim() && !files?.length && !functionResponse) return;\n sendingRef.current = true;\n // 清空建议问题\n setSuggestedQuestions([]);\n // 正常发送时重置 reChat 删除标记\n reChatRemovedInvocationIdsRef.current = new Set();\n // 发送消息\n setMessages((prev) => {\n let temp = [...prev];\n // 如果 text 存在\n if (text.trim()) {\n temp.push({\n id: v4(),\n role: \"user\",\n text,\n });\n }\n // 如果file 存在\n if (files.length > 0) {\n temp.push({\n id: v4(),\n role: \"user\",\n fileData: files.map((file) => ({\n displayName: file.fileName || file.name,\n mimeType: file.mimeType || file.response?.mimeType,\n fileUri:\n file.tempUrl || file.response?.fileUrl || file.response?.tempUrl,\n })),\n });\n }\n // 如果 functionResponse 存在\n if (functionResponse) {\n temp.push({\n id: v4(),\n role: \"user\",\n functionResponse,\n });\n }\n return temp;\n });\n try {\n await sendMessageRequest({\n stream: true,\n sessionId: currentSessionId,\n content: {\n role: \"user\",\n parts: functionResponse ? [{ functionResponse }] : [{ text }],\n },\n files: files.map((file) => ({\n fileName: file.fileName || file.response?.fileName,\n fileId: file.fileId || file.response?.fileId,\n tempUrl:\n file.tempUrl || file.response?.fileUrl || file.response?.tempUrl,\n type: file.type || file.response?.fileType,\n mimeType: file.mimeType || file.response?.mimeType,\n })),\n ...(stateDeltaRef.current !== undefined && {\n stateDelta: stateDeltaRef.current,\n }),\n });\n } finally {\n sendingRef.current = false;\n }\n // 获取聊天记录\n initAppConversations();\n };\n\n // 重新发送会话\n const reChat = async () => {\n if (loadingRef.current || sendingRef.current) return;\n if (messages.length === 0) return;\n sendingRef.current = true;\n // 清空建议问题\n setSuggestedQuestions([]);\n\n // 找到最后一条用户消息的索引,删除其后所有 bot 消息\n const lastUserIndex = messages.findLastIndex(\n (msg) => msg.role === \"user\" && !msg.functionResponse,\n );\n if (lastUserIndex === -1) {\n sendingRef.current = false;\n return;\n }\n\n const newMessages = messages.slice(0, lastUserIndex + 1);\n setMessages(newMessages);\n\n // 收集被截断的 bot 消息的 invocationId,轮询时忽略这些旧回复\n const removedInvocationIds = new Set<string>();\n for (let i = lastUserIndex + 1; i < messages.length; i++) {\n const msg = messages[i];\n if (msg.invocationId) removedInvocationIds.add(msg.invocationId);\n }\n reChatRemovedInvocationIdsRef.current = removedInvocationIds;\n\n const lastUserMessage = newMessages[lastUserIndex];\n const { text = \"\", fileData = [] } = lastUserMessage;\n\n try {\n await sendMessageRequest({\n stream: true,\n sessionId: currentSessionId,\n content: {\n role: \"user\",\n parts: [{ text }],\n },\n files: fileData?.map((file) => ({\n fileName: file.displayName,\n tempUrl: file.fileUri,\n mimeType: file.mimeType,\n })),\n ...(stateDeltaRef.current !== undefined && {\n stateDelta: stateDeltaRef.current,\n }),\n });\n } finally {\n sendingRef.current = false;\n }\n };\n\n // 确认函数调用\n const confirmFnCall = (fnCall: FunctionCall, confirmed: boolean) => {\n const functionResponse = strategies?.createFunctionResponse?.(\n fnCall,\n confirmed,\n ) ?? {\n id: fnCall.id,\n name: fnCall.name,\n response: { confirmed },\n };\n startChat({ functionResponse });\n };\n\n // 使用建议问题\n const suggestChat = (text: string) => {\n if (loadingRef.current) return;\n if (!text.trim()) return;\n setSuggestedQuestions([]);\n startChat({ text });\n };\n\n // 停止会话(只中断前台连接)\n const stopChat = useCallback(() => {\n pendingSessionEventsRef.current = null;\n ctrl.current?.abort();\n ctrl.current = null;\n setLoading(false);\n textMsgRef.current = null;\n }, [setLoading]);\n\n // 清除/重置会话\n const clearChat = () => {\n const newSessionId = v4();\n setCurrentSessionId(newSessionId);\n // 清除 reChat 删除标记\n reChatRemovedInvocationIdsRef.current = new Set();\n // 重置聊天内容\n stopChat();\n setPrologue(appInfo?.onboardingInfo?.prologue || \"\");\n setMessages([]);\n setSuggestedQuestions(appInfo?.onboardingInfo?.suggested_questions || []);\n };\n\n // 格式化会话记录\n const formatMessages = useCallback(\n (sessionEvents: any[], isReplace = false) => {\n const mapped = mapSessionMessages(sessionEvents);\n setMessages((prev) => (isReplace ? mapped : [...prev, ...mapped]));\n },\n [],\n );\n\n // 设置当前会话详情\n const setCurrentSession = async (sessionId: string) => {\n if (sessionId) {\n if (sessionId === currentSessionId) {\n return;\n }\n\n pendingSessionEventsRef.current = null;\n // 切换会话时重置 reChat 删除标记\n reChatRemovedInvocationIdsRef.current = new Set();\n\n // 1. 将当前会话挂起到后台(不中断 SSE 连接)\n const prevSessionId = currentSessionId;\n if (ctrl.current) {\n // 有活跃流式连接,保存到后台\n backgroundRef.current.set(prevSessionId, {\n ctrl: ctrl.current,\n messages: [...messagesRef.current],\n loading: true,\n textMsgRef: textMsgRef.current,\n });\n ctrl.current = null;\n textMsgRef.current = null;\n setLoading(false);\n } else if (messagesRef.current.length > 0) {\n // 无活跃连接但有消息,缓存用于切回\n backgroundRef.current.set(prevSessionId, {\n ctrl: new AbortController(),\n messages: [...messagesRef.current],\n loading: false,\n textMsgRef: null,\n });\n }\n\n // 2. 尝试从后台恢复目标会话\n const bg = backgroundRef.current.get(sessionId);\n if (bg) {\n setMessages(bg.messages);\n messagesRef.current = bg.messages;\n textMsgRef.current = bg.textMsgRef;\n // 仅当 SSE 连接还在运行时才恢复 loading 状态,\n // 避免 SSE 已关闭但 bg 快照中 loading 仍为 true 导致 sender 永久卡住\n const isSseStillActive = bg.loading && !bg.ctrl.signal.aborted;\n setLoading(isSseStillActive);\n ctrl.current = isSseStillActive ? bg.ctrl : null;\n setCurrentSessionId(sessionId);\n setInitialized(true);\n backgroundRef.current.delete(sessionId);\n return;\n }\n\n // 3. 后台没有目标 session,走 API 加载(原有逻辑)\n setInitialized(false);\n setCurrentSessionId(sessionId);\n sessionDetailLoadingRef.current = true;\n try {\n const { data, result } = await fetchSessionDetail({\n url,\n appNo,\n sessionId,\n token: tokenRef.current,\n });\n\n if (result?.code === API_SUCCESS_CODE) {\n setPrologue(appInfo?.onboardingInfo?.prologue || \"\");\n if (Array.isArray(data) && data.length > 0) {\n formatMessages(data, true);\n } else {\n setSuggestedQuestions(\n appInfo?.onboardingInfo?.suggested_questions || [],\n );\n }\n }\n } finally {\n sessionDetailLoadingRef.current = false;\n setInitialized(true);\n }\n } else {\n setCurrentSessionId(v4());\n }\n };\n\n // 获取聊天记录\n const initAppConversations = async (fetchDetail = false) => {\n try {\n setSessionLoading(true);\n\n const {\n data = [],\n pagination,\n result,\n } = await fetchSessionList({\n url,\n appNo,\n token: tokenRef.current,\n pageSize: sessionPagination.pageSize,\n });\n\n if (result?.code === API_SUCCESS_CODE) {\n if (data.length > 0) {\n const formatSessions = data.map((item) => {\n return {\n key: item.sessionId,\n label: item.title || \"新对话\",\n timestamp: new Date(item.startTime).getTime(),\n messages: [],\n meta: {\n ...item,\n },\n };\n });\n\n setSessionList(formatSessions);\n // 设置分页信息\n setSessionPagination({\n pageNum: sessionPagination.pageNum,\n pageSize: sessionPagination.pageSize,\n total: pagination?.total || 0,\n });\n const { sessionId } = data?.[0];\n if (showFirstSession) {\n setCurrentSession(sessionId);\n } else {\n fetchDetail && setPrologue(appInfo?.onboardingInfo?.prologue || \"\");\n fetchDetail &&\n setSuggestedQuestions(\n appInfo?.onboardingInfo?.suggested_questions || [],\n );\n }\n // 成功回调\n if (!initialized) {\n onSuccess?.({\n code: SuccessCode.APP_MESSAGES_INIT_SUCCESS,\n message: \"初始化聊天记录成功\",\n data: {\n sessionId,\n },\n });\n setInitialized(true);\n }\n } else {\n // 无会话记录时,初始化会话详情\n clearChat();\n }\n } else {\n // 服务端业务错误,透传原始 code + message 给接入方自行处理\n onError?.({\n code: result?.code || \"UNKNOWN_ERROR\",\n message: result?.message || \"获取会话列表失败\",\n raw: result,\n });\n setSessionList([]);\n setCurrentSessionId(v4());\n setPrologue(\"\");\n setSuggestedQuestions([]);\n }\n } catch {\n onError?.({\n code: ErrorCode.NETWORK_ERROR,\n message: \"获取会话列表失败\",\n });\n } finally {\n setSessionLoading(false);\n }\n };\n\n // 删除会话\n const deleteSession = async (sessionId: string) => {\n if (!sessionId) return;\n const { result } = await closeSession({\n url,\n appNo,\n sessionId,\n token: tokenRef.current,\n });\n if (result?.code === API_SUCCESS_CODE) {\n // 删除成功后,重新获取会话列表\n initAppConversations(true);\n // 如果删除的是当前会话,则创建新的会话\n if (sessionId === currentSessionId) {\n clearChat();\n }\n } else {\n message.error(\"删除会话失败\");\n }\n };\n\n // 点赞/点踩\n const likeMessage = async (\n invocationId: string,\n isLike: 1 | -1,\n feedbackData?: { feedbackTags?: string; feedbackDescription?: string },\n ) => {\n if (!appNo || !invocationId) return false;\n const { result } = await addFeedback({\n url,\n appNo,\n token: tokenRef.current,\n requestId: invocationId,\n isLike,\n ...feedbackData,\n });\n if (result?.code === API_SUCCESS_CODE) {\n setMessages((prev) =>\n prev.map((m) =>\n m.invocationId === invocationId ? { ...m, isLike } : m,\n ),\n );\n return true;\n }\n return false;\n };\n\n // 更新会话名称\n const updateSession = async (sessionId: string, title: string) => {\n if (!sessionId || !title) return;\n const { result } = await updateSessionTitle({\n url,\n appNo,\n title,\n sessionId,\n token: tokenRef.current,\n });\n if (result?.code === API_SUCCESS_CODE) {\n // 编辑成功后,重新获取会话列表\n initAppConversations();\n } else {\n message.error(\"更新会话失败\");\n }\n };\n\n // 初始化应用\n const initConfig = async () => {\n try {\n setSessionLoading(true);\n const { data, result } = await fetchAppConfig({ url, appNo });\n if (result.code === API_SUCCESS_CODE) {\n setAppInfo(data);\n // 成功回调\n onSuccess?.({\n code: SuccessCode.APP_CONFIG_INIT_SUCCESS,\n message: \"初始化配置成功\",\n });\n } else {\n // 服务端业务错误,透传原始 code + message\n onError?.({\n code: result.code || \"UNKNOWN_ERROR\",\n message: result.message || \"获取应用配置失败\",\n raw: result,\n });\n }\n } catch (error) {\n onError?.({\n code: ErrorCode.NETWORK_ERROR,\n message: \"获取应用配置失败\",\n });\n } finally {\n setSessionLoading(false);\n }\n };\n\n // 初始化—获取配置 (仅在启用时)\n useEffect(() => {\n if (enabled && url && appNo) {\n initConfig();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, url, appNo]);\n\n // 初始化-聊天记录\n useEffect(() => {\n if (appInfo) {\n initAppConversations(true);\n }\n }, [appInfo]);\n\n // 轮询当前会话详情,空闲时补入后端异步任务产生的模型消息。\n useEffect(() => {\n if (\n !enabled ||\n !initialized ||\n !pollSessionEvents ||\n !appNo ||\n !currentSessionId\n )\n return;\n\n let disposed = false;\n let requesting = false;\n const pollingSessionId = currentSessionId;\n\n const poll = async () => {\n if (disposed || requesting || sessionDetailLoadingRef.current) return;\n requesting = true;\n try {\n const { data, result } = await fetchSessionDetail({\n url,\n appNo,\n sessionId: pollingSessionId,\n token: tokenRef.current,\n });\n if (\n !disposed &&\n result?.code === API_SUCCESS_CODE &&\n Array.isArray(data)\n ) {\n syncSessionEvents(data, pollingSessionId);\n }\n } catch {\n // 新会话尚未落库或短暂网络异常时等待下一轮,不打断当前聊天。\n } finally {\n requesting = false;\n }\n };\n\n // 不立即执行首次 poll,避免与 initAppConversations / setCurrentSession / fetchSessionDetail 竞争。首次数据由初始化流程加载,轮询仅负责后续增量同步。\n const timer = window.setInterval(poll, sessionEventsPollingInterval);\n return () => {\n disposed = true;\n window.clearInterval(timer);\n };\n }, [\n appNo,\n currentSessionId,\n enabled,\n initialized,\n pollSessionEvents,\n sessionEventsPollingInterval,\n syncSessionEvents,\n url,\n ]);\n\n // 组件卸载时清理所有连接(前台 + 后台)\n useEffect(() => {\n return () => {\n ctrl.current?.abort();\n backgroundRef.current.forEach((bg) => bg.ctrl?.abort());\n backgroundRef.current.clear();\n };\n }, []);\n\n return {\n appInfo,\n startChat,\n reChat,\n stopChat,\n clearChat,\n suggestChat,\n confirmFnCall,\n initialized,\n currentSessionId,\n sessionList,\n sessionPagination,\n prologue,\n suggestions: suggestedQuestions,\n loading,\n sessionLoading,\n messages: mergedMessages,\n insertSuggestedQuestions,\n insertPrologue,\n deleteSession,\n updateSession,\n setSuggestedQuestions,\n setCurrentSession,\n setMessages,\n storeEvents,\n storeMessage,\n likeMessage,\n setStateDelta: (delta: Record<string, any> | undefined) => {\n stateDeltaRef.current = delta;\n },\n };\n}\n\nexport default useADKChat;\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { useEffect, useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n fetchEventSource,\n EventStreamContentType,\n} from \"@microsoft/fetch-event-source\";\nimport { message } from \"antd\";\nimport { v4 } from \"uuid\";\nimport { SESSION_PAGE_SIZE, API_SUCCESS_CODE } from \"@/constants\";\nimport {\n SuccessCode,\n ErrorCode,\n DebugOptions,\n FunctionCall,\n SendContent,\n SessionData,\n AgentRunRequest,\n Event,\n FunctionResponse,\n IMessage,\n Part,\n} from \"@/types\";\nimport {\n fetchAppConfig,\n fetchSessionList,\n fetchSessionDetail,\n closeSession,\n updateSessionTitle,\n addFeedback,\n type ChatConfig,\n} from \"@/services/api\";\nimport { safeJsonParse } from \"@/utils\";\n\nconst combineTextParts = (parts: Part[]) => {\n const result: Part[] = [];\n let combinedTextPart: Part | undefined;\n\n // eslint-disable-next-line no-restricted-syntax\n for (const part of parts) {\n // 纯文本 part(没有 fileData 等其他字段)才合并\n const isPureText = part.text && !part.fileData;\n if (isPureText) {\n // 如果没有 combined 或 combined 思考类型跟当前 part 不同,则创建新的合并引用\n if (!combinedTextPart || combinedTextPart.thought !== part.thought) {\n combinedTextPart = { ...part };\n result.push(combinedTextPart);\n } else {\n combinedTextPart.text =\n (combinedTextPart.text || \"\") + (part.text || \"\");\n }\n } else {\n combinedTextPart = undefined;\n result.push(part);\n }\n }\n return result;\n};\n\nconst DEFAULT_SESSION_EVENTS_POLLING_INTERVAL = 10000;\n\n/**\n * 从 event + part 构建非文本 IMessage(functionCall / functionResponse / executableCode 等)。\n */\nconst buildNonTextMessage = (\n event: Event,\n part: Part,\n role: \"user\" | \"bot\" = \"bot\",\n): IMessage => {\n const msg: IMessage = {\n id: v4(),\n author: event.author,\n invocationId: event.invocationId,\n eventId: event.id,\n timestamp: event.timestamp,\n isLike: event.isLike || 0,\n role,\n modelCode: event.modelCode,\n usageMetadata: event.usageMetadata,\n finishReason: event.finishReason,\n raw: event,\n };\n\n if (part.inlineData) {\n msg.inlineData = {\n displayName: part.inlineData.displayName,\n data: part.inlineData.data,\n mimeType: part.inlineData.mimeType,\n };\n } else if (part.fileData) {\n msg.fileData = [part.fileData];\n } else if (part.functionCall) {\n msg.functionCall = part.functionCall;\n } else if (part.functionResponse) {\n msg.functionResponse = part.functionResponse;\n } else if (part.executableCode) {\n msg.executableCode = part.executableCode;\n } else if (part.codeExecutionResult) {\n msg.codeExecutionResult = part.codeExecutionResult;\n } else if (part.text) {\n msg.text = part.text;\n msg.thought = part.thought;\n }\n\n return msg;\n};\n\nconst getMessageEventId = (messageItem: IMessage) =>\n messageItem.eventId || messageItem.raw?.id;\n\nconst deduplicateMessages = (messageItems: IMessage[]) => {\n const seenMessageIds = new Set<string>();\n let hasDuplicate = false;\n\n const uniqueIdMessages = messageItems.filter((messageItem) => {\n if (seenMessageIds.has(messageItem.id)) {\n hasDuplicate = true;\n return false;\n }\n seenMessageIds.add(messageItem.id);\n return true;\n });\n\n // 机器人文本消息去重:同一 invocationId + 思考类型的文本消息,\n // 如果文本内容存在包含关系,保留最长的(sessionDetails 完整消息),去掉被包含的短文本(SSE 流式增量)。\n // 使用 invocationId 分组,同一轮对话的 invocationId 始终一致, SSE 后续 chunk 的 首个id 与 sessionDetails 的 id 相同,其余不同,\n const botTextGroups = new Map<\n string,\n Array<{ messageItem: IMessage; normalizedText: string }>\n >();\n uniqueIdMessages.forEach((messageItem) => {\n if (\n messageItem.role !== \"bot\" ||\n !messageItem.invocationId ||\n typeof messageItem.text !== \"string\"\n )\n return;\n\n const normalizedText = messageItem.text.replace(/\\s+/g, \" \").trim();\n if (!normalizedText) return;\n\n const fileKey = (messageItem.fileData || [])\n .map((file) => file.fileUri)\n .join(\"|\");\n const groupKey = `${messageItem.invocationId}\\u0000${Boolean(\n messageItem.thought,\n )}\\u0000${fileKey}`;\n const group = botTextGroups.get(groupKey) || [];\n group.push({ messageItem, normalizedText });\n botTextGroups.set(groupKey, group);\n });\n\n const redundantMessageIds = new Set<string>();\n botTextGroups.forEach((group) => {\n if (group.length <= 1) return;\n const completeTexts: string[] = [];\n [...group]\n .sort((a, b) => b.normalizedText.length - a.normalizedText.length)\n .forEach(({ messageItem, normalizedText }) => {\n if (\n completeTexts.some((completeText) =>\n completeText.includes(normalizedText),\n )\n ) {\n redundantMessageIds.add(messageItem.id);\n hasDuplicate = true;\n return;\n }\n completeTexts.push(normalizedText);\n });\n });\n\n return hasDuplicate\n ? uniqueIdMessages.filter(\n (messageItem) => !redundantMessageIds.has(messageItem.id),\n )\n : messageItems;\n};\n\nconst mapSessionMessages = (sessionEvents: any[]): IMessage[] => {\n const mapped: IMessage[] = [];\n sessionEvents.forEach((item) => {\n if (!item || !item.content || !Array.isArray(item.content.parts)) return;\n // 后端为异步任务插入的用户事件仅用于关联任务,不在页面展示。\n if (\n item.author === \"user\" &&\n item.content.parts.some((part: any) => part.task)\n )\n return;\n // functionResponse 的 user 事件仅用于配对 functionCall,不作为独立消息展示\n if (\n item.content.role === \"user\" &&\n item.content.parts.every((part: any) => !part || part.functionResponse)\n )\n return;\n\n const role =\n (item.content.role || \"\").toLowerCase() === \"user\" ? \"user\" : \"bot\";\n const parts = item.content.parts.filter((part: any) => {\n if (!part) return false;\n return Boolean(\n part.text ||\n part.inlineData ||\n part.functionCall ||\n part.functionResponse ||\n part.fileData ||\n part.executableCode ||\n part.codeExecutionResult ||\n part.errorMessage,\n );\n });\n if (parts.length === 0) return;\n\n const textParts = parts.filter(\n (part: any) => part.text || part.errorMessage || part.inlineData,\n );\n const fileDataParts = parts.filter((part: any) => part.fileData);\n const otherParts = parts.filter(\n (part: any) =>\n !part.text && !part.errorMessage && !part.inlineData && !part.fileData,\n );\n\n // 使用确定性 ID:同一服务端事件 + 同一 part 类型始终生成相同 ID,\n // 确保多次 mapSessionMessages 调用产生的消息可以被 id 去重正确识别。\n let partCounter = 0;\n\n if (textParts.length > 0 || fileDataParts.length > 0) {\n const messageItem: IMessage = {\n id: `session-event:${item.id}:${partCounter++}`,\n author: item.author,\n invocationId: item.invocationId,\n eventId: item.id,\n timestamp: item.timestamp,\n isLike: item.isLike,\n role,\n modelCode: item.modelCode,\n usageMetadata: item.usageMetadata,\n finishReason: item.finishReason,\n raw: item,\n };\n\n textParts.forEach((part: any) => {\n if (part.inlineData) {\n messageItem.inlineData = {\n displayName: part.inlineData.displayName,\n data: part.inlineData.data,\n mimeType: part.inlineData.mimeType,\n };\n }\n if (part.text) {\n messageItem.text =\n (messageItem.text ? `${messageItem.text}\\n` : \"\") + part.text;\n if (typeof part.thought !== \"undefined\")\n messageItem.thought = part.thought;\n }\n if (part.errorMessage) {\n messageItem.text =\n (messageItem.text ? `${messageItem.text}\\n` : \"\") +\n part.errorMessage;\n }\n });\n\n if (fileDataParts.length > 0) {\n messageItem.fileData = fileDataParts.map((part: any) => ({\n displayName: part.fileData.displayName || \"\",\n fileUri: part.fileData.fileUri,\n mimeType: part.fileData.mimeType,\n }));\n }\n mapped.push(messageItem);\n }\n\n otherParts.forEach((part: any) => {\n const messageItem: IMessage = {\n id: `session-event:${item.id}:${partCounter++}`,\n author: item.author,\n invocationId: item.invocationId,\n eventId: item.id,\n timestamp: item.timestamp,\n isLike: item.isLike,\n role,\n modelCode: item.modelCode,\n usageMetadata: item.usageMetadata,\n finishReason: item.finishReason,\n raw: item,\n };\n\n if (part.functionCall) messageItem.functionCall = part.functionCall;\n if (part.executableCode) messageItem.executableCode = part.executableCode;\n if (part.codeExecutionResult)\n messageItem.codeExecutionResult = part.codeExecutionResult;\n if (part.functionResponse) {\n const functionCallMessage = mapped.find(\n (currentMessage) =>\n currentMessage.functionCall?.id === part.functionResponse?.id,\n );\n if (functionCallMessage) {\n functionCallMessage.functionResponse = part.functionResponse;\n }\n return;\n }\n mapped.push(messageItem);\n });\n });\n return mapped;\n};\n\nconst insertMissingSessionEvents = (\n currentMessages: IMessage[],\n sessionEvents: any[],\n removedInvocationIds?: Set<string>,\n) => {\n const renderedEventIds = new Set(\n currentMessages.map(getMessageEventId).filter(Boolean),\n );\n\n // 从所有 sessionEvents 中提取 functionResponse,配对到 currentMessages 中缺少响应的 functionCall\n // (functionResponse 事件的 role 为 user,不应作为独立消息展示,仅用于补齐工具调用状态)\n let nextMessages = [...currentMessages];\n const fnResMap = new Map<string, any>();\n sessionEvents.forEach((event) => {\n if (event.content?.role !== \"user\" || !Array.isArray(event.content?.parts))\n return;\n event.content.parts.forEach((p: any) => {\n if (p.functionResponse?.id) {\n fnResMap.set(p.functionResponse.id, p.functionResponse);\n }\n });\n });\n if (fnResMap.size > 0) {\n let paired = false;\n nextMessages = nextMessages.map((msg) => {\n if (msg.functionCall && !msg.functionResponse) {\n const callId = msg.functionCall.id;\n if (callId && fnResMap.has(callId)) {\n paired = true;\n return { ...msg, functionResponse: fnResMap.get(callId) };\n }\n }\n return msg;\n });\n if (!paired) nextMessages = currentMessages;\n }\n\n const missingEvents = sessionEvents.filter((event) => {\n const parts = event.content?.parts;\n const canRender =\n Boolean(event.id) &&\n event.content?.role === \"model\" &&\n Array.isArray(parts) &&\n parts.length > 0;\n if (!canRender || renderedEventIds.has(event.id)) return false;\n\n // reChat 截断后,忽略被删除的 invocationId 对应的旧 bot 消息\n if (\n removedInvocationIds &&\n removedInvocationIds.size > 0 &&\n event.invocationId &&\n removedInvocationIds.has(event.invocationId)\n ) {\n return false;\n }\n\n return true;\n });\n if (missingEvents.length === 0) return nextMessages;\n\n const missingMessages = mapSessionMessages(missingEvents);\n if (missingMessages.length === 0) return nextMessages;\n\n const eventOrder = new Map(\n sessionEvents.map((event, index) => [event.id, index]),\n );\n const getMessageOrder = (messageItem: IMessage) => {\n const eventId = getMessageEventId(messageItem);\n if (eventId && eventOrder.has(eventId)) return eventOrder.get(eventId)!;\n\n const timestamp = messageItem.timestamp ?? messageItem.raw?.timestamp;\n if (timestamp !== undefined) {\n const nextEventIndex = sessionEvents.findIndex(\n (event) => (event.timestamp || 0) > timestamp,\n );\n return nextEventIndex < 0\n ? sessionEvents.length + 0.5\n : nextEventIndex - 0.5;\n }\n return Number.POSITIVE_INFINITY;\n };\n\n // nextMessages 已在上方 functionResponse 配对阶段创建,此处直接复用\n missingMessages.forEach((messageItem) => {\n const targetOrder = getMessageOrder(messageItem);\n let insertIndex = nextMessages.findIndex((currentMessage) => {\n const currentOrder = getMessageOrder(currentMessage);\n return Number.isFinite(currentOrder) && currentOrder > targetOrder;\n });\n if (insertIndex < 0) insertIndex = nextMessages.length;\n nextMessages.splice(insertIndex, 0, messageItem);\n });\n return nextMessages;\n};\n\n// 后台会话连接状态\ninterface BackgroundSession {\n ctrl: AbortController;\n messages: IMessage[];\n loading: boolean;\n textMsgRef: IMessage | null;\n}\n\nfunction useADKChat({\n url = window.location.origin,\n token,\n config = {},\n type: _type = \"agentDebug\",\n enabled = true, // ← 新增: 是否启用 Hook\n strategies,\n onError,\n onMessage,\n onSuccess,\n onStream,\n}: DebugOptions) {\n const [loading, setLoadingState] = useState(false);\n const loadingRef = useRef(false);\n const setLoading = useCallback((nextLoading: boolean) => {\n loadingRef.current = nextLoading;\n setLoadingState(nextLoading);\n }, []);\n const [sessionLoading, setSessionLoading] = useState(false);\n const sendingRef = useRef(false); // 同步锁,防止快速重复点击\n const ctrl = useRef<AbortController | null>(null);\n const tokenRef = useRef(token);\n tokenRef.current = token;\n // 应用配置\n const { appNo, showFirstSession } = config || {};\n const pollSessionEvents = config?.session?.pollSessionEvents ?? true;\n const sessionEventsPollingInterval = Math.max(\n config?.session?.sessionEventsPollingInterval ??\n DEFAULT_SESSION_EVENTS_POLLING_INTERVAL,\n 1000,\n );\n const [appInfo, setAppInfo] = useState<ChatConfig | null>(null);\n // 初始化完成\n const [initialized, setInitialized] = useState(false);\n // 会话记录\n const [sessionList, setSessionList] = useState<SessionData[]>([]);\n // 当前会话\n const [currentSessionId, setCurrentSessionId] = useState<string>(() => v4());\n // 会话分页设置\n const [sessionPagination, setSessionPagination] = useState({\n total: 0,\n pageNum: 1,\n pageSize: SESSION_PAGE_SIZE,\n });\n // 开场白\n const [prologue, setPrologue] = useState<string>(\"\");\n // 建议问题\n const [suggestedQuestions, setSuggestedQuestions] = useState<string[]>([]);\n const [messages, setMessages] = useState<IMessage[]>([]);\n const pendingSessionEventsRef = useRef<{\n sessionId: string;\n events: any[];\n } | null>(null);\n const sessionDetailLoadingRef = useRef(false);\n // 用户自定义业务参数 (stateDelta),每次发送请求时携带\n const stateDeltaRef = useRef<Record<string, any> | undefined>(undefined);\n // reChat 截断消息时记录被删除的 invocationId,防止轮询把旧 bot 回复补回\n const reChatRemovedInvocationIdsRef = useRef<Set<string>>(new Set());\n\n // ===== 多会话后台连接管理 =====\n const backgroundRef = useRef<Map<string, BackgroundSession>>(new Map());\n const messagesRef = useRef<IMessage[]>(messages);\n messagesRef.current = messages;\n const currentSessionIdRef = useRef<string>(currentSessionId);\n currentSessionIdRef.current = currentSessionId;\n // 合并消息\n const mergedMessages = useMemo(() => {\n const fnResMap: Record<string, FunctionResponse> = {};\n const uniqueMessages = deduplicateMessages(messages);\n uniqueMessages.forEach((msg) => {\n if (msg.functionResponse) {\n fnResMap[msg?.functionResponse?.id || \"\"] = msg.functionResponse;\n }\n });\n return uniqueMessages.map((msg) => {\n if (msg.functionCall) {\n return {\n ...msg,\n functionResponse: fnResMap[msg?.functionCall?.id || \"\"],\n };\n }\n return msg;\n });\n }, [messages]);\n const textMsgRef = useRef<IMessage>(null);\n const eventDataRef = useRef<Map<string, any>>(new Map());\n const flushPendingSessionEvents = useCallback(() => {\n const pending = pendingSessionEventsRef.current;\n // 仅在用户正在发送或流式文本拼接时跳过 flush,\n // loading 状态不应阻塞轮询补入(异步任务完成的消息需要在 loading 期间也能补入)\n const replyInProgress = sendingRef.current || textMsgRef.current !== null;\n if (\n !pending ||\n replyInProgress ||\n pending.sessionId !== currentSessionIdRef.current\n )\n return;\n\n pendingSessionEventsRef.current = null;\n\n // 使用 functional update 在同一个 setMessages 回调中完成 diff + 写入,\n // 避免双重调用和 loading 闪烁。仅在有实际新消息时才触发 loading 状态。\n setMessages((prev) => {\n const nextMessages = insertMissingSessionEvents(\n prev,\n pending.events,\n reChatRemovedInvocationIdsRef.current,\n );\n if (nextMessages === prev) return prev; // 无变化,不触发 re-render\n messagesRef.current = nextMessages;\n return nextMessages;\n });\n }, []);\n\n const syncSessionEvents = useCallback(\n (events: any[], targetSessionId: string) => {\n if (targetSessionId !== currentSessionIdRef.current) return;\n pendingSessionEventsRef.current = {\n sessionId: targetSessionId,\n events,\n };\n flushPendingSessionEvents();\n },\n [flushPendingSessionEvents],\n );\n\n useEffect(() => {\n pendingSessionEventsRef.current = null;\n }, [currentSessionId]);\n\n useEffect(() => {\n if (!loading) flushPendingSessionEvents();\n }, [flushPendingSessionEvents, loading]);\n\n // 插入消息\n const insertMessage = useCallback((msg: IMessage) => {\n setMessages((prev) => {\n const lastMessage = prev[prev.length - 1];\n if (lastMessage?.isLoading) {\n return [...prev.slice(0, -1), msg, lastMessage];\n }\n return [...prev, msg];\n });\n }, []);\n\n // 初始化开场白预设置问题\n const insertSuggestedQuestions = useCallback(\n (suggested_questions: string[] = []) => {\n if (!suggested_questions?.length) return;\n // 无消息内容 且 有建议问题时\n setSuggestedQuestions((prev) =>\n messages.length === 0 ? suggested_questions : prev,\n );\n },\n [messages.length],\n );\n\n // 初始化开场白\n const insertPrologue = useCallback((prologueText: string) => {\n if (prologueText) {\n setPrologue(prologueText);\n }\n }, []);\n\n // 更新消息\n const updateMessage = useCallback((msg: IMessage) => {\n setMessages((prev) => {\n return prev.map((m) => {\n if (m.id === msg.id) {\n return msg;\n }\n return m;\n });\n });\n }, []);\n\n const withEventMeta = useCallback((msg: IMessage, event: Event): IMessage => {\n return {\n ...msg,\n modelCode: event.modelCode ?? msg.modelCode,\n usageMetadata: event.usageMetadata ?? msg.usageMetadata,\n finishReason: event.finishReason ?? msg.finishReason,\n raw: {\n ...(msg.raw || {}),\n ...event,\n },\n };\n }, []);\n\n const updateLastBotEventMeta = useCallback(\n (event: Event) => {\n if (!event.modelCode && !event.usageMetadata && !event.finishReason)\n return;\n\n setMessages((prev) => {\n const next = [...prev];\n const index = next.findLastIndex((msg) => msg.role === \"bot\");\n if (index < 0) return prev;\n\n next[index] = withEventMeta(next[index], event);\n return next;\n });\n },\n [withEventMeta],\n );\n\n // 存储事件\n const storeEvents = useCallback((part: Part | null, event: any) => {\n let title = \"\";\n\n if (part == null && event.actions?.artifactDelta) {\n title += \"eventAction: artifact\";\n } else if (part) {\n if (part.text) {\n title += `text:${part.text}`;\n } else if (part.functionCall) {\n title += `functionCall:${part.functionCall.name}`;\n } else if (part.functionResponse) {\n title += `functionResponse:${part.functionResponse.name}`;\n } else if (part.executableCode) {\n title += `executableCode:${part.executableCode.code?.slice(0, 10)}`;\n } else if (part.codeExecutionResult) {\n title += `codeExecutionResult:${part.codeExecutionResult.outcome}`;\n } else if (part.errorMessage) {\n title += `errorMessage:${part.errorMessage}`;\n }\n }\n\n const updatedEvent = { ...event, title };\n\n const newEventData = new Map(eventDataRef.current);\n newEventData.set(event.id, updatedEvent);\n eventDataRef.current = newEventData;\n }, []);\n\n // 存储消息\n const storeMessage = useCallback(\n (part: Part | null, event: Event, role: \"user\" | \"bot\") => {\n if (!part || Object.keys(part).length === 0) return;\n\n const msg = buildNonTextMessage(event, part, role);\n\n // groundingMetadata 仅在前台 SSE 场景需要\n if (\n part.text &&\n event?.groundingMetadata?.searchEntryPoint?.renderedContent\n ) {\n msg.renderedContent =\n event.groundingMetadata.searchEntryPoint.renderedContent;\n }\n\n insertMessage(msg);\n },\n [insertMessage],\n );\n\n // 处理消息部分(关键更新)\n const processPart = useCallback(\n (event: Event, part: Part, ignore: boolean = false) => {\n const renderedContent =\n event.groundingMetadata?.searchEntryPoint?.renderedContent;\n if (part.text) {\n if (ignore) return;\n const newChunk = part.text;\n\n if (\n !textMsgRef.current ||\n textMsgRef.current.thought !== part.thought\n ) {\n const newMessage: IMessage = {\n id: v4(),\n author: event.author,\n invocationId: event.invocationId,\n eventId: event.id,\n timestamp: event.timestamp,\n role: \"bot\",\n text: newChunk,\n isLike: event.isLike || 0,\n thought: part.thought,\n modelCode: event.modelCode,\n usageMetadata: event.usageMetadata,\n finishReason: event.finishReason,\n raw: event,\n };\n\n if (renderedContent) {\n newMessage.renderedContent = renderedContent;\n }\n\n textMsgRef.current = newMessage;\n // 存储原数据\n storeEvents(part, event);\n // 插入消息\n insertMessage(newMessage);\n } else {\n if (renderedContent) {\n textMsgRef.current = {\n ...textMsgRef.current,\n renderedContent,\n };\n }\n textMsgRef.current = {\n ...withEventMeta(textMsgRef.current, event),\n text: (textMsgRef.current.text || \"\") + newChunk,\n };\n updateMessage(textMsgRef.current);\n if (event.partial === false) {\n storeEvents(part, event);\n textMsgRef.current = null;\n }\n }\n } else {\n textMsgRef.current = null;\n storeEvents(part, event);\n storeMessage(part, event, \"bot\");\n }\n },\n [storeEvents, storeMessage, insertMessage, updateMessage, withEventMeta],\n );\n\n // 处理建议类消息\n const processFollowupPart = useCallback(\n (event: Event) => {\n // 获取建议类消息的文本内容\n const part = event?.content?.parts?.[0] || null;\n const text = part?.text || \"\";\n storeEvents(part, event);\n if (text) {\n setSuggestedQuestions((prev) => [...prev, text]);\n }\n },\n [storeEvents],\n );\n\n // 处理错误消息\n const processErrorMessage = useCallback(\n (chunkJson: any) => {\n storeEvents(null, chunkJson);\n insertMessage({\n id: v4(),\n text: chunkJson.errorMessage,\n role: \"bot\",\n });\n },\n [storeEvents, insertMessage],\n );\n\n // 处理动作和制品\n const processActionArtifact = useCallback(\n (event: any) => {\n if (event.actions && event.actions.artifactDelta) {\n storeEvents(null, event);\n storeMessage(null, event, \"bot\");\n }\n },\n [storeEvents, storeMessage],\n );\n\n // 发送消息请求\n const sendMessageRequest = useCallback(\n (values: AgentRunRequest) => {\n return new Promise<void>((resolve) => {\n const targetSessionId = values.sessionId || currentSessionIdRef.current;\n\n // 只 abort 同一 session 的旧连接\n if (targetSessionId === currentSessionIdRef.current && ctrl.current) {\n ctrl.current.abort();\n }\n const newCtrl = new AbortController();\n if (targetSessionId === currentSessionIdRef.current) {\n setLoading(true);\n ctrl.current = newCtrl;\n }\n\n // 当 signal 被外部 abort(stopChat)时,确保外层 Promise 被 resolve\n // 否则 startChat 中的 await 会永远挂起,sendingRef 无法重置为 false\n newCtrl.signal.addEventListener(\n \"abort\",\n () => {\n resolve();\n },\n { once: true },\n );\n\n const requestUrl = `${url}/api/gateway-web/openApi/v1/aizt/app/${appNo}/sendMsgStreaming`;\n\n // 后台流式文本拼接\n let bgTextMsg: IMessage | null = null;\n\n fetchEventSource(requestUrl, {\n method: \"POST\",\n signal: newCtrl.signal,\n body: JSON.stringify(values),\n openWhenHidden: true,\n headers: {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": \"no-cache\",\n stream: \"true\",\n Authorization: `Bearer ${tokenRef.current}`,\n },\n async onopen(response) {\n if (\n response.ok &&\n response.headers.get(\"content-type\") === EventStreamContentType\n ) {\n // everything's good\n } else if (response.status === 401 || response.status === 403) {\n setLoading(false);\n onError?.({\n code: ErrorCode.AUTH_ERROR,\n message:\n response.status === 401\n ? \"认证失败,token 无效或已过期\"\n : \"无权限访问该资源\",\n });\n resolve();\n } else if (\n response.status >= 400 &&\n response.status < 500 &&\n response.status !== 429\n ) {\n resolve();\n } else {\n resolve();\n }\n },\n onmessage: (event) => {\n const rawData = safeJsonParse(event.data, {});\n\n // 处理新的数据格式: { data: {...}, result: {...} }\n let chunkJson: Event = rawData;\n if (rawData.data && rawData.result) {\n // 转换为旧格式\n chunkJson = {\n ...rawData.data,\n content: rawData.data,\n invocationId: rawData.result.invocationId,\n sessionId: rawData.result.sessionId,\n id:\n rawData.data.id ||\n rawData.result.id ||\n rawData.result.eventId ||\n rawData.result.invocationId,\n };\n }\n\n if (chunkJson.error) {\n message.warning(chunkJson.error);\n return;\n }\n\n // 判断是否为后台 session\n const isBackground =\n currentSessionIdRef.current !== targetSessionId;\n\n if (isBackground) {\n // 后台 session:更新 backgroundRef 中的消息\n const bg = backgroundRef.current.get(targetSessionId);\n if (!bg) return;\n\n if (chunkJson.content) {\n if (chunkJson.content.role === \"followup\") return;\n for (const part of combineTextParts(chunkJson.content.parts)) {\n const isPureText = part.text && !part.fileData;\n if (isPureText) {\n if (chunkJson?.partial === false) continue;\n const newChunk = part.text || \"\";\n if (!bgTextMsg || bgTextMsg?.thought !== part.thought) {\n const newMessage: IMessage = {\n id: v4(),\n author: chunkJson.author,\n invocationId: chunkJson.invocationId,\n eventId: chunkJson.id,\n timestamp: chunkJson.timestamp,\n role: \"bot\",\n text: newChunk,\n thought: part.thought,\n };\n bgTextMsg = newMessage;\n bg.messages = [...bg.messages, newMessage];\n } else {\n bgTextMsg = {\n ...bgTextMsg,\n text: (bgTextMsg.text || \"\") + newChunk,\n };\n bg.messages = bg.messages.map((m) =>\n m.id === bgTextMsg!.id ? bgTextMsg! : m,\n );\n if (chunkJson.finishReason === \"stop\") {\n bgTextMsg = null;\n }\n }\n } else {\n bgTextMsg = null;\n bg.messages = [\n ...bg.messages,\n buildNonTextMessage(chunkJson, part),\n ];\n }\n }\n } else if (chunkJson.errorMessage) {\n bg.messages = [\n ...bg.messages,\n { id: v4(), text: chunkJson.errorMessage, role: \"bot\" },\n ];\n }\n bg.textMsgRef = bgTextMsg;\n return;\n }\n\n // 前台 session:正常处理\n onStream?.(chunkJson);\n updateLastBotEventMeta(chunkJson);\n if (chunkJson.content) {\n // 建议类消息单独处理\n if (chunkJson.content.role === \"followup\") {\n processFollowupPart(chunkJson);\n return;\n }\n // eslint-disable-next-line no-restricted-syntax\n for (const part of combineTextParts(chunkJson.content.parts)) {\n // partial为 false 时忽略该条消息文本\n processPart(chunkJson, part, chunkJson?.partial === false);\n }\n } else if (chunkJson.errorMessage) {\n processErrorMessage(chunkJson);\n } else if (chunkJson.actions) {\n processActionArtifact(chunkJson);\n }\n },\n onclose: () => {\n const isBackground =\n currentSessionIdRef.current !== targetSessionId;\n if (isBackground) {\n const bg = backgroundRef.current.get(targetSessionId);\n if (bg) {\n bg.loading = false;\n bg.textMsgRef = null;\n }\n // 如果该后台会话已被恢复到前台(backgroundRef 中已删除),\n // 需要更新前台 loading 状态\n if (\n !backgroundRef.current.has(targetSessionId) &&\n currentSessionIdRef.current === targetSessionId\n ) {\n setLoading(false);\n textMsgRef.current = null;\n }\n } else {\n setLoading(false);\n if (textMsgRef.current) {\n onMessage?.(textMsgRef.current?.text || \"\", textMsgRef.current);\n }\n textMsgRef.current = null;\n ctrl.current = null;\n }\n resolve();\n },\n onerror: (error) => {\n const isBackground =\n currentSessionIdRef.current !== targetSessionId;\n if (isBackground) {\n const bg = backgroundRef.current.get(targetSessionId);\n if (bg) bg.loading = false;\n // 同上:后台会话已恢复到前台时同步 loading 状态\n if (\n !backgroundRef.current.has(targetSessionId) &&\n currentSessionIdRef.current === targetSessionId\n ) {\n setLoading(false);\n ctrl.current = null;\n }\n } else {\n setLoading(false);\n ctrl.current = null;\n }\n resolve();\n console.error(\"EventSource failed:\", error);\n throw error;\n },\n });\n });\n },\n [\n processActionArtifact,\n processErrorMessage,\n processPart,\n updateLastBotEventMeta,\n ],\n );\n\n // 发送会话\n const startChat = async ({\n text = \"\",\n files = [],\n functionResponse,\n }: SendContent) => {\n if (loadingRef.current || sendingRef.current) return;\n if (!text.trim() && !files?.length && !functionResponse) return;\n sendingRef.current = true;\n // 清空建议问题\n setSuggestedQuestions([]);\n // 正常发送时重置 reChat 删除标记\n reChatRemovedInvocationIdsRef.current = new Set();\n // 发送消息\n setMessages((prev) => {\n let temp = [...prev];\n // 如果 text 存在\n if (text.trim()) {\n temp.push({\n id: v4(),\n role: \"user\",\n text,\n });\n }\n // 如果file 存在\n if (files.length > 0) {\n temp.push({\n id: v4(),\n role: \"user\",\n fileData: files.map((file) => ({\n displayName: file.fileName || file.name,\n mimeType: file.mimeType || file.response?.mimeType,\n fileUri:\n file.tempUrl || file.response?.fileUrl || file.response?.tempUrl,\n })),\n });\n }\n // 如果 functionResponse 存在\n if (functionResponse) {\n temp.push({\n id: v4(),\n role: \"user\",\n functionResponse,\n });\n }\n return temp;\n });\n try {\n await sendMessageRequest({\n stream: true,\n sessionId: currentSessionId,\n content: {\n role: \"user\",\n parts: functionResponse ? [{ functionResponse }] : [{ text }],\n },\n files: files.map((file) => ({\n fileName: file.fileName || file.response?.fileName,\n fileId: file.fileId || file.response?.fileId,\n tempUrl:\n file.tempUrl || file.response?.fileUrl || file.response?.tempUrl,\n type: file.type || file.response?.fileType,\n mimeType: file.mimeType || file.response?.mimeType,\n })),\n ...(stateDeltaRef.current !== undefined && {\n stateDelta: stateDeltaRef.current,\n }),\n });\n } finally {\n sendingRef.current = false;\n }\n // 获取聊天记录\n initAppConversations();\n };\n\n // 重新发送会话\n const reChat = async () => {\n if (loadingRef.current || sendingRef.current) return;\n if (messages.length === 0) return;\n sendingRef.current = true;\n // 清空建议问题\n setSuggestedQuestions([]);\n\n // 找到最后一条用户消息的索引,删除其后所有 bot 消息\n const lastUserIndex = messages.findLastIndex(\n (msg) => msg.role === \"user\" && !msg.functionResponse,\n );\n if (lastUserIndex === -1) {\n sendingRef.current = false;\n return;\n }\n\n const newMessages = messages.slice(0, lastUserIndex + 1);\n setMessages(newMessages);\n\n // 收集被截断的 bot 消息的 invocationId,轮询时忽略这些旧回复\n const removedInvocationIds = new Set<string>();\n for (let i = lastUserIndex + 1; i < messages.length; i++) {\n const msg = messages[i];\n if (msg.invocationId) removedInvocationIds.add(msg.invocationId);\n }\n reChatRemovedInvocationIdsRef.current = removedInvocationIds;\n\n const lastUserMessage = newMessages[lastUserIndex];\n const { text = \"\", fileData = [] } = lastUserMessage;\n\n try {\n await sendMessageRequest({\n stream: true,\n sessionId: currentSessionId,\n content: {\n role: \"user\",\n parts: [{ text }],\n },\n files: fileData?.map((file) => ({\n fileName: file.displayName,\n tempUrl: file.fileUri,\n mimeType: file.mimeType,\n })),\n ...(stateDeltaRef.current !== undefined && {\n stateDelta: stateDeltaRef.current,\n }),\n });\n } finally {\n sendingRef.current = false;\n }\n };\n\n // 确认函数调用\n const confirmFnCall = (fnCall: FunctionCall, confirmed: boolean) => {\n const functionResponse = strategies?.createFunctionResponse?.(\n fnCall,\n confirmed,\n ) ?? {\n id: fnCall.id,\n name: fnCall.name,\n response: { confirmed },\n };\n startChat({ functionResponse });\n };\n\n // 使用建议问题\n const suggestChat = (text: string) => {\n if (loadingRef.current) return;\n if (!text.trim()) return;\n setSuggestedQuestions([]);\n startChat({ text });\n };\n\n // 停止会话(只中断前台连接)\n const stopChat = useCallback(() => {\n pendingSessionEventsRef.current = null;\n ctrl.current?.abort();\n ctrl.current = null;\n setLoading(false);\n textMsgRef.current = null;\n }, [setLoading]);\n\n // 清除/重置会话\n const clearChat = () => {\n const newSessionId = v4();\n setCurrentSessionId(newSessionId);\n // 清除 reChat 删除标记\n reChatRemovedInvocationIdsRef.current = new Set();\n // 重置聊天内容\n stopChat();\n setPrologue(appInfo?.onboardingInfo?.prologue || \"\");\n setMessages([]);\n setSuggestedQuestions(appInfo?.onboardingInfo?.suggested_questions || []);\n };\n\n // 格式化会话记录\n const formatMessages = useCallback(\n (sessionEvents: any[], isReplace = false) => {\n const mapped = mapSessionMessages(sessionEvents);\n setMessages((prev) => (isReplace ? mapped : [...prev, ...mapped]));\n },\n [],\n );\n\n // 设置当前会话详情\n const setCurrentSession = async (sessionId: string) => {\n if (sessionId) {\n if (sessionId === currentSessionId) {\n return;\n }\n\n pendingSessionEventsRef.current = null;\n // 切换会话时重置 reChat 删除标记\n reChatRemovedInvocationIdsRef.current = new Set();\n\n // 1. 将当前会话挂起到后台(不中断 SSE 连接)\n const prevSessionId = currentSessionId;\n if (ctrl.current) {\n // 有活跃流式连接,保存到后台\n backgroundRef.current.set(prevSessionId, {\n ctrl: ctrl.current,\n messages: [...messagesRef.current],\n loading: true,\n textMsgRef: textMsgRef.current,\n });\n ctrl.current = null;\n textMsgRef.current = null;\n setLoading(false);\n } else if (messagesRef.current.length > 0) {\n // 无活跃连接但有消息,缓存用于切回\n backgroundRef.current.set(prevSessionId, {\n ctrl: new AbortController(),\n messages: [...messagesRef.current],\n loading: false,\n textMsgRef: null,\n });\n }\n\n // 2. 尝试从后台恢复目标会话\n const bg = backgroundRef.current.get(sessionId);\n if (bg) {\n setMessages(bg.messages);\n messagesRef.current = bg.messages;\n textMsgRef.current = bg.textMsgRef;\n // 仅当 SSE 连接还在运行时才恢复 loading 状态,\n // 避免 SSE 已关闭但 bg 快照中 loading 仍为 true 导致 sender 永久卡住\n const isSseStillActive = bg.loading && !bg.ctrl.signal.aborted;\n setLoading(isSseStillActive);\n ctrl.current = isSseStillActive ? bg.ctrl : null;\n setCurrentSessionId(sessionId);\n setInitialized(true);\n backgroundRef.current.delete(sessionId);\n return;\n }\n\n // 3. 后台没有目标 session,走 API 加载(原有逻辑)\n setInitialized(false);\n setCurrentSessionId(sessionId);\n sessionDetailLoadingRef.current = true;\n try {\n const { data, result } = await fetchSessionDetail({\n url,\n appNo,\n sessionId,\n token: tokenRef.current,\n });\n\n if (result?.code === API_SUCCESS_CODE) {\n setPrologue(appInfo?.onboardingInfo?.prologue || \"\");\n if (Array.isArray(data) && data.length > 0) {\n formatMessages(data, true);\n } else {\n setSuggestedQuestions(\n appInfo?.onboardingInfo?.suggested_questions || [],\n );\n }\n }\n } finally {\n sessionDetailLoadingRef.current = false;\n setInitialized(true);\n }\n } else {\n setCurrentSessionId(v4());\n }\n };\n\n // 获取聊天记录\n const initAppConversations = async (fetchDetail = false) => {\n try {\n setSessionLoading(true);\n\n const {\n data = [],\n pagination,\n result,\n } = await fetchSessionList({\n url,\n appNo,\n token: tokenRef.current,\n pageSize: sessionPagination.pageSize,\n });\n\n if (result?.code === API_SUCCESS_CODE) {\n if (data.length > 0) {\n const formatSessions = data.map((item) => {\n return {\n key: item.sessionId,\n label: item.title || \"新对话\",\n timestamp: new Date(item.startTime).getTime(),\n messages: [],\n meta: {\n ...item,\n },\n };\n });\n\n setSessionList(formatSessions);\n // 设置分页信息\n setSessionPagination({\n pageNum: sessionPagination.pageNum,\n pageSize: sessionPagination.pageSize,\n total: pagination?.total || 0,\n });\n const { sessionId } = data?.[0];\n if (showFirstSession) {\n setCurrentSession(sessionId);\n } else {\n fetchDetail && setPrologue(appInfo?.onboardingInfo?.prologue || \"\");\n fetchDetail &&\n setSuggestedQuestions(\n appInfo?.onboardingInfo?.suggested_questions || [],\n );\n }\n // 成功回调\n if (!initialized) {\n onSuccess?.({\n code: SuccessCode.APP_MESSAGES_INIT_SUCCESS,\n message: \"初始化聊天记录成功\",\n data: {\n sessionId,\n },\n });\n setInitialized(true);\n }\n } else {\n // 无会话记录时,初始化会话详情\n clearChat();\n }\n } else {\n // 服务端业务错误,透传原始 code + message 给接入方自行处理\n onError?.({\n code: result?.code || \"UNKNOWN_ERROR\",\n message: result?.message || \"获取会话列表失败\",\n raw: result,\n });\n setSessionList([]);\n setCurrentSessionId(v4());\n setPrologue(\"\");\n setSuggestedQuestions([]);\n }\n } catch {\n onError?.({\n code: ErrorCode.NETWORK_ERROR,\n message: \"获取会话列表失败\",\n });\n } finally {\n setSessionLoading(false);\n }\n };\n\n // 删除会话\n const deleteSession = async (sessionId: string) => {\n if (!sessionId) return;\n const { result } = await closeSession({\n url,\n appNo,\n sessionId,\n token: tokenRef.current,\n });\n if (result?.code === API_SUCCESS_CODE) {\n // 删除成功后,重新获取会话列表\n initAppConversations(true);\n // 如果删除的是当前会话,则创建新的会话\n if (sessionId === currentSessionId) {\n clearChat();\n }\n } else {\n message.error(\"删除会话失败\");\n }\n };\n\n // 点赞/点踩\n const likeMessage = async (\n invocationId: string,\n isLike: 1 | -1,\n feedbackData?: { feedbackTags?: string; feedbackDescription?: string },\n ) => {\n if (!appNo || !invocationId) return false;\n const { result } = await addFeedback({\n url,\n appNo,\n token: tokenRef.current,\n requestId: invocationId,\n isLike,\n ...feedbackData,\n });\n if (result?.code === API_SUCCESS_CODE) {\n setMessages((prev) =>\n prev.map((m) =>\n m.invocationId === invocationId ? { ...m, isLike } : m,\n ),\n );\n return true;\n }\n return false;\n };\n\n // 更新会话名称\n const updateSession = async (sessionId: string, title: string) => {\n if (!sessionId || !title) return;\n const { result } = await updateSessionTitle({\n url,\n appNo,\n title,\n sessionId,\n token: tokenRef.current,\n });\n if (result?.code === API_SUCCESS_CODE) {\n // 编辑成功后,重新获取会话列表\n initAppConversations();\n } else {\n message.error(\"更新会话失败\");\n }\n };\n\n // 初始化应用\n const initConfig = async () => {\n try {\n setSessionLoading(true);\n const { data, result } = await fetchAppConfig({ url, appNo });\n if (result.code === API_SUCCESS_CODE) {\n setAppInfo(data);\n // 成功回调\n onSuccess?.({\n code: SuccessCode.APP_CONFIG_INIT_SUCCESS,\n message: \"初始化配置成功\",\n });\n } else {\n // 服务端业务错误,透传原始 code + message\n onError?.({\n code: result.code || \"UNKNOWN_ERROR\",\n message: result.message || \"获取应用配置失败\",\n raw: result,\n });\n }\n } catch (error) {\n onError?.({\n code: ErrorCode.NETWORK_ERROR,\n message: \"获取应用配置失败\",\n });\n } finally {\n setSessionLoading(false);\n }\n };\n\n // 初始化—获取配置 (仅在启用时)\n useEffect(() => {\n if (enabled && url && appNo) {\n initConfig();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, url, appNo]);\n\n // 初始化-聊天记录\n useEffect(() => {\n if (appInfo) {\n initAppConversations(true);\n }\n }, [appInfo]);\n\n // 轮询当前会话详情,空闲时补入后端异步任务产生的模型消息。\n useEffect(() => {\n if (\n !enabled ||\n !initialized ||\n !pollSessionEvents ||\n !appNo ||\n !currentSessionId\n )\n return;\n\n let disposed = false;\n let requesting = false;\n const pollingSessionId = currentSessionId;\n\n const poll = async () => {\n if (disposed || requesting || sessionDetailLoadingRef.current) return;\n requesting = true;\n try {\n const { data, result } = await fetchSessionDetail({\n url,\n appNo,\n sessionId: pollingSessionId,\n token: tokenRef.current,\n });\n if (\n !disposed &&\n result?.code === API_SUCCESS_CODE &&\n Array.isArray(data)\n ) {\n syncSessionEvents(data, pollingSessionId);\n }\n } catch {\n // 新会话尚未落库或短暂网络异常时等待下一轮,不打断当前聊天。\n } finally {\n requesting = false;\n }\n };\n\n // 不立即执行首次 poll,避免与 initAppConversations / setCurrentSession / fetchSessionDetail 竞争。首次数据由初始化流程加载,轮询仅负责后续增量同步。\n const timer = window.setInterval(poll, sessionEventsPollingInterval);\n return () => {\n disposed = true;\n window.clearInterval(timer);\n };\n }, [\n appNo,\n currentSessionId,\n enabled,\n initialized,\n pollSessionEvents,\n sessionEventsPollingInterval,\n syncSessionEvents,\n url,\n ]);\n\n // 组件卸载时清理所有连接(前台 + 后台)\n useEffect(() => {\n return () => {\n ctrl.current?.abort();\n backgroundRef.current.forEach((bg) => bg.ctrl?.abort());\n backgroundRef.current.clear();\n };\n }, []);\n\n return {\n appInfo,\n startChat,\n reChat,\n stopChat,\n clearChat,\n suggestChat,\n confirmFnCall,\n initialized,\n currentSessionId,\n sessionList,\n sessionPagination,\n prologue,\n suggestions: suggestedQuestions,\n loading,\n sessionLoading,\n messages: mergedMessages,\n insertSuggestedQuestions,\n insertPrologue,\n deleteSession,\n updateSession,\n setSuggestedQuestions,\n setCurrentSession,\n setMessages,\n storeEvents,\n storeMessage,\n likeMessage,\n setStateDelta: (delta: Record<string, any> | undefined) => {\n stateDeltaRef.current = delta;\n },\n };\n}\n\nexport default useADKChat;\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkE;AAClE,gCAGO;AACP,kBAAwB;AACxB,kBAAmB;AACnB,uBAAoD;AACpD,mBAYO;AACP,iBAQO;AACP,mBAA8B;AAE9B,IAAM,mBAAmB,CAAC,UAAkB;AAC1C,QAAM,SAAiB,CAAC;AACxB,MAAI;AAGJ,aAAW,QAAQ,OAAO;AAExB,UAAM,aAAa,KAAK,QAAQ,CAAC,KAAK;AACtC,QAAI,YAAY;AAEd,UAAI,CAAC,oBAAoB,iBAAiB,YAAY,KAAK,SAAS;AAClE,2BAAmB,EAAE,GAAG,KAAK;AAC7B,eAAO,KAAK,gBAAgB;AAAA,MAC9B,OAAO;AACL,yBAAiB,QACd,iBAAiB,QAAQ,OAAO,KAAK,QAAQ;AAAA,MAClD;AAAA,IACF,OAAO;AACL,yBAAmB;AACnB,aAAO,KAAK,IAAI;AAAA,IAClB;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,0CAA0C;AAKhD,IAAM,sBAAsB,CAC1B,OACA,MACA,OAAuB,UACV;AACb,QAAM,MAAgB;AAAA,IACpB,QAAI,gBAAG;AAAA,IACP,QAAQ,MAAM;AAAA,IACd,cAAc,MAAM;AAAA,IACpB,SAAS,MAAM;AAAA,IACf,WAAW,MAAM;AAAA,IACjB,QAAQ,MAAM,UAAU;AAAA,IACxB;AAAA,IACA,WAAW,MAAM;AAAA,IACjB,eAAe,MAAM;AAAA,IACrB,cAAc,MAAM;AAAA,IACpB,KAAK;AAAA,EACP;AAEA,MAAI,KAAK,YAAY;AACnB,QAAI,aAAa;AAAA,MACf,aAAa,KAAK,WAAW;AAAA,MAC7B,MAAM,KAAK,WAAW;AAAA,MACtB,UAAU,KAAK,WAAW;AAAA,IAC5B;AAAA,EACF,WAAW,KAAK,UAAU;AACxB,QAAI,WAAW,CAAC,KAAK,QAAQ;AAAA,EAC/B,WAAW,KAAK,cAAc;AAC5B,QAAI,eAAe,KAAK;AAAA,EAC1B,WAAW,KAAK,kBAAkB;AAChC,QAAI,mBAAmB,KAAK;AAAA,EAC9B,WAAW,KAAK,gBAAgB;AAC9B,QAAI,iBAAiB,KAAK;AAAA,EAC5B,WAAW,KAAK,qBAAqB;AACnC,QAAI,sBAAsB,KAAK;AAAA,EACjC,WAAW,KAAK,MAAM;AACpB,QAAI,OAAO,KAAK;AAChB,QAAI,UAAU,KAAK;AAAA,EACrB;AAEA,SAAO;AACT;AAEA,IAAM,oBAAoB,CAAC,gBAAuB;AAzGlD;AA0GE,qBAAY,aAAW,iBAAY,QAAZ,mBAAiB;AAAA;AAE1C,IAAM,sBAAsB,CAAC,iBAA6B;AACxD,QAAM,iBAAiB,oBAAI,IAAY;AACvC,MAAI,eAAe;AAEnB,QAAM,mBAAmB,aAAa,OAAO,CAAC,gBAAgB;AAC5D,QAAI,eAAe,IAAI,YAAY,EAAE,GAAG;AACtC,qBAAe;AACf,aAAO;AAAA,IACT;AACA,mBAAe,IAAI,YAAY,EAAE;AACjC,WAAO;AAAA,EACT,CAAC;AAKD,QAAM,gBAAgB,oBAAI,IAGxB;AACF,mBAAiB,QAAQ,CAAC,gBAAgB;AACxC,QACE,YAAY,SAAS,SACrB,CAAC,YAAY,gBACb,OAAO,YAAY,SAAS;AAE5B;AAEF,UAAM,iBAAiB,YAAY,KAAK,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAClE,QAAI,CAAC;AAAgB;AAErB,UAAM,WAAW,YAAY,YAAY,CAAC,GACvC,IAAI,CAAC,SAAS,KAAK,OAAO,EAC1B,KAAK,GAAG;AACX,UAAM,WAAW,GAAG,YAAY,iBAAqB;AAAA,MACnD,YAAY;AAAA,IACd,MAAU;AACV,UAAM,QAAQ,cAAc,IAAI,QAAQ,KAAK,CAAC;AAC9C,UAAM,KAAK,EAAE,aAAa,eAAe,CAAC;AAC1C,kBAAc,IAAI,UAAU,KAAK;AAAA,EACnC,CAAC;AAED,QAAM,sBAAsB,oBAAI,IAAY;AAC5C,gBAAc,QAAQ,CAAC,UAAU;AAC/B,QAAI,MAAM,UAAU;AAAG;AACvB,UAAM,gBAA0B,CAAC;AACjC,KAAC,GAAG,KAAK,EACN,KAAK,CAAC,GAAG,MAAM,EAAE,eAAe,SAAS,EAAE,eAAe,MAAM,EAChE,QAAQ,CAAC,EAAE,aAAa,eAAe,MAAM;AAC5C,UACE,cAAc;AAAA,QAAK,CAAC,iBAClB,aAAa,SAAS,cAAc;AAAA,MACtC,GACA;AACA,4BAAoB,IAAI,YAAY,EAAE;AACtC,uBAAe;AACf;AAAA,MACF;AACA,oBAAc,KAAK,cAAc;AAAA,IACnC,CAAC;AAAA,EACL,CAAC;AAED,SAAO,eACH,iBAAiB;AAAA,IACf,CAAC,gBAAgB,CAAC,oBAAoB,IAAI,YAAY,EAAE;AAAA,EAC1D,IACA;AACN;AAEA,IAAM,qBAAqB,CAAC,kBAAqC;AAC/D,QAAM,SAAqB,CAAC;AAC5B,gBAAc,QAAQ,CAAC,SAAS;AAC9B,QAAI,CAAC,QAAQ,CAAC,KAAK,WAAW,CAAC,MAAM,QAAQ,KAAK,QAAQ,KAAK;AAAG;AAElE,QACE,KAAK,WAAW,UAChB,KAAK,QAAQ,MAAM,KAAK,CAAC,SAAc,KAAK,IAAI;AAEhD;AAEF,QACE,KAAK,QAAQ,SAAS,UACtB,KAAK,QAAQ,MAAM,MAAM,CAAC,SAAc,CAAC,QAAQ,KAAK,gBAAgB;AAEtE;AAEF,UAAM,QACH,KAAK,QAAQ,QAAQ,IAAI,YAAY,MAAM,SAAS,SAAS;AAChE,UAAM,QAAQ,KAAK,QAAQ,MAAM,OAAO,CAAC,SAAc;AACrD,UAAI,CAAC;AAAM,eAAO;AAClB,aAAO;AAAA,QACL,KAAK,QACL,KAAK,cACL,KAAK,gBACL,KAAK,oBACL,KAAK,YACL,KAAK,kBACL,KAAK,uBACL,KAAK;AAAA,MACP;AAAA,IACF,CAAC;AACD,QAAI,MAAM,WAAW;AAAG;AAExB,UAAM,YAAY,MAAM;AAAA,MACtB,CAAC,SAAc,KAAK,QAAQ,KAAK,gBAAgB,KAAK;AAAA,IACxD;AACA,UAAM,gBAAgB,MAAM,OAAO,CAAC,SAAc,KAAK,QAAQ;AAC/D,UAAM,aAAa,MAAM;AAAA,MACvB,CAAC,SACC,CAAC,KAAK,QAAQ,CAAC,KAAK,gBAAgB,CAAC,KAAK,cAAc,CAAC,KAAK;AAAA,IAClE;AAIA,QAAI,cAAc;AAElB,QAAI,UAAU,SAAS,KAAK,cAAc,SAAS,GAAG;AACpD,YAAM,cAAwB;AAAA,QAC5B,IAAI,iBAAiB,KAAK,MAAM;AAAA,QAChC,QAAQ,KAAK;AAAA,QACb,cAAc,KAAK;AAAA,QACnB,SAAS,KAAK;AAAA,QACd,WAAW,KAAK;AAAA,QAChB,QAAQ,KAAK;AAAA,QACb;AAAA,QACA,WAAW,KAAK;AAAA,QAChB,eAAe,KAAK;AAAA,QACpB,cAAc,KAAK;AAAA,QACnB,KAAK;AAAA,MACP;AAEA,gBAAU,QAAQ,CAAC,SAAc;AAC/B,YAAI,KAAK,YAAY;AACnB,sBAAY,aAAa;AAAA,YACvB,aAAa,KAAK,WAAW;AAAA,YAC7B,MAAM,KAAK,WAAW;AAAA,YACtB,UAAU,KAAK,WAAW;AAAA,UAC5B;AAAA,QACF;AACA,YAAI,KAAK,MAAM;AACb,sBAAY,QACT,YAAY,OAAO,GAAG,YAAY;AAAA,IAAW,MAAM,KAAK;AAC3D,cAAI,OAAO,KAAK,YAAY;AAC1B,wBAAY,UAAU,KAAK;AAAA,QAC/B;AACA,YAAI,KAAK,cAAc;AACrB,sBAAY,QACT,YAAY,OAAO,GAAG,YAAY;AAAA,IAAW,MAC9C,KAAK;AAAA,QACT;AAAA,MACF,CAAC;AAED,UAAI,cAAc,SAAS,GAAG;AAC5B,oBAAY,WAAW,cAAc,IAAI,CAAC,UAAe;AAAA,UACvD,aAAa,KAAK,SAAS,eAAe;AAAA,UAC1C,SAAS,KAAK,SAAS;AAAA,UACvB,UAAU,KAAK,SAAS;AAAA,QAC1B,EAAE;AAAA,MACJ;AACA,aAAO,KAAK,WAAW;AAAA,IACzB;AAEA,eAAW,QAAQ,CAAC,SAAc;AAChC,YAAM,cAAwB;AAAA,QAC5B,IAAI,iBAAiB,KAAK,MAAM;AAAA,QAChC,QAAQ,KAAK;AAAA,QACb,cAAc,KAAK;AAAA,QACnB,SAAS,KAAK;AAAA,QACd,WAAW,KAAK;AAAA,QAChB,QAAQ,KAAK;AAAA,QACb;AAAA,QACA,WAAW,KAAK;AAAA,QAChB,eAAe,KAAK;AAAA,QACpB,cAAc,KAAK;AAAA,QACnB,KAAK;AAAA,MACP;AAEA,UAAI,KAAK;AAAc,oBAAY,eAAe,KAAK;AACvD,UAAI,KAAK;AAAgB,oBAAY,iBAAiB,KAAK;AAC3D,UAAI,KAAK;AACP,oBAAY,sBAAsB,KAAK;AACzC,UAAI,KAAK,kBAAkB;AACzB,cAAM,sBAAsB,OAAO;AAAA,UACjC,CAAC,mBAAgB;AAnS3B;AAoSY,yCAAe,iBAAf,mBAA6B,UAAO,UAAK,qBAAL,mBAAuB;AAAA;AAAA,QAC/D;AACA,YAAI,qBAAqB;AACvB,8BAAoB,mBAAmB,KAAK;AAAA,QAC9C;AACA;AAAA,MACF;AACA,aAAO,KAAK,WAAW;AAAA,IACzB,CAAC;AAAA,EACH,CAAC;AACD,SAAO;AACT;AAEA,IAAM,6BAA6B,CACjC,iBACA,eACA,yBACG;AACH,QAAM,mBAAmB,IAAI;AAAA,IAC3B,gBAAgB,IAAI,iBAAiB,EAAE,OAAO,OAAO;AAAA,EACvD;AAIA,MAAI,eAAe,CAAC,GAAG,eAAe;AACtC,QAAM,WAAW,oBAAI,IAAiB;AACtC,gBAAc,QAAQ,CAAC,UAAU;AA9TnC;AA+TI,UAAI,WAAM,YAAN,mBAAe,UAAS,UAAU,CAAC,MAAM,SAAQ,WAAM,YAAN,mBAAe,KAAK;AACvE;AACF,UAAM,QAAQ,MAAM,QAAQ,CAAC,MAAW;AAjU5C,UAAAA;AAkUM,WAAIA,MAAA,EAAE,qBAAF,gBAAAA,IAAoB,IAAI;AAC1B,iBAAS,IAAI,EAAE,iBAAiB,IAAI,EAAE,gBAAgB;AAAA,MACxD;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACD,MAAI,SAAS,OAAO,GAAG;AACrB,QAAI,SAAS;AACb,mBAAe,aAAa,IAAI,CAAC,QAAQ;AACvC,UAAI,IAAI,gBAAgB,CAAC,IAAI,kBAAkB;AAC7C,cAAM,SAAS,IAAI,aAAa;AAChC,YAAI,UAAU,SAAS,IAAI,MAAM,GAAG;AAClC,mBAAS;AACT,iBAAO,EAAE,GAAG,KAAK,kBAAkB,SAAS,IAAI,MAAM,EAAE;AAAA,QAC1D;AAAA,MACF;AACA,aAAO;AAAA,IACT,CAAC;AACD,QAAI,CAAC;AAAQ,qBAAe;AAAA,EAC9B;AAEA,QAAM,gBAAgB,cAAc,OAAO,CAAC,UAAU;AAtVxD;AAuVI,UAAM,SAAQ,WAAM,YAAN,mBAAe;AAC7B,UAAM,YACJ,QAAQ,MAAM,EAAE,OAChB,WAAM,YAAN,mBAAe,UAAS,WACxB,MAAM,QAAQ,KAAK,KACnB,MAAM,SAAS;AACjB,QAAI,CAAC,aAAa,iBAAiB,IAAI,MAAM,EAAE;AAAG,aAAO;AAGzD,QACE,wBACA,qBAAqB,OAAO,KAC5B,MAAM,gBACN,qBAAqB,IAAI,MAAM,YAAY,GAC3C;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT,CAAC;AACD,MAAI,cAAc,WAAW;AAAG,WAAO;AAEvC,QAAM,kBAAkB,mBAAmB,aAAa;AACxD,MAAI,gBAAgB,WAAW;AAAG,WAAO;AAEzC,QAAM,aAAa,IAAI;AAAA,IACrB,cAAc,IAAI,CAAC,OAAO,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC;AAAA,EACvD;AACA,QAAM,kBAAkB,CAAC,gBAA0B;AAnXrD;AAoXI,UAAM,UAAU,kBAAkB,WAAW;AAC7C,QAAI,WAAW,WAAW,IAAI,OAAO;AAAG,aAAO,WAAW,IAAI,OAAO;AAErE,UAAM,YAAY,YAAY,eAAa,iBAAY,QAAZ,mBAAiB;AAC5D,QAAI,cAAc,QAAW;AAC3B,YAAM,iBAAiB,cAAc;AAAA,QACnC,CAAC,WAAW,MAAM,aAAa,KAAK;AAAA,MACtC;AACA,aAAO,iBAAiB,IACpB,cAAc,SAAS,MACvB,iBAAiB;AAAA,IACvB;AACA,WAAO,OAAO;AAAA,EAChB;AAGA,kBAAgB,QAAQ,CAAC,gBAAgB;AACvC,UAAM,cAAc,gBAAgB,WAAW;AAC/C,QAAI,cAAc,aAAa,UAAU,CAAC,mBAAmB;AAC3D,YAAM,eAAe,gBAAgB,cAAc;AACnD,aAAO,OAAO,SAAS,YAAY,KAAK,eAAe;AAAA,IACzD,CAAC;AACD,QAAI,cAAc;AAAG,oBAAc,aAAa;AAChD,iBAAa,OAAO,aAAa,GAAG,WAAW;AAAA,EACjD,CAAC;AACD,SAAO;AACT;AAUA,SAAS,WAAW;AAAA,EAClB,MAAM,OAAO,SAAS;AAAA,EACtB;AAAA,EACA,SAAS,CAAC;AAAA,EACV,MAAM,QAAQ;AAAA,EACd,UAAU;AAAA;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiB;AAnajB;AAoaE,QAAM,CAAC,SAAS,eAAe,QAAI,uBAAS,KAAK;AACjD,QAAM,iBAAa,qBAAO,KAAK;AAC/B,QAAM,iBAAa,0BAAY,CAAC,gBAAyB;AACvD,eAAW,UAAU;AACrB,oBAAgB,WAAW;AAAA,EAC7B,GAAG,CAAC,CAAC;AACL,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,uBAAS,KAAK;AAC1D,QAAM,iBAAa,qBAAO,KAAK;AAC/B,QAAM,WAAO,qBAA+B,IAAI;AAChD,QAAM,eAAW,qBAAO,KAAK;AAC7B,WAAS,UAAU;AAEnB,QAAM,EAAE,OAAO,iBAAiB,IAAI,UAAU,CAAC;AAC/C,QAAM,sBAAoB,sCAAQ,YAAR,mBAAiB,sBAAqB;AAChE,QAAM,+BAA+B,KAAK;AAAA,MACxC,sCAAQ,YAAR,mBAAiB,iCACf;AAAA,IACF;AAAA,EACF;AACA,QAAM,CAAC,SAAS,UAAU,QAAI,uBAA4B,IAAI;AAE9D,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,KAAK;AAEpD,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAwB,CAAC,CAAC;AAEhE,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,uBAAiB,UAAM,gBAAG,CAAC;AAE3E,QAAM,CAAC,mBAAmB,oBAAoB,QAAI,uBAAS;AAAA,IACzD,OAAO;AAAA,IACP,SAAS;AAAA,IACT,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAiB,EAAE;AAEnD,QAAM,CAAC,oBAAoB,qBAAqB,QAAI,uBAAmB,CAAC,CAAC;AACzE,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAqB,CAAC,CAAC;AACvD,QAAM,8BAA0B,qBAGtB,IAAI;AACd,QAAM,8BAA0B,qBAAO,KAAK;AAE5C,QAAM,oBAAgB,qBAAwC,MAAS;AAEvE,QAAM,oCAAgC,qBAAoB,oBAAI,IAAI,CAAC;AAGnE,QAAM,oBAAgB,qBAAuC,oBAAI,IAAI,CAAC;AACtE,QAAM,kBAAc,qBAAmB,QAAQ;AAC/C,cAAY,UAAU;AACtB,QAAM,0BAAsB,qBAAe,gBAAgB;AAC3D,sBAAoB,UAAU;AAE9B,QAAM,qBAAiB,sBAAQ,MAAM;AACnC,UAAM,WAA6C,CAAC;AACpD,UAAM,iBAAiB,oBAAoB,QAAQ;AACnD,mBAAe,QAAQ,CAAC,QAAQ;AA7dpC,UAAAA;AA8dM,UAAI,IAAI,kBAAkB;AACxB,mBAASA,MAAA,2BAAK,qBAAL,gBAAAA,IAAuB,OAAM,EAAE,IAAI,IAAI;AAAA,MAClD;AAAA,IACF,CAAC;AACD,WAAO,eAAe,IAAI,CAAC,QAAQ;AAlevC,UAAAA;AAmeM,UAAI,IAAI,cAAc;AACpB,eAAO;AAAA,UACL,GAAG;AAAA,UACH,kBAAkB,WAASA,MAAA,2BAAK,iBAAL,gBAAAA,IAAmB,OAAM,EAAE;AAAA,QACxD;AAAA,MACF;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,CAAC;AACb,QAAM,iBAAa,qBAAiB,IAAI;AACxC,QAAM,mBAAe,qBAAyB,oBAAI,IAAI,CAAC;AACvD,QAAM,gCAA4B,0BAAY,MAAM;AAClD,UAAM,UAAU,wBAAwB;AAGxC,UAAM,kBAAkB,WAAW,WAAW,WAAW,YAAY;AACrE,QACE,CAAC,WACD,mBACA,QAAQ,cAAc,oBAAoB;AAE1C;AAEF,4BAAwB,UAAU;AAIlC,gBAAY,CAAC,SAAS;AACpB,YAAM,eAAe;AAAA,QACnB;AAAA,QACA,QAAQ;AAAA,QACR,8BAA8B;AAAA,MAChC;AACA,UAAI,iBAAiB;AAAM,eAAO;AAClC,kBAAY,UAAU;AACtB,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,wBAAoB;AAAA,IACxB,CAAC,QAAe,oBAA4B;AAC1C,UAAI,oBAAoB,oBAAoB;AAAS;AACrD,8BAAwB,UAAU;AAAA,QAChC,WAAW;AAAA,QACX;AAAA,MACF;AACA,gCAA0B;AAAA,IAC5B;AAAA,IACA,CAAC,yBAAyB;AAAA,EAC5B;AAEA,8BAAU,MAAM;AACd,4BAAwB,UAAU;AAAA,EACpC,GAAG,CAAC,gBAAgB,CAAC;AAErB,8BAAU,MAAM;AACd,QAAI,CAAC;AAAS,gCAA0B;AAAA,EAC1C,GAAG,CAAC,2BAA2B,OAAO,CAAC;AAGvC,QAAM,oBAAgB,0BAAY,CAAC,QAAkB;AACnD,gBAAY,CAAC,SAAS;AACpB,YAAM,cAAc,KAAK,KAAK,SAAS,CAAC;AACxC,UAAI,2CAAa,WAAW;AAC1B,eAAO,CAAC,GAAG,KAAK,MAAM,GAAG,EAAE,GAAG,KAAK,WAAW;AAAA,MAChD;AACA,aAAO,CAAC,GAAG,MAAM,GAAG;AAAA,IACtB,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAGL,QAAM,+BAA2B;AAAA,IAC/B,CAAC,sBAAgC,CAAC,MAAM;AACtC,UAAI,EAAC,2DAAqB;AAAQ;AAElC;AAAA,QAAsB,CAAC,SACrB,SAAS,WAAW,IAAI,sBAAsB;AAAA,MAChD;AAAA,IACF;AAAA,IACA,CAAC,SAAS,MAAM;AAAA,EAClB;AAGA,QAAM,qBAAiB,0BAAY,CAAC,iBAAyB;AAC3D,QAAI,cAAc;AAChB,kBAAY,YAAY;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,QAAM,oBAAgB,0BAAY,CAAC,QAAkB;AACnD,gBAAY,CAAC,SAAS;AACpB,aAAO,KAAK,IAAI,CAAC,MAAM;AACrB,YAAI,EAAE,OAAO,IAAI,IAAI;AACnB,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,oBAAgB,0BAAY,CAAC,KAAe,UAA2B;AAC3E,WAAO;AAAA,MACL,GAAG;AAAA,MACH,WAAW,MAAM,aAAa,IAAI;AAAA,MAClC,eAAe,MAAM,iBAAiB,IAAI;AAAA,MAC1C,cAAc,MAAM,gBAAgB,IAAI;AAAA,MACxC,KAAK;AAAA,QACH,GAAI,IAAI,OAAO,CAAC;AAAA,QAChB,GAAG;AAAA,MACL;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,6BAAyB;AAAA,IAC7B,CAAC,UAAiB;AAChB,UAAI,CAAC,MAAM,aAAa,CAAC,MAAM,iBAAiB,CAAC,MAAM;AACrD;AAEF,kBAAY,CAAC,SAAS;AACpB,cAAM,OAAO,CAAC,GAAG,IAAI;AACrB,cAAM,QAAQ,KAAK,cAAc,CAAC,QAAQ,IAAI,SAAS,KAAK;AAC5D,YAAI,QAAQ;AAAG,iBAAO;AAEtB,aAAK,KAAK,IAAI,cAAc,KAAK,KAAK,GAAG,KAAK;AAC9C,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAGA,QAAM,kBAAc,0BAAY,CAAC,MAAmB,UAAe;AAvmBrE,QAAAA,KAAAC;AAwmBI,QAAI,QAAQ;AAEZ,QAAI,QAAQ,UAAQD,MAAA,MAAM,YAAN,gBAAAA,IAAe,gBAAe;AAChD,eAAS;AAAA,IACX,WAAW,MAAM;AACf,UAAI,KAAK,MAAM;AACb,iBAAS,QAAQ,KAAK;AAAA,MACxB,WAAW,KAAK,cAAc;AAC5B,iBAAS,gBAAgB,KAAK,aAAa;AAAA,MAC7C,WAAW,KAAK,kBAAkB;AAChC,iBAAS,oBAAoB,KAAK,iBAAiB;AAAA,MACrD,WAAW,KAAK,gBAAgB;AAC9B,iBAAS,mBAAkBC,MAAA,KAAK,eAAe,SAApB,gBAAAA,IAA0B,MAAM,GAAG;AAAA,MAChE,WAAW,KAAK,qBAAqB;AACnC,iBAAS,uBAAuB,KAAK,oBAAoB;AAAA,MAC3D,WAAW,KAAK,cAAc;AAC5B,iBAAS,gBAAgB,KAAK;AAAA,MAChC;AAAA,IACF;AAEA,UAAM,eAAe,EAAE,GAAG,OAAO,MAAM;AAEvC,UAAM,eAAe,IAAI,IAAI,aAAa,OAAO;AACjD,iBAAa,IAAI,MAAM,IAAI,YAAY;AACvC,iBAAa,UAAU;AAAA,EACzB,GAAG,CAAC,CAAC;AAGL,QAAM,mBAAe;AAAA,IACnB,CAAC,MAAmB,OAAc,SAAyB;AAroB/D,UAAAD,KAAAC;AAsoBM,UAAI,CAAC,QAAQ,OAAO,KAAK,IAAI,EAAE,WAAW;AAAG;AAE7C,YAAM,MAAM,oBAAoB,OAAO,MAAM,IAAI;AAGjD,UACE,KAAK,UACLA,OAAAD,MAAA,+BAAO,sBAAP,gBAAAA,IAA0B,qBAA1B,gBAAAC,IAA4C,kBAC5C;AACA,YAAI,kBACF,MAAM,kBAAkB,iBAAiB;AAAA,MAC7C;AAEA,oBAAc,GAAG;AAAA,IACnB;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAGA,QAAM,kBAAc;AAAA,IAClB,CAAC,OAAc,MAAY,SAAkB,UAAU;AA1pB3D,UAAAD,KAAAC;AA2pBM,YAAM,mBACJA,OAAAD,MAAA,MAAM,sBAAN,gBAAAA,IAAyB,qBAAzB,gBAAAC,IAA2C;AAC7C,UAAI,KAAK,MAAM;AACb,YAAI;AAAQ;AACZ,cAAM,WAAW,KAAK;AAEtB,YACE,CAAC,WAAW,WACZ,WAAW,QAAQ,YAAY,KAAK,SACpC;AACA,gBAAM,aAAuB;AAAA,YAC3B,QAAI,gBAAG;AAAA,YACP,QAAQ,MAAM;AAAA,YACd,cAAc,MAAM;AAAA,YACpB,SAAS,MAAM;AAAA,YACf,WAAW,MAAM;AAAA,YACjB,MAAM;AAAA,YACN,MAAM;AAAA,YACN,QAAQ,MAAM,UAAU;AAAA,YACxB,SAAS,KAAK;AAAA,YACd,WAAW,MAAM;AAAA,YACjB,eAAe,MAAM;AAAA,YACrB,cAAc,MAAM;AAAA,YACpB,KAAK;AAAA,UACP;AAEA,cAAI,iBAAiB;AACnB,uBAAW,kBAAkB;AAAA,UAC/B;AAEA,qBAAW,UAAU;AAErB,sBAAY,MAAM,KAAK;AAEvB,wBAAc,UAAU;AAAA,QAC1B,OAAO;AACL,cAAI,iBAAiB;AACnB,uBAAW,UAAU;AAAA,cACnB,GAAG,WAAW;AAAA,cACd;AAAA,YACF;AAAA,UACF;AACA,qBAAW,UAAU;AAAA,YACnB,GAAG,cAAc,WAAW,SAAS,KAAK;AAAA,YAC1C,OAAO,WAAW,QAAQ,QAAQ,MAAM;AAAA,UAC1C;AACA,wBAAc,WAAW,OAAO;AAChC,cAAI,MAAM,YAAY,OAAO;AAC3B,wBAAY,MAAM,KAAK;AACvB,uBAAW,UAAU;AAAA,UACvB;AAAA,QACF;AAAA,MACF,OAAO;AACL,mBAAW,UAAU;AACrB,oBAAY,MAAM,KAAK;AACvB,qBAAa,MAAM,OAAO,KAAK;AAAA,MACjC;AAAA,IACF;AAAA,IACA,CAAC,aAAa,cAAc,eAAe,eAAe,aAAa;AAAA,EACzE;AAGA,QAAM,0BAAsB;AAAA,IAC1B,CAAC,UAAiB;AA1tBtB,UAAAD,KAAAC;AA4tBM,YAAM,SAAOA,OAAAD,MAAA,+BAAO,YAAP,gBAAAA,IAAgB,UAAhB,gBAAAC,IAAwB,OAAM;AAC3C,YAAM,QAAO,6BAAM,SAAQ;AAC3B,kBAAY,MAAM,KAAK;AACvB,UAAI,MAAM;AACR,8BAAsB,CAAC,SAAS,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,MACjD;AAAA,IACF;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAGA,QAAM,0BAAsB;AAAA,IAC1B,CAAC,cAAmB;AAClB,kBAAY,MAAM,SAAS;AAC3B,oBAAc;AAAA,QACZ,QAAI,gBAAG;AAAA,QACP,MAAM,UAAU;AAAA,QAChB,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,IACA,CAAC,aAAa,aAAa;AAAA,EAC7B;AAGA,QAAM,4BAAwB;AAAA,IAC5B,CAAC,UAAe;AACd,UAAI,MAAM,WAAW,MAAM,QAAQ,eAAe;AAChD,oBAAY,MAAM,KAAK;AACvB,qBAAa,MAAM,OAAO,KAAK;AAAA,MACjC;AAAA,IACF;AAAA,IACA,CAAC,aAAa,YAAY;AAAA,EAC5B;AAGA,QAAM,yBAAqB;AAAA,IACzB,CAAC,WAA4B;AAC3B,aAAO,IAAI,QAAc,CAAC,YAAY;AACpC,cAAM,kBAAkB,OAAO,aAAa,oBAAoB;AAGhE,YAAI,oBAAoB,oBAAoB,WAAW,KAAK,SAAS;AACnE,eAAK,QAAQ,MAAM;AAAA,QACrB;AACA,cAAM,UAAU,IAAI,gBAAgB;AACpC,YAAI,oBAAoB,oBAAoB,SAAS;AACnD,qBAAW,IAAI;AACf,eAAK,UAAU;AAAA,QACjB;AAIA,gBAAQ,OAAO;AAAA,UACb;AAAA,UACA,MAAM;AACJ,oBAAQ;AAAA,UACV;AAAA,UACA,EAAE,MAAM,KAAK;AAAA,QACf;AAEA,cAAM,aAAa,GAAG,2CAA2C;AAGjE,YAAI,YAA6B;AAEjC,wDAAiB,YAAY;AAAA,UAC3B,QAAQ;AAAA,UACR,QAAQ,QAAQ;AAAA,UAChB,MAAM,KAAK,UAAU,MAAM;AAAA,UAC3B,gBAAgB;AAAA,UAChB,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,iBAAiB;AAAA,YACjB,QAAQ;AAAA,YACR,eAAe,UAAU,SAAS;AAAA,UACpC;AAAA,UACA,MAAM,OAAO,UAAU;AACrB,gBACE,SAAS,MACT,SAAS,QAAQ,IAAI,cAAc,MAAM,kDACzC;AAAA,YAEF,WAAW,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AAC7D,yBAAW,KAAK;AAChB,iDAAU;AAAA,gBACR,MAAM,uBAAU;AAAA,gBAChB,SACE,SAAS,WAAW,MAChB,sBACA;AAAA,cACR;AACA,sBAAQ;AAAA,YACV,WACE,SAAS,UAAU,OACnB,SAAS,SAAS,OAClB,SAAS,WAAW,KACpB;AACA,sBAAQ;AAAA,YACV,OAAO;AACL,sBAAQ;AAAA,YACV;AAAA,UACF;AAAA,UACA,WAAW,CAAC,UAAU;AACpB,kBAAM,cAAU,4BAAc,MAAM,MAAM,CAAC,CAAC;AAG5C,gBAAI,YAAmB;AACvB,gBAAI,QAAQ,QAAQ,QAAQ,QAAQ;AAElC,0BAAY;AAAA,gBACV,GAAG,QAAQ;AAAA,gBACX,SAAS,QAAQ;AAAA,gBACjB,cAAc,QAAQ,OAAO;AAAA,gBAC7B,WAAW,QAAQ,OAAO;AAAA,gBAC1B,IACE,QAAQ,KAAK,MACb,QAAQ,OAAO,MACf,QAAQ,OAAO,WACf,QAAQ,OAAO;AAAA,cACnB;AAAA,YACF;AAEA,gBAAI,UAAU,OAAO;AACnB,kCAAQ,QAAQ,UAAU,KAAK;AAC/B;AAAA,YACF;AAGA,kBAAM,eACJ,oBAAoB,YAAY;AAElC,gBAAI,cAAc;AAEhB,oBAAM,KAAK,cAAc,QAAQ,IAAI,eAAe;AACpD,kBAAI,CAAC;AAAI;AAET,kBAAI,UAAU,SAAS;AACrB,oBAAI,UAAU,QAAQ,SAAS;AAAY;AAC3C,2BAAW,QAAQ,iBAAiB,UAAU,QAAQ,KAAK,GAAG;AAC5D,wBAAM,aAAa,KAAK,QAAQ,CAAC,KAAK;AACtC,sBAAI,YAAY;AACd,yBAAI,uCAAW,aAAY;AAAO;AAClC,0BAAM,WAAW,KAAK,QAAQ;AAC9B,wBAAI,CAAC,cAAa,uCAAW,aAAY,KAAK,SAAS;AACrD,4BAAM,aAAuB;AAAA,wBAC3B,QAAI,gBAAG;AAAA,wBACP,QAAQ,UAAU;AAAA,wBAClB,cAAc,UAAU;AAAA,wBACxB,SAAS,UAAU;AAAA,wBACnB,WAAW,UAAU;AAAA,wBACrB,MAAM;AAAA,wBACN,MAAM;AAAA,wBACN,SAAS,KAAK;AAAA,sBAChB;AACA,kCAAY;AACZ,yBAAG,WAAW,CAAC,GAAG,GAAG,UAAU,UAAU;AAAA,oBAC3C,OAAO;AACL,kCAAY;AAAA,wBACV,GAAG;AAAA,wBACH,OAAO,UAAU,QAAQ,MAAM;AAAA,sBACjC;AACA,yBAAG,WAAW,GAAG,SAAS;AAAA,wBAAI,CAAC,MAC7B,EAAE,OAAO,UAAW,KAAK,YAAa;AAAA,sBACxC;AACA,0BAAI,UAAU,iBAAiB,QAAQ;AACrC,oCAAY;AAAA,sBACd;AAAA,oBACF;AAAA,kBACF,OAAO;AACL,gCAAY;AACZ,uBAAG,WAAW;AAAA,sBACZ,GAAG,GAAG;AAAA,sBACN,oBAAoB,WAAW,IAAI;AAAA,oBACrC;AAAA,kBACF;AAAA,gBACF;AAAA,cACF,WAAW,UAAU,cAAc;AACjC,mBAAG,WAAW;AAAA,kBACZ,GAAG,GAAG;AAAA,kBACN,EAAE,QAAI,gBAAG,GAAG,MAAM,UAAU,cAAc,MAAM,MAAM;AAAA,gBACxD;AAAA,cACF;AACA,iBAAG,aAAa;AAChB;AAAA,YACF;AAGA,iDAAW;AACX,mCAAuB,SAAS;AAChC,gBAAI,UAAU,SAAS;AAErB,kBAAI,UAAU,QAAQ,SAAS,YAAY;AACzC,oCAAoB,SAAS;AAC7B;AAAA,cACF;AAEA,yBAAW,QAAQ,iBAAiB,UAAU,QAAQ,KAAK,GAAG;AAE5D,4BAAY,WAAW,OAAM,uCAAW,aAAY,KAAK;AAAA,cAC3D;AAAA,YACF,WAAW,UAAU,cAAc;AACjC,kCAAoB,SAAS;AAAA,YAC/B,WAAW,UAAU,SAAS;AAC5B,oCAAsB,SAAS;AAAA,YACjC;AAAA,UACF;AAAA,UACA,SAAS,MAAM;AA16BzB,gBAAAD;AA26BY,kBAAM,eACJ,oBAAoB,YAAY;AAClC,gBAAI,cAAc;AAChB,oBAAM,KAAK,cAAc,QAAQ,IAAI,eAAe;AACpD,kBAAI,IAAI;AACN,mBAAG,UAAU;AACb,mBAAG,aAAa;AAAA,cAClB;AAGA,kBACE,CAAC,cAAc,QAAQ,IAAI,eAAe,KAC1C,oBAAoB,YAAY,iBAChC;AACA,2BAAW,KAAK;AAChB,2BAAW,UAAU;AAAA,cACvB;AAAA,YACF,OAAO;AACL,yBAAW,KAAK;AAChB,kBAAI,WAAW,SAAS;AACtB,yDAAYA,MAAA,WAAW,YAAX,gBAAAA,IAAoB,SAAQ,IAAI,WAAW;AAAA,cACzD;AACA,yBAAW,UAAU;AACrB,mBAAK,UAAU;AAAA,YACjB;AACA,oBAAQ;AAAA,UACV;AAAA,UACA,SAAS,CAAC,UAAU;AAClB,kBAAM,eACJ,oBAAoB,YAAY;AAClC,gBAAI,cAAc;AAChB,oBAAM,KAAK,cAAc,QAAQ,IAAI,eAAe;AACpD,kBAAI;AAAI,mBAAG,UAAU;AAErB,kBACE,CAAC,cAAc,QAAQ,IAAI,eAAe,KAC1C,oBAAoB,YAAY,iBAChC;AACA,2BAAW,KAAK;AAChB,qBAAK,UAAU;AAAA,cACjB;AAAA,YACF,OAAO;AACL,yBAAW,KAAK;AAChB,mBAAK,UAAU;AAAA,YACjB;AACA,oBAAQ;AACR,oBAAQ,MAAM,uBAAuB,KAAK;AAC1C,kBAAM;AAAA,UACR;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,YAAY,OAAO;AAAA,IACvB,OAAO;AAAA,IACP,QAAQ,CAAC;AAAA,IACT;AAAA,EACF,MAAmB;AACjB,QAAI,WAAW,WAAW,WAAW;AAAS;AAC9C,QAAI,CAAC,KAAK,KAAK,KAAK,EAAC,+BAAO,WAAU,CAAC;AAAkB;AACzD,eAAW,UAAU;AAErB,0BAAsB,CAAC,CAAC;AAExB,kCAA8B,UAAU,oBAAI,IAAI;AAEhD,gBAAY,CAAC,SAAS;AACpB,UAAI,OAAO,CAAC,GAAG,IAAI;AAEnB,UAAI,KAAK,KAAK,GAAG;AACf,aAAK,KAAK;AAAA,UACR,QAAI,gBAAG;AAAA,UACP,MAAM;AAAA,UACN;AAAA,QACF,CAAC;AAAA,MACH;AAEA,UAAI,MAAM,SAAS,GAAG;AACpB,aAAK,KAAK;AAAA,UACR,QAAI,gBAAG;AAAA,UACP,MAAM;AAAA,UACN,UAAU,MAAM,IAAI,CAAC,SAAM;AApgCrC,gBAAAA,KAAAC,KAAA;AAogCyC;AAAA,cAC7B,aAAa,KAAK,YAAY,KAAK;AAAA,cACnC,UAAU,KAAK,cAAYD,MAAA,KAAK,aAAL,gBAAAA,IAAe;AAAA,cAC1C,SACE,KAAK,aAAWC,MAAA,KAAK,aAAL,gBAAAA,IAAe,cAAW,UAAK,aAAL,mBAAe;AAAA,YAC7D;AAAA,WAAE;AAAA,QACJ,CAAC;AAAA,MACH;AAEA,UAAI,kBAAkB;AACpB,aAAK,KAAK;AAAA,UACR,QAAI,gBAAG;AAAA,UACP,MAAM;AAAA,UACN;AAAA,QACF,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT,CAAC;AACD,QAAI;AACF,YAAM,mBAAmB;AAAA,QACvB,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,SAAS;AAAA,UACP,MAAM;AAAA,UACN,OAAO,mBAAmB,CAAC,EAAE,iBAAiB,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC;AAAA,QAC9D;AAAA,QACA,OAAO,MAAM,IAAI,CAAC,SAAM;AA9hChC,cAAAD,KAAAC,KAAA;AA8hCoC;AAAA,YAC1B,UAAU,KAAK,cAAYD,MAAA,KAAK,aAAL,gBAAAA,IAAe;AAAA,YAC1C,QAAQ,KAAK,YAAUC,MAAA,KAAK,aAAL,gBAAAA,IAAe;AAAA,YACtC,SACE,KAAK,aAAW,UAAK,aAAL,mBAAe,cAAW,UAAK,aAAL,mBAAe;AAAA,YAC3D,MAAM,KAAK,UAAQ,UAAK,aAAL,mBAAe;AAAA,YAClC,UAAU,KAAK,cAAY,UAAK,aAAL,mBAAe;AAAA,UAC5C;AAAA,SAAE;AAAA,QACF,GAAI,cAAc,YAAY,UAAa;AAAA,UACzC,YAAY,cAAc;AAAA,QAC5B;AAAA,MACF,CAAC;AAAA,IACH,UAAE;AACA,iBAAW,UAAU;AAAA,IACvB;AAEA,yBAAqB;AAAA,EACvB;AAGA,QAAM,SAAS,YAAY;AACzB,QAAI,WAAW,WAAW,WAAW;AAAS;AAC9C,QAAI,SAAS,WAAW;AAAG;AAC3B,eAAW,UAAU;AAErB,0BAAsB,CAAC,CAAC;AAGxB,UAAM,gBAAgB,SAAS;AAAA,MAC7B,CAAC,QAAQ,IAAI,SAAS,UAAU,CAAC,IAAI;AAAA,IACvC;AACA,QAAI,kBAAkB,IAAI;AACxB,iBAAW,UAAU;AACrB;AAAA,IACF;AAEA,UAAM,cAAc,SAAS,MAAM,GAAG,gBAAgB,CAAC;AACvD,gBAAY,WAAW;AAGvB,UAAM,uBAAuB,oBAAI,IAAY;AAC7C,aAAS,IAAI,gBAAgB,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxD,YAAM,MAAM,SAAS,CAAC;AACtB,UAAI,IAAI;AAAc,6BAAqB,IAAI,IAAI,YAAY;AAAA,IACjE;AACA,kCAA8B,UAAU;AAExC,UAAM,kBAAkB,YAAY,aAAa;AACjD,UAAM,EAAE,OAAO,IAAI,WAAW,CAAC,EAAE,IAAI;AAErC,QAAI;AACF,YAAM,mBAAmB;AAAA,QACvB,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,SAAS;AAAA,UACP,MAAM;AAAA,UACN,OAAO,CAAC,EAAE,KAAK,CAAC;AAAA,QAClB;AAAA,QACA,OAAO,qCAAU,IAAI,CAAC,UAAU;AAAA,UAC9B,UAAU,KAAK;AAAA,UACf,SAAS,KAAK;AAAA,UACd,UAAU,KAAK;AAAA,QACjB;AAAA,QACA,GAAI,cAAc,YAAY,UAAa;AAAA,UACzC,YAAY,cAAc;AAAA,QAC5B;AAAA,MACF,CAAC;AAAA,IACH,UAAE;AACA,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF;AAGA,QAAM,gBAAgB,CAAC,QAAsB,cAAuB;AAvmCtE,QAAAD;AAwmCI,UAAM,qBAAmBA,MAAA,yCAAY,2BAAZ,gBAAAA,IAAA;AAAA;AAAA,MACvB;AAAA,MACA;AAAA,UACG;AAAA,MACH,IAAI,OAAO;AAAA,MACX,MAAM,OAAO;AAAA,MACb,UAAU,EAAE,UAAU;AAAA,IACxB;AACA,cAAU,EAAE,iBAAiB,CAAC;AAAA,EAChC;AAGA,QAAM,cAAc,CAAC,SAAiB;AACpC,QAAI,WAAW;AAAS;AACxB,QAAI,CAAC,KAAK,KAAK;AAAG;AAClB,0BAAsB,CAAC,CAAC;AACxB,cAAU,EAAE,KAAK,CAAC;AAAA,EACpB;AAGA,QAAM,eAAW,0BAAY,MAAM;AA5nCrC,QAAAA;AA6nCI,4BAAwB,UAAU;AAClC,KAAAA,MAAA,KAAK,YAAL,gBAAAA,IAAc;AACd,SAAK,UAAU;AACf,eAAW,KAAK;AAChB,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,UAAU,CAAC;AAGf,QAAM,YAAY,MAAM;AAroC1B,QAAAA,KAAAC;AAsoCI,UAAM,mBAAe,gBAAG;AACxB,wBAAoB,YAAY;AAEhC,kCAA8B,UAAU,oBAAI,IAAI;AAEhD,aAAS;AACT,kBAAYD,MAAA,mCAAS,mBAAT,gBAAAA,IAAyB,aAAY,EAAE;AACnD,gBAAY,CAAC,CAAC;AACd,4BAAsBC,MAAA,mCAAS,mBAAT,gBAAAA,IAAyB,wBAAuB,CAAC,CAAC;AAAA,EAC1E;AAGA,QAAM,qBAAiB;AAAA,IACrB,CAAC,eAAsB,YAAY,UAAU;AAC3C,YAAM,SAAS,mBAAmB,aAAa;AAC/C,kBAAY,CAAC,SAAU,YAAY,SAAS,CAAC,GAAG,MAAM,GAAG,MAAM,CAAE;AAAA,IACnE;AAAA,IACA,CAAC;AAAA,EACH;AAGA,QAAM,oBAAoB,OAAO,cAAsB;AA3pCzD,QAAAD,KAAAC;AA4pCI,QAAI,WAAW;AACb,UAAI,cAAc,kBAAkB;AAClC;AAAA,MACF;AAEA,8BAAwB,UAAU;AAElC,oCAA8B,UAAU,oBAAI,IAAI;AAGhD,YAAM,gBAAgB;AACtB,UAAI,KAAK,SAAS;AAEhB,sBAAc,QAAQ,IAAI,eAAe;AAAA,UACvC,MAAM,KAAK;AAAA,UACX,UAAU,CAAC,GAAG,YAAY,OAAO;AAAA,UACjC,SAAS;AAAA,UACT,YAAY,WAAW;AAAA,QACzB,CAAC;AACD,aAAK,UAAU;AACf,mBAAW,UAAU;AACrB,mBAAW,KAAK;AAAA,MAClB,WAAW,YAAY,QAAQ,SAAS,GAAG;AAEzC,sBAAc,QAAQ,IAAI,eAAe;AAAA,UACvC,MAAM,IAAI,gBAAgB;AAAA,UAC1B,UAAU,CAAC,GAAG,YAAY,OAAO;AAAA,UACjC,SAAS;AAAA,UACT,YAAY;AAAA,QACd,CAAC;AAAA,MACH;AAGA,YAAM,KAAK,cAAc,QAAQ,IAAI,SAAS;AAC9C,UAAI,IAAI;AACN,oBAAY,GAAG,QAAQ;AACvB,oBAAY,UAAU,GAAG;AACzB,mBAAW,UAAU,GAAG;AAGxB,cAAM,mBAAmB,GAAG,WAAW,CAAC,GAAG,KAAK,OAAO;AACvD,mBAAW,gBAAgB;AAC3B,aAAK,UAAU,mBAAmB,GAAG,OAAO;AAC5C,4BAAoB,SAAS;AAC7B,uBAAe,IAAI;AACnB,sBAAc,QAAQ,OAAO,SAAS;AACtC;AAAA,MACF;AAGA,qBAAe,KAAK;AACpB,0BAAoB,SAAS;AAC7B,8BAAwB,UAAU;AAClC,UAAI;AACF,cAAM,EAAE,MAAM,OAAO,IAAI,UAAM,+BAAmB;AAAA,UAChD;AAAA,UACA;AAAA,UACA;AAAA,UACA,OAAO,SAAS;AAAA,QAClB,CAAC;AAED,aAAI,iCAAQ,UAAS,mCAAkB;AACrC,wBAAYD,MAAA,mCAAS,mBAAT,gBAAAA,IAAyB,aAAY,EAAE;AACnD,cAAI,MAAM,QAAQ,IAAI,KAAK,KAAK,SAAS,GAAG;AAC1C,2BAAe,MAAM,IAAI;AAAA,UAC3B,OAAO;AACL;AAAA,gBACEC,MAAA,mCAAS,mBAAT,gBAAAA,IAAyB,wBAAuB,CAAC;AAAA,YACnD;AAAA,UACF;AAAA,QACF;AAAA,MACF,UAAE;AACA,gCAAwB,UAAU;AAClC,uBAAe,IAAI;AAAA,MACrB;AAAA,IACF,OAAO;AACL,8BAAoB,gBAAG,CAAC;AAAA,IAC1B;AAAA,EACF;AAGA,QAAM,uBAAuB,OAAO,cAAc,UAAU;AA7uC9D,QAAAD,KAAAC;AA8uCI,QAAI;AACF,wBAAkB,IAAI;AAEtB,YAAM;AAAA,QACJ,OAAO,CAAC;AAAA,QACR;AAAA,QACA;AAAA,MACF,IAAI,UAAM,6BAAiB;AAAA,QACzB;AAAA,QACA;AAAA,QACA,OAAO,SAAS;AAAA,QAChB,UAAU,kBAAkB;AAAA,MAC9B,CAAC;AAED,WAAI,iCAAQ,UAAS,mCAAkB;AACrC,YAAI,KAAK,SAAS,GAAG;AACnB,gBAAM,iBAAiB,KAAK,IAAI,CAAC,SAAS;AACxC,mBAAO;AAAA,cACL,KAAK,KAAK;AAAA,cACV,OAAO,KAAK,SAAS;AAAA,cACrB,WAAW,IAAI,KAAK,KAAK,SAAS,EAAE,QAAQ;AAAA,cAC5C,UAAU,CAAC;AAAA,cACX,MAAM;AAAA,gBACJ,GAAG;AAAA,cACL;AAAA,YACF;AAAA,UACF,CAAC;AAED,yBAAe,cAAc;AAE7B,+BAAqB;AAAA,YACnB,SAAS,kBAAkB;AAAA,YAC3B,UAAU,kBAAkB;AAAA,YAC5B,QAAO,yCAAY,UAAS;AAAA,UAC9B,CAAC;AACD,gBAAM,EAAE,UAAU,IAAI,6BAAO;AAC7B,cAAI,kBAAkB;AACpB,8BAAkB,SAAS;AAAA,UAC7B,OAAO;AACL,2BAAe,cAAYD,MAAA,mCAAS,mBAAT,gBAAAA,IAAyB,aAAY,EAAE;AAClE,2BACE;AAAA,gBACEC,MAAA,mCAAS,mBAAT,gBAAAA,IAAyB,wBAAuB,CAAC;AAAA,YACnD;AAAA,UACJ;AAEA,cAAI,CAAC,aAAa;AAChB,mDAAY;AAAA,cACV,MAAM,yBAAY;AAAA,cAClB,SAAS;AAAA,cACT,MAAM;AAAA,gBACJ;AAAA,cACF;AAAA,YACF;AACA,2BAAe,IAAI;AAAA,UACrB;AAAA,QACF,OAAO;AAEL,oBAAU;AAAA,QACZ;AAAA,MACF,OAAO;AAEL,2CAAU;AAAA,UACR,OAAM,iCAAQ,SAAQ;AAAA,UACtB,UAAS,iCAAQ,YAAW;AAAA,UAC5B,KAAK;AAAA,QACP;AACA,uBAAe,CAAC,CAAC;AACjB,gCAAoB,gBAAG,CAAC;AACxB,oBAAY,EAAE;AACd,8BAAsB,CAAC,CAAC;AAAA,MAC1B;AAAA,IACF,QAAE;AACA,yCAAU;AAAA,QACR,MAAM,uBAAU;AAAA,QAChB,SAAS;AAAA,MACX;AAAA,IACF,UAAE;AACA,wBAAkB,KAAK;AAAA,IACzB;AAAA,EACF;AAGA,QAAM,gBAAgB,OAAO,cAAsB;AACjD,QAAI,CAAC;AAAW;AAChB,UAAM,EAAE,OAAO,IAAI,UAAM,yBAAa;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,SAAS;AAAA,IAClB,CAAC;AACD,SAAI,iCAAQ,UAAS,mCAAkB;AAErC,2BAAqB,IAAI;AAEzB,UAAI,cAAc,kBAAkB;AAClC,kBAAU;AAAA,MACZ;AAAA,IACF,OAAO;AACL,0BAAQ,MAAM,QAAQ;AAAA,IACxB;AAAA,EACF;AAGA,QAAM,cAAc,OAClB,cACA,QACA,iBACG;AACH,QAAI,CAAC,SAAS,CAAC;AAAc,aAAO;AACpC,UAAM,EAAE,OAAO,IAAI,UAAM,wBAAY;AAAA,MACnC;AAAA,MACA;AAAA,MACA,OAAO,SAAS;AAAA,MAChB,WAAW;AAAA,MACX;AAAA,MACA,GAAG;AAAA,IACL,CAAC;AACD,SAAI,iCAAQ,UAAS,mCAAkB;AACrC;AAAA,QAAY,CAAC,SACX,KAAK;AAAA,UAAI,CAAC,MACR,EAAE,iBAAiB,eAAe,EAAE,GAAG,GAAG,OAAO,IAAI;AAAA,QACvD;AAAA,MACF;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAGA,QAAM,gBAAgB,OAAO,WAAmB,UAAkB;AAChE,QAAI,CAAC,aAAa,CAAC;AAAO;AAC1B,UAAM,EAAE,OAAO,IAAI,UAAM,+BAAmB;AAAA,MAC1C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,SAAS;AAAA,IAClB,CAAC;AACD,SAAI,iCAAQ,UAAS,mCAAkB;AAErC,2BAAqB;AAAA,IACvB,OAAO;AACL,0BAAQ,MAAM,QAAQ;AAAA,IACxB;AAAA,EACF;AAGA,QAAM,aAAa,YAAY;AAC7B,QAAI;AACF,wBAAkB,IAAI;AACtB,YAAM,EAAE,MAAM,OAAO,IAAI,UAAM,2BAAe,EAAE,KAAK,MAAM,CAAC;AAC5D,UAAI,OAAO,SAAS,mCAAkB;AACpC,mBAAW,IAAI;AAEf,+CAAY;AAAA,UACV,MAAM,yBAAY;AAAA,UAClB,SAAS;AAAA,QACX;AAAA,MACF,OAAO;AAEL,2CAAU;AAAA,UACR,MAAM,OAAO,QAAQ;AAAA,UACrB,SAAS,OAAO,WAAW;AAAA,UAC3B,KAAK;AAAA,QACP;AAAA,MACF;AAAA,IACF,SAAS,OAAP;AACA,yCAAU;AAAA,QACR,MAAM,uBAAU;AAAA,QAChB,SAAS;AAAA,MACX;AAAA,IACF,UAAE;AACA,wBAAkB,KAAK;AAAA,IACzB;AAAA,EACF;AAGA,8BAAU,MAAM;AACd,QAAI,WAAW,OAAO,OAAO;AAC3B,iBAAW;AAAA,IACb;AAAA,EAEF,GAAG,CAAC,SAAS,KAAK,KAAK,CAAC;AAGxB,8BAAU,MAAM;AACd,QAAI,SAAS;AACX,2BAAqB,IAAI;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAGZ,8BAAU,MAAM;AACd,QACE,CAAC,WACD,CAAC,eACD,CAAC,qBACD,CAAC,SACD,CAAC;AAED;AAEF,QAAI,WAAW;AACf,QAAI,aAAa;AACjB,UAAM,mBAAmB;AAEzB,UAAM,OAAO,YAAY;AACvB,UAAI,YAAY,cAAc,wBAAwB;AAAS;AAC/D,mBAAa;AACb,UAAI;AACF,cAAM,EAAE,MAAM,OAAO,IAAI,UAAM,+BAAmB;AAAA,UAChD;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,OAAO,SAAS;AAAA,QAClB,CAAC;AACD,YACE,CAAC,aACD,iCAAQ,UAAS,qCACjB,MAAM,QAAQ,IAAI,GAClB;AACA,4BAAkB,MAAM,gBAAgB;AAAA,QAC1C;AAAA,MACF,QAAE;AAAA,MAEF,UAAE;AACA,qBAAa;AAAA,MACf;AAAA,IACF;AAGA,UAAM,QAAQ,OAAO,YAAY,MAAM,4BAA4B;AACnE,WAAO,MAAM;AACX,iBAAW;AACX,aAAO,cAAc,KAAK;AAAA,IAC5B;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAGD,8BAAU,MAAM;AACd,WAAO,MAAM;AAx+CjB,UAAAD;AAy+CM,OAAAA,MAAA,KAAK,YAAL,gBAAAA,IAAc;AACd,oBAAc,QAAQ,QAAQ,CAAC,OAAI;AA1+CzC,YAAAA;AA0+C4C,gBAAAA,MAAA,GAAG,SAAH,gBAAAA,IAAS;AAAA,OAAO;AACtD,oBAAc,QAAQ,MAAM;AAAA,IAC9B;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe,CAAC,UAA2C;AACzD,oBAAc,UAAU;AAAA,IAC1B;AAAA,EACF;AACF;AAEA,IAAO,qBAAQ;",
|
|
6
6
|
"names": ["_a", "_b"]
|
|
7
7
|
}
|
|
@@ -102,17 +102,18 @@ var deduplicateMessages = function deduplicateMessages(messageItems) {
|
|
|
102
102
|
return true;
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
//
|
|
105
|
+
// 机器人文本消息去重:同一 invocationId + 思考类型的文本消息,
|
|
106
|
+
// 如果文本内容存在包含关系,保留最长的(sessionDetails 完整消息),去掉被包含的短文本(SSE 流式增量)。
|
|
107
|
+
// 使用 invocationId 分组,同一轮对话的 invocationId 始终一致, SSE 后续 chunk 的 首个id 与 sessionDetails 的 id 相同,其余不同,
|
|
106
108
|
var botTextGroups = new Map();
|
|
107
109
|
uniqueIdMessages.forEach(function (messageItem) {
|
|
108
|
-
|
|
109
|
-
if (messageItem.role !== "bot" || !eventId || typeof messageItem.text !== "string") return;
|
|
110
|
+
if (messageItem.role !== "bot" || !messageItem.invocationId || typeof messageItem.text !== "string") return;
|
|
110
111
|
var normalizedText = messageItem.text.replace(/\s+/g, " ").trim();
|
|
111
112
|
if (!normalizedText) return;
|
|
112
113
|
var fileKey = (messageItem.fileData || []).map(function (file) {
|
|
113
114
|
return file.fileUri;
|
|
114
115
|
}).join("|");
|
|
115
|
-
var groupKey = "".concat(
|
|
116
|
+
var groupKey = "".concat(messageItem.invocationId, "\0").concat(Boolean(messageItem.thought), "\0").concat(fileKey);
|
|
116
117
|
var group = botTextGroups.get(groupKey) || [];
|
|
117
118
|
group.push({
|
|
118
119
|
messageItem: messageItem,
|
|
@@ -122,6 +123,7 @@ var deduplicateMessages = function deduplicateMessages(messageItems) {
|
|
|
122
123
|
});
|
|
123
124
|
var redundantMessageIds = new Set();
|
|
124
125
|
botTextGroups.forEach(function (group) {
|
|
126
|
+
if (group.length <= 1) return;
|
|
125
127
|
var completeTexts = [];
|
|
126
128
|
_toConsumableArray(group).sort(function (a, b) {
|
|
127
129
|
return b.normalizedText.length - a.normalizedText.length;
|