@yumiai/chat-widget 0.1.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ChatWidget.tsx","../src/types.ts","../src/hooks/useMessageAggregator.ts","../src/hooks/useSSE.ts","../src/components/PinnedArea.tsx","../src/components/PlanCard.tsx","../src/components/TodoCard.tsx","../src/components/RoundHeader.tsx","../src/components/MessageContent.tsx","../src/components/SchemaFormRenderer.tsx","../src/components/ToolCardBuffering.tsx","../src/components/renderers/utils.tsx","../src/components/renderers/ContentRenderer.tsx","../src/components/renderers/CommandRenderer.tsx","../src/components/renderers/BrowserRenderer.tsx","../src/components/renderers/QueryRenderer.tsx","../src/components/renderers/PathRenderer.tsx","../src/components/renderers/TriggerRenderer.tsx","../src/components/renderers/ThinkingRenderer.tsx","../src/components/renderers/ParamsRenderer.tsx","../src/components/renderers/ToolResultRenderer.tsx","../src/components/ChildAgentCard.tsx","../src/errors.ts","../src/adapters/DefaultJetAgentsAdapter.ts"],"sourcesContent":["/**\n * ChatWidget 主组件\n * \n * 严格按照设计文档实现:\n * - SSE 消息流处理\n * - 动态置顶(滚动切换,带防抖和滞后阈值)\n * - 多轮对话展示\n * - 平滑过渡动画(淡入淡出)\n * - 子 Agent 卡片\n * - Human-in-the-loop 支持\n */\n\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { \n ChatWidgetProps, \n Round, \n Artifact,\n SSEMessage,\n ChatWidgetAPI,\n AggregatedMessage,\n MessageContentType,\n NotificationTurn,\n ResourceContent,\n UiConfig,\n ExecutionStatus,\n} from './types'\nimport { DEFAULT_CONFIG, mergeConsecutiveThinkMessages } from './types'\nimport { useMessageAggregator } from './hooks/useMessageAggregator'\nimport { useSSE } from './hooks/useSSE'\nimport { PinnedArea, RoundHeader, MessageContent, ChildAgentCard } from './components'\nimport './ChatWidget.css'\n\n// 平滑过渡参数(来自设计文档 5.1.5)\nconst HYSTERESIS_THRESHOLD = 30 // 滞后阈值 30px\nconst DEBOUNCE_DELAY = 150 // 防抖延迟 150ms\nconst FADE_DURATION = 150 // 淡入淡出时长 150ms\n\n/** 将 notification_turns 列表转换为 ChatWidget 的 Round[]\n *\n * notification_turns 的字段与 SSE Notification.to_json() 完全对齐,\n * 因此可以直接映射到前端的 AggregatedMessage。\n */\nfunction convertTurnsToRounds(turns: NotificationTurn[]): Round[] {\n // 按 interaction_id 分组\n const groups = new Map<string, NotificationTurn[]>()\n for (const t of turns) {\n const iid = t.interaction_id\n if (!groups.has(iid)) groups.set(iid, [])\n groups.get(iid)!.push(t)\n }\n\n const rounds: Round[] = []\n let roundIdx = 0\n\n for (const [interactionId, group] of groups) {\n // 找 user_input turn 作为该轮的用户消息\n const userTurn = group.find(t => t.type === 'user_input')\n const userText = userTurn\n ? (userTurn.contents || []).map(c => c.content || '').join('')\n : '(历史消息)'\n\n // 非 user_input 的 turns 转成 AggregatedMessage\n const agentMessages: AggregatedMessage[] = []\n for (const turn of group) {\n if (turn.type === 'user_input') continue\n\n const contents = turn.contents || []\n if (contents.length === 0 && !turn.type.startsWith('mcp_')) continue\n\n const ext = turn.ext || {}\n\n // 每个 content part 生成一条 AggregatedMessage\n if (contents.length > 0) {\n for (let i = 0; i < contents.length; i++) {\n const part = contents[i]\n const partType = part.type || 'text'\n // 映射 content part type 到 ChatWidget 的 MessageContentType\n let contentType: MessageContentType = 'text'\n if (partType === 'think') contentType = 'think'\n else if (partType === 'plan') contentType = 'plan'\n else if (partType === 'artifact') contentType = 'artifact'\n else if (partType === 'json_schema') contentType = 'json_schema'\n else if (partType === 'html_schema') contentType = 'html_schema'\n\n agentMessages.push({\n id: `hist-${turn.turn_id}-${i}`,\n agentInstanceId: turn.agent_instance_id || 0,\n callBatchId: String(turn.call_batch_id || 0),\n parentCallBatchId: turn.parent_call_batch_id != null ? String(turn.parent_call_batch_id) : undefined,\n level: turn.level ?? 0,\n agentName: turn.card_title || turn.agent_id || 'Assistant',\n notificationType: turn.type as any,\n toolName: ext.tool_name as string | undefined,\n toolCallId: ext.tool_call_id as string | undefined,\n toolStatus: ext.status as 'success' | 'error' | undefined,\n taskPurpose: (ext.task_purpose || ext._task_purpose) as string | undefined,\n uiConfig: ext.ui_config as UiConfig | undefined,\n parentToolCallId: ext.parent_tool_call_id as string | undefined,\n contentType,\n contentChunks: [part.content || ''],\n timestamp: String(turn.timestamp || ''),\n toolPhase: turn.type.startsWith('mcp_') ? 'complete' : undefined,\n })\n }\n } else {\n // mcp_start / mcp_end 等无内容的 turn\n agentMessages.push({\n id: `hist-${turn.turn_id}`,\n agentInstanceId: turn.agent_instance_id || 0,\n callBatchId: String(turn.call_batch_id || 0),\n parentCallBatchId: turn.parent_call_batch_id != null ? String(turn.parent_call_batch_id) : undefined,\n level: turn.level ?? 0,\n agentName: turn.card_title || turn.agent_id || 'Assistant',\n notificationType: turn.type as any,\n toolName: ext.tool_name as string | undefined,\n toolCallId: ext.tool_call_id as string | undefined,\n toolStatus: ext.status as 'success' | 'error' | undefined,\n taskPurpose: (ext.task_purpose || ext._task_purpose) as string | undefined,\n uiConfig: ext.ui_config as UiConfig | undefined,\n parentToolCallId: ext.parent_tool_call_id as string | undefined,\n contentType: 'text',\n contentChunks: [],\n timestamp: String(turn.timestamp || ''),\n toolPhase: 'complete',\n })\n }\n }\n\n roundIdx++\n const ts = group[0]?.timestamp_start || group[0]?.timestamp\n rounds.push({\n interactionId,\n index: roundIdx,\n userMessage: userText,\n timestamp: ts ? new Date(ts).toISOString() : new Date().toISOString(),\n status: 'completed',\n messages: agentMessages,\n })\n }\n return rounds\n}\n\nconst ChatWidget: React.FC<ChatWidgetProps> = ({\n adapter,\n sessionId: propSessionId,\n initialMessages: _initialMessages,\n config: userConfig,\n renderHeaderExtra,\n renderFooter,\n onArtifactClick,\n onHITLSubmit: _onHITLSubmit,\n onStatusChange,\n onError,\n onReady,\n className,\n style,\n height = 600,\n}) => {\n // 合并配置\n const config = useMemo(() => ({\n ...DEFAULT_CONFIG,\n ...userConfig,\n }), [userConfig])\n\n // 消息聚合 Hook\n const { \n state: aggregatorState,\n todoMap,\n processMessage, \n getRoundsList,\n startNewRound,\n loadRounds,\n finalizeRound,\n } = useMessageAggregator()\n\n // 组件状态\n const [pinnedInteractionId, setPinnedInteractionId] = useState<string | null>(null)\n const [isTransitioning, setIsTransitioning] = useState(false)\n const [executionStatus, setExecutionStatus] = useState<'idle' | 'running' | 'compressing' | 'completed' | 'error'>('idle')\n const [currentSessionId, setCurrentSessionId] = useState<number | null>(null)\n \n // Session Title 状态\n const [sessionTitle, setSessionTitle] = useState<string>('') // 完整的 session title\n const [displayedTitle, setDisplayedTitle] = useState<string>('') // 打字机效果显示的部分\n const [isTitleAnimating, setIsTitleAnimating] = useState(false) // 是否正在打字机动画\n const sessionTitleFetchedRef = useRef<boolean>(false) // 是否已尝试获取过 title\n\n // Agent 实例复用:追踪 agentId → level0 agent_instance_id 映射\n // 实例与记忆绑定,相同 agent_id 的后续请求应复用实例以保持上下文\n const agentInstanceMapRef = useRef<Map<string, number>>(new Map())\n const currentAgentIdRef = useRef<string>('agent-666')\n const historyLoadedRef = useRef<boolean>(false)\n\n // 外部传入 sessionId 时:设置 currentSessionId 并尝试加载历史消息\n useEffect(() => {\n if (!propSessionId) return\n const numericId = typeof propSessionId === 'string' ? parseInt(propSessionId, 10) : propSessionId\n if (isNaN(numericId)) return\n\n setCurrentSessionId(numericId)\n\n if (historyLoadedRef.current) return\n historyLoadedRef.current = true\n\n const loadHistory = async () => {\n try {\n console.log('[ChatWidget] Loading session history for:', numericId)\n const [turns, detail] = await Promise.all([\n adapter.getSessionHistory(numericId),\n adapter.getSessionDetail(numericId).catch(() => null),\n ])\n if (detail?.session_title) {\n setSessionTitle(detail.session_title)\n sessionTitleFetchedRef.current = true\n }\n if (!turns || turns.length === 0) return\n\n // 从历史 turns 中恢复 agent_instance_id 映射,\n // 确保恢复会话后的第一条消息能复用正确的 agent 实例\n for (const t of turns) {\n if ((t.level === 0 || t.level == null) && t.agent_instance_id && t.agent_id) {\n agentInstanceMapRef.current.set(t.agent_id, t.agent_instance_id)\n }\n }\n if (agentInstanceMapRef.current.size > 0) {\n console.log('[ChatWidget] Restored agent instance map from history:', Object.fromEntries(agentInstanceMapRef.current))\n }\n\n const rounds = convertTurnsToRounds(turns)\n if (rounds.length > 0) {\n loadRounds(rounds)\n setExecutionStatus('completed')\n setPinnedInteractionId(rounds[rounds.length - 1].interactionId)\n }\n console.log('[ChatWidget] Loaded', rounds.length, 'history rounds from', turns.length, 'turns')\n } catch (err) {\n console.warn('[ChatWidget] Failed to load session history:', err)\n }\n }\n loadHistory()\n }, [propSessionId, loadRounds])\n\n // 处理 SSE 消息\n const handleSSEMessage = useCallback((message: SSEMessage & { type?: string; session_id?: number; notification_type?: string }) => {\n // 处理会话信息消息(只更新 session_id,不创建新轮次)\n if (message.type === 'session_info' && message.session_id) {\n setCurrentSessionId(message.session_id)\n // 重置 title 获取状态,新 session 需要重新获取\n sessionTitleFetchedRef.current = false\n // 注意:不在这里调用 startNewRound,轮次已在 sendMessage 中创建\n return\n }\n \n // 处理 session_title 通知消息 - 不当作普通消息处理,而是更新标题栏\n if (message.notification_type === 'session_title' && message.content) {\n console.log('[ChatWidget] Received session_title:', message.content)\n setSessionTitle(message.content)\n sessionTitleFetchedRef.current = true // 标记已收到 title\n return // 不传递给消息聚合器\n }\n \n // JETP-021: 压缩通知 → 更新状态,不创建消息\n const msgType = message.type || message.notification_type\n if (msgType === 'compression_started') {\n setExecutionStatus('compressing')\n return\n }\n if (msgType === 'compression_completed') {\n setExecutionStatus('running')\n return\n }\n\n // 处理结束消息\n if (message.type === 'finish') {\n // 收尾:将当前轮次中未完成的工具卡片强制标记为 complete\n // 防止 JetAgents 漏发 mcp_end 导致 UI 永远停留在\"生成中/执行中\"\n const iid = message.interaction_id || aggregatorState.currentInteractionId\n if (iid) {\n finalizeRound(iid)\n }\n setExecutionStatus('completed')\n return\n }\n \n // 处理错误消息\n if (message.type === 'error') {\n setExecutionStatus('error')\n onError?.(new Error(message.content || 'Unknown error'))\n return\n }\n \n // 常规消息,交给聚合器处理\n if (message.interaction_id && message.content_type) {\n // 捕获 level 0 的 agent_instance_id,用于后续请求复用实例\n // 实例与记忆绑定,复用可保持 agent 的上下文连续性\n if (message.level === 0 && message.agent_instance_id) {\n const prevId = agentInstanceMapRef.current.get(currentAgentIdRef.current)\n if (prevId !== message.agent_instance_id) {\n agentInstanceMapRef.current.set(currentAgentIdRef.current, message.agent_instance_id)\n console.log('[ChatWidget] Captured level-0 agent instance:', currentAgentIdRef.current, '→', message.agent_instance_id)\n }\n }\n processMessage(message as SSEMessage)\n }\n }, [processMessage, onError, finalizeRound, aggregatorState.currentInteractionId])\n\n // SSE 连接 Hook — auth delegated to adapter\n const { status: connectionStatus, connect, disconnect: _disconnect } = useSSE({\n adapter,\n onMessage: handleSSEMessage,\n onError,\n })\n\n // 需要清屏滚动的 interactionId\n const [pendingScrollInteractionId, setPendingScrollInteractionId] = useState<string | null>(null)\n\n // 发送消息方法(可通过 ref 暴露给父组件)\n const sendMessage = useCallback((message: string, agentId: string = 'agent-666') => {\n // 生成新的 interaction_id\n const interactionId = crypto.randomUUID()\n \n console.log('====== [sendMessage v2] 发送新消息 ======', { interactionId, message })\n \n // 更新当前 agent_id(用于 SSE 消息回来时捕获对应的 instance_id)\n currentAgentIdRef.current = agentId\n \n // 重置 session title 状态(新对话轮次)\n // 注:如果是同一个 session 的多轮对话,title 可能保持不变\n // 但如果是新 session,会重置\n sessionTitleFetchedRef.current = false\n \n // 先添加用户消息到新轮次\n startNewRound(interactionId, message)\n \n // 立即切换置顶到新轮次(设计文档:新轮次开始时自动切换置顶)\n console.log('[sendMessage] 切换置顶到:', interactionId)\n setPinnedInteractionId(interactionId)\n \n // 重置用户滚动状态为底部\n isUserAtBottomRef.current = true\n \n // 标记需要清屏滚动(等待 DOM 更新后执行)\n setPendingScrollInteractionId(interactionId)\n \n // 更新状态为运行中\n setExecutionStatus('running')\n \n // 查找已知的 level-0 agent 实例 ID(实例绑定记忆,复用以保持上下文)\n const knownInstanceId = agentInstanceMapRef.current.get(agentId)\n if (knownInstanceId) {\n console.log('[sendMessage] 复用 agent 实例:', agentId, '→', knownInstanceId)\n }\n \n // 连接 SSE 并发送消息\n connect(adapter.getStreamUrl(), {\n message,\n agent_id: agentId,\n agent_instance_id: knownInstanceId,\n session_id: currentSessionId,\n interaction_id: interactionId,\n })\n }, [adapter, currentSessionId, startNewRound, connect])\n\n // Refs\n const messageListRef = useRef<HTMLDivElement>(null)\n const scrollDebounceTimer = useRef<number | null>(null)\n const lastScrollTop = useRef(0)\n const isUserAtBottomRef = useRef(true) // 用户是否在底部附近\n const isProgrammaticScrollRef = useRef(false) // 是否正在执行程序控制的滚动(禁止动态置顶)\n const clearScreenScrollTopRef = useRef<number | null>(null) // 清屏滚动后的初始 scrollTop\n\n // 获取轮次列表\n const rounds = useMemo(() => getRoundsList(), [getRoundsList, aggregatorState])\n\n // 获取当前轮次的辅助方法(必须在 rounds 声明之后)\n const getCurrentRound = useCallback((): Round | null => {\n if (rounds.length === 0) return null\n return rounds[rounds.length - 1]\n }, [rounds])\n\n // 当前置顶的轮次\n const pinnedRound = useMemo(() => {\n if (!pinnedInteractionId && rounds.length > 0) {\n return rounds[rounds.length - 1]\n }\n return rounds.find(r => r.interactionId === pinnedInteractionId) || null\n }, [rounds, pinnedInteractionId])\n\n // 计算当前应该置顶的轮次\n // 规则:如果分隔线\"↑ 上一轮对话 ↑\"出现在可视区域,则置顶到上一轮\n const calculatePinnedRound = useCallback((): string | null => {\n if (!messageListRef.current || rounds.length === 0) {\n return rounds[rounds.length - 1]?.interactionId || null\n }\n\n const listRect = messageListRef.current.getBoundingClientRect()\n const viewportTop = listRect.top\n \n // 从最后一轮向前遍历,找到第一个\"分隔线可见\"的轮次\n // 如果分隔线可见,说明上一轮应该被置顶\n for (let i = rounds.length - 1; i >= 0; i--) {\n const round = rounds[i]\n const container = messageListRef.current.querySelector(\n `[data-interaction-id=\"${round.interactionId}\"]`\n ) as HTMLElement\n \n if (!container) continue\n \n const rect = container.getBoundingClientRect()\n \n // 如果轮次容器的顶部在可视区域内或以上,这一轮应该被置顶\n // 加一点容差(50px),避免在边界处频繁切换\n if (rect.top <= viewportTop + 50) {\n return round.interactionId\n }\n \n // 如果是非首轮,检查其上方的分隔线是否可见\n if (i > 0) {\n // 分隔线在轮次容器上方,如果轮次顶部接近可视区域顶部,\n // 说明分隔线可能已经可见,应该切换到上一轮\n if (rect.top <= viewportTop + 100) {\n // 分隔线可见,返回上一轮\n return rounds[i - 1].interactionId\n }\n }\n }\n\n // 默认返回第一轮\n return rounds[0]?.interactionId || null\n }, [rounds])\n\n // 更新置顶区域(带淡入淡出动画)\n const updatePinnedArea = useCallback((interactionId: string | null) => {\n if (isTransitioning || interactionId === pinnedInteractionId) return\n \n setIsTransitioning(true)\n\n // 淡出后更新内容(150ms)\n setTimeout(() => {\n setPinnedInteractionId(interactionId)\n \n // 淡入后解除锁定(150ms)\n setTimeout(() => {\n setIsTransitioning(false)\n }, FADE_DURATION)\n }, FADE_DURATION)\n }, [isTransitioning, pinnedInteractionId])\n\n // 滚动处理(带防抖和滞后阈值)\n const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {\n const target = e.currentTarget\n const currentScrollTop = target.scrollTop\n const scrollDelta = Math.abs(currentScrollTop - lastScrollTop.current)\n\n // 程序控制滚动期间,不更新状态,直接返回\n if (isProgrammaticScrollRef.current) {\n lastScrollTop.current = currentScrollTop\n return\n }\n\n // 判断用户是否在底部附近(距离底部 50px 以内)\n const scrollBottom = target.scrollHeight - target.scrollTop - target.clientHeight\n isUserAtBottomRef.current = scrollBottom < 50\n \n // 如果用户滚动到底部附近,清除清屏模式,恢复自动滚动\n if (scrollBottom < 50 && clearScreenScrollTopRef.current !== null) {\n clearScreenScrollTopRef.current = null\n }\n\n // 清除之前的防抖定时器\n if (scrollDebounceTimer.current) {\n clearTimeout(scrollDebounceTimer.current)\n }\n\n const newPinnedRound = calculatePinnedRound()\n\n // 过渡期间不处理\n if (isTransitioning) {\n lastScrollTop.current = currentScrollTop\n return\n }\n\n if (newPinnedRound !== pinnedInteractionId) {\n if (scrollDelta >= HYSTERESIS_THRESHOLD) {\n // 显著滚动(超过滞后阈值):立即切换\n updatePinnedArea(newPinnedRound)\n lastScrollTop.current = currentScrollTop\n } else {\n // 小幅滚动:防抖后切换\n scrollDebounceTimer.current = window.setTimeout(() => {\n if (!isTransitioning && !isProgrammaticScrollRef.current) {\n const confirmedRound = calculatePinnedRound()\n if (confirmedRound !== pinnedInteractionId) {\n updatePinnedArea(confirmedRound)\n }\n }\n lastScrollTop.current = target.scrollTop\n }, DEBOUNCE_DELAY)\n }\n } else {\n lastScrollTop.current = currentScrollTop\n }\n }, [calculatePinnedRound, updatePinnedArea, isTransitioning, pinnedInteractionId])\n\n // 按层级组织消息(用于渲染子 Agent)\n // 判断规则:parentCallBatchId 为有效正值 → 子消息;否则 → 根消息\n // 分组键:优先用 parentToolCallId(精准绑定到具体 call_agent 工具调用),\n // 回退到 parentCallBatchId(兼容无 parentToolCallId 的场景)\n const organizeMessagesByLevel = useCallback((messages: Round['messages']) => {\n const rootMessages: Round['messages'] = []\n const childrenMap = new Map<string, Round['messages']>()\n\n const isChildMessage = (msg: Round['messages'][0]) => {\n const pcb = msg.parentCallBatchId\n if (pcb == null || pcb === '' || pcb === '-1') return false\n const pcbNum = Number(pcb)\n if (pcbNum <= 0 || isNaN(pcbNum)) return false\n return true\n }\n\n messages.forEach(msg => {\n if (isChildMessage(msg)) {\n // 优先用 parentToolCallId 作为分组键(精准绑定),回退到 parentCallBatchId\n const key = msg.parentToolCallId || String(msg.parentCallBatchId)\n const children = childrenMap.get(key) || []\n children.push(msg)\n childrenMap.set(key, children)\n } else {\n rootMessages.push(msg)\n }\n })\n\n return { rootMessages, childrenMap }\n }, [])\n\n // 文件内容查看器状态\n const [viewerOpen, setViewerOpen] = useState(false)\n const [viewerLoading, setViewerLoading] = useState(false)\n const [viewerContent, setViewerContent] = useState<ResourceContent | null>(null)\n const [viewerError, setViewerError] = useState<string | null>(null)\n const [viewerArtifact, setViewerArtifact] = useState<Artifact | null>(null)\n\n // 处理产出物点击 — 打开内容查看器\n const handleArtifactClick = useCallback((artifact: Artifact) => {\n onArtifactClick?.(artifact)\n\n if (!currentSessionId) return\n\n setViewerArtifact(artifact)\n setViewerOpen(true)\n setViewerLoading(true)\n setViewerContent(null)\n setViewerError(null)\n\n adapter.getResourceContent(currentSessionId, artifact.id)\n .then(data => {\n setViewerContent(data)\n setViewerLoading(false)\n })\n .catch(err => {\n console.error('[ChatWidget] Failed to fetch resource content:', err)\n setViewerError(err?.message || '无法获取文件内容')\n setViewerLoading(false)\n })\n }, [onArtifactClick, currentSessionId])\n\n // 渲染单个轮次的消息\n const renderRoundMessages = useCallback((round: Round) => {\n const { rootMessages: rawRootMessages, childrenMap } = organizeMessagesByLevel(round.messages)\n const rootMessages = mergeConsecutiveThinkMessages(rawRootMessages)\n const elements: React.ReactNode[] = []\n\n // 跟踪已渲染的子 agent,避免重复(以 childrenMap key 为单位)\n const renderedChildKeys = new Set<string>()\n\n // 判断某条根消息是否是 call_agent 工具卡片\n const isCallAgentToolCard = (msg: Round['messages'][0]) => {\n if (!msg.toolPhase) return false\n const name = (msg.toolName || '').toLowerCase()\n return name.includes('call_agent') || name.includes('callagent')\n }\n\n rootMessages.forEach((msg) => {\n if (isCallAgentToolCard(msg)) {\n // 精准绑定:优先用 toolCallId 匹配 childrenMap(子消息按 parentToolCallId 分组)\n // 回退到 callBatchId(兼容无 parentToolCallId 的旧数据)\n const childKey = msg.toolCallId && childrenMap.has(msg.toolCallId)\n ? msg.toolCallId\n : childrenMap.has(String(msg.callBatchId))\n ? String(msg.callBatchId)\n : null\n\n if (childKey && !renderedChildKeys.has(childKey)) {\n renderedChildKeys.add(childKey)\n const children = childrenMap.get(childKey)!\n // 按 agentInstanceId 分组子消息\n const childGroups = new Map<number, Round['messages']>()\n children.forEach(child => {\n const group = childGroups.get(child.agentInstanceId) || []\n group.push(child)\n childGroups.set(child.agentInstanceId, group)\n })\n childGroups.forEach((groupChildren, agentInstanceId) => {\n const firstChild = groupChildren[0]\n elements.push(\n <ChildAgentCard\n key={`child-${childKey}-${agentInstanceId}`}\n message={firstChild}\n children={groupChildren.slice(1)}\n maxHeight={config.childAgentMaxHeight}\n config={config}\n onArtifactClick={handleArtifactClick}\n defaultExpanded={true}\n parentTaskPurpose={msg.taskPurpose}\n />\n )\n })\n return\n }\n }\n\n // 普通消息:正常渲染为 MessageContent\n elements.push(\n <MessageContent\n key={msg.id}\n message={msg}\n enableTypewriter={config.enableTypewriter}\n typewriterSpeed={config.typewriterSpeed}\n onArtifactClick={handleArtifactClick}\n />\n )\n })\n\n return elements\n }, [organizeMessagesByLevel, config, handleArtifactClick])\n\n // 初始化:设置默认置顶轮次\n useEffect(() => {\n if (rounds.length > 0 && !pinnedInteractionId) {\n setPinnedInteractionId(rounds[rounds.length - 1].interactionId)\n }\n }, [rounds, pinnedInteractionId])\n\n // 容器高度(用于清屏垫片)\n const [containerHeight, setContainerHeight] = useState(0)\n // 各轮次内容高度(用于动态计算垫片高度)\n const [roundHeights, setRoundHeights] = useState<Map<string, number>>(new Map())\n\n // 监听容器高度变化\n useEffect(() => {\n if (!messageListRef.current) return\n \n const updateHeight = () => {\n if (messageListRef.current) {\n setContainerHeight(messageListRef.current.clientHeight)\n }\n }\n \n updateHeight()\n \n // 监听窗口大小变化\n window.addEventListener('resize', updateHeight)\n return () => window.removeEventListener('resize', updateHeight)\n }, [])\n\n // 监听各轮次容器高度变化\n useEffect(() => {\n if (!messageListRef.current) return\n \n const roundContainers = messageListRef.current.querySelectorAll('.round-container')\n if (roundContainers.length === 0) return\n \n const resizeObserver = new ResizeObserver((entries) => {\n const newHeights = new Map(roundHeights)\n let changed = false\n \n entries.forEach((entry) => {\n const interactionId = (entry.target as HTMLElement).dataset.interactionId\n if (interactionId) {\n const height = entry.contentRect.height\n if (newHeights.get(interactionId) !== height) {\n newHeights.set(interactionId, height)\n changed = true\n }\n }\n })\n \n if (changed) {\n setRoundHeights(newHeights)\n }\n })\n \n roundContainers.forEach((container) => {\n resizeObserver.observe(container)\n })\n \n return () => resizeObserver.disconnect()\n }, [rounds.length]) // 当轮次数量变化时重新设置观察器\n\n // 计算动态垫片高度:容器高度 - 对应轮次内容高度\n const getSpacerHeight = useCallback((interactionId: string): number => {\n const roundHeight = roundHeights.get(interactionId) || 0\n // 垫片高度 = 容器高度 - 轮次内容高度,最小为 0\n return Math.max(0, containerHeight - roundHeight)\n }, [containerHeight, roundHeights])\n\n // 用 ref 追踪已处理的清屏滚动,避免重复执行\n const processedScrollRef = useRef<string | null>(null)\n \n // 清屏滚动:新轮次开始时滚动到新轮次的顶部\n useEffect(() => {\n if (!pendingScrollInteractionId || !messageListRef.current) return\n \n // 如果已经处理过这个 interactionId,不再重复执行\n if (processedScrollRef.current === pendingScrollInteractionId) return\n \n const roundExists = rounds.some(r => r.interactionId === pendingScrollInteractionId)\n if (!roundExists) return\n \n const targetInteractionId = pendingScrollInteractionId\n \n // 立即用 ref 标记已处理,防止重复执行\n processedScrollRef.current = targetInteractionId\n \n // 异步清除 state(用于下次新轮次)\n setPendingScrollInteractionId(null)\n \n // 标记程序控制的滚动和清屏模式\n isProgrammaticScrollRef.current = true\n clearScreenScrollTopRef.current = 0 // 先设一个值表示清屏模式\n \n // 滚动到新轮次的顶部\n const scrollToRoundTop = () => {\n if (!messageListRef.current) return\n \n const container = messageListRef.current\n const roundElement = container.querySelector(\n `[data-interaction-id=\"${targetInteractionId}\"]`\n ) as HTMLElement\n \n if (roundElement) {\n // 直接使用 offsetTop,这是元素相对于 offsetParent 的位置\n // 减去容器的 padding,再加 20px 确保分隔线完全不可见\n const targetScrollTop = roundElement.offsetTop - 16 + 20\n \n container.scrollTop = Math.max(0, targetScrollTop)\n // 更新清屏后的实际 scrollTop\n clearScreenScrollTopRef.current = container.scrollTop\n }\n }\n \n // 执行滚动\n requestAnimationFrame(scrollToRoundTop)\n \n // 解除程序控制锁定\n setTimeout(() => {\n isProgrammaticScrollRef.current = false\n }, 200)\n }, [rounds, pendingScrollInteractionId])\n\n // 新消息时自动滚动\n useEffect(() => {\n // 程序控制滚动期间(如清屏滚动),不执行自动滚动\n if (isProgrammaticScrollRef.current) return\n if (!messageListRef.current || (executionStatus !== 'running' && executionStatus !== 'compressing')) return\n \n requestAnimationFrame(() => {\n if (!messageListRef.current || isProgrammaticScrollRef.current) return\n \n const container = messageListRef.current\n const maxScrollTop = container.scrollHeight - container.clientHeight\n const currentScrollTop = container.scrollTop\n \n // 清屏模式:追踪当前轮次内容增长,只在内容超出可视区域时滚动\n if (clearScreenScrollTopRef.current !== null) {\n // 获取所有轮次容器,取最后一个\n const roundContainers = container.querySelectorAll('.round-container')\n const currentRoundElement = roundContainers[roundContainers.length - 1] as HTMLElement\n \n if (currentRoundElement) {\n // 计算当前轮次内容底部相对于容器顶部的位置\n const roundBottom = currentRoundElement.offsetTop + currentRoundElement.offsetHeight\n // 可视区域底部 = scrollTop + clientHeight\n const visibleBottom = currentScrollTop + container.clientHeight\n \n // 只有当轮次内容底部超出可视区域时才滚动\n if (roundBottom > visibleBottom) {\n // 滚动到让轮次底部刚好可见\n const targetScrollTop = roundBottom - container.clientHeight\n // 但不能小于清屏时的位置(避免向上滚动露出分隔线)\n const finalScrollTop = Math.max(targetScrollTop, clearScreenScrollTopRef.current)\n container.scrollTop = finalScrollTop\n }\n }\n return\n }\n \n // 正常模式:用户在底部附近时自动滚动\n if (isUserAtBottomRef.current) {\n container.scrollTop = maxScrollTop\n }\n })\n }, [aggregatorState, executionStatus])\n\n const scrollToBottom = useCallback(() => {\n if (!messageListRef.current) return\n messageListRef.current.scrollTop = messageListRef.current.scrollHeight\n }, [])\n\n const getStatus = useCallback((): ExecutionStatus => executionStatus, [executionStatus])\n\n const widgetAPI = useMemo<ChatWidgetAPI>(() => ({\n sendMessage,\n getCurrentRound,\n getAllRounds: getRoundsList,\n scrollToBottom,\n getStatus,\n }), [sendMessage, getCurrentRound, getRoundsList, scrollToBottom, getStatus])\n\n // 暴露 API 给父组件\n useEffect(() => {\n onReady?.(widgetAPI)\n }, [onReady, widgetAPI])\n\n // 状态变化回调\n useEffect(() => {\n onStatusChange?.(executionStatus)\n }, [executionStatus, onStatusChange])\n\n // Session Title 打字机效果\n useEffect(() => {\n if (!sessionTitle) {\n setDisplayedTitle('')\n setIsTitleAnimating(false)\n return\n }\n \n // 如果新 title 和当前显示不同,启动打字机动画\n if (sessionTitle !== displayedTitle) {\n setIsTitleAnimating(true)\n let currentIndex = 0\n \n const animateTitle = () => {\n if (currentIndex <= sessionTitle.length) {\n setDisplayedTitle(sessionTitle.slice(0, currentIndex))\n currentIndex++\n requestAnimationFrame(() => {\n setTimeout(animateTitle, 50) // 50ms 每字符\n })\n } else {\n setIsTitleAnimating(false)\n }\n }\n \n // 从头开始打字机效果\n setDisplayedTitle('')\n requestAnimationFrame(animateTitle)\n }\n }, [sessionTitle])\n\n // 从后端获取 session title\n const fetchSessionTitle = useCallback(async (sessionId: number) => {\n if (sessionTitleFetchedRef.current) return // 已有 title,不重复获取\n \n try {\n console.log('[ChatWidget] Fetching session title for session:', sessionId)\n const detail = await adapter.getSessionDetail(sessionId)\n if (detail.session_title) {\n console.log('[ChatWidget] Fetched session title:', detail.session_title)\n setSessionTitle(detail.session_title)\n sessionTitleFetchedRef.current = true\n }\n } catch (error) {\n console.warn('[ChatWidget] Failed to fetch session title:', error)\n }\n }, [])\n\n // 时机1: 用户完成输入后,如果有 session_id 且没有 title,尝试获取\n // 时机2: level0 的 agent 停止运行且 title 为空时,获取一次\n useEffect(() => {\n // 当执行完成且没有 title 时,尝试获取\n if (executionStatus === 'completed' && currentSessionId && !sessionTitle && !sessionTitleFetchedRef.current) {\n // 延迟一点获取,确保后端有时间生成 title\n const timer = setTimeout(() => {\n fetchSessionTitle(currentSessionId)\n }, 500)\n return () => clearTimeout(timer)\n }\n }, [executionStatus, currentSessionId, sessionTitle, fetchSessionTitle])\n\n // 连接状态变化\n useEffect(() => {\n if (connectionStatus === 'connected') {\n setExecutionStatus('running')\n } else if (connectionStatus === 'disconnected') {\n setExecutionStatus('completed')\n } else if (connectionStatus === 'error') {\n setExecutionStatus('error')\n }\n }, [connectionStatus])\n\n // 清理定时器\n useEffect(() => {\n return () => {\n if (scrollDebounceTimer.current) {\n clearTimeout(scrollDebounceTimer.current)\n }\n }\n }, [])\n\n // 获取状态显示\n const getStatusDisplay = () => {\n if (executionStatus === 'compressing') {\n return { icon: '🗜️', text: '上下文压缩中...' }\n }\n switch (connectionStatus) {\n case 'connecting':\n return { icon: '⏳', text: '连接中...' }\n case 'connected':\n return { icon: '⏳', text: '执行中...' }\n case 'error':\n return { icon: '✗', text: '连接错误' }\n default:\n return { icon: '○', text: '待命' }\n }\n }\n\n const statusDisplay = getStatusDisplay()\n\n return (\n <div \n className={`chat-widget ${config.theme} ${className || ''}`}\n style={{ ...style, height }}\n >\n {/* 头部 */}\n <div className=\"chat-header\">\n <div className=\"chat-header-title\">\n <span className=\"header-icon\">🤖</span>\n <span>AI 助手</span>\n </div>\n \n {/* Session Title - 居中显示,打字机效果 */}\n {displayedTitle && (\n <div className={`session-title ${isTitleAnimating ? 'animating' : ''}`}>\n <span className=\"session-title-text\">{displayedTitle}</span>\n {isTitleAnimating && <span className=\"title-cursor\">|</span>}\n </div>\n )}\n \n <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n {currentSessionId != null && renderHeaderExtra?.(currentSessionId)}\n <div className={`status-badge status-${connectionStatus}`}>\n <span className=\"status-icon\">{statusDisplay.icon}</span>\n <span>{statusDisplay.text}</span>\n </div>\n </div>\n </div>\n\n {/* 消息区域容器 */}\n <div className=\"message-list-container\">\n {/* 置顶区域 */}\n {config.showPinnedArea && (\n <PinnedArea\n round={pinnedRound}\n isTransitioning={isTransitioning}\n config={config}\n todoMap={todoMap}\n />\n )}\n\n {/* 可滚动消息列表 */}\n <div \n className=\"message-list\"\n ref={messageListRef}\n onScroll={handleScroll}\n >\n {rounds.map((round, index) => (\n <React.Fragment key={round.interactionId}>\n {/* 非首轮前添加分隔线 */}\n {index > 0 && (\n <div className=\"round-separator\">↑ 上一轮对话 ↑</div>\n )}\n \n {/* 轮次容器(用于滚动位置判断) */}\n <div \n className=\"round-container\"\n data-round={round.index}\n data-interaction-id={round.interactionId}\n >\n {/* 轮次标题(非置顶时显示,置顶时折叠隐藏) */}\n <RoundHeader\n round={round}\n isPinned={round.interactionId === pinnedInteractionId}\n config={config}\n todoMap={todoMap}\n />\n \n {/* AI 回复消息 */}\n {renderRoundMessages(round)}\n </div>\n\n {/* 动态清屏垫片:只对最后一个轮次生效,历史轮次的垫片折叠为 0 */}\n {/* 这样历史轮次不会出现大空白,而新轮次仍然有\"从顶部开始\"的效果 */}\n {index > 0 && (\n <div \n className={`clear-screen-spacer ${index < rounds.length - 1 || getSpacerHeight(round.interactionId) <= 0 ? 'spacer-collapsed' : ''}`}\n style={{ height: index < rounds.length - 1 ? 0 : Math.max(0, getSpacerHeight(round.interactionId)) }}\n data-spacer-for={round.interactionId}\n />\n )}\n </React.Fragment>\n ))}\n\n {/* 空状态 */}\n {rounds.length === 0 && (\n <div className=\"empty-state\">\n <span className=\"empty-icon\">💬</span>\n <span className=\"empty-text\">等待对话开始...</span>\n </div>\n )}\n </div>\n </div>\n\n {/* 底部 */}\n <div className=\"chat-footer\">\n {renderFooter ? renderFooter(widgetAPI) : '由 JetAgents 驱动'}\n </div>\n\n {/* 文件内容查看器 */}\n {viewerOpen && (\n <div className=\"artifact-viewer-overlay\" onClick={() => setViewerOpen(false)}>\n <div className=\"artifact-viewer-panel\" onClick={e => e.stopPropagation()}>\n <div className=\"artifact-viewer-header\">\n <div className=\"artifact-viewer-title\">\n <span className=\"artifact-viewer-icon\">📄</span>\n <span>{viewerArtifact?.name || '文件内容'}</span>\n </div>\n <button className=\"artifact-viewer-close\" onClick={() => setViewerOpen(false)}>✕</button>\n </div>\n {viewerContent && (\n <div className=\"artifact-viewer-meta\">\n <span>{viewerContent.mime_type || '未知类型'}</span>\n {viewerContent.file_size != null && (\n <span>{viewerContent.file_size > 1024 ? `${(viewerContent.file_size / 1024).toFixed(1)} KB` : `${viewerContent.file_size} B`}</span>\n )}\n <span className=\"artifact-viewer-path\">{viewerContent.git_path}</span>\n </div>\n )}\n <div className=\"artifact-viewer-body\">\n {viewerLoading && (\n <div className=\"artifact-viewer-loading\">\n <span className=\"loading-spinner\" />\n <span>加载中...</span>\n </div>\n )}\n {viewerError && (\n <div className=\"artifact-viewer-error\">{viewerError}</div>\n )}\n {viewerContent && !viewerContent.is_binary && (\n <pre className=\"artifact-viewer-content\">{viewerContent.content}</pre>\n )}\n {viewerContent?.is_binary && (\n <div className=\"artifact-viewer-binary\">二进制文件,无法直接预览</div>\n )}\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default ChatWidget\n","import type React from 'react'\n\n// ========== SSE Protocol Types ==========\n\nexport type MessageContentType =\n | 'text'\n | 'think'\n | 'plan'\n | 'artifact'\n | 'json_schema'\n | 'html_schema'\n | 'json_schema_wait'\n\nexport type NotificationType =\n | 'user_input'\n | 'node_notification'\n | 'start'\n | 'model_start'\n | 'model_result'\n | 'model_end'\n | 'agent_start'\n | 'agent_result'\n | 'agent_end'\n | 'artifact_start'\n | 'artifact_result'\n | 'artifact_end'\n | 'plan_start'\n | 'plan_result'\n | 'plan_end'\n | 'mcp_generating'\n | 'mcp_start'\n | 'mcp_result'\n | 'mcp_end'\n | 'finish'\n | 'canceled'\n | 'error'\n | 'human_input_request'\n | 'human_input_received'\n | 'human_input_timeout'\n | 'human_input_completed'\n | 'session_title'\n | 'compression_started'\n | 'compression_completed'\n | 'node_summary'\n\nexport interface UiConfig {\n display_type: 'content' | 'command' | 'browser' | 'query' | 'path' | 'trigger' | 'thinking' | 'params'\n icon?: string\n primary_field?: string\n header_field?: string\n compact_fields?: string[]\n hide_fields?: string[]\n}\n\nexport interface SSEMessage {\n interaction_id: string\n agent_instance_id: number\n call_batch_id: string\n parent_call_batch_id?: string\n level: number\n agent_name: string\n task_purpose?: string\n notification_type?: NotificationType\n tool_name?: string\n tool_call_id?: string\n tool_status?: 'success' | 'error'\n args_preview?: string\n ui_config?: UiConfig\n parent_tool_call_id?: string\n content_type: MessageContentType\n content: string\n timestamp?: string\n}\n\n// ========== Domain Types ==========\n\nexport interface PlanItem {\n text: string\n status: 'pending' | 'active' | 'completed' | 'error'\n}\n\nexport interface TaskPlan {\n title?: string\n items: PlanItem[]\n progress: { completed: number; total: number }\n}\n\nexport type TodoTaskStatus = 'pending' | 'in_progress' | 'completed' | 'blocked'\n\nexport interface TodoTask {\n id: string | null\n description: string\n status: TodoTaskStatus\n children: TodoTask[]\n}\n\nexport interface TodoGroup {\n name: string\n status: TodoTaskStatus\n tasks: TodoTask[]\n}\n\nexport interface TodoPhase {\n name: string\n status: TodoTaskStatus\n groups: TodoGroup[]\n tasks: TodoTask[]\n}\n\nexport interface TodoStats {\n total: number\n completed: number\n in_progress: number\n pending: number\n blocked: number\n}\n\nexport interface TodoData {\n title: string\n phases: TodoPhase[]\n stats: TodoStats\n}\n\nexport interface TodoNotificationContent {\n operation: 'checklist_edit'\n plan_id: string\n checklist_path: string\n checklist_content: string\n checklist: TodoData\n source_type: 'checklist_edit'\n}\n\nexport function isTodoNotificationContent(data: unknown): data is TodoNotificationContent {\n if (!data || typeof data !== 'object') return false\n const obj = data as Record<string, unknown>\n return obj.operation === 'checklist_edit' && obj.checklist != null\n}\n\nexport interface Artifact {\n id: string\n name: string\n type: string\n size?: string\n content?: string\n preview?: string\n metadata?: {\n gitPath?: string\n gitCommitHash?: string\n createdByAgentId?: string\n operationType?: string\n }\n}\n\nexport interface HITLRequest {\n await_command_uuid: string\n schema_type: 'json_schema' | 'html_schema'\n schema: object | string\n title?: string\n description?: string\n}\n\nexport interface HITLResponse {\n await_command_uuid: string\n data: unknown\n confirmed: boolean\n}\n\n// ========== Aggregated Message ==========\n\nexport interface AggregatedMessage {\n id: string\n agentInstanceId: number\n callBatchId: string\n parentCallBatchId?: string\n level: number\n agentName: string\n taskPurpose?: string\n notificationType?: NotificationType\n toolName?: string\n toolCallId?: string\n toolStatus?: 'success' | 'error'\n toolPhase?: 'generating' | 'executing' | 'complete' | 'error'\n argsPreview?: string\n uiConfig?: UiConfig\n parentToolCallId?: string\n contentType: MessageContentType\n contentChunks: string[]\n timestamp: string\n plan?: TaskPlan\n artifact?: Artifact\n artifacts?: Artifact[]\n hitlRequest?: HITLRequest\n}\n\n// ========== Round ==========\n\nexport interface Round {\n interactionId: string\n index: number\n userMessage: string\n timestamp: string\n status: 'running' | 'completed' | 'error'\n plan?: TaskPlan\n messages: AggregatedMessage[]\n topPosition?: number\n}\n\n// ========== Execution Status ==========\n\nexport type ExecutionStatus =\n | 'idle'\n | 'running'\n | 'compressing'\n | 'completed'\n | 'error'\n\n// ========== Widget State ==========\n\nexport interface ChatWidgetState {\n rounds: Map<string, Round>\n currentInteractionId: string | null\n pinnedInteractionId: string | null\n connectionStatus: 'connecting' | 'connected' | 'disconnected' | 'error'\n executionStatus: ExecutionStatus\n isTransitioning: boolean\n pendingHITL: Map<string, HITLRequest>\n}\n\n// ========== Widget Config ==========\n\nexport interface ChatWidgetConfig {\n showPinnedArea?: boolean\n showPlan?: boolean\n enableTypewriter?: boolean\n typewriterSpeed?: number\n autoScroll?: boolean\n childAgentMaxHeight?: number\n theme?: 'light' | 'dark' | 'auto'\n displayLevels?: number[]\n}\n\nexport const DEFAULT_CONFIG: Required<ChatWidgetConfig> = {\n showPinnedArea: true,\n showPlan: true,\n enableTypewriter: true,\n typewriterSpeed: 30,\n autoScroll: true,\n childAgentMaxHeight: 200,\n theme: 'auto',\n displayLevels: [0, 1, 2],\n}\n\n// ========== Widget Props ==========\n\nexport interface ChatWidgetProps {\n adapter: ChatWidgetAdapter\n sessionId?: string | number\n initialMessages?: Round[]\n config?: ChatWidgetConfig\n renderHeaderExtra?: (sessionId: string | number) => React.ReactNode\n renderFooter?: (api: ChatWidgetAPI | null) => React.ReactNode\n renderToolResult?: (displayType: string, data: ToolCallData) => React.ReactNode | null\n locale?: 'zh-CN' | 'en-US'\n onArtifactClick?: (artifact: Artifact) => void\n onHITLSubmit?: (response: HITLResponse) => Promise<void>\n onStatusChange?: (status: ExecutionStatus) => void\n onError?: (error: Error) => void\n onReady?: (api: ChatWidgetAPI) => void\n className?: string\n style?: React.CSSProperties\n height?: number | string\n}\n\n// ========== Widget API ==========\n\nexport interface ChatWidgetAPI {\n sendMessage: (message: string, agentId?: string) => void\n getCurrentRound: () => Round | null\n getAllRounds: () => Round[]\n scrollToBottom: () => void\n getStatus: () => ExecutionStatus\n}\n\n// ========== Tool Call Data ==========\n\nexport interface ToolCallData {\n tool_name: string\n display_type: string\n args: Record<string, unknown>\n args_preview?: Record<string, unknown>\n result?: unknown\n status: 'pending' | 'running' | 'completed' | 'failed'\n ui_config?: UiConfig\n}\n\n// ========== Adapter Types ==========\n\nexport interface NotificationTurn {\n type: string\n contents: Array<{ type?: string; content?: string; read?: boolean }>\n timestamp: number | null\n session_id: number\n interaction_id: string\n agent_id: string | null\n agent_instance_id: number\n parent_agent_instance_id: number\n call_batch_id: number\n parent_call_batch_id: number | null\n level: number | null\n card_title: string | null\n caller_type: string | null\n user_id: string | null\n ext: Record<string, unknown> | null\n turn_id: number\n turn_index: number\n status: string\n timestamp_start: number | null\n timestamp_end: number | null\n}\n\nexport interface ResourceContent {\n resource_id: string\n file_name: string\n git_path: string\n mime_type: string | null\n is_text_readable: boolean | null\n file_size: number | null\n is_binary: boolean\n content: string\n}\n\nexport interface SessionDetail {\n session_id: number\n session_title?: string\n status?: string\n created_at?: string\n}\n\n// ========== ChatWidgetAdapter ==========\n\nexport interface ChatWidgetAdapter {\n createSession(agentId: string): Promise<{\n sessionId: number\n instanceId: number\n }>\n\n getSessionDetail(sessionId: number): Promise<SessionDetail>\n\n getSessionHistory(sessionId: number): Promise<NotificationTurn[]>\n\n getResourceContent(\n sessionId: number,\n resourceId: string,\n ): Promise<ResourceContent>\n\n submitHITLResponse(response: HITLResponse): Promise<void>\n\n getStreamUrl(): string\n\n getAuthHeaders(): Record<string, string>\n\n getExtraHeaders?(): Record<string, string>\n\n onAuthFailure?(): void\n\n refreshAuth?(): Promise<boolean>\n}\n\n// ========== Render Helpers ==========\n\nexport function mergeConsecutiveThinkMessages(messages: AggregatedMessage[]): AggregatedMessage[] {\n if (messages.length === 0) return messages\n\n const result: AggregatedMessage[] = []\n let pendingThink: AggregatedMessage | null = null\n\n for (const msg of messages) {\n if (msg.contentType === 'think') {\n if (pendingThink) {\n const prev: AggregatedMessage = pendingThink\n pendingThink = {\n ...prev,\n contentChunks: [...prev.contentChunks, ...msg.contentChunks],\n }\n } else {\n pendingThink = { ...msg, contentChunks: [...msg.contentChunks] }\n }\n } else {\n if (pendingThink) {\n result.push(pendingThink)\n pendingThink = null\n }\n result.push(msg)\n }\n }\n\n if (pendingThink) {\n result.push(pendingThink)\n }\n\n return result\n}\n\n// ========== Sub-component Props ==========\n\nexport interface TodoCardProps {\n todo: TodoData\n compact?: boolean\n}\n\nexport interface PinnedAreaProps {\n round: Round | null\n isTransitioning: boolean\n config?: ChatWidgetConfig\n todoMap?: Map<string, TodoData>\n}\n\nexport interface RoundHeaderProps {\n round: Round\n isPinned: boolean\n config?: ChatWidgetConfig\n todoMap?: Map<string, TodoData>\n}\n\nexport interface MessageContentProps {\n message: AggregatedMessage\n enableTypewriter?: boolean\n typewriterSpeed?: number\n onArtifactClick?: (artifact: Artifact) => void\n}\n\nexport interface ChildAgentCardProps {\n message: AggregatedMessage\n children: AggregatedMessage[]\n maxHeight?: number\n config?: ChatWidgetConfig\n defaultExpanded?: boolean\n parentTaskPurpose?: string\n}\n\nexport interface PlanCardProps {\n plan: TaskPlan\n status: Round['status']\n compact?: boolean\n}\n\nexport interface HITLFormProps {\n request: HITLRequest\n onSubmit: (data: unknown, confirmed: boolean) => void\n onCancel: () => void\n}\n","/**\n * 消息聚合 Hook\n * \n * 实现高性能消息聚合:\n * - Map 索引 O(1) 查找\n * - 字符串数组延迟拼接\n * - requestAnimationFrame 批量更新\n * - 延迟 JSON 解析\n */\n\nimport { useCallback, useRef, useState } from 'react'\nimport type { \n SSEMessage, \n AggregatedMessage, \n Round, \n TaskPlan,\n TodoData,\n Artifact,\n HITLRequest,\n PlanItem\n} from '../types'\nimport { isTodoNotificationContent } from '../types'\n\n/** 从流式 argsPreview 中提取 _task_purpose / task_purpose 值 */\nfunction extractTaskPurposeFromPreview(preview: string): string | undefined {\n const m = preview.match(/\"_?task_purpose\"\\s*:\\s*\"([^\"]*)\"/)\n return m?.[1] || undefined\n}\n\ninterface MessageAggregatorState {\n rounds: Map<string, Round>\n currentInteractionId: string | null\n}\n\ninterface UseMessageAggregatorReturn {\n state: MessageAggregatorState\n todoMap: Map<string, TodoData>\n processMessage: (message: SSEMessage) => void\n getRoundsList: () => Round[]\n getCurrentRound: () => Round | null\n startNewRound: (interactionId: string, userMessage: string) => void\n loadRounds: (rounds: Round[]) => void\n finalizeRound: (interactionId: string) => void\n clear: () => void\n}\n\nexport function useMessageAggregator(): UseMessageAggregatorReturn {\n // 使用 Map 实现 O(1) 查找\n const [state, setState] = useState<MessageAggregatorState>({\n rounds: new Map(),\n currentInteractionId: null,\n })\n\n // Session 级 Todo 状态(按 plan_id 索引,幂等替换)\n const [todoMap, setTodoMap] = useState<Map<string, TodoData>>(new Map())\n const todoMapRef = useRef<Map<string, TodoData>>(new Map())\n\n // 使用 ref 存储中间状态,避免频繁触发渲染\n const pendingUpdates = useRef<SSEMessage[]>([])\n const rafId = useRef<number | null>(null)\n const messageIndexRef = useRef<Map<string, AggregatedMessage>>(new Map())\n const roundIndexRef = useRef<Map<string, Round>>(new Map())\n const processedChunksRef = useRef<Set<string>>(new Set()) // 追踪已处理的 chunk\n // 追踪每个 call_batch_id 属于哪个 interaction_id(轮次)\n // 用于处理 JetAgents Redis 缓冲消息:将消息路由到正确的轮次\n const callBatchToRoundRef = useRef<Map<string, string>>(new Map())\n\n // 解析 plan 内容\n const parsePlan = useCallback((content: string): TaskPlan | null => {\n try {\n const parsed = JSON.parse(content)\n if (parsed.items && Array.isArray(parsed.items)) {\n return {\n title: parsed.title,\n items: parsed.items.map((item: { text?: string; status?: string }) => ({\n text: item.text || '',\n status: item.status || 'pending',\n })) as PlanItem[],\n progress: {\n completed: parsed.items.filter((i: { status?: string }) => i.status === 'completed').length,\n total: parsed.items.length,\n },\n }\n }\n } catch {\n // 非 JSON 格式的 plan,解析为简单列表\n const lines = content.split('\\n').filter(Boolean)\n return {\n items: lines.map((line) => ({\n text: line.replace(/^[-*]\\s*/, ''),\n status: 'pending' as const,\n })),\n progress: { completed: 0, total: lines.length },\n }\n }\n return null\n }, [])\n\n // 解析单个 JetAgents artifact JSON\n const parseSingleArtifact = useCallback((parsed: Record<string, unknown>): Artifact | null => {\n // JetAgents 文件 artifact 格式\n if (parsed.type === 'file' && parsed.data) {\n const data = parsed.data as Record<string, unknown>\n const fileSize = data.file_size as number | undefined\n const sizeStr = fileSize ? (fileSize > 1024 \n ? `${(fileSize / 1024).toFixed(1)} KB` \n : `${fileSize} B`) : undefined\n \n return {\n id: (parsed.identifier || data.file_id || crypto.randomUUID()) as string,\n name: (data.file_name || parsed.description || 'Untitled') as string,\n type: (data.mime_type || 'text/plain') as string,\n size: sizeStr,\n content: parsed.description as string,\n preview: `${parsed.intention}: ${parsed.description}`,\n metadata: {\n gitPath: data.git_path as string,\n gitCommitHash: data.git_commit_hash as string,\n createdByAgentId: data.created_by_agent_id as string,\n operationType: data.operation_type as string,\n },\n }\n }\n \n // 标准格式\n return {\n id: (parsed.id || crypto.randomUUID()) as string,\n name: (parsed.name || 'Untitled') as string,\n type: (parsed.type || 'text/plain') as string,\n size: parsed.size as string | undefined,\n content: parsed.content as string | undefined,\n preview: parsed.preview as string | undefined,\n }\n }, [])\n\n // 解析 artifact 内容(支持 JetAgents 格式,支持多个连接的 JSON)\n const parseArtifact = useCallback((content: string): Artifact | null => {\n try {\n // 尝试直接解析\n const parsed = JSON.parse(content)\n return parseSingleArtifact(parsed)\n } catch {\n // 可能是多个 JSON 连接在一起(如 {...}{...})\n // 尝试分割并解析第一个\n const firstJsonEnd = content.indexOf('}{')\n if (firstJsonEnd > 0) {\n try {\n const firstJson = content.substring(0, firstJsonEnd + 1)\n const parsed = JSON.parse(firstJson)\n return parseSingleArtifact(parsed)\n } catch {\n return null\n }\n }\n return null\n }\n }, [parseSingleArtifact])\n\n // 解析多个 artifact(支持 {...}{...} 格式)\n const parseArtifacts = useCallback((content: string): Artifact[] => {\n const artifacts: Artifact[] = []\n \n // 分割多个 JSON(用 }{ 分隔)\n const jsonStrings = content.split(/\\}\\s*\\{/).map((str, index, arr) => {\n if (index === 0) return str + (arr.length > 1 ? '}' : '')\n if (index === arr.length - 1) return '{' + str\n return '{' + str + '}'\n })\n \n for (const jsonStr of jsonStrings) {\n try {\n const parsed = JSON.parse(jsonStr)\n const artifact = parseSingleArtifact(parsed)\n if (artifact) {\n artifacts.push(artifact)\n }\n } catch {\n // 忽略解析错误\n }\n }\n \n return artifacts\n }, [parseSingleArtifact])\n\n // 解析 HITL 请求\n const parseHITLRequest = useCallback((content: string, contentType: string): HITLRequest | null => {\n try {\n const parsed = JSON.parse(content)\n return {\n await_command_uuid: parsed.await_command_uuid || '',\n schema_type: contentType === 'html_schema' ? 'html_schema' : 'json_schema',\n schema: parsed.schema || parsed,\n title: parsed.title,\n description: parsed.description,\n }\n } catch {\n return null\n }\n }, [])\n\n // 批量处理更新\n const flushUpdates = useCallback(() => {\n if (pendingUpdates.current.length === 0) return\n\n const updates = [...pendingUpdates.current]\n pendingUpdates.current = []\n\n // === 在 setState 之外处理数据(避免 React 重复调用导致的问题) ===\n let latestInteractionId: string | null = null\n let todoMapChanged = false\n\n for (const msg of updates) {\n const { agent_instance_id, call_batch_id, content_type, content } = msg\n let { interaction_id } = msg\n\n // ========== 过滤 node_summary 消息 ==========\n // TODO: node_summary 是节点执行完成后的总结消息,用于其他用途(如历史记录展示),\n // 暂不渲染到聊天消息流中。后续需要:\n // 1. 将 node_summary 存储到单独的状态中\n // 2. 在合适的 UI 位置展示(如轮次折叠摘要、历史记录等)\n if (msg.notification_type === 'node_summary') {\n continue\n }\n // ========== 结束:过滤 node_summary ==========\n\n // ========== JETP-021: 过滤压缩通知 ==========\n // compression_started/completed 由 ChatWidget 直接处理为状态变更,\n // 不应创建消息行或追加内容\n if (msg.notification_type === 'compression_started' || msg.notification_type === 'compression_completed') {\n continue\n }\n // ========== 结束:过滤压缩通知 ==========\n\n // ========== JETP-024: Todo (Checklist) 通知路由 ==========\n // plan_result + operation=checklist_edit → 更新 session 级 todoMap,不创建消息行\n if (msg.notification_type === 'plan_result' && content) {\n try {\n const parsed = typeof content === 'string' ? JSON.parse(content) : content\n if (isTodoNotificationContent(parsed)) {\n const planId = parsed.plan_id || 'default'\n todoMapRef.current = new Map(todoMapRef.current).set(planId, parsed.checklist)\n todoMapChanged = true\n continue\n }\n } catch { /* not JSON or not checklist, fall through to normal processing */ }\n }\n // ========== 结束:Todo 通知路由 ==========\n\n // ========== Redis 缓冲消息路由 ==========\n // JetAgents 的 Redis 缓冲机制:连接断开后的消息会被缓冲,重连后发送\n // 这些消息可能属于之前的轮次,需要根据 call_batch_id 路由到正确的轮次\n const existingRoundForBatch = callBatchToRoundRef.current.get(call_batch_id)\n if (existingRoundForBatch && existingRoundForBatch !== interaction_id) {\n // 这个 call_batch_id 已经绑定到其他轮次,将消息路由到那个轮次\n interaction_id = existingRoundForBatch\n } else if (!existingRoundForBatch) {\n // 首次见到这个 call_batch_id,绑定到当前轮次\n callBatchToRoundRef.current.set(call_batch_id, interaction_id)\n }\n // ========== 结束:Redis 缓冲消息路由 ==========\n\n // 获取或创建轮次\n let round = roundIndexRef.current.get(interaction_id)\n if (!round) {\n round = {\n interactionId: interaction_id,\n index: roundIndexRef.current.size + 1,\n userMessage: '',\n timestamp: msg.timestamp || new Date().toISOString(),\n status: 'running',\n messages: [],\n }\n roundIndexRef.current.set(interaction_id, round)\n }\n latestInteractionId = interaction_id\n\n // 生成消息唯一键(加入 interaction_id 确保跨轮次隔离)\n // 对于 MCP 消息,使用 tool_call_id 作为 key,这样 start/end 会更新同一个消息的状态\n const notification_type = msg.notification_type\n const isMcpMessage = notification_type && ['mcp_generating', 'mcp_start', 'mcp_result', 'mcp_end'].includes(notification_type)\n let messageKey = isMcpMessage \n ? `${interaction_id}-${agent_instance_id}-mcp-${msg.tool_call_id || call_batch_id}`\n : `${interaction_id}-${agent_instance_id}-${call_batch_id}-${content_type}`\n\n // ========== MCP key 容错:tool_call_id 不一致时的回退匹配 ==========\n // JetAgents 的 mcp_start/mcp_end/mcp_result 有时不携带 ext.tool_call_id,\n // 导致 key 从 \"...-mcp-{tool_call_id}\" 退化为 \"...-mcp-{call_batch_id}\",\n // 与之前 mcp_generating 创建的 key 不匹配。\n // 回退策略:在同一轮次中按 call_batch_id + tool_name 寻找未完成的工具卡片。\n if (isMcpMessage && notification_type !== 'mcp_generating' && !messageIndexRef.current.has(messageKey)) {\n const fallback = round.messages.find(m =>\n m.toolPhase && m.toolPhase !== 'complete' && m.toolPhase !== 'error'\n && m.callBatchId === call_batch_id\n && (msg.tool_name ? m.toolName === msg.tool_name : true)\n )\n if (fallback) {\n messageKey = fallback.id\n }\n }\n // ========== 结束:MCP key 容错 ==========\n\n // ========== 非连续同类型消息分段 ==========\n // 修复排序问题:当消息序列为 text → tool_use → tool_result → text 时,\n // 两个 text 消息具有相同的 messageKey 会被错误合并为一条消息,\n // 导致渲染顺序变为 [text(含a+d), tool] 而非 [text(a), tool(b,c), text(d)]。\n // 解决方案:对于非 MCP 消息,仅当该 key 对应的消息是轮次中最后一条时才合并(即连续流式块),\n // 否则创建带分段后缀的新 key。\n //\n // JETP-011 补丁:模型流式输出中,文本和工具调用可能交叉到达。\n // 短文本残片(< 10 字符)如果紧跟在工具卡片后面,说明它是被工具调用切割的\n // 上一句话的尾巴,应合并回工具卡片之前的最近文本段,而不是创建新分段。\n if (!isMcpMessage && messageIndexRef.current.has(messageKey)) {\n const baseKey = messageKey\n // 收集所有候选 key(原始 key + 已有分段)\n const candidateKeys = [baseKey]\n let segIdx = 1\n while (messageIndexRef.current.has(`${baseKey}-${segIdx}`)) {\n candidateKeys.push(`${baseKey}-${segIdx}`)\n segIdx++\n }\n // 查找是否有候选 key 对应的消息是当前轮次的最后一条(可以安全合并)\n const lastMsgId = round.messages.length > 0\n ? round.messages[round.messages.length - 1].id\n : null\n const mergeTarget = candidateKeys.find(k => k === lastMsgId)\n if (mergeTarget) {\n // 找到可合并的目标(它是轮次最后一条消息,说明是连续流式块)\n messageKey = mergeTarget\n } else {\n // 没有可合并的目标 —— 中间插入了其他类型的消息\n // JETP-011: 短残片回溯合并 —— 如果当前文本很短且最后一条消息是工具卡片,\n // 将其合并回被工具卡片打断前的最近文本段\n const lastMsg = round.messages.length > 0 ? round.messages[round.messages.length - 1] : null\n const isAfterToolCard = lastMsg && lastMsg.toolPhase !== undefined\n const isShortFragment = content.length < 10\n\n if (isAfterToolCard && isShortFragment) {\n // 回溯到最近的同类型文本段\n const latestTextKey = candidateKeys[candidateKeys.length - 1]\n messageKey = latestTextKey\n } else {\n messageKey = `${baseKey}-${segIdx}`\n }\n }\n }\n // ========== 结束:非连续同类型消息分段 ==========\n \n // 获取或创建消息\n let message = messageIndexRef.current.get(messageKey)\n if (!message) {\n message = {\n id: messageKey,\n agentInstanceId: agent_instance_id,\n callBatchId: call_batch_id,\n parentCallBatchId: msg.parent_call_batch_id,\n level: msg.level,\n agentName: msg.agent_name,\n taskPurpose: msg.task_purpose, // 任务目标\n notificationType: msg.notification_type, // 顶层通知类型\n toolName: msg.tool_name, // 工具名称\n toolCallId: msg.tool_call_id, // 工具调用 ID\n toolStatus: msg.tool_status, // 工具执行状态\n toolPhase: notification_type === 'mcp_generating' ? 'generating'\n : notification_type === 'mcp_start' ? 'executing'\n : notification_type === 'mcp_end' ? (msg.tool_status === 'error' ? 'error' : 'complete')\n : undefined,\n argsPreview: msg.args_preview,\n uiConfig: msg.ui_config,\n parentToolCallId: msg.parent_tool_call_id,\n contentType: content_type,\n contentChunks: [],\n timestamp: msg.timestamp || new Date().toISOString(),\n }\n messageIndexRef.current.set(messageKey, message)\n // 添加到 round.messages\n if (!round.messages.some(m => m.id === messageKey)) {\n round.messages.push(message)\n }\n } else if (isMcpMessage) {\n // 不可变更新:创建新 message 引用,使 React.memo 能检测到变化,\n // 避免每次 mcp_generating 更新导致所有消息组件全量重渲染\n const prev = message\n message = { ...message, contentChunks: [...message.contentChunks] }\n\n message.notificationType = msg.notification_type\n if (msg.tool_status) {\n message.toolStatus = msg.tool_status\n }\n if (msg.task_purpose && !message.taskPurpose) {\n message.taskPurpose = msg.task_purpose\n }\n if (!message.taskPurpose && msg.args_preview) {\n const tp = extractTaskPurposeFromPreview(msg.args_preview)\n if (tp) message.taskPurpose = tp\n }\n // toolPhase 只允许单向推进: generating → executing → complete/error\n // 防止 FINISH 触发 finalizeRound 之后,RAF 批处理中残留的 mcp_generating\n // 将已完成的卡片回退到 \"生成中\"\n const isTerminal = message.toolPhase === 'complete' || message.toolPhase === 'error'\n if (notification_type === 'mcp_generating') {\n if (!isTerminal) {\n message.toolPhase = 'generating'\n }\n if (msg.args_preview) {\n message.argsPreview = msg.args_preview\n }\n if (msg.ui_config && !message.uiConfig) {\n message.uiConfig = msg.ui_config\n }\n } else if (notification_type === 'mcp_start') {\n if (!isTerminal) {\n message.toolPhase = 'executing'\n }\n } else if (notification_type === 'mcp_end') {\n message.toolPhase = msg.tool_status === 'error' ? 'error' : 'complete'\n }\n\n // 替换索引和 round.messages 中的旧引用\n messageIndexRef.current.set(messageKey, message)\n const prevIdx = round.messages.indexOf(prev)\n if (prevIdx >= 0) round.messages[prevIdx] = message\n }\n\n // 追加内容(使用计数器防止重复)\n // JETP-010: MCP 生命周期消息(mcp_generating/mcp_start/mcp_end)的 content\n // 是状态文本(如\"🔧 保存笑话 (write)\"),不应作为消息正文追加到 contentChunks,\n // 否则 ToolCardBuffering 会把状态文本当成工具执行结果渲染出来。\n const skipContent = isMcpMessage && notification_type !== 'mcp_result'\n if (!skipContent) {\n const chunkIndex = message.contentChunks.length\n const chunkId = `${messageKey}-chunk-${chunkIndex}`\n if (!processedChunksRef.current.has(chunkId)) {\n processedChunksRef.current.add(chunkId)\n // 不可变更新:创建新 message 引用以触发 React.memo 重渲染\n const prevMsg = message\n message = { ...message, contentChunks: [...message.contentChunks, content] }\n messageIndexRef.current.set(messageKey, message)\n const idx = round.messages.indexOf(prevMsg)\n if (idx >= 0) round.messages[idx] = message\n }\n }\n\n // 延迟解析特殊内容类型\n if (content_type === 'plan') {\n const plan = parsePlan(message.contentChunks.join(''))\n if (plan) {\n message.plan = plan\n round.plan = plan\n }\n } else if (content_type === 'artifact') {\n const allContent = message.contentChunks.join('')\n const artifacts = parseArtifacts(allContent)\n if (artifacts.length > 0) {\n message.artifacts = artifacts\n message.artifact = artifacts[0] // 向后兼容\n }\n } else if (content_type === 'json_schema' || content_type === 'html_schema' || content_type === 'json_schema_wait') {\n message.hitlRequest = parseHITLRequest(message.contentChunks.join(''), content_type) ?? undefined\n }\n }\n\n // === 只在 setState 中做状态快照 ===\n setState(() => {\n // 从 ref 构建新的 Map(浅拷贝触发 React 更新)\n const newRounds = new Map(roundIndexRef.current)\n return {\n rounds: newRounds,\n currentInteractionId: latestInteractionId,\n }\n })\n\n if (todoMapChanged) {\n setTodoMap(new Map(todoMapRef.current))\n }\n\n rafId.current = null\n }, [parsePlan, parseArtifact, parseHITLRequest])\n\n // 处理单条消息\n const processMessage = useCallback((message: SSEMessage) => {\n pendingUpdates.current.push(message)\n\n // 使用 RAF 批量更新\n if (rafId.current === null) {\n rafId.current = requestAnimationFrame(flushUpdates)\n }\n }, [flushUpdates])\n\n // 获取轮次列表(按时间排序)\n const getRoundsList = useCallback((): Round[] => {\n return Array.from(state.rounds.values()).sort((a, b) => a.index - b.index)\n }, [state.rounds])\n\n // 获取当前轮次\n const getCurrentRound = useCallback((): Round | null => {\n if (!state.currentInteractionId) return null\n return state.rounds.get(state.currentInteractionId) || null\n }, [state.rounds, state.currentInteractionId])\n\n // 开始新的轮次\n const startNewRound = useCallback((interactionId: string, userMessage: string) => {\n // 先同步更新 ref,避免与 flushUpdates 的竞态条件\n const round: Round = {\n interactionId,\n index: roundIndexRef.current.size + 1,\n userMessage,\n timestamp: new Date().toISOString(),\n status: 'running',\n messages: [],\n }\n roundIndexRef.current.set(interactionId, round)\n \n // 再异步更新 state\n setState((prevState) => {\n const newRounds = new Map(prevState.rounds)\n // 使用已在 ref 中创建的 round\n newRounds.set(interactionId, round)\n\n return {\n rounds: newRounds,\n currentInteractionId: interactionId,\n }\n })\n }, [])\n\n // 批量加载历史轮次(用于恢复 session)\n const loadRounds = useCallback((rounds: Round[]) => {\n roundIndexRef.current.clear()\n messageIndexRef.current.clear()\n callBatchToRoundRef.current.clear()\n processedChunksRef.current.clear()\n\n const newRounds = new Map<string, Round>()\n for (const round of rounds) {\n newRounds.set(round.interactionId, round)\n roundIndexRef.current.set(round.interactionId, round)\n for (const msg of round.messages) {\n messageIndexRef.current.set(msg.id, msg)\n if (msg.callBatchId) {\n callBatchToRoundRef.current.set(msg.callBatchId, round.interactionId)\n }\n }\n }\n\n const lastId = rounds.length > 0 ? rounds[rounds.length - 1].interactionId : null\n setState({ rounds: newRounds, currentInteractionId: lastId })\n }, [])\n\n // 流结束时收尾:将该轮次中所有未完成的工具卡片强制标记为 complete\n // 防止 JetAgents 漏发 mcp_end 导致 UI 永远停留在\"生成中/执行中\"\n const finalizeRound = useCallback((interactionId: string) => {\n const round = roundIndexRef.current.get(interactionId)\n if (!round) return\n\n let changed = false\n for (let i = 0; i < round.messages.length; i++) {\n const msg = round.messages[i]\n if (msg.toolPhase && msg.toolPhase !== 'complete' && msg.toolPhase !== 'error') {\n const updated = { ...msg, toolPhase: 'complete' as const }\n round.messages[i] = updated\n messageIndexRef.current.set(msg.id, updated)\n changed = true\n }\n }\n\n if (changed) {\n setState(() => ({\n rounds: new Map(roundIndexRef.current),\n currentInteractionId: interactionId,\n }))\n }\n }, [])\n\n // 清空状态\n const clear = useCallback(() => {\n pendingUpdates.current = []\n messageIndexRef.current.clear()\n roundIndexRef.current.clear()\n processedChunksRef.current.clear()\n callBatchToRoundRef.current.clear()\n todoMapRef.current.clear()\n if (rafId.current) {\n cancelAnimationFrame(rafId.current)\n rafId.current = null\n }\n setState({\n rounds: new Map(),\n currentInteractionId: null,\n })\n setTodoMap(new Map())\n }, [])\n\n return {\n state,\n todoMap,\n processMessage,\n getRoundsList,\n getCurrentRound,\n startNewRound,\n loadRounds,\n finalizeRound,\n clear,\n }\n}\n\nexport default useMessageAggregator\n","/**\n * SSE 连接 Hook (SDK version)\n *\n * Auth and headers are fully delegated to ChatWidgetAdapter,\n * eliminating direct localStorage / env-var coupling.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { SSEMessage, ChatWidgetAdapter } from '../types'\n\nexport type ConnectionStatus = 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error'\n\ninterface UseSSEOptions {\n adapter: ChatWidgetAdapter\n autoConnect?: boolean\n reconnectInterval?: number\n maxReconnectAttempts?: number\n onMessage?: (message: SSEMessage) => void\n onStatusChange?: (status: ConnectionStatus) => void\n onError?: (error: Error) => void\n}\n\ninterface UseSSEReturn {\n status: ConnectionStatus\n connect: (url: string, body?: object) => void\n disconnect: () => void\n}\n\nexport function useSSE(options: UseSSEOptions): UseSSEReturn {\n const {\n adapter,\n autoConnect = false,\n reconnectInterval = 3000,\n maxReconnectAttempts = 3,\n onMessage,\n onStatusChange,\n onError,\n } = options\n\n const [status, setStatus] = useState<ConnectionStatus>('idle')\n const eventSourceRef = useRef<EventSource | null>(null)\n const abortControllerRef = useRef<AbortController | null>(null)\n const reconnectAttemptsRef = useRef(0)\n const reconnectTimerRef = useRef<number | null>(null)\n\n // 更新状态并触发回调\n const updateStatus = useCallback((newStatus: ConnectionStatus) => {\n setStatus(newStatus)\n onStatusChange?.(newStatus)\n }, [onStatusChange])\n\n // 断开连接\n const disconnect = useCallback(() => {\n if (reconnectTimerRef.current) {\n clearTimeout(reconnectTimerRef.current)\n reconnectTimerRef.current = null\n }\n if (eventSourceRef.current) {\n eventSourceRef.current.close()\n eventSourceRef.current = null\n }\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n abortControllerRef.current = null\n }\n reconnectAttemptsRef.current = 0\n updateStatus('disconnected')\n }, [updateStatus])\n\n // 建立连接\n const connect = useCallback((url: string, body?: object) => {\n // 断开现有连接\n disconnect()\n \n updateStatus('connecting')\n\n // 如果有 body,使用 fetch + ReadableStream\n if (body) {\n abortControllerRef.current = new AbortController()\n \n const doFetch = () => {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Accept': 'text/event-stream',\n ...adapter.getAuthHeaders(),\n ...(adapter.getExtraHeaders?.() ?? {}),\n }\n\n return fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: abortControllerRef.current!.signal,\n })\n }\n\n doFetch()\n .then(async (response) => {\n if (response.status === 401) {\n console.warn('[useSSE] Got 401, attempting token refresh via adapter...')\n const refreshed = await adapter.refreshAuth?.()\n if (refreshed) {\n console.log('[useSSE] Token refreshed, retrying SSE connection')\n const retryResponse = await doFetch()\n if (!retryResponse.ok) {\n throw new Error(`HTTP ${retryResponse.status}: ${retryResponse.statusText}`)\n }\n return retryResponse\n }\n adapter.onAuthFailure?.()\n throw new Error('HTTP 401: Unauthorized')\n }\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n return response\n })\n .then(async (response) => {\n updateStatus('connected')\n reconnectAttemptsRef.current = 0\n\n const reader = response.body?.getReader()\n if (!reader) {\n throw new Error('Response body is not readable')\n }\n\n const decoder = new TextDecoder()\n let buffer = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n \n // 解析 SSE 事件\n const lines = buffer.split('\\n')\n buffer = lines.pop() || '' // 保留不完整的行\n\n for (const line of lines) {\n if (line.startsWith('data:')) {\n const data = line.slice(5).trim()\n if (data && data !== '[DONE]') {\n try {\n const message = JSON.parse(data) as SSEMessage\n onMessage?.(message)\n } catch (e) {\n console.warn('Failed to parse SSE message:', data, e)\n }\n }\n }\n }\n }\n\n updateStatus('disconnected')\n })\n .catch((error) => {\n if (error.name === 'AbortError') {\n updateStatus('disconnected')\n } else {\n const is401 = error instanceof Error && error.message.includes('401')\n console.error('SSE connection error:', error)\n updateStatus('error')\n onError?.(error instanceof Error ? error : new Error(String(error)))\n \n // Don't retry on auth errors — refresh already attempted above\n if (is401) return\n\n // Retry only on transient network errors\n if (reconnectAttemptsRef.current < maxReconnectAttempts) {\n reconnectAttemptsRef.current++\n reconnectTimerRef.current = window.setTimeout(() => {\n connect(url, body)\n }, reconnectInterval)\n }\n }\n })\n } else {\n // 使用原生 EventSource (GET 请求)\n try {\n const eventSource = new EventSource(url)\n eventSourceRef.current = eventSource\n\n eventSource.onopen = () => {\n updateStatus('connected')\n reconnectAttemptsRef.current = 0\n }\n\n eventSource.onmessage = (event) => {\n if (event.data && event.data !== '[DONE]') {\n try {\n const message = JSON.parse(event.data) as SSEMessage\n onMessage?.(message)\n } catch (e) {\n console.warn('Failed to parse SSE message:', event.data, e)\n }\n }\n }\n\n eventSource.onerror = () => {\n eventSource.close()\n updateStatus('error')\n \n // 尝试重连\n if (reconnectAttemptsRef.current < maxReconnectAttempts) {\n reconnectAttemptsRef.current++\n reconnectTimerRef.current = window.setTimeout(() => {\n connect(url)\n }, reconnectInterval)\n }\n }\n } catch (error) {\n updateStatus('error')\n onError?.(error instanceof Error ? error : new Error(String(error)))\n }\n }\n }, [adapter, disconnect, updateStatus, onMessage, onError, maxReconnectAttempts, reconnectInterval])\n\n useEffect(() => {\n if (autoConnect) {\n connect(adapter.getStreamUrl())\n }\n return () => {\n disconnect()\n }\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n return {\n status,\n connect,\n disconnect,\n }\n}\n\nexport default useSSE\n","/**\n * 置顶区域组件\n * 显示当前置顶轮次的用户消息、任务计划和 Todo\n */\n\nimport React from 'react'\nimport type { PinnedAreaProps } from '../types'\nimport PlanCard from './PlanCard'\nimport { TodoCardMulti } from './TodoCard'\nimport './PinnedArea.css'\n\nconst PinnedArea: React.FC<PinnedAreaProps> = ({ \n round, \n isTransitioning,\n todoMap,\n}) => {\n if (!round) return null\n\n const hasTodo = todoMap && todoMap.size > 0\n\n const formatTime = (timestamp: string) => {\n try {\n return new Date(timestamp).toLocaleTimeString('zh-CN', {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n })\n } catch {\n return ''\n }\n }\n\n return (\n <div className=\"chat-pinned-area\">\n <div className={`pinned-content ${isTransitioning ? 'fade-out' : ''}`}>\n {/* 用户消息 */}\n <div className=\"pinned-user-message\">\n {round.userMessage || '(无消息内容)'}\n </div>\n \n {/* Todo (JETP-024) — 优先展示 */}\n {hasTodo && <TodoCardMulti todoMap={todoMap} />}\n\n {/* 旧版 plan — 仅在没有 Todo 时显示 */}\n {!hasTodo && round.plan && (\n <PlanCard \n plan={round.plan} \n status={round.status}\n />\n )}\n </div>\n \n {/* 时间戳 - 放在外层右下角 */}\n <span className=\"pinned-timestamp\">{formatTime(round.timestamp)}</span>\n </div>\n )\n}\n\nexport default PinnedArea\n","/**\n * 任务计划卡片组件\n */\n\nimport React from 'react'\nimport type { PlanCardProps } from '../types'\nimport './PlanCard.css'\n\nconst PlanCard: React.FC<PlanCardProps> = ({ \n plan, \n status,\n compact = false,\n}) => {\n const statusIcons = {\n completed: '✓',\n active: '→',\n pending: '○',\n error: '✗',\n }\n\n if (compact) {\n // 紧凑模式:单行显示\n return (\n <div className=\"plan-card-compact\">\n <span className=\"plan-icon\">📋</span>\n <span className=\"plan-items-inline\">\n {plan.items.map((item, i) => (\n <span key={i} className={`plan-item-inline ${item.status}`}>\n [{statusIcons[item.status]} {item.text}]\n </span>\n ))}\n </span>\n </div>\n )\n }\n\n return (\n <div className={`plan-card ${status === 'completed' ? 'completed' : ''}`}>\n <div className=\"plan-header\">\n <div className=\"plan-title\">\n <span className=\"plan-icon\">📋</span>\n <span>任务计划</span>\n </div>\n <span className=\"plan-progress\">\n ({plan.progress.completed}/{plan.progress.total})\n </span>\n </div>\n <ul className=\"plan-items\">\n {plan.items.map((item, index) => (\n <li key={index} className={`plan-item ${item.status}`}>\n <span className=\"plan-item-icon\">{statusIcons[item.status]}</span>\n <span className=\"plan-item-text\">{item.text}</span>\n {item.status === 'active' && (\n <span className=\"plan-item-status\">执行中</span>\n )}\n </li>\n ))}\n </ul>\n </div>\n )\n}\n\nexport default PlanCard\n","import React, { useState, useCallback, useMemo } from 'react'\nimport type { TodoCardProps, TodoTask, TodoData, TodoTaskStatus, TodoPhase, TodoGroup } from '../types'\nimport './TodoCard.css'\n\nconst STATUS_ICON: Record<TodoTaskStatus, string> = {\n pending: '○',\n in_progress: '→',\n completed: '✓',\n blocked: '⚠',\n}\n\nconst MAX_VISIBLE_ITEMS = 8\n\n/** Flatten phases → groups → tasks into a single ordered list for flat rendering */\nfunction flattenTasks(todo: TodoData): TodoTask[] {\n const result: TodoTask[] = []\n for (const phase of todo.phases) {\n for (const task of phase.tasks) {\n result.push(task)\n }\n for (const group of phase.groups) {\n for (const task of group.tasks) {\n result.push(task)\n }\n }\n }\n return result\n}\n\nfunction findCurrentTask(tasks: TodoTask[]): TodoTask | null {\n return tasks.find(t => t.status === 'in_progress') || null\n}\n\n// ========== Task row component ==========\n\nconst TaskRow: React.FC<{\n task: TodoTask\n depth?: number\n}> = ({ task, depth = 0 }) => {\n const [expanded, setExpanded] = useState(\n task.status === 'in_progress' && task.children.length > 0,\n )\n\n const hasChildren = task.children.length > 0\n const toggle = useCallback(() => setExpanded(v => !v), [])\n\n return (\n <>\n <div\n className={`todo-task-row todo-status-${task.status}`}\n style={{ paddingLeft: `${12 + depth * 16}px` }}\n onClick={hasChildren ? toggle : undefined}\n role={hasChildren ? 'button' : undefined}\n >\n <span className=\"todo-status-icon\">{STATUS_ICON[task.status]}</span>\n {hasChildren && (\n <span className={`todo-expand-arrow ${expanded ? 'expanded' : ''}`}>▸</span>\n )}\n <span className=\"todo-task-desc\">{task.description}</span>\n </div>\n {expanded && task.children.map((child, i) => (\n <TaskRow key={child.id || i} task={child} depth={depth + 1} />\n ))}\n </>\n )\n}\n\n// ========== Compact mode ==========\n\nconst TodoCardCompact: React.FC<{ todo: TodoData }> = ({ todo }) => {\n const tasks = useMemo(() => flattenTasks(todo), [todo])\n const current = findCurrentTask(tasks)\n const { stats } = todo\n\n return (\n <div className=\"todo-card-compact\">\n <span className=\"todo-compact-icon\">☰</span>\n <span className=\"todo-compact-title\">{todo.title}</span>\n {current && (\n <>\n <span className=\"todo-compact-sep\">→</span>\n <span className=\"todo-compact-current\">{current.description}</span>\n </>\n )}\n <span className=\"todo-compact-progress\">\n 已完成 {stats.completed}/{stats.total}\n </span>\n </div>\n )\n}\n\n// ========== Full mode ==========\n\nconst TodoCard: React.FC<TodoCardProps> = ({ todo, compact = false }) => {\n const [expanded, setExpanded] = useState(false)\n const [showAll, setShowAll] = useState(false)\n\n const tasks = useMemo(() => flattenTasks(todo), [todo])\n const { stats } = todo\n const progress = stats.total > 0 ? stats.completed / stats.total : 0\n\n if (compact) {\n return <TodoCardCompact todo={todo} />\n }\n\n const visibleTasks = showAll ? tasks : tasks.slice(0, MAX_VISIBLE_ITEMS)\n const hiddenCount = tasks.length - MAX_VISIBLE_ITEMS\n\n const current = useMemo(() => findCurrentTask(tasks), [tasks])\n const isAllDone = stats.completed === stats.total && stats.total > 0\n const hasBlocked = stats.blocked > 0\n\n return (\n <div className=\"todo-card\">\n {/* Header — clickable to toggle */}\n <div className=\"todo-header\" onClick={() => setExpanded(v => !v)} role=\"button\">\n <div className=\"todo-title\">\n <span className={`todo-header-arrow ${expanded ? 'expanded' : ''}`}>▸</span>\n <span className=\"todo-title-icon\">☰</span>\n <span className=\"todo-title-text\">{todo.title}</span>\n </div>\n\n {/* Collapsed: show current task status; Expanded: just show count */}\n {!expanded && (\n <div className=\"todo-header-status\">\n {isAllDone ? (\n <span className=\"todo-header-done\">✓ 已完成</span>\n ) : hasBlocked ? (\n <span className=\"todo-header-blocked\">⚠ {stats.blocked} 项阻塞</span>\n ) : current ? (\n <>\n <span className=\"todo-header-current-sep\">→</span>\n <span className=\"todo-header-current\">{current.description}</span>\n </>\n ) : null}\n </div>\n )}\n\n <span className=\"todo-header-count\">\n 已完成 {stats.completed}/{stats.total}\n </span>\n </div>\n\n {/* Progress bar — always visible */}\n <div className=\"todo-progress-bar\">\n <div\n className=\"todo-progress-fill\"\n style={{ width: `${progress * 100}%` }}\n />\n </div>\n\n {/* Expandable body */}\n {expanded && (\n <>\n {/* Task list */}\n <div className=\"todo-list\">\n {visibleTasks.map((task, i) => (\n <TaskRow key={task.id || i} task={task} />\n ))}\n </div>\n\n {/* Truncation */}\n {!showAll && hiddenCount > 0 && (\n <div className=\"todo-more\" onClick={() => setShowAll(true)}>\n + {hiddenCount} more\n </div>\n )}\n </>\n )}\n </div>\n )\n}\n\n// ========== Multi-todo wrapper ==========\n\nexport const TodoCardMulti: React.FC<{\n todoMap: Map<string, TodoData>\n compact?: boolean\n}> = ({ todoMap, compact = false }) => {\n const entries = useMemo(() => Array.from(todoMap.entries()), [todoMap])\n const [activeId, setActiveId] = useState<string | null>(null)\n\n if (entries.length === 0) return null\n\n // Single todo — no selector\n if (entries.length === 1) {\n return <TodoCard todo={entries[0][1]} compact={compact} />\n }\n\n const selectedId = activeId || entries[entries.length - 1][0]\n const selectedTodo = todoMap.get(selectedId)\n\n if (compact) {\n return (\n <div className=\"todo-multi-compact\">\n {entries.map(([id, todo]) => (\n <TodoCardCompact key={id} todo={todo} />\n ))}\n </div>\n )\n }\n\n return (\n <div className=\"todo-card\">\n {/* Multi-todo selector */}\n <div className=\"todo-multi-tabs\">\n {entries.map(([id, todo]) => (\n <button\n key={id}\n className={`todo-tab ${id === selectedId ? 'active' : ''}`}\n onClick={() => setActiveId(id)}\n >\n {todo.title}\n <span className=\"todo-tab-progress\">\n {todo.stats.completed}/{todo.stats.total}\n </span>\n\n </button>\n ))}\n </div>\n\n {selectedTodo && <TodoCard todo={selectedTodo} />}\n </div>\n )\n}\n\nexport default TodoCard\n","/**\n * 轮次标题组件\n * 在消息流中显示非置顶轮次的用户消息和计划\n */\n\nimport React from 'react'\nimport type { RoundHeaderProps } from '../types'\nimport PlanCard from './PlanCard'\nimport { TodoCardMulti } from './TodoCard'\nimport './RoundHeader.css'\n\nconst RoundHeader: React.FC<RoundHeaderProps> = ({ \n round, \n isPinned,\n todoMap,\n}) => {\n const statusLabels = {\n running: { icon: '⏳', text: '执行中', className: 'running' },\n completed: { icon: '✓', text: '已完成', className: 'completed' },\n error: { icon: '✗', text: '执行失败', className: 'error' },\n }\n\n const status = statusLabels[round.status]\n const hasTodo = todoMap && todoMap.size > 0\n\n return (\n <div className={`round-header ${isPinned ? 'pinned' : ''}`}>\n <div className=\"round-header-title\">\n <div className=\"user-avatar\">\n <span className=\"avatar-icon\">👤</span>\n <span className=\"user-message-text\">{round.userMessage || '(无消息)'}</span>\n </div>\n <span className={`round-status ${status.className}`}>\n {status.icon} {status.text}\n </span>\n </div>\n {hasTodo && <TodoCardMulti todoMap={todoMap} compact />}\n {!hasTodo && round.plan && (\n <PlanCard plan={round.plan} status={round.status} compact />\n )}\n </div>\n )\n}\n\nexport default RoundHeader\n","/**\n * 消息内容组件\n * 根据消息类型渲染不同的内容\n * 文本类型使用 Streamdown 渲染 Markdown(代码高亮、Mermaid、数学公式、CJK)\n * 保留逐字打字机效果:将逐步展开的文本交给 Streamdown 渲染\n */\n\nimport React, { useEffect, useState, useRef, memo } from 'react'\nimport { Streamdown } from 'streamdown'\nimport { code } from '@streamdown/code'\nimport { mermaid } from '@streamdown/mermaid'\nimport { createMathPlugin } from '@streamdown/math'\nimport { cjk } from '@streamdown/cjk'\nimport type { MessageContentProps } from '../types'\nimport SchemaFormRenderer from './SchemaFormRenderer'\nimport ToolCardBuffering from './ToolCardBuffering'\nimport './MessageContent.css'\n\nconst math = createMathPlugin({ singleDollarTextMath: true })\nconst streamdownPlugins = { code, mermaid, math, cjk }\n\n/**\n * 计算文本中某个定界符的非重叠出现次数\n */\nfunction countOccurrences(text: string, needle: string): number {\n let count = 0\n let pos = 0\n while (pos < text.length) {\n const idx = text.indexOf(needle, pos)\n if (idx === -1) break\n count++\n pos = idx + needle.length\n }\n return count\n}\n\n/**\n * 将裸 displayedLength 对齐到 Markdown 安全边界,\n * 避免在代码围栏语言名、数学公式中间截断。\n *\n * 规则:\n * 1. ``` 代码围栏行 → 跳到行尾(保护语言名)\n * 2. 正在凑齐 ``` → 跳到行尾\n * 3. $$ 块公式内 → 跳到闭合 $$ 之后(整块一次展示)\n * 4. $ 行内公式内 → 跳到闭合 $ 之后(整个公式一次展示)\n */\nfunction snapToSafeBoundary(content: string, length: number): number {\n if (length >= content.length) return content.length\n if (length === 0) return 0\n\n const slice = content.slice(0, length)\n const lastNL = slice.lastIndexOf('\\n')\n const currentLine = slice.slice(lastNL + 1)\n\n // ── 代码围栏 ──\n if (/^`{3,}/.test(currentLine)) {\n const lineEnd = content.indexOf('\\n', lastNL + 1)\n return lineEnd !== -1 ? lineEnd + 1 : content.length\n }\n\n if (/`{1,2}$/.test(currentLine) && length < content.length && content[length] === '`') {\n const lineEnd = content.indexOf('\\n', lastNL + 1)\n return lineEnd !== -1 ? lineEnd + 1 : content.length\n }\n\n // ── $$ 块公式 ──\n\n // 切点在 $ 上且下一个也是 $ → 先凑齐 $$ 再重新检查\n if (slice.endsWith('$') && length < content.length && content[length] === '$') {\n return snapToSafeBoundary(content, length + 1)\n }\n\n // $$ 出现奇数次 → 在未闭合块内 → 跳到闭合 $$\n const ddCount = countOccurrences(slice, '$$')\n if (ddCount % 2 === 1) {\n const closeIdx = content.indexOf('$$', length)\n if (closeIdx !== -1) {\n return Math.min(closeIdx + 2, content.length)\n }\n }\n\n // ── $ 行内公式 ──\n // 排除已处理的 $$(它们已被上面的逻辑处理)\n // 统计单独的 $ 符号:总 $ 数 - 2 * $$ 数\n // 如果结果为奇数 → 在未闭合的行内公式内 → 跳到闭合 $\n const totalDollars = countOccurrences(slice, '$')\n const singleDollars = totalDollars - 2 * ddCount\n if (singleDollars % 2 === 1) {\n // 找下一个不是 $$ 的单独 $\n let searchPos = length\n while (searchPos < content.length) {\n const idx = content.indexOf('$', searchPos)\n if (idx === -1) break\n // 如果是 $$(块公式),跳过\n if (idx + 1 < content.length && content[idx + 1] === '$') {\n searchPos = idx + 2\n continue\n }\n // 如果前一个字符也是 $,跳过(这是 $$ 的第二个 $)\n if (idx > 0 && content[idx - 1] === '$') {\n searchPos = idx + 1\n continue\n }\n return Math.min(idx + 1, content.length)\n }\n }\n\n return length\n}\n\n/**\n * 打字机 hook:基于 requestAnimationFrame 追赶模式逐字展开内容。\n * 自动对齐到 Markdown 安全边界,不会截断代码围栏语言名。\n * 返回 [displayedContent, isTyping]\n */\nfunction useTypewriter(\n content: string,\n enabled: boolean,\n speed: number = 30,\n): [string, boolean] {\n const [displayedLength, setDisplayedLength] = useState(0)\n const [isTyping, setIsTyping] = useState(false)\n const rafRef = useRef<number | null>(null)\n const targetLengthRef = useRef(0)\n const displayedLengthRef = useRef(0)\n\n displayedLengthRef.current = displayedLength\n\n useEffect(() => {\n if (!enabled) {\n setDisplayedLength(content.length)\n targetLengthRef.current = content.length\n return\n }\n\n targetLengthRef.current = content.length\n\n if (rafRef.current) return\n if (displayedLengthRef.current >= content.length) return\n\n setIsTyping(true)\n let lastTime = performance.now()\n\n const animate = (currentTime: number) => {\n const deltaTime = currentTime - lastTime\n lastTime = currentTime\n\n const charsToAdd = Math.max(1, Math.ceil(deltaTime / speed))\n const currentDisplayed = displayedLengthRef.current\n const target = targetLengthRef.current\n const raw = Math.min(currentDisplayed + charsToAdd, target)\n const newLength = snapToSafeBoundary(content, raw)\n\n setDisplayedLength(newLength)\n displayedLengthRef.current = newLength\n\n if (newLength >= target) {\n setIsTyping(false)\n rafRef.current = null\n } else {\n rafRef.current = requestAnimationFrame(animate)\n }\n }\n\n rafRef.current = requestAnimationFrame(animate)\n\n return () => {\n if (rafRef.current) {\n cancelAnimationFrame(rafRef.current)\n rafRef.current = null\n }\n }\n }, [content, enabled, speed])\n\n return [content.slice(0, displayedLength), isTyping]\n}\n\nconst MessageContent: React.FC<MessageContentProps> = memo(({\n message,\n enableTypewriter = true,\n typewriterSpeed = 30,\n onArtifactClick,\n}) => {\n const content = message.contentChunks.join('')\n const isTextType = message.contentType === 'text'\n\n const [displayedContent, isTyping] = useTypewriter(\n content,\n enableTypewriter && isTextType,\n typewriterSpeed,\n )\n\n // 思考过程\n if (message.contentType === 'think') {\n return (\n <ThinkChunk content={content} isThinking={isTyping} />\n )\n }\n\n // HITL 等待表单\n if (message.contentType === 'json_schema_wait' || message.contentType === 'json_schema' || message.contentType === 'html_schema') {\n return (\n <HITLWaitCard content={content} hitlRequest={message.hitlRequest} />\n )\n }\n\n // 产出物\n if (message.contentType === 'artifact' && (message.artifacts || message.artifact)) {\n const artifacts = message.artifacts || (message.artifact ? [message.artifact] : [])\n return (\n <div className=\"artifact-list\">\n {artifacts.map((artifact, index) => (\n <ArtifactCard\n key={artifact.id || index}\n artifact={artifact}\n onClick={() => onArtifactClick?.(artifact)}\n />\n ))}\n </div>\n )\n }\n\n // JETP-010: toolPhase\n if (message.toolPhase) {\n return <ToolCardBuffering message={message} />\n }\n\n // MCP 工具事件\n const isMcpEvent = message.notificationType && ['mcp_start', 'mcp_result', 'mcp_end'].includes(message.notificationType)\n\n if (isMcpEvent) {\n const toolName = message.toolName || (() => {\n const match = content.match(/[🔧\\s]*(.+?)\\s*\\((\\w+)\\)/) || content.match(/[🔧\\s]*execute tool:\\s*(\\S+)/)\n return match ? (match[2] || match[1]) : null\n })()\n\n const toolLabelMatch = content.match(/[🔧\\s]*(.+?)\\s*\\(/)\n const toolLabel = toolLabelMatch ? toolLabelMatch[1].trim() : (message.taskPurpose || toolName || content)\n\n let statusIcon = '🔧'\n let statusClass = ''\n let statusText = ''\n\n if (message.notificationType === 'mcp_start') {\n statusIcon = '⏳'\n statusClass = 'tool-running'\n statusText = '执行中'\n } else if (message.notificationType === 'mcp_end') {\n if (message.toolStatus === 'error') {\n statusIcon = '❌'\n statusClass = 'tool-error'\n statusText = '失败'\n } else {\n statusIcon = '✅'\n statusClass = 'tool-success'\n statusText = '完成'\n }\n } else {\n statusIcon = '🔧'\n statusClass = 'tool-running'\n }\n\n return (\n <div className={`tool-execution ${statusClass}`}>\n <span className=\"tool-icon\">{statusIcon}</span>\n <span className=\"tool-text\">{toolLabel}{toolName && toolName !== toolLabel ? ` (${toolName})` : ''}</span>\n {statusText && <span className=\"tool-status\">{statusText}</span>}\n </div>\n )\n }\n\n // 降级:正则匹配旧格式工具行\n const toolLineRegex = /^[🔧\\s]*execute tool:\\s*(\\S+)\\s*$/m\n const toolMatch = content.match(toolLineRegex)\n\n if (toolMatch) {\n const toolName = toolMatch[1]\n const matchIndex = content.indexOf(toolMatch[0])\n const beforeContent = content.slice(0, matchIndex).trim()\n const afterContent = content.slice(matchIndex + toolMatch[0].length).trim()\n\n return (\n <>\n {beforeContent && (\n <div className=\"sd-message\">\n <Streamdown plugins={streamdownPlugins}>{beforeContent}</Streamdown>\n </div>\n )}\n <div className=\"tool-execution\">\n <span className=\"tool-icon\">🔧</span>\n <span className=\"tool-text\">执行工具: {toolName}</span>\n </div>\n {afterContent && (\n <div className=\"sd-message\">\n <Streamdown plugins={streamdownPlugins}>{afterContent}</Streamdown>\n </div>\n )}\n </>\n )\n }\n\n // 普通文本 → 打字机 + Streamdown 渲染\n return (\n <div className=\"sd-message\">\n <Streamdown\n plugins={streamdownPlugins}\n isAnimating={isTyping}\n >\n {displayedContent}\n </Streamdown>\n {isTyping && <span className=\"streaming-cursor\" />}\n </div>\n )\n})\n\n// 思考过程折叠块\nconst ThinkChunk: React.FC<{ content: string; isThinking?: boolean }> = ({ content, isThinking = false }) => {\n const [isExpanded, setIsExpanded] = useState(false)\n const [manualToggled, setManualToggled] = useState(false)\n const [prevContentLength, setPrevContentLength] = useState(0)\n const [thinking, setThinking] = useState(true)\n const previewRef = useRef<HTMLDivElement>(null)\n\n const isActive = thinking || isThinking\n\n const thinkingTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n useEffect(() => {\n if (content.length > prevContentLength) {\n setThinking(true)\n setPrevContentLength(content.length)\n if (thinkingTimerRef.current) {\n clearTimeout(thinkingTimerRef.current)\n thinkingTimerRef.current = null\n }\n }\n\n thinkingTimerRef.current = setTimeout(() => {\n if (content.length === prevContentLength) {\n setThinking(false)\n }\n }, 5000)\n\n return () => {\n if (thinkingTimerRef.current) {\n clearTimeout(thinkingTimerRef.current)\n }\n }\n }, [content, prevContentLength])\n\n useEffect(() => {\n if (previewRef.current && isActive && !isExpanded) {\n previewRef.current.scrollTop = previewRef.current.scrollHeight\n }\n }, [content, isActive, isExpanded])\n\n const extractHeading = (text: string): string | null => {\n const match = text.match(/^#\\s+(.+)$/m)\n return match ? match[1].trim() : null\n }\n\n const heading = extractHeading(content)\n const displayText = heading\n ? heading\n : (isActive ? '思考中...' : '思考完成')\n\n const showPreview = isActive && !manualToggled && !isExpanded && content.length > 0\n\n const [previewVisible, setPreviewVisible] = useState(false)\n useEffect(() => {\n if (showPreview) {\n setPreviewVisible(true)\n } else if (previewVisible) {\n const t = setTimeout(() => setPreviewVisible(false), 600)\n return () => clearTimeout(t)\n }\n }, [showPreview]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const handleToggle = () => {\n setManualToggled(true)\n setPreviewVisible(false)\n setIsExpanded(!isExpanded)\n }\n\n return (\n <div className={`think-chunk ${isExpanded ? 'expanded' : ''} ${isActive ? 'thinking' : ''}`}>\n <div\n className=\"think-header\"\n onClick={handleToggle}\n >\n <div className=\"think-title\">\n <span className={`think-icon ${isActive ? 'thinking-animation' : ''}`}>💭</span>\n <span className=\"think-text\">{displayText}</span>\n {isActive && <span className=\"thinking-dots\"><span>.</span><span>.</span><span>.</span></span>}\n </div>\n <span className={`collapse-arrow ${(isExpanded || previewVisible) ? 'expanded' : ''}`}>\n ▼\n </span>\n </div>\n <div\n className={`think-preview ${previewVisible ? 'think-preview-open' : 'think-preview-closed'}`}\n ref={previewRef}\n >\n <div className=\"sd-think\">\n <Streamdown plugins={streamdownPlugins} isAnimating={isActive}>\n {content}\n </Streamdown>\n </div>\n </div>\n {isExpanded && (\n <div className=\"think-content\">\n <div className=\"sd-think\">\n <Streamdown plugins={streamdownPlugins}>\n {content}\n </Streamdown>\n </div>\n </div>\n )}\n </div>\n )\n}\n\n// HITL 等待卡片\nconst HITLWaitCard: React.FC<{\n content: string\n hitlRequest?: MessageContentProps['message']['hitlRequest']\n}> = ({ content, hitlRequest }) => {\n const parseFirstJson = (str: string): unknown | null => {\n try {\n return JSON.parse(str)\n } catch {\n let depth = 0\n let start = -1\n for (let i = 0; i < str.length; i++) {\n if (str[i] === '{') {\n if (depth === 0) start = i\n depth++\n } else if (str[i] === '}') {\n depth--\n if (depth === 0 && start !== -1) {\n try {\n return JSON.parse(str.slice(start, i + 1))\n } catch {\n start = -1\n }\n }\n }\n }\n return null\n }\n }\n\n const getDisplayText = (): string => {\n const parsed = parseFirstJson(content) as Record<string, unknown> | null\n if (!parsed) {\n return content || '等待用户输入...'\n }\n\n if (parsed.content !== undefined) {\n let langContent = parsed.content\n\n if (typeof langContent === 'string') {\n try {\n langContent = JSON.parse(langContent)\n } catch {\n return (langContent as string) || '等待用户输入...'\n }\n }\n\n if (typeof langContent === 'object' && langContent !== null) {\n const langObj = langContent as Record<string, string>\n return langObj.zh_CN || langObj.en_US || JSON.stringify(langContent)\n }\n return String(langContent) || '等待用户输入...'\n }\n if (parsed.zh_CN || parsed.en_US) {\n return (parsed.zh_CN || parsed.en_US) as string\n }\n if (parsed.type && (parsed.props as Record<string, unknown>)?.title) {\n return (parsed.props as Record<string, string>).title\n }\n return content\n }\n\n const getFormSchema = (): object | null => {\n const parsed = parseFirstJson(content) as Record<string, unknown> | null\n if (parsed) {\n if (parsed.type && (parsed.children || parsed.props)) {\n return parsed\n }\n }\n if (hitlRequest?.schema) {\n return hitlRequest.schema as object\n }\n return null\n }\n\n const displayText = getDisplayText()\n const formSchema = getFormSchema()\n\n if (formSchema) {\n const schemaObj = formSchema as Record<string, unknown>\n const title = (schemaObj.props as Record<string, unknown>)?.title as string || hitlRequest?.title || '请填写表单'\n\n const handleFormSubmit = (values: Record<string, unknown>) => {\n console.log('[HITL] 表单提交:', values, 'await_command_uuid:', hitlRequest?.await_command_uuid)\n }\n\n return (\n <div className=\"hitl-form-card\">\n <div className=\"hitl-form-header\">\n <span className=\"hitl-form-icon\">📋</span>\n <span className=\"hitl-form-title\">{title}</span>\n </div>\n <div className=\"hitl-form-body\">\n <SchemaFormRenderer\n schema={formSchema as Parameters<typeof SchemaFormRenderer>[0]['schema']}\n onSubmit={handleFormSubmit}\n awaitCommandUuid={hitlRequest?.await_command_uuid}\n />\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"hitl-wait-card\">\n <div className=\"hitl-icon\">⏳</div>\n <div className=\"hitl-content\">\n <div className=\"hitl-text\">{displayText}</div>\n {hitlRequest?.await_command_uuid && (\n <div className=\"hitl-uuid\">ID: {hitlRequest.await_command_uuid.slice(0, 8)}...</div>\n )}\n </div>\n </div>\n )\n}\n\n// 产出物卡片\nconst ArtifactCard: React.FC<{\n artifact: NonNullable<MessageContentProps['message']['artifact']>\n onClick?: () => void\n}> = ({ artifact, onClick }) => {\n const iconMap: Record<string, string> = {\n 'text/markdown': '📝',\n 'text/plain': '📄',\n 'application/json': '📊',\n 'image/': '🖼️',\n 'application/pdf': '📕',\n }\n\n const icon = Object.entries(iconMap).find(([type]) =>\n artifact.type.startsWith(type)\n )?.[1] || '📎'\n\n return (\n <div className=\"artifact-card\" onClick={onClick}>\n <span className=\"artifact-icon\">{icon}</span>\n <div className=\"artifact-info\">\n <div className=\"artifact-name\">{artifact.name}</div>\n <div className=\"artifact-meta\">{artifact.type}</div>\n </div>\n {artifact.size && (\n <span className=\"artifact-size\">{artifact.size}</span>\n )}\n </div>\n )\n}\n\nexport default MessageContent\n","/**\n * Schema 表单渲染器\n * 根据 JSON schema 动态生成表单 UI\n */\n\nimport React, { useState, useCallback } from 'react'\nimport './SchemaFormRenderer.css'\n\n// Schema 节点类型定义\ninterface SchemaNode {\n type: string\n key?: string\n name?: string\n props?: Record<string, unknown>\n children?: SchemaNode[]\n options?: Array<{ label: string; value: string }>\n rules?: Array<{ required?: boolean; message?: string }>\n schema?: SchemaNode // FormChunk 的嵌套 schema\n}\n\ninterface SchemaFormRendererProps {\n schema: SchemaNode\n onSubmit?: (values: Record<string, unknown>) => void | Promise<void>\n awaitCommandUuid?: string\n}\n\n// 递归渲染 schema 节点\nconst renderNode = (\n node: SchemaNode,\n values: Record<string, unknown>,\n onChange: (name: string, value: unknown) => void,\n errors: Record<string, string>\n): React.ReactNode => {\n if (!node) return null\n\n const { type, key, name, props, children, options, schema } = node\n const nodeKey = key || name || Math.random().toString()\n\n switch (type) {\n case 'Card':\n return (\n <div key={nodeKey} className=\"schema-card\">\n {children?.map((child) => renderNode(child, values, onChange, errors))}\n </div>\n )\n\n case 'FormChunk':\n // FormChunk 包含嵌套的 schema\n if (schema) {\n return renderNode(schema, values, onChange, errors)\n }\n return children?.map((child) => renderNode(child, values, onChange, errors))\n\n case 'Form':\n return (\n <div key={nodeKey} className=\"schema-form\">\n {children?.map((child) => renderNode(child, values, onChange, errors))}\n </div>\n )\n\n case 'FormItem': {\n const label = (props?.label as string) || ''\n const required = node.rules?.some(r => r.required)\n const error = name ? errors[name] : undefined\n \n return (\n <div key={nodeKey} className={`schema-form-item ${error ? 'has-error' : ''}`}>\n <label className=\"schema-form-label\">\n {required && <span className=\"required-mark\">*</span>}\n {label}\n </label>\n <div className=\"schema-form-control\">\n {children?.map((child) => renderNode(\n { ...child, name: name || child.name },\n values,\n onChange,\n errors\n ))}\n </div>\n {error && <div className=\"schema-form-error\">{error}</div>}\n </div>\n )\n }\n\n case 'RadioGroup': {\n const fieldName = name || ''\n const currentValue = values[fieldName] as string | undefined\n \n return (\n <div key={nodeKey} className=\"schema-radio-group\">\n {options?.map((option) => (\n <label key={option.value} className=\"schema-radio-option\">\n <input\n type=\"radio\"\n name={fieldName}\n value={option.value}\n checked={currentValue === option.value}\n onChange={() => onChange(fieldName, option.value)}\n />\n <span className=\"radio-checkmark\"></span>\n <span className=\"radio-label\">{option.label}</span>\n </label>\n ))}\n </div>\n )\n }\n\n case 'CheckboxGroup': {\n const fieldName = name || ''\n const currentValues = (values[fieldName] as string[]) || []\n \n return (\n <div key={nodeKey} className=\"schema-checkbox-group\">\n {options?.map((option) => (\n <label key={option.value} className=\"schema-checkbox-option\">\n <input\n type=\"checkbox\"\n value={option.value}\n checked={currentValues.includes(option.value)}\n onChange={(e) => {\n const newValues = e.target.checked\n ? [...currentValues, option.value]\n : currentValues.filter(v => v !== option.value)\n onChange(fieldName, newValues)\n }}\n />\n <span className=\"checkbox-checkmark\"></span>\n <span className=\"checkbox-label\">{option.label}</span>\n </label>\n ))}\n </div>\n )\n }\n\n case 'Input': {\n const fieldName = name || ''\n const placeholder = (props?.placeholder as string) || ''\n \n return (\n <input\n key={nodeKey}\n type=\"text\"\n className=\"schema-input\"\n placeholder={placeholder}\n value={(values[fieldName] as string) || ''}\n onChange={(e) => onChange(fieldName, e.target.value)}\n />\n )\n }\n\n case 'TextArea': {\n const fieldName = name || ''\n const placeholder = (props?.placeholder as string) || ''\n const rows = (props?.rows as number) || 3\n \n return (\n <textarea\n key={nodeKey}\n className=\"schema-textarea\"\n placeholder={placeholder}\n rows={rows}\n value={(values[fieldName] as string) || ''}\n onChange={(e) => onChange(fieldName, e.target.value)}\n />\n )\n }\n\n case 'Select': {\n const fieldName = name || ''\n const placeholder = (props?.placeholder as string) || '请选择'\n \n return (\n <select\n key={nodeKey}\n className=\"schema-select\"\n value={(values[fieldName] as string) || ''}\n onChange={(e) => onChange(fieldName, e.target.value)}\n >\n <option value=\"\" disabled>{placeholder}</option>\n {options?.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n )\n }\n\n default:\n // 对于未知类型,尝试渲染子节点\n if (children && children.length > 0) {\n return children.map((child) => renderNode(child, values, onChange, errors))\n }\n return null\n }\n}\n\n// 从 schema 中提取所有表单字段的规则\nconst extractRules = (node: SchemaNode): Record<string, Array<{ required?: boolean; message?: string }>> => {\n const rules: Record<string, Array<{ required?: boolean; message?: string }>> = {}\n \n const traverse = (n: SchemaNode) => {\n if (n.name && n.rules) {\n rules[n.name] = n.rules\n }\n if (n.children) {\n n.children.forEach(traverse)\n }\n if (n.schema) {\n traverse(n.schema)\n }\n }\n \n traverse(node)\n return rules\n}\n\nconst SchemaFormRenderer: React.FC<SchemaFormRendererProps> = ({\n schema,\n onSubmit,\n awaitCommandUuid,\n}) => {\n const [values, setValues] = useState<Record<string, unknown>>({})\n const [errors, setErrors] = useState<Record<string, string>>({})\n const [isSubmitting, setIsSubmitting] = useState(false)\n\n const handleChange = useCallback((name: string, value: unknown) => {\n setValues(prev => ({ ...prev, [name]: value }))\n // 清除对应字段的错误\n setErrors(prev => {\n const newErrors = { ...prev }\n delete newErrors[name]\n return newErrors\n })\n }, [])\n\n const validate = useCallback((): boolean => {\n const rules = extractRules(schema)\n const newErrors: Record<string, string> = {}\n \n Object.entries(rules).forEach(([fieldName, fieldRules]) => {\n fieldRules.forEach(rule => {\n if (rule.required) {\n const value = values[fieldName]\n const isEmpty = value === undefined || value === null || value === '' ||\n (Array.isArray(value) && value.length === 0)\n if (isEmpty) {\n newErrors[fieldName] = rule.message || '此项为必填项'\n }\n }\n })\n })\n \n setErrors(newErrors)\n return Object.keys(newErrors).length === 0\n }, [schema, values])\n\n const handleSubmit = useCallback(async () => {\n if (!validate()) return\n \n setIsSubmitting(true)\n try {\n await onSubmit?.(values)\n } finally {\n setIsSubmitting(false)\n }\n }, [validate, values, onSubmit])\n\n return (\n <div className=\"schema-form-renderer\">\n {renderNode(schema, values, handleChange, errors)}\n \n <div className=\"schema-form-actions\">\n <button\n className=\"schema-submit-btn\"\n onClick={handleSubmit}\n disabled={isSubmitting}\n >\n {isSubmitting ? '提交中...' : '提交'}\n </button>\n </div>\n \n {awaitCommandUuid && (\n <div className=\"schema-form-meta\">\n <span className=\"meta-uuid\">请求 ID: {awaitCommandUuid.slice(0, 8)}...</span>\n </div>\n )}\n </div>\n )\n}\n\nexport default SchemaFormRenderer\n","import React, { useMemo, useRef, memo } from 'react'\nimport type { AggregatedMessage } from '../types'\nimport { parseArgsIncremental, phaseConfig } from './renderers/utils'\nimport type { ParseCache } from './renderers/utils'\nimport ContentRenderer from './renderers/ContentRenderer'\nimport CommandRenderer from './renderers/CommandRenderer'\nimport BrowserRenderer from './renderers/BrowserRenderer'\nimport QueryRenderer from './renderers/QueryRenderer'\nimport PathRenderer from './renderers/PathRenderer'\nimport TriggerRenderer from './renderers/TriggerRenderer'\nimport ThinkingRenderer from './renderers/ThinkingRenderer'\nimport ParamsRenderer from './renderers/ParamsRenderer'\nimport ToolResultRenderer from './renderers/ToolResultRenderer'\nimport type { RendererProps } from './renderers/types'\nimport './ToolCardBuffering.css'\nimport './renderers/renderers.css'\n\nconst renderers: Record<string, React.FC<RendererProps>> = {\n content: ContentRenderer,\n command: CommandRenderer,\n browser: BrowserRenderer,\n query: QueryRenderer,\n path: PathRenderer,\n trigger: TriggerRenderer,\n thinking: ThinkingRenderer,\n params: ParamsRenderer,\n}\n\ninterface ToolCardBufferingProps {\n message: AggregatedMessage\n}\n\nconst ToolCardBuffering: React.FC<ToolCardBufferingProps> = memo(({ message }) => {\n const phase = message.toolPhase || 'generating'\n const config = phaseConfig[phase]\n const uiConfig = message.uiConfig || { display_type: 'params' as const }\n const parseCacheRef = useRef<ParseCache | null>(null)\n const parsedArgs = useMemo(\n () => parseArgsIncremental(message.argsPreview, parseCacheRef),\n [message.argsPreview],\n )\n\n const displayType = uiConfig.display_type || 'params'\n const Renderer = renderers[displayType] || ParamsRenderer\n\n // mcp_result 内容(存在 contentChunks 中)\n const resultContent = message.contentChunks.join('')\n const hasResult = resultContent.trim().length > 0\n\n return (\n <div className={`tool-card-buffering ${config.className}`}>\n <Renderer\n message={message}\n uiConfig={uiConfig}\n parsedArgs={parsedArgs}\n phase={phase}\n />\n {hasResult && (\n <ToolResultRenderer content={resultContent} />\n )}\n </div>\n )\n})\n\nexport default ToolCardBuffering\n","import React from 'react'\n\n/**\n * 增量解析缓存:记录上一次 parsePartialJson 的结果,\n * 使后续 argsPreview 增长时只需从截断位置 slice,不必重头扫描。\n */\nexport interface ParseCache {\n stableFields: Record<string, any> // 已完成(非截断)的字段\n truncatedKey: string | null // 最后一个截断字段的 key\n truncatedValueStart: number // 截断字段的值在 raw 中的起始偏移(引号后第一个字符)\n lastArgsLen: number // 上次 argsPreview 的长度\n}\n\n/**\n * 增量版 parseArgs:利用 ParseCache 避免 O(N²) 重复扫描。\n *\n * argsPreview 是 append-only 的(模型流式输出只追加字符),\n * 因此一旦 stable 字段被解析且截断字段的起始位置被记录,\n * 后续更新只需 slice + decodeJsonEscapes 即可 —— O(delta) 而非 O(N)。\n */\nexport function parseArgsIncremental(\n argsPreview: string | undefined,\n cache: React.MutableRefObject<ParseCache | null>,\n): Record<string, any> | null {\n if (!argsPreview) return null\n\n // JSON 完整时(工具参数输出完毕)直接用原生解析\n try {\n cache.current = null\n return JSON.parse(argsPreview)\n } catch {\n // 继续增量/部分解析\n }\n\n const prev = cache.current\n\n // 增量路径:argsPreview 只是追加了新字节,截断字段位置不变\n if (prev && prev.truncatedKey && prev.truncatedValueStart > 0\n && argsPreview.length > prev.lastArgsLen) {\n prev.lastArgsLen = argsPreview.length\n const rawValue = argsPreview.slice(prev.truncatedValueStart)\n return { ...prev.stableFields, [prev.truncatedKey]: decodeJsonEscapes(rawValue) }\n }\n\n // 首次完整扫描(或缓存失效)\n const meta = parsePartialJsonWithMeta(argsPreview)\n if (!meta) return null\n\n // 构建缓存\n const stableFields = { ...meta.fields }\n if (meta.truncatedKey) {\n delete stableFields[meta.truncatedKey]\n }\n cache.current = {\n stableFields,\n truncatedKey: meta.truncatedKey,\n truncatedValueStart: meta.truncatedValueStart,\n lastArgsLen: argsPreview.length,\n }\n\n return meta.fields\n}\n\nexport function parseArgs(argsPreview: string | undefined): Record<string, any> | null {\n if (!argsPreview) return null\n try {\n return JSON.parse(argsPreview)\n } catch {\n return parsePartialJson(argsPreview)\n }\n}\n\ninterface PartialParseMeta {\n fields: Record<string, any>\n truncatedKey: string | null\n truncatedValueStart: number\n}\n\n/**\n * 带元数据的部分 JSON 解析。\n * 除了提取字段值外,还记录最后一个截断字段的 key 和值起始偏移,\n * 供 parseArgsIncremental 做增量更新。\n */\nfunction parsePartialJsonWithMeta(raw: string): PartialParseMeta | null {\n const fields: Record<string, any> = {}\n let i = raw.indexOf('{')\n if (i < 0) return null\n i++\n\n let foundAny = false\n let truncatedKey: string | null = null\n let truncatedValueStart = -1\n\n while (i < raw.length) {\n while (i < raw.length && ' \\t\\r\\n,'.includes(raw[i])) i++\n if (i >= raw.length || raw[i] === '}') break\n\n if (raw[i] !== '\"') break\n const keyEnd = findClosingQuote(raw, i)\n if (keyEnd < 0) break\n const key = raw.slice(i + 1, keyEnd)\n i = keyEnd + 1\n\n while (i < raw.length && ' \\t\\r\\n'.includes(raw[i])) i++\n if (i >= raw.length || raw[i] !== ':') break\n i++\n while (i < raw.length && ' \\t\\r\\n'.includes(raw[i])) i++\n if (i >= raw.length) break\n\n // 记录值的起始位置(对于字符串,跳过开头引号)\n const valueStartPos = (raw[i] === '\"') ? i + 1 : i\n\n const [value, nextPos, complete] = parseValue(raw, i)\n if (value !== undefined) {\n fields[key] = value\n foundAny = true\n }\n if (!complete) {\n truncatedKey = key\n truncatedValueStart = valueStartPos\n break\n }\n i = nextPos\n }\n\n return foundAny ? { fields, truncatedKey, truncatedValueStart } : null\n}\n\n/**\n * 容错解析不完整的 JSON 字符串(streaming 阶段截断场景)。\n * 保留向后兼容,供非增量场景使用。\n */\nfunction parsePartialJson(raw: string): Record<string, any> | null {\n const meta = parsePartialJsonWithMeta(raw)\n return meta ? meta.fields : null\n}\n\n/**\n * 解码 JSON 字符串中的转义序列。\n * 在 streaming 阶段 parsePartialJson 无法使用 JSON.parse,\n * 因此需要手动解码 \\n \\t \\\" \\\\ 等转义,以确保 content 字段的\n * 换行符被正确还原,否则 split('\\n') 无法正常拆行。\n */\nfunction decodeJsonEscapes(raw: string): string {\n let result = ''\n let i = 0\n while (i < raw.length) {\n if (raw[i] === '\\\\' && i + 1 < raw.length) {\n const next = raw[i + 1]\n switch (next) {\n case 'n': result += '\\n'; break\n case 't': result += '\\t'; break\n case 'r': result += '\\r'; break\n case '\"': result += '\"'; break\n case '\\\\': result += '\\\\'; break\n case '/': result += '/'; break\n default: result += '\\\\' + next; break\n }\n i += 2\n } else {\n result += raw[i]\n i++\n }\n }\n return result\n}\n\nfunction findClosingQuote(s: string, openPos: number): number {\n let i = openPos + 1\n while (i < s.length) {\n if (s[i] === '\\\\') { i += 2; continue }\n if (s[i] === '\"') return i\n i++\n }\n return -1\n}\n\n/** Returns [value, nextPosition, isComplete] */\nfunction parseValue(s: string, pos: number): [any, number, boolean] {\n if (pos >= s.length) return [undefined, pos, false]\n const ch = s[pos]\n\n if (ch === '\"') {\n const end = findClosingQuote(s, pos)\n if (end < 0) {\n // truncated string — decode escape sequences so \\n becomes real newlines\n return [decodeJsonEscapes(s.slice(pos + 1)), s.length, false]\n }\n try {\n const val = JSON.parse(s.slice(pos, end + 1))\n return [val, end + 1, true]\n } catch {\n return [decodeJsonEscapes(s.slice(pos + 1, end)), end + 1, true]\n }\n }\n\n // number / boolean / null — scan until delimiter\n if ('-0123456789'.includes(ch)) {\n let end = pos + 1\n while (end < s.length && '0123456789.eE+-'.includes(s[end])) end++\n const numStr = s.slice(pos, end)\n const num = Number(numStr)\n if (!isNaN(num) && numStr.length > 0) return [num, end, true]\n return [undefined, end, end < s.length]\n }\n\n if (s.startsWith('true', pos)) return [true, pos + 4, true]\n if (s.startsWith('false', pos)) return [false, pos + 5, true]\n if (s.startsWith('null', pos)) return [null, pos + 4, true]\n\n // nested object or array — try to find balanced close, otherwise skip\n if (ch === '{' || ch === '[') {\n const close = ch === '{' ? '}' : ']'\n let depth = 1, j = pos + 1, inStr = false\n while (j < s.length && depth > 0) {\n if (inStr) {\n if (s[j] === '\\\\') { j += 2; continue }\n if (s[j] === '\"') inStr = false\n } else {\n if (s[j] === '\"') inStr = true\n else if (s[j] === ch) depth++\n else if (s[j] === close) depth--\n }\n j++\n }\n if (depth === 0) {\n try {\n return [JSON.parse(s.slice(pos, j)), j, true]\n } catch {\n return [s.slice(pos, j), j, true]\n }\n }\n return [undefined, j, false] // truncated nested structure\n }\n\n return [undefined, pos + 1, false]\n}\n\nexport function extractField(\n args: Record<string, any> | null,\n fieldName: string | undefined\n): any {\n if (!args || !fieldName) return undefined\n return args[fieldName]\n}\n\nexport function formatValue(value: any): string {\n if (value === undefined || value === null) return ''\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'boolean') return String(value)\n return JSON.stringify(value, null, 2)\n}\n\nexport function buildCompactTags(\n args: Record<string, any> | null,\n compactFields: string[] | undefined,\n hideFields: string[] | undefined\n): Array<{ key: string; value: string }> {\n if (!args || !compactFields) return []\n const hidden = new Set(hideFields || [])\n return compactFields\n .filter(f => !hidden.has(f) && args[f] !== undefined)\n .map(f => ({ key: f, value: formatValue(args[f]) }))\n}\n\nexport const phaseConfig = {\n generating: { icon: '⚙️', label: '生成中', className: 'phase-generating' },\n executing: { icon: '⏳', label: '执行中', className: 'phase-executing' },\n complete: { icon: '✅', label: '完成', className: 'phase-complete' },\n error: { icon: '❌', label: '失败', className: 'phase-error' },\n} as const\n\nexport const PhaseLabel: React.FC<{ phase: string }> = ({ phase }) => {\n const cfg = phaseConfig[phase as keyof typeof phaseConfig]\n return (\n <span className=\"tool-phase-label\">\n {cfg?.label || phase}\n {phase === 'generating' && (\n <span className=\"tool-card-dots\"><span /><span /><span /></span>\n )}\n </span>\n )\n}\n\nexport const CompactTags: React.FC<{ tags: Array<{ key: string; value: string }> }> = ({ tags }) => (\n <div className=\"compact-tags\">\n {tags.slice(0, 5).map(t => (\n <span key={t.key} className=\"compact-tag\">{t.key}: {t.value}</span>\n ))}\n {tags.length > 5 && <span className=\"compact-tag\">+{tags.length - 5}</span>}\n </div>\n)\n","import React, { useState, useMemo } from 'react'\nimport type { RendererProps } from './types'\nimport { extractField, formatValue, PhaseLabel } from './utils'\n\nconst MAX_PREVIEW_LINES = 2\n\nconst ContentRenderer: React.FC<RendererProps> = ({ message, uiConfig, parsedArgs, phase }) => {\n const [expanded, setExpanded] = useState(false)\n const headerValue = extractField(parsedArgs, uiConfig.header_field)\n const primaryValue = extractField(parsedArgs, uiConfig.primary_field)\n const toolName = message.toolName || 'tool'\n const taskPurpose = message.taskPurpose\n const isEdit = toolName === 'edit' || toolName === 'edit_block'\n const contentStr = primaryValue ? formatValue(primaryValue) : ''\n const hasContent = contentStr.length > 0\n const isGenerating = phase === 'generating'\n\n const shortPath = useMemo(() => {\n if (!headerValue) return undefined\n const full = String(headerValue)\n const parts = full.split('/')\n return parts.length > 2 ? `.../${parts.slice(-2).join('/')}` : full\n }, [headerValue])\n\n const { previewLines, totalLines } = useMemo(() => {\n if (!contentStr) return { previewLines: [] as string[], totalLines: 0 }\n const lines = contentStr.split('\\n').filter(l => l.trim())\n const total = lines.length\n if (isGenerating) {\n return { previewLines: lines.slice(-MAX_PREVIEW_LINES), totalLines: total }\n }\n return { previewLines: lines.slice(0, MAX_PREVIEW_LINES), totalLines: total }\n }, [contentStr, isGenerating])\n\n // edit 工具:提取 old_string 做 diff 预览\n const oldValue = isEdit ? extractField(parsedArgs, 'old_string') : undefined\n const oldPreviewLines = useMemo(() => {\n if (!oldValue) return []\n const s = formatValue(oldValue)\n return s.split('\\n').filter(l => l.trim()).slice(0, 1)\n }, [oldValue])\n\n return (\n <>\n {/* Cursor 风格标题栏 */}\n <div\n className=\"tool-card-header\"\n onClick={() => hasContent && setExpanded(!expanded)}\n style={{ cursor: hasContent ? 'pointer' : 'default' }}\n >\n <span className=\"tool-phase-icon\">📄</span>\n {taskPurpose ? (\n <>\n <span className=\"tool-card-name\">{taskPurpose}</span>\n <span className=\"tool-card-fn\">({toolName})</span>\n </>\n ) : (\n <span className=\"tool-card-name\">{toolName}</span>\n )}\n {shortPath && <code className=\"tool-card-path-inline\">{shortPath}</code>}\n <PhaseLabel phase={phase} />\n {hasContent && <span className=\"tool-card-expand\">{expanded ? '▼' : '▶'}</span>}\n </div>\n\n {/* Diff 风格预览(折叠态 + generating 态可见) */}\n {(hasContent || isGenerating) && !expanded && (\n <div className={`content-diff-preview${isGenerating ? ' streaming' : ''}`}>\n {isEdit && !isGenerating && oldPreviewLines.map((line, i) => (\n <div key={`old-${i}`} className=\"diff-line diff-remove\">\n <span className=\"diff-sign\">-</span>\n <span className=\"diff-text\">{line}</span>\n </div>\n ))}\n {previewLines.length > 0 ? previewLines.map((line, i) => (\n <div key={i} className=\"diff-line diff-add\">\n <span className=\"diff-sign\">+</span>\n <span className=\"diff-text\">\n {line}\n {isGenerating && i === previewLines.length - 1 && (\n <span className=\"streaming-block-cursor\" />\n )}\n </span>\n </div>\n )) : isGenerating && (\n <div className=\"diff-line diff-add\">\n <span className=\"diff-sign\">+</span>\n <span className=\"diff-text\">\n <span className=\"streaming-block-cursor\" />\n </span>\n </div>\n )}\n {!isGenerating && totalLines > MAX_PREVIEW_LINES && (\n <div className=\"diff-more\">... +{totalLines - MAX_PREVIEW_LINES} lines</div>\n )}\n </div>\n )}\n\n {/* 展开态:完整内容 */}\n {expanded && (\n <div className=\"content-renderer-body\">\n {headerValue && (\n <div className=\"content-renderer-path\">{headerValue}</div>\n )}\n <pre className=\"content-renderer-code\">{contentStr}</pre>\n </div>\n )}\n </>\n )\n}\n\nexport default ContentRenderer\n","import React from 'react'\nimport type { RendererProps } from './types'\nimport { extractField, formatValue, PhaseLabel } from './utils'\n\nconst CommandRenderer: React.FC<RendererProps> = ({ message, uiConfig, parsedArgs, phase }) => {\n const command = extractField(parsedArgs, uiConfig.primary_field)\n const toolName = message.toolName || 'tool'\n const taskPurpose = message.taskPurpose\n\n return (\n <>\n <div className=\"tool-card-header\">\n <span className=\"tool-phase-icon\">💻</span>\n {taskPurpose ? (\n <>\n <span className=\"tool-card-name\">{taskPurpose}</span>\n <span className=\"tool-card-fn\">({toolName})</span>\n </>\n ) : (\n <span className=\"tool-card-name\">{toolName}</span>\n )}\n <PhaseLabel phase={phase} />\n </div>\n {command && (\n <div className=\"command-renderer-terminal\">\n <span className=\"command-prompt\">$</span>\n <code className=\"command-text\">{formatValue(command)}</code>\n </div>\n )}\n </>\n )\n}\n\nexport default CommandRenderer\n","import React from 'react'\nimport type { RendererProps } from './types'\nimport { extractField, formatValue, PhaseLabel } from './utils'\n\nconst BROWSER_ICONS: Record<string, string> = {\n browser_navigate: '🌐', browser_navigate1: '🌐',\n browser_click: '🖱️', browser_click1: '🖱️',\n browser_type: '⌨️', browser_hover: '👆',\n browser_snapshot: '📸', browser_take_screenshot: '📸',\n browser_press_key: '⌨️', browser_drag: '↔️',\n browser_tab_new: '➕', browser_tab_close: '✖️',\n browser_wait: '⏱️', browser_wait_for: '⏱️',\n}\n\nconst BrowserRenderer: React.FC<RendererProps> = ({ message, uiConfig, parsedArgs, phase }) => {\n const toolName = message.toolName || ''\n const taskPurpose = message.taskPurpose\n const icon = BROWSER_ICONS[toolName] || '🌐'\n const primaryValue = extractField(parsedArgs, uiConfig.primary_field)\n\n return (\n <>\n <div className=\"tool-card-header\">\n <span className=\"tool-phase-icon\">{icon}</span>\n {taskPurpose ? (\n <>\n <span className=\"tool-card-name\">{taskPurpose}</span>\n <span className=\"tool-card-fn\">({toolName})</span>\n </>\n ) : (\n <span className=\"tool-card-name\">{toolName}</span>\n )}\n {primaryValue && (\n <span className=\"browser-primary-value\">{formatValue(primaryValue)}</span>\n )}\n <PhaseLabel phase={phase} />\n </div>\n </>\n )\n}\n\nexport default BrowserRenderer\n","import React from 'react'\nimport type { RendererProps } from './types'\nimport { extractField, formatValue, PhaseLabel } from './utils'\n\nconst QueryRenderer: React.FC<RendererProps> = ({ message, uiConfig, parsedArgs, phase }) => {\n const queryValue = extractField(parsedArgs, uiConfig.primary_field)\n const headerValue = extractField(parsedArgs, uiConfig.header_field)\n const toolName = message.toolName || 'tool'\n const taskPurpose = message.taskPurpose\n\n return (\n <>\n <div className=\"tool-card-header\">\n <span className=\"tool-phase-icon\">🔍</span>\n {taskPurpose ? (\n <>\n <span className=\"tool-card-name\">{taskPurpose}</span>\n <span className=\"tool-card-fn\">({toolName})</span>\n </>\n ) : (\n <span className=\"tool-card-name\">{toolName}</span>\n )}\n {queryValue && (\n <span className=\"query-inline\">\"{formatValue(queryValue)}\"</span>\n )}\n {headerValue && (\n <span className=\"query-scope-inline\">in {formatValue(headerValue)}</span>\n )}\n <PhaseLabel phase={phase} />\n </div>\n </>\n )\n}\n\nexport default QueryRenderer\n","import React from 'react'\nimport type { RendererProps } from './types'\nimport { extractField, formatValue, PhaseLabel } from './utils'\n\nconst PathRenderer: React.FC<RendererProps> = ({ message, uiConfig, parsedArgs, phase }) => {\n const pathValue = extractField(parsedArgs, uiConfig.primary_field)\n const toolName = message.toolName || 'tool'\n const taskPurpose = message.taskPurpose\n const isDir = ['list_directory', 'create_directory', 'mkdir', 'rmdir'].includes(toolName)\n const icon = isDir ? '📂' : '📄'\n\n return (\n <>\n <div className=\"tool-card-header\">\n <span className=\"tool-phase-icon\">{icon}</span>\n {taskPurpose ? (\n <>\n <span className=\"tool-card-name\">{taskPurpose}</span>\n <span className=\"tool-card-fn\">({toolName})</span>\n </>\n ) : (\n <span className=\"tool-card-name\">{toolName}</span>\n )}\n {pathValue && (\n <code className=\"tool-card-path-inline\">{formatValue(pathValue)}</code>\n )}\n <PhaseLabel phase={phase} />\n </div>\n </>\n )\n}\n\nexport default PathRenderer\n","import React, { useState } from 'react'\nimport type { RendererProps } from './types'\nimport { extractField, formatValue, buildCompactTags, PhaseLabel, CompactTags } from './utils'\n\nconst TriggerRenderer: React.FC<RendererProps> = ({ message, uiConfig, parsedArgs, phase }) => {\n const [expanded, setExpanded] = useState(false)\n const headerValue = extractField(parsedArgs, uiConfig.header_field)\n const primaryValue = extractField(parsedArgs, uiConfig.primary_field)\n const tags = buildCompactTags(parsedArgs, uiConfig.compact_fields, uiConfig.hide_fields)\n const toolLabel = message.taskPurpose || message.toolName || 'tool'\n const hasDetail = !!parsedArgs && Object.keys(parsedArgs).length > 0\n\n return (\n <>\n <div\n className=\"tool-card-header\"\n onClick={() => hasDetail && setExpanded(!expanded)}\n style={{ cursor: hasDetail ? 'pointer' : 'default' }}\n >\n <span className=\"tool-phase-icon\">⏰</span>\n <span className=\"tool-card-name\">{toolLabel}</span>\n {(headerValue || primaryValue) && (\n <span className=\"trigger-title\">{formatValue(headerValue || primaryValue)}</span>\n )}\n <PhaseLabel phase={phase} />\n {hasDetail && <span className=\"tool-card-expand\">{expanded ? '▼' : '▶'}</span>}\n </div>\n {tags.length > 0 && <CompactTags tags={tags} />}\n {expanded && parsedArgs && (\n <div className=\"trigger-detail\">\n {Object.entries(parsedArgs)\n .filter(([k]) => !uiConfig.hide_fields?.includes(k))\n .map(([k, v]) => (\n <div key={k} className=\"trigger-row\">\n <span className=\"trigger-key\">{k}</span>\n <span className=\"trigger-value\">{formatValue(v)}</span>\n </div>\n ))}\n </div>\n )}\n </>\n )\n}\n\nexport default TriggerRenderer\n","import React from 'react'\nimport type { RendererProps } from './types'\nimport { extractField, formatValue, PhaseLabel } from './utils'\n\nconst ThinkingRenderer: React.FC<RendererProps> = ({ message, uiConfig, parsedArgs, phase }) => {\n const thought = extractField(parsedArgs, uiConfig.primary_field)\n const stepInfo = parsedArgs\n ? `${parsedArgs.thoughtNumber || '?'}/${parsedArgs.totalThoughts || '?'}`\n : ''\n\n return (\n <>\n <div className=\"tool-card-header\">\n <span className=\"tool-phase-icon\">💭</span>\n <span className=\"tool-card-name\">思考推理</span>\n {stepInfo && <span className=\"thinking-step\">步骤 {stepInfo}</span>}\n <PhaseLabel phase={phase} />\n </div>\n {thought && (\n <div className=\"thinking-bubble\">\n {formatValue(thought)}\n </div>\n )}\n </>\n )\n}\n\nexport default ThinkingRenderer\n","import React, { useState } from 'react'\nimport type { RendererProps } from './types'\nimport { extractField, formatValue, PhaseLabel } from './utils'\n\nconst ParamsRenderer: React.FC<RendererProps> = ({ message, uiConfig, parsedArgs, phase }) => {\n const [expanded, setExpanded] = useState(false)\n const headerValue = extractField(parsedArgs, uiConfig?.header_field)\n const toolName = message.toolName || 'tool'\n const taskPurpose = message.taskPurpose\n const hasArgs = !!parsedArgs && Object.keys(parsedArgs).length > 0\n\n return (\n <>\n <div\n className=\"tool-card-header\"\n onClick={() => hasArgs && setExpanded(!expanded)}\n style={{ cursor: hasArgs ? 'pointer' : 'default' }}\n >\n <span className=\"tool-phase-icon\">⚙️</span>\n {taskPurpose ? (\n <>\n <span className=\"tool-card-name\">{taskPurpose}</span>\n <span className=\"tool-card-fn\">({toolName})</span>\n </>\n ) : (\n <span className=\"tool-card-name\">{toolName}</span>\n )}\n {headerValue && <code className=\"tool-card-path-inline\">{formatValue(headerValue)}</code>}\n <PhaseLabel phase={phase} />\n {hasArgs && <span className=\"tool-card-expand\">{expanded ? '▼' : '▶'}</span>}\n </div>\n {expanded && parsedArgs && (\n <div className=\"params-detail\">\n {Object.entries(parsedArgs)\n .filter(([k]) => !uiConfig?.hide_fields?.includes(k))\n .map(([k, v]) => (\n <div key={k} className=\"params-row\">\n <span className=\"params-key\">{k}:</span>\n <span className=\"params-value\">{formatValue(v)}</span>\n </div>\n ))}\n </div>\n )}\n </>\n )\n}\n\nexport default ParamsRenderer\n","import React, { useState } from 'react'\n\ninterface SearchResult {\n title: string\n link: string\n snippet: string\n position?: number\n date?: string\n}\n\ninterface ToolResultRendererProps {\n content: string\n defaultExpanded?: boolean\n}\n\nfunction tryParseJson(raw: string): unknown | null {\n try {\n return JSON.parse(raw)\n } catch {\n return null\n }\n}\n\nfunction isSearchResultsShape(data: unknown): data is { query?: string; search_results: { results: SearchResult[] } } {\n if (!data || typeof data !== 'object') return false\n const obj = data as Record<string, unknown>\n const sr = obj.search_results as Record<string, unknown> | undefined\n return sr != null && Array.isArray(sr.results) && sr.results.length > 0\n}\n\ninterface ScrapeResult {\n url: string\n title?: string\n snippet?: string\n}\n\nfunction isScrapeResultShape(data: unknown): data is ScrapeResult {\n if (!data || typeof data !== 'object') return false\n const obj = data as Record<string, unknown>\n return typeof obj.url === 'string' && obj.url.length > 0\n && !('search_results' in obj)\n && (typeof obj.title === 'string' || typeof obj.snippet === 'string')\n}\n\nconst SearchResultsView: React.FC<{ query?: string; results: SearchResult[] }> = ({ query, results }) => (\n <div className=\"tool-result-search\">\n {query && <div className=\"tool-result-search-query\">🔍 {query}</div>}\n <div className=\"tool-result-search-list\">\n {results.slice(0, 8).map((r, i) => (\n <a\n key={i}\n className=\"tool-result-search-item\"\n href={r.link}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <div className=\"search-item-title\">{r.title}</div>\n <div className=\"search-item-snippet\">{r.snippet}</div>\n {r.date && <span className=\"search-item-date\">{r.date}</span>}\n </a>\n ))}\n {results.length > 8 && (\n <div className=\"search-item-more\">+{results.length - 8} more</div>\n )}\n </div>\n </div>\n)\n\nconst ScrapeResultView: React.FC<{ result: ScrapeResult }> = ({ result }) => (\n <div className=\"tool-result-scrape\">\n <a\n className=\"scrape-result-link\"\n href={result.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {result.title && <div className=\"scrape-result-title\">{result.title}</div>}\n <div className=\"scrape-result-url\">{result.url}</div>\n </a>\n {result.snippet && <div className=\"scrape-result-snippet\">{result.snippet}</div>}\n </div>\n)\n\nconst JsonView: React.FC<{ data: unknown }> = ({ data }) => {\n const formatted = JSON.stringify(data, null, 2)\n const lines = formatted.split('\\n')\n const needsTruncation = lines.length > 12\n\n const [showAll, setShowAll] = useState(false)\n const display = showAll ? formatted : lines.slice(0, 12).join('\\n')\n\n return (\n <div className=\"tool-result-json\">\n <pre className=\"tool-result-json-code\">{display}</pre>\n {needsTruncation && !showAll && (\n <div className=\"tool-result-json-more\" onClick={() => setShowAll(true)}>\n 展开全部 ({lines.length} 行)\n </div>\n )}\n </div>\n )\n}\n\nconst ToolResultRenderer: React.FC<ToolResultRendererProps> = ({ content, defaultExpanded = false }) => {\n const [isExpanded, setIsExpanded] = useState(defaultExpanded)\n\n if (!content.trim()) return null\n\n const parsed = tryParseJson(content)\n\n const summaryText = (() => {\n if (parsed && isSearchResultsShape(parsed)) {\n const count = parsed.search_results.results.length\n return `搜索结果 · ${count} 条`\n }\n if (parsed && isScrapeResultShape(parsed)) {\n const title = parsed.title || new URL(parsed.url).hostname\n return `抓取结果 · ${title}`\n }\n if (parsed) {\n const str = JSON.stringify(parsed)\n return str.length > 60 ? str.slice(0, 60) + '…' : str\n }\n return content.length > 80 ? content.slice(0, 80) + '…' : content\n })()\n\n return (\n <div className=\"tool-result-section\">\n <div className=\"tool-result-header\" onClick={() => setIsExpanded(!isExpanded)}>\n <span className=\"tool-result-label\">📋 执行结果</span>\n <span className=\"tool-result-summary\">{summaryText}</span>\n <span className={`collapse-arrow ${isExpanded ? 'expanded' : ''}`}>▼</span>\n </div>\n {isExpanded && (\n <div className=\"tool-result-body\">\n {parsed && isSearchResultsShape(parsed) ? (\n <SearchResultsView query={parsed.query} results={parsed.search_results.results} />\n ) : parsed && isScrapeResultShape(parsed) ? (\n <ScrapeResultView result={parsed} />\n ) : parsed ? (\n <JsonView data={parsed} />\n ) : (\n <div className=\"tool-result-text\">{content}</div>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport default ToolResultRenderer\n","/**\n * 子 Agent 卡片组件\n * 可折叠,固定高度,内部滚动\n */\n\nimport React, { useState, useRef, useEffect, useMemo } from 'react'\nimport type { ChildAgentCardProps, Artifact } from '../types'\nimport { mergeConsecutiveThinkMessages } from '../types'\nimport MessageContent from './MessageContent'\nimport './ChildAgentCard.css'\n\nconst ChildAgentCard: React.FC<ChildAgentCardProps & {\n onArtifactClick?: (artifact: Artifact) => void\n}> = ({ \n message, \n children,\n maxHeight = 200,\n config,\n onArtifactClick,\n defaultExpanded = false,\n parentTaskPurpose,\n}) => {\n const [isExpanded, setIsExpanded] = useState(defaultExpanded)\n const contentRef = useRef<HTMLDivElement>(null)\n\n // 判断执行状态\n const hasActiveContent = children.some(\n m => m.contentType === 'text' && m.contentChunks.join('').trim()\n )\n const status = hasActiveContent ? 'completed' : 'running'\n\n // 自动滚动到底部\n useEffect(() => {\n if (isExpanded && contentRef.current) {\n contentRef.current.scrollTop = contentRef.current.scrollHeight\n }\n }, [isExpanded, children])\n\n // 卡片标题:优先使用父级 call_agent 的 taskPurpose(精准描述本子 Agent 的任务),\n // 回退到子 Agent 自身消息中的 taskPurpose 或 agentName\n const cardTitle = parentTaskPurpose || message.taskPurpose || message.agentName\n\n return (\n <div className={`child-agent-card ${isExpanded ? 'expanded' : ''}`}>\n <div \n className=\"child-agent-header\"\n onClick={() => setIsExpanded(!isExpanded)}\n >\n <div className=\"child-agent-title\">\n <span className=\"card-title\">{cardTitle}</span>\n </div>\n <div className=\"child-agent-status\">\n <span className={`status-badge status-${status}`}>\n <span className={`status-icon ${status === 'running' ? 'spinning' : ''}`}>\n {status === 'running' ? '⏳' : '✓'}\n </span>\n <span className=\"status-text\">{status === 'running' ? '执行中' : '已完成'}</span>\n </span>\n <span className={`collapse-arrow ${isExpanded ? 'expanded' : ''}`}>\n ▼\n </span>\n </div>\n </div>\n \n {isExpanded && (\n <div \n className=\"child-agent-content\"\n ref={contentRef}\n style={{ maxHeight }}\n >\n <div className=\"child-agent-inner\">\n {/* 先渲染父消息本身的内容 */}\n {message.contentChunks.length > 0 && (\n <MessageContent\n key={message.id}\n message={message}\n enableTypewriter={config?.enableTypewriter}\n typewriterSpeed={config?.typewriterSpeed}\n onArtifactClick={onArtifactClick}\n />\n )}\n {/* 再渲染子消息(连续 think 合并为单条) */}\n {mergeConsecutiveThinkMessages(children).map((childMsg) => (\n <MessageContent\n key={childMsg.id}\n message={childMsg}\n enableTypewriter={config?.enableTypewriter}\n typewriterSpeed={config?.typewriterSpeed}\n onArtifactClick={onArtifactClick}\n />\n ))}\n </div>\n {/* Agent 名称放在右下角 */}\n <div className=\"child-agent-footer\">\n <span className=\"footer-agent-icon\">🤖</span>\n <span className=\"footer-agent-name\">{message.agentName}</span>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default ChildAgentCard\n","export class ChatWidgetAuthError extends Error {\n readonly name = 'ChatWidgetAuthError' as const\n\n constructor(message = 'Authentication failed') {\n super(message)\n }\n}\n\nexport class ChatWidgetNetworkError extends Error {\n readonly name = 'ChatWidgetNetworkError' as const\n\n constructor(\n message: string,\n public readonly statusCode: number,\n ) {\n super(message)\n }\n}\n","import type { ChatWidgetAdapter, NotificationTurn, ResourceContent, SessionDetail, HITLResponse } from '../types.js'\nimport { ChatWidgetAuthError, ChatWidgetNetworkError } from '../errors.js'\n\nexport interface DefaultJetAgentsAdapterOptions {\n baseUrl: string\n getToken: () => string | null\n refreshToken?: () => Promise<string | null>\n getOrgId?: () => string | null\n onAuthFailure?: () => void\n}\n\nexport class DefaultJetAgentsAdapter implements ChatWidgetAdapter {\n private readonly baseUrl: string\n private readonly options: DefaultJetAgentsAdapterOptions\n private refreshPromise: Promise<boolean> | null = null\n\n constructor(options: DefaultJetAgentsAdapterOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.options = options\n }\n\n async createSession(agentId: string): Promise<{ sessionId: number; instanceId: number }> {\n const res = await this.fetchJSON<{ session_id: number; user_caller_instance: number }>(\n '/api/session/create',\n {\n method: 'POST',\n body: JSON.stringify({ agent_id: agentId, type: 'user_input', contents: [{ type: 'text', content: '' }] }),\n },\n )\n return { sessionId: res.session_id, instanceId: res.user_caller_instance }\n }\n\n async getSessionDetail(sessionId: number): Promise<SessionDetail> {\n const res = await this.fetchJSON<SessionDetail>(`/api/session/detail/${sessionId}`)\n return res\n }\n\n async getSessionHistory(sessionId: number): Promise<NotificationTurn[]> {\n const res = await this.fetchJSON<{ turns?: NotificationTurn[] }>(`/api/session/messages/${sessionId}`)\n return res.turns ?? (Array.isArray(res) ? res as unknown as NotificationTurn[] : [])\n }\n\n async getResourceContent(sessionId: number, resourceId: string): Promise<ResourceContent> {\n const res = await this.fetchJSON<{ data?: ResourceContent }>(`/api/workspace/resource/${sessionId}/${resourceId}/content`)\n return (res.data ?? res) as ResourceContent\n }\n\n async submitHITLResponse(response: HITLResponse): Promise<void> {\n await this.fetchJSON('/api/human-response', {\n method: 'POST',\n body: JSON.stringify(response),\n })\n }\n\n getStreamUrl(): string {\n return `${this.baseUrl}/api/session/send_message`\n }\n\n getAuthHeaders(): Record<string, string> {\n const headers: Record<string, string> = {}\n const token = this.options.getToken()\n if (token) {\n headers['Authorization'] = `Bearer ${token}`\n }\n const orgId = this.options.getOrgId?.()\n if (orgId) {\n headers['X-Org-Id'] = orgId\n }\n return headers\n }\n\n onAuthFailure(): void {\n this.options.onAuthFailure?.()\n }\n\n async refreshAuth(): Promise<boolean> {\n if (!this.options.refreshToken) return false\n\n if (this.refreshPromise) {\n return this.refreshPromise\n }\n\n this.refreshPromise = this.options.refreshToken()\n .then((token) => token !== null)\n .finally(() => {\n this.refreshPromise = null\n })\n\n return this.refreshPromise\n }\n\n private async fetchJSON<T>(path: string, init?: RequestInit): Promise<T> {\n const url = `${this.baseUrl}${path}`\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.getAuthHeaders(),\n }\n\n const response = await fetch(url, {\n ...init,\n headers: { ...headers, ...(init?.headers as Record<string, string> | undefined) },\n })\n\n if (response.status === 401) {\n const refreshed = await this.refreshAuth()\n if (refreshed) {\n const retryHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.getAuthHeaders(),\n }\n const retryResponse = await fetch(url, {\n ...init,\n headers: { ...retryHeaders, ...(init?.headers as Record<string, string> | undefined) },\n })\n if (retryResponse.ok) {\n return retryResponse.json() as Promise<T>\n }\n }\n this.onAuthFailure()\n throw new ChatWidgetAuthError('Authentication failed')\n }\n\n if (!response.ok) {\n throw new ChatWidgetNetworkError(\n `Request failed: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n\n return response.json() as Promise<T>\n }\n}\n"],"mappings":"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","names":["React","useCallback","useEffect","useMemo","useRef","useState","useCallback","useRef","useState","useState","useCallback","jsx","jsxs","useState","useCallback","jsx","jsxs","jsx","jsxs","useEffect","useState","useRef","memo","useState","useCallback","jsx","jsxs","useState","useCallback","useMemo","useRef","jsx","jsxs","jsxs","jsx","useState","useMemo","Fragment","jsx","jsxs","useState","useMemo","Fragment","jsx","jsxs","Fragment","jsx","jsxs","Fragment","jsx","jsxs","Fragment","jsx","jsxs","useState","Fragment","jsx","jsxs","useState","Fragment","jsx","jsxs","useState","Fragment","jsx","jsxs","useState","useState","jsx","jsxs","jsx","jsxs","useRef","useMemo","Fragment","jsx","jsxs","useState","useRef","useEffect","memo","useState","useRef","useEffect","jsx","jsxs","useState","useRef","useEffect","jsx","jsxs","useMemo","useState","useRef","useEffect","rounds","useCallback","height","React"]}