@yumiai/chat-widget 0.1.2 → 0.2.1
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.
- package/CHANGELOG.md +100 -0
- package/README.md +119 -22
- package/dist/ExcelCore-DJOIVQMI.js +11 -0
- package/dist/ExcelCore-DJOIVQMI.js.map +1 -0
- package/dist/ExcelViewer-3YLLYYIQ.js +65 -0
- package/dist/ExcelViewer-3YLLYYIQ.js.map +1 -0
- package/dist/GerberViewerA2UI-7CNT7HX4.css +693 -0
- package/dist/GerberViewerA2UI-7CNT7HX4.css.map +1 -0
- package/dist/GerberViewerA2UI-X5FWAD5M.js +57 -0
- package/dist/GerberViewerA2UI-X5FWAD5M.js.map +1 -0
- package/dist/GraphStatsLegend-D5bPeXB_.d.cts +607 -0
- package/dist/GraphStatsLegend-D5bPeXB_.d.ts +607 -0
- package/dist/JsonRenderStandalone-EIZM62JU.js +18 -0
- package/dist/JsonRenderStandalone-EIZM62JU.js.map +1 -0
- package/dist/JsonRenderStandalone-POB4Q3N3.css +2384 -0
- package/dist/JsonRenderStandalone-POB4Q3N3.css.map +1 -0
- package/dist/JsonRenderStandalone-UsTcST4G.d.cts +23 -0
- package/dist/JsonRenderStandalone-UsTcST4G.d.ts +23 -0
- package/dist/KicadViewer-GV6ZC4AQ.js +124 -0
- package/dist/KicadViewer-GV6ZC4AQ.js.map +1 -0
- package/dist/KicadViewerCore-U7BWZHKJ.js +11 -0
- package/dist/KicadViewerCore-U7BWZHKJ.js.map +1 -0
- package/dist/PdfViewer-CHPDRK46.js +51 -0
- package/dist/PdfViewer-CHPDRK46.js.map +1 -0
- package/dist/PdfViewer-LPYGQETK.css +1899 -0
- package/dist/PdfViewer-LPYGQETK.css.map +1 -0
- package/dist/PdfViewerCore-HJPEHSRA.js +364 -0
- package/dist/PdfViewerCore-HJPEHSRA.js.map +1 -0
- package/dist/PowerPointCore-FPDR2BL4.js +11 -0
- package/dist/PowerPointCore-FPDR2BL4.js.map +1 -0
- package/dist/PowerPointViewer-LQTO6UCU.js +61 -0
- package/dist/PowerPointViewer-LQTO6UCU.js.map +1 -0
- package/dist/StepViewerCore-7W3L3R4E.js +285 -0
- package/dist/StepViewerCore-7W3L3R4E.js.map +1 -0
- package/dist/ThreeViewerCore-N3QJD5QI.js +161 -0
- package/dist/ThreeViewerCore-N3QJD5QI.js.map +1 -0
- package/dist/WordCore-JKSXK2XD.js +11 -0
- package/dist/WordCore-JKSXK2XD.js.map +1 -0
- package/dist/WordViewer-ZHCQMHOH.js +61 -0
- package/dist/WordViewer-ZHCQMHOH.js.map +1 -0
- package/dist/chunk-2SKA3F5U.js +88 -0
- package/dist/chunk-2SKA3F5U.js.map +1 -0
- package/dist/chunk-2UC7YLVX.js +318 -0
- package/dist/chunk-2UC7YLVX.js.map +1 -0
- package/dist/chunk-3R6T3LBR.js +24 -0
- package/dist/chunk-3R6T3LBR.js.map +1 -0
- package/dist/chunk-56WRZM3R.js +398 -0
- package/dist/chunk-56WRZM3R.js.map +1 -0
- package/dist/chunk-7A4FY6FK.js +10226 -0
- package/dist/chunk-7A4FY6FK.js.map +1 -0
- package/dist/chunk-7D4SUZUM.js +38 -0
- package/dist/chunk-7D4SUZUM.js.map +1 -0
- package/dist/chunk-7S67DOHQ.js +436 -0
- package/dist/chunk-7S67DOHQ.js.map +1 -0
- package/dist/chunk-CFKGNAJM.js +14013 -0
- package/dist/chunk-CFKGNAJM.js.map +1 -0
- package/dist/chunk-GAMA3VA7.js +99 -0
- package/dist/chunk-GAMA3VA7.js.map +1 -0
- package/dist/chunk-GYXTSY22.js +639 -0
- package/dist/chunk-GYXTSY22.js.map +1 -0
- package/dist/chunk-K4KGNVL5.js +77 -0
- package/dist/chunk-K4KGNVL5.js.map +1 -0
- package/dist/chunk-KQV7IKET.js +1621 -0
- package/dist/chunk-KQV7IKET.js.map +1 -0
- package/dist/chunk-O3NXUM6C.js +1871 -0
- package/dist/chunk-O3NXUM6C.js.map +1 -0
- package/dist/chunk-PZXSASDY.js +83 -0
- package/dist/chunk-PZXSASDY.js.map +1 -0
- package/dist/chunk-QLVPIM6R.js +595 -0
- package/dist/chunk-QLVPIM6R.js.map +1 -0
- package/dist/chunk-VXJWGLZ7.js +21 -0
- package/dist/chunk-VXJWGLZ7.js.map +1 -0
- package/dist/chunk-XQ562W7I.js +116 -0
- package/dist/chunk-XQ562W7I.js.map +1 -0
- package/dist/components/JsonRender/standalone.cjs +39368 -0
- package/dist/components/JsonRender/standalone.cjs.map +1 -0
- package/dist/components/JsonRender/standalone.css +2384 -0
- package/dist/components/JsonRender/standalone.css.map +1 -0
- package/dist/components/JsonRender/standalone.d.cts +16 -0
- package/dist/components/JsonRender/standalone.d.ts +16 -0
- package/dist/components/JsonRender/standalone.js +38 -0
- package/dist/components/JsonRender/standalone.js.map +1 -0
- package/dist/gerber-2d-entry-OQ4SQRBY.js +3950 -0
- package/dist/gerber-2d-entry-OQ4SQRBY.js.map +1 -0
- package/dist/gerber-3d-entry-DEHDBOO2.js +3679 -0
- package/dist/gerber-3d-entry-DEHDBOO2.js.map +1 -0
- package/dist/gerber-simulation-entry-EBDX72XE.js +1801 -0
- package/dist/gerber-simulation-entry-EBDX72XE.js.map +1 -0
- package/dist/index.cjs +60113 -2970
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +11342 -1708
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +3275 -77
- package/dist/index.d.ts +3275 -77
- package/dist/index.js +18078 -2540
- package/dist/index.js.map +1 -1
- package/dist/provenance/index.cjs +2248 -0
- package/dist/provenance/index.cjs.map +1 -0
- package/dist/provenance/index.css +52 -0
- package/dist/provenance/index.css.map +1 -0
- package/dist/provenance/index.d.cts +12 -0
- package/dist/provenance/index.d.ts +12 -0
- package/dist/provenance/index.js +27 -0
- package/dist/provenance/index.js.map +1 -0
- package/dist/resolveToArrayBuffer-AQIDZHSQ.js +23 -0
- package/dist/resolveToArrayBuffer-AQIDZHSQ.js.map +1 -0
- package/package.json +98 -17
package/dist/index.js.map
CHANGED
|
@@ -1 +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 endedAgentInstanceIds={round.endedAgentInstanceIds}\n allRoundMessages={round.messages}\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 /** 本轮次内已收到 agent_end 的 agent_instance_id 集合,与 notification_turns 的 agent start/stop 对齐,用于子 Agent 卡片「已完成」判断 */\n endedAgentInstanceIds?: Set<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 /** 本轮次已收到 agent_end 的 agent_instance_id(与 notification_turns 对齐),有则优先据此显示「已完成」 */\n endedAgentInstanceIds?: Set<number>\n /** 本轮次全部消息,用于判断该 agent 是否有未完成的工具(子 agent 的 MCP 消息可能挂在别的 parent 下,不在此卡片的 children 里) */\n allRoundMessages?: AggregatedMessage[]\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 /** 每轮次已收到 agent_end 的 agent_instance_id,与 notification_turns 的 turn_type=agent_end 对齐 */\n endedAgentInstanceIdsByRound: Map<string, Set<number>>\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 endedAgentInstanceIdsByRound: new Map(),\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 // 每轮次已收到 agent_end 的 agent_instance_id(与 notification_turns 的 agent_start/agent_end 对齐)\n const endedAgentInstanceIdsByRoundRef = useRef<Map<string, Set<number>>>(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 // ========== agent_end:与 notification_turns 的 agent start/stop 对齐 ==========\n // 后端在子 Agent 结束时发送 agent_end,据此判断子 Agent 卡片应显示「已完成」而非推断\n if (msg.notification_type === 'agent_end') {\n const iid = interaction_id\n const aid = msg.agent_instance_id\n if (iid != null && aid != null) {\n const prev = endedAgentInstanceIdsByRoundRef.current\n const set = new Set(prev.get(iid) || [])\n set.add(aid)\n endedAgentInstanceIdsByRoundRef.current = new Map(prev).set(iid, set)\n }\n latestInteractionId = interaction_id\n continue\n }\n // ========== 结束:agent_end ==========\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 const endedByRound = endedAgentInstanceIdsByRoundRef.current\n const endedAgentInstanceIdsByRound = new Map(\n [...endedByRound.entries()].map(([k, v]) => [k, new Set(v)])\n )\n return {\n rounds: newRounds,\n currentInteractionId: latestInteractionId,\n endedAgentInstanceIdsByRound,\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 // 获取轮次列表(按时间排序),并挂上本轮已结束的 agent_instance_id(用于子 Agent 卡片状态)\n const getRoundsList = useCallback((): Round[] => {\n const endedByRound = state.endedAgentInstanceIdsByRound\n return Array.from(state.rounds.values())\n .map((r) => ({\n ...r,\n endedAgentInstanceIds: endedByRound.get(r.interactionId) || new Set<number>(),\n }))\n .sort((a, b) => a.index - b.index)\n }, [state.rounds, state.endedAgentInstanceIdsByRound])\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 endedAgentInstanceIdsByRound: prevState.endedAgentInstanceIdsByRound,\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 endedAgentInstanceIdsByRoundRef.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, endedAgentInstanceIdsByRound: new Map() })\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 const endedByRound = endedAgentInstanceIdsByRoundRef.current\n setState(() => ({\n rounds: new Map(roundIndexRef.current),\n currentInteractionId: interactionId,\n endedAgentInstanceIdsByRound: new Map([...endedByRound.entries()].map(([k, v]) => [k, new Set(v)])),\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 endedAgentInstanceIdsByRoundRef.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 endedAgentInstanceIdsByRound: new Map(),\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 endedAgentInstanceIds,\n allRoundMessages,\n}) => {\n const [isExpanded, setIsExpanded] = useState(defaultExpanded)\n const contentRef = useRef<HTMLDivElement>(null)\n\n // 优先用后端 agent_end 判断(与 notification_turns 的 agent start/stop 对齐),否则回退到内容+工具阶段\n const allMessages = useMemo(() => [message, ...children], [message, children])\n const hasExplicitEnd = endedAgentInstanceIds != null && endedAgentInstanceIds.has(message.agentInstanceId)\n const hasActiveContent = allMessages.some(\n m => m.contentType === 'text' && m.contentChunks.join('').trim()\n )\n // 同一 agent 的 MCP 消息可能因 parent 挂在别处而不在 children 里,需用整轮消息按 agentInstanceId 判断\n const hasInProgressTool = useMemo(() => {\n if (allMessages.some(m => m.toolPhase === 'generating' || m.toolPhase === 'executing')) return true\n if (allRoundMessages == null) return false\n return allRoundMessages.some(\n m => m.agentInstanceId === message.agentInstanceId && (m.toolPhase === 'generating' || m.toolPhase === 'executing')\n )\n }, [allMessages, allRoundMessages, message.agentInstanceId])\n const status = hasExplicitEnd\n ? 'completed'\n : (hasActiveContent && !hasInProgressTool ? '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","useMemo","jsx","jsxs","useState","useRef","useMemo","useEffect","jsx","jsxs","useMemo","useState","useRef","useEffect","rounds","useCallback","height","React"]}
|
|
1
|
+
{"version":3,"sources":["../src/ChatWidget.tsx","../src/types.ts","../src/controller/useChatWidgetController.ts","../src/hooks/useMessageAggregator.ts","../src/utils/randomUUID.ts","../src/utils/memTelemetry.ts","../src/hooks/useConnectionId.ts","../src/hooks/useSSE.ts","../src/hooks/useAuthedFetch.ts","../src/contexts/AdapterContext.tsx","../src/hooks/useSessionChannel.ts","../src/hooks/usePoolObservation.ts","../src/hooks/useSessionClients.ts","../src/errors.ts","../src/hooks/useGenUIPending.ts","../src/components/PinnedArea.tsx","../src/components/PlanCard.tsx","../src/components/Icon/Icon.tsx","../src/components/Icon/iconMap.ts","../src/components/TodoCard.tsx","../src/components/UserMessageContent.tsx","../src/utils/parseUserMessage.ts","../src/utils/fileTypeIcon.ts","../src/components/CollapsibleContent.tsx","../src/components/RoundHeader.tsx","../src/components/RoundMessageList.tsx","../src/utils/messageOrganizer.ts","../src/utils/roundMessageUtils.ts","../src/components/MessageContent.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/message/ThinkChunk.tsx","../src/components/message/HITLWaitCard.tsx","../src/components/SchemaFormRenderer.tsx","../src/utils/schemaFormUtils.tsx","../src/components/message/ArtifactCard.tsx","../src/components/message/McpToolEvent.tsx","../src/utils/messageParser.ts","../src/components/message/LegacyToolLine.tsx","../src/components/JsonRender/JsonRenderCard.tsx","../src/components/JsonRender/ActionBridge.ts","../src/components/JsonRender/GenUIContext.tsx","../src/hooks/useTypewriter.ts","../src/utils/typewriterUtils.ts","../src/components/ChildAgentCard.tsx","../src/hooks/useChildAgentStatus.ts","../src/components/RoundsView.tsx","../src/components/FileViewer/FileViewer.tsx","../src/components/FileViewer/utils/fileCategory.ts","../src/components/FileViewer/utils/contentUrl.ts","../src/components/FileViewer/viewers/FallbackViewer.tsx","../src/components/FileViewer/viewers/ViewerLoading.tsx","../src/components/FileViewer/FileViewerModal.tsx","../src/hooks/useXrefScrollToTarget.ts","../src/components/FileViewer/FileViewerPanel.tsx","../src/components/FileViewer/Breadcrumb.tsx","../src/components/ContextBridge/useSelectionBridge.ts","../src/components/ContextBridge/FloatingToolbar.tsx","../src/components/ContextBridge/useSmartPaste.ts","../src/hooks/useFileViewerNavigation.ts","../src/hooks/useNativeCopyInterceptor.ts","../src/components/FileViewer/xref/LinkCard.tsx","../src/components/FileViewer/xref/ResourceChip.tsx","../src/components/FileViewer/HoverPreview.tsx","../src/components/FileViewer/ViewerInteractionAdapter.ts","../src/components/ForeignRoundBadge.tsx","../src/components/SplitPanel/SplitPanel.tsx","../src/components/SplitPanel/useDragResize.ts","../src/components/ContextBridge/FloatingInput.tsx","../src/components/ContextBridge/ContextChip.tsx","../src/components/SplitPanel/AttentionToast.tsx","../src/components/SplitPanel/ImmersiveShell.tsx","../src/components/SplitPanel/TabBar.tsx","../src/utils/fileTypeColor.ts","../src/hooks/useEscStack.ts","../src/hooks/useShortcuts.ts","../src/hooks/useNarrowMode.ts","../src/hooks/useAttentionManager.ts","../src/hooks/useFileViewer.ts","../src/hooks/useScrollManager.ts","../src/hooks/useReferenceManager.ts","../src/hooks/useTypewriterTitle.ts","../src/hooks/useAutoTheme.ts","../src/hooks/useChatOrchestration.ts","../src/hooks/useFileUpload.ts","../src/hooks/useViewerTabs.ts","../src/hooks/useAutoTab.ts","../src/hooks/useWorkspaceFiles.ts","../src/hooks/useTreePersist.ts","../src/hooks/useAnnotations.ts","../src/hooks/annotationUtils.ts","../src/contexts/ResourceProvider.tsx","../src/components/JsonRender/JsonRenderViewer.tsx","../src/components/PoolStatusPopover/PoolStatusPopover.tsx","../src/components/SplitPanel/ChatOverlay.tsx","../src/components/Workspace/WorkspacePanel.tsx","../src/components/Workspace/WorkspaceContextMenu.tsx","../src/components/Discussion/DiscussionPanel.tsx","../src/components/Discussion/DiscussionViewer.tsx","../src/components/Discussion/DiscussionComposer.tsx","../src/components/Discussion/MentionAutocomplete.tsx","../src/hooks/useDiscussions.ts","../src/components/Annotation/AnnotationFAB.tsx","../src/components/Annotation/AnnotationPanel.tsx","../src/components/Annotation/InlineAnnotationInput.tsx","../src/components/ChannelSidebar/ChannelSidebar.tsx","../src/components/FloatingConversation/FloatingConversation.tsx","../src/hooks/useFloatingWindows.ts","../src/hooks/useClientIdAllocator.ts","../src/hooks/useBootLegacyImport.ts","../src/hooks/useClientId.ts","../src/components/SelectionHighlight/SelectionHighlight.tsx","../src/components/SessionForbiddenBanner.tsx","../src/hooks/useAgentControl.ts","../src/hooks/useSessionList.ts","../src/components/ContextBridge/RichInput.tsx","../src/components/Composer/DefaultComposer.tsx","../src/components/SkillSelector/SkillSelector.tsx","../src/hooks/useSkillOrchestration.ts","../src/hooks/useSkillData.ts","../src/hooks/useSkillSelectorState.ts","../src/components/Composer/ModelPicker/ModelPicker.tsx","../src/components/Composer/ModelPicker/useModels.ts","../src/components/Composer/ModelPicker/modelRegistry.ts","../src/components/Composer/ModelPicker/useAgentDefaultModel.ts","../src/components/SessionListPanel/SessionListPanel.tsx","../src/hooks/useCatalogFragment.ts","../src/adapters/DefaultJetAgentsAdapter.ts","../src/utils/statusDisplay.ts","../src/components/AgentGroup/AgentGroupPanel.tsx","../src/contexts/ShareResourceProvider.tsx"],"sourcesContent":["/**\n * ChatWidget 主组件 — UI Shell\n *\n * Business logic (SSE, aggregation, session, status) is delegated to\n * useChatWidgetController. This file only owns DOM/scroll/viewer/animation.\n */\n\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { \n ChatWidgetProps, \n ChatWidgetAPI,\n Artifact,\n PendingHIL,\n} from './types'\nimport { DEFAULT_CONFIG } from './types'\nimport { useChatWidgetController } from './controller'\nimport { useGenUIPending } from './hooks/useGenUIPending'\nimport { PinnedArea, RoundHeader, RoundsView } from './components'\nimport RoundMessageList from './components/RoundMessageList'\nimport ForeignRoundBadge from './components/ForeignRoundBadge'\nimport { FileViewerPanel } from './components/FileViewer'\nimport { SplitPanel } from './components/SplitPanel'\nimport ContextChip from './components/ContextBridge/ContextChip'\nimport { useSmartPaste } from './components/ContextBridge/useSmartPaste'\nimport { useAttentionManager } from './hooks/useAttentionManager'\nimport { useFileViewer } from './hooks/useFileViewer'\nimport { useScrollManager } from './hooks/useScrollManager'\nimport { useReferenceManager } from './hooks/useReferenceManager'\nimport { useTypewriterTitle } from './hooks/useTypewriterTitle'\nimport { useAutoTheme, type ResolvedTheme } from './hooks/useAutoTheme'\nimport { useChatOrchestration } from './hooks/useChatOrchestration'\nimport { useFileUpload } from './hooks/useFileUpload'\nimport { useViewerTabs } from './hooks/useViewerTabs'\nimport { useAutoTab, type ArtifactRef } from './hooks/useAutoTab'\nimport { useWorkspaceFiles, type WorkspaceFile } from './hooks/useWorkspaceFiles'\nimport { useTreePersist } from './hooks/useTreePersist'\nimport { useAnnotations } from './hooks/useAnnotations'\nimport { anchoredGroupKey } from './hooks/annotationUtils'\nimport { I18nContext, resolveMessages } from './i18n'\nimport { InteractionContext } from './hooks/useInteractionDispatch'\nimport { GenUIProvider } from './components/JsonRender/GenUIContext'\nimport { ResourceProvider } from './contexts/ResourceProvider.js'\nimport { AdapterProvider } from './contexts/AdapterContext'\nimport { JsonRenderViewer } from './components/JsonRender/JsonRenderViewer'\nimport { registry as genUIRegistry } from './components/JsonRender/domain/registry'\nimport { PoolStatusPopover } from './components/PoolStatusPopover'\nimport { Icon } from './components/Icon/Icon'\nimport ChatOverlay from './components/SplitPanel/ChatOverlay'\nimport { WorkspacePanel } from './components/Workspace'\nimport { DiscussionPanel } from './components/Discussion'\nimport { useDiscussions } from './hooks/useDiscussions'\nimport { AnnotationFAB, AnnotationPanel, InlineAnnotationInput } from './components/Annotation'\nimport type { AnnotationPanelMessage } from './components/Annotation/AnnotationPanel'\nimport { ChannelSidebar } from './components/ChannelSidebar'\nimport type { ChannelCategory } from './components/ChannelSidebar'\nimport { FloatingConversation } from './components/FloatingConversation'\nimport type { FloatingMessage } from './components/FloatingConversation'\nimport { useFloatingWindows } from './hooks/useFloatingWindows'\nimport { useSessionClients } from './hooks/useSessionClients'\nimport { useClientIdAllocator } from './hooks/useClientIdAllocator'\nimport { useBootLegacyImport } from './hooks/useBootLegacyImport'\nimport { InvalidClientIdError } from './errors'\nimport { SelectionHighlight } from './components/SelectionHighlight'\nimport type { SelectionHighlightItem } from './components/SelectionHighlight'\nimport { SessionForbiddenBanner } from './components/SessionForbiddenBanner'\nimport './ChatWidget.css'\n\nconst THEME_CLASS: Partial<Record<ResolvedTheme, string>> = {\n dark: 'ycw-dark',\n midnight: 'ycw-midnight',\n neumorphism: 'ycw-neu',\n}\n\nconst KICANVAS_JP_THEME: Record<ResolvedTheme, 'jp-light' | 'jp-dark' | 'jp-midnight' | 'jp-neu'> = {\n light: 'jp-light',\n dark: 'jp-dark',\n midnight: 'jp-midnight',\n neumorphism: 'jp-neu',\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 onSelectionAsk,\n onBeforeCopy,\n renderToolResult,\n onHITLSubmit,\n onConnectionChange,\n onRoundChange,\n onMessageAppended,\n onRoundStart,\n onRoundEnd,\n onStatusChange,\n onError,\n onInteraction,\n onReady,\n className,\n style,\n height = 600,\n locale = 'zh-CN',\n messages: messagesOverride,\n kicanvasScriptUrl,\n currentUserAlias: propCurrentUserAlias,\n}) => {\n const i18n = useMemo(() => resolveMessages(locale, messagesOverride), [locale, messagesOverride])\n const config = useMemo(() => ({\n ...DEFAULT_CONFIG,\n ...userConfig,\n }), [userConfig])\n\n const resolvedTheme = useAutoTheme(config.theme)\n\n const activeSpecIdsRef = useRef<string[]>([])\n\n // ── Controller: all business logic ──\n // JETP-038: discussion WS update handler ref (wired below after useDiscussions)\n const discussionUpdateRef = useRef<((event: Record<string, unknown>) => void) | undefined>(undefined)\n\n // 跨 hook 数据通道\n // session(项目)下的所有 client(任务话池)cid 列表,作为 controller 拉历史的范围。\n // controller 在最顶层先调用,需要 historyClientIds 才能正确拉历史;\n // 但 useSessionClients 又要等 controller.currentSessionId 才能去拉 client 列表。\n // t0:controller 第一次调用 → historyClientIds=[] → controller skip 拉历史\n // t1:useSessionClients items 到达 → setState → controller 重新渲染\n // t2:controller useEffect 看到非空 historyClientIds → 拉一次完整历史\n // 若 session 还没有任何 cid,会在 session 切换 effect 里现场分配一个空白任务话池。\n const [historyClientIds, setHistoryClientIds] = useState<string[]>([])\n\n // 当前选中的任务话池 cid。\n // - 主区显示该 cid 对应的 rounds;\n // - 默认输入框(footer / immersive)发送时使用此 cid;\n // - 由 ChannelSidebar 点击 / 浮窗 focus / session 初始化 effect 维护。\n // 任务话池之间完全对等,没有\"主对话\"概念。\n const [currentClientId, setCurrentClientId] = useState<string | null>(null)\n const currentClientIdRef = useRef<string | null>(null)\n currentClientIdRef.current = currentClientId\n\n const {\n executionStatus,\n connectionStatus,\n rounds,\n localInteractionIds,\n currentSessionId,\n sessionTitle,\n todoMap,\n specMetaMap,\n specLifecycleMap,\n sendMessage: controllerSendMessage,\n widgetAPI: controllerWidgetAPI,\n sessionBusy,\n poolObservation,\n wsConnected,\n hasMore,\n loadingMore,\n loadOlderPage,\n ensureSession,\n } = useChatWidgetController({\n adapter,\n sessionId: propSessionId,\n reuseAgentInstance: config.reuseAgentInstance,\n transport: config.transport,\n activeSpecIdsRef,\n // JETP-057:显式开启 in-flight 历史,刷新后正在执行的子 agent 卡片不会消失。\n // historyClientIds 由 useSessionClients items 派生(见 useEffect 同步处),\n // 首渲染为 [](controller 会 skip 拉历史),items 到达后会扩展为该 session 全部 cid。\n historyClientIds,\n historyIncludeInFlight: true,\n eagerSessionCreation: config.eagerSessionCreation,\n onStatusChange,\n onError,\n onConnectionChange,\n onRoundChange,\n onMessageAppended,\n onRoundStart,\n onRoundEnd,\n onDiscussionUpdate: useCallback((event: Record<string, unknown>) => {\n discussionUpdateRef.current?.(event)\n }, []),\n // 把 controller 的\"会话生命周期事件\"翻译成两条 InteractionEvent,\n // 让宿主可以只盯一个 onInteraction 通道。详见 types.ts 的 'session-created' / 'session-updated'。\n onSessionEvent: useCallback(\n (event: import('./types').SessionLifecycleEvent) => {\n onInteraction?.({\n type: event.type === 'created' ? 'session-created' : 'session-updated',\n target: String(event.sessionId),\n metadata: {\n sessionId: event.sessionId,\n ...(event.sessionTitle !== undefined ? { sessionTitle: event.sessionTitle } : {}),\n ...(event.agentId !== undefined ? { agentId: event.agentId } : {}),\n ...(event.source !== undefined ? { source: event.source } : {}),\n },\n timestamp: Date.now(),\n })\n },\n [onInteraction],\n ),\n })\n\n const numericSessionId = typeof currentSessionId === 'string' ? Number(currentSessionId) : currentSessionId ?? undefined\n\n // ── JETP-083 WS3.7.6 + A3 — connect-time pending HIL hydration ──────────\n // The hook short-circuits to `[]` when the adapter doesn't implement\n // `getPendingHILs` (older backend / mock adapters) — host UI degrades\n // gracefully to no-ribbon behaviour.\n const { pending: pendingHILs } = useGenUIPending({\n adapter,\n sessionId: numericSessionId ?? null,\n })\n const pendingHILBySpecId = useMemo(() => {\n const m = new Map<string, PendingHIL>()\n for (const p of pendingHILs) m.set(p.specId, p)\n return m\n }, [pendingHILs])\n\n const foreignRounds = useMemo(\n () => rounds.filter(r => !localInteractionIds.has(r.interactionId)),\n [rounds, localInteractionIds],\n )\n const localRounds = useMemo(\n () => rounds.filter(r => localInteractionIds.has(r.interactionId)),\n [rounds, localInteractionIds],\n )\n // JETP-056:三件套统一通过 `{ adapter }` 注入完整 adapter;\n // useAuthedFetch 会自动用 adapter.getAuthHeaders() 注入鉴权头,并在 401 时\n // 走 adapter.refreshAuth → onAuthFailure 链路(替代 JETP-054 hotfix 手工 shim)。\n const threeHooksOpts = useMemo(() => ({ adapter }), [adapter])\n\n const { items: sessionClientItems, loadedSessionId: sessionClientsLoadedSid, prependLocal: prependLocalClient, refresh: refreshSessionClients, error: sessionClientsError } =\n useSessionClients(currentSessionId ?? null, '', threeHooksOpts)\n\n // 把 useSessionClients 拿到的所有 v2 ``c_<22>`` 推回 controller 拉历史。\n // - 仅过滤 v2 cid(^c_[A-Za-z0-9]{22}$);\n // - 上限 16(与 BE _MAX_CIDS 对齐)。\n useEffect(() => {\n const V2_RE = /^c_[A-Za-z0-9]{22}$/\n const ids = new Set<string>()\n for (const it of sessionClientItems) {\n if (typeof it.id !== 'string') continue\n const cid = it.id.trim()\n if (!V2_RE.test(cid)) continue\n ids.add(cid)\n if (ids.size >= 16) break\n }\n const next = Array.from(ids)\n setHistoryClientIds(prev => {\n if (prev.length === next.length && prev.every((v, i) => v === next[i])) return prev\n return next\n })\n }, [sessionClientItems])\n\n // v2 client_id 分配器(懒初始化,每个 ChatWidget 实例一份 inflight 表)\n const clientIdAllocator = useClientIdAllocator(undefined, threeHooksOpts)\n\n // boot 时一次性把 localStorage 残留的 v1 字面量补到 clients 表\n useBootLegacyImport(currentSessionId ?? null, '', threeHooksOpts)\n\n // 单飞:currentClientId 还未就绪时(新建 session 边界 / session 切换的初始化窗口期),\n // 由 send 路径触发现场分配;同一时刻最多 1 个 inflight,并发 send 复用同一 Promise。\n const sendBootstrapInflightRef = useRef<Promise<string> | null>(null)\n\n // sessionClientsError 的 ref 副本:在 send 路径短路判断里同步读取,避免把它放进\n // cidGuardedControllerSendMessage 的依赖列表里、每次错误信息变化都重新生成回调。\n // 用 ref 也确保 fire-and-forget 的 send(DefaultComposer)拿到的是“最新一刻”的状态。\n const sessionClientsErrorRef = useRef<Error | null>(null)\n useEffect(() => {\n sessionClientsErrorRef.current = sessionClientsError ?? null\n }, [sessionClientsError])\n\n /**\n * `cidGuardedControllerSendMessage` —— sendMessage 的 cid 守门 + 兜底分配。\n *\n * 任务话池模型下:\n * - 调用方显式传入合法 v2 cid(浮窗 / annotation) → 直接使用;\n * - 调用方未传 cid 或传非 v2 → 走兜底:\n * 1) 若 currentClientId 已就绪(默认输入框场景)→ 用它;\n * 2) 否则现场调 allocator 创建一个空白「任务话池」并 setCurrent → 用新 cid;\n * 3) 分配失败(session 未建 / 网络错) → 抛 `InvalidClientIdError`,\n * 通过 onInteraction 上报(业务侧可 toast / 排队),不污染后端 routing 表。\n *\n * 不再有「主对话」特权概念:兜底分配出来的 cid 与其它任务话池完全对等。\n */\n const cidGuardedControllerSendMessage = useCallback(\n async (\n message: string,\n agentId?: string,\n inlineRefs?: import('./types').FileReference[],\n selectedSkills?: import('./types').SelectedSkillRef[],\n overrideInstanceId?: number | null,\n clientId?: string,\n fileAttachments?: import('./types').FileAttachment[],\n modelOverride?: import('./types').ModelOverride | null,\n ): Promise<void> => {\n const V2_RE = /^c_[A-Za-z0-9]{22}$/\n let cid = (clientId ?? '').trim()\n\n // ── Forbidden-session short-circuit ────────────────────────────────────────\n // 如果当前 session 已经被 useSessionClients 判为业务禁入(典型:HTTP 200 +\n // wrapper.code=400 \"Session not allowed\"),就**不要**再走 createClient\n // 兜底分配。理由:\n // 1) 后端会再回 \"Session not allowed\" → 我们 wrap 成\n // `InvalidClientIdError: Failed to allocate task pool: ...` 重新抛出;\n // 2) DefaultComposer 是 fire-and-forget 调用 api.sendMessage,没人 catch,\n // → 直接变成 \"Unhandled Promise Rejection\" 砸到控制台/上报;\n // 3) 用户体验上:错误已经在 SessionForbiddenBanner 里清楚展示了,再多 POST\n // 一次只是平白污染日志和 routing 表。\n // 直接抛带原始业务消息的 InvalidClientIdError,调用方(DefaultComposer 等)\n // 通过 .catch 静默吞掉,错误事件已经由上面的 SessionForbiddenBanner / 业务监听消费。\n const forbiddenErr = sessionClientsErrorRef.current\n if (forbiddenErr) {\n const err = new InvalidClientIdError(\n forbiddenErr.message || 'Session is not accessible.',\n 'session_forbidden',\n currentSessionId ?? null,\n )\n try {\n onInteraction?.({\n type: 'error',\n source: 'ChatWidget.sendMessage',\n code: 'CLIENT_ID_REQUIRED',\n reason: err.reason,\n message: err.message,\n } as unknown as import('./types').ChatWidgetInteractionEvent)\n } catch { /* swallow */ }\n throw err\n }\n\n if (!V2_RE.test(cid)) {\n // 1) 传入了非空但非 v2 → 直接拒(避免把 'main' / 'file:*' 等 legacy 字面量灌进 routing)\n if (cid) {\n const err = new InvalidClientIdError(\n `sendMessage received non-v2 client_id ${JSON.stringify(clientId)}.`,\n 'legacy_format',\n currentSessionId ?? null,\n )\n try {\n onInteraction?.({\n type: 'error',\n source: 'ChatWidget.sendMessage',\n code: 'CLIENT_ID_REQUIRED',\n reason: err.reason,\n message: err.message,\n } as unknown as import('./types').ChatWidgetInteractionEvent)\n } catch { /* swallow */ }\n throw err\n }\n\n // 2) 未传 → 优先 currentClientId\n const fromState = currentClientIdRef.current\n if (fromState && V2_RE.test(fromState)) {\n cid = fromState\n } else {\n // 3) 现场分配(带单飞);分配失败抛 InvalidClientIdError\n try {\n cid = await (sendBootstrapInflightRef.current ?? (sendBootstrapInflightRef.current = (async () => {\n let sid: string | number | null | undefined = currentSessionId\n if (sid === undefined || sid === null) {\n sid = await ensureSession()\n }\n if (sid === undefined || sid === null) {\n throw new InvalidClientIdError(\n 'Session is not ready; cannot allocate task pool.',\n 'session_not_ready',\n null,\n )\n }\n console.debug('[CW POST] from sendBootstrap', { sid })\n // JETP-073:协议归位,不传 title 让 PG 写 NULL;node_title_agent 在\n // first_agent_start 时派生真名后通过 CLIENT_TITLE event 推送给前端。\n // prependLocalClient 仍传 '任务话池' 作 SDK 内存态占位,仅本地 state,\n // 不写 PG;LLM 真名落 store 后 SessionListPanel 会自动覆盖显示。\n const newCid = await clientIdAllocator.createClient(sid, {})\n prependLocalClient({\n id: newCid,\n title: '任务话池',\n contextPreloads: [],\n isLegacy: false,\n archived: false,\n lastActiveAt: Date.now(),\n })\n setCurrentClientId(newCid)\n currentClientIdRef.current = newCid\n void refreshSessionClients()\n return newCid\n })()))\n } catch (e) {\n sendBootstrapInflightRef.current = null\n const err = e instanceof InvalidClientIdError\n ? e\n : new InvalidClientIdError(\n `Failed to allocate task pool: ${e instanceof Error ? e.message : String(e)}`,\n 'allocation_failed',\n currentSessionId ?? null,\n )\n try {\n onInteraction?.({\n type: 'error',\n source: 'ChatWidget.sendMessage',\n code: 'CLIENT_ID_REQUIRED',\n reason: err.reason,\n message: err.message,\n } as unknown as import('./types').ChatWidgetInteractionEvent)\n } catch { /* swallow */ }\n throw err\n } finally {\n // 不论成功/失败都清理 inflight:失败让下次重试有机会,成功让下次直接走 currentClientId 快路径\n sendBootstrapInflightRef.current = null\n }\n }\n }\n\n return controllerSendMessage(message, agentId, inlineRefs, selectedSkills, overrideInstanceId, cid, fileAttachments, modelOverride ?? null)\n },\n [controllerSendMessage, currentSessionId, ensureSession, clientIdAllocator, prependLocalClient, refreshSessionClients, onInteraction],\n )\n\n // 主区显示「当前选中任务话池」的 rounds。\n // currentClientId === null 时显示空(极少出现的边界,由 session 切换 effect 现场分配 cid 后立刻填上)。\n const currentClientRounds = useMemo(\n () => (currentClientId ? localRounds.filter(r => r.clientId === currentClientId) : []),\n [localRounds, currentClientId],\n )\n\n // 调试:rounds 在各 cid 间的实际分布 + 每个 round 的内容摘要\n useEffect(() => {\n const byCid = new Map<string, number>()\n for (const r of rounds) {\n const k = r.clientId ?? '(no-cid)'\n byCid.set(k, (byCid.get(k) ?? 0) + 1)\n }\n console.debug('[CW rounds breakdown]', {\n totalRounds: rounds.length,\n localCount: localRounds.length,\n foreignCount: foreignRounds.length,\n currentClientId,\n currentClientRoundsCount: currentClientRounds.length,\n sessionCidCount: sessionClientItems.length,\n historyClientIds,\n hasMore,\n perCidRoundCount: Object.fromEntries(byCid),\n })\n // 把每个 round 的结构都打出来\n rounds.forEach((r, i) => {\n const msgs = (r as unknown as { messages?: Array<Record<string, unknown>> }).messages ?? []\n console.debug(`[CW round#${i}]`, {\n interactionId: r.interactionId,\n clientId: r.clientId,\n index: (r as { index?: number }).index,\n messageCount: msgs.length,\n messageSummary: msgs.slice(0, 8).map(m => ({\n role: m.role,\n subType: m.subType ?? m.sub_type,\n textPreview: typeof m.content === 'string' ? (m.content as string).slice(0, 60) : `[${typeof m.content}]`,\n turnIndex: m.turnIndex ?? m.turn_index,\n calleeInstanceId: m.calleeInstanceId ?? m.callee_instance_id,\n })),\n })\n })\n }, [rounds, localRounds, foreignRounds, currentClientId, currentClientRounds, sessionClientItems, historyClientIds, hasMore])\n const [foreignBarOpen, setForeignBarOpen] = useState(false)\n\n const interactionDispatch = useCallback(\n (event: import('./types').ChatWidgetInteractionEvent) => onInteraction?.(event),\n [onInteraction],\n )\n\n // ── Extracted hooks ──\n const {\n messageListRef,\n isUserAtBottomRef,\n pinnedInteractionId,\n isTransitioning,\n pendingScrollInteractionId,\n setPendingScrollInteractionId,\n handleScroll,\n scrollToBottom,\n getSpacerHeight,\n setPinnedInteractionId,\n } = useScrollManager({ rounds, executionStatus })\n\n // JETP-037: sentinel ref + IntersectionObserver for infinite scroll\n const sentinelRef = useRef<HTMLDivElement>(null)\n const isProgrammaticScrollRef = useRef(false)\n\n useEffect(() => {\n const sentinel = sentinelRef.current\n const container = messageListRef.current\n if (!sentinel || !container || !hasMore) return\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting && hasMore && !loadingMore) {\n const prevScrollHeight = container.scrollHeight\n\n loadOlderPage().then(() => {\n isProgrammaticScrollRef.current = true\n requestAnimationFrame(() => {\n const newScrollHeight = container.scrollHeight\n container.scrollTop += newScrollHeight - prevScrollHeight\n setTimeout(() => {\n isProgrammaticScrollRef.current = false\n }, 50)\n })\n })\n }\n },\n {\n root: container,\n rootMargin: '300px 0px 0px 0px',\n },\n )\n\n observer.observe(sentinel)\n return () => observer.disconnect()\n }, [hasMore, loadingMore, loadOlderPage, messageListRef])\n\n const referenceManager = useReferenceManager({ dispatch: onInteraction ? interactionDispatch : null })\n const { references, addReference, removeReference } = referenceManager\n const referenceInsertHandlerRef = useRef<((ref: import('./types').FileReference) => void) | null>(null)\n\n const handleReference = useCallback((ref: import('./types').FileReference) => {\n if (referenceInsertHandlerRef.current) {\n referenceInsertHandlerRef.current(ref)\n } else {\n addReference(ref)\n }\n }, [addReference])\n\n const {\n viewerOpen,\n viewerLoading,\n viewerContent,\n viewerError,\n viewerArtifact,\n immersive,\n setImmersive,\n openArtifact: handleArtifactClick,\n closeViewer,\n } = useFileViewer({\n adapter,\n currentSessionId,\n onArtifactClick,\n errorMessage: i18n['viewer.error'],\n dispatch: onInteraction ? interactionDispatch : null,\n })\n\n // ── CWRF-010 Phase 1: Viewer tabs ──\n const viewerTabsApi = useViewerTabs()\n\n const allArtifacts = useMemo<ArtifactRef[]>(() => {\n const seen = new Set<string>()\n const result: ArtifactRef[] = []\n for (const round of rounds) {\n for (const m of round.messages) {\n if (m.artifacts) {\n for (const a of m.artifacts) {\n if (a.resource_id && !seen.has(a.resource_id)) {\n seen.add(a.resource_id)\n result.push({\n resourceId: a.resource_id,\n fileName: a.name || a.type || 'file',\n mimeType: a.mime_type,\n })\n }\n }\n }\n }\n }\n return result\n }, [rounds])\n\n const autoOpenSplit = useCallback(() => {\n if (!viewerOpen) handleArtifactClick(allArtifacts[0] as any)\n }, [viewerOpen, handleArtifactClick, allArtifacts])\n\n useAutoTab({\n artifacts: allArtifacts,\n tabs: viewerTabsApi,\n enabled: viewerOpen || immersive,\n autoOpenSplit,\n })\n\n // ── CWRF-010 Phase 2: Workspace files ──\n const {\n tree: workspaceTree,\n recentChanges: workspaceRecentChanges,\n fileCount: workspaceFileCount,\n refresh: workspaceRefresh,\n } = useWorkspaceFiles({\n adapter,\n sessionId: numericSessionId ?? null,\n wsConnected,\n })\n\n // ── CWRF-010 + JETP-038: Discussion files ──\n const currentUserAlias = propCurrentUserAlias ?? 'user'\n\n const {\n discussions,\n activeCount: activeDiscussionCount,\n newDiscussionIds,\n totalCount: discussionCount,\n postMessage: postDiscussionMessage,\n discussionUnread,\n clearDiscussionUnread,\n handleWsDiscussionUpdate,\n refresh: refreshDiscussions,\n } = useDiscussions({\n adapter,\n sessionId: numericSessionId ?? null,\n currentUser: currentUserAlias,\n wsConnected,\n poolAgents: poolObservation.poolAgents,\n })\n\n useEffect(() => {\n discussionUpdateRef.current = handleWsDiscussionUpdate\n }, [handleWsDiscussionUpdate])\n\n const treePersist = useTreePersist(numericSessionId ?? null)\n const treePersistState = useMemo(() => treePersist.load(), [treePersist])\n\n const handleTreeExpandChange = useCallback((paths: string[]) => {\n treePersist.save({ expandedPaths: paths, scrollTop: 0 })\n }, [treePersist])\n\n // ── CWRF-010 Phase 1-2-3: Overlay state for immersive mode ──\n const [activeOverlay, setActiveOverlay] = useState<'home' | 'workspace' | 'discussion' | 'annotation' | null>(null)\n\n const toggleOverlay = useCallback((overlay: 'home' | 'workspace' | 'discussion' | 'annotation') => {\n setActiveOverlay(prev => prev === overlay ? null : overlay)\n }, [])\n\n const handleRailHome = useCallback(() => toggleOverlay('home'), [toggleOverlay])\n const handleRailWorkspace = useCallback(() => toggleOverlay('workspace'), [toggleOverlay])\n const handleRailAnnotation = useCallback(() => toggleOverlay('annotation'), [toggleOverlay])\n\n const handleWorkspaceSelectFile = useCallback((file: WorkspaceFile) => {\n handleArtifactClick({\n id: file.resourceId,\n name: file.fileName,\n type: file.nodeType,\n } as Artifact)\n setActiveOverlay(null)\n }, [handleArtifactClick])\n\n // ── CWRF-010 Phase 3: Annotations ──\n const activeResourceId = useMemo(() => {\n if (viewerContent?.resource_id) return viewerContent.resource_id\n if ((viewerArtifact as any)?.resource_id) return (viewerArtifact as any).resource_id\n return null\n }, [viewerContent, viewerArtifact])\n\n const activeFileName = useMemo(() => {\n if (viewerArtifact?.name) return viewerArtifact.name\n if (viewerContent?.file_name) return viewerContent.file_name\n return 'file'\n }, [viewerContent, viewerArtifact])\n\n const [activeAnnotationId, setActiveAnnotationId] = useState<string | null>(null)\n const [inlineAnchor, setInlineAnchor] = useState<{\n rect: { top: number; left: number; width: number; height: number }\n anchor: { text: string; startLine?: number; endLine?: number }\n } | null>(null)\n\n // ── GenUI Page Viewer (JETP-033) — multi-page support ──\n const [genUIPageDismissed, setGenUIPageDismissed] = useState(false)\n const [genUIActiveSpecId, setGenUIActiveSpecId] = useState<string | null>(null)\n\n const genUIPages = useMemo(() => {\n const pageMap = new Map<string, { specId: string; patches: string[]; loading: boolean; resourceId?: string }>()\n const pageOrder: string[] = []\n for (const round of rounds) {\n for (const m of round.messages) {\n if (m.renderMode !== 'page' || !m.specId || !m.uiPatches || m.uiPatches.length === 0) continue\n\n const existing = pageMap.get(m.specId)\n if (existing) {\n existing.patches = [...existing.patches, ...m.uiPatches]\n if (!existing.resourceId) {\n existing.resourceId = specMetaMap.get(m.specId)?.resourceId\n }\n } else {\n pageMap.set(m.specId, { specId: m.specId, patches: [...m.uiPatches], loading: false, resourceId: specMetaMap.get(m.specId)?.resourceId })\n pageOrder.push(m.specId)\n }\n }\n }\n const pages = pageOrder.map(id => pageMap.get(id)!)\n if (pages.length > 0) {\n pages[pages.length - 1].loading = executionStatus === 'running'\n }\n return pages\n }, [rounds, executionStatus, specMetaMap])\n\n activeSpecIdsRef.current = useMemo(() => genUIPages.map(p => p.specId), [genUIPages])\n\n const genUIPageOpen = genUIPages.length > 0 && !genUIPageDismissed\n\n const prevPageCountRef = useRef(0)\n useEffect(() => {\n if (genUIPages.length === 0) return\n const latestSpecId = genUIPages[genUIPages.length - 1].specId\n if (genUIPages.length > prevPageCountRef.current) {\n setGenUIActiveSpecId(latestSpecId)\n setGenUIPageDismissed(false)\n }\n if (!genUIActiveSpecId) {\n setGenUIActiveSpecId(latestSpecId)\n }\n prevPageCountRef.current = genUIPages.length\n }, [genUIPages, genUIActiveSpecId])\n\n const closeGenUIPage = useCallback(() => {\n setGenUIPageDismissed(true)\n }, [])\n\n const openGenUIPage = useCallback((specId?: string) => {\n setGenUIPageDismissed(false)\n if (specId) setGenUIActiveSpecId(specId)\n }, [])\n\n const handleGenUIAsk = useCallback((ref: import('./types').FileReference) => {\n onSelectionAsk?.(ref)\n }, [onSelectionAsk])\n\n const { displayedTitle, isTitleAnimating } = useTypewriterTitle(sessionTitle)\n\n const {\n unreadCount,\n toasts,\n trackNewMessage,\n clearUnread,\n dismissToast,\n } = useAttentionManager({\n fileViewerOpen: viewerOpen,\n immersive,\n })\n\n // ── JETP-040: File upload hook (must be before orchestration so auto-bridge works) ──\n const fileUploadEnabled = !!adapter.uploadFiles\n // JETP-058: 上传路径专用的 cid 分配器。\n // - 如果 currentClientId 已存在(用户正在某个话池里)→ useFileUpload 直接使用,不调到这里;\n // - 否则(刚切到老 session 还没选话池 / 新建 session 边界)→ 现场 createClient\n // 生成 v2 cid,作为新话池注入 UI(与 sendMessage bootstrap 同样的副作用)。\n // useClientIdAllocator 内部已对 (sid, title, preloads) 做 inflight 去重,\n // 所以同一时刻多个 addFiles 调用会被合并为同一个 createClient 请求。\n const ensureClientIdForUpload = useCallback(async (): Promise<string> => {\n let sid: string | number | null | undefined = currentSessionId\n if (sid === undefined || sid === null) {\n sid = await ensureSession()\n }\n if (sid === undefined || sid === null) {\n throw new InvalidClientIdError(\n 'Session is not ready; cannot allocate task pool for upload.',\n 'session_not_ready',\n null,\n )\n }\n // JETP-073:同 sendBootstrap 注释 — 协议归位不传 title;本地 state 仍占位\n const newCid = await clientIdAllocator.createClient(sid, {})\n prependLocalClient({\n id: newCid,\n title: '任务话池',\n contextPreloads: [],\n isLegacy: false,\n archived: false,\n lastActiveAt: Date.now(),\n })\n setCurrentClientId(newCid)\n currentClientIdRef.current = newCid\n void refreshSessionClients()\n return newCid\n }, [currentSessionId, ensureSession, clientIdAllocator, prependLocalClient, refreshSessionClients])\n const fileUploadApi = useFileUpload({\n adapter,\n sessionId: currentSessionId,\n ensureSession,\n onUploadSuccess: workspaceRefresh,\n currentClientId,\n ensureClientId: ensureClientIdForUpload,\n })\n\n const prevSessionRef = useRef(currentSessionId)\n useEffect(() => {\n const prev = prevSessionRef.current\n if (prev !== currentSessionId) {\n // Only clear uploads on real session *switch* (old → new), not initial creation (null → new)\n if (prev != null && currentSessionId != null) {\n fileUploadApi.clear()\n }\n prevSessionRef.current = currentSessionId\n }\n }, [currentSessionId, fileUploadApi])\n\n // ── Orchestration: sendMessage wrapping, attention tracking, HITL, immersive send ──\n const {\n sendMessage,\n handleHITLSubmit,\n handleImmersiveSend,\n currentAgentIdRef,\n } = useChatOrchestration({\n // 强 cid 校验版本:sendMessage 必带 v2 c_<22>,否则抛错并通过 onInteraction 上报。\n controllerSendMessage: cidGuardedControllerSendMessage,\n rounds,\n references: referenceManager,\n scrollPrep: { setPendingScrollInteractionId, isUserAtBottomRef },\n attention: { trackNewMessage },\n adapter,\n currentSessionId,\n viewerContent,\n onHITLSubmit,\n interactionDispatch,\n fileUpload: fileUploadEnabled ? fileUploadApi : undefined,\n // 默认输入框(footer / immersive)发送时回退到当前选中的任务话池 cid\n defaultClientIdRef: currentClientIdRef,\n })\n\n // ── CWRF-010 Phase 3 / JETP-058 Annotation hooks ──\n // 注入 v2 cid allocator:file/selection annotation 不再用字面量 ``file:`` / ``sel:``,\n // 改成调 /api/session/{sid}/clients 现场分配 v2 ``c_<22>``,\n // 业务上下文(resourceId / anchor 文本 / 范围哈希)下沉到 context_preloads。\n const annotateAllocate = useCallback(\n async (opts: {\n kind: 'file' | 'selection'\n resourceId: string\n anchor?: { text?: string; startLine?: number; endLine?: number }\n title?: string\n }): Promise<string> => {\n if (currentSessionId === undefined || currentSessionId === null) {\n throw new InvalidClientIdError(\n 'Cannot allocate annotation client_id: session is not ready.',\n 'session_not_ready',\n null,\n )\n }\n const preloads: import('./hooks/useClientIdAllocator').ContextPreload[] = [\n opts.kind === 'file'\n ? { kind: 'file', refId: opts.resourceId }\n : {\n kind: 'selection',\n refId: opts.resourceId,\n // anchor.text 摘要 + 起止行作为 rangeHash 的人类可读表征\n rangeHash: `${opts.anchor?.startLine ?? ''}-${opts.anchor?.endLine ?? ''}:${(opts.anchor?.text ?? '').slice(0, 64)}`,\n },\n ]\n console.debug('[CW POST] from annotation openClient', { sid: currentSessionId, kind: opts.kind })\n const cid = await clientIdAllocator.createClient(currentSessionId, {\n title: opts.title ?? (opts.kind === 'file' ? '文件批注' : '选区问答'),\n contextPreloads: preloads,\n })\n // sidebar 乐观插入;后台 refresh 取权威排序与 metadata。\n prependLocalClient({\n id: cid,\n title: opts.title ?? (opts.kind === 'file' ? '文件批注' : '选区问答'),\n contextPreloads: preloads,\n isLegacy: false,\n archived: false,\n lastActiveAt: Date.now(),\n })\n void refreshSessionClients()\n return cid\n },\n [clientIdAllocator, currentSessionId, prependLocalClient, refreshSessionClients],\n )\n\n const annotationsApi = useAnnotations({\n sendMessage,\n rounds,\n activeResourceId,\n allocateClientId: annotateAllocate,\n })\n\n const handleSelectionAsk = useCallback((ref: import('./types').FileReference) => {\n const resId = activeResourceId || ref.resourceId\n if (immersive && ref.selection && resId) {\n const sel = window.getSelection()\n let rect = { top: 200, left: 200, width: 100, height: 20 }\n if (sel && sel.rangeCount > 0) {\n const domRect = sel.getRangeAt(0).getBoundingClientRect()\n rect = { top: domRect.top, left: domRect.left, width: domRect.width, height: domRect.height }\n }\n setInlineAnchor({\n rect,\n anchor: { text: ref.selection.text, startLine: ref.selection.startLine, endLine: ref.selection.endLine },\n })\n } else {\n // 宿主可监听 onSelectionAsk;未接管时须落回默认行为(插入引用 / ContextChip),否则\n // FileViewerPanel 在存在 onSelectionAsk 时不会调用 onReference,Demo 等集成会「问一下无反应」。\n onSelectionAsk?.(ref)\n if (!onSelectionAsk) {\n handleReference(ref)\n }\n }\n }, [immersive, activeResourceId, onSelectionAsk, handleReference])\n\n // 选区追问:startAnchoredAnnotation 异步分配 v2 cid 并发首条消息;\n // 这里记下 annotation groupKey,待 useAnnotations 解析到 round 拿到 clientId 后,\n // 由下方 effect 把对应浮窗 open 起来。\n const pendingSelQAChannelRef = useRef<string | null>(null)\n\n const handleInlineAnnotationSend = useCallback((message: string) => {\n if (!activeResourceId || !inlineAnchor) return\n const anchor = inlineAnchor.anchor\n void annotationsApi.startAnchoredAnnotation(activeResourceId, anchor, message)\n pendingSelQAChannelRef.current = anchoredGroupKey(activeResourceId, anchor)\n setInlineAnchor(null)\n }, [activeResourceId, inlineAnchor, annotationsApi])\n\n const handleInlineAnnotationClose = useCallback(() => {\n setInlineAnchor(null)\n }, [])\n\n const handleAnnotationFABSend = useCallback((message: string) => {\n if (!activeResourceId) return\n annotationsApi.startFileLevelAnnotation(activeResourceId, message)\n }, [activeResourceId, annotationsApi])\n\n const handleAnnotationFollowUp = useCallback((annotationId: string, text: string) => {\n annotationsApi.sendFollowUp(annotationId, text)\n }, [annotationsApi])\n\n const annotationPanelFileLevelConv = useMemo(() => {\n const fl = annotationsApi.fileLevelForResource\n if (!fl) return null\n return {\n id: fl.id,\n messages: annotationsApi.getMessages(fl.id) as AnnotationPanelMessage[],\n preview: fl.preview,\n }\n }, [annotationsApi])\n\n const annotationPanelAnchored = useMemo(() => {\n return annotationsApi.anchoredForResource.map(a => ({\n id: a.id,\n anchor: a.anchor ? { text: a.anchor.text || '', startLine: a.anchor.startLine, endLine: a.anchor.endLine } : undefined,\n messages: annotationsApi.getMessages(a.id) as AnnotationPanelMessage[],\n preview: a.preview,\n }))\n }, [annotationsApi])\n\n // ── CWRF-010 v2: Channel Sidebar + Floating Conversation Windows ──\n // 全部以「任务话池 cid」为单位渲染,对等。\n const floatingWindows = useFloatingWindows()\n const HIGHLIGHT_COLORS = ['rgba(99,102,241,0.2)', 'rgba(16,185,129,0.2)', 'rgba(245,158,11,0.2)']\n\n // cid → annotation interaction(仅当 cid 由 annotation 流程分配且已在 round 中观察到 clientId 才会建立映射)\n const cidToAnnotation = useMemo(() => {\n const m = new Map<string, typeof annotationsApi.interactions[number]>()\n for (const a of annotationsApi.interactions) {\n if (a.clientId) m.set(a.clientId, a)\n }\n return m\n }, [annotationsApi.interactions])\n\n // 按 contextPreloads.kind 分桶;annotation 派生的 cid 一定带 file/selection preload,\n // 没有 preload 的就是普通任务话池(chat)。\n function preloadKind(it: { contextPreloads?: unknown[] }): 'file' | 'selection' | null {\n const list = Array.isArray(it.contextPreloads) ? it.contextPreloads : []\n for (const p of list) {\n if (p && typeof p === 'object' && 'kind' in p) {\n const k = (p as { kind?: unknown }).kind\n if (k === 'file' || k === 'selection') return k\n }\n }\n return null\n }\n\n const channelCategories = useMemo<ChannelCategory[]>(() => {\n const chatChannels: ChannelCategory['channels'] = []\n const fileQAChannels: ChannelCategory['channels'] = []\n const selectionQAChannels: ChannelCategory['channels'] = []\n\n for (const it of sessionClientItems) {\n if (it.archived) continue\n const ann = cidToAnnotation.get(it.id)\n const kind = preloadKind(it) ?? (ann ? (ann.kind === 'anchored' ? 'selection' : 'file') : null)\n const isActive = floatingWindows.isOpen(it.id) || it.id === currentClientId\n if (kind === 'selection') {\n const anchor = ann?.anchor\n const label = anchor?.text\n ? (anchor.startLine != null ? `L${anchor.startLine} ` : '') + `\"${anchor.text.slice(0, 16)}${anchor.text.length > 16 ? '…' : ''}\"`\n : (it.title || ann?.preview || '选区')\n const ch: ChannelCategory['channels'][number] = {\n id: it.id,\n label,\n kind: 'selection-qa',\n unreadCount: 0,\n isActive,\n }\n if (ann?.resourceId) (ch as { resourceId?: string }).resourceId = ann.resourceId\n if (anchor) (ch as { anchor?: typeof anchor }).anchor = anchor\n selectionQAChannels.push(ch)\n } else if (kind === 'file') {\n const label = it.title || ann?.preview || activeFileName || 'file'\n const ch: ChannelCategory['channels'][number] = {\n id: it.id,\n label,\n kind: 'file-qa',\n unreadCount: 0,\n isActive,\n }\n if (ann?.resourceId) (ch as { resourceId?: string }).resourceId = ann.resourceId\n fileQAChannels.push(ch)\n } else {\n chatChannels.push({\n id: it.id,\n label: it.title || '任务话池',\n kind: 'chat',\n unreadCount: it.id === currentClientId ? unreadCount : 0,\n isActive,\n })\n }\n }\n\n return [\n { id: 'cat-chat', label: i18n['sidebar.chat'] ?? '对话', iconName: 'chat', channels: chatChannels },\n { id: 'cat-file-qa', label: i18n['sidebar.fileQA'] ?? '文件问答', iconName: 'file', channels: fileQAChannels },\n { id: 'cat-sel-qa', label: i18n['sidebar.selectionQA'] ?? '选区问答', iconName: 'chatCircleDots', channels: selectionQAChannels },\n ]\n }, [sessionClientItems, cidToAnnotation, floatingWindows, currentClientId, unreadCount, activeFileName, i18n])\n\n const handleChannelClick = useCallback((clientId: string) => {\n setCurrentClientId(clientId)\n floatingWindows.toggle(clientId)\n }, [floatingWindows])\n\n // 选区追问发起后:若 annotation 已分配 v2 cid 且对应浮窗未打开,则自动打开它。\n // 不再使用 ``ch:sel:*`` 字面量做兜底通信。\n useEffect(() => {\n const pendingId = pendingSelQAChannelRef.current\n if (!pendingId) return\n const ann = annotationsApi.interactions.find(a => a.id === pendingId)\n if (ann?.clientId) {\n floatingWindows.open(ann.clientId)\n pendingSelQAChannelRef.current = null\n }\n }, [annotationsApi.interactions, floatingWindows])\n\n const getMessagesForChannel = useCallback((clientId: string): FloatingMessage[] => {\n // 优先走 annotation 解析(保留 stripAnnotationMarker 等渲染语义)\n const ann = cidToAnnotation.get(clientId)\n if (ann) {\n const annMsgs = annotationsApi.getMessages(ann.id)\n return annMsgs.map(m => ({\n role: m.role as 'user' | 'assistant',\n text: m.text,\n timestamp: m.timestamp,\n }))\n }\n // 普通任务话池:直接按 cid 过滤 localRounds\n const msgs: FloatingMessage[] = []\n for (const round of localRounds) {\n if (round.clientId !== clientId) continue\n if (round.userMessage) {\n const userTs =\n round.startedAt ??\n (() => {\n const parsed = Date.parse(round.timestamp)\n return Number.isNaN(parsed) ? undefined : parsed\n })()\n msgs.push({ role: 'user', text: round.userMessage, timestamp: userTs })\n }\n for (const m of round.messages) {\n if (m.contentType === 'text' && m.contentChunks && m.contentChunks.length > 0) {\n const parsed = Date.parse(m.timestamp)\n msgs.push({\n role: 'assistant',\n text: m.contentChunks.join(''),\n timestamp: Number.isNaN(parsed) ? undefined : parsed,\n })\n }\n }\n }\n return msgs\n }, [localRounds, annotationsApi, cidToAnnotation])\n\n const handleFloatingSend = useCallback((clientId: string, text: string) => {\n // annotation cid → 走 annotationsApi.sendFollowUp 保留 marker 语义;\n // 否则走 sendMessage 显式带本浮窗 cid。\n const ann = cidToAnnotation.get(clientId)\n if (ann) {\n void Promise.resolve(annotationsApi.sendFollowUp(ann.id, text)).catch(() => {})\n return\n }\n // 浮窗 send 也可能因 session 被禁入抛 InvalidClientIdError;显式吞掉避免 unhandled rejection。\n void Promise.resolve(sendMessage(text, undefined, undefined, undefined, undefined, clientId)).catch(() => {})\n }, [sendMessage, annotationsApi, cidToAnnotation])\n\n const getChannelTitle = useCallback((clientId: string): string => {\n for (const cat of channelCategories) {\n const ch = cat.channels.find(c => c.id === clientId)\n if (ch) return ch.label\n }\n const ann = cidToAnnotation.get(clientId)\n if (ann?.preview) return ann.preview\n return ''\n }, [channelCategories, cidToAnnotation])\n\n const activeSelectionChannels = useMemo(() => {\n return floatingWindows.windows\n .map(w => cidToAnnotation.get(w.clientId))\n .filter((a): a is NonNullable<typeof a> => !!a && a.kind === 'anchored')\n }, [floatingWindows.windows, cidToAnnotation])\n\n const selectionHighlights = useMemo<SelectionHighlightItem[]>(() => {\n const topWindow = floatingWindows.windows.length > 0\n ? floatingWindows.windows.reduce((a, b) => a.zIndex > b.zIndex ? a : b)\n : null\n\n return activeSelectionChannels.flatMap((interaction, idx) => {\n if (!interaction?.anchor) return []\n const isTopWindow = !!interaction.clientId && topWindow?.clientId === interaction.clientId\n const item: SelectionHighlightItem = {\n id: interaction.id,\n text: interaction.anchor.text || '',\n color: HIGHLIGHT_COLORS[idx % HIGHLIGHT_COLORS.length],\n active: isTopWindow,\n }\n if (interaction.anchor.startLine != null) {\n item.startLine = interaction.anchor.startLine\n }\n if (interaction.anchor.endLine != null) {\n item.endLine = interaction.anchor.endLine\n }\n return [item]\n })\n }, [activeSelectionChannels, floatingWindows.windows])\n\n const viewerContainerRef = useRef<HTMLDivElement>(null)\n\n useSmartPaste({\n enabled: true,\n onReference: handleReference,\n })\n\n // PinnedArea 必须严格按当前任务话池 cid 过滤,否则会把别的 cid 最后一条 round\n // (甚至 agent 自发产生的、没有 userMessage 的 round)钉到顶上 → 显示\n // \"(无消息内容)\" + \"Invalid Date\" 串台。源数据用 currentClientRounds 而非 rounds。\n // 同时跳过没有 userMessage 的 round(它们没法作为\"上一条用户问题\"被钉住)。\n const pinnedRound = useMemo(() => {\n if (pinnedInteractionId) {\n const pinned = currentClientRounds.find(r => r.interactionId === pinnedInteractionId)\n if (pinned && pinned.userMessage) return pinned\n return null\n }\n if (currentClientRounds.length === 0) return null\n for (let i = currentClientRounds.length - 1; i >= 0; i--) {\n const r = currentClientRounds[i]\n if (r.userMessage) return r\n }\n return null\n }, [currentClientRounds, pinnedInteractionId])\n\n const setReferenceInsertHandler = useCallback((handler: ((ref: import('./types').FileReference) => void) | null) => {\n referenceInsertHandlerRef.current = handler\n }, [])\n\n // 开一个新「任务话池」浮动窗。先在后端创建 v2 client,再把它推入浮动窗。\n const openClientWindow = useCallback(\n async (opts: { title?: string; contextPreloads?: unknown[] }): Promise<string> => {\n if (currentSessionId === undefined || currentSessionId === null) {\n throw new Error('openClientWindow requires an active session')\n }\n console.debug('[CW POST] from openClientWindow', { sid: currentSessionId, title: opts?.title })\n const cid = await clientIdAllocator.createClient(currentSessionId, {\n title: opts?.title,\n contextPreloads: opts?.contextPreloads as never,\n })\n floatingWindows.openWith({\n clientId: cid,\n title: opts?.title,\n contextPreloads: opts?.contextPreloads,\n })\n prependLocalClient({\n id: cid,\n title: opts?.title ?? '',\n contextPreloads: Array.isArray(opts?.contextPreloads) ? opts.contextPreloads : [],\n isLegacy: false,\n archived: false,\n lastActiveAt: Date.now(),\n })\n // 新建即视为当前选中的任务话池\n setCurrentClientId(cid)\n void refreshSessionClients()\n return cid\n },\n [clientIdAllocator, currentSessionId, floatingWindows, prependLocalClient, refreshSessionClients],\n )\n\n // session(项目)切换时初始化 currentClientId(任务话池):\n // - items 已有非 archived 的 cid → 选第一个(lastActiveAt 排序的最新)\n // - items 为空 → 现场分配一个空白任务话池\n // 若 currentClientId 已经属于当前 items 则保持不变,避免抖动。\n //\n // ★ 关键守门(正向断言):必须 ``sessionClientsLoadedSid === currentSessionId`` 才允许\n // 走\"items 为空 → 创建新空白话池\"分支。**严禁**用 hook 的 loading 反向守门——\n // 原因:useSessionClients 在 sessionId 切换时通过 useEffect 调度 setLoading(true),\n // 而本 effect 与该 useEffect 在同一 commit 阶段触发,闭包捕获的是 Render N 的旧\n // state(loading=false),守门会被绕过 → POST 创建新 cid → 顶掉历史话池 →\n // \"等待对话开始...\"。loadedSessionId 是 fetch 完成后才前推、且会被 sessionId\n // 切换重置为 null 的状态量,闭包里读到的值天然只能是\"已为该 sid 拉过\"或 null,\n // 不存在时序漂移。\n // 派生:rounds 里实际出现过的 cid(\"真正有历史/活动\"的 cid)。\n // 注意:用 join 形式做依赖,否则 rounds 任意微变都会导致 init-effect 重跑。\n const cidsWithRoundsList = useMemo(() => {\n const seen = new Set<string>()\n for (const r of rounds) {\n const cid = (r as { clientId?: string | null }).clientId\n if (cid && !seen.has(cid)) seen.add(cid)\n }\n return Array.from(seen)\n }, [rounds])\n const cidsWithRoundsKey = cidsWithRoundsList.join('|')\n\n const sessionInitInflightRef = useRef<Set<string | number>>(new Set())\n // 防御:abort-on-error 分支的\"已记录上下文\",避免在不可避免的 deps churn(例如\n // controller SSE 心跳引发的父级 re-render)下把同一条 \"Session not allowed\" 信息\n // 重复刷上百行。键 = `${sid}|${err.message}`,键变化才再次 log。\n const lastInitAbortKeyRef = useRef<string | null>(null)\n // 同样防御:enter 日志按\"实际语义变化\"去重——如果 sid/cid/loadedSid/items快照/error 都没变,\n // 就跳过 enter log,避免 SSE 心跳等无意义 deps churn 把控制台刷成几千行。\n const lastInitEnterKeyRef = useRef<string | null>(null)\n useEffect(() => {\n const enterKey = [\n currentSessionId,\n currentClientId,\n sessionClientsLoadedSid,\n sessionClientItems.map(i => `${i.id}:${i.archived ? 1 : 0}`).join(','),\n sessionClientsError?.message ?? '',\n cidsWithRoundsKey,\n ].join('|')\n if (lastInitEnterKeyRef.current !== enterKey) {\n lastInitEnterKeyRef.current = enterKey\n console.debug('[CW init-effect] enter', {\n currentSessionId,\n currentClientId,\n sessionClientsLoadedSid,\n itemsCount: sessionClientItems.length,\n itemsSorted: sessionClientItems.map(i => ({\n id: i.id,\n archived: i.archived,\n lastActiveAt: i.lastActiveAt,\n title: i.title,\n })),\n cidsWithRounds: cidsWithRoundsList,\n inflight: Array.from(sessionInitInflightRef.current),\n })\n }\n if (currentSessionId === undefined || currentSessionId === null) {\n console.debug('[CW init-effect] → null sid, clear currentClientId')\n setCurrentClientId(null)\n return\n }\n\n // ★ 优先级 1:「rounds 中出现过的 cid」就是真正有历史的话池。\n // 旧逻辑按 lastActiveAt desc 取 firstAlive,会被历史 bug 留下来的\"空话池\"\n // (同一 session 里 lastActiveAt 比真正话池新但里面 0 turn)顶包 → 主区\n // `currentClientRounds = localRounds.filter(r => r.clientId === currentClientId)`\n // 过滤出 0 → \"等待对话开始...\",且历史 round 因 controller 把所有 history\n // interaction_id 都加进 localInteractionIds 也不会出现在 foreignBar。\n // 这里只要 history 已加载(rounds 非空),就强制把 currentClientId 切到\n // 有 round 的 cid(取 rounds[0],convertTurnsToRounds 默认按时间倒序,\n // 即用户最近活动的话池),保证 UI 首屏就能看见历史。\n if (cidsWithRoundsList.length > 0) {\n if (currentClientId && cidsWithRoundsList.includes(currentClientId)) {\n console.debug('[CW init-effect] → currentClientId in rounds, keep')\n return\n }\n const target = cidsWithRoundsList[0]\n console.debug('[CW init-effect] → pick cid from rounds', target)\n setCurrentClientId(target)\n return\n }\n\n // ★ 优先级 2:rounds 还没拉到(首屏 controller 异步在飞)。\n // 占位:保持已选 cid(如果它仍在 items 里);否则按 firstAlive 选一个。\n // 等 controller 把历史拉回来,上面优先级 1 会接管并切换到正确 cid。\n if (currentClientId && sessionClientItems.some(it => !it.archived && it.id === currentClientId)) {\n console.debug('[CW init-effect] → currentClientId already in items, keep')\n return\n }\n const firstAlive = sessionClientItems.find(it => !it.archived)\n if (firstAlive) {\n console.debug('[CW init-effect] → pick firstAlive (placeholder)', firstAlive.id)\n setCurrentClientId(firstAlive.id)\n return\n }\n // 必须等到 hook 已成功(或失败)为当前 sid 完成至少一次 GET /clients。\n if (sessionClientsLoadedSid !== currentSessionId) {\n console.debug('[CW init-effect] → wait for loadedSid match', {\n loadedSid: sessionClientsLoadedSid,\n sid: currentSessionId,\n })\n return\n }\n // 关键熔断:上次拉取报错就**不要**走\"空 session → CREATE NEW EMPTY CID\"分支。\n // 否则一旦后端因业务原因(如 \"Session not allowed\")拒绝 GET,前端会被误导\n // 成空 session → 紧接着 POST /clients 又被同一原因拒绝 → useEffect 依赖\n // (sessionClientsLoadedSid + currentClientId) 不变, 但 inflight Set 在\n // catch finally 里会被 delete → 下一次 render 又触发 → 无限 POST 死循环\n // (正是 screenshot 里 \"→ CREATE NEW EMPTY CID\" 反复刷屏的成因)。\n if (sessionClientsError) {\n const abortKey = `${currentSessionId}|${sessionClientsError.message}`\n if (lastInitAbortKeyRef.current !== abortKey) {\n lastInitAbortKeyRef.current = abortKey\n console.debug('[CW init-effect] → sessionClients has error, abort auto-create', {\n sid: currentSessionId,\n err: sessionClientsError.message,\n })\n }\n return\n }\n // 一旦不再处于 forbidden 状态(用户成功 self-join 后 refresh),重置 dedup 键,\n // 让下一次再出现的 forbidden 仍能首次记录。\n if (lastInitAbortKeyRef.current !== null) lastInitAbortKeyRef.current = null\n // 空 session:现场分配一个任务话池(防抖:每个 sid 只做一次)\n const sid = currentSessionId\n if (sessionInitInflightRef.current.has(sid)) {\n console.debug('[CW init-effect] → already inflight for', sid)\n return\n }\n console.debug('[CW init-effect] → CREATE NEW EMPTY CID for', sid)\n sessionInitInflightRef.current.add(sid)\n void (async () => {\n try {\n console.debug('[CW POST] from init-effect', { sid })\n // JETP-073:协议归位,不传 title;同 sendBootstrap 注释\n const cid = await clientIdAllocator.createClient(sid, {})\n console.debug('[CW init-effect] CREATE OK', { sid, cid })\n prependLocalClient({\n id: cid,\n title: '任务话池',\n contextPreloads: [],\n isLegacy: false,\n archived: false,\n lastActiveAt: Date.now(),\n })\n setCurrentClientId(cid)\n void refreshSessionClients()\n } catch (e) {\n console.error('[ChatWidget] session 初始化任务话池失败:', e)\n } finally {\n sessionInitInflightRef.current.delete(sid)\n }\n })()\n }, [currentSessionId, sessionClientItems, sessionClientsLoadedSid, sessionClientsError, currentClientId, clientIdAllocator, prependLocalClient, refreshSessionClients, cidsWithRoundsList, cidsWithRoundsKey])\n\n const widgetAPI = useMemo<ChatWidgetAPI>(() => ({\n ...controllerWidgetAPI,\n sendMessage,\n scrollToBottom,\n setReferenceInsertHandler,\n openClientWindow,\n fileUpload: fileUploadEnabled ? {\n ...fileUploadApi,\n enabled: true,\n } : undefined,\n }), [controllerWidgetAPI, sendMessage, scrollToBottom, setReferenceInsertHandler, openClientWindow, fileUploadEnabled, fileUploadApi])\n\n useEffect(() => {\n onReady?.(widgetAPI)\n }, [onReady, widgetAPI])\n\n return (\n <I18nContext.Provider value={i18n}>\n <InteractionContext.Provider value={onInteraction ? interactionDispatch : null}>\n <AdapterProvider adapter={adapter}>\n <ResourceProvider adapter={adapter} sessionId={numericSessionId}>\n <GenUIProvider\n adapter={adapter}\n sessionId={numericSessionId != null ? numericSessionId : null}\n clientId={currentClientId}\n agentWaiting={executionStatus === 'running'}\n registry={genUIRegistry}\n openPageViewer={openGenUIPage}\n pendingHILBySpecId={pendingHILBySpecId}\n specLifecycleBySpecId={specLifecycleMap}\n >\n <div \n className={`ycw ${THEME_CLASS[resolvedTheme] ?? ''} ${className || ''}`}\n style={{ ...style, height }}\n >\n {/* 头部 */}\n <div className=\"ycw-header\">\n <div className=\"ycw-header-title\">\n <span className=\"ycw-header-icon\">\n <Icon name=\"robot\" size={20} aria-hidden={true} />\n </span>\n <span>{i18n['header.title']}</span>\n </div>\n \n {/* Session Title - 居中显示,打字机效果 */}\n {displayedTitle && (\n <div className={`ycw-session-title ${isTitleAnimating ? 'ycw-animating' : ''}`}>\n <span className=\"ycw-session-title-text\">{displayedTitle}</span>\n {isTitleAnimating && <span className=\"ycw-title-cursor\">|</span>}\n </div>\n )}\n \n <div className=\"ycw-header-actions\">\n {workspaceFileCount > 0 && (\n <button\n className=\"ycw-header-workspace-btn\"\n onClick={() => setActiveOverlay(prev => prev === 'workspace' ? null : 'workspace')}\n title={i18n['workspace.title'] ?? 'Workspace'}\n aria-label={i18n['workspace.title'] ?? 'Workspace'}\n >\n <Icon name=\"folder\" size={18} aria-hidden />\n {workspaceFileCount > 0 && (\n <span className=\"ycw-header-workspace-count\">{workspaceFileCount}</span>\n )}\n </button>\n )}\n {discussionCount > 0 && (\n <button\n className=\"ycw-header-discussion-btn\"\n onClick={() => {\n setActiveOverlay(prev => prev === 'discussion' ? null : 'discussion')\n if (activeOverlay !== 'discussion') clearDiscussionUnread()\n }}\n title=\"讨论\"\n aria-label=\"讨论\"\n >\n <Icon name=\"chatCircleDots\" size={18} aria-hidden />\n {activeDiscussionCount > 0 && (\n <span className=\"ycw-header-discussion-count\">{activeDiscussionCount}</span>\n )}\n {discussionUnread > 0 && (\n <span className=\"ycw-header-discussion-unread\">{discussionUnread}</span>\n )}\n {newDiscussionIds.size > 0 && discussionUnread === 0 && (\n <span className=\"ycw-header-discussion-dot\" />\n )}\n </button>\n )}\n {currentSessionId != null && renderHeaderExtra?.(currentSessionId)}\n <PoolStatusPopover\n agents={poolObservation.poolAgents}\n sessionBusy={sessionBusy}\n connectionStatus={connectionStatus}\n i18n={i18n}\n />\n </div>\n </div>\n\n {/* SplitPanel: 对话 + 文件面板并排 (CWRF-002 / CWRF-010) */}\n <SplitPanel\n open={viewerOpen || genUIPageOpen}\n onClose={() => { closeViewer(); closeGenUIPage(); clearUnread(); setActiveOverlay(null) }}\n immersive={immersive}\n onImmersiveChange={setImmersive}\n unreadCount={unreadCount}\n onChatFocus={clearUnread}\n references={references}\n onImmersiveSend={handleImmersiveSend}\n onRemoveReference={removeReference}\n toasts={toasts}\n onDismissToast={dismissToast}\n tabs={viewerTabsApi.tabs}\n activeTabId={viewerTabsApi.activeTabId}\n onTabSwitch={viewerTabsApi.switchTab}\n onTabClose={viewerTabsApi.removeTab}\n onRailHome={handleRailHome}\n onRailWorkspace={handleRailWorkspace}\n onRailAnnotation={handleRailAnnotation}\n annotationCount={annotationsApi.interactions.length}\n activeOverlay={activeOverlay}\n contextLabel={activeFileName}\n overlayContent={\n <>\n <ChatOverlay\n open={activeOverlay === 'home'}\n onClose={() => setActiveOverlay(null)}\n unreadCount={unreadCount}\n >\n <RoundsView\n rounds={localRounds}\n config={config}\n todoMap={todoMap}\n observedInstanceStates={poolObservation.instanceStates}\n onArtifactClick={handleArtifactClick}\n onHITLSubmit={handleHITLSubmit}\n renderToolResult={renderToolResult}\n className=\"ycw-message-list--overlay\"\n />\n </ChatOverlay>\n <WorkspacePanel\n open={activeOverlay === 'workspace'}\n onClose={() => setActiveOverlay(null)}\n tree={workspaceTree}\n recentChanges={workspaceRecentChanges}\n onSelectFile={handleWorkspaceSelectFile}\n highlightedIds={new Set(workspaceRecentChanges.map(f => f.resourceId))}\n initialExpandedPaths={treePersistState?.expandedPaths}\n onExpandStateChange={handleTreeExpandChange}\n onDownloadAll={\n adapter.downloadWorkspaceZip && numericSessionId != null\n ? () => adapter.downloadWorkspaceZip!(numericSessionId)\n : undefined\n }\n onUploadFiles={\n adapter.uploadWorkspaceFiles && numericSessionId != null\n ? async (files: File[], targetDirectory?: string) => {\n // JETP-058: WorkspacePanel 上传同样必须带 v2 cid。\n // 优先复用 currentClientId;缺失则现场分配(与拖入输入框一致)。\n const cid = currentClientIdRef.current ?? await ensureClientIdForUpload()\n await adapter.uploadWorkspaceFiles!(numericSessionId, files, { targetDirectory, clientId: cid })\n workspaceRefresh()\n }\n : undefined\n }\n onCreateFolder={\n adapter.createWorkspaceDirectory && numericSessionId != null\n ? async (folderName: string, parentPath?: string) => {\n await adapter.createWorkspaceDirectory!(numericSessionId, folderName, parentPath)\n workspaceRefresh()\n }\n : undefined\n }\n onRename={\n adapter.renameWorkspaceItem && numericSessionId != null\n ? async (oldPath: string, newName: string) => {\n await adapter.renameWorkspaceItem!(numericSessionId, oldPath, newName)\n workspaceRefresh()\n }\n : undefined\n }\n onDelete={\n adapter.deleteWorkspaceItems && numericSessionId != null\n ? async (paths: string[]) => {\n await adapter.deleteWorkspaceItems!(numericSessionId, paths)\n workspaceRefresh()\n }\n : undefined\n }\n onMove={\n adapter.moveWorkspaceItems && numericSessionId != null\n ? async (sourcePaths: string[], targetDir: string) => {\n await adapter.moveWorkspaceItems!(numericSessionId, sourcePaths, targetDir)\n workspaceRefresh()\n }\n : undefined\n }\n onCopy={\n adapter.copyWorkspaceItems && numericSessionId != null\n ? async (sourcePaths: string[], targetDir: string) => {\n await adapter.copyWorkspaceItems!(numericSessionId, sourcePaths, targetDir)\n workspaceRefresh()\n }\n : undefined\n }\n />\n <DiscussionPanel\n open={activeOverlay === 'discussion'}\n onClose={() => { setActiveOverlay(null); clearDiscussionUnread() }}\n discussions={discussions}\n newDiscussionIds={newDiscussionIds}\n currentUserAlias={currentUserAlias}\n sessionId={numericSessionId}\n adapter={adapter}\n poolAgents={poolObservation.poolAgents}\n onRefresh={refreshDiscussions}\n onPostMessage={postDiscussionMessage}\n />\n <AnnotationPanel\n open={activeOverlay === 'annotation'}\n onClose={() => setActiveOverlay(null)}\n fileLevelConversation={annotationPanelFileLevelConv}\n anchoredAnnotations={annotationPanelAnchored}\n activeAnnotationId={activeAnnotationId}\n onSetActive={setActiveAnnotationId}\n onSendFollowUp={handleAnnotationFollowUp}\n isCreating={annotationsApi.isCreating}\n />\n </>\n }\n fabContent={\n immersive ? (\n <>\n <AnnotationFAB\n resourceId={activeResourceId}\n fileName={activeFileName}\n onSend={handleAnnotationFABSend}\n visible={immersive && activeOverlay !== 'annotation'}\n disabled={annotationsApi.isCreating}\n />\n {inlineAnchor && (\n <InlineAnnotationInput\n anchorRect={inlineAnchor.rect}\n anchorText={inlineAnchor.anchor.text}\n onSend={handleInlineAnnotationSend}\n onClose={handleInlineAnnotationClose}\n onFallback={() => {\n setInlineAnchor(null)\n }}\n />\n )}\n </>\n ) : undefined\n }\n sidebarContent={\n immersive ? (\n <ChannelSidebar\n categories={channelCategories}\n onChannelClick={handleChannelClick}\n onExitImmersive={() => {\n setImmersive(false)\n setActiveOverlay(null)\n }}\n />\n ) : undefined\n }\n floatingLayerContent={\n immersive && floatingWindows.windows.length > 0 ? (\n <>\n {floatingWindows.windows.map((win, idx) => {\n const ann = cidToAnnotation.get(win.clientId)\n const isSelection = ann?.kind === 'anchored'\n const anchorContext = isSelection ? ann?.anchor?.text : undefined\n return (\n <FloatingConversation\n key={win.clientId}\n clientId={win.clientId}\n title={getChannelTitle(win.clientId)}\n messages={getMessagesForChannel(win.clientId)}\n onSend={handleFloatingSend}\n onClose={() => floatingWindows.close(win.clientId)}\n onFocus={() => { floatingWindows.focus(win.clientId); setCurrentClientId(win.clientId) }}\n onMinimize={() => floatingWindows.minimize(win.clientId)}\n onRestore={() => floatingWindows.restore(win.clientId)}\n onPositionChange={(pos) => floatingWindows.updatePosition(win.clientId, pos)}\n position={win.position}\n zIndex={win.zIndex}\n minimized={win.minimized}\n isLoading={executionStatus === 'running' && win.clientId === currentClientId}\n highlightColor={isSelection ? HIGHLIGHT_COLORS[idx % HIGHLIGHT_COLORS.length] : undefined}\n anchorContext={anchorContext}\n />\n )\n })}\n </>\n ) : undefined\n }\n primaryContent={\n <>\n <div className=\"ycw-message-list-container\">\n {config.showPinnedArea && (\n <PinnedArea\n round={pinnedRound}\n isTransitioning={isTransitioning}\n config={config}\n todoMap={todoMap}\n />\n )}\n\n <div\n className=\"ycw-message-list\"\n ref={messageListRef}\n onScroll={handleScroll}\n >\n {hasMore && (\n <div\n ref={sentinelRef}\n className=\"ycw-pagination-sentinel\"\n style={{ height: 1, width: '100%', pointerEvents: 'none' }}\n />\n )}\n {loadingMore && (\n <div className=\"ycw-pagination-loading\" style={{ display: 'flex', justifyContent: 'center', padding: '12px 0' }}>\n <span className=\"ycw-pagination-spinner\" />\n </div>\n )}\n\n {foreignRounds.length > 0 && (\n <div className=\"ycw-foreign-rounds-bar\">\n <div\n className=\"ycw-foreign-rounds-bar-header\"\n role=\"button\"\n tabIndex={0}\n onClick={() => setForeignBarOpen(prev => !prev)}\n onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setForeignBarOpen(prev => !prev) } }}\n >\n <span className=\"ycw-foreign-bar-dot\" />\n <span className=\"ycw-foreign-bar-text\">\n {i18n['round.foreign.label']}\n </span>\n <span className=\"ycw-foreign-badge-count\">\n {foreignRounds.length}\n </span>\n <Icon name={foreignBarOpen ? 'caretDown' : 'caretRight'} size={14} aria-hidden={true} />\n </div>\n {foreignBarOpen && (\n <div className=\"ycw-foreign-rounds-bar-list\">\n {foreignRounds.map(round => (\n <ForeignRoundBadge\n key={round.interactionId}\n round={round}\n unreadCount={round.messages.length}\n />\n ))}\n </div>\n )}\n </div>\n )}\n\n {currentClientRounds.map((round, index) => (\n <React.Fragment key={round.interactionId}>\n {index > 0 && (\n <div className=\"ycw-round-separator\">{i18n['round.separator']}</div>\n )}\n\n <div\n className=\"ycw-round-container\"\n data-round={round.index}\n data-interaction-id={round.interactionId}\n >\n <RoundHeader\n round={round}\n isPinned={round.interactionId === pinnedInteractionId}\n config={config}\n todoMap={todoMap}\n />\n <RoundMessageList\n round={round}\n config={config}\n onArtifactClick={handleArtifactClick}\n onHITLSubmit={handleHITLSubmit}\n renderToolResult={renderToolResult}\n observedInstanceStates={poolObservation.instanceStates}\n />\n </div>\n\n {index > 0 && (\n <div\n className={`ycw-clear-screen-spacer ${index < currentClientRounds.length - 1 || getSpacerHeight(round.interactionId) <= 0 ? 'ycw-spacer-collapsed' : ''}`}\n style={{ height: index < currentClientRounds.length - 1 ? 0 : Math.max(0, getSpacerHeight(round.interactionId)) }}\n data-spacer-for={round.interactionId}\n />\n )}\n </React.Fragment>\n ))}\n\n {currentClientRounds.length === 0 && foreignRounds.length === 0 && !sessionClientsError && (\n <div className=\"ycw-empty-state\">\n <span className=\"ycw-empty-icon\">{i18n['empty.icon']}</span>\n <span className=\"ycw-empty-text\">{i18n['empty.waiting']}</span>\n </div>\n )}\n {sessionClientsError && currentClientRounds.length === 0 && foreignRounds.length === 0 && (\n <SessionForbiddenBanner\n sessionId={currentSessionId ?? null}\n error={sessionClientsError}\n adapter={adapter}\n onJoined={() => {\n void refreshSessionClients()\n }}\n />\n )}\n </div>\n </div>\n\n <div className=\"ycw-footer\">\n {!referenceInsertHandlerRef.current && references.length > 0 && (\n <div className=\"ycw-cb-chip-list\" style={{ padding: '4px 16px 0' }}>\n {references.map((ref, i) => (\n <ContextChip key={`${ref.resourceId}-${i}`} reference={ref} onRemove={() => removeReference(i)} />\n ))}\n </div>\n )}\n {renderFooter ? renderFooter(widgetAPI) : i18n['footer.attribution']}\n </div>\n\n </>\n }\n >\n <div ref={viewerContainerRef} style={{ height: '100%', position: 'relative' }}>\n {genUIPageOpen && genUIPages.length > 0 ? (\n <JsonRenderViewer\n pages={genUIPages}\n activeSpecId={genUIActiveSpecId ?? undefined}\n onClose={closeGenUIPage}\n onFullscreen={() => setImmersive(true)}\n onReference={handleReference}\n onSelectionAsk={handleGenUIAsk}\n onBeforeCopy={onBeforeCopy}\n adapter={adapter}\n sessionId={typeof currentSessionId === 'string' ? Number(currentSessionId) : currentSessionId ?? null}\n clientId={currentClientId}\n agentWaiting={executionStatus === 'running'}\n registry={genUIRegistry}\n />\n ) : (\n <FileViewerPanel\n initialResource={viewerContent}\n initialArtifact={viewerArtifact}\n loading={viewerLoading}\n error={viewerError}\n adapter={adapter}\n sessionId={currentSessionId}\n onReference={handleReference}\n onSelectionAsk={handleSelectionAsk}\n onBeforeCopy={onBeforeCopy}\n onClose={() => { closeViewer(); clearUnread() }}\n onFullscreen={() => setImmersive(true)}\n kicanvasScriptUrl={kicanvasScriptUrl}\n kicanvasTheme={KICANVAS_JP_THEME[resolvedTheme]}\n />\n )}\n {immersive && selectionHighlights.length > 0 && (\n <SelectionHighlight\n highlights={selectionHighlights}\n containerRef={viewerContainerRef}\n />\n )}\n </div>\n </SplitPanel>\n </div>\n </GenUIProvider>\n </ResourceProvider>\n </AdapterProvider>\n </InteractionContext.Provider>\n </I18nContext.Provider>\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 | 'gen_ui_card'\n | 'gen_ui_page'\n | 'gen_ui_meta'\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 /** [DEPRECATED 起 JETP-073] session 级 LLM 起名;仅在兼容期 dual-write 中复用,\n * 新代码请改用 'client_title'。 */\n | 'session_title'\n /** JETP-073:client(\"办公室\")级 LLM 起名 notification。controller 派发为\n * ``ClientTitleEvent``;上游消费方按 ``client_id`` 增量更新本地 cache。 */\n | 'client_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 spec_id?: string\n render_mode?: 'card' | 'page'\n /** JETP-045 Layer 1:客户端连接子空间标识;后端 Notification.client_id 透传下来。 */\n client_id?: string\n /**\n * JETP-045 Phase 2 P2-T03:与所属 LLM 物理流对齐的边界 ID。\n * MODEL_START / 中间 chunk / MODEL_END 共享同一 stream_uuid。\n * 前端 useMessageAggregator.messageKey 主分支按此聚合 → 彻底解决 Bug 1\n * (撞键导致 think2 头部错合到 think1)。\n * 旧后端不下发 → undefined → useMessageAggregator 走兜底分支保持向后兼容。\n */\n stream_uuid?: string\n /**\n * JETP-045 Phase 2 P2-T08/T10:所属 turn 在 (interaction_id, callee_instance_id)\n * 内的单调序号;与 db-writer ``MAX(turn_index)+1`` 同算法。\n * 前端 ``turnCursorRef`` 用 ``${iid}::${callee}`` 为 key 推进;断线重连发\n * subscribe 时按 (iid, callee, max_turn_index) 形式上报,服务端只补\n * ``turn_index > max_turn_index`` 的 turn(AC-TURN-002/005)。\n */\n turn_index?: number\n /**\n * JETP-045:被叫 agent 实例 ID。AC-TURN-003 多 callee 独立 cursor 必需。\n * 旧后端可能直接把 ``agent_instance_id`` 当 callee 用 → adapter 透传。\n */\n callee_instance_id?: number\n /**\n * JETP-045 Phase 6 — 触发该 notification 的源连接 ID(后端 Notification.connection_id_from)。\n * 前端 ``useMessageAggregator`` 用 ``connection_id_from === my_connection_id`` 识别 echo。\n * 旧后端不下发 → undefined → 不做 echo 抑制,回退到 Phase 1-5 行为 (AC-CONN-008)。\n */\n connection_id_from?: 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 /** 后端资源 ID,与附件/工作区文件关联 */\n resource_id?: string\n mime_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 /** JETP-040: Optional attached files for multipart HITL upload */\n files?: File[]\n session_id?: number\n agent_instance_id?: number\n text?: string\n /**\n * JETP-003 ADR-006 v1.1.2 / WS2.6 — V2 ``c_<22 base62>`` window/conversation\n * identifier for the chat-widget instance that produced this response.\n *\n * Stage A grayscale (current): when omitted on A2UI payloads, jetagents\n * /api/human-response increments ``hip_client_id_missing_total`` Counter\n * + WARN log and falls back to session-wide routing.\n *\n * Stage B strict cutover (post-grayscale): A2UI payloads (data with\n * ``__action`` + ``spec_id``) without client_id will be rejected.\n *\n * The chat-widget always knows its own client_id (from useClientIdAllocator\n * → ``currentClientId``); GenUIProvider injects it into GenUIContext, and\n * ActionBridge / handleHITLSubmit auto-fill this field when not set by\n * the caller.\n */\n client_id?: string\n}\n\n// ========== JETP-083 Collaborative HIL ==========\n\n/**\n * JETP-083 WS3.7.6 — pending HIL Entity projection returned by\n * ``GET /api/genui/pending``.\n *\n * Shape mirrors `jetagents/main.py:get_genui_pending` 1:1; fields are\n * derived from `HilEntity` + the principal-scoped projection helper.\n *\n * Phase 1 invariants:\n * - The returned list contains *only* HILs whose `resolved_recipients`\n * include the connecting principal — backend ACL via the registry's\n * principal index. No client-side filter is needed (or sufficient).\n * - `recipientsSummary.recipientCount` is intentionally a count, not a\n * list of co-recipients, to avoid leaking other users' identities.\n * Phase 2 multi-recipient delivery may extend this with masked\n * summaries.\n * - `state` is always a non-terminal state (registry filters out\n * resolved/cancelled/expired before returning).\n */\nexport interface PendingHIL {\n hilId: string\n specId: string\n /** Note: backend stores as string even when the URL `session_id` is int. */\n sessionId: string\n state: 'pending' | 'delivered' | 'in_progress' | 'partially_resolved'\n schemaVersion: 'v1'\n createdAt: string | null\n lastUpdatedAt: string | null\n origin: {\n agentId: string | null\n /** Originating client_id; audit-only after WS3.7.4. */\n clientId: string | null\n /** Compact origin principal — drops null fields. */\n principal: {\n principalKind?: string\n principalKey?: string\n realmId?: string\n authInstanceId?: string\n } | null\n }\n recipientsSummary: {\n delivery: 'first_wins' | 'all_must' | 'quorum' | 'broadcast_first_wins'\n selectorKind: 'literal' | 'role' | 'group' | 'realm'\n recipientCount: number\n /** Whether the connecting principal is a recipient (sanity flag). */\n includeSelf: boolean\n }\n}\n\n// ========== Spec Lifecycle (JETP-083 WS3.7.5 / JETP-033 WS1.1) ==========\n\n/**\n * Terminal lifecycle marker for a spec, emitted by the backend via the\n * `gen_ui_meta` channel as either:\n *\n * - `{op:\"replace\", path:\"/_meta/cancelled\", value:{reason}}` — HIL on the\n * spec was cancelled (user, agent, or system-initiated; see WS3.7.5).\n * - `{op:\"replace\", path:\"/_meta/error\", value:{error_code, payload}}`\n * or legacy flat `{error, payload}` — terminal error such as\n * `patch_rounds_exceeded` (ADR-012 D1).\n *\n * The aggregator surfaces this in `specLifecycleMap` keyed by spec_id; the\n * host UI can disable the form, dim the card, or show a banner. Once a spec\n * has a lifecycle entry, further patches for it should be visually muted.\n */\nexport type SpecLifecycleEntry =\n | { state: 'cancelled'; reason: string }\n | { state: 'error'; errorCode: string; payload?: Record<string, unknown> }\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 specId?: string\n uiPatches?: string[]\n renderMode?: 'card' | 'page'\n /** JETP-045 Layer 1:客户端连接子空间标识。 */\n clientId?: string\n /**\n * JETP-045 Phase 6 — 触发该消息的源连接 ID;与 ``SSEMessage.connection_id_from`` 透传。\n * 仅用于 UI 调试/数据回放;echo 的渲染策略由 ``isEcho`` 决定。\n */\n connectionIdFrom?: string\n /**\n * JETP-045 Phase 6 (AC-CONN-006/007) — 该消息是否由\"我这条连接\"自己回环触发。\n * - true:UI 应抑制 user_input 的重复渲染(已由 round.userMessage optimistic 显示);\n * 其余非 user_input 类型仍照常渲染,仅可作为视觉淡化提示。\n * - false / undefined:来自其他 tab/连接 或旧后端无 ``connection_id_from`` ⇒ 视为远端。\n */\n isEcho?: boolean\n}\n\n// ========== Round ==========\n\nexport interface Round {\n interactionId: string\n index: number\n userMessage: string\n timestamp: string\n /** 用户消息时间戳(毫秒),可选;缺省时可用 `timestamp` 解析 */\n startedAt?: number\n status: 'running' | 'completed' | 'error'\n plan?: TaskPlan\n messages: AggregatedMessage[]\n topPosition?: number\n /** 本轮次内已收到 agent_end 的 agent_instance_id 集合,与 notification_turns 的 agent start/stop 对齐,用于子 Agent 卡片「已完成」判断 */\n endedAgentInstanceIds?: Set<number>\n /** JETP-045 Layer 1:客户端连接子空间标识。 */\n clientId?: string\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' | 'midnight' | 'neumorphism' | 'auto'\n displayLevels?: number[]\n /**\n * Whether to reuse agent_instance_id from session history when restoring a session.\n *\n * - `true` (default): cache the historical agent_instance_id and send it with\n * new messages, ensuring the same agent executor handles follow-up requests.\n * Best for single-user continuation of an existing conversation.\n *\n * - `false`: do NOT cache the historical agent_instance_id; each new message\n * lets the backend create a fresh agent executor. This avoids InstanceTaskQueue\n * contention and is required for multi-user collaboration on a shared session.\n */\n reuseAgentInstance?: boolean\n transport?: 'ws' | 'sse'\n /**\n * 是否在 ChatWidget mount 时立即调用 ``adapter.createSession`` 预分配 session+workspace。\n *\n * - ``true``(默认):保留原 SDK 行为,让首次 ``sendMessage`` 不必等会话创建。\n * 适合\"嵌入式单会话\"场景(host 始终给确定 sessionId 或希望开局立即就绪)。\n *\n * - ``false``:不在 mount 时建会话;只有用户调用 ``api.sendMessage`` 或 host 显式\n * 传入 sessionId 时才进入会话流程。适合\"多会话侧栏 + 选择/新建\"的 host\n * (如 Demo App、JetForge Console),避免每次刷新都在后端 page 列表里\n * 留下空 session。\n */\n eagerSessionCreation?: boolean\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 reuseAgentInstance: true,\n transport: 'ws',\n eagerSessionCreation: true,\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 messages?: Partial<import('./i18n/messages.js').ChatWidgetMessages>\n onArtifactClick?: (artifact: Artifact) => void\n onSelectionAsk?: (reference: FileReference) => void\n onBeforeCopy?: (reference: FileReference) => void\n onHITLSubmit?: (response: HITLResponse) => Promise<void>\n onConnectionChange?: (connected: boolean) => void\n onRoundChange?: (rounds: Round[]) => void\n onMessageAppended?: (message: AggregatedMessage) => void\n onRoundStart?: (interactionId: string, userMessage: string) => void\n onRoundEnd?: (interactionId: string) => void\n onStatusChange?: (status: ExecutionStatus) => void\n onError?: (error: Error) => void\n onInteraction?: (event: ChatWidgetInteractionEvent) => void\n onReady?: (api: ChatWidgetAPI) => void\n className?: string\n style?: React.CSSProperties\n height?: number | string\n /** 自建 jp-kicanvas 脚本 URL;未设则用 VITE_KICANVAS_SCRIPT_URL 或官方 CDN */\n kicanvasScriptUrl?: string\n /** JETP-038: Current human user alias for discussion participation (e.g. \"user:alice\"). Defaults to \"user\". */\n currentUserAlias?: string\n}\n\n// ========== Skill Selector Types (JETP-032) ==========\n\nexport interface SkillSummary {\n id: string\n name: string\n displayName: string\n description: string\n version?: string\n category?: string\n tags?: string[]\n}\n\nexport interface SkillListParams {\n search?: string\n page?: number\n pageSize?: number\n}\n\nexport interface SkillListResponse {\n skills: SkillSummary[]\n total: number\n page: number\n pageSize: number\n}\n\nexport interface SelectedSkillRef {\n id: string\n name: string\n version?: string\n}\n\n// ========== Interaction Events ==========\n\nexport type InteractionEventType =\n | 'child-agent-toggle'\n | 'tool-result-toggle'\n | 'think-toggle'\n | 'todo-toggle'\n | 'todo-item-click'\n | 'link-click'\n | 'xref-navigate'\n | 'file-download'\n | 'artifact-click'\n | 'plan-step-click'\n | 'reference-add'\n | 'reference-remove'\n | 'viewer-open'\n | 'viewer-close'\n | 'immersive-toggle'\n | 'message-copy'\n | 'hitl-submit'\n | 'skill-select'\n | 'skill-remove'\n | 'skill-popup-open'\n | 'skill-popup-close'\n | 'skill-search'\n /**\n * 会话生命周期:controller 真新建出 session 后触发(adapter.createSession 成功 /\n * 后端通过 SSE ``session_info`` 推回新 session_id 都算)。从 ``sessionId`` prop\n * 恢复历史会话不会触发本事件。\n * metadata: ``{ sessionId: number, agentId?: string }``\n */\n | 'session-created'\n /**\n * 会话信息更新:当前以 session_title 变化为唯一来源——SSE ``session_title`` 通知到达、\n * loadHistory 取 detail / 兜底 sessionDetail 拿到非空 title 都会触发一次。\n * metadata: ``{ sessionId: number, sessionTitle?: string }``\n */\n | 'session-updated'\n\nexport interface ChatWidgetInteractionEvent {\n type: InteractionEventType\n target: string\n metadata?: Record<string, unknown>\n timestamp: number\n}\n\n/**\n * Controller 对外暴露的\"会话生命周期事件\"——比 InteractionEvent 更窄:\n * 只关心\"创建\" / \"信息更新\",不耦合 UI 交互层。ChatWidget 默认把它转译成\n * ``'session-created' / 'session-updated'`` 这两条 InteractionEvent;高级宿主\n * 也可以直接拿 controller 的 ``onSessionEvent`` 自己处理,绕开 InteractionContext。\n */\nexport interface SessionLifecycleEvent {\n type: 'created' | 'updated'\n sessionId: number\n /** updated 时携带最新 session_title;created 一般为空。 */\n sessionTitle?: string\n /** created 时携带 agentId,便于宿主统计 / 路由。 */\n agentId?: string\n /** created 的来源:显式 createSession vs 后端 SSE 推回。 */\n source?: 'explicit' | 'sse'\n}\n\n/**\n * JETP-073:client(\"办公室\")级 title 解析事件。\n *\n * controller 在以下时机各 emit 一次:\n * - SSE/WS ``client_title`` notification 到达(backend `node_title_agent`\n * 基于 first_agent_start 派生出 LLM 起名后通过 redis stream 推下来)。\n *\n * 与 ``SessionLifecycleEvent.updated`` 关键区别:\n * - SessionLifecycleEvent 绑定 ``sessionId``;一个 session 一次。\n * - ClientTitleEvent 绑定 ``clientId``;多 client session 下每个 client 一次。\n *\n * sessionId 字段仅作上下文 hint,可能为 -1(loadHistory 中 session 未敲定时)。\n * 真正的 routing key 是 ``clientId``。\n */\nexport interface ClientTitleEvent {\n type: 'client_title'\n /** controller 当时持有的 currentSessionId;-1 表示未知(loadHistory 阶段)。 */\n sessionId: number\n /** v2 client_id:``c_<22 base62>``。后端保证非空。 */\n clientId: string\n /** LLM 派生的 client title(已被 backend 截到 ≤24 字)。 */\n clientTitle: string\n}\n\n// ========== Model Override (per-call) ==========\n\n/**\n * 前端在发送一条消息时显式指定要用的模型,覆盖该 agent 在后端注册的默认 ``ModelMeta``。\n *\n * 设计:\n * - ``name`` 必须是后端 fusion 能识别的 model 标识;前端不做白名单(后端校验)。\n * - ``scope`` 决定是否透传到此次调用派生出的所有子 agent:\n * - ``'root'`` 只覆盖入口 agent 自己;子 agent 仍按各自 ``AgentMeta.model``。\n * - ``'all'``(默认)父 → 子 → 孙都用同一个 model,便于\"指定模型跑完一棵任务树\"。\n * - ``settings`` 是增量字段,会浅合并进 ``ModelMeta.settings``(如 ``{ temperature: 0.3 }``)。\n *\n * 不在第一版做的事:按 role 映射 (`{ ask: 'haiku', deliver: 'opus' }`)、\n * 自动降级到 agent 默认模型(语义上\"用户授权使用且仅使用这个 model\")。\n */\nexport interface ModelOverride {\n name: string\n scope?: 'root' | 'all'\n settings?: Record<string, unknown>\n}\n\n// ========== Model Listing (selector source) ==========\n// 数据**唯一来源**是 hip-server ``GET /api/v1/models`` —— hip 这层直接代理\n// model-lake 的 active 模型注册表,**不经过 fusion**(fusion 仅在实际调用时承担\n// 账号/重试/路由职责,不应污染\"哪些模型对用户可见\"的语义)。\n//\n// 字段定义贴近 hip 端 ``BasenameGroupedOutput`` / ``GroupedOutput`` / ``Output`` 的归一化形态:\n// - group_by=basename → ``ModelListItemBasenameGrouped``(按物理模型 basename 聚合,\n// 吞掉 openrouter 渠道把 ``provider/model`` 写成\n// ``provider__model`` 造成的\"双胞胎\";UI picker 默认)\n// - group_by=name → ``ModelListItemGrouped``(同 name 多渠道合并)\n// - 不带参数 → ``ModelListItemRaw``(每条 = 一个 channel/name 对;高级用法)\n//\n// 不在 SDK 一侧做\"按 role 自动选模型\"等语义糖;那属于上层应用编排(yumiai-web 等)。\n\n/**\n * 单条模型记录,等价于 hip ``Model`` DTO。每条 = 一个 (channel, model_name) 对。\n *\n * 何时用:上层希望让用户显式挑渠道(高阶面板 / 调试视图)。\n * 想法是稳定 ``id`` 直接映射到 ``ModelOverride.name``——若上层需要传渠道路由,\n * 就传完整 id(``channel/name``);想让后端按账号策略选渠道,就传 ``name``。\n */\nexport interface ModelListItemRaw {\n id: string\n name: string\n channel: string\n created: number\n /**\n * 该 (channel, model_name) 当前是否可用——hip-server 联表 model-lake\n * ``/internal/model-status`` 的判定结果。\n *\n * **fail-safe 默认 true**:当 hip 端 status 接口拉不到 / 该 id 不在结果集时\n * 都视为可用,避免一个内部接口故障让 picker 整体空列表。前端按\"显式 false 才隐藏\"\n * 处理,**不要**对未定义状态做特殊兜底(与后端契约一致)。\n *\n * 字段为 optional 是为了兼容尚未升级到带 availability 的 hip 老版本:\n * 解析方未拿到字段时按 true 处理(``ModelPicker`` 已经实现该兜底)。\n */\n available?: boolean\n}\n\n/**\n * 聚合形态(``group_by=name``),等价于 hip ``GroupedModel`` DTO。\n * 每条 = 一个 model_name + 该 name 下所有可用渠道。\n *\n * 用法:picker 直接展示 ``name`` / ``displayName``,用户挑后把 ``name``\n * 灌入 ``ModelOverride.name``,后端自行按账号策略选渠道。\n */\nexport interface ModelListItemGrouped {\n name: string\n channels: string[]\n /**\n * Channels 的子集,只含 ``available=true`` 的渠道。\n * 前端不展示渠道时直接消费 ``defaultChannel``;\n * 展示渠道时可用此把不可用的置灰。Optional 兼容老版本 hip。\n */\n availableChannels?: string[]\n /**\n * 该 name 下默认选中的渠道。\n * 选取规则(hip 端):**先 available 再 created** —— 即优先在 available\n * 渠道里选注册时间最早的;全不可用才 fallback 到整体最早。\n */\n defaultChannel: string\n created: number\n /**\n * 该 name 下是否至少有一个渠道可用。前端可用此快速决定\"整行隐藏\"。\n * Optional 兼容老版本 hip:未定义时按 true 处理。\n */\n anyAvailable?: boolean\n}\n\n/**\n * Basename 聚合形态下的\"渠道-完整 name\"组合,等价于 hip ``BasenameVariant``。\n *\n * 关键约束:``name`` 字段是 model-lake 视角的**完整 model_name**\n * (``anthropic__claude-opus-4`` / ``claude-opus-4-6`` / ``qwen__qwen3-max`` 等),\n * 必须原样回传给后端 ``ModelOverride.name``。``basename`` 仅是 UI 标签,**不能**\n * 替代 name —— 否则会丢失渠道路由信息(同 basename 不同渠道 = 不同账号 / 不同价格)。\n */\nexport interface ModelListVariant {\n name: string\n channel: string\n created: number\n /**\n * 该 variant 当前是否可用,语义同 ``ModelListItemRaw.available``。\n * fail-safe 默认 true(optional + 未定义按 true 处理)。\n */\n available?: boolean\n}\n\n/**\n * Basename 聚合形态(``group_by=basename``),等价于 hip ``BasenameGrouped``。\n *\n * 设计动机:model-lake 入库时 openrouter 渠道把 ``provider/model``\n * (如 ``qwen/qwen3-max``)反规范化为 ``provider__model``(``qwen__qwen3-max``),\n * 与 ali 渠道的 ``qwen3-max`` 在 ``ModelListItemGrouped`` 视角下被识别为不同 name,\n * 实际上是同一物理模型。Basename 聚合再合并一层,给 picker 一个\"无重复\"的列表。\n *\n * 用法:picker 列表 = ``basename``;点开后展开 ``variants``,让用户挑渠道;\n * 选定后把对应 variant 的 ``name`` 灌入 ``ModelOverride.name``。\n */\nexport interface ModelListItemBasenameGrouped {\n basename: string\n variants: ModelListVariant[]\n /**\n * 默认选中的 variant。\n * 选取规则(hip 端):**先 available 再 created** —— 即优先在 available\n * variant 里选注册时间最早的;全不可用才 fallback 到整体最早。\n */\n defaultVariant: ModelListVariant\n created: number\n /**\n * 该 basename 下是否至少有一个 variant 可用。前端可据此整行隐藏,\n * 让运营态 picker 不出现\"全部下游挂掉\"的死项。Optional 兼容老版本 hip:\n * 未定义时按 true 处理。\n */\n anyAvailable?: boolean\n}\n\nexport interface ListModelsResponse<TItem = ModelListItemBasenameGrouped> {\n items: TItem[]\n total: number\n}\n\n/**\n * adapter.listModels 入参;保持极简、不引入 channel 之外的过滤维度——\n * 进一步的\"按租户/角色\"过滤应在 backend 端做(hip 后续可加 query 参数),\n * 而不是让前端自己穿配置文件。\n */\nexport interface ListModelsParams {\n /**\n * 默认 ``'basename'``:按物理模型 basename 聚合,picker 默认形态。\n * - ``'name'`` → 按完整 model_name 聚合(不归一 ``__`` ↔ ``/``);\n * - ``'none'`` → 返回 raw(按 channel/name 对)。\n */\n groupBy?: 'basename' | 'name' | 'none'\n}\n\n// ========== Widget API ==========\n\nexport interface ChatWidgetAPI {\n sendMessage: (message: string, agentId?: string, inlineRefs?: FileReference[], selectedSkills?: SelectedSkillRef[], overrideInstanceId?: number | null, clientId?: string, fileAttachments?: FileAttachment[], modelOverride?: ModelOverride | null) => void | Promise<void>\n getCurrentRound: () => Round | null\n getAllRounds: () => Round[]\n scrollToBottom: () => void\n getStatus: () => ExecutionStatus\n /** Register a handler to receive references inline (e.g. insert into RichInput). When set, references bypass the external chip list. */\n setReferenceInsertHandler: (handler: ((ref: FileReference) => void) | null) => void\n /**\n * JETP-052 F-3c:在当前 session 内\"开一个新对话流的浮动窗\"。\n *\n * 编排:\n * 1. 调用后端 ``POST /api/session/{sid}/clients`` 拿到 v2 ``c_<22>`` client_id\n * 2. 把它加入 ``useFloatingWindows`` 浮动窗列表(``openWith``,附 title + contextPreloads 元数据)\n * 3. 乐观更新到 ``useSessionClients`` 列表(sidebar 立刻可见)\n *\n * 失败时 reject;调用方 catch 后可以走 toast 或重试。\n * 返回新分配的 v2 client_id(业务层可用来后续 sendMessage(clientId=...))。\n */\n openClientWindow?: (opts: { title?: string; contextPreloads?: unknown[] }) => Promise<string>\n /**\n * 协作式停止当前 session 的 Agent 执行 —— 通过 `adapter.stopAgent` 走\n * `POST /api/session/stop`,由后端写 Redis stop 信号;运行时检查点会在下一个\n * tick 退出。详细机制见 `ChatWidgetAdapter.stopAgent` 注释。\n *\n * 设计要点(与 `useAgentControl().stop` 共享同一底层路径):\n * - **HTTP 单通道**:不依赖 WS 是否在线;跨 Pod 仍能命中;与 pause/resume 走 WS\n * 的策略解耦(pause/resume 修改 pool 进程内状态,必须 WS 直送对应 Pod)。\n * - **幂等**:后端键已存在时返回 `success(data={})`,连点两次安全。\n * - **可选**:自定义 adapter 未实现 `stopAgent` 时本字段为 `undefined`,UI 应\n * 据此降级(例如 DefaultComposer 在没有 stopAgent 时仍走旧 disabled 行为)。\n *\n * 何时存在:\n * - `currentSessionId` 已就绪 **且** `adapter.stopAgent` 是函数 → 暴露此方法;\n * - 否则为 `undefined`,避免给 UI 带来\"按了没反应\"的错觉。\n *\n * 失败语义:内部已 catch 网络错误并 `console.warn`,不向上抛 —— 让按钮 UI 不必\n * 写自己的 try/catch;如宿主需要错误回调,请自行包一层 `try { await api.stopAgent() }`。\n */\n stopAgent?: () => Promise<void>\n\n /** JETP-040: File upload state and actions. Undefined when adapter does not support uploads. */\n fileUpload?: {\n attachments: UploadedFileInfo[]\n readyFiles: FileAttachment[]\n isUploading: boolean\n addFiles: (files: File[]) => void\n removeFile: (resourceId: string) => void\n clear: () => void\n enabled: boolean\n }\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 raw_message_count?: number\n /** JETP-045 Layer 1:客户端连接子空间标识。 */\n client_id?: string\n}\n\nexport interface PaginatedHistoryResponse {\n turns: NotificationTurn[]\n has_more: boolean\n next_cursor: string | 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 /** Direct URL for binary content (e.g. MinIO presigned URL), avoids base64 transfer for large files */\n content_url?: string\n /** Language hint for syntax highlighting (e.g. \"python\", \"go\"); inferred from extension when absent */\n language?: string\n}\n\n/** Result of resolving a resource_id via ResourceProvider (CWRF-008) */\nexport interface ResourceResolveResult {\n url?: string\n content?: string\n contentUrl?: string\n mimeType?: string\n fileName?: string\n isText?: boolean\n gitPath?: string\n}\n\n/** File entry returned by listDirectoryFiles (CWRF-009) */\nexport interface DirectoryFileEntry {\n resource_id: string\n file_name: string\n git_path: string\n download_url?: string\n node_type: string\n}\n\n/** Options for listDirectoryFiles (CWRF-009) */\nexport interface ListDirectoryFilesOptions {\n extensions?: string[]\n recursive?: boolean\n generateUrls?: boolean\n}\n\nexport interface SessionDetail {\n session_id: number\n session_title?: string\n status?: string\n created_at?: string\n}\n\n// ========== Pool Observation ==========\n\nexport interface PoolAgentAction {\n tool_call_id: string\n tool: string\n purpose: string\n status: 'running' | 'completed' | 'failed' | string\n ts: number\n}\n\nexport interface PoolAgent {\n agent_instance_id: number\n agent_id: string\n agent_alias?: string\n /**\n * JETP-083 WS3.7.7 follow-up: ``PAUSED`` is emitted by the backend\n * ``RuntimeMonitor.agent_pool_status`` projection when the agent\n * instance is blocked in ``_await_genui_blocking`` waiting on a HIL\n * reply. ``PoolStatusPopover`` maps it to the ``paused`` state-key\n * (label \"等待人工\" / \"Awaiting human\"); previously it fell through to\n * the ``unknown`` bucket and the popover rendered \"未知\".\n */\n state: 'RUNNING' | 'PAUSED' | 'COMPLETED' | 'LOST' | string\n task_purpose?: string\n recent_actions?: PoolAgentAction[]\n /**\n * JETP-074(无退化路径版):agent 归属到的 client(\"办公室\"),**必填**。\n * backend MonitorRegistry.register 已严格化(缺 cid → ValueError),到达前端的\n * 每个 PoolAgent 都必须有 cid;usePoolObservation 在 push/poll 路径上对缺 cid\n * 的 patch 直接 console.error + drop,不让无 cid 的 agent 污染 observation。\n */\n client_id: string\n}\n\nexport interface PoolStatusResponse {\n session_id: number\n total: number\n agents: PoolAgent[]\n}\n\n// ========== Discussion API (JETP-038) ==========\n\nexport interface MentionTarget {\n identifier: string\n agent_id?: string\n agent_instance_id?: number\n}\n\nexport interface PostDiscussionMessageRequest {\n discussion_path: string\n speaker: string\n message_type: string\n mentions: string[]\n mention_targets?: MentionTarget[]\n body: string\n title?: string\n}\n\nexport interface PostDiscussionMessageResponse {\n ok: boolean\n message_index: number\n status: string\n remaining_messages: number\n participants_changed: boolean\n error?: string\n unresolved_mentions?: string[]\n}\n\n/**\n * JETP-075: User-initiated discussion creation (POST /api/session/{sid}/discussion/create).\n *\n * Field shape mirrors backend Pydantic ``PostDiscussionCreateRequest`` 1:1\n * (jetagents/runtime/discuss/api.py). 详见\n * doc/proposals/JETP-075-user-initiated-discussion/00_protocol.md §2.\n *\n * 必填字段(pydantic ``Field(...)`` 强制):\n * - ``topic`` : 1..100 chars, 进 YAML front-matter ``topic:``\n * - ``creator`` : ``user:<id>``,必须出现在 participants 内\n * - ``participants`` : 2..20 alias,第一位 = creator\n *\n * 可选字段:\n * - ``max_messages`` : 5..500,默认 50\n * - ``initial_body`` : ≤ 4000 chars;非空时同步写入首条消息并触发 ``_run_write_hook``\n * - ``initial_mentions`` : 必须是 participants 子集(service-level guard)\n * - ``initial_mention_targets``: 与 ``/message`` 端点同形态,用于 pin agent_instance_id\n */\nexport interface CreateDiscussionRequest {\n topic: string\n creator: string\n participants: string[]\n max_messages?: number\n initial_body?: string\n initial_mentions?: string[]\n initial_mention_targets?: MentionTarget[]\n}\n\n/**\n * JETP-075: Response of POST /api/session/{sid}/discussion/create。\n *\n * 字段含义见 doc/proposals/JETP-075-user-initiated-discussion/00_protocol.md §2/§5:\n * - ``ok`` : false 时 error 非空\n * - ``discussion_path`` : ``discussions/<slug>-<unix_ms>.disc.md`` 相对 workspace_root\n * - ``status`` : 创建后恒为 ``'active'``;schema 上对齐 DiscussionMeta.status\n * - ``message_count`` : 0 if no initial_body, 1 otherwise\n * - ``participants`` : echo 回完整列表(前端可用来 hydrate 浮窗 metadata)\n * - ``error`` : 错误时填,如 ``\"creator must appear in participants\"``\n * - ``unresolved_mentions``: initial_mentions 中无法在 session pool 解析的 alias 子集\n */\nexport interface CreateDiscussionResponse {\n ok: boolean\n discussion_path: string\n status: 'active' | 'converging' | 'resolved'\n message_count: number\n participants: string[]\n error: string\n unresolved_mentions: string[]\n}\n\n// ========== ChatWidgetAdapter ==========\n\n/**\n * JETP-057:``getSessionHistory`` 入参契约。\n *\n * 设计:doc/proposals/JETP-057-history-by-client-id/chat-widget/01_adapter_design.md\n *\n * - ``clientIds`` 必传:禁止前端忘传 → 后端走 session-only 全表扫的退化路径。\n * 常见取值:``['main']`` / ``['main', 'file:abc.txt', 'sel:section-1']``。\n * - ``includeInFlight`` 默认 false(与后端默认对齐);前端控制器层默认传 true,\n * 避免 in-flight 子 agent 卡刷新后消失。\n * - ``pageSize`` / ``beforeCursor`` 用于 keyset 分页(可选)。\n */\nexport interface GetSessionHistoryOptions {\n clientIds: string[]\n pageSize?: number\n beforeCursor?: string\n includeInFlight?: boolean\n}\n\n/**\n * Session 列表项(用于侧栏 / 会话切换面板)。\n *\n * 字段优先级(用于 title 显示):\n * 1. ``sessionTitle`` —— 后端 SESSION_TITLE 通知落库的\"对话标题\",最权威。\n * 2. ``summary`` —— 首轮模型摘要,作为 fallback。\n * 3. 都无 → 调用方自行兜底(如 \"会话 {id}\")。\n *\n * 历史背景:JETP-058 之前 demo 误用 ``title`` 字段名,永远拿不到值;\n * 现在 SDK 强制规范化为 ``sessionTitle``,adapter 层负责把后端各种字段名\n * 翻译过来。\n */\nexport interface SessionListItem {\n id: number\n sessionTitle?: string | null\n summary?: string | null\n createdAt?: string | null\n updatedAt?: string | null\n /** 可选:会话累计运行时长(秒),后端有则透传。 */\n runningTime?: number | null\n}\n\nexport interface ListSessionsParams {\n /** 1-based 页码;默认 1。 */\n page?: number\n /** 每页大小;默认 20。 */\n pageSize?: number\n}\n\nexport interface ListSessionsResponse {\n items: SessionListItem[]\n total: number\n page: number\n pageSize: number\n}\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 /**\n * List sessions belonging to the current user (paged).\n *\n * 用于宿主侧栏 / `<SessionListPanel>`。当 adapter 不实现该方法时,\n * `<SessionListPanel>` 显示\"unsupported\"空态,`useSessionList().supported`\n * 返回 false。adapter 应负责字段名规范化(snake_case → SDK 标准)。\n */\n listSessions?(params?: ListSessionsParams): Promise<ListSessionsResponse>\n\n /**\n * Delete a session by id.\n *\n * 当 adapter 不实现该方法时,`<SessionListPanel>` 隐藏每行的删除按钮,\n * `useSessionList().canDelete` 返回 false。\n */\n deleteSession?(sessionId: number): Promise<void>\n\n getSessionHistory(\n sessionId: number,\n options: GetSessionHistoryOptions,\n ): Promise<NotificationTurn[] | PaginatedHistoryResponse>\n\n getResourceContent(\n sessionId: number,\n resourceId: string,\n ): Promise<ResourceContent>\n\n submitHITLResponse(response: HITLResponse): Promise<void>\n\n /**\n * JETP-083 WS3.7.6 — fetch pending Collaborative HIL entities for the\n * connecting principal.\n *\n * Used by `useGenUIPending(sessionId)` on session connect / reconnect\n * (e.g. fresh client, reload, hot-failover). Returns *only* HILs whose\n * `resolved_recipients` include the connecting principal — the backend\n * applies the ACL via the registry's principal-scoped index, so this\n * endpoint cannot leak across users.\n *\n * When absent, JETP-083 connect-time hydration is disabled and the\n * widget falls back to live-only behaviour: a HIL pause is only seen\n * by the originating client. (Same as pre-WS3.7.6 behaviour.)\n *\n * Backend: `GET /api/genui/pending?session_id=...` (jetagents `main.py`).\n */\n getPendingHILs?(sessionId: number): Promise<PendingHIL[]>\n\n /**\n * 触发\"协作式停止\"信号:直接 `POST /api/session/stop`,由后端 handler 把\n * `agent:signal:stop:{session_id}:{interaction_id}=stop` 写入 Redis;运行时\n * 各检查点(agent_state_machine_v2 / simple_agent_pool / agent_executor /\n * base_pusher)轮询同一 key 后 yield `StoppedAgentCommand` 优雅退出,并由\n * pusher 推送 `CANCELED` 通知。\n *\n * 设计要点:\n * - **不依赖 WS 活性**:HTTP 任意 Pod 接到都能写入共享 Redis,跨 Pod 一致;\n * 而 WS `control_agent` 必须命中持有该 session pool 的同一进程。\n * - **后端幂等**:键已为 `\"stop\"` 时直接返回 `success(data={})`,不会重复发\n * `CANCELED`,前端连点两次安全。\n * - **与 pause/resume 解耦**:pause/resume 修改 pool 进程内状态,必须 WS 直送;\n * stop 只是写一个全局 Redis 标志,HTTP 更稳。\n *\n * 参数说明:\n * - `sessionId`:必填;后端从 DB 取该 session 的最新 event 来定位 stop key。\n * - `agentInstanceId`:保留参数,**当前后端 handler 不读**(仅 session 维度\n * 停止整轮交互);保留是为了未来若引入实例级停止时调用方无需变更签名。\n *\n * 失败语义:401 由 adapter 的 `authedFetch` 自动 refresh + 重试;其它非 200\n * 应抛 `ChatWidgetNetworkError`(含后端 `error(\"no event in session\")` 等业务\n * 失败码),上层据此 toast / 解锁按钮,避免吞错。\n *\n * 可选实现:自定义 adapter 未实现时,`useAgentControl.stop` 会回退到原 WS\n * `control_agent { action: 'stop' }` 路径以保持向后兼容。\n */\n stopAgent?(params: { sessionId: number; agentInstanceId?: number }): Promise<void>\n\n getStreamUrl(): string\n\n /**\n * WebSocket URL for persistent session-level downlink (CWRF-010 S3 architecture).\n * When provided and the session is active, the controller prefers WS over SSE.\n * Messages are sent via fire-and-confirm POST; responses arrive through this WS channel.\n * Falls back to SSE when absent or WS connection fails.\n */\n getWsUrl?(sessionId: number): string\n\n getAuthHeaders(): Record<string, string>\n\n getExtraHeaders?(): Record<string, string>\n\n /**\n * Build the SSE request body for the stream endpoint.\n * If implemented, ChatWidget uses the returned object as the POST body.\n * If absent, ChatWidget sends the default simplified format {message, agent_id, ...}.\n */\n buildStreamBody?(params: {\n message: string\n agentId: string\n sessionId: number | null\n interactionId: string\n agentInstanceId?: number\n callerInstanceId?: number\n selectedSkills?: SelectedSkillRef[]\n activeSpecIds?: string[]\n /**\n * JETP-045 Layer 1:客户端连接子空间标识。\n * 推荐由 `useClientId` hook 派生;不传时 adapter 兜底为 'main'。\n */\n clientId?: string\n /**\n * JETP-045 Phase 6 — Layer 1.5 物理连接 ID(前端 ``useConnectionId`` 派生)。\n * adapter 应把它写入 body 的 ``connection_id`` 字段;缺省时不写入,后端按\n * \"未知连接\" 处理(不做 echo 抑制,等同 Phase 1-5 行为)。\n */\n connectionId?: string\n fileAttachments?: FileAttachment[]\n /**\n * 前端指定的\"本次调用使用的模型\",覆盖 agent 的默认 ``ModelMeta``。\n * 缺省 / null 时维持原行为(agent 自己的注册模型),与历史版本完全兼容。\n * 详见 ``ModelOverride``。\n */\n modelOverride?: ModelOverride | null\n }): object\n\n listSkills?(params?: SkillListParams): Promise<SkillListResponse>\n\n onAuthFailure?(): void\n\n refreshAuth?(): Promise<boolean>\n\n /**\n * Batch-resolve @xref RID references to file metadata.\n * When absent, ResourceChip falls back to displaying the @xref description text.\n */\n resolveXrefs?(refs: XrefRef[]): Promise<XrefMeta[]>\n\n /**\n * Obtain a direct URL for a resource (e.g. MinIO/S3 presigned URL) for streaming large binary files.\n * When absent, falls back to base64 decoding from ResourceContent.content.\n */\n getResourceUrl?(sessionId: number, resourceId: string): Promise<string>\n\n /**\n * Obtain a server-rendered preview URL for office/legacy files (CWRF-008).\n * Backend converts the file (e.g. via LibreOffice headless) and returns a URL to the converted HTML/PDF.\n * When absent, office viewers fall back to client-side rendering or download link.\n */\n getPreviewUrl?(sessionId: number, resourceId: string, format?: 'html' | 'pdf'): Promise<string>\n\n /**\n * Transform a raw SSE JSON object into ChatWidget SSEMessage format.\n * Used when connecting directly to backends that emit a different SSE schema\n * (e.g. JetAgents Notification format vs ChatWidget flat format).\n * Returns an array of SSEMessage objects (one notification may expand to multiple messages).\n * Return null/undefined to drop the message.\n */\n transformSSEMessage?(raw: Record<string, unknown>): SSEMessage[] | null\n\n /**\n * Fetch provenance graph snapshot for a session.\n * When absent, provenance features are disabled.\n */\n getProvenanceGraph?(\n sessionId: number,\n params?: { since_turn_id?: number; limit?: number },\n ): Promise<import('./provenance/types.js').ProvenanceGraphSnapshot>\n\n /**\n * List files in a directory, filtered by extensions (CWRF-009).\n * Used by KiCad project viewer to discover all design files in a project directory.\n * When absent, project-level multi-file viewing is unavailable.\n */\n listDirectoryFiles?(\n sessionId: number,\n dirPrefix: string,\n options?: ListDirectoryFilesOptions,\n ): Promise<DirectoryFileEntry[]>\n\n /**\n * Create an artifact share link (JETP-034).\n * When absent, Share button is hidden in jr-page viewer.\n */\n shareArtifact?(params: {\n artifactId: string\n sessionId: number\n title?: string\n artifactType?: 'file' | 'jr-page'\n shareType?: 1 | 2\n }): Promise<{\n shareCode: string\n shareUrl: string\n password?: string\n } | null>\n\n /**\n * Query the agent pool observation status for a session.\n * Returns the list of agent instances and their states from MonitorRegistry.\n * When absent, observation-driven status is disabled and the widget falls\n * back to event-driven status tracking.\n */\n getPoolStatus?(sessionId: number): Promise<PoolStatusResponse>\n\n /**\n * 拉取\"用户可选模型清单\"。**唯一来源**是 hip-server,**不走 fusion**。\n *\n * 当 adapter 不实现该方法时,上层 ModelPicker 应隐藏自身(fall back 到 agent\n * 注册的默认模型,行为与历史版本完全一致)。\n *\n * URL 拼接规则:\n * ``${hipBaseUrl}/api/v1/models?...``,``hipBaseUrl`` 缺省时退化为相对 URL,\n * 交给开发态 vite proxy / 生产态网关接管,与本 adapter 其他 hip 调用一致。\n *\n * 三态 vs. 抛错:\n * - 网络/服务故障 → 抛 ``ChatWidgetNetworkError``,让 UI 决定降级(toast + 隐藏);\n * - 清单为空(数组长度 0) → 正常返回,UI 表现为\"暂无可选模型\",不弹错;\n * - 不同 ``groupBy`` 返回不同的 item 形态,靠泛型在编译期收敛。\n */\n listModels?<TGroup extends 'basename' | 'name' | 'none' = 'basename'>(\n params?: ListModelsParams & { groupBy?: TGroup },\n ): Promise<\n ListModelsResponse<\n TGroup extends 'basename'\n ? ModelListItemBasenameGrouped\n : TGroup extends 'name'\n ? ModelListItemGrouped\n : ModelListItemRaw\n >\n >\n\n /**\n * 按 ``agentId`` 查询该 agent 在后端注册的默认模型,**仅用于 picker 展示态**。\n *\n * 与 ``listModels`` 一样唯一走 hip-server(``GET /api/v1/agents/{agent_id}/default-model``),\n * 不绕 fusion。该端点是后续 hip 全量代理 jetagents 的入口之一。\n *\n * 三态约定:\n * - 命中:返回 ``{ name, displayName?, version? }``,picker 把展示态自动定位到该 model;\n * - 业务找不到 / 上游 404:返回 ``null``(**不抛**),picker 退化到\"显示默认模型\"标签;\n * - 网络/超时/5xx:返回 ``null``(**不抛**),同上兜底;调用方真的关心错误时\n * 可以观察 ``console.warn``。\n *\n * 这种\"全部失败都吞成 null\"的策略是有意为之:\n * 该方法是\"展示性的人因优化\",**不能因为它失败就阻塞用户输入**——\n * 失败时 picker 仍可正常工作,只是少一个细节。所以 adapter 这一层吃掉异常,\n * 而不是把它推给 UI 层做 try/catch。\n *\n * 当 adapter 不实现该方法时,picker 永远只显示\"默认模型\"占位,不报错。\n */\n getAgentDefaultModel?(agentId: string): Promise<{\n name: string\n displayName?: string\n version?: string\n } | null>\n\n /**\n * JETP-038: Post a human message to a discussion file.\n * When absent, DiscussionComposer is hidden.\n */\n postDiscussionMessage?(\n sessionId: number,\n req: PostDiscussionMessageRequest,\n ): Promise<PostDiscussionMessageResponse>\n\n /**\n * JETP-075: Create a new discussion file (user-initiated).\n *\n * 调用后端 ``POST /api/session/{sid}/discussion/create``:\n * - 在 workspace 下生成 ``discussions/<slug>-<unix_ms>.disc.md``\n * - YAML front-matter 持久化 topic / participants / created_by 等元数据\n * - 若 ``initial_body`` 非空,同时写入首条消息并触发 ``DiscussionWriteHook``\n * (进而 reinvoke @ 中的 agent / 投递 inbox notification)\n *\n * **当 adapter 不实现该方法时**:宿主端\"创建讨论\"入口必须隐藏或禁用,\n * 否则会出现\"前端开了浮窗但 .disc.md 不存在 → DiscussionViewer 一直显示\n * 占位\"的退化症(即 JETP-075 修复的 bug 形态)。\n *\n * 协议契约:``CreateDiscussionRequest`` / ``CreateDiscussionResponse``\n * 与后端 Pydantic schema 1:1 对齐,详见\n * doc/proposals/JETP-075-user-initiated-discussion/00_protocol.md §2。\n *\n * 错误处理(adapter 应原样抛出供上层 try/catch):\n * - 400 → ``CreateDiscussionResponse.error`` 非空(topic empty / creator\n * not in participants / mentions not subset)\n * - 404 → workspace 未 onboard,宿主侧应 toast 提示\n * - 409 → 同毫秒 slug 碰撞,宿主侧建议重试一次(带新 ts)\n * - 5xx → 网络/持久化失败,按 ChatWidgetNetworkError 风格抛出\n */\n createDiscussion?(\n sessionId: number,\n body: CreateDiscussionRequest,\n ): Promise<CreateDiscussionResponse>\n\n /**\n * JETP-038: List agents in the session pool (for @mention autocomplete).\n * When absent, MentionAutocomplete only shows current participants.\n */\n getPoolAgents?(sessionId: number): Promise<PoolAgent[]>\n\n /**\n * Download all visible workspace files as a single .zip archive.\n * When absent, the download button is hidden in WorkspacePanel.\n */\n downloadWorkspaceZip?(sessionId: number): Promise<void>\n\n /**\n * JETP-040 / JETP-058: Upload files to the knowledge base (batch).\n * Returns resource_ids for use in send_message file contents.\n * When sessionId is provided, files are also registered in the workspace.\n * When absent, file attachment UI is hidden.\n *\n * `clientId` (JETP-058, v2 `^c_[A-Za-z0-9]{22}$`) 必填:服务端 ARTIFACT_* 通知的\n * Layer-1 子空间标识。整 batch 复用同一 cid;retry 必须传同一 cid,让\n * `_aggregate_turn` 走 `interaction_id` 幂等键合并到同一序列。\n */\n uploadFiles?(files: File[], sessionId: number | undefined, clientId: string): Promise<FileUploadResult>\n\n /**\n * JETP-040: Poll upload processing status for previously uploaded files.\n */\n getUploadStatus?(resourceIds: string[]): Promise<FileUploadStatusResult>\n\n /**\n * JETP-040 / JETP-058: Upload files directly to the workspace file system.\n * When absent, the upload button is hidden in WorkspacePanel.\n *\n * `options.clientId` (JETP-058, v2) 必填,理由同 `uploadFiles`。\n */\n uploadWorkspaceFiles?(\n sessionId: number,\n files: File[],\n options: { targetDirectory?: string; clientId: string },\n ): Promise<WorkspaceUploadResult>\n\n createWorkspaceDirectory?(\n sessionId: number,\n dirName: string,\n parentPath?: string,\n ): Promise<{ code: number; message: string }>\n\n renameWorkspaceItem?(\n sessionId: number,\n oldPath: string,\n newName: string,\n ): Promise<{ code: number; message: string }>\n\n deleteWorkspaceItems?(\n sessionId: number,\n paths: string[],\n ): Promise<{ code: number; message: string }>\n\n moveWorkspaceItems?(\n sessionId: number,\n sourcePaths: string[],\n targetDir: string,\n ): Promise<{ code: number; message: string }>\n\n copyWorkspaceItems?(\n sessionId: number,\n sourcePaths: string[],\n targetDir: string,\n ): Promise<{ code: number; message: string }>\n}\n\n// ========== FileViewer Types (CWRF-001) ==========\n\n/** Input parameter for @xref reference resolution */\nexport interface XrefRef {\n /** Raw URI, e.g. \"rid://res-abc123#§3.2\" or \"url://docs.example.com/api\" */\n uri: string\n /** Description parameter from the @xref markup */\n description: string\n /** Relationship type */\n relation: 'cites' | 'implements' | 'extends' | 'derived_from' | 'supersedes' | 'related'\n}\n\n/** Return value from resolveXrefs */\nexport interface XrefMeta {\n /** Corresponding original URI */\n uri: string\n /** Resolved file name */\n file_name?: string\n /** File MIME type */\n mime_type?: string\n /** File path in workspace */\n git_path?: string\n /** Resource ID usable with getResourceContent */\n resource_id?: string\n /** File size in bytes */\n file_size?: number\n}\n\n/** Frontend @xref parse result — aligned with backend xref_parser.py XrefRecord format */\nexport interface XrefRecord {\n relation: string\n target_resource: string\n target_file_id: string | null\n target_location: string | null\n description: string\n source_line: number\n}\n\n/** File category enum — routes to the correct viewer */\nexport type FileCategory =\n | 'markdown'\n | 'code'\n | 'text'\n | 'image'\n | 'video'\n | 'audio'\n | 'html'\n | 'json'\n | 'pdf'\n | 'kicad'\n | '3d'\n | 'step'\n | 'gerber'\n | 'word'\n | 'excel'\n | 'powerpoint'\n | 'unknown'\n\n// ========== Context Bridge (CWRF-002) ==========\n\n/** KiCad 画布点选(需 jp-kicanvas 透出 kicanvas:select + detail.jp) */\nexport interface KicadCanvasSelectionPayload {\n uuid: string | null\n snippet: string | null\n /** 为 true 表示收到画布选中事件但无 detail.jp(当前为官方 KiCanvas) */\n noJp?: boolean\n /** 点击位置相对于画布容器的坐标,用于浮动工具栏定位 */\n anchorRect?: { top: number; left: number; width: number; height: number }\n /** 多选时的所有 uuid+snippet 列表 */\n items?: Array<{ uuid: string; snippet: string | null }>\n}\n\nexport interface FileReference {\n resourceId: string\n sessionId: number\n fileName: string\n mimeType?: string | null\n specId?: string\n selection?: {\n text: string\n startLine?: number\n endLine?: number\n /** PDF page number (1-based) */\n page?: number\n /** End page when selection spans pages */\n endPage?: number\n /** Base64 data-url when an image was selected */\n imageSrc?: string\n }\n}\n\n// ========== File Upload Types (JETP-040) ==========\n\nexport interface UploadedFileInfo {\n resourceId: string\n fileName: string\n gitPath?: string\n localFile?: File\n status: 'uploading' | 'processing' | 'ready' | 'error'\n progress?: string\n error?: string\n}\n\nexport interface FileUploadResult {\n status?: 'accepted' | 'partial_success' | 'failed'\n code?: number\n message: string\n data: {\n files: Array<{\n resource_id: string\n original_filename: string\n status: number\n message: string\n git_path?: string\n git_commit_hash?: string\n }>\n errors?: Array<{ original_filename: string; error: string }>\n total_files: number\n successful_uploads: number\n failed_uploads: number\n }\n}\n\nexport interface FileUploadStatusResult {\n status: string\n data: {\n files: Array<{ resource_id: string; status: number; progress?: string | null }>\n successful_count: number\n failed_count: number\n not_found_resource_ids: string[]\n total_requested: number\n }\n}\n\nexport interface WorkspaceUploadResult {\n code: number\n message: string\n data?: unknown\n}\n\nexport interface FileAttachment {\n resourceId: string\n fileName: string\n gitPath?: string\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 ForeignRoundBadgeProps {\n round: Round\n unreadCount: number\n onExpand?: (interactionId: string) => void\n}\n\nexport interface MessageContentProps {\n message: AggregatedMessage\n enableTypewriter?: boolean\n typewriterSpeed?: number\n onArtifactClick?: (artifact: Artifact) => void\n onHITLSubmit?: (response: HITLResponse) => Promise<void>\n renderToolResult?: (displayType: string, data: ToolCallData) => React.ReactNode | null\n observedInstanceStates?: Map<number, PoolAgent>\n}\n\nexport interface ChildAgentCardProps {\n message: AggregatedMessage\n children: AggregatedMessage[]\n maxHeight?: number\n config?: ChatWidgetConfig\n defaultExpanded?: boolean\n parentTaskPurpose?: string\n /** 本轮次已收到 agent_end 的 agent_instance_id(与 notification_turns 对齐),有则优先据此显示「已完成」 */\n endedAgentInstanceIds?: Set<number>\n /** 本轮次全部消息,用于判断该 agent 是否有未完成的工具(子 agent 的 MCP 消息可能挂在别的 parent 下,不在此卡片的 children 里) */\n allRoundMessages?: AggregatedMessage[]\n onHITLSubmit?: (response: HITLResponse) => Promise<void>\n /** Observation-driven instance states from MonitorRegistry (pool observation). */\n observedInstanceStates?: Map<number, PoolAgent>\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 * useChatWidgetController — headless orchestration hook\n *\n * Manages: transport connection (WS primary / SSE fallback), message aggregation,\n * session lifecycle, execution status, and event dispatch.\n * Does NOT manage: scroll, pinning, transitions, file viewer, or any DOM.\n */\n\nimport { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'\nimport { I18nContext } from '../i18n/context'\nimport type {\n ChatWidgetAdapter,\n SSEMessage,\n Round,\n ExecutionStatus,\n ChatWidgetAPI,\n AggregatedMessage,\n Artifact,\n FileReference,\n NotificationTurn,\n PaginatedHistoryResponse,\n UiConfig,\n MessageContentType,\n TodoData,\n SelectedSkillRef,\n} from '../types'\nimport { isTodoNotificationContent } from '../types'\nimport { useMessageAggregator, parseGenUIMetaContent } from '../hooks/useMessageAggregator'\nimport { useConnectionId } from '../hooks/useConnectionId'\nimport { useSSE } from '../hooks/useSSE'\nimport { useAuthedFetch } from '../hooks/useAuthedFetch'\nimport { randomUUID } from '../utils/randomUUID'\nimport type { ConnectionStatus } from '../hooks/useSSE'\nimport { useSessionChannel } from '../hooks/useSessionChannel.js'\nimport type { SessionChannelMessage } from '../hooks/useSessionChannel.js'\nimport { usePoolObservation } from '../hooks/usePoolObservation.js'\nimport type { PoolObservation } from '../hooks/usePoolObservation.js'\nimport { useSessionClients } from '../hooks/useSessionClients'\nimport { InvalidClientIdError } from '../errors'\n\nexport type { ConnectionStatus }\n\n// ────────────────────────────── Types ──────────────────────────────\n\nexport interface ChatWidgetControllerOptions {\n adapter: ChatWidgetAdapter\n sessionId?: string | number\n reuseAgentInstance?: boolean\n activeSpecIdsRef?: React.RefObject<string[]>\n /** Transport mode: 'ws' uses WebSocket, 'sse' uses Server-Sent Events. No fallback between them. */\n transport?: 'ws' | 'sse'\n /**\n * JETP-058:拉历史时透传给 adapter 的 v2 ``c_<22>`` client_ids 列表。\n *\n * - **不再有 legacy \"main\" 默认值**:v2-only 强约束下,调用方未派生出任何 v2 cid 之前\n * controller 不会发起 history 请求(避免 silent fallback 写脏数据);\n * - 由 ChatWidget 内部派生为该 session 全部任务话池 cid 列表后再下传;\n * - 空数组 / undefined → controller skip 调 adapter,等下一轮派生到非空 list 时自动重拉。\n */\n historyClientIds?: string[]\n /**\n * JETP-057:拉历史时是否包含 status='building' 的 in-flight turns。\n * 前端默认 ``true`` —— 否则刷新后正在跑的子 agent 卡片会暂时消失。\n */\n historyIncludeInFlight?: boolean\n /**\n * 是否在 mount 时立即调用 ``adapter.createSession`` 预分配 session+workspace。\n * 默认 ``true`` 保持原 SDK 行为;多会话宿主(如 Demo / Console)应传 ``false``,\n * 避免每次刷新(无 ``sessionId`` prop 的 mount)都在后端 page 列表里插入空 session。\n */\n eagerSessionCreation?: boolean\n onStatusChange?: (status: ExecutionStatus) => void\n onConnectionChange?: (connected: boolean) => void\n onRoundChange?: (rounds: Round[]) => void\n onMessageAppended?: (message: AggregatedMessage, round?: Round) => void\n onRoundStart?: (interactionId: string, userMessage: string) => void\n onRoundEnd?: (interactionId: string) => void\n onError?: (error: Error) => void\n onDiscussionUpdate?: (event: Record<string, unknown>) => void\n /**\n * 会话生命周期事件回调。controller 在以下时机各 emit 一次:\n *\n * - `created` :``adapter.createSession`` 成功 / 后端通过 SSE ``session_info`` 推回新 session_id;\n * 从 ``sessionId`` prop 恢复历史会话不会触发本事件。\n * - `updated` :当前以 ``session_title`` 变化为唯一来源 —— SSE ``session_title`` 通知 /\n * ``loadHistory`` 取 detail / 兜底 ``getSessionDetail`` 拿到非空 title 都会各触发一次。\n *\n * ChatWidget 默认会把这两条 emit 转译成 ``'session-created' / 'session-updated'``\n * InteractionEvent;如果宿主不走 InteractionContext,可以直接读这个回调。\n */\n onSessionEvent?: (event: import('../types.js').SessionLifecycleEvent) => void\n /**\n * JETP-073:client(\"办公室\")级 title 解析事件回调。\n *\n * 触发时机:SSE/WS 收到 ``notification_type: 'client_title'`` 消息(backend\n * `node_title_agent` 在 first agent start 后基于 LLM 派生出的客户端标题)。\n *\n * 与 ``onSessionEvent`` 关键区别:\n * - ``onSessionEvent.updated`` 一个 session 触发一次;\n * - ``onClientTitleEvent`` 一个 session 内每个 client 各触发一次(多 client 场景常见)。\n *\n * 上层(如 yumiai-web ``WorkspaceCore``)把 ``clientId → clientTitle`` 累加到本地 map,\n * 下游派生(如 ``useDeriveCubicleClients``)优先使用 backend 真值,缺值时再 fallback。\n *\n * 本回调不会被 controller 内部消化掉;message 也不会进入 rounds(被\n * ``LIFECYCLE_TURN_TYPES`` 过滤)。\n */\n onClientTitleEvent?: (event: import('../types.js').ClientTitleEvent) => void\n}\n\nexport interface ChatWidgetControllerState {\n executionStatus: ExecutionStatus\n connectionStatus: ConnectionStatus\n /** Effective transport mode: 'ws' when WebSocket is active, 'sse' otherwise */\n activeTransport: 'ws' | 'sse'\n rounds: Round[]\n /** Interaction IDs owned by this tab (sent locally or loaded from history). */\n localInteractionIds: ReadonlySet<string>\n currentSessionId: number | null\n sessionTitle: string\n todoMap: Map<string, TodoData>\n specMetaMap: Map<string, { resourceId: string; gitPath: string }>\n /** JETP-083 WS3.7.5 — terminal lifecycle markers (cancelled/error) by spec_id. */\n specLifecycleMap: Map<string, import('../types').SpecLifecycleEntry>\n sendMessage: (message: string, agentId?: string, inlineRefs?: FileReference[], selectedSkills?: SelectedSkillRef[], overrideInstanceId?: number | null, clientId?: string, fileAttachments?: import('../types').FileAttachment[], modelOverride?: import('../types').ModelOverride | null) => Promise<void>\n widgetAPI: ChatWidgetAPI\n /** Agent instance states tracked via WS status stream. Empty map when SSE transport. */\n agentStates: Map<number, import('../hooks/useSessionChannel.js').AgentInstanceState>\n /** Send agent control frame (pause/resume/stop) via WS. No-op when SSE. */\n sendControlFrame: import('../hooks/useSessionChannel.js').UseSessionChannelReturn['sendControlFrame']\n /** Whether any agent is RUNNING in the session (observation-driven, for top bar). */\n sessionBusy: boolean\n /** Whether the WebSocket is connected (for useDiscussions polling adjustment). */\n wsConnected: boolean\n /** Whether the primary (level-0) agent instance is RUNNING (observation-driven, for input box). */\n primaryAgentBusy: boolean\n /** Full pool observation data (for child agent cards). */\n poolObservation: PoolObservation\n /** JETP-037: whether more older pages are available */\n hasMore: boolean\n /** JETP-037: whether an older page is currently loading */\n loadingMore: boolean\n /** JETP-037: trigger loading of the next older page */\n loadOlderPage: () => Promise<void>\n /** Ensure a session exists, creating one with retries if needed. */\n ensureSession: () => Promise<number>\n}\n\n// ────────────────────────── Helpers ──────────────────────────\n//\n// History recovery pipeline (方案 D — 三层流水线)\n//\n// Layer 1 — lifecycle filter : 丢弃纯生命周期 turn(不携带用户可见内容)\n// Layer 2 — MCP merge : 同一 tool_call_id 的 mcp_start/mcp_end 合并为一条消息\n// Layer 3 — content transform: artifact 解析、plan_result todoMap 提取、JSON 安全序列化\n//\n// 未来演进方向见 JETP-037 开发文档:可替换为方案 C(DB turn → SSEMessage → 实时管线)\n// ──────────────────────────────────────────────────────────────\n\n// ── Layer 1: 应被直接丢弃的生命周期 turn 类型 ──\nconst LIFECYCLE_TURN_TYPES = new Set([\n 'session_title', // [DEPRECATED 起 JETP-073] 仅在 dual-write 兼容期出现\n 'client_title', // JETP-073:client(\"办公室\")级 LLM 起名\n 'start', 'finish',\n 'user_input',\n 'model_start', 'model_end',\n 'agent_start', 'agent_end',\n 'artifact_start', 'artifact_end',\n 'compression_started', 'compression_completed',\n 'node_notification',\n 'canceled',\n 'plan_start', 'plan_end',\n])\n\n// ── Layer 3 helper: artifact 解析 ──\n\nfunction parseArtifactFromContent(content: string): Artifact | null {\n try {\n const parsed = JSON.parse(content) as Record<string, unknown>\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\n ? fileSize > 1024 ? `${(fileSize / 1024).toFixed(1)} KB` : `${fileSize} B`\n : undefined\n return {\n id: (parsed.identifier || data.file_id || `art-${Date.now()}`) 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 return {\n id: (parsed.id || `art-${Date.now()}`) 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 } catch {\n return null\n }\n}\n\n// ── Layer 2: 将同一 tool_call_id 的 MCP turn 合并为一条 AggregatedMessage ──\n\ninterface MergedMcpTurn {\n toolCallId: string\n toolName: string\n taskPurpose?: string\n toolStatus?: 'success' | 'error'\n uiConfig?: UiConfig\n parentToolCallId?: string\n argsPreview?: string\n agentInstanceId: number\n callBatchId: number\n parentCallBatchId?: number\n level: number\n agentName: string\n agentId: string\n timestamp: number\n turnId: number\n resultContentChunks: string[]\n}\n\nfunction mergeMcpTurns(group: NotificationTurn[]): MergedMcpTurn[] {\n const byToolCallId = new Map<string, { start?: NotificationTurn; end?: NotificationTurn; resultContents: string[] }>()\n const ordered: string[] = []\n\n for (const turn of group) {\n if (turn.type !== 'mcp_start' && turn.type !== 'mcp_end' && turn.type !== 'mcp_result') continue\n const tcId = (turn.ext as Record<string, unknown> | null)?.tool_call_id as string | undefined\n if (!tcId) continue\n if (!byToolCallId.has(tcId)) {\n byToolCallId.set(tcId, { resultContents: [] })\n ordered.push(tcId)\n }\n const entry = byToolCallId.get(tcId)!\n if (turn.type === 'mcp_start') entry.start = turn\n else if (turn.type === 'mcp_end') entry.end = turn\n else if (turn.type === 'mcp_result') {\n for (const part of (turn.contents || [])) {\n const raw = part.content\n const str = typeof raw === 'string' ? raw : (raw != null ? JSON.stringify(raw) : '')\n if (str) entry.resultContents.push(str)\n }\n }\n }\n\n const result: MergedMcpTurn[] = []\n for (const tcId of ordered) {\n const { start, end, resultContents } = byToolCallId.get(tcId)!\n const repr = start || end!\n const ext = (repr.ext || {}) as Record<string, unknown>\n const endExt = end ? (end.ext || {}) as Record<string, unknown> : ext\n\n const toolName = (ext.tool_name || endExt.tool_name || '') as string\n const isCallAgent = toolName === 'call_agent'\n result.push({\n toolCallId: tcId,\n toolName,\n taskPurpose: (ext.task_purpose || ext._task_purpose || endExt.task_purpose || endExt._task_purpose) as string | undefined,\n toolStatus: (endExt.status || ext.status) as 'success' | 'error' | undefined,\n uiConfig: (ext.ui_config || endExt.ui_config) as UiConfig | undefined,\n parentToolCallId: (ext.parent_tool_call_id || endExt.parent_tool_call_id) as string | undefined,\n argsPreview: (ext.args_preview || endExt.args_preview) as string | undefined,\n agentInstanceId: repr.agent_instance_id || 0,\n callBatchId: repr.call_batch_id || 0,\n parentCallBatchId: repr.parent_call_batch_id ?? undefined,\n level: repr.level ?? 0,\n agentName: isCallAgent ? (repr.card_title || repr.agent_id || '') : (repr.agent_id || ''),\n agentId: repr.agent_id || '',\n timestamp: repr.timestamp || repr.timestamp_start || 0,\n turnId: repr.turn_id || 0,\n resultContentChunks: resultContents,\n })\n }\n return result\n}\n\n// ── Main conversion function ──\n\ninterface ConvertResult {\n rounds: Round[]\n todoEntries: Map<string, TodoData>\n specMetaMap: Map<string, { resourceId: string; gitPath: string }>\n /** JETP-083 WS3.7.5 — replays surface terminal cancelled/error state too. */\n specLifecycleMap: Map<string, import('../types').SpecLifecycleEntry>\n}\n\nexport function convertTurnsToRounds(turns: NotificationTurn[], fallbackUserText: string, fallbackAgentName: string): ConvertResult {\n // ── JETP-052 BUG-1:稳定排序 ──\n // 服务端不保证 turns 数组有序(多 callee fan-out / xread 多 stream 合并均会乱序)。\n // 排序键三元组:(turn_index ?? Infinity, turn_id, timestamp_start ?? timestamp ?? 0)\n // - turn_index 是 db-writer 在 (interaction_id, callee_instance_id) 维度的单调键 → 主排序键。\n // - turn_index 缺失(旧后端)退到 turn_id(PK,单调)→ 次排序键。\n // - turn_id 也缺失再退到 timestamp(ms)→ 兜底排序键。\n // 同 turn_index/turn_id 同 ts 时保留服务端原顺序(稳定排序)。\n const turnKey = (t: NotificationTurn): [number, number, number] => {\n const idx = typeof t.turn_index === 'number' ? t.turn_index : Number.POSITIVE_INFINITY\n const tid = typeof t.turn_id === 'number' ? t.turn_id : Number.POSITIVE_INFINITY\n const ts = typeof t.timestamp_start === 'number'\n ? t.timestamp_start\n : (typeof t.timestamp === 'number' ? t.timestamp : 0)\n return [idx, tid, ts]\n }\n const cmp3 = (a: [number, number, number], b: [number, number, number]): number => {\n if (a[0] !== b[0]) return a[0] - b[0]\n if (a[1] !== b[1]) return a[1] - b[1]\n return a[2] - b[2]\n }\n const sortedTurns = [...turns].sort((a, b) => cmp3(turnKey(a), turnKey(b)))\n\n // 分组保持插入顺序 = sortedTurns 的首遇顺序 → 跨 round 排序也对齐。\n const groups = new Map<string, NotificationTurn[]>()\n for (const t of sortedTurns) {\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 const todoEntries = new Map<string, TodoData>()\n const specMetaMap = new Map<string, { resourceId: string; gitPath: string }>()\n const specLifecycleMap = new Map<string, import('../types').SpecLifecycleEntry>()\n let roundIdx = 0\n\n for (const [interactionId, group] of groups) {\n // extract user text\n const userTurn = group.find(t => t.type === 'user_input')\n const userText = userTurn\n ? (userTurn.contents || []).map(c => c.content || '').join('')\n : fallbackUserText\n\n // ── Layer 2: pre-merge MCP turns by tool_call_id ──\n const mcpMerged = mergeMcpTurns(group)\n const mcpToolCallIds = new Set(mcpMerged.map(m => m.toolCallId))\n\n const agentMessages: AggregatedMessage[] = []\n const genUIMessageMap = new Map<string, AggregatedMessage>()\n\n // We interleave MCP merged messages at the position of their first turn\n // to preserve chronological ordering with non-MCP messages.\n const emittedMcpIds = new Set<string>()\n\n for (const turn of group) {\n // ── Layer 1: lifecycle filter ──\n if (LIFECYCLE_TURN_TYPES.has(turn.type)) continue\n\n const contents = turn.contents || []\n const ext = (turn.ext || {}) as Record<string, unknown>\n\n // ── Layer 2: MCP turns — emit merged message on first encounter ──\n if (turn.type === 'mcp_start' || turn.type === 'mcp_end' || turn.type === 'mcp_result' || turn.type === 'mcp_generating') {\n const tcId = ext.tool_call_id as string | undefined\n if (tcId && mcpToolCallIds.has(tcId) && !emittedMcpIds.has(tcId)) {\n emittedMcpIds.add(tcId)\n const merged = mcpMerged.find(m => m.toolCallId === tcId)!\n // YWRF-DUP-001:与 useMessageAggregator live 路径 (L391) 同形态\n // ``${interaction_id}-${agent_instance_id}-mcp-${tool_call_id}``\n // 让 mergeRecoveryRounds 的 id-based dedup 能把 live + recovery 同 turn 合并掉,\n // 避免 live → 中途 recovery_turns 双投递时同一工具卡片在 round 里出现两次。\n agentMessages.push({\n id: `${interactionId}-${merged.agentInstanceId}-mcp-${tcId}`,\n agentInstanceId: merged.agentInstanceId,\n callBatchId: String(merged.callBatchId),\n parentCallBatchId: merged.parentCallBatchId != null ? String(merged.parentCallBatchId) : undefined,\n level: merged.level,\n agentName: merged.agentName || fallbackAgentName,\n notificationType: 'mcp_end' as any,\n toolName: merged.toolName,\n toolCallId: merged.toolCallId,\n toolStatus: merged.toolStatus,\n taskPurpose: merged.taskPurpose,\n uiConfig: merged.uiConfig,\n parentToolCallId: merged.parentToolCallId,\n argsPreview: merged.argsPreview,\n contentType: 'text',\n contentChunks: merged.resultContentChunks,\n timestamp: String(merged.timestamp),\n toolPhase: merged.toolStatus === 'error' ? 'error' : 'complete',\n })\n }\n continue\n }\n\n // ── Layer 3: content transform ──\n\n // plan_result → extract todoMap, skip message\n if (turn.type === 'plan_result' && contents.length > 0) {\n for (const part of contents) {\n const raw = part.content\n const parsed = typeof raw === 'object' && raw != null\n ? raw\n : (() => { try { return JSON.parse(raw as string) } catch { return null } })()\n if (parsed && isTodoNotificationContent(parsed)) {\n const planId = (parsed as { plan_id?: string }).plan_id || 'default'\n todoEntries.set(planId, (parsed as { checklist: TodoData }).checklist)\n }\n }\n continue\n }\n\n // empty content for non-MCP turns → skip\n if (contents.length === 0) continue\n\n for (let i = 0; i < contents.length; i++) {\n const part = contents[i]\n const partType = part.type || 'text'\n\n // ── GenUI handling: accumulate patches per spec_id ──\n if (partType === 'gen_ui_card' || partType === 'gen_ui_page') {\n const specId = (part as any).spec_id as string | undefined\n if (!specId) continue\n const rawContent = part.content\n const patchStr = typeof rawContent === 'string'\n ? rawContent\n : (rawContent != null ? JSON.stringify(rawContent) : '')\n const existing = genUIMessageMap.get(specId)\n if (existing) {\n if (patchStr) existing.uiPatches = [...(existing.uiPatches || []), patchStr]\n } else {\n // YWRF-DUP-001:与 useMessageAggregator live 路径 (L393-394) 同形态\n // ``${interaction_id}-genui-${spec_id}``\n // 同一 spec_id 的 live 与 recovery 收敛到同 id,merge 阶段去重。\n const msg: AggregatedMessage = {\n id: `${interactionId}-genui-${specId}`,\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.agent_id || fallbackAgentName,\n notificationType: turn.type as any,\n contentType: partType as MessageContentType,\n contentChunks: [],\n timestamp: String(turn.timestamp || ''),\n specId,\n renderMode: (part as any).render_mode as 'card' | 'page' | undefined,\n uiPatches: patchStr ? [patchStr] : [],\n }\n genUIMessageMap.set(specId, msg)\n agentMessages.push(msg)\n }\n continue\n }\n\n if (partType === 'gen_ui_meta') {\n const specId = (part as any).spec_id as string | undefined\n const parsed = parseGenUIMetaContent(part.content as unknown)\n if (specId && parsed) {\n if (parsed.kind === 'identity') {\n specMetaMap.set(specId, { resourceId: parsed.resourceId, gitPath: parsed.gitPath })\n } else {\n specLifecycleMap.set(specId, parsed.entry)\n }\n }\n continue\n }\n\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 const rawContent = part.content\n const contentStr = typeof rawContent === 'string'\n ? rawContent\n : (rawContent != null ? JSON.stringify(rawContent) : '')\n\n // YWRF-DUP-001 — message id 与 useMessageAggregator live 路径 (L398) 对齐:\n // live:``${interaction_id}-ti-${turn_index}``(按 turn_index 聚合)\n // recovery:缺 turn_index → 退回 ``hist-${turn_id}-${i}`` 兜底\n //\n // 修复前两条路径用不同 namespace(``iid-ti-N`` vs ``hist-...``),\n // ``mergeRecoveryRounds`` 按 id 去重永远命不中 → 同一 turn 被加两份。\n // 用户实测:「等任务结束点侧边栏走 loadHistory 重建(单源)→ 重复消失」即此漏洞。\n //\n // i > 0(同一 turn 多 content,理论场景)追加 ``-${i}`` 后缀避免与 i=0 撞键。\n const hasTurnIdx = typeof turn.turn_index === 'number'\n const id = hasTurnIdx\n ? (i === 0\n ? `${interactionId}-ti-${turn.turn_index}`\n : `${interactionId}-ti-${turn.turn_index}-${i}`)\n : `hist-${turn.turn_id}-${i}`\n\n const msg: AggregatedMessage = {\n 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.agent_id || fallbackAgentName,\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: [contentStr],\n timestamp: String(turn.timestamp || ''),\n }\n\n if (contentType === 'artifact' && contentStr) {\n const artifact = parseArtifactFromContent(contentStr)\n if (artifact) {\n msg.artifacts = [artifact]\n msg.artifact = artifact\n }\n }\n\n agentMessages.push(msg)\n }\n }\n\n roundIdx++\n const ts = group[0]?.timestamp_start || group[0]?.timestamp\n // JETP-045 P7:channel_id 已撤回;后端 _turn_to_dict 已统一下发 client_id(老 turn 由后端兜底)\n const clientId = group[0]?.client_id ?? ''\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 clientId: clientId || undefined,\n })\n\n }\n\n return { rounds, todoEntries, specMetaMap, specLifecycleMap }\n}\n\n// ──────────────────────── Hook ────────────────────────\n\nexport function useChatWidgetController(\n options: ChatWidgetControllerOptions,\n): ChatWidgetControllerState {\n const {\n adapter,\n sessionId: propSessionId,\n reuseAgentInstance = true,\n activeSpecIdsRef,\n transport: transportPref = 'ws',\n historyClientIds,\n historyIncludeInFlight = true,\n eagerSessionCreation = true,\n onStatusChange,\n onConnectionChange,\n onRoundChange,\n onMessageAppended,\n onRoundStart,\n onRoundEnd,\n onError,\n onDiscussionUpdate,\n onSessionEvent,\n onClientTitleEvent,\n } = options\n\n // ── Session lifecycle event helper ──\n // 用 ref 持有最新回调,避免把 onSessionEvent 写进每个 useCallback / SSE handler 的依赖里。\n const onSessionEventRef = useRef(onSessionEvent)\n useEffect(() => { onSessionEventRef.current = onSessionEvent }, [onSessionEvent])\n const emitSessionEvent = useCallback(\n (event: import('../types.js').SessionLifecycleEvent) => {\n onSessionEventRef.current?.(event)\n },\n [],\n )\n\n // ── JETP-073 client_title event helper(与 emitSessionEvent 同形) ──\n // 同样用 ref 持有最新回调,保持 SSE/WS handler 的依赖列表稳定。\n const onClientTitleEventRef = useRef(onClientTitleEvent)\n useEffect(() => { onClientTitleEventRef.current = onClientTitleEvent }, [onClientTitleEvent])\n const emitClientTitleEvent = useCallback(\n (event: import('../types.js').ClientTitleEvent) => {\n try {\n onClientTitleEventRef.current?.(event)\n } catch (err) {\n // 上层 listener 抛错不能击穿 message 流;与 emitSessionEvent 静默语义对齐。\n console.error('[client_title] listener error', err)\n }\n },\n [],\n )\n // JETP-058 v2-only:默认空数组(=== \"尚未派生出任何 v2 cid\")。\n // controller 在 effectiveHistoryClientIds 为空时不会发起 history 请求;\n // ChatWidget 派生出该 session 全部任务话池 cid(``c_<22>``)后会再触发 effect 重拉。\n // 用 join('|') 稳定 useMemo 依赖,避免调用方每次传入新数组引起 effect 抖动。\n const historyClientIdsKey = (historyClientIds ?? []).join('|')\n const effectiveHistoryClientIds = useMemo<string[]>(\n () => (historyClientIds && historyClientIds.length > 0 ? [...historyClientIds] : []),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [historyClientIdsKey],\n )\n\n const i18nMessages = useContext(I18nContext)\n\n // ── Message aggregator ──\n const {\n state: aggregatorState,\n todoMap,\n specMetaMap,\n specLifecycleMap,\n processMessage,\n getRoundsList,\n startNewRound,\n loadRounds,\n prependRounds,\n mergeRecoveryRounds,\n finalizeRound,\n loadTodoMap,\n loadSpecMetaMap,\n loadSpecLifecycleMap,\n setMyConnectionId,\n clear: aggregatorClear,\n } = useMessageAggregator()\n\n // JETP-045 Phase 6 (P6-T06):本 tab 物理连接 ID(每个 ChatWidget mount 唯一)。\n // 所有 sendMessage / buildStreamBody 用同一个值;下行 notification 的\n // ``connection_id_from === connectionId`` 即视为 echo (AC-CONN-006)。\n const connectionId = useConnectionId()\n useEffect(() => {\n setMyConnectionId(connectionId)\n }, [connectionId, setMyConnectionId])\n\n // ── Core state ──\n const [executionStatus, setExecutionStatus] = useState<ExecutionStatus>('idle')\n const [currentSessionId, _setCurrentSessionId] = useState<number | null>(null)\n // JETP-058 fix:sessionId 必须有同步 ref 副本。原因:\n // ensureClientId() → ensureSession() → setCurrentSessionId(s1) (React state 异步)\n // → 控制流回到 sendMessage,同一回调里读 ``currentSessionId`` 仍是 null\n // → 又走一遍 ensureSession() → 后端 createSession 第二次!\n // 用 ref 同步保存最新值,所有 ensureSession / sendMessage 内的判空都改读 ref。\n const currentSessionIdRef = useRef<number | null>(null)\n const setCurrentSessionId = useCallback((id: number | null) => {\n currentSessionIdRef.current = id\n _setCurrentSessionId(id)\n }, [])\n const [sessionTitle, setSessionTitle] = useState('')\n const sessionTitleFetchedRef = useRef(false)\n\n // ── JETP-073 fix_p2 · load history hydration of clientTitleMap ──\n //\n // 问题:CLIENT_TITLE notification 只在「新建 client → LLM 起名」时推送一次。\n // 重新进 workspace / 刷新页面时,PG 里 ``clients.title`` 已经有值,但 controller\n // 不会 re-emit ClientTitleEvent → 上层(yumiai-web WorkspaceCore)的\n // ``clientTitleMap`` 是空 Map → sidebar 退化到 FALLBACK_CLIENT_TITLE='新任务'。\n //\n // 修复:controller 内部跟着 currentSessionId 拉一次 ``/api/session/{sid}/clients``,\n // 对每个 ``title`` 非空的 client emit 一次 ClientTitleEvent。dedup 避免与\n // 同期 SSE notification 撞车(emitClientTitleSeenRef 按 cid 记最后一次 emit 的\n // title,相同则跳过)。切 sessionId 时清 ref。\n //\n // 与 ChatWidget.tsx 内部已有的 useSessionClients 共存:两个 hook 实例各拉一次\n // /api/session/{sid}/clients,但 useSessionClients 内部带 inflight dedup +\n // StaleResponseGuard,不会出现并发竞争;后续如要消除冗余可把这条职责上移到\n // ChatWidget(让 ChatWidget 把 sessionClientItems 往下传)。\n const emitClientTitleSeenRef = useRef<Map<string, string>>(new Map())\n const { items: hydratedClientItems, loadedSessionId: hydratedLoadedSid } =\n useSessionClients(currentSessionId, '', { adapter })\n useEffect(() => {\n // 切 session 清 dedup(旧 session 的 cid 永远不会再出现)\n emitClientTitleSeenRef.current = new Map()\n }, [currentSessionId])\n useEffect(() => {\n if (hydratedLoadedSid !== currentSessionId) return\n if (!hydratedClientItems || hydratedClientItems.length === 0) return\n for (const it of hydratedClientItems) {\n const title = (it.title ?? '').trim()\n if (!title) continue\n const last = emitClientTitleSeenRef.current.get(it.id)\n if (last === title) continue\n emitClientTitleSeenRef.current.set(it.id, title)\n emitClientTitleEvent({\n type: 'client_title',\n sessionId: typeof currentSessionId === 'number' ? currentSessionId : -1,\n clientId: it.id,\n clientTitle: title,\n })\n }\n }, [hydratedClientItems, hydratedLoadedSid, currentSessionId, emitClientTitleEvent])\n\n // Agent instance reuse tracking\n const agentInstanceMapRef = useRef<Map<string, number>>(new Map())\n const currentAgentIdRef = useRef('agent-680')\n const callerInstanceIdRef = useRef<number | null>(null)\n const bypassInstanceTrackingIdsRef = useRef<Set<string>>(new Set())\n const prevReuseRef = useRef(reuseAgentInstance)\n useEffect(() => {\n if (prevReuseRef.current && !reuseAgentInstance) {\n agentInstanceMapRef.current.clear()\n }\n prevReuseRef.current = reuseAgentInstance\n }, [reuseAgentInstance])\n const activeInteractionIdRef = useRef<string | null>(null)\n // JETP-057: key 由 sessionId|clientIds|includeInFlight 组成。\n // 当 ChatWidget 异步派生出更全的 clientIds(含浮窗 / v2 c_xxx)时,\n // key 会变,effect 自然会用新参数重拉一次完整历史。\n const historyLoadedRef = useRef<string | null>(null)\n // JETP-045 P5 (P2-T11):cursor 形态升级为 Map[(iid::callee) → max_turn_index]。\n // 旧 ``Record<iid, max>`` 形态在 fan-out(同 iid 多 callee)场景下会撞 key\n // → 一个 callee 的高 turn_index 把另一个 callee 的低 turn_index 顶掉,\n // 重连补全时整段 turn 丢失。改为复合 key 后多 callee 各自独立推进。\n // db-writer 的单调粒度也是 (interaction_id, callee_instance_id),三方对齐。\n const turnCursorRef = useRef<Map<string, number>>(new Map())\n const cursorKey = useCallback((interactionId: string, callee: number): string =>\n `${interactionId}::${callee}`, [])\n const advanceTurnCursor = useCallback((\n interactionId: string,\n callee: number,\n turnIndex: number,\n ): void => {\n if (!interactionId || !Number.isFinite(callee) || !Number.isFinite(turnIndex)) return\n const key = cursorKey(interactionId, callee)\n const cur = turnCursorRef.current.get(key) ?? 0\n if (turnIndex > cur) turnCursorRef.current.set(key, turnIndex)\n }, [cursorKey])\n\n // JETP-037: pagination state\n const [hasMore, setHasMore] = useState(false)\n const [nextCursor, setNextCursor] = useState<string | null>(null)\n const [loadingMore, setLoadingMore] = useState(false)\n\n // Multi-tab interaction isolation: map server-generated interaction IDs to\n // client UUIDs so foreign rounds are not merged into the active round.\n const serverToClientIdMapRef = useRef(new Map<string, string>())\n const localInteractionIdsRef = useRef(new Set<string>())\n\n // ── Session creation with retry ──\n const eagerSessionCreatedRef = useRef(false)\n const sessionCreationPromiseRef = useRef<Promise<number> | null>(null)\n\n const ensureSession = useCallback(async (): Promise<number> => {\n // JETP-058 fix:用 ref 而不是 state,保证同一回调内连续调用看到的是最新值,\n // 否则会出现\"ensureClientId 已 createSession 但 sendMessage 又再 createSession\"的双开。\n if (currentSessionIdRef.current != null) return currentSessionIdRef.current\n if (sessionCreationPromiseRef.current) return sessionCreationPromiseRef.current\n\n const promise = (async () => {\n const MAX_RETRIES = 3\n const RETRY_DELAY = 1000\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n const session = await adapter.createSession(currentAgentIdRef.current)\n setCurrentSessionId(session.sessionId)\n callerInstanceIdRef.current = session.instanceId\n eagerSessionCreatedRef.current = true\n emitSessionEvent({\n type: 'created',\n sessionId: session.sessionId,\n agentId: currentAgentIdRef.current,\n source: 'explicit',\n })\n return session.sessionId\n } catch (err) {\n console.warn(`[Controller] Session creation attempt ${attempt}/${MAX_RETRIES} failed:`, err)\n if (attempt < MAX_RETRIES) {\n await new Promise(r => setTimeout(r, RETRY_DELAY * attempt))\n }\n }\n }\n throw new Error('Session creation failed after retries')\n })()\n\n sessionCreationPromiseRef.current = promise\n try {\n return await promise\n } finally {\n sessionCreationPromiseRef.current = null\n }\n }, [adapter, currentSessionId])\n\n // ── Eager session creation: allocate session+workspace before user sends first message ──\n // 由 ``eagerSessionCreation`` 配置控制;多会话宿主(Demo / Console)应关掉,\n // 否则每次无 ``sessionId`` prop 的刷新都会落一条空 session 进 ``/api/session/page``。\n useEffect(() => {\n if (!eagerSessionCreation) return\n if (propSessionId != null || currentSessionId != null || eagerSessionCreatedRef.current) return\n if (!adapter.buildStreamBody) return\n eagerSessionCreatedRef.current = true\n\n ensureSession().catch(() => {\n eagerSessionCreatedRef.current = false\n })\n // Only run once on mount when no prop session\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // ── SSE message handler ──\n const handleSSEMessage = useCallback(\n (message: SSEMessage & { type?: string; session_id?: number; notification_type?: string }) => {\n if (adapter.transformSSEMessage && message.interaction_id) {\n const serverId = message.interaction_id\n if (serverToClientIdMapRef.current.has(serverId)) {\n message.interaction_id = serverToClientIdMapRef.current.get(serverId)!\n }\n }\n\n const isLocalInteraction = !message.interaction_id\n || localInteractionIdsRef.current.has(message.interaction_id)\n || serverToClientIdMapRef.current.has(message.interaction_id)\n\n if (message.type === 'session_info' && message.session_id) {\n // 与 ensureSession 互斥:sse session_info 仅在\"后端在第一条消息时创建 session\n // 并通过 SSE 推回新 sid\"路径出现;从 props 恢复或 ensureSession 已落定的 sid\n // 不会再走这里。因此可以直接当作 created 上报。\n const isNewSession = currentSessionIdRef.current !== message.session_id\n setCurrentSessionId(message.session_id)\n sessionTitleFetchedRef.current = false\n if (isNewSession) {\n emitSessionEvent({\n type: 'created',\n sessionId: message.session_id,\n agentId: currentAgentIdRef.current,\n source: 'sse',\n })\n }\n return\n }\n\n if (message.notification_type === 'session_title' && message.content) {\n setSessionTitle(message.content)\n sessionTitleFetchedRef.current = true\n const sid = currentSessionIdRef.current\n if (sid != null) {\n emitSessionEvent({ type: 'updated', sessionId: sid, sessionTitle: message.content })\n }\n return\n }\n\n // JETP-073: client(\"办公室\")级 LLM 起名增量事件。\n // 与 session_title 平行:内部不维护 client cache(rounds 已经按 cid 切片),\n // 只把事件 emit 给上层(如 yumiai-web WorkspaceCore)做 cid → title 累加。\n if (message.notification_type === 'client_title' && message.content) {\n const cid = (message as { client_id?: string }).client_id\n if (!cid) {\n // backend 永远应当带 cid;缺字段时 warn + skip,不破坏后续 message 流。\n console.warn('[client_title] missing client_id, skip', {\n interaction_id: message.interaction_id,\n content_preview: message.content?.slice?.(0, 32),\n })\n return\n }\n emitClientTitleEvent({\n type: 'client_title',\n sessionId: currentSessionIdRef.current ?? -1,\n clientId: cid,\n clientTitle: message.content,\n })\n return\n }\n\n const msgType = message.type || message.notification_type\n if (msgType === 'compression_started') {\n if (isLocalInteraction) setExecutionStatus('compressing')\n return\n }\n if (msgType === 'compression_completed') {\n if (isLocalInteraction) setExecutionStatus('running')\n return\n }\n\n if (message.type === 'finish' || message.type === 'connection_closing') {\n const iid = message.interaction_id || aggregatorState.currentInteractionId\n if (iid) finalizeRound(iid)\n if (isLocalInteraction) setExecutionStatus('completed')\n return\n }\n\n if (message.type === 'error') {\n if (isLocalInteraction) {\n setExecutionStatus('error')\n onError?.(new Error(message.content || i18nMessages['error.unknown']))\n }\n return\n }\n\n if (message.interaction_id && message.content_type) {\n if (isLocalInteraction && message.level === 0 && message.agent_instance_id\n && !bypassInstanceTrackingIdsRef.current.has(message.interaction_id)) {\n agentInstanceMapRef.current.set(currentAgentIdRef.current, message.agent_instance_id)\n }\n processMessage(message as SSEMessage)\n }\n\n // JETP-045 P5 (P2-T12):实时帧推进 turnCursor。\n // 历史路径在 handleRecoveryTurns / loadHistory / loadOlderPage 已经推进;\n // 这里覆盖 SSE/WS 实时推送 → 断线重连时只补 ``turn_index > cursor`` 的 turn,\n // 与 db-writer 单调粒度 (interaction_id, callee_instance_id) 三方对齐。\n if (\n message.interaction_id\n && typeof message.turn_index === 'number'\n && typeof message.callee_instance_id === 'number'\n ) {\n advanceTurnCursor(message.interaction_id, message.callee_instance_id, message.turn_index)\n }\n },\n [\n adapter,\n processMessage,\n onError,\n finalizeRound,\n aggregatorState.currentInteractionId,\n advanceTurnCursor,\n ],\n )\n\n // ── SSE connection (fallback transport) ──\n const { status: sseStatus, connect: sseConnect, disconnect: _sseDisconnect } = useSSE({\n adapter,\n onMessage: handleSSEMessage,\n onError,\n })\n\n // JETP-056 P2:fire-and-confirm POST 走统一 useAuthedFetch(替代手工 401 重试 + onAuthFailure)\n const facAuthedFetch = useAuthedFetch(adapter)\n\n // ── WS transport (primary when configured) ──\n // YWRF-DUP-002 修复:transport 决策(shouldUseWs)必须只取决于 adapter 能力 + 用户偏好,\n // 不能耦合 currentSessionId。否则「新会话首条消息」会撞 stale-closure 双投递:\n // 1. ChatWidget remount → currentSessionId=null → shouldUseWs=false 被 sendMessage 闭包锁住\n // 2. sendMessage 里 await ensureSession() 把 sid 建出来 → 触发重渲染 → WS hook 激活\n // 3. 但闭包里 shouldUseWs 仍 false → 走 else 调 sseConnect → useSSE 的 fetch reader 读 POST\n // 响应的 SSE 流;与此同时 WS 也在推同一份 chunks → 每条 chunk 进 handleSSEMessage 两次。\n // wsUrl / wsChannel.enabled 仍然用 currentSessionId 把关,避免 sid 未定时空连。\n const wsCapable = !!adapter.getWsUrl\n const wsUrl = useMemo(\n () => (wsCapable && currentSessionId != null) ? adapter.getWsUrl!(currentSessionId) : null,\n [adapter, currentSessionId, wsCapable],\n )\n // 不可仅依赖 adapter 引用:getToken 来自 localStorage 时,adapter 不变 token 也会变。\n // 每轮渲染从 adapter 取最新 Authorization,供 useSessionChannel 的 token 依赖触发重连。\n const authHeader = adapter.getAuthHeaders()['Authorization'] ?? ''\n const wsToken = authHeader.replace(/^Bearer\\s+/i, '') || null\n\n // JETP-072 AC-WIDGET-002/003: 只有 transport='ws' 且 adapter 暴露 getWsUrl\n // 时才真正走 WS。否则自动降级 SSE 并一次性 console.warn,避免 adapter 缺 getWsUrl\n // 时 wsChannel url 为 null 导致僵尸连接。\n const shouldUseWs = transportPref === 'ws' && wsCapable\n const wsFallbackWarnedRef = useRef(false)\n useEffect(() => {\n if (transportPref === 'ws' && !adapter.getWsUrl && !wsFallbackWarnedRef.current) {\n wsFallbackWarnedRef.current = true\n console.warn(\n '[JETP-072] transport: \"ws\" requested but adapter.getWsUrl is missing; '\n + 'falling back to SSE. Implement adapter.getWsUrl(sessionId) to enable WS.',\n )\n }\n }, [transportPref, adapter])\n\n const onDiscussionUpdateRef = useRef(onDiscussionUpdate)\n onDiscussionUpdateRef.current = onDiscussionUpdate\n\n const handleWsMessage = useCallback(\n (msg: SessionChannelMessage) => {\n\n // JETP-038: intercept discussion_update events before SSE transform\n if (msg.type === 'discussion_update' || (msg.data as Record<string, unknown>)?.type === 'discussion_update') {\n onDiscussionUpdateRef.current?.(msg.data as Record<string, unknown>)\n }\n\n if (adapter.transformSSEMessage) {\n const transformed = adapter.transformSSEMessage(msg.data as Record<string, unknown>)\n if (transformed) {\n for (const sseMsg of transformed) {\n handleSSEMessage(sseMsg as unknown as SSEMessage & { type?: string; session_id?: number; notification_type?: string })\n }\n }\n } else {\n const raw = msg.data as Record<string, unknown>\n const sseMsg = raw as unknown as SSEMessage & {\n type?: string\n session_id?: number\n notification_type?: string\n }\n // JETP-045 P7:channel_id 已撤回;旧后端兼容已在 adapter.transformSSEMessage 边界完成\n handleSSEMessage(sseMsg)\n }\n },\n [adapter, handleSSEMessage],\n )\n\n const handleRecoveryTurns = useCallback(\n (rawTurns: unknown[]) => {\n const turns = rawTurns as NotificationTurn[]\n if (!turns.length) return\n\n for (const t of turns) {\n const iid = t.interaction_id\n if (iid) localInteractionIdsRef.current.add(iid)\n const idx = t.turn_index\n const callee = (t as { callee_instance_id?: number; agent_instance_id?: number })\n .callee_instance_id ?? (t as { agent_instance_id?: number }).agent_instance_id\n if (iid && typeof idx === 'number' && typeof callee === 'number') {\n advanceTurnCursor(iid, callee, idx)\n }\n }\n\n const { rounds: recoveryRounds, todoEntries, specMetaMap: recoveryMeta, specLifecycleMap: recoveryLifecycle } = convertTurnsToRounds(\n turns,\n i18nMessages['history.noMessage'],\n i18nMessages['agent.defaultName'],\n )\n if (recoveryRounds.length > 0) {\n mergeRecoveryRounds(recoveryRounds)\n }\n if (todoEntries.size > 0) {\n loadTodoMap(todoEntries)\n }\n if (recoveryMeta.size > 0) {\n loadSpecMetaMap(recoveryMeta)\n }\n if (recoveryLifecycle.size > 0) {\n loadSpecLifecycleMap(recoveryLifecycle)\n }\n },\n [mergeRecoveryRounds, loadTodoMap, loadSpecMetaMap, loadSpecLifecycleMap, i18nMessages],\n )\n\n // Pool observation hook (declared early so the status event handler can be\n // passed into useSessionChannel). sessionId-guard is handled inside the hook.\n const { observation: poolObservation, handlePoolSnapshot } = usePoolObservation({\n adapter,\n sessionId: currentSessionId,\n })\n\n const handleStatusEvent = useCallback(\n (msg: SessionChannelMessage) => { handlePoolSnapshot(msg) },\n [handlePoolSnapshot],\n )\n\n const wsChannel = useSessionChannel({\n sessionId: currentSessionId,\n wsUrl,\n token: wsToken,\n transport: shouldUseWs ? 'ws' : 'sse',\n enabled: shouldUseWs && currentSessionId != null,\n turnCursorRef,\n onMessage: handleWsMessage,\n onStatusEvent: handleStatusEvent,\n onRecoveryTurns: handleRecoveryTurns,\n })\n\n const wsConnectedRef = useRef(false)\n wsConnectedRef.current = wsChannel.connected\n const ensureWsConnectedRef = useRef(wsChannel.ensureConnected)\n ensureWsConnectedRef.current = wsChannel.ensureConnected\n\n // Track WS connection failure: if WS doesn't connect within 8s, degrade\n // connectionStatus so the UI isn't stuck at \"连接中...\" forever.\n const [wsGaveUp, setWsGaveUp] = useState(false)\n useEffect(() => {\n if (!shouldUseWs || currentSessionId == null) { setWsGaveUp(false); return }\n if (wsChannel.connected) { setWsGaveUp(false); return }\n const timer = setTimeout(() => setWsGaveUp(true), 8000)\n return () => clearTimeout(timer)\n }, [shouldUseWs, currentSessionId, wsChannel.connected])\n\n const connectionStatus: ConnectionStatus = shouldUseWs\n ? (wsChannel.connected ? 'connected' : (wsGaveUp ? 'connected' : (currentSessionId != null ? 'connecting' : 'idle')))\n : sseStatus\n\n // ── Rounds (derived) ──\n const rounds = useMemo(() => getRoundsList(), [getRoundsList, aggregatorState])\n\n // ── Send message ──\n const sendMessage = useCallback(\n async (message: string, agentId: string = 'agent-680', _inlineRefs?: FileReference[], selectedSkills?: SelectedSkillRef[], overrideInstanceId?: number | null, clientId?: string, fileAttachments?: import('../types').FileAttachment[], modelOverride?: import('../types').ModelOverride | null) => {\n const interactionId = randomUUID()\n activeInteractionIdRef.current = interactionId\n localInteractionIdsRef.current.add(interactionId)\n sessionTitleFetchedRef.current = false\n\n const hasBypass = overrideInstanceId !== undefined\n if (hasBypass) {\n bypassInstanceTrackingIdsRef.current.add(interactionId)\n } else {\n currentAgentIdRef.current = agentId\n }\n\n startNewRound(interactionId, message, clientId)\n setExecutionStatus('running')\n\n // JETP-058 fix:同样改读 ref —— 上游 ChatWidget.cidGuardedControllerSendMessage\n // 已经走了一次 ensureSession() 把 sid 落 ref 上;如果这里继续读 state,\n // 同步上下文里 React 还没 flush,会再触发一次 createSession。\n let sessionId = currentSessionIdRef.current ?? currentSessionId\n if (sessionId == null && adapter.buildStreamBody) {\n try {\n sessionId = await ensureSession()\n } catch (err) {\n setExecutionStatus('error')\n return\n }\n }\n\n const resolvedInstanceId = hasBypass\n ? (overrideInstanceId ?? undefined)\n : agentInstanceMapRef.current.get(agentId)\n\n // JETP-058 v2-only:到达 controller.sendMessage 时 clientId 必须是 v2 ``c_<22>``;\n // 任何 ``main`` / ``file:*`` / ``sel:*`` / 空串都立刻抛错(避免污染 routing/turn 表)。\n // 后端 main.py 的 AgentCallEvent 也会再做一遍 422 兜底;前端这里早抛省一次往返。\n const trimmedClientId = clientId?.trim() ?? ''\n if (!/^c_[A-Za-z0-9]{22}$/.test(trimmedClientId)) {\n setExecutionStatus('error')\n throw new InvalidClientIdError(\n `sendMessage requires a v2 client_id (^c_[A-Za-z0-9]{22}$); got ${JSON.stringify(clientId ?? null)}.`,\n /^(main|file:|sel:).*/.test(trimmedClientId) ? 'legacy_format' : 'missing',\n sessionId ?? null,\n )\n }\n\n // JETP-045 P7:channelId 已全栈撤回;buildStreamBody 仅接受 clientId(无兼容期形参)\n const streamBody = adapter.buildStreamBody\n ? adapter.buildStreamBody({\n message,\n agentId,\n sessionId,\n interactionId,\n agentInstanceId: resolvedInstanceId,\n callerInstanceId: callerInstanceIdRef.current ?? undefined,\n selectedSkills,\n activeSpecIds: activeSpecIdsRef?.current ?? undefined,\n clientId,\n // JETP-045 Phase 6 (P6-T06) / AC-CONN-003:connection_id 上行\n connectionId,\n fileAttachments,\n // 前端\"本次调用使用的模型\"覆盖项;缺省则不写入 body,行为与历史一致\n modelOverride: modelOverride ?? null,\n })\n : {\n message,\n agent_id: agentId,\n agent_instance_id: resolvedInstanceId,\n session_id: sessionId,\n interaction_id: interactionId,\n client_id: clientId,\n connection_id: connectionId,\n }\n\n if (shouldUseWs) {\n if (!wsConnectedRef.current) {\n try { await ensureWsConnectedRef.current() } catch { /* proceed anyway — POST may still succeed */ }\n }\n // JETP-056 P2:useAuthedFetch 已统一注入 Authorization + extraHeaders + 401 refresh + onAuthFailure;\n // controller 只需要补 fire-and-confirm 协议 header(X-Transport-Mode)即可。\n try {\n const res = await facAuthedFetch(adapter.getStreamUrl(), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Transport-Mode': 'fire-and-confirm',\n },\n body: JSON.stringify(streamBody),\n })\n if (res.ok) {\n try {\n const ack = await res.json() as { interaction_id?: string }\n if (ack.interaction_id && ack.interaction_id !== interactionId) {\n serverToClientIdMapRef.current.set(ack.interaction_id, interactionId)\n }\n } catch { /* non-JSON ack, mapping happens on first WS msg */ }\n } else {\n console.error(`[Controller] Fire-and-confirm POST failed (${res.status})`)\n onError?.(new Error(`Send failed: HTTP ${res.status}`))\n }\n } catch (err) {\n console.error('[Controller] Fire-and-confirm POST error', err)\n onError?.(err instanceof Error ? err : new Error(String(err)))\n }\n } else {\n sseConnect(adapter.getStreamUrl(), streamBody)\n }\n },\n [adapter, currentSessionId, startNewRound, sseConnect, shouldUseWs, onError, ensureSession, connectionId, activeSpecIdsRef, facAuthedFetch],\n )\n\n // ── Load session history ──\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 if (!reuseAgentInstance) return\n // JETP-058:v2-only — clientIds 还没派生出来时不发请求;\n // 等 ChatWidget 通过 useSessionClients/allocator 拿到 c_<22> 再触发 effect 重拉。\n if (effectiveHistoryClientIds.length === 0) return\n const loadKey = `${numericId}|${effectiveHistoryClientIds.join(',')}|${historyIncludeInFlight ? 1 : 0}`\n if (historyLoadedRef.current === loadKey) return\n historyLoadedRef.current = loadKey\n\n const loadHistory = async () => {\n try {\n // JETP-055 P4: 历史回放只走 v2 paginated turns + session detail。\n // convertTurnsToRounds 已按 interaction_id 分组并保留\n // level / agent_instance_id / parent_call_batch_id, 完整还原\n // client/turn 骨架, 不再需要老 v1 channels 接口。\n // JETP-057:clientIds 必传 + include_in_flight=true 透传,\n // 一次拉到主区+所有浮窗历史并保留 in-flight 子 agent 卡。\n console.debug('[Ctrl loadHistory] START', {\n sid: numericId,\n pageSize: 5,\n clientIds: effectiveHistoryClientIds,\n includeInFlight: historyIncludeInFlight,\n })\n const [historyRaw, detail] = await Promise.all([\n adapter.getSessionHistory(numericId, {\n pageSize: 5,\n clientIds: effectiveHistoryClientIds,\n includeInFlight: historyIncludeInFlight,\n }),\n adapter.getSessionDetail(numericId).catch(() => null),\n ])\n console.debug('[Ctrl loadHistory] adapter returned', {\n isArray: Array.isArray(historyRaw),\n rawTurnCount: Array.isArray(historyRaw)\n ? historyRaw.length\n : (historyRaw as PaginatedHistoryResponse)?.turns?.length,\n hasMore: Array.isArray(historyRaw) ? false : (historyRaw as PaginatedHistoryResponse)?.has_more,\n nextCursor: Array.isArray(historyRaw) ? null : (historyRaw as PaginatedHistoryResponse)?.next_cursor,\n })\n if (detail?.session_title) {\n setSessionTitle(detail.session_title)\n sessionTitleFetchedRef.current = true\n emitSessionEvent({ type: 'updated', sessionId: numericId, sessionTitle: detail.session_title })\n }\n\n const historyResult: PaginatedHistoryResponse = Array.isArray(historyRaw)\n ? { turns: historyRaw, has_more: false, next_cursor: null }\n : historyRaw as PaginatedHistoryResponse\n\n const turns = historyResult.turns\n setHasMore(historyResult.has_more ?? false)\n setNextCursor(historyResult.next_cursor ?? null)\n\n if (!turns || turns.length === 0) {\n console.debug('[Ctrl loadHistory] empty turns → return')\n return\n }\n // 全部 turn 的 level / callee / sub_type 分布——用于确认子 agent turn 是否拉回\n const byLevel = new Map<string | number, number>()\n const byCallee = new Map<string | number, number>()\n const bySubType = new Map<string | number, number>()\n const byParentBatch = new Map<string | number, number>()\n for (const t of turns) {\n const lv = t.level ?? '(null)'\n byLevel.set(lv, (byLevel.get(lv) ?? 0) + 1)\n const c = (t as { callee_instance_id?: number }).callee_instance_id\n ?? (t as { agent_instance_id?: number }).agent_instance_id ?? '(none)'\n byCallee.set(c, (byCallee.get(c) ?? 0) + 1)\n const st = (t as { sub_type?: string }).sub_type ?? '(none)'\n bySubType.set(st, (bySubType.get(st) ?? 0) + 1)\n const pb = (t as { parent_call_batch_id?: string | number }).parent_call_batch_id ?? '(none)'\n byParentBatch.set(pb, (byParentBatch.get(pb) ?? 0) + 1)\n }\n console.debug('[Ctrl loadHistory] turns distribution', {\n totalTurns: turns.length,\n byLevel: Object.fromEntries(byLevel),\n byCallee: Object.fromEntries(byCallee),\n bySubType: Object.fromEntries(bySubType),\n byParentBatch: Object.fromEntries(byParentBatch),\n })\n console.debug('[Ctrl loadHistory] turns sample (first 5)', turns.slice(0, 5).map(t => ({\n interaction_id: t.interaction_id,\n client_id: (t as { client_id?: string }).client_id,\n turn_index: t.turn_index,\n callee: (t as { callee_instance_id?: number }).callee_instance_id ?? (t as { agent_instance_id?: number }).agent_instance_id,\n parent_call_batch_id: (t as { parent_call_batch_id?: string | number }).parent_call_batch_id,\n role: (t as { role?: string }).role,\n sub_type: (t as { sub_type?: string }).sub_type,\n level: t.level,\n agent_id: (t as { agent_id?: string }).agent_id,\n })))\n // 任意 level>0 的子 agent turn 完整 dump\n const subTurns = turns.filter(t => (t.level ?? 0) > 0)\n if (subTurns.length > 0) {\n console.debug('[Ctrl loadHistory] sub-agent turns', subTurns.slice(0, 10).map(t => ({\n level: t.level,\n callee: (t as { callee_instance_id?: number }).callee_instance_id,\n parent_call_batch_id: (t as { parent_call_batch_id?: string | number }).parent_call_batch_id,\n sub_type: (t as { sub_type?: string }).sub_type,\n turn_index: t.turn_index,\n agent_id: (t as { agent_id?: string }).agent_id,\n })))\n } else {\n console.debug('[Ctrl loadHistory] NO sub-agent turns in returned history')\n }\n\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\n for (const t of turns) {\n const iid = t.interaction_id\n if (iid) localInteractionIdsRef.current.add(iid)\n const idx = t.turn_index\n const callee = (t as { callee_instance_id?: number; agent_instance_id?: number })\n .callee_instance_id ?? (t as { agent_instance_id?: number }).agent_instance_id\n if (iid && typeof idx === 'number' && typeof callee === 'number') {\n advanceTurnCursor(iid, callee, idx)\n }\n }\n\n const { rounds: historyRounds, todoEntries, specMetaMap: historyMeta, specLifecycleMap: historyLifecycle } = convertTurnsToRounds(turns, i18nMessages['history.noMessage'], i18nMessages['agent.defaultName'])\n console.debug('[Ctrl loadHistory] convertTurnsToRounds produced', {\n roundCount: historyRounds.length,\n rounds: historyRounds.map(r => {\n const msgs = (r as unknown as { messages?: Array<Record<string, unknown>> }).messages ?? []\n const lvCount = new Map<number, number>()\n for (const m of msgs) {\n const lv = (m.level as number) ?? 0\n lvCount.set(lv, (lvCount.get(lv) ?? 0) + 1)\n }\n return {\n interactionId: (r as { interactionId?: string }).interactionId,\n clientId: (r as { clientId?: string | null }).clientId,\n messageCount: msgs.length,\n messageByLevel: Object.fromEntries(lvCount),\n roundKeys: Object.keys(r as unknown as Record<string, unknown>),\n messageBrief: msgs.map(m => ({\n lv: m.level,\n aiid: m.agentInstanceId,\n cb: m.callBatchId,\n pcb: m.parentCallBatchId,\n ntype: m.notificationType,\n ctype: m.contentType,\n tool: m.toolName,\n preview: Array.isArray(m.contentChunks)\n ? (m.contentChunks as string[]).join('').slice(0, 50)\n : undefined,\n })),\n }\n }),\n })\n if (historyRounds.length > 0) {\n loadRounds(historyRounds)\n setExecutionStatus('completed')\n }\n if (todoEntries.size > 0) {\n loadTodoMap(todoEntries)\n }\n if (historyMeta.size > 0) {\n loadSpecMetaMap(historyMeta)\n }\n if (historyLifecycle.size > 0) {\n loadSpecLifecycleMap(historyLifecycle)\n }\n } catch (err) {\n console.warn('[Controller] Failed to load session history:', err)\n }\n }\n loadHistory()\n // JETP-057:effectiveHistoryClientIds / historyIncludeInFlight 也参与,\n // 当 ChatWidget 派生出更全的 clientIds(含浮窗)时自动重拉一次完整历史。\n }, [propSessionId, reuseAgentInstance, loadRounds, loadTodoMap, adapter, effectiveHistoryClientIds, historyIncludeInFlight])\n\n // ── JETP-037: load older page on scroll ──\n const loadOlderPage = useCallback(async () => {\n if (!currentSessionId || !hasMore || loadingMore || !nextCursor) return\n // JETP-058:v2-only — clientIds 为空时不调 adapter(adapter 会 fail-fast 抛 RangeError)。\n if (effectiveHistoryClientIds.length === 0) return\n\n setLoadingMore(true)\n try {\n // JETP-057:分页加载也带同一组 clientIds + include_in_flight,保持一致。\n const raw = await adapter.getSessionHistory(currentSessionId, {\n pageSize: 5,\n beforeCursor: nextCursor,\n clientIds: effectiveHistoryClientIds,\n includeInFlight: historyIncludeInFlight,\n })\n const result: PaginatedHistoryResponse = Array.isArray(raw)\n ? { turns: raw, has_more: false, next_cursor: null }\n : raw as PaginatedHistoryResponse\n\n setHasMore(result.has_more ?? false)\n setNextCursor(result.next_cursor ?? null)\n\n if (result.turns.length > 0) {\n for (const t of result.turns) {\n const iid = t.interaction_id\n if (iid) localInteractionIdsRef.current.add(iid)\n const idx = t.turn_index\n const callee = (t as { callee_instance_id?: number; agent_instance_id?: number })\n .callee_instance_id ?? (t as { agent_instance_id?: number }).agent_instance_id\n if (iid && typeof idx === 'number' && typeof callee === 'number') {\n advanceTurnCursor(iid, callee, idx)\n }\n }\n\n const { rounds: olderRounds, todoEntries, specMetaMap: olderMeta, specLifecycleMap: olderLifecycle } = convertTurnsToRounds(\n result.turns,\n i18nMessages['history.noMessage'],\n i18nMessages['agent.defaultName'],\n )\n if (olderRounds.length > 0) {\n prependRounds(olderRounds)\n }\n if (todoEntries.size > 0) {\n loadTodoMap(todoEntries)\n }\n if (olderMeta.size > 0) {\n loadSpecMetaMap(olderMeta)\n }\n if (olderLifecycle.size > 0) {\n loadSpecLifecycleMap(olderLifecycle)\n }\n }\n } catch (err) {\n console.warn('[Controller] Failed to load older page:', err)\n } finally {\n setLoadingMore(false)\n }\n }, [currentSessionId, hasMore, loadingMore, nextCursor, adapter, prependRounds, loadTodoMap, loadSpecLifecycleMap, i18nMessages, effectiveHistoryClientIds, historyIncludeInFlight])\n\n // ── Clear multi-tab isolation maps on session change ──\n // Only reset when switching between two real sessions (not null → first).\n //\n // JETP-052 BUG-3 修复:除了 isolation maps,还必须把所有 session-scoped 的内部状态\n // 全部归零,否则切换 session 后旧 session 的 round/message/agentInstanceMap/turnCursor\n // 会和新 session 的实时帧混在一起 → 子 agent 消息错位、丢失甚至 round 翻倍。\n //\n // demo 通过 ``key={...activeSessionId...}`` 强制 ChatWidget remount,不会触发本路径;\n // 但 SDK 嵌入方可能复用同一个 controller 实例并改 propSessionId,必须靠这里兜底。\n const prevSessionIdRef = useRef(currentSessionId)\n useEffect(() => {\n if (currentSessionId !== prevSessionIdRef.current && prevSessionIdRef.current != null) {\n serverToClientIdMapRef.current.clear()\n localInteractionIdsRef.current = new Set()\n bypassInstanceTrackingIdsRef.current = new Set()\n agentInstanceMapRef.current.clear()\n callerInstanceIdRef.current = null\n turnCursorRef.current = new Map()\n activeInteractionIdRef.current = null\n historyLoadedRef.current = null\n sessionTitleFetchedRef.current = false\n setSessionTitle('')\n setHasMore(false)\n setNextCursor(null)\n setLoadingMore(false)\n setExecutionStatus('idle')\n aggregatorClear()\n }\n prevSessionIdRef.current = currentSessionId\n }, [currentSessionId, aggregatorClear])\n\n // ── Sync SSE connection→execution status (SSE mode only) ──\n // In WS mode, the WS stays open; execution lifecycle is driven by message types (finish/error).\n useEffect(() => {\n if (shouldUseWs) return\n if (sseStatus === 'connected') setExecutionStatus('running')\n else if (sseStatus === 'disconnected') setExecutionStatus('completed')\n else if (sseStatus === 'error') setExecutionStatus('error')\n }, [sseStatus, shouldUseWs])\n\n // ── Fetch session title when execution completes ──\n useEffect(() => {\n if (executionStatus === 'completed' && currentSessionId && !sessionTitle && !sessionTitleFetchedRef.current) {\n const timer = setTimeout(() => {\n adapter\n .getSessionDetail(currentSessionId)\n .then(d => {\n if (d.session_title) {\n setSessionTitle(d.session_title)\n sessionTitleFetchedRef.current = true\n emitSessionEvent({ type: 'updated', sessionId: currentSessionId, sessionTitle: d.session_title })\n }\n })\n .catch(() => {})\n }, 500)\n return () => clearTimeout(timer)\n }\n }, [executionStatus, currentSessionId, sessionTitle, adapter])\n\n // ── Event: onStatusChange ──\n useEffect(() => {\n onStatusChange?.(executionStatus)\n }, [executionStatus, onStatusChange])\n\n // ── Event: onConnectionChange ──\n useEffect(() => {\n onConnectionChange?.(connectionStatus === 'connected')\n }, [connectionStatus, onConnectionChange])\n\n // ── Event: onRoundChange ──\n const prevRoundsLenRef = useRef(0)\n useEffect(() => {\n if (rounds.length !== prevRoundsLenRef.current) {\n const isNewRound = rounds.length > prevRoundsLenRef.current\n prevRoundsLenRef.current = rounds.length\n onRoundChange?.(rounds)\n if (isNewRound && rounds.length > 0) {\n const latest = rounds[rounds.length - 1]\n onRoundStart?.(latest.interactionId, latest.userMessage || '')\n }\n }\n }, [rounds, onRoundChange, onRoundStart])\n\n // ── Event: onMessageAppended ──\n const prevMsgCountRef = useRef(0)\n useEffect(() => {\n const totalMessages = rounds.reduce((sum, r) => sum + r.messages.length, 0)\n if (totalMessages > prevMsgCountRef.current && prevMsgCountRef.current > 0) {\n const lastRound = rounds[rounds.length - 1]\n if (lastRound && lastRound.messages.length > 0) {\n const lastMsg = lastRound.messages[lastRound.messages.length - 1]\n onMessageAppended?.(lastMsg, lastRound)\n }\n }\n prevMsgCountRef.current = totalMessages\n }, [rounds, onMessageAppended])\n\n // ── Event: onRoundEnd ──\n const prevStatusRef = useRef<ExecutionStatus>('idle')\n useEffect(() => {\n const wasRunning = prevStatusRef.current === 'running' || prevStatusRef.current === 'compressing'\n const isStopped = executionStatus === 'idle' || executionStatus === 'error'\n if (wasRunning && isStopped && rounds.length > 0) {\n const latest = rounds[rounds.length - 1]\n onRoundEnd?.(latest.interactionId)\n }\n prevStatusRef.current = executionStatus\n }, [executionStatus, rounds, onRoundEnd])\n\n // ── Widget API ──\n const getCurrentRound = useCallback((): Round | null => {\n if (rounds.length === 0) return null\n return rounds[rounds.length - 1]\n }, [rounds])\n\n const scrollToBottom = useCallback(() => {\n /* no-op in headless controller; UI layer handles scrolling */\n }, [])\n\n const getStatus = useCallback((): ExecutionStatus => executionStatus, [executionStatus])\n\n /**\n * 协作式停止当前 session 的 Agent —— 与 `useAgentControl().stop` 走完全相同的\n * `adapter.stopAgent` 路径(HTTP `POST /api/session/stop`),但通过\n * `widgetAPI.stopAgent` 暴露给 DefaultComposer / 宿主 UI 直接调用,无需再\n * 手动 wire `useAgentControl`。\n *\n * 仅在「currentSessionId 存在 + adapter 实现了 stopAgent」时才组装函数;否则\n * 让 widgetAPI.stopAgent === undefined,让 UI 据此降级(DefaultComposer 走\n * 旧 loading disabled 行为,避免给用户\"按了没反应\"的错觉)。\n *\n * 错误处理:在这里就 catch 并 console.warn,不向上抛 —— 让按钮 UI 不必写\n * try/catch;如宿主需要业务错误回调,自行 `try { await api.stopAgent() }` 即可。\n */\n const stopAgent = useMemo<(() => Promise<void>) | undefined>(() => {\n const sid = typeof currentSessionId === 'string'\n ? Number(currentSessionId)\n : currentSessionId\n if (sid == null || Number.isNaN(sid)) return undefined\n if (typeof adapter.stopAgent !== 'function') return undefined\n return async () => {\n try {\n await adapter.stopAgent!({ sessionId: sid })\n } catch (err) {\n console.warn('[chat-widget] stopAgent failed', err)\n }\n }\n }, [adapter, currentSessionId])\n\n const widgetAPI = useMemo<ChatWidgetAPI>(\n () => ({\n sendMessage,\n getCurrentRound,\n getAllRounds: getRoundsList,\n scrollToBottom,\n getStatus,\n setReferenceInsertHandler: () => {},\n stopAgent,\n }),\n [sendMessage, getCurrentRound, getRoundsList, scrollToBottom, getStatus, stopAgent],\n )\n\n // Derive primaryAgentBusy from pool observation: look up the level-0 agent\n // instance tracked by agentInstanceMapRef for the current agent ID.\n const primaryAgentBusy = useMemo(() => {\n const primaryInstanceId = agentInstanceMapRef.current.get(currentAgentIdRef.current)\n if (primaryInstanceId == null) return false\n const entry = poolObservation.instanceStates.get(primaryInstanceId)\n return entry?.state === 'RUNNING'\n }, [poolObservation])\n\n return {\n executionStatus,\n connectionStatus,\n activeTransport: (shouldUseWs && wsChannel.connected) ? 'ws' as const : 'sse' as const,\n rounds,\n localInteractionIds: localInteractionIdsRef.current,\n currentSessionId,\n sessionTitle,\n todoMap,\n specMetaMap,\n specLifecycleMap,\n sendMessage,\n widgetAPI,\n agentStates: wsChannel.agentStates,\n sendControlFrame: wsChannel.sendControlFrame,\n sessionBusy: poolObservation.sessionBusy,\n primaryAgentBusy,\n poolObservation,\n wsConnected: wsChannel.connected,\n hasMore,\n loadingMore,\n loadOlderPage,\n ensureSession,\n }\n}\n","/**\n * 消息聚合 Hook\n * \n * 实现高性能消息聚合:\n * - Map 索引 O(1) 查找\n * - 字符串数组延迟拼接\n * - requestAnimationFrame 批量更新\n * - 延迟 JSON 解析\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { \n SSEMessage, \n AggregatedMessage, \n Round, \n TaskPlan,\n TodoData,\n Artifact,\n HITLRequest,\n PlanItem,\n SpecLifecycleEntry,\n} from '../types'\nimport { isTodoNotificationContent } from '../types'\nimport { isDevMode } from '../utils/env.js'\nimport { randomUUID } from '../utils/randomUUID'\nimport { registerMemSource, unregisterMemSource } from '../utils/memTelemetry'\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\n/**\n * JETP-083 WS3.7.5 + JETP-033 WS1.1 — parse `gen_ui_meta` payload.\n *\n * Backend currently emits three shapes on the same channel:\n * 1. **identity** (legacy, JETP-034): `{resource_id, git_path}`\n * 2. **cancelled** (JETP-083, JSON-Patch): `{op:\"replace\",\n * path:\"/_meta/cancelled\", value:{reason}}`\n * 3. **error** (JETP-033 WS1.1, flat): `{error:\"patch_rounds_exceeded\",\n * payload:{...}}` — kept tolerant of a future JSON-Patch form\n * `{op:\"replace\", path:\"/_meta/error\", value:{error_code, payload}}`.\n *\n * Returns `null` for malformed / unknown payloads — caller silently drops to\n * keep parity with the existing tolerant convention (see L580 below).\n */\nexport type SpecMetaParsed =\n | { kind: 'identity'; resourceId: string; gitPath: string }\n | { kind: 'lifecycle'; entry: SpecLifecycleEntry }\n\nexport function parseGenUIMetaContent(raw: unknown): SpecMetaParsed | null {\n let parsed: any\n try {\n const str = typeof raw === 'string' ? raw : JSON.stringify(raw)\n parsed = JSON.parse(str)\n } catch {\n return null\n }\n if (!parsed || typeof parsed !== 'object') return null\n\n if (parsed.op === 'replace' && typeof parsed.path === 'string') {\n if (parsed.path === '/_meta/cancelled') {\n const v = (parsed.value ?? {}) as { reason?: unknown }\n return {\n kind: 'lifecycle',\n entry: { state: 'cancelled', reason: typeof v.reason === 'string' ? v.reason : '' },\n }\n }\n if (parsed.path === '/_meta/error') {\n const v = (parsed.value ?? {}) as { error_code?: unknown; code?: unknown; payload?: unknown }\n const errorCode =\n typeof v.error_code === 'string'\n ? v.error_code\n : typeof v.code === 'string'\n ? v.code\n : 'unknown'\n return {\n kind: 'lifecycle',\n entry: {\n state: 'error',\n errorCode,\n payload: v.payload && typeof v.payload === 'object' ? (v.payload as Record<string, unknown>) : undefined,\n },\n }\n }\n return null\n }\n\n if (typeof parsed.error === 'string') {\n return {\n kind: 'lifecycle',\n entry: {\n state: 'error',\n errorCode: parsed.error,\n payload: parsed.payload && typeof parsed.payload === 'object' ? parsed.payload : undefined,\n },\n }\n }\n\n if (typeof parsed.resource_id === 'string') {\n return {\n kind: 'identity',\n resourceId: parsed.resource_id,\n gitPath: typeof parsed.git_path === 'string' ? parsed.git_path : '',\n }\n }\n\n return null\n}\n\ninterface MessageAggregatorState {\n rounds: Map<string, Round>\n currentInteractionId: string | null\n /** 每轮次已收到 agent_end 的 agent_instance_id,与 notification_turns 的 turn_type=agent_end 对齐 */\n endedAgentInstanceIdsByRound: Map<string, Set<number>>\n}\n\ninterface UseMessageAggregatorReturn {\n state: MessageAggregatorState\n todoMap: Map<string, TodoData>\n specMetaMap: Map<string, { resourceId: string; gitPath: string }>\n /** JETP-083 WS3.7.5 — terminal lifecycle markers (cancelled / error) keyed by spec_id. */\n specLifecycleMap: Map<string, SpecLifecycleEntry>\n processMessage: (message: SSEMessage) => void\n getRoundsList: () => Round[]\n getCurrentRound: () => Round | null\n startNewRound: (interactionId: string, userMessage: string, clientId?: string) => void\n loadRounds: (rounds: Round[]) => void\n prependRounds: (olderRounds: Round[]) => void\n mergeRecoveryRounds: (rounds: Round[]) => void\n finalizeRound: (interactionId: string) => void\n loadTodoMap: (entries: Map<string, TodoData>) => void\n loadSpecMetaMap: (entries: Map<string, { resourceId: string; gitPath: string }>) => void\n loadSpecLifecycleMap: (entries: Map<string, SpecLifecycleEntry>) => void\n clear: () => void\n /**\n * JETP-045 Phase 6 (P6-T07) — 设置当前 tab 的物理连接 ID。\n * Aggregator 用 ``msg.connection_id_from === myConnectionId`` 识别 echo (AC-CONN-006/007)。\n * Controller 在 mount 期间用 ``useConnectionId()`` 派生后调用一次即可;多次调用幂等。\n * 不传或传 undefined ⇒ 关闭 echo 检测,行为退化到 Phase 1-5 (AC-CONN-008)。\n */\n setMyConnectionId: (id: string | undefined) => 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 endedAgentInstanceIdsByRound: new Map(),\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 const [specMetaMap, setSpecMetaMap] = useState<Map<string, { resourceId: string; gitPath: string }>>(new Map())\n const specMetaMapRef = useRef<Map<string, { resourceId: string; gitPath: string }>>(new Map())\n // JETP-083 WS3.7.5 — terminal spec lifecycle (cancelled / error). Separate from\n // specMetaMap because (a) the identity payload may also exist on a cancelled\n // spec — we shouldn't overwrite share-button data; (b) callers typically\n // visualize the two independently (one drives card header, the other drives\n // a state-overlay).\n const [specLifecycleMap, setSpecLifecycleMap] = useState<Map<string, SpecLifecycleEntry>>(new Map())\n const specLifecycleMapRef = useRef<Map<string, SpecLifecycleEntry>>(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 // YWRF-DUP-001:原 processedChunksRef chunkId 计数器从未命中(contentChunks.length\n // 单调递增 → chunkId 每次都是新键),是死代码。已移除以避免误导排查;\n // recovery vs live 真重复改由 mergeRecoveryRounds 同 schema id 去重承担。\n // 追踪每个 call_batch_id 属于哪个 interaction_id(轮次)\n // 用于处理 JetAgents Redis 缓冲消息:将消息路由到正确的轮次\n const callBatchToRoundRef = useRef<Map<string, string>>(new Map())\n // 每轮次已收到 agent_end 的 agent_instance_id(与 notification_turns 的 agent_start/agent_end 对齐)\n const endedAgentInstanceIdsByRoundRef = useRef<Map<string, Set<number>>>(new Map())\n // JETP-045 Phase 6 (P6-T07):本 tab 的 connection_id;用于 echo 识别。\n // ref 存储以便 flushUpdates 在 setState 之外读取最新值;外部通过 setMyConnectionId 设置。\n const myConnectionIdRef = useRef<string | undefined>(undefined)\n const setMyConnectionId = useCallback((id: string | undefined) => {\n myConnectionIdRef.current = id && id.trim() ? id.trim() : undefined\n }, [])\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 || 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 || 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 // JETP-BUG: 必须在任何 return 路径之前重置 rafId,否则一旦此回调抛异常或\n // 在空队列时提前返回,rafId 将永远保持非 null,后续 processMessage 不再\n // 调度新的 RAF,导致渲染永久停滞(直到 clear() 被调用)。\n rafId.current = null\n\n if (pendingUpdates.current.length === 0) return\n\n const updates = [...pendingUpdates.current]\n pendingUpdates.current = []\n\n try {\n\n // === 在 setState 之外处理数据(避免 React 重复调用导致的问题) ===\n let latestInteractionId: string | null = null\n let todoMapChanged = false\n let specMetaChanged = false\n let specLifecycleChanged = 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-033: 过滤 a2ui 工具通知 ==========\n // a2ui 是 GenUI 准备性工具,其结果返回给模型而非用户,不应显示为工具卡片\n if (msg.tool_name === 'a2ui' && ['mcp_generating', 'mcp_start', 'mcp_result', 'mcp_end'].includes(msg.notification_type ?? '')) {\n continue\n }\n // ========== 结束:过滤 a2ui ==========\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 //\n // YWRF-001 J5 / fs11 防御性二次过滤:\n // call_batch_id 是 backend 全局自增 ID,**不该**跨 cid 复用,但当 backend\n // bug(如 agent_instance 复用 + race / Redis 重放)时同一 batch_id 可能\n // 出现在两个不同的 (interaction_id, client_id) 上。如果 ref 仅按 batch_id\n // 索引,就会把第二个 cid 的消息错路由到第一个 cid 的 round 上。\n // 修复:key 拼上 cid(缺失时退化为 ''),让两个 cid 的同 batch_id 自然分桶。\n const incomingClientId = msg.client_id\n const batchKey = `${call_batch_id}|${incomingClientId ?? ''}`\n const existingRoundForBatch = callBatchToRoundRef.current.get(batchKey)\n if (existingRoundForBatch && existingRoundForBatch !== interaction_id) {\n // 这个 (call_batch_id, cid) 已经绑定到其他轮次,将消息路由到那个轮次\n interaction_id = existingRoundForBatch\n } else if (!existingRoundForBatch) {\n // 首次见到这个 (call_batch_id, cid),绑定到当前轮次\n callBatchToRoundRef.current.set(batchKey, interaction_id)\n }\n // ========== 结束:Redis 缓冲消息路由 ==========\n\n // ========== agent_end:与 notification_turns 的 agent start/stop 对齐 ==========\n // 后端在子 Agent 结束时发送 agent_end,据此判断子 Agent 卡片应显示「已完成」而非推断\n if (msg.notification_type === 'agent_end') {\n const iid = interaction_id\n const aid = msg.agent_instance_id\n if (iid != null && aid != null) {\n const prev = endedAgentInstanceIdsByRoundRef.current\n const set = new Set(prev.get(iid) || [])\n set.add(aid)\n endedAgentInstanceIdsByRoundRef.current = new Map(prev).set(iid, set)\n }\n latestInteractionId = interaction_id\n continue\n }\n // ========== 结束:agent_end ==========\n\n // 获取或创建轮次\n // JETP-045 P7:channel_id 已全栈撤回;旧后端兼容已在 adapter 边界折叠到 client_id\n //\n // YWRF-001 J5 / fs11 防御性二次过滤:\n // roundIndexRef 默认按 interaction_id 索引(与后端 event_source_id 对齐,\n // 理论上唯一)。但当 backend bug(agent_instance 复用 / iid 池化)让两个\n // cid 共享 interaction_id 时,原实现会让两个对话流的 message 全部塞进\n // 同一个 round,UI 上 cid A 的浮窗看见 cid B 的 think / 工具卡。\n //\n // 修复:lookup 命中后校验 ``round.clientId === incomingClientId``,\n // 不一致 → 派生 cid-keyed round(key = ``${iid}|${cid}``),把第二个\n // cid 的消息隔离到独立的 round。round.interactionId 保留**原始** iid\n // 供 finalizeRound / callBatchToRoundRef 反查;只是 ref key 改了。\n let roundKey = interaction_id\n let round = roundIndexRef.current.get(roundKey)\n if (round && incomingClientId && round.clientId && round.clientId !== incomingClientId) {\n // cid 不一致 → 用 cid-keyed key 重新 lookup / create\n roundKey = `${interaction_id}|${incomingClientId}`\n round = roundIndexRef.current.get(roundKey)\n // 同步把上面 batchKey 的绑定也改到 cid-keyed roundKey 上(一旦本批次的\n // 后续消息复用 batch lookup,应该指向新派生的 round 而不是原来的)\n if (existingRoundForBatch === interaction_id) {\n callBatchToRoundRef.current.set(batchKey, roundKey)\n }\n }\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 clientId: incomingClientId,\n }\n roundIndexRef.current.set(roundKey, round)\n } else if (incomingClientId && !round.clientId) {\n round.clientId = incomingClientId\n }\n latestInteractionId = roundKey\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 const isGenUIMessage = content_type === 'gen_ui_card' || content_type === 'gen_ui_page'\n // JETP-045 P4 (P2-T05/T07) + JETP-058 修复:\n // 权威分段键是后端的 ``turn_index``(``BasePusher._assign_turn_index`` 在 fan-out 前\n // 分配;同 (iid, callee, sub_type, stream_uuid) 的 chunk 共享同一 index,亚型/流切换 → 新 index)。\n // 这与 db_pipeline 的 turn 聚合粒度严格对齐,**两个不同 turn_index 的内容必须落在不同 message**,\n // 否则就会出现\"派 agent 前后两段主 agent text 合并到同一气泡\"的 Bug。\n //\n // messageKey 选择策略:\n // 1. MCP / GenUI:保留原 key(按 tool_call_id / spec_id 跨 turn 聚合状态卡片);\n // 2. 其它内容(text / think / plan / artifact / ...):以 turn_index 为主键;\n // 3. turn_index 缺失(旧后端 / 罕见 race)→ 退回 stream_uuid → (agent, batch, content_type)。\n const streamUuid = msg.stream_uuid\n const turnIdx: number | undefined = typeof msg.turn_index === 'number' ? msg.turn_index : undefined\n const usingTurnIndex = !isMcpMessage && !isGenUIMessage && typeof turnIdx === 'number'\n const usingStreamUuid = !isMcpMessage && !isGenUIMessage && !usingTurnIndex && !!streamUuid\n let messageKey: string\n if (isMcpMessage) {\n messageKey = `${interaction_id}-${agent_instance_id}-mcp-${msg.tool_call_id || call_batch_id}`\n } else if (isGenUIMessage && msg.spec_id) {\n messageKey = `${interaction_id}-genui-${msg.spec_id}`\n } else if (usingTurnIndex) {\n // ★ 主分支:turn_index 与后端 turn 聚合粒度严格对齐;同 turn 的 chunk 自然合并,\n // 不同 turn 的 think/text 永不撞键 → 两段独立 text/think 各自一个气泡。\n messageKey = `${interaction_id}-ti-${turnIdx}`\n } else if (usingStreamUuid) {\n // 退路 1:旧后端没下发 turn_index 但有 stream_uuid → 按物理流边界聚合\n messageKey = `${interaction_id}-${streamUuid}-${content_type}`\n } else {\n // 退路 2:极旧后端两者都没 → 沿用最早的复合键\n // YWRF-001 J5 / fs11:兜底键含 ``agent_instance_id``,如果 backend 复用\n // instance_id 跨 cid(已观察到的实际 bug:agent-690 同一 instance 服务两\n // 个对话),同 (iid, aid, bid, ctype) 会撞键把第二个 cid 的内容追加到\n // 第一个 cid 的 message 上。加 cid 前缀让两个 cid 自然分桶。\n messageKey = `${incomingClientId ?? '_no_cid_'}-${interaction_id}-${agent_instance_id}-${call_batch_id}-${content_type}`\n }\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 // ========== 非连续同类型消息分段(仅在兜底无 stream_uuid 路径下需要) ==========\n // 旧后端兼容路径:当消息序列为 text → tool_use → tool_result → text 且\n // 两段 text 共用 (interaction, agent, batch, content_type) 主键时,必须按\"是否\n // 是轮次最后一条\"判断能否合并;否则创建带 -N 后缀的新分段 key。\n //\n // JETP-045 Phase 2 P2-T06:删除原 JETP-011 短残片回贴启发式。\n // - 启用 stream_uuid 后,think1 / think2 分别属于不同物理流 → 自动有不同 key\n // → 撞键根因消失,启发式不再需要(相反它会引入误合并风险)\n // - 旧后端兜底路径不再做短残片回贴;接受少量短残片单独成段,UI 自然降级。\n if (!usingTurnIndex && !usingStreamUuid && !isMcpMessage && !isGenUIMessage && messageIndexRef.current.has(messageKey)) {\n const baseKey = messageKey\n const candidateKeys = [baseKey]\n let segIdx = 1\n while (messageIndexRef.current.has(`${baseKey}-${segIdx}`)) {\n candidateKeys.push(`${baseKey}-${segIdx}`)\n segIdx++\n }\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 messageKey = mergeTarget\n } else {\n messageKey = `${baseKey}-${segIdx}`\n }\n }\n // ========== 结束:非连续同类型消息分段 ==========\n \n // 获取或创建消息\n let message = messageIndexRef.current.get(messageKey)\n // JETP-045 Phase 6:echo 检测 — 仅当 my_connection_id 已设置且 ``connection_id_from``\n // 非空时才比较;任一缺失即视为远端,保持向后兼容 (AC-CONN-008)。\n const myCid = myConnectionIdRef.current\n const incomingCidFrom = msg.connection_id_from\n const isEcho = !!(myCid && incomingCidFrom && incomingCidFrom === myCid)\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 clientId: msg.client_id,\n connectionIdFrom: incomingCidFrom,\n isEcho,\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 if (notification_type === 'mcp_generating' && isDevMode()) {\n console.log('[useMessageAggregator] MCP new message generating', { agent_instance_id, tool_name: msg.tool_name, messageKey: messageKey.slice(-40) })\n }\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 if (isDevMode()) {\n console.log('[useMessageAggregator] MCP generating', { agent_instance_id, tool_name: msg.tool_name, messageKey: messageKey.slice(-40) })\n }\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') || isGenUIMessage\n if (!skipContent) {\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 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 } else if (content_type === 'gen_ui_meta') {\n const parsed = parseGenUIMetaContent(content as unknown)\n const targetSpecId = msg.spec_id\n if (parsed && targetSpecId) {\n if (parsed.kind === 'identity') {\n specMetaMapRef.current.set(targetSpecId, {\n resourceId: parsed.resourceId,\n gitPath: parsed.gitPath,\n })\n specMetaChanged = true\n } else {\n specLifecycleMapRef.current.set(targetSpecId, parsed.entry)\n specLifecycleChanged = true\n }\n }\n } else if (content_type === 'gen_ui_card' || content_type === 'gen_ui_page') {\n const prevMsg = message\n const prevPatches = message.uiPatches ?? []\n const newPatches = content != null && content !== '' ? [...prevPatches, content] : [...prevPatches]\n message = {\n ...message,\n specId: msg.spec_id ?? message.specId,\n renderMode: (msg.render_mode as 'card' | 'page') ?? message.renderMode,\n uiPatches: newPatches,\n }\n messageIndexRef.current.set(messageKey, message)\n const idx = round.messages.indexOf(prevMsg)\n if (idx >= 0) round.messages[idx] = message\n console.log('[JETP-033] GenUI patch received:', {\n content_type,\n spec_id: msg.spec_id,\n render_mode: msg.render_mode,\n totalPatches: newPatches.length,\n contentPreview: typeof content === 'string' ? content.substring(0, 80) : typeof content,\n })\n }\n }\n\n // === 只在 setState 中做状态快照 ===\n setState(() => {\n // 从 ref 构建新的 Map(浅拷贝触发 React 更新)\n const newRounds = new Map(roundIndexRef.current)\n const endedByRound = endedAgentInstanceIdsByRoundRef.current\n const endedAgentInstanceIdsByRound = new Map(\n [...endedByRound.entries()].map(([k, v]) => [k, new Set(v)])\n )\n return {\n rounds: newRounds,\n currentInteractionId: latestInteractionId,\n endedAgentInstanceIdsByRound,\n }\n })\n\n if (todoMapChanged) {\n setTodoMap(new Map(todoMapRef.current))\n }\n if (specMetaChanged) {\n setSpecMetaMap(new Map(specMetaMapRef.current))\n }\n if (specLifecycleChanged) {\n setSpecLifecycleMap(new Map(specLifecycleMapRef.current))\n }\n\n } catch (error) {\n // 异常不应导致渲染停滞:rafId 已在函数入口重置,\n // 后续 processMessage 仍能调度新的 RAF 重试。\n console.error('[useMessageAggregator] flushUpdates error — dropped batch of', updates.length, 'messages:', error)\n }\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 // 获取轮次列表(按时间排序),并挂上本轮已结束的 agent_instance_id(用于子 Agent 卡片状态)\n const getRoundsList = useCallback((): Round[] => {\n const endedByRound = state.endedAgentInstanceIdsByRound\n return Array.from(state.rounds.values())\n .map((r) => ({\n ...r,\n endedAgentInstanceIds: endedByRound.get(r.interactionId) || new Set<number>(),\n }))\n .sort((a, b) => a.index - b.index)\n }, [state.rounds, state.endedAgentInstanceIdsByRound])\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, clientId?: 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 clientId,\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 endedAgentInstanceIdsByRound: prevState.endedAgentInstanceIdsByRound,\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 endedAgentInstanceIdsByRoundRef.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, endedAgentInstanceIdsByRound: new Map() })\n }, [])\n\n const prependRounds = useCallback((olderRounds: Round[]) => {\n if (olderRounds.length === 0) return\n\n const newMap = new Map<string, Round>()\n\n for (const round of olderRounds) {\n if (roundIndexRef.current.has(round.interactionId)) continue\n newMap.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 for (const [id, round] of roundIndexRef.current) {\n newMap.set(id, round)\n }\n\n let idx = 0\n for (const [, round] of newMap) {\n round.index = ++idx\n }\n\n roundIndexRef.current = newMap\n\n const endedByRound = endedAgentInstanceIdsByRoundRef.current\n setState(() => ({\n rounds: new Map(roundIndexRef.current),\n currentInteractionId: roundIndexRef.current.size > 0\n ? [...roundIndexRef.current.keys()].pop()!\n : null,\n endedAgentInstanceIdsByRound: new Map(\n [...endedByRound.entries()].map(([k, v]) => [k, new Set(v)]),\n ),\n }))\n }, [])\n\n const mergeRecoveryRounds = useCallback((recoveryRounds: Round[]) => {\n if (recoveryRounds.length === 0) return\n\n // ── JETP-052 BUG-2 修复 ──\n // 旧实现是 REPLACE(recovery 全量覆盖 round.messages),在 db-writer 落库滞后场景下\n // 会把 live 已经渲染的 末端 message(README artifact / final gen_ui_page)整段擦掉。\n //\n // 新实现是 MERGE:\n // 1. 已存在 round 的 message 按 ``id`` 建立 set;\n // 2. recovery 来的 message 同 id ⇒ 视为权威,覆盖 live 版本;\n // 3. recovery 没有覆盖到的 live message ⇒ 全部保留,挂到 recovery 之后;\n // 4. recovery 的新 message ⇒ 按 recovery 自身顺序排在前段;\n // 5. 不再需要的 live 索引(被 recovery 覆盖的)才从 messageIndexRef 删除。\n //\n // 这样即使 recovery 比 live 少(典型:DB 落库滞后),也只是\"少补一点历史\",\n // 而不会丢掉 live 已经稳定的末端消息。\n for (const round of recoveryRounds) {\n const existing = roundIndexRef.current.get(round.interactionId)\n\n if (!existing) {\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 continue\n }\n\n const recoveryIds = new Set(round.messages.map(m => m.id))\n const liveOnly = existing.messages.filter(m => !recoveryIds.has(m.id))\n\n const merged: AggregatedMessage[] = [...round.messages, ...liveOnly]\n const mergedRound: Round = {\n ...existing,\n ...round,\n messages: merged,\n }\n\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 roundIndexRef.current.set(round.interactionId, mergedRound)\n }\n\n const endedByRound = endedAgentInstanceIdsByRoundRef.current\n setState(() => ({\n rounds: new Map(roundIndexRef.current),\n currentInteractionId: roundIndexRef.current.size > 0\n ? [...roundIndexRef.current.keys()].pop()!\n : null,\n endedAgentInstanceIdsByRound: new Map(\n [...endedByRound.entries()].map(([k, v]) => [k, new Set(v)]),\n ),\n }))\n }, [])\n\n // 流结束时收尾:将该轮次中所有未完成的工具卡片强制标记为 complete\n // 防止 JetAgents 漏发 mcp_end 导致 UI 永远停留在\"生成中/执行中\"\n //\n // YWRF-001 J5 / fs11:roundIndexRef 在 cid 防御性分桶后,key 可能是\n // ``interaction_id`` 或 ``${interaction_id}|${cid}``。controller 收 finish\n // 信号时只拿到 backend iid,所以这里要兼容两种 key 形态:\n // 1. 直接按 iid lookup(标准路径,单 cid 场景);\n // 2. 找不到时遍历 ``${iid}|*`` 的所有 cid-keyed round 一并 finalize\n // (fs11 多 cid 场景下,finish 语义上覆盖该 iid 的所有派生 round)。\n const finalizeRound = useCallback((interactionId: string) => {\n // fs11:finish 信号语义是\"该 backend iid 整体完成\",多 cid 派生场景下\n // 必须把 ``iid`` + 所有 ``${iid}|*`` 同时 finalize,否则未派生侧(cid B)\n // 的工具卡会卡在\"生成中\"。direct hit 不能 short-circuit。\n const matched: string[] = []\n const prefix = `${interactionId}|`\n for (const key of roundIndexRef.current.keys()) {\n if (key === interactionId || key.startsWith(prefix)) {\n matched.push(key)\n }\n }\n if (matched.length === 0) return\n\n let changed = false\n for (const key of matched) {\n const round = roundIndexRef.current.get(key)\n if (!round) continue\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\n if (changed) {\n const endedByRound = endedAgentInstanceIdsByRoundRef.current\n setState(() => ({\n rounds: new Map(roundIndexRef.current),\n currentInteractionId: matched[matched.length - 1],\n endedAgentInstanceIdsByRound: new Map([...endedByRound.entries()].map(([k, v]) => [k, new Set(v)])),\n }))\n }\n }, [])\n\n // 清空状态\n const clear = useCallback(() => {\n pendingUpdates.current = []\n messageIndexRef.current.clear()\n roundIndexRef.current.clear()\n callBatchToRoundRef.current.clear()\n endedAgentInstanceIdsByRoundRef.current.clear()\n todoMapRef.current.clear()\n specMetaMapRef.current.clear()\n specLifecycleMapRef.current.clear()\n setSpecLifecycleMap(new Map())\n if (rafId.current) {\n cancelAnimationFrame(rafId.current)\n rafId.current = null\n }\n setState({\n rounds: new Map(),\n currentInteractionId: null,\n endedAgentInstanceIdsByRound: new Map(),\n })\n setTodoMap(new Map())\n setSpecMetaMap(new Map())\n }, [])\n\n const loadTodoMap = useCallback((entries: Map<string, TodoData>) => {\n if (entries.size === 0) return\n for (const [k, v] of entries) {\n todoMapRef.current.set(k, v)\n }\n setTodoMap(new Map(todoMapRef.current))\n }, [])\n\n const loadSpecMetaMap = useCallback((entries: Map<string, { resourceId: string; gitPath: string }>) => {\n if (entries.size === 0) return\n for (const [k, v] of entries) {\n specMetaMapRef.current.set(k, v)\n }\n setSpecMetaMap(new Map(specMetaMapRef.current))\n }, [])\n\n const loadSpecLifecycleMap = useCallback((entries: Map<string, SpecLifecycleEntry>) => {\n if (entries.size === 0) return\n for (const [k, v] of entries) {\n specLifecycleMapRef.current.set(k, v)\n }\n setSpecLifecycleMap(new Map(specLifecycleMapRef.current))\n }, [])\n\n // ---------------------------------------------------------------------------\n // 内存埋点(dev-only,零生产开销 — getter 只在 __ymMem.snapshot() 被调时才执行)\n // ---------------------------------------------------------------------------\n // 每个 useMessageAggregator 实例(理论上 ChatWidget 单例,所以一份)\n // 注册一次。多实例场景以最后一个为准(snapshot 仍能反映\"当前活跃\" widget)。\n useEffect(() => {\n registerMemSource('aggregator', () => {\n let chunks_count = 0\n let content_chars_total = 0\n let largest_message_chars = 0\n for (const m of messageIndexRef.current.values()) {\n chunks_count += m.contentChunks.length\n let mChars = 0\n for (const c of m.contentChunks) {\n if (typeof c === 'string') mChars += c.length\n }\n content_chars_total += mChars\n if (mChars > largest_message_chars) largest_message_chars = mChars\n }\n return {\n rounds: roundIndexRef.current.size,\n messages: messageIndexRef.current.size,\n chunks_in_messages: chunks_count,\n // YWRF-DUP-001:processedChunksRef 已删(dead code),此字段保留兼容\n // 现有 __ymMem 调试快照消费方,恒为 0。\n chunks_processed_set_size: 0,\n call_batch_routes: callBatchToRoundRef.current.size,\n content_chars_total,\n largest_message_chars,\n todo_entries: todoMapRef.current.size,\n spec_meta_entries: specMetaMapRef.current.size,\n spec_lifecycle_entries: specLifecycleMapRef.current.size,\n pending_updates: pendingUpdates.current.length,\n }\n })\n return () => {\n unregisterMemSource('aggregator')\n }\n }, [])\n\n return {\n state,\n todoMap,\n specMetaMap,\n specLifecycleMap,\n processMessage,\n getRoundsList,\n getCurrentRound,\n startNewRound,\n loadRounds,\n prependRounds,\n mergeRecoveryRounds,\n finalizeRound,\n loadTodoMap,\n loadSpecMetaMap,\n loadSpecLifecycleMap,\n clear,\n setMyConnectionId,\n }\n}\n\nexport default useMessageAggregator\n","/**\n * RFC 4122 v4 UUID。\n *\n * `crypto.randomUUID` 仅在「安全上下文」可用(HTTPS、localhost 等)。\n * 通过局域网 IP + HTTP 访问时不可用,需用 `getRandomValues` 回退。\n */\nexport function randomUUID(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID()\n }\n if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\n const bytes = new Uint8Array(16)\n crypto.getRandomValues(bytes)\n bytes[6] = (bytes[6]! & 0x0f) | 0x40\n bytes[8] = (bytes[8]! & 0x3f) | 0x80\n const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {\n const r = (Math.random() * 16) | 0\n const v = c === 'x' ? r : (r & 0x3) | 0x8\n return v.toString(16)\n })\n}\n","/**\n * 内存埋点 — dev-only 全局采样器\n *\n * 设计目标:\n * · **零生产开销**:所有热路径只调 `incCounter / decCounter`(一次属性 ++);\n * `snapshot()` 才走全部 getter,不在渲染热路径里。\n * · **不入侵业务**:业务模块通过 `registerMemSource(name, getter)` 把自己的\n * \"可观测维度\"挂上来;不引用业务类型,避免反向依赖。\n * · **不强制开启**:dev 默认开;生产侧可以通过 ``window.__YM_MEM_FORCE = true``\n * 手工打开(用于 staging 排查)。\n *\n * 使用:\n * ```ts\n * // 业务模块(一次性,模块顶层)\n * registerMemSource('aggregator', () => ({\n * rounds: roundIndexRef.current.size,\n * messages: messageIndexRef.current.size,\n * chunks_processed: processedChunksRef.current.size,\n * content_chars_total: totalChars(),\n * }))\n *\n * // dev console\n * __ymMem.snapshot() // 打一次\n * __ymMem.start(5_000) // 每 5s 在 console.table 出一行\n * __ymMem.stop()\n * __ymMem.diff(prev) // 对比两次 snapshot\n * ```\n *\n * 维度规约:\n * · 数值字段单位:count / bytes / chars 自描述(在 key 命名里带后缀);\n * · 布尔字段:以 ``is_`` / ``has_`` 开头;\n * · 嵌套对象按 source name 命名,避免冲突;\n * · `__ymMem.heap` 单独存浏览器 ``performance.memory`` 估算,仅 Chromium 有,Safari 缺失返回 null。\n */\n\nimport { isDevMode } from './env'\n\n// ---------------------------------------------------------------------------\n// 类型\n// ---------------------------------------------------------------------------\n\n/** 单个数据源 getter;返回扁平 key:value 对象,value 应是 number/boolean/string */\nexport type MemSourceGetter = () => Record<string, number | string | boolean | null>\n\n/** 单次快照 — `sources` 用 source name 索引各数据源最新值 */\nexport interface MemSnapshot {\n /** ms since epoch */\n at: number\n /** 自从模块初始化已运行的时间(ms) */\n uptime_ms: number\n /** 浏览器内存(仅 Chromium 提供,否则 null) */\n heap: {\n used_mb: number\n total_mb: number\n limit_mb: number\n } | null\n /** 各数据源最新值(key = source name) */\n sources: Record<string, Record<string, number | string | boolean | null>>\n /** 计数器(内置,可加可减) */\n counters: Record<string, number>\n}\n\n// ---------------------------------------------------------------------------\n// 内部状态\n// ---------------------------------------------------------------------------\n\nconst sources = new Map<string, MemSourceGetter>()\nconst counters = new Map<string, number>()\nconst startedAt = Date.now()\n\nlet pollHandle: ReturnType<typeof setInterval> | null = null\nlet lastLoggedSnapshot: MemSnapshot | null = null\n\n// ---------------------------------------------------------------------------\n// API(业务侧)\n// ---------------------------------------------------------------------------\n\n/**\n * 注册一个数据源。**幂等**:同名再注册会覆盖。\n *\n * 业务模块在 hook 顶层(不放在 useEffect 里)调用一次即可;模块卸载时通常\n * 不需要 unregister,因为 getter 持有 ref 闭包,刷新时整个模块图重置。\n */\nexport function registerMemSource(name: string, getter: MemSourceGetter): void {\n if (!shouldEnable()) return\n sources.set(name, getter)\n}\n\n/** 取消注册 — 仅供测试 / 业务有特殊场景需要时使用 */\nexport function unregisterMemSource(name: string): void {\n sources.delete(name)\n}\n\n/**\n * 累加计数器(线程安全:JS 单线程)。\n * 用于跟踪\"开/关\"型事件的总量,例如 sse_connect_total / sse_disconnect_total。\n */\nexport function incCounter(name: string, delta = 1): void {\n if (!shouldEnable()) return\n counters.set(name, (counters.get(name) ?? 0) + delta)\n}\n\n/** 显式置 0;常用于 ``connections_active`` 这种\"当前在线数\"。 */\nexport function setCounter(name: string, value: number): void {\n if (!shouldEnable()) return\n counters.set(name, value)\n}\n\n// ---------------------------------------------------------------------------\n// API(消费侧 — Console / DevTools)\n// ---------------------------------------------------------------------------\n\nexport function snapshot(): MemSnapshot {\n const out: MemSnapshot = {\n at: Date.now(),\n uptime_ms: Date.now() - startedAt,\n heap: readHeap(),\n sources: {},\n counters: Object.fromEntries(counters),\n }\n for (const [name, getter] of sources) {\n try {\n out.sources[name] = getter()\n } catch (err) {\n out.sources[name] = { _error: String((err as Error)?.message ?? err) }\n }\n }\n return out\n}\n\n/** 周期 console.table 一行;intervalMs 默认 5_000。 */\nexport function start(intervalMs = 5_000): void {\n if (!shouldEnable()) return\n stop()\n pollHandle = setInterval(() => {\n const snap = snapshot()\n const flat = flattenForTable(snap)\n // eslint-disable-next-line no-console\n console.log('[ymMem]', new Date(snap.at).toISOString().slice(11, 19), flat)\n lastLoggedSnapshot = snap\n }, Math.max(500, intervalMs))\n}\n\nexport function stop(): void {\n if (pollHandle) {\n clearInterval(pollHandle)\n pollHandle = null\n }\n}\n\n/**\n * 对比两次 snapshot;输出每个数值字段的 delta(数字字段才算)。\n * 不传 prev 则用上次 ``start()`` 周期最后一次记录的 snapshot 对比当前。\n */\nexport function diff(prev?: MemSnapshot): Record<string, number> {\n const a = prev ?? lastLoggedSnapshot\n const b = snapshot()\n if (!a) return {}\n const out: Record<string, number> = {}\n out['__elapsed_ms'] = b.at - a.at\n if (a.heap && b.heap) {\n out['heap.used_mb'] = round(b.heap.used_mb - a.heap.used_mb)\n }\n for (const [src, kv] of Object.entries(b.sources)) {\n const prevKv = a.sources[src] ?? {}\n for (const [k, v] of Object.entries(kv)) {\n if (typeof v === 'number' && typeof prevKv[k] === 'number') {\n out[`${src}.${k}`] = round((v as number) - (prevKv[k] as number))\n }\n }\n }\n for (const [k, v] of Object.entries(b.counters)) {\n const prevV = a.counters[k] ?? 0\n out[`counter.${k}`] = round(v - prevV)\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// 工具\n// ---------------------------------------------------------------------------\n\nfunction shouldEnable(): boolean {\n if (isDevMode()) return true\n // 允许生产环境通过 window.__YM_MEM_FORCE 临时打开(staging 用)\n if (typeof window !== 'undefined') {\n return (window as unknown as { __YM_MEM_FORCE?: boolean }).__YM_MEM_FORCE === true\n }\n return false\n}\n\ninterface PerfMemory {\n usedJSHeapSize?: number\n totalJSHeapSize?: number\n jsHeapSizeLimit?: number\n}\n\nfunction readHeap(): MemSnapshot['heap'] {\n if (typeof performance === 'undefined') return null\n const mem = (performance as unknown as { memory?: PerfMemory }).memory\n if (!mem || typeof mem.usedJSHeapSize !== 'number') return null\n return {\n used_mb: round(mem.usedJSHeapSize / 1024 / 1024),\n total_mb: round((mem.totalJSHeapSize ?? 0) / 1024 / 1024),\n limit_mb: round((mem.jsHeapSizeLimit ?? 0) / 1024 / 1024),\n }\n}\n\nfunction flattenForTable(snap: MemSnapshot): Record<string, number | string | boolean | null> {\n const flat: Record<string, number | string | boolean | null> = {\n uptime_s: Math.round(snap.uptime_ms / 1000),\n heap_used_mb: snap.heap?.used_mb ?? null,\n heap_total_mb: snap.heap?.total_mb ?? null,\n }\n for (const [src, kv] of Object.entries(snap.sources)) {\n for (const [k, v] of Object.entries(kv)) {\n flat[`${src}.${k}`] = v\n }\n }\n for (const [k, v] of Object.entries(snap.counters)) {\n flat[`c.${k}`] = v\n }\n return flat\n}\n\nfunction round(n: number): number {\n return Math.round(n * 100) / 100\n}\n\n// ---------------------------------------------------------------------------\n// 自动挂载 window.__ymMem\n// ---------------------------------------------------------------------------\n\nif (typeof window !== 'undefined' && shouldEnable()) {\n ;(window as unknown as { __ymMem: unknown }).__ymMem = {\n snapshot,\n start,\n stop,\n diff,\n incCounter,\n setCounter,\n registerMemSource,\n /** 列出当前注册的 source 名 */\n sources: () => Array.from(sources.keys()),\n }\n // eslint-disable-next-line no-console\n console.log(\n '%c[ymMem] enabled — try `__ymMem.snapshot()` / `__ymMem.start(5000)` / `__ymMem.diff()`',\n 'color:#7aa6ff;font-weight:bold;',\n )\n}\n","/**\n * JETP-045 Phase 6 PR-T04 — `useConnectionId` hook\n *\n * Layer 1.5 (CONNECTION) `connection_id`:每个 ChatWidget mount(≈ 每个浏览器 tab)\n * 派生一次 UUID,作为本 tab 与后端之间所有 WS/SSE 上行请求的物理连接标识。\n *\n * 设计契约(详见 doc/proposals/JETP-045/00_protocol/08_connection_id.md §2.1.1):\n * 1. 同一 mount 周期内稳定 (AC-CONN-001):任何调用都返回同一字符串。\n * 2. unmount/remount 后变化 (AC-CONN-001):新挂载是新 tab/新连接。\n * 3. 字符集:满足 `/^[A-Za-z0-9._:-]+$/`,长度 ∈ [1, 128] (AC-CONN-002);\n * 与后端 ``SourceEvent.connection_id`` Pydantic 校验对齐。\n * 4. 不持久化 (与 client_id 显式区分):localStorage 不写入;刷新 ⇒ 新 ID。\n * 5. SSR / 隐私模式 / 测试环境兜底:若 ``crypto.randomUUID`` 不可用,退化到\n * 时间戳 + 计数器,仍然满足字符集 + 唯一性。\n *\n * 工业级可靠性:\n * - 仅依赖 ``useRef``,零 effect、零订阅;不会触发 React 重渲染。\n * - 派生函数纯函数,可被纯函数测试/Node SSR 安全调用。\n * - 不依赖 ``window``;服务器端渲染时也能拿到一个稳定字符串(仅对该次 SSR 生效)。\n */\nimport { useRef } from 'react'\n\nconst CONNECTION_ID_REGEX = /^[A-Za-z0-9._:-]+$/\nconst CONNECTION_ID_MAX = 128\n\nlet _fallbackCounter = 0\n\n/**\n * 生成一个 connection_id(纯函数,可独立测试)。\n *\n * @returns 形如 ``conn:7f3a9b2c-4e1d-...`` 的合法字符串。``-`` 和 ``:`` 在字符集内,\n * 所以保留 UUID 原 hyphen,无需替换。前缀 ``conn:`` 用于日志检索定位。\n */\nexport function generateConnectionId(): string {\n let raw: string\n try {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n raw = crypto.randomUUID()\n } else {\n _fallbackCounter = (_fallbackCounter + 1) >>> 0\n raw = `${Date.now().toString(36)}-${_fallbackCounter.toString(36)}-${Math.floor(Math.random() * 1e9).toString(36)}`\n }\n } catch {\n _fallbackCounter = (_fallbackCounter + 1) >>> 0\n raw = `${Date.now().toString(36)}-${_fallbackCounter.toString(36)}`\n }\n let value = `conn:${raw}`\n if (value.length > CONNECTION_ID_MAX) value = value.slice(0, CONNECTION_ID_MAX)\n if (!CONNECTION_ID_REGEX.test(value)) {\n // 极端 fallback:strip 非法字符\n value = value.replace(/[^A-Za-z0-9._:-]/g, '_').slice(0, CONNECTION_ID_MAX)\n }\n return value\n}\n\n/**\n * useConnectionId — 给 ChatWidget mount 周期返回一个稳定的 connection_id。\n *\n * - 多次调用同一 hook 实例返回同值;不同 mount 返回不同值。\n * - 不引发任何重渲染;可安全在 render 期内同步派生。\n */\nexport function useConnectionId(): string {\n const ref = useRef<string | null>(null)\n if (ref.current === null) {\n ref.current = generateConnectionId()\n }\n return ref.current\n}\n","/**\n * SSE 连接 Hook (SDK version)\n *\n * JETP-056 P2 收敛:\n * - 全链路统一 ``fetch + ReadableStream``:废弃浏览器 ``EventSource``。\n * 原因:``EventSource`` API 不支持自定义 header,无法注入 ``Authorization``,\n * 在 Bearer-only 部署下完全跳过鉴权(依赖 cookie 兜底是错的)。\n * - 鉴权 / 401 重试 / onAuthFailure 全部收敛到 ``useAuthedFetch``:\n * - useSSE 不再手写 401 重试逻辑;\n * - 与 useChatWidgetController 等其他鉴权入口共用同一条策略链。\n * - 下游 SSE 解析逻辑(reader loop / data: 解析 / transformSSEMessage)保持不变,\n * 行为兼容;GET 与 POST 仅在 ``method`` / ``body`` 上有差异。\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { SSEMessage, ChatWidgetAdapter } from '../types'\nimport { useAuthedFetch } from './useAuthedFetch'\nimport { incCounter } from '../utils/memTelemetry'\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 abortControllerRef = useRef<AbortController | null>(null)\n const reconnectAttemptsRef = useRef(0)\n const reconnectTimerRef = useRef<number | null>(null)\n\n // useAuthedFetch 把 Authorization 注入 / 401 refresh / onAuthFailure 集中到一条链;\n // SSE 走 stream 而非 JSON 响应,但前置鉴权处理与普通请求完全一致。\n const authedFetch = useAuthedFetch(adapter)\n\n // Ref for callbacks to avoid stale closures inside long-running fetch streams\n const onMessageRef = useRef(onMessage)\n onMessageRef.current = onMessage\n const adapterRef = useRef(adapter)\n adapterRef.current = adapter\n\n const updateStatus = useCallback((newStatus: ConnectionStatus) => {\n setStatus(newStatus)\n onStatusChange?.(newStatus)\n }, [onStatusChange])\n\n const disconnect = useCallback(() => {\n if (reconnectTimerRef.current) {\n clearTimeout(reconnectTimerRef.current)\n reconnectTimerRef.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 const connect = useCallback((url: string, body?: object) => {\n disconnect()\n updateStatus('connecting')\n\n abortControllerRef.current = new AbortController()\n const signal = abortControllerRef.current.signal\n\n // dev 内存埋点:sse 连接活跃数(active = total_open - total_close)\n // 每次 connect() 即视为一次\"开\",无论后端是否真握上手;catch / disconnect 各自计 close。\n incCounter('sse_connect_total', 1)\n incCounter('sse_active', 1)\n let closedOnce = false\n const markClosed = () => {\n if (closedOnce) return\n closedOnce = true\n incCounter('sse_active', -1)\n incCounter('sse_disconnect_total', 1)\n }\n\n // GET / POST 共用同一条 fetch + reader 路径;\n // useAuthedFetch 已注入 Authorization,调用方只需补充 SSE 专属 header。\n const init: RequestInit = body\n ? {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'text/event-stream',\n },\n body: JSON.stringify(body),\n signal,\n }\n : {\n method: 'GET',\n headers: {\n 'Accept': 'text/event-stream',\n },\n signal,\n }\n\n authedFetch(url, init)\n .then(async (response) => {\n // 401 已由 useAuthedFetch 处理(refreshAuth + onAuthFailure);\n // 这里只需对剩余非 2xx 走错误链路。\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\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 事件(与原 EventSource 行为兼容:以 ``data:`` 行为单位分发)\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 parsed = JSON.parse(data)\n const xform = adapterRef.current.transformSSEMessage\n if (xform) {\n const transformed = xform(parsed)\n if (transformed) {\n for (const msg of transformed) {\n onMessageRef.current?.(msg)\n }\n }\n } else {\n onMessageRef.current?.(parsed as SSEMessage)\n }\n } catch (e) {\n console.warn('Failed to parse SSE message:', data, e)\n }\n }\n }\n }\n }\n\n markClosed()\n updateStatus('disconnected')\n })\n .catch((error: unknown) => {\n markClosed()\n if ((error as { name?: string } | null)?.name === 'AbortError') {\n updateStatus('disconnected')\n return\n }\n const errMsg = error instanceof Error ? error.message : String(error)\n const is401 = errMsg.includes('401')\n console.error('SSE connection error:', error)\n updateStatus('error')\n onError?.(error instanceof Error ? error : new Error(errMsg))\n\n // 401:refreshAuth 已由 useAuthedFetch 兜过,不再重连,避免无限旋\n if (is401) return\n\n if (reconnectAttemptsRef.current < maxReconnectAttempts) {\n reconnectAttemptsRef.current++\n reconnectTimerRef.current = window.setTimeout(() => {\n connect(url, body)\n }, reconnectInterval)\n }\n })\n }, [authedFetch, disconnect, updateStatus, 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 * JETP-056 — useAuthedFetch\n *\n * 集中所有\"前端 → jetagents 后端\"HTTP 调用的鉴权头注入与 401 处理。\n *\n * 设计动机(参考 JETP-054 hotfix):\n * - chat-widget 内部历史上有 25+ 处直接 `fetch(...)`,每处都需要手动从 adapter\n * 拉 `getAuthHeaders()` 拼到 headers 里。任何一处遗漏都会导致 401 → 整条链路\n * 卡住(消息发不出、client_id 分配失败、legacy import 不工作等)。\n * - 把它收敛到一个 hook 后,后续新增 fetch 只要走 useAuthedFetch,鉴权就自动正确,\n * 防回归。\n *\n * 401 处理链:\n * 1. 收到 401 且开启 retryOn401(默认开启);\n * 2. 调 adapter.refreshAuth?.();\n * 3. 若返回 true:重新拉一次 getAuthHeaders() 并把请求重发一次(不再 401 重试);\n * 4. 否则:调用 adapter.onAuthFailure?.(),把原 401 Response 返回给调用方。\n *\n * 兼容性:\n * - 默认 credentials: 'omit':JetAgents 与 chat-widget 常跨源(如 :5180 → :8080),\n * 服务端若配置 allow_origins=['*'] 且 allow_credentials=True,浏览器会拒绝带\n * credentials:'include' 的请求(CORS:* 与 Cookie 凭证不能并存)。鉴权走\n * Authorization / X-User-ID 头,不依赖跨域 Cookie。\n * - 若宿主确实需要跨域 Cookie,请在 init 中显式传 credentials: 'include',并确保\n * 后端 CORS 对具体 Origin 回显且非通配 *。\n * - 调用方可以覆盖 credentials、headers;只在未指定时填默认值。\n */\nimport { useCallback } from 'react'\nimport type { ChatWidgetAdapter } from '../types'\nimport { useAdapter } from '../contexts/AdapterContext'\n\nexport type AuthedFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>\n\nexport interface UseAuthedFetchOptions {\n /** 显式 adapter;优先级高于 Context 中的 adapter */\n adapter?: ChatWidgetAdapter | null\n /** 是否在 401 时自动走 refreshAuth → 重发;默认 true */\n retryOn401?: boolean\n}\n\nfunction isOptionsObject(v: unknown): v is UseAuthedFetchOptions {\n if (!v || typeof v !== 'object' || Array.isArray(v)) return false\n // 仅当对象明确出现 options 专属字段时才识别为 options,避免把 minimal shim\n // adapter(仅有 getAuthHeaders)误判成 options 而丢失鉴权头。\n return 'adapter' in (v as object) || 'retryOn401' in (v as object)\n}\n\nfunction applyAuthHeaders(\n headers: Headers,\n adapter: ChatWidgetAdapter | null,\n): void {\n if (!adapter) return\n try {\n const auth = adapter.getAuthHeaders?.() ?? {}\n for (const [k, v] of Object.entries(auth)) {\n if (typeof v === 'string') headers.set(k, v)\n }\n } catch {\n /* getAuthHeaders 异常不应阻塞请求;后端会拒并触发 401 走标准链路 */\n }\n try {\n const extra = (adapter.getExtraHeaders?.() ?? {}) as Record<string, string>\n for (const [k, v] of Object.entries(extra)) {\n if (typeof v === 'string') headers.set(k, v)\n }\n } catch {\n /* 同上 */\n }\n}\n\nexport function useAuthedFetch(\n arg?: ChatWidgetAdapter | UseAuthedFetchOptions | null,\n): AuthedFetch {\n const ctxAdapter = useAdapter()\n\n let explicitAdapter: ChatWidgetAdapter | null | undefined\n let retryOn401 = true\n if (isOptionsObject(arg)) {\n explicitAdapter = arg.adapter\n retryOn401 = arg.retryOn401 !== false\n } else {\n explicitAdapter = arg as ChatWidgetAdapter | null | undefined\n }\n const adapter: ChatWidgetAdapter | null = explicitAdapter ?? ctxAdapter ?? null\n\n return useCallback<AuthedFetch>(\n async (input, init) => {\n const merged: RequestInit = { ...init }\n if (merged.credentials === undefined) merged.credentials = 'omit'\n const headers = new Headers(merged.headers || {})\n applyAuthHeaders(headers, adapter)\n merged.headers = headers\n\n let resp = await fetch(input as RequestInfo, merged)\n\n if (resp.status === 401 && adapter && retryOn401) {\n let refreshed = false\n if (typeof adapter.refreshAuth === 'function') {\n try {\n refreshed = (await adapter.refreshAuth()) === true\n } catch {\n refreshed = false\n }\n }\n if (refreshed) {\n const headers2 = new Headers(merged.headers || {})\n applyAuthHeaders(headers2, adapter)\n merged.headers = headers2\n resp = await fetch(input as RequestInfo, merged)\n } else {\n try {\n adapter.onAuthFailure?.()\n } catch {\n /* onAuthFailure 异常不影响把 401 返回给调用方 */\n }\n }\n }\n\n return resp\n },\n [adapter, retryOn401],\n )\n}\n","/**\n * JETP-056 — AdapterContext\n *\n * 提供一个 React Context 用于把 ChatWidgetAdapter 下放到 widget 子树。\n * 业务动机:ChatWidget 内部 hook/component 数量持续增长(25+ 处直接 fetch),\n * 通过 Context 统一注入 adapter 后,可:\n * 1. 让 useAuthedFetch 在任意位置无 prop drilling 拿到 adapter;\n * 2. 防止\"中间组件忘了透传 adapter → 鉴权头丢失\"这类 JETP-054 同源 bug;\n * 3. 给后续 P2 的 25 处裸 fetch 收敛留好基础设施。\n *\n * 使用约定:\n * - useAdapter():nullable,给\"context 不强制必须存在\"的旧调用方用;\n * - useAdapterRequired():在 dev 期硬抛,帮助快速定位\"忘挂 Provider\"。\n *\n * 与既有 ResourceProvider 的关系:\n * ResourceProvider 是\"业务能力门面\"(把 adapter 的资源相关方法包装成更高阶 API),\n * AdapterContext 则是\"原始 adapter 透传\",二者职责正交、可并存。\n */\nimport React, { createContext, useContext } from 'react'\nimport type { ChatWidgetAdapter } from '../types'\n\nconst AdapterContext = createContext<ChatWidgetAdapter | null>(null)\n\nexport interface AdapterProviderProps {\n adapter: ChatWidgetAdapter\n children: React.ReactNode\n}\n\nexport const AdapterProvider: React.FC<AdapterProviderProps> = ({ adapter, children }) => {\n return <AdapterContext.Provider value={adapter}>{children}</AdapterContext.Provider>\n}\n\n/**\n * 读取 context 中的 adapter;若没有 Provider 包裹则返回 null。\n *\n * 适用于:\n * - 想\"优雅降级到无鉴权 fetch\"的旧调用方;\n * - 在 SSR / 测试环境里允许不挂 Provider 的工具型 hook。\n */\nexport function useAdapter(): ChatWidgetAdapter | null {\n return useContext(AdapterContext)\n}\n\n/**\n * 强制读取 adapter;缺失时抛出 Error。\n *\n * 适用于:\n * - 业务上\"没有 adapter 就不应该执行\"的关键路径(如发送消息、创建 session)。\n */\nexport function useAdapterRequired(): ChatWidgetAdapter {\n const ctx = useContext(AdapterContext)\n if (!ctx) {\n throw new Error(\n 'useAdapterRequired: missing <AdapterProvider>. ' +\n 'Wrap your tree (typically inside <ChatWidget>) so that the adapter is available.',\n )\n }\n return ctx\n}\n","import type { RefObject } from 'react'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { incCounter } from '../utils/memTelemetry'\n\nexport type TransportMode = 'ws' | 'sse'\n\nexport interface AgentInstanceState {\n agentInstanceId: number\n status: 'running' | 'paused' | 'finished' | 'stopped' | 'error'\n name?: string\n interactionId?: string\n}\n\nexport interface SessionChannelMessage {\n type: string\n data: unknown\n interactionId?: string\n agentInstanceId?: number\n seq?: number\n}\n\nexport interface AgentControlFrame {\n action: 'pause' | 'resume' | 'stop'\n agentInstanceId: number\n}\n\nexport interface UseSessionChannelOptions {\n sessionId: number | null\n wsUrl?: string | null\n token?: string | null\n transport?: TransportMode\n enabled?: boolean\n /**\n * JETP-045 P5 (P2-T11/T13):cursor 形态升级为 ``Map<\"${iid}::${callee}\", max_turn_index>``。\n * 多 callee fan-out 场景下不再撞 key(旧 ``Record<iid, max>`` 会丢一个 callee\n * 的记录)。subscribe 时序列化为 array of (interaction_id, callee_instance_id,\n * max_turn_index);后端 ``/ws/session/{id}`` handler (PR-8 P2-T14) 同时支持\n * 旧 dict 形态以兼容老前端。\n */\n turnCursorRef?: RefObject<Map<string, number>>\n onMessage?: (msg: SessionChannelMessage) => void\n onStatusEvent?: (event: SessionChannelMessage) => void\n /** Fired when the server sends DB-sourced recovery turns after detecting\n * that Redis Streams have been trimmed past the client's cursor. */\n onRecoveryTurns?: (turns: unknown[]) => void\n}\n\nexport interface UseSessionChannelReturn {\n connected: boolean\n transport: TransportMode\n agentStates: Map<number, AgentInstanceState>\n sendControlFrame: (frame: AgentControlFrame) => void\n lastSeq: number\n /** Force reconnect if WS is not connected; resolves when connected or rejects on timeout. */\n ensureConnected: () => Promise<void>\n}\n\nconst STATUS_EVENT_TYPES = new Set([\n 'agent_paused',\n 'agent_resumed',\n 'agent_stopped',\n 'interaction_started',\n 'interaction_finished',\n 'pool_snapshot',\n])\n\nfunction appendTokenQuery(baseUrl: string, token: string | null | undefined): string {\n try {\n const u = new URL(baseUrl)\n u.searchParams.set('token', token ?? '')\n return u.toString()\n } catch {\n const sep = baseUrl.includes('?') ? '&' : '?'\n return `${baseUrl}${sep}token=${encodeURIComponent(token ?? '')}`\n }\n}\n\nfunction applyStatusEvent(\n eventType: string,\n msg: SessionChannelMessage,\n prev: Map<number, AgentInstanceState>,\n): Map<number, AgentInstanceState> {\n if (eventType === 'pool_snapshot') return prev\n\n const raw = msg.data\n if (typeof raw !== 'object' || raw === null) {\n if (eventType === 'interaction_started' || eventType === 'interaction_finished') {\n const id = msg.agentInstanceId\n if (typeof id !== 'number') return prev\n const next = new Map(prev)\n const existing = next.get(id) ?? { agentInstanceId: id, status: 'running' as const }\n if (eventType === 'interaction_started') {\n next.set(id, {\n ...existing,\n interactionId: msg.interactionId ?? existing.interactionId,\n })\n } else {\n next.set(id, { ...existing, interactionId: undefined })\n }\n return next\n }\n return prev\n }\n\n const d = raw as Record<string, unknown>\n const agentInstanceId =\n typeof d.agentInstanceId === 'number' ? d.agentInstanceId : msg.agentInstanceId\n if (typeof agentInstanceId !== 'number') return prev\n\n const next = new Map(prev)\n const existing = next.get(agentInstanceId) ?? {\n agentInstanceId,\n status: 'running' as const,\n }\n const name = typeof d.name === 'string' ? d.name : existing.name\n const interactionFromData = typeof d.interactionId === 'string' ? d.interactionId : undefined\n\n switch (eventType) {\n case 'agent_paused':\n next.set(agentInstanceId, {\n ...existing,\n status: 'paused',\n name,\n interactionId: interactionFromData ?? msg.interactionId ?? existing.interactionId,\n })\n break\n case 'agent_resumed':\n next.set(agentInstanceId, {\n ...existing,\n status: 'running',\n name,\n interactionId: interactionFromData ?? msg.interactionId ?? existing.interactionId,\n })\n break\n case 'agent_stopped':\n next.set(agentInstanceId, {\n ...existing,\n status: 'stopped',\n name,\n interactionId: interactionFromData ?? msg.interactionId ?? existing.interactionId,\n })\n break\n case 'interaction_started':\n next.set(agentInstanceId, {\n ...existing,\n interactionId: interactionFromData ?? msg.interactionId ?? existing.interactionId,\n })\n break\n case 'interaction_finished':\n next.set(agentInstanceId, {\n ...existing,\n interactionId: undefined,\n })\n break\n default:\n break\n }\n return next\n}\n\nfunction parseSessionMessage(raw: unknown): SessionChannelMessage | null {\n if (raw === null || typeof raw !== 'object') return null\n const obj = raw as Record<string, unknown>\n\n // Backend WS sends frames in two formats:\n // 1. Control/meta frames: { type: \"subscribed\"|\"heartbeat\"|\"error\", ... }\n // 2. Stream data frames: { stream: \"private\"|\"status\"|\"shared\", id: \"...\", data: {...} }\n if (typeof obj.stream === 'string' && 'data' in obj) {\n const innerData = obj.data as Record<string, unknown> | undefined\n const type = (innerData && typeof innerData.type === 'string') ? innerData.type : obj.stream as string\n return {\n type,\n data: innerData ?? obj.data,\n interactionId: (innerData && typeof innerData.interaction_id === 'string')\n ? innerData.interaction_id\n : (innerData && typeof innerData.event_source_id === 'string') ? innerData.event_source_id : undefined,\n agentInstanceId: (innerData && typeof innerData.agent_instance_id === 'number')\n ? innerData.agent_instance_id : undefined,\n seq: typeof obj.seq === 'number' ? obj.seq : undefined,\n _streamTag: obj.stream as string,\n _streamId: typeof obj.id === 'string' ? obj.id : undefined,\n } as SessionChannelMessage & { _streamTag?: string; _streamId?: string }\n }\n\n const type = typeof obj.type === 'string' ? obj.type : ''\n return {\n type,\n data: 'data' in obj ? obj.data : obj,\n interactionId: typeof obj.interactionId === 'string' ? obj.interactionId : undefined,\n agentInstanceId: typeof obj.agentInstanceId === 'number' ? obj.agentInstanceId : undefined,\n seq: typeof obj.seq === 'number' ? obj.seq : undefined,\n }\n}\n\nexport function useSessionChannel(options: UseSessionChannelOptions): UseSessionChannelReturn {\n const {\n sessionId,\n wsUrl,\n token,\n transport = 'ws',\n enabled = true,\n turnCursorRef: externalTurnCursorRef,\n onMessage,\n onStatusEvent,\n onRecoveryTurns,\n } = options\n\n const wsRef = useRef<WebSocket | null>(null)\n const reconnectTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const handshakeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const heartbeatTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)\n const lastReceivedAtRef = useRef(0)\n const backoffMsRef = useRef(1000)\n const shouldReconnectRef = useRef(true)\n const handshakeConfirmedRef = useRef(false)\n const lastSeqRef = useRef(0)\n const onMessageRef = useRef(onMessage)\n const onStatusEventRef = useRef(onStatusEvent)\n const onRecoveryTurnsRef = useRef(onRecoveryTurns)\n onMessageRef.current = onMessage\n onStatusEventRef.current = onStatusEvent\n onRecoveryTurnsRef.current = onRecoveryTurns\n\n const lastStreamIdsRef = useRef({ shared: '0', status: '0', private: '0' })\n const openSocketRef = useRef<(() => void) | null>(null)\n const connectedRef = useRef(false)\n\n // JETP-045 P6 (P2-T15/T16) — recovery 上界 dedup map\n // key = `${interaction_id}::${callee_instance_id}`,value = recovery_max_turn_index\n // 用于过滤 xread 流式帧中已被 recovery_turns 覆盖的重复消息(Bug 2-D)。\n // 单 session entry 数通常 < 100,无需 LRU;session 切换时显式清空。\n const recoveryUpperBoundsRef = useRef<Map<string, number>>(new Map())\n\n const [connected, _setConnected] = useState(false)\n const setConnected = useCallback((v: boolean) => { connectedRef.current = v; _setConnected(v) }, [])\n const [agentStates, setAgentStates] = useState<Map<number, AgentInstanceState>>(() => new Map())\n const [lastSeq, setLastSeq] = useState(0)\n\n useEffect(() => {\n lastSeqRef.current = 0\n setLastSeq(0)\n setAgentStates(new Map())\n lastStreamIdsRef.current = { shared: '0', status: '0', private: '0' }\n recoveryUpperBoundsRef.current = new Map()\n }, [sessionId])\n\n useEffect(() => {\n if (transport === 'sse') {\n setConnected(true)\n return () => {\n setConnected(false)\n }\n }\n\n if (!enabled || sessionId == null || !wsUrl) {\n setConnected(false)\n return\n }\n\n shouldReconnectRef.current = true\n backoffMsRef.current = 1000\n\n const HEARTBEAT_INTERVAL = 5_000\n const HEARTBEAT_TIMEOUT = 20_000\n\n const stopHeartbeat = () => {\n if (heartbeatTimerRef.current) {\n clearInterval(heartbeatTimerRef.current)\n heartbeatTimerRef.current = null\n }\n }\n\n const startHeartbeat = (ws: WebSocket) => {\n stopHeartbeat()\n lastReceivedAtRef.current = Date.now()\n heartbeatTimerRef.current = setInterval(() => {\n if (ws.readyState !== WebSocket.OPEN) {\n stopHeartbeat()\n return\n }\n\n // Browser throttles timers in background tabs (setInterval → 1/min).\n // When we regain focus the elapsed gap is huge but the connection is\n // likely still alive. Reset the clock instead of killing the socket.\n if (document.hidden) {\n lastReceivedAtRef.current = Date.now()\n return\n }\n\n const silentMs = Date.now() - lastReceivedAtRef.current\n if (silentMs >= HEARTBEAT_TIMEOUT) {\n console.warn(`[WS] No data received for ${(silentMs / 1000).toFixed(0)}s, closing stale connection`)\n stopHeartbeat()\n ws.close(4001, 'Heartbeat timeout')\n return\n }\n try {\n ws.send(JSON.stringify({ type: 'ping' }))\n } catch { /* socket closing, onclose will handle reconnect */ }\n }, HEARTBEAT_INTERVAL)\n }\n\n const scheduleReconnect = () => {\n if (reconnectTimerRef.current) {\n clearTimeout(reconnectTimerRef.current)\n reconnectTimerRef.current = null\n }\n const delay = Math.min(backoffMsRef.current, 30000)\n backoffMsRef.current = Math.min(backoffMsRef.current * 2, 30000)\n reconnectTimerRef.current = setTimeout(() => {\n reconnectTimerRef.current = null\n if (!shouldReconnectRef.current) return\n openSocket()\n }, delay)\n }\n\n const openSocket = () => {\n if (!shouldReconnectRef.current) return\n if (reconnectTimerRef.current) {\n clearTimeout(reconnectTimerRef.current)\n reconnectTimerRef.current = null\n }\n\n const url = appendTokenQuery(wsUrl, token)\n const ws = new WebSocket(url)\n wsRef.current = ws\n\n // dev 内存埋点:ws 连接活跃数\n incCounter('ws_connect_total', 1)\n incCounter('ws_active', 1)\n let wsClosedOnce = false\n const markWsClosed = () => {\n if (wsClosedOnce) return\n wsClosedOnce = true\n incCounter('ws_active', -1)\n incCounter('ws_disconnect_total', 1)\n }\n // 把 marker 挂到 socket 上,让 effect cleanup 路径(会 null onclose)也能正确扣计数\n ;(ws as unknown as { __ymMarkClosed?: () => void }).__ymMarkClosed = markWsClosed\n\n ws.onopen = () => {\n backoffMsRef.current = 1000\n handshakeConfirmedRef.current = false\n startHeartbeat(ws)\n const ids = lastStreamIdsRef.current\n // JETP-045 P5 (P2-T13):subscribe 帧 ``turn_cursor`` 升级为 array 形式\n // [{interaction_id, callee_instance_id, max_turn_index}, ...]\n // 后端 (P2-T14) 同时支持旧 dict 形态 → 渐进升级零停机。\n const cursorMap = externalTurnCursorRef?.current\n const turnCursor: Array<{ interaction_id: string; callee_instance_id: number; max_turn_index: number }> =\n cursorMap\n ? Array.from(cursorMap.entries()).map(([k, v]) => {\n const sep = k.indexOf('::')\n if (sep < 0) {\n return { interaction_id: k, callee_instance_id: -1, max_turn_index: v }\n }\n const iid = k.slice(0, sep)\n const calleeStr = k.slice(sep + 2)\n const callee = Number(calleeStr)\n return {\n interaction_id: iid,\n callee_instance_id: Number.isFinite(callee) ? callee : -1,\n max_turn_index: v,\n }\n })\n : []\n ws.send(JSON.stringify({\n type: 'subscribe',\n last_id_shared: ids.shared,\n last_id_status: ids.status,\n last_id_private: ids.private,\n turn_cursor: turnCursor,\n }))\n\n handshakeTimerRef.current = setTimeout(() => {\n handshakeTimerRef.current = null\n if (!handshakeConfirmedRef.current && ws.readyState === WebSocket.OPEN) {\n ws.close(4000, 'Handshake timeout — no server ack received')\n }\n }, 5000)\n }\n\n ws.onmessage = (ev: MessageEvent) => {\n lastReceivedAtRef.current = Date.now()\n\n let parsed: unknown\n try {\n parsed = JSON.parse(String(ev.data))\n } catch {\n return\n }\n\n const msg = parseSessionMessage(parsed)\n if (!msg) return\n\n if (!handshakeConfirmedRef.current) {\n handshakeConfirmedRef.current = true\n setConnected(true)\n if (handshakeTimerRef.current) {\n clearTimeout(handshakeTimerRef.current)\n handshakeTimerRef.current = null\n }\n }\n\n if (msg.type === 'ping') {\n ws.send(JSON.stringify({ type: 'pong' }))\n return\n }\n\n if (msg.type === 'pong' || msg.type === 'heartbeat') {\n return\n }\n\n // JETP-045 P6 (P2-T16) — 收到 subscribed/recovery_turns 帧时填充 dedup map。\n // 上界数组形态:[{interaction_id, callee_instance_id, max_turn_index}]\n // 后端在 ``main.py`` 的 WS handler 同步下发到这两种帧(字符级一致),\n // 任意一个先到都能让前端立即去重;都缺失(旧后端)→ map 为空 → 不去重。\n const ingestRecoveryUpperBounds = (raw: Record<string, unknown> | undefined) => {\n if (!raw) return\n const arr = raw.recovery_max_turn_index\n if (!Array.isArray(arr)) return\n for (const entry of arr) {\n if (!entry || typeof entry !== 'object') continue\n const e = entry as Record<string, unknown>\n const iid = typeof e.interaction_id === 'string' ? e.interaction_id : ''\n const calleeRaw = e.callee_instance_id\n const maxRaw = e.max_turn_index\n const callee = typeof calleeRaw === 'number'\n ? calleeRaw\n : (typeof calleeRaw === 'string' && calleeRaw !== '' ? Number(calleeRaw) : NaN)\n const max = typeof maxRaw === 'number'\n ? maxRaw\n : (typeof maxRaw === 'string' && maxRaw !== '' ? Number(maxRaw) : NaN)\n if (!iid || !Number.isFinite(callee) || !Number.isFinite(max)) continue\n const key = `${iid}::${callee}`\n const prev = recoveryUpperBoundsRef.current.get(key)\n if (prev == null || max > prev) {\n recoveryUpperBoundsRef.current.set(key, max)\n }\n }\n }\n\n if (msg.type === 'subscribed') {\n ingestRecoveryUpperBounds(msg.data as Record<string, unknown> | undefined)\n }\n\n if (msg.type === 'recovery_turns') {\n const raw = msg.data as Record<string, unknown> | undefined\n ingestRecoveryUpperBounds(raw)\n const turns = raw && Array.isArray(raw.turns)\n ? raw.turns as unknown[]\n : []\n if (turns.length > 0) {\n onRecoveryTurnsRef.current?.(turns)\n }\n return\n }\n\n // JETP-045 P6 AC-RECOVERY-003 — xread 重叠帧 dedup。\n // 仅对 stream 数据帧(带 _streamTag 的实时通知)做检查;控制帧透传。\n // 判定:从 inner data 取 (interaction_id, callee_instance_id, turn_index)\n // 三者齐全且 turn_index <= recoveryUpperBoundsRef[key] → 丢弃。\n const isWithinRecoveryRange = (m: SessionChannelMessage): boolean => {\n if (recoveryUpperBoundsRef.current.size === 0) return false\n const data = m.data as Record<string, unknown> | undefined\n if (!data || typeof data !== 'object') return false\n const iid = typeof data.interaction_id === 'string'\n ? data.interaction_id\n : (typeof data.event_source_id === 'string' ? data.event_source_id : '')\n const calleeRaw = data.callee_instance_id ?? data.calleeInstanceId ?? data.agent_instance_id\n const idxRaw = data.turn_index ?? data.turnIndex\n const callee = typeof calleeRaw === 'number'\n ? calleeRaw\n : (typeof calleeRaw === 'string' && calleeRaw !== '' ? Number(calleeRaw) : NaN)\n const idx = typeof idxRaw === 'number'\n ? idxRaw\n : (typeof idxRaw === 'string' && idxRaw !== '' ? Number(idxRaw) : NaN)\n if (!iid || !Number.isFinite(callee) || !Number.isFinite(idx)) return false\n const upper = recoveryUpperBoundsRef.current.get(`${iid}::${callee}`)\n return upper != null && idx <= upper\n }\n\n if (typeof msg.seq === 'number') {\n lastSeqRef.current = msg.seq\n setLastSeq(msg.seq)\n }\n\n const extMsg = msg as SessionChannelMessage & { _streamTag?: string; _streamId?: string }\n const isStreamFrame = !!(extMsg._streamTag && extMsg._streamId)\n if (isStreamFrame) {\n const tag = extMsg._streamTag as keyof typeof lastStreamIdsRef.current\n if (tag in lastStreamIdsRef.current) {\n lastStreamIdsRef.current[tag] = extMsg._streamId as string\n }\n delete extMsg._streamTag\n delete extMsg._streamId\n }\n\n // JETP-045 P6 AC-RECOVERY-003 — 仅对 stream 数据帧执行 recovery dedup。\n if (isStreamFrame && isWithinRecoveryRange(msg)) {\n if (typeof console !== 'undefined' && typeof console.debug === 'function') {\n console.debug(\n '[recovery_dedup] dropping xread frame within recovery range',\n { type: msg.type },\n )\n }\n return\n }\n\n onMessageRef.current?.(msg)\n\n if (STATUS_EVENT_TYPES.has(msg.type)) {\n onStatusEventRef.current?.(msg)\n setAgentStates((prev) => applyStatusEvent(msg.type, msg, prev))\n }\n }\n\n ws.onerror = () => {}\n\n ws.onclose = () => {\n markWsClosed()\n stopHeartbeat()\n handshakeConfirmedRef.current = false\n if (handshakeTimerRef.current) {\n clearTimeout(handshakeTimerRef.current)\n handshakeTimerRef.current = null\n }\n setConnected(false)\n if (wsRef.current === ws) {\n wsRef.current = null\n }\n if (shouldReconnectRef.current) {\n scheduleReconnect()\n }\n }\n }\n\n // When tab returns to foreground, reset heartbeat clock and send an\n // immediate ping so we detect a dead connection quickly.\n const onVisibilityChange = () => {\n if (!document.hidden) {\n lastReceivedAtRef.current = Date.now()\n const ws = wsRef.current\n if (ws && ws.readyState === WebSocket.OPEN) {\n try { ws.send(JSON.stringify({ type: 'ping' })) } catch { /* ignore */ }\n }\n }\n }\n document.addEventListener('visibilitychange', onVisibilityChange)\n\n openSocketRef.current = openSocket\n openSocket()\n\n return () => {\n document.removeEventListener('visibilitychange', onVisibilityChange)\n openSocketRef.current = null\n shouldReconnectRef.current = false\n handshakeConfirmedRef.current = false\n stopHeartbeat()\n if (reconnectTimerRef.current) {\n clearTimeout(reconnectTimerRef.current)\n reconnectTimerRef.current = null\n }\n if (handshakeTimerRef.current) {\n clearTimeout(handshakeTimerRef.current)\n handshakeTimerRef.current = null\n }\n const w = wsRef.current\n if (w) {\n // 主动卸载路径下 onclose 被置 null,这里手工调埋点 marker 扣计数。\n ;(w as unknown as { __ymMarkClosed?: () => void }).__ymMarkClosed?.()\n w.onclose = null\n w.close()\n wsRef.current = null\n }\n setConnected(false)\n }\n }, [sessionId, wsUrl, token, transport, enabled])\n\n const sendControlFrame = useCallback((frame: AgentControlFrame) => {\n const ws = wsRef.current\n if (!ws || ws.readyState !== WebSocket.OPEN) return\n ws.send(JSON.stringify({ type: 'control_agent', ...frame }))\n }, [])\n\n const ensureConnected = useCallback((): Promise<void> => {\n if (connectedRef.current && wsRef.current?.readyState === WebSocket.OPEN) {\n return Promise.resolve()\n }\n\n const existing = wsRef.current\n if (existing && existing.readyState === WebSocket.CONNECTING) {\n return new Promise<void>((resolve, reject) => {\n const tid = setTimeout(() => { reject(new Error('WS connect timeout')) }, 8_000)\n const orig = existing.onopen\n existing.onopen = (ev) => {\n clearTimeout(tid)\n if (typeof orig === 'function') orig.call(existing, ev)\n resolve()\n }\n })\n }\n\n if (existing) {\n ;(existing as unknown as { __ymMarkClosed?: () => void }).__ymMarkClosed?.()\n existing.onclose = null\n existing.close()\n wsRef.current = null\n }\n\n openSocketRef.current?.()\n\n const ws = wsRef.current\n if (!ws) return Promise.reject(new Error('WS not available'))\n\n return new Promise<void>((resolve, reject) => {\n const tid = setTimeout(() => { reject(new Error('WS connect timeout')) }, 8_000)\n const origOpen = ws.onopen\n ws.onopen = (ev) => {\n clearTimeout(tid)\n if (typeof origOpen === 'function') origOpen.call(ws, ev)\n resolve()\n }\n const origClose = ws.onclose\n ws.onclose = (ev) => {\n clearTimeout(tid)\n if (typeof origClose === 'function') origClose.call(ws, ev)\n reject(new Error(`WS closed: ${ev.code}`))\n }\n })\n }, [])\n\n return {\n connected,\n transport,\n agentStates,\n sendControlFrame,\n lastSeq,\n ensureConnected,\n }\n}\n","/**\n * usePoolObservation — observation-driven agent pool status\n *\n * Hybrid push+poll strategy:\n * Push: pool_snapshot events from the WS status stream give near-instant updates.\n * Poll: GET /api/monitor/pool/{session_id} at adaptive intervals as a reliable fallback.\n *\n * Consumers:\n * - Top bar: sessionBusy (any RUNNING agent in the session)\n * - Child agent cards: instanceStates.get(agentInstanceId)\n * - Input box: caller checks the primary agent instance via instanceStates\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { ChatWidgetAdapter, PoolAgent, PoolAgentAction, PoolStatusResponse } from '../types'\nimport type { SessionChannelMessage } from './useSessionChannel'\n\nconst POLL_INTERVAL_BUSY = 3_000\nconst POLL_INTERVAL_IDLE = 15_000\n\nexport interface PoolObservation {\n sessionBusy: boolean\n instanceStates: Map<number, PoolAgent>\n poolAgents: PoolAgent[]\n}\n\nconst EMPTY_MAP = new Map<number, PoolAgent>()\nconst EMPTY: PoolObservation = { sessionBusy: false, instanceStates: EMPTY_MAP, poolAgents: [] }\n\n// JETP-074(无退化路径版):缺 client_id 的 agent 直接从 observation 中剔除,\n// 不再 silent 让它进 cubicle 分组的 fallback。这样上游 useDeriveCubicleClients\n// 可以严格按 cid 分组,任何缺 cid 的 leak 都能在 console 立刻看到。\nfunction isValidPoolAgent(a: PoolAgent): boolean {\n if (typeof a.client_id !== 'string' || !a.client_id) {\n console.error(\n '[JETP-074] usePoolObservation drop PoolAgent without client_id:',\n { agent_instance_id: a.agent_instance_id, agent_id: a.agent_id, state: a.state },\n )\n return false\n }\n return true\n}\n\nfunction buildObservation(agents: PoolAgent[]): PoolObservation {\n const map = new Map<number, PoolAgent>()\n let busy = false\n const valid: PoolAgent[] = []\n for (const a of agents) {\n if (!isValidPoolAgent(a)) continue\n map.set(a.agent_instance_id, a)\n if (a.state === 'RUNNING') busy = true\n valid.push(a)\n }\n return { sessionBusy: busy, instanceStates: map, poolAgents: valid }\n}\n\nexport interface UsePoolObservationOptions {\n adapter: ChatWidgetAdapter\n sessionId: number | null\n enabled?: boolean\n}\n\nexport function usePoolObservation(options: UsePoolObservationOptions): {\n observation: PoolObservation\n handlePoolSnapshot: (msg: SessionChannelMessage) => void\n} {\n const { adapter, sessionId, enabled = true } = options\n const [observation, setObservation] = useState<PoolObservation>(EMPTY)\n const busyRef = useRef(false)\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const mountedRef = useRef(true)\n\n const canPoll = enabled && sessionId != null && typeof adapter.getPoolStatus === 'function'\n\n const doPoll = useCallback(async () => {\n if (!canPoll || sessionId == null) return\n try {\n const res: PoolStatusResponse = await adapter.getPoolStatus!(sessionId)\n if (!mountedRef.current) return\n const obs = buildObservation(res.agents ?? [])\n busyRef.current = obs.sessionBusy\n setObservation(obs)\n } catch {\n // network hiccup — keep last state, retry on next interval\n }\n }, [adapter, sessionId, canPoll])\n\n // Push handler: apply a single pool_snapshot event from the WS status stream\n const handlePoolSnapshot = useCallback((msg: SessionChannelMessage) => {\n if (msg.type !== 'pool_snapshot') return\n const d = msg.data as Record<string, unknown> | null\n if (!d || typeof d !== 'object') return\n const instanceId = d.agent_instance_id as number | undefined\n if (typeof instanceId !== 'number') return\n\n // JETP-074(无退化路径版):cid 是 PoolAgent 的硬必须字段。\n // - 已知该 instance 之前注册过(existing)→ 复用 existing.client_id\n // 即可(cid 业务上 immutable),新 patch 不带 cid 不致命\n // - 第一次见到该 instance 且 patch 不带 cid → 拒绝写入 + 报错,\n // 避免一个无 cid 的 PoolAgent 进 observation 然后被 useDeriveCubicleClients\n // 悄悄合并到 default-room\n const rawCid = typeof d.client_id === 'string' ? d.client_id.trim() : ''\n const cidFromPatch = rawCid.length > 0 ? rawCid : undefined\n\n setObservation(prev => {\n const existing = prev.instanceStates.get(instanceId)\n const resolvedCid = cidFromPatch ?? existing?.client_id\n if (!resolvedCid) {\n console.error(\n '[JETP-074] usePoolObservation drop pool_snapshot push without client_id:',\n { agent_instance_id: instanceId, agent_id: d.agent_id, state: d.state },\n )\n return prev\n }\n const patch: PoolAgent = {\n agent_instance_id: instanceId,\n agent_id: (d.agent_id as string) ?? existing?.agent_id ?? '',\n agent_alias: (d.agent_alias as string | undefined) ?? existing?.agent_alias,\n state: (d.state as string) ?? 'RUNNING',\n task_purpose: (d.task_purpose as string) ?? existing?.task_purpose,\n recent_actions: Array.isArray(d.recent_actions)\n ? (d.recent_actions as PoolAgentAction[])\n : existing?.recent_actions,\n client_id: resolvedCid,\n }\n const next = new Map(prev.instanceStates)\n next.set(instanceId, patch)\n const agents = Array.from(next.values())\n const busy = agents.some(a => a.state === 'RUNNING')\n busyRef.current = busy\n return { sessionBusy: busy, instanceStates: next, poolAgents: agents }\n })\n }, [])\n\n // Adaptive polling loop\n useEffect(() => {\n mountedRef.current = true\n if (!canPoll) {\n setObservation(EMPTY)\n busyRef.current = false\n return\n }\n\n doPoll()\n\n const schedule = () => {\n if (timerRef.current) clearTimeout(timerRef.current)\n const interval = busyRef.current ? POLL_INTERVAL_BUSY : POLL_INTERVAL_IDLE\n timerRef.current = setTimeout(() => {\n if (!mountedRef.current) return\n doPoll().then(schedule)\n }, interval)\n }\n schedule()\n\n return () => {\n mountedRef.current = false\n if (timerRef.current) {\n clearTimeout(timerRef.current)\n timerRef.current = null\n }\n }\n }, [canPoll, doPoll])\n\n return { observation, handlePoolSnapshot }\n}\n","/**\n * `useSessionClients` — session(项目)下的 client(任务话池)列表\n *\n * 概念模型(JETP-058 v2-only 后已稳态):\n * - session 视为「项目」;\n * - client(``c_<22>``)视为「任务话池」;\n * - 一个 session 可以有 N 个对等 cid,没有「主对话」概念。\n * 某个 cid 是不是当前正在看的,由上层 ChatWidget 的 ``currentClientId`` 状态决定,\n * 与 hook 无关。\n *\n * 工业级保障:\n * - SessionId 切换时自动重拉,并丢弃过期请求结果(StaleResponseGuard via local seq)。\n * - 单飞(in-flight)保护:同 sessionId 短时间内重复 refresh,复用同一 fetch Promise。\n * - 失败时保留旧 items,仅写入 error;不清空(保护 UI 不闪烁)。\n * - prependLocal 提供乐观插入用于 createClient 后立即可见,按 id 去重并提升到顶部。\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport type { ChatWidgetAdapter } from '../types'\nimport { useAuthedFetch } from './useAuthedFetch'\n\nexport interface ClientItem {\n id: string\n title: string\n contextPreloads: unknown[]\n isLegacy: boolean\n archived: boolean\n lastActiveAt: number\n}\n\nexport interface UseSessionClientsReturn {\n items: ClientItem[]\n loading: boolean\n error: Error | null\n refresh: () => Promise<void>\n /** 局部更新(新建后乐观插入);按 id 去重并置顶。 */\n prependLocal: (it: ClientItem) => void\n /**\n * 已成功拉到 ``items`` 的 sessionId(成功或失败均更新;失败时 ``items`` 保留旧值,但本字段仍前推\n * → 上层可据此判断\"对当前 sid 至少完成过一次拉取\",避免 React useEffect 闭包时序坑:\n * 同 commit 内 hook 的 setLoading(true) 还没生效时,上层 useEffect 看到的是上一渲染的 false,\n * 仅靠 ``loading`` 守门会被绕过 → 误判该 session 是空 session 而 POST 创建新 cid。\n * 必须改用 ``loadedSessionId === currentSessionId`` 的正向断言。\n */\n loadedSessionId: string | number | null\n}\n\ninterface ServerClient {\n id: string\n title?: string\n context_preloads?: unknown[]\n is_legacy?: boolean\n archived?: boolean\n last_active_at?: number\n}\n\n/**\n * 业务错误:HTTP 200 但 jetagents ResponseModel.code !== 200 时由 refresh 抛出。\n *\n * 上层(如 ChatWidget init-effect)可以 ``err instanceof BusinessError`` 区分:\n * - 网络/服务故障(普通 Error) → 可重试\n * - 业务级拒绝(如 \"Session not allowed\")→ 不应自动重试或自动建空 client\n */\nexport class BusinessError extends Error {\n code: number\n constructor(code: number, message: string) {\n super(message)\n this.code = code\n this.name = 'BusinessError'\n }\n}\n\nfunction mapItem(x: ServerClient): ClientItem {\n return {\n id: String(x.id),\n title: String(x.title ?? ''),\n contextPreloads: Array.isArray(x.context_preloads) ? x.context_preloads : [],\n isLegacy: Boolean(x.is_legacy),\n archived: Boolean(x.archived),\n lastActiveAt: Number(x.last_active_at ?? 0),\n }\n}\n\n/**\n * @param sessionId 当前 session ID;为 `null` 时不发起请求。\n * @param apiBase 可选 API 基地址(如 ``'https://api.example.com'``);缺省走同源相对路径。\n * @param opts.adapter JETP-056:完整 ChatWidgetAdapter;走 useAuthedFetch 统一鉴权。\n * @param opts.getAuthHeaders JETP-054 hotfix(兼容期保留):仅注入 JWT/Bearer 头。\n */\nexport function useSessionClients(\n sessionId: string | number | null,\n apiBase = '',\n opts?: {\n adapter?: ChatWidgetAdapter | null\n getAuthHeaders?: () => Record<string, string>\n },\n): UseSessionClientsReturn {\n const [items, setItems] = useState<ClientItem[]>([])\n const [loading, setLoading] = useState<boolean>(false)\n const [error, setError] = useState<Error | null>(null)\n // 已完成(成功或失败)至少一次拉取的 sessionId。null 表示从未拉过任何 session。\n const [loadedSessionId, setLoadedSessionId] = useState<string | number | null>(null)\n\n const seqRef = useRef(0)\n const inflightRef = useRef<Promise<void> | null>(null)\n const baseRef = useRef<string>(apiBase)\n baseRef.current = apiBase\n\n // JETP-056:优先 adapter;否则用 getAuthHeaders shim;都无时退化为透明 fetch。\n const shimAdapter = useMemo<ChatWidgetAdapter | null>(() => {\n if (opts?.adapter) return opts.adapter\n if (opts?.getAuthHeaders) {\n return { getAuthHeaders: opts.getAuthHeaders } as unknown as ChatWidgetAdapter\n }\n return null\n }, [opts?.adapter, opts?.getAuthHeaders])\n const authedFetch = useAuthedFetch(shimAdapter)\n\n const refresh = useCallback(async (): Promise<void> => {\n if (sessionId === null || sessionId === undefined || sessionId === '') return\n if (inflightRef.current) {\n console.debug('[USC] refresh skipped (inflight reused)', { sid: sessionId, seq: seqRef.current })\n return inflightRef.current\n }\n\n const mySeq = ++seqRef.current\n setLoading(true)\n const base = baseRef.current.replace(/\\/+$/, '')\n const url = `${base}/api/session/${encodeURIComponent(String(sessionId))}/clients`\n console.debug('[USC] refresh START', { sid: sessionId, seq: mySeq, url })\n\n const job = (async () => {\n try {\n const resp = await authedFetch(url)\n if (mySeq !== seqRef.current) {\n console.debug('[USC] refresh STALE after fetch', { sid: sessionId, mySeq, curSeq: seqRef.current })\n return\n }\n if (!resp.ok) {\n throw new Error(`list clients HTTP ${resp.status}`)\n }\n // jetagents ResponseModel: {code, session_id, message, data}\n // - 业务成功: HTTP 200 + code=200 + data={items, ...}\n // - 业务错误: HTTP 200 + code=400 + data={} (resp.ok 仍为 true)\n // 兼容: 若直接返回 plain {items} 也可(极旧版本/mock)。\n // 必须显式检查 wrapper.code,否则 \"Session not allowed\" 会被误当成\"无 client\",\n // 让上层 init-effect 误以为是空 session 而无限 POST 创建新 cid。\n const wrapper = (await resp.json()) as\n | { code?: number; message?: string; data?: { items?: ServerClient[] } }\n | { items?: ServerClient[] }\n if (mySeq !== seqRef.current) {\n console.debug('[USC] refresh STALE after json', { sid: sessionId, mySeq, curSeq: seqRef.current })\n return\n }\n const isWrapped =\n wrapper && typeof wrapper === 'object' && 'code' in wrapper && 'data' in wrapper\n if (isWrapped) {\n const wrappedCode = (wrapper as { code?: number }).code\n if (typeof wrappedCode === 'number' && wrappedCode !== 200) {\n const businessMsg =\n ((wrapper as { message?: string }).message?.trim()) || `business error code=${wrappedCode}`\n throw new BusinessError(wrappedCode, businessMsg)\n }\n }\n const payload =\n isWrapped\n ? (wrapper as { data?: { items?: ServerClient[] } }).data ?? (wrapper as { items?: ServerClient[] })\n : (wrapper as { items?: ServerClient[] })\n const mapped = (Array.isArray(payload?.items) ? payload!.items! : []).map(mapItem)\n console.debug('[USC] refresh OK', { sid: sessionId, seq: mySeq, count: mapped.length, ids: mapped.map(m => m.id), archivedCount: mapped.filter(m => m.archived).length })\n setItems(mapped)\n setError(null)\n } catch (e) {\n if (mySeq !== seqRef.current) return // stale\n console.debug('[USC] refresh ERROR', { sid: sessionId, seq: mySeq, err: String(e) })\n setError(e as Error)\n // 不清空 items,保持上一次成功结果以避免 UI 闪烁\n } finally {\n if (mySeq === seqRef.current) {\n setLoading(false)\n // 关键:成功/失败均标记 loadedSessionId,让上层能用正向断言守门\n // (sessionId 切换时本字段已先被重置为 null,见下面的 useEffect)。\n setLoadedSessionId(sessionId)\n console.debug('[USC] refresh FIN setLoadedSessionId', { sid: sessionId, seq: mySeq })\n }\n inflightRef.current = null\n }\n })()\n\n inflightRef.current = job\n await job\n }, [sessionId, authedFetch])\n\n // sessionId 切换 → 重拉;切换瞬间清空 items 让 UI 不串。\n // 关键:**任何 sessionId 变化(包括 valid → valid)都必须**:\n // 1) seq++ 让旧 fetch 的 setItems 写入 stale-skip;\n // 2) inflightRef 置空,否则同一 hook 实例的新 sessionId refresh 会复用旧 Promise → 永远不发新请求;\n // 3) setItems([]) 清空,避免上层 useEffect 看到上个 session 残留 items 误判;\n // 4) setLoadedSessionId(null) 让上层\"loadedSessionId === currentSessionId\"的正向守门\n // 在新 fetch 完成前一直为 false(仅靠 loading 守门会被 useEffect 闭包时序绕过)。\n useEffect(() => {\n if (sessionId === null || sessionId === undefined || sessionId === '') {\n console.debug('[USC] sid effect → reset (null sid)')\n seqRef.current++\n inflightRef.current = null\n setItems([])\n setError(null)\n setLoading(false)\n setLoadedSessionId(null)\n return\n }\n console.debug('[USC] sid effect → reset+refresh', { sid: sessionId, prevSeq: seqRef.current })\n seqRef.current++\n inflightRef.current = null\n setItems([])\n setError(null)\n setLoading(true)\n setLoadedSessionId(null)\n void refresh()\n }, [sessionId, refresh])\n\n const prependLocal = useCallback((it: ClientItem) => {\n setItems(prev => {\n const filtered = prev.filter(x => x.id !== it.id)\n return [it, ...filtered]\n })\n }, [])\n\n // 同 useClientIdAllocator:把返回对象 useMemo 起来。即便所有字段单独都是稳定的,\n // 裸对象字面量每次 render 都是新引用,上层若整体放入 deps(少数旧用例)会被牵连重渲染。\n // 当前 ChatWidget 用的是解构(每个字段单独),其实不会受影响;这里 memoize 是防御。\n return useMemo(\n () => ({ items, loading, error, refresh, prependLocal, loadedSessionId }),\n [items, loading, error, refresh, prependLocal, loadedSessionId],\n )\n}\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\n/**\n * JETP-054 — `client_id` 协议守门错误。\n *\n * 抛出场景(前端硬错误,不再 silent fallback 'main'):\n * 1. session 已就绪但 v2 client_id 分配在 N 次重试后仍失败;\n * 2. 调用方(adapter / controller)在到达发送层时仍未拿到合法 cid;\n * 3. 后端在 strict 模式下返回 `CLIENT_ID_REQUIRED` 4xx(统一映射到本错误)。\n *\n * 设计意图:\n * - 把\"路径异常\"显式化,便于上层 toast / retry / 上报;\n * - 与后端 `ClientIdRequiredError` 形成端到端契约对齐;\n * - 与 `ChatWidgetAuthError` / `ChatWidgetNetworkError` 同级别,可被业务统一捕获。\n */\nexport class InvalidClientIdError extends Error {\n readonly name = 'InvalidClientIdError' as const\n\n constructor(\n message: string,\n public readonly reason:\n | 'missing'\n | 'session_not_ready'\n | 'allocation_failed'\n | 'legacy_main'\n | 'legacy_format'\n | 'session_forbidden',\n /*\n * JETP-058 v2-only: 'legacy_format' 是新增的硬错误 reason,\n * 表示拿到了非 v2 的字面量('main' / 'file:*' / 'sel:*' / '' / 短串等),\n * 与原有 'legacy_main' 区分,便于上层 toast 和 telemetry 区分根因。\n *\n * 'session_forbidden': 当前用户被后端 ACL 拒绝访问该 session(典型 wrapper.code=400\n * \"Session not allowed\"),由 ChatWidget.cidGuardedControllerSendMessage 在 send\n * 路径上短路抛出,避免在已知禁入的情况下继续 POST /clients 浪费 round-trip 并污染\n * Unhandled Promise Rejection。上层(DefaultComposer 等 fire-and-forget 的发送)\n * 应 .catch 静默吞掉;UI 侧错误已通过 SessionForbiddenBanner 展示。\n */\n public readonly sessionId?: string | number | null,\n ) {\n super(message)\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { ChatWidgetAdapter, PendingHIL } from '../types.js'\nimport { ChatWidgetAuthError } from '../errors.js'\n\nexport interface UseGenUIPendingOptions {\n /**\n * Adapter from `<ChatWidget>`. When the adapter does not implement\n * `getPendingHILs` (`supported` will be `false`), the hook short-circuits\n * to an empty list — host UI should hide the pending indicator and rely\n * on live-only HIL behaviour (pre-WS3.7.6).\n */\n adapter: ChatWidgetAdapter | null | undefined\n /**\n * Active session id. The hook re-runs whenever this changes so a fresh\n * client opening session_a then session_b will hydrate twice.\n * `null` / `undefined` → no fetch.\n */\n sessionId: number | null | undefined\n /**\n * External refresh trigger. Recommended caller hooks: WebSocket\n * `hil_created` / `hil_resolved` / `hil_cancelled` events from\n * `useSessionChannel`; chat-widget refresh button; visibility-change\n * (tab returns to foreground).\n *\n * Any monotonic increase forces a re-fetch.\n */\n refreshKey?: number\n /**\n * Optional periodic poll interval in ms. Phase 1 default is \"no poll\"\n * — the WS3.7.4 push fanout already keeps clients in sync; this hook\n * is for *connect-time* hydration. Hosts that don't have a downlink\n * channel may opt-in to polling.\n */\n pollMs?: number\n /**\n * Adapter 401 hook — typically the same callback you wire on the\n * widget's `onAuthFailure`.\n */\n onAuthFailure?: () => void\n /**\n * Generic failure hook. Phase 1 hydration is best-effort; failure is\n * surfaced here but the hook itself does not fall back to throwing.\n */\n onError?: (err: unknown) => void\n}\n\nexport interface UseGenUIPendingReturn {\n pending: PendingHIL[]\n loading: boolean\n /** Adapter implements `getPendingHILs`. */\n supported: boolean\n /**\n * Most recent fetch error (or `null` after a successful reload).\n */\n error: unknown\n /**\n * Imperative re-fetch — call after submitting a HIL response so the\n * pending list shrinks immediately (alternative: bump `refreshKey`).\n */\n refresh: () => void\n}\n\n/**\n * `useGenUIPending` — JETP-083 WS3.7.6 connect-time HIL hydration hook.\n *\n * Returns the list of *currently pending* Collaborative HIL entities\n * visible to the connecting principal in the active session. The\n * acceptance scenario is \"open a fresh client → see your pending HILs\"\n * (per JETP-083 phase 1 README §2.WS3.7.6).\n *\n * The hook does *not* render UI; consumers (the widget itself,\n * `<HILPendingBanner>`, host shells) decide how to surface the pending\n * count. Suggested patterns:\n *\n * - Show a banner \"{N} pending approvals on this session\" with a click\n * → scroll to the spec.\n * - Decorate spec cards in `<MessageList>` with an \"awaiting your input\"\n * ribbon when `pending.find(p => p.specId === spec.id)`.\n * - Pre-flight a chime / browser notification on the *first* hydration\n * (use a ref to skip subsequent re-fetches).\n *\n * Failure mode: hydration failures NEVER block the widget. We log via\n * `onError` and return the previous successful list (or `[]` on first\n * fetch). Acceptance for WS3.7.6 explicitly tolerates \"endpoint missing\"\n * (older backend) by setting `supported=false`.\n */\nexport function useGenUIPending(options: UseGenUIPendingOptions): UseGenUIPendingReturn {\n const { adapter, sessionId, refreshKey, pollMs, onAuthFailure, onError } = options\n\n const [pending, setPending] = useState<PendingHIL[]>([])\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<unknown>(null)\n const supported = !!adapter?.getPendingHILs\n\n const inFlightRef = useRef<AbortController | null>(null)\n const refreshRef = useRef<() => void>(() => {})\n\n const fetchOnce = useCallback(async () => {\n if (!adapter?.getPendingHILs || sessionId == null) {\n setPending([])\n return\n }\n inFlightRef.current?.abort()\n const ctrl = new AbortController()\n inFlightRef.current = ctrl\n setLoading(true)\n try {\n const list = await adapter.getPendingHILs(sessionId)\n if (!ctrl.signal.aborted) {\n setPending(list)\n setError(null)\n }\n } catch (e) {\n if (ctrl.signal.aborted) return\n if (e instanceof ChatWidgetAuthError) {\n try { onAuthFailure?.() } catch { /* noop */ }\n }\n setError(e)\n try { onError?.(e) } catch { /* noop */ }\n // Keep last successful pending list; first-fetch failure leaves [].\n } finally {\n if (!ctrl.signal.aborted) setLoading(false)\n }\n }, [adapter, sessionId, onAuthFailure, onError])\n\n refreshRef.current = fetchOnce\n\n // Initial fetch + react to sessionId / refreshKey changes\n useEffect(() => {\n if (!supported || sessionId == null) {\n setPending([])\n return\n }\n void fetchOnce()\n return () => {\n inFlightRef.current?.abort()\n }\n }, [supported, sessionId, refreshKey, fetchOnce])\n\n // Optional polling (off by default per Phase 1)\n useEffect(() => {\n if (!supported || sessionId == null || !pollMs || pollMs <= 0) return\n const t = window.setInterval(() => { void fetchOnce() }, pollMs)\n return () => { window.clearInterval(t) }\n }, [supported, sessionId, pollMs, fetchOnce])\n\n return {\n pending,\n loading,\n supported,\n error,\n refresh: useCallback(() => { refreshRef.current() }, []),\n }\n}\n","/**\n * 置顶区域组件\n * 显示当前置顶轮次的用户消息、任务计划和 Todo\n */\n\nimport React, { useMemo } from 'react'\nimport type { PinnedAreaProps } from '../types'\nimport { useChatWidgetI18n } from '../i18n'\nimport PlanCard from './PlanCard'\nimport { TodoCardMulti } from './TodoCard'\nimport UserMessageContent from './UserMessageContent'\nimport CollapsibleContent from './CollapsibleContent'\nimport './PinnedArea.css'\n\nconst ATTACHMENT_RE = /\\[附件:[^\\]]+\\]/g\nconst ATTACH_ROW_HEIGHT = 60\n\nconst PinnedArea: React.FC<PinnedAreaProps> = ({ \n round, \n isTransitioning,\n todoMap,\n}) => {\n const { messages, locale, t } = useChatWidgetI18n()\n\n const collapsibleMax = useMemo(() => {\n const msg = round?.userMessage || ''\n const matches = msg.match(ATTACHMENT_RE)\n if (!matches || matches.length === 0) return 120\n const rows = Math.ceil(matches.length / 2)\n return 120 + rows * ATTACH_ROW_HEIGHT\n }, [round?.userMessage])\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(locale, {\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=\"ycw-pinned-area\">\n <div className={`ycw-pinned-content ${isTransitioning ? 'ycw-fade-out' : ''}`}>\n <div className=\"ycw-pinned-user-message\">\n <CollapsibleContent maxHeight={collapsibleMax}>\n {round.userMessage\n ? <UserMessageContent text={round.userMessage} stripSkillTemplate={t('skill.inlineLabel')} />\n : messages['pinned.noMessage']}\n </CollapsibleContent>\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=\"ycw-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, PlanItem } from '../types'\nimport { useChatWidgetI18n } from '../i18n'\nimport { useInteractionDispatch } from '../hooks/useInteractionDispatch'\nimport { Icon } from './Icon/Icon'\nimport type { IconName } from './Icon/Icon'\nimport './PlanCard.css'\n\nfunction planItemIconName(status: PlanItem['status']): IconName {\n switch (status) {\n case 'completed':\n return 'check'\n case 'active':\n return 'caretRight'\n case 'error':\n return 'x'\n default:\n return 'circle'\n }\n}\n\nconst PlanCard: React.FC<PlanCardProps> = ({ \n plan, \n status,\n compact = false,\n}) => {\n const { t } = useChatWidgetI18n()\n const emitInteraction = useInteractionDispatch()\n\n if (compact) {\n // 紧凑模式:单行显示\n return (\n <div className=\"ycw-plan-card-compact\">\n <span className=\"ycw-plan-icon\">\n <Icon name=\"list\" size={14} aria-hidden={true} />\n </span>\n <span className=\"ycw-plan-items-inline\">\n {plan.items.map((item, i) => (\n <span key={i} className=\"ycw-plan-item-inline\" data-state={item.status}>\n [\n <Icon name={planItemIconName(item.status)} size={12} aria-hidden={true} />\n {' '}\n {item.text}\n ]\n </span>\n ))}\n </span>\n </div>\n )\n }\n\n return (\n <div\n className=\"ycw-plan-card\"\n data-state={status === 'completed' ? 'completed' : undefined}\n >\n <div className=\"ycw-plan-header\">\n <div className=\"ycw-plan-title\">\n <span className=\"ycw-plan-icon\">\n <Icon name=\"list\" size={14} aria-hidden={true} />\n </span>\n <span>{t('plan.title')}</span>\n </div>\n <span className=\"ycw-plan-progress\">\n ({plan.progress.completed}/{plan.progress.total})\n </span>\n </div>\n <ul className=\"ycw-plan-items\">\n {plan.items.map((item, index) => (\n <li\n key={index}\n className=\"ycw-plan-item\"\n data-state={item.status}\n onClick={() => emitInteraction('plan-step-click', item.text, { index, status: item.status })}\n style={{ cursor: 'pointer' }}\n >\n <span className=\"ycw-plan-item-icon\">\n <Icon name={planItemIconName(item.status)} size={14} aria-hidden={true} />\n </span>\n <span className=\"ycw-plan-item-text\">{item.text}</span>\n {item.status === 'active' && (\n <span className=\"ycw-plan-item-status\">{t('plan.status.active')}</span>\n )}\n </li>\n ))}\n </ul>\n </div>\n )\n}\n\nexport default PlanCard\n","import React, { useEffect, useState } from 'react'\nimport type { Icon as PhosphorIcon } from '@phosphor-icons/react'\nimport type { IconName } from './iconMap'\nimport { loadIcons } from './iconMap'\nimport './Icon.css'\n\nexport type IconWeight = 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone'\n\nexport interface IconProps {\n name: IconName\n size?: number\n weight?: IconWeight\n className?: string\n color?: string\n style?: React.CSSProperties\n 'aria-hidden'?: boolean\n 'aria-label'?: string\n}\n\nconst Icon: React.FC<IconProps> = ({\n name,\n size = 16,\n weight = 'regular',\n className = '',\n color,\n style,\n 'aria-hidden': ariaHidden = true,\n 'aria-label': ariaLabel,\n}) => {\n const [IconComponent, setIconComponent] = useState<PhosphorIcon | null>(null)\n\n useEffect(() => {\n let cancelled = false\n loadIcons().then(map => {\n if (!cancelled) {\n const ic = map.get(name)\n if (ic) setIconComponent(() => ic)\n }\n })\n return () => { cancelled = true }\n }, [name])\n\n if (!IconComponent) {\n return (\n <span\n className={`ycw-icon ycw-icon-fallback ${className}`}\n style={{ width: size, height: size, fontSize: size, lineHeight: `${size}px`, ...style }}\n aria-hidden={ariaHidden}\n aria-label={ariaLabel}\n role={ariaLabel ? 'img' : undefined}\n />\n )\n }\n\n return (\n <IconComponent\n size={size}\n weight={weight}\n color={color}\n className={`ycw-icon ${className}`}\n style={style}\n aria-hidden={ariaHidden}\n aria-label={ariaLabel}\n role={ariaLabel ? 'img' : undefined}\n />\n )\n}\n\nexport { Icon }\nexport type { IconName }\n","import type { Icon as PhosphorIcon } from '@phosphor-icons/react'\n\nexport type IconName =\n | 'robot'\n | 'chat'\n | 'clipboard'\n | 'paperclip'\n | 'chart'\n | 'notepad'\n | 'warning'\n | 'check'\n | 'checkCircle'\n | 'hourglass'\n | 'spinner'\n | 'x'\n | 'xCircle'\n | 'circle'\n | 'caretDown'\n | 'caretRight'\n | 'lightning'\n | 'gear'\n | 'play'\n | 'brain'\n | 'list'\n | 'file'\n | 'fileText'\n | 'fileCode'\n | 'filePdf'\n | 'filePlus'\n | 'fileXls'\n | 'fileDoc'\n | 'filePpt'\n | 'fileCsv'\n | 'fileZip'\n | 'download'\n | 'arrowsOut'\n | 'arrowsIn'\n | 'arrowUp'\n | 'minus'\n | 'magnifyingGlass'\n | 'globe'\n | 'code'\n | 'terminal'\n | 'package'\n | 'copy'\n | 'link'\n | 'share'\n | 'arrowLeft'\n | 'info'\n | 'compress'\n | 'eye'\n | 'circuitry'\n | 'user'\n | 'image'\n | 'folder'\n | 'folderOpen'\n | 'house'\n | 'pencilSimple'\n | 'chatCircleDots'\n | 'pushPin'\n | 'pause'\n | 'stop'\n | 'table'\n | 'layers'\n | 'brackets'\n | 'usersThree'\n | 'uploadSimple'\n | 'plus'\n | 'folderPlus'\n | 'arrowRight'\n | 'dotsThree'\n | 'cpu'\n | 'sparkle'\n | 'chevronDown'\n\nlet _cache: Map<IconName, PhosphorIcon> | null = null\n\nasync function loadIcons(): Promise<Map<IconName, PhosphorIcon>> {\n if (_cache) return _cache\n const mod = await import('@phosphor-icons/react')\n _cache = new Map<IconName, PhosphorIcon>([\n ['robot', mod.Robot],\n ['chat', mod.ChatCircle],\n ['clipboard', mod.ClipboardText],\n ['paperclip', mod.Paperclip],\n ['chart', mod.ChartBar],\n ['notepad', mod.Notepad],\n ['warning', mod.Warning],\n ['check', mod.Check],\n ['checkCircle', mod.CheckCircle],\n ['hourglass', mod.Hourglass],\n ['spinner', mod.SpinnerGap],\n ['x', mod.X],\n ['xCircle', mod.XCircle],\n ['circle', mod.Circle],\n ['caretDown', mod.CaretDown],\n ['caretRight', mod.CaretRight],\n ['lightning', mod.Lightning],\n ['gear', mod.Gear],\n ['play', mod.Play],\n ['brain', mod.Brain],\n ['list', mod.ListBullets],\n ['file', mod.File],\n ['fileText', mod.FileText],\n ['fileCode', mod.FileCode],\n ['filePdf', mod.FilePdf],\n ['filePlus', mod.FilePlus],\n ['fileXls', mod.FileXls],\n ['fileDoc', mod.FileDoc],\n ['filePpt', mod.FilePpt],\n ['fileCsv', mod.FileCsv],\n ['fileZip', mod.FileZip],\n ['download', mod.DownloadSimple],\n ['arrowsOut', mod.ArrowsOut],\n ['arrowsIn', mod.ArrowsIn],\n ['arrowUp', mod.ArrowUp],\n ['minus', mod.Minus],\n ['magnifyingGlass', mod.MagnifyingGlass],\n ['globe', mod.Globe],\n ['code', mod.Code],\n ['terminal', mod.Terminal],\n ['package', mod.Package],\n ['copy', mod.Copy],\n ['link', mod.Link],\n ['share', mod.ShareNetwork],\n ['arrowLeft', mod.ArrowLeft],\n ['info', mod.Info],\n ['compress', mod.FunnelSimple],\n ['eye', mod.Eye],\n ['circuitry', mod.Circuitry],\n ['user', mod.User],\n ['image', mod.Image],\n ['folder', mod.Folder],\n ['folderOpen', mod.FolderOpen],\n ['house', mod.House],\n ['pencilSimple', mod.PencilSimple],\n ['chatCircleDots', mod.ChatCircleDots],\n ['pushPin', mod.PushPin],\n ['pause', mod.Pause],\n ['stop', mod.Stop],\n ['table', mod.Table],\n ['layers', mod.Stack],\n ['brackets', mod.BracketsSquare],\n ['usersThree', mod.UsersThree],\n ['uploadSimple', mod.UploadSimple],\n ['plus', mod.Plus],\n ['folderPlus', mod.FolderPlus],\n ['arrowRight', mod.ArrowRight],\n ['dotsThree', mod.DotsThree],\n ['cpu', mod.Cpu],\n ['sparkle', mod.Sparkle],\n ['chevronDown', mod.CaretDown],\n ])\n return _cache\n}\n\nexport { loadIcons }\n","import React, { useState, useCallback, useMemo, useRef, useEffect } from 'react'\nimport type { TodoCardProps, TodoTask, TodoData, TodoTaskStatus, TodoPhase, TodoGroup } from '../types'\nimport { useChatWidgetI18n } from '../i18n'\nimport { useInteractionDispatch } from '../hooks/useInteractionDispatch'\nimport { Icon } from './Icon/Icon'\nimport './TodoCard.css'\n\nconst STATUS_ICON: Record<TodoTaskStatus, string> = {\n pending: '○',\n in_progress: '→',\n completed: '✓',\n blocked: '⚠',\n}\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 emitInteraction = useInteractionDispatch()\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(() => {\n emitInteraction('todo-item-click', task.id ?? 'unknown', { status: task.status })\n setExpanded(v => !v)\n }, [emitInteraction, task.id, task.status])\n\n return (\n <>\n <div\n className={`ycw-todo-task-row ycw-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=\"ycw-todo-status-icon\">{STATUS_ICON[task.status]}</span>\n {hasChildren && (\n <span className={`ycw-todo-expand-arrow ${expanded ? 'ycw-expanded' : ''}`}>▸</span>\n )}\n <span className=\"ycw-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 const { t } = useChatWidgetI18n()\n\n return (\n <div className=\"ycw-todo-card-compact\">\n <span className=\"ycw-todo-compact-icon\">\n <Icon name=\"list\" size={14} aria-hidden={true} />\n </span>\n <span className=\"ycw-todo-compact-title\">{todo.title}</span>\n {current && (\n <>\n <span className=\"ycw-todo-compact-sep\">→</span>\n <span className=\"ycw-todo-compact-current\">{current.description}</span>\n </>\n )}\n <span className=\"ycw-todo-compact-progress\">\n {t('todo.completed.count', { completed: stats.completed, total: stats.total })}\n </span>\n </div>\n )\n}\n\n// ========== Full mode ==========\n\nconst TodoCard: React.FC<TodoCardProps> = ({ todo, compact = false }) => {\n const emitInteraction = useInteractionDispatch()\n const [expanded, setExpanded] = useState(false)\n const { t, messages } = useChatWidgetI18n()\n const listRef = useRef<HTMLDivElement>(null)\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 current = useMemo(() => findCurrentTask(tasks), [tasks])\n const isAllDone = stats.completed === stats.total && stats.total > 0\n const hasBlocked = stats.blocked > 0\n\n const currentIdx = useMemo(() => {\n if (!current) return -1\n return tasks.findIndex(t => t === current)\n }, [tasks, current])\n\n useEffect(() => {\n if (expanded && listRef.current && currentIdx >= 0) {\n const row = listRef.current.children[currentIdx] as HTMLElement | undefined\n row?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n }\n }, [expanded, currentIdx])\n\n return (\n <div className=\"ycw-todo-card\">\n {/* Header — clickable to toggle */}\n <div className=\"ycw-todo-header\" onClick={() => {\n emitInteraction('todo-toggle', todo.title, { tab: todo.title })\n setExpanded(v => !v)\n }} role=\"button\">\n <div className=\"ycw-todo-title\">\n <span className={`ycw-todo-header-arrow ${expanded ? 'ycw-expanded' : ''}`}>▸</span>\n <span className=\"ycw-todo-title-icon\">\n <Icon name=\"list\" size={14} aria-hidden={true} />\n </span>\n <span className=\"ycw-todo-title-text\">{todo.title}</span>\n </div>\n\n {/* Collapsed: show current task status; Expanded: just show count */}\n {!expanded && (\n <div className=\"ycw-todo-header-status\">\n {isAllDone ? (\n <span className=\"ycw-todo-header-done\">\n <Icon name=\"check\" aria-hidden={true} />\n {' '}\n {messages['todo.header.done']}\n </span>\n ) : hasBlocked ? (\n <span className=\"ycw-todo-header-blocked\">\n <Icon name=\"warning\" aria-hidden={true} />\n {' '}\n {t('todo.blocked.count', { count: stats.blocked })}\n </span>\n ) : current ? (\n <>\n <span className=\"ycw-todo-header-current-sep\">→</span>\n <span className=\"ycw-todo-header-current\">{current.description}</span>\n </>\n ) : null}\n </div>\n )}\n\n <span className=\"ycw-todo-header-count\">\n {t('todo.completed.count', { completed: stats.completed, total: stats.total })}\n </span>\n </div>\n\n {/* Progress bar — always visible */}\n <div className=\"ycw-todo-progress-bar\">\n <div\n className=\"ycw-todo-progress-fill\"\n style={{ width: `${progress * 100}%` }}\n />\n </div>\n\n {/* Expandable body */}\n {expanded && (\n <div className=\"ycw-todo-list\" ref={listRef}>\n {tasks.map((task, i) => (\n <TaskRow key={task.id || i} task={task} />\n ))}\n </div>\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 emitInteraction = useInteractionDispatch()\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=\"ycw-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=\"ycw-todo-card\">\n {/* Multi-todo selector */}\n <div className=\"ycw-todo-multi-tabs\">\n {entries.map(([id, todo]) => (\n <button\n key={id}\n className=\"ycw-todo-tab\"\n data-state={id === selectedId ? 'active' : undefined}\n onClick={() => {\n emitInteraction('todo-toggle', todo.title, { tab: todo.title })\n setActiveId(id)\n }}\n >\n {todo.title}\n <span className=\"ycw-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","import React, { useMemo } from 'react'\nimport { Streamdown } from 'streamdown'\nimport { code } from '@streamdown/code'\nimport { cjk } from '@streamdown/cjk'\nimport { parseUserMessage, hasRichContent } from '../utils/parseUserMessage'\nimport { Icon } from './Icon/Icon'\nimport { fileTypeIcon, fileTypeColor } from '../utils/fileTypeIcon'\nimport '../components/ContextBridge/ContextBridge.css'\nimport '../components/SkillSelector/SkillSelector.css'\n\nconst userMsgPlugins = { code, cjk }\n\nfunction fileExtLabel(fileName: string): string {\n const dot = fileName.lastIndexOf('.')\n return dot > 0 ? fileName.slice(dot + 1).toUpperCase() : 'FILE'\n}\n\ninterface UserMessageContentProps {\n text: string\n className?: string\n /**\n * JETP-032:当传入此 i18n 模板(含 ``{{name}}`` 标记)时,本组件会先把\n * 形如 ``<prefix>{{SKILL:xxx}}<suffix>`` 的片段折叠回裸 ``{{SKILL:xxx}}``,\n * 再交给 ``parseUserMessage``,这样卡片视觉上只剩下 chip + 用户实际内容,\n * 不再展示自动注入的引导话术(\"先查看并使用…技能,去解决:\")。\n * 后端持久化与 echo 都仍然是完整文本,模型读到的提示不变。\n */\n stripSkillTemplate?: string\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\n/**\n * 把 ``<prefix>{{SKILL:xxx}}<suffix>`` 折叠回 ``{{SKILL:xxx}}``。\n * 模板形如 ``先查看并使用{{name}}技能,去解决:``,以 ``{{name}}`` 为锚分裂出\n * prefix / suffix;若模板格式异常或 prefix+suffix 全空,原样返回。\n */\nfunction stripSkillTemplateFromText(text: string, template: string): string {\n if (!template) return text\n const idx = template.indexOf('{{name}}')\n if (idx < 0) return text\n const prefix = template.slice(0, idx)\n const suffix = template.slice(idx + '{{name}}'.length)\n if (!prefix && !suffix) return text\n const re = new RegExp(\n escapeRegExp(prefix) + '(\\\\{\\\\{SKILL:.+?\\\\}\\\\})' + escapeRegExp(suffix),\n 'g',\n )\n return text.replace(re, '$1')\n}\n\nconst UserMessageContent: React.FC<UserMessageContentProps> = ({ text, className, stripSkillTemplate }) => {\n const effectiveText = useMemo(\n () => (stripSkillTemplate ? stripSkillTemplateFromText(text, stripSkillTemplate) : text),\n [text, stripSkillTemplate],\n )\n const segments = useMemo(() => parseUserMessage(effectiveText), [effectiveText])\n const hasRich = useMemo(() => hasRichContent(effectiveText), [effectiveText])\n\n if (!hasRich) {\n return (\n <div className={`ycw-user-msg-md sd-message ${className || ''}`}>\n <Streamdown plugins={userMsgPlugins} isAnimating={false}>\n {effectiveText}\n </Streamdown>\n </div>\n )\n }\n\n const rendered: React.ReactNode[] = []\n const attachments: Array<{ fileName: string; gitPath?: string; key: number }> = []\n\n const flushAttachments = () => {\n if (attachments.length === 0) return\n rendered.push(\n <div key={`att-group-${attachments[0].key}`} className=\"ycw-user-attach-grid\">\n {attachments.map(att => {\n const color = fileTypeColor(att.fileName)\n return (\n <div key={att.key} className=\"ycw-user-attach-card\" title={att.gitPath || att.fileName}>\n <span\n className=\"ycw-user-attach-icon\"\n style={color ? { background: color } : undefined}\n >\n <Icon name={fileTypeIcon(att.fileName)} size={20} weight=\"fill\" aria-hidden />\n </span>\n <div className=\"ycw-user-attach-body\">\n <div className=\"ycw-user-attach-name\">{att.fileName}</div>\n <div className=\"ycw-user-attach-meta\">{fileExtLabel(att.fileName)}</div>\n </div>\n </div>\n )\n })}\n </div>,\n )\n attachments.length = 0\n }\n\n segments.forEach((seg, i) => {\n if (seg.type === 'attachment') {\n attachments.push({ fileName: seg.fileName, gitPath: seg.gitPath, key: i })\n return\n }\n flushAttachments()\n\n if (seg.type === 'text') {\n rendered.push(\n <span key={i} className=\"ycw-user-msg-md sd-message\">\n <Streamdown plugins={userMsgPlugins} isAnimating={false}>\n {seg.content}\n </Streamdown>\n </span>,\n )\n } else if (seg.type === 'skill') {\n rendered.push(\n <span key={i} className=\"ycw-msg-skill-chip\" title={seg.skillName}>\n <span className=\"ycw-msg-skill-chip-label\">{seg.skillName}</span>\n </span>,\n )\n } else {\n const preview = seg.selection\n ? seg.selection.length > 30 ? seg.selection.slice(0, 30) + '…' : seg.selection\n : null\n rendered.push(\n <span key={i} className=\"ycw-cb-context-chip ycw-msg-ref-chip\" title={seg.selection || seg.fileName}>\n <span className=\"ycw-cb-chip-icon\">📎</span>\n <span className=\"ycw-cb-chip-file\">{seg.fileName}</span>\n {seg.lineRange && <span className=\"ycw-cb-chip-line\">{`L${seg.lineRange}`}</span>}\n {preview && <span className=\"ycw-cb-chip-preview\">{preview}</span>}\n </span>,\n )\n }\n })\n flushAttachments()\n\n return <div className={`ycw-user-msg-rich ${className || ''}`}>{rendered}</div>\n}\n\nexport default UserMessageContent\n","export interface ParsedRefChip {\n type: 'ref'\n fileName: string\n lineRange?: string\n selection?: string\n}\n\nexport interface ParsedSkillChip {\n type: 'skill'\n skillName: string\n}\n\nexport interface ParsedAttachmentChip {\n type: 'attachment'\n fileName: string\n resourceId: string\n gitPath?: string\n}\n\nexport interface ParsedText {\n type: 'text'\n content: string\n}\n\nexport type ParsedSegment = ParsedRefChip | ParsedSkillChip | ParsedAttachmentChip | ParsedText\n\nconst REF_PATTERN = /\\[(?:引用文件|Reference):\\s*([^\\]]+)\\](?:\\s*\\(L([\\d-]+)\\))?(?:\\n```\\n([\\s\\S]*?)\\n```)?/g\nconst SKILL_PATTERN = /\\{\\{SKILL:(.+?)\\}\\}/g\nconst ATTACHMENT_PATTERN = /\\[附件:\\s*([^\\|]+?)\\s*\\|\\s*resource_id:\\s*([^\\|\\]]+?)(?:\\s*\\|\\s*path:\\s*([^\\]]*?))?\\s*\\]/g\n\nconst COMBINED_PATTERN = new RegExp(\n [\n REF_PATTERN.source,\n SKILL_PATTERN.source,\n ATTACHMENT_PATTERN.source,\n ].join('|'),\n 'g',\n)\n\nexport function parseUserMessage(text: string): ParsedSegment[] {\n if (!text) return []\n\n const segments: ParsedSegment[] = []\n let lastIndex = 0\n\n for (const match of text.matchAll(COMBINED_PATTERN)) {\n const matchStart = match.index!\n if (matchStart > lastIndex) {\n const before = text.slice(lastIndex, matchStart)\n if (before.trim()) segments.push({ type: 'text', content: before.trim() })\n }\n\n if (match[4] !== undefined) {\n segments.push({ type: 'skill', skillName: match[4].trim() })\n } else if (match[5] !== undefined) {\n segments.push({\n type: 'attachment',\n fileName: match[5].trim(),\n resourceId: match[6].trim(),\n gitPath: match[7]?.trim() || undefined,\n })\n } else {\n segments.push({\n type: 'ref',\n fileName: match[1].trim(),\n lineRange: match[2] || undefined,\n selection: match[3] || undefined,\n })\n }\n\n lastIndex = matchStart + match[0].length\n }\n\n if (lastIndex < text.length) {\n const rest = text.slice(lastIndex).trim()\n if (rest) segments.push({ type: 'text', content: rest })\n }\n\n return segments.length > 0 ? segments : [{ type: 'text', content: text }]\n}\n\nexport function hasRichContent(text: string): boolean {\n REF_PATTERN.lastIndex = 0\n SKILL_PATTERN.lastIndex = 0\n ATTACHMENT_PATTERN.lastIndex = 0\n return REF_PATTERN.test(text) || SKILL_PATTERN.test(text) || ATTACHMENT_PATTERN.test(text)\n}\n\n/** @deprecated Use hasRichContent instead */\nexport function hasReferenceBlocks(text: string): boolean {\n return hasRichContent(text)\n}\n","import type { IconName } from '../components/Icon/iconMap.js'\n\nconst mimeToIcon: Array<[string, IconName]> = [\n ['application/pdf', 'file'],\n ['text/markdown', 'file'],\n ['text/plain', 'file'],\n ['text/html', 'code'],\n ['text/css', 'code'],\n ['text/javascript', 'code'],\n ['text/typescript', 'code'],\n ['application/json', 'code'],\n ['application/xml', 'code'],\n ['image/', 'image'],\n ['video/', 'file'],\n ['audio/', 'file'],\n]\n\nconst extToIcon: Record<string, IconName> = {\n '.kicad_sch': 'circuitry',\n '.kicad_pcb': 'circuitry',\n '.kicad_pro': 'package',\n '.kicad_sym': 'circuitry',\n '.kicad_mod': 'circuitry',\n '.gbr': 'circuitry',\n '.gtl': 'circuitry',\n '.gbl': 'circuitry',\n '.gbs': 'circuitry',\n '.gts': 'circuitry',\n '.gko': 'circuitry',\n '.drl': 'circuitry',\n '.pdf': 'filePdf',\n '.md': 'fileText',\n '.txt': 'fileText',\n '.log': 'fileText',\n '.py': 'fileCode',\n '.ts': 'fileCode',\n '.tsx': 'fileCode',\n '.js': 'fileCode',\n '.jsx': 'fileCode',\n '.c': 'fileCode',\n '.cpp': 'fileCode',\n '.h': 'fileCode',\n '.go': 'fileCode',\n '.rs': 'fileCode',\n '.java': 'fileCode',\n '.html': 'fileCode',\n '.css': 'fileCode',\n '.json': 'fileCode',\n '.xml': 'fileCode',\n '.yaml': 'fileCode',\n '.yml': 'fileCode',\n '.toml': 'fileCode',\n '.png': 'image',\n '.jpg': 'image',\n '.jpeg': 'image',\n '.gif': 'image',\n '.svg': 'image',\n '.webp': 'image',\n '.bmp': 'image',\n '.xlsx': 'fileXls',\n '.xls': 'fileXls',\n '.csv': 'fileCsv',\n '.docx': 'fileDoc',\n '.doc': 'fileDoc',\n '.pptx': 'filePpt',\n '.ppt': 'filePpt',\n '.zip': 'fileZip',\n '.tar': 'fileZip',\n '.gz': 'fileZip',\n '.rar': 'fileZip',\n '.step': 'package',\n '.stp': 'package',\n '.stl': 'package',\n}\n\nconst extToColor: Record<string, string> = {\n '.xlsx': '#217346', '.xls': '#217346', '.csv': '#217346',\n '.docx': '#2b579a', '.doc': '#2b579a',\n '.pptx': '#d24726', '.ppt': '#d24726',\n '.pdf': '#e2574c',\n '.zip': '#f0a30a', '.tar': '#f0a30a', '.gz': '#f0a30a', '.rar': '#f0a30a',\n '.png': '#8b5cf6', '.jpg': '#8b5cf6', '.jpeg': '#8b5cf6', '.svg': '#8b5cf6',\n '.kicad_sch': '#0ea5e9', '.kicad_pcb': '#0ea5e9',\n}\n\nexport function fileTypeColor(fileName: string): string | undefined {\n if (!fileName) return undefined\n const lower = fileName.toLowerCase()\n const dot = lower.lastIndexOf('.')\n if (dot < 0) return undefined\n const ext = lower.slice(dot)\n return extToColor[ext]\n}\n\nexport function fileTypeIcon(mimeOrExt: string): IconName {\n if (!mimeOrExt) return 'file'\n\n const lower = mimeOrExt.toLowerCase()\n\n if (lower.startsWith('.') || lower.includes('.')) {\n const ext = lower.startsWith('.') ? lower : '.' + lower.split('.').pop()\n if (ext && ext in extToIcon) return extToIcon[ext]\n }\n\n for (const [prefix, icon] of mimeToIcon) {\n if (lower.startsWith(prefix)) return icon\n }\n\n return 'file'\n}\n","import React, { useRef, useState, useEffect, useCallback } from 'react'\nimport './CollapsibleContent.css'\n\ninterface CollapsibleContentProps {\n maxHeight?: number\n children: React.ReactNode\n className?: string\n expandLabel?: string\n collapseLabel?: string\n}\n\nconst EXPANDED_MAX = 400\n\nconst CollapsibleContent: React.FC<CollapsibleContentProps> = ({\n maxHeight = 120,\n children,\n className,\n expandLabel = '展开',\n collapseLabel = '收起',\n}) => {\n const contentRef = useRef<HTMLDivElement>(null)\n const [overflows, setOverflows] = useState(false)\n const [expanded, setExpanded] = useState(false)\n\n useEffect(() => {\n const el = contentRef.current\n if (!el) return\n const check = () => setOverflows(el.scrollHeight > maxHeight + 4)\n check()\n const ro = new ResizeObserver(check)\n ro.observe(el)\n return () => ro.disconnect()\n }, [maxHeight, children])\n\n const toggle = useCallback(() => setExpanded(v => !v), [])\n\n const innerStyle: React.CSSProperties | undefined = overflows\n ? expanded\n ? { maxHeight: EXPANDED_MAX, overflowY: 'auto' }\n : { maxHeight }\n : undefined\n\n return (\n <div className={`ycw-collapsible ${overflows && !expanded ? 'ycw-collapsible-clamped' : ''} ${expanded ? 'ycw-collapsible-expanded' : ''} ${className || ''}`}>\n <div\n ref={contentRef}\n className=\"ycw-collapsible-inner\"\n style={innerStyle}\n >\n {children}\n </div>\n {overflows && (\n <button\n type=\"button\"\n className=\"ycw-collapsible-toggle\"\n onClick={toggle}\n >\n {expanded ? collapseLabel : expandLabel}\n </button>\n )}\n </div>\n )\n}\n\nexport default CollapsibleContent\n","/**\n * 轮次标题组件\n * 在消息流中显示非置顶轮次的用户消息和计划\n */\n\nimport React, { useMemo } from 'react'\nimport type { RoundHeaderProps } from '../types'\nimport { useChatWidgetI18n } from '../i18n'\nimport PlanCard from './PlanCard'\nimport { TodoCardMulti } from './TodoCard'\nimport UserMessageContent from './UserMessageContent'\nimport CollapsibleContent from './CollapsibleContent'\nimport { Icon } from './Icon/Icon'\nimport './RoundHeader.css'\n\nconst ATTACHMENT_RE = /\\[附件:[^\\]]+\\]/g\nconst ATTACH_ROW_HEIGHT = 60\n\nconst RoundHeader: React.FC<RoundHeaderProps> = ({ \n round, \n isPinned,\n todoMap,\n}) => {\n const { messages, t } = useChatWidgetI18n()\n const collapsibleMax = useMemo(() => {\n const msg = round?.userMessage || ''\n const matches = msg.match(ATTACHMENT_RE)\n if (!matches || matches.length === 0) return 80\n const rows = Math.ceil(matches.length / 2)\n return 80 + rows * ATTACH_ROW_HEIGHT\n }, [round?.userMessage])\n const statusConfig = {\n running: { icon: 'hourglass' as const, text: messages['round.status.running'] },\n completed: { icon: 'check' as const, text: messages['round.status.completed'] },\n error: { icon: 'x' as const, text: messages['round.status.error'] },\n }\n\n const status = statusConfig[round.status]\n const hasTodo = todoMap && todoMap.size > 0\n\n return (\n <div className={`ycw-round-header ${isPinned ? 'pinned' : ''}`}>\n <div className=\"ycw-round-header-top\">\n <div className=\"ycw-user-avatar\">\n <span className=\"ycw-avatar-icon\">\n <Icon name=\"user\" size={14} aria-hidden={true} />\n </span>\n </div>\n <span className=\"ycw-round-status\" data-state={round.status}>\n <Icon name={status.icon} size={14} aria-hidden={true} />\n {' '}\n {status.text}\n </span>\n </div>\n <div className=\"ycw-user-message-text\">\n <CollapsibleContent maxHeight={collapsibleMax}>\n {round.userMessage\n ? <UserMessageContent text={round.userMessage} stripSkillTemplate={t('skill.inlineLabel')} />\n : messages['round.noMessage']}\n </CollapsibleContent>\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","import React from 'react'\nimport type { Round, ChatWidgetConfig, HITLResponse, ToolCallData, PoolAgent } from '../types'\nimport { mergeConsecutiveThinkMessages } from '../types'\nimport { organizeMessagesByLevel } from '../utils/messageOrganizer'\nimport { groupChildMessages, shouldSkipRootCallAgentCard } from '../utils/roundMessageUtils'\nimport MessageContent from './MessageContent'\nimport ChildAgentCard from './ChildAgentCard'\n\ninterface RoundMessageListProps {\n round: Round\n config: Required<ChatWidgetConfig>\n onArtifactClick?: (artifact: any) => void\n onHITLSubmit?: (response: HITLResponse) => Promise<void>\n renderToolResult?: (displayType: string, data: ToolCallData) => React.ReactNode | null\n observedInstanceStates?: Map<number, PoolAgent>\n}\n\nconst RoundMessageList: React.FC<RoundMessageListProps> = ({\n round,\n config,\n onArtifactClick,\n onHITLSubmit,\n renderToolResult,\n observedInstanceStates,\n}) => {\n const { rootMessages: rawRootMessages, childrenMap } = organizeMessagesByLevel(round.messages)\n const rootMessages = mergeConsecutiveThinkMessages(rawRootMessages)\n const elements: React.ReactNode[] = []\n const renderedChildKeys = new Set<string>()\n\n // 任意 root msg,只要 toolCallId 或 callBatchId 命中 childrenMap,就把对应 children\n // 渲染为 ChildAgentCard。不再硬要求父 tool 名等于 call_agent —— 后端真实数据里\n // 子 agent 可能由任意工具/路径拉起,关联唯一可信凭据是 callBatchId / parentCallBatchId。\n const resolveChildKey = (msg: typeof rootMessages[number]): string | null => {\n if (msg.toolCallId && childrenMap.has(msg.toolCallId)) return msg.toolCallId\n const cb = String(msg.callBatchId ?? '')\n if (cb && childrenMap.has(cb)) return cb\n return null\n }\n\n const renderChildGroup = (childKey: string, parentTaskPurpose?: string) => {\n if (renderedChildKeys.has(childKey)) return\n renderedChildKeys.add(childKey)\n const children = childrenMap.get(childKey)!\n const groups = groupChildMessages(children)\n groups.forEach(({ agentInstanceId, firstChild, children: rest }) => {\n elements.push(\n <ChildAgentCard\n key={`child-${childKey}-${agentInstanceId}`}\n message={firstChild}\n children={rest}\n maxHeight={config.childAgentMaxHeight}\n config={config}\n onArtifactClick={onArtifactClick}\n onHITLSubmit={onHITLSubmit}\n defaultExpanded={true}\n parentTaskPurpose={parentTaskPurpose}\n endedAgentInstanceIds={round.endedAgentInstanceIds}\n allRoundMessages={round.messages}\n observedInstanceStates={observedInstanceStates}\n />\n )\n })\n }\n\n rootMessages.forEach((msg) => {\n const childKey = resolveChildKey(msg)\n // 当 root 自身是 call_agent 工具卡,且对应子 Agent 已经渲染为 ChildAgentCard 时,\n // 跳过外层 \"派遣 xxx (call_agent) 生成中…\" 提示。ChildAgentCard 自带状态徽章\n // (running / completed),保留外层会出现两块同质卡片同时存在、视觉冗余的问题。\n // 边界:childKey 还未命中(子 agent 尚未启动)→ 不跳过,外层占位继续显示,\n // 直到子 Agent 第一条消息到达后由 ChildAgentCard 接管。\n if (!shouldSkipRootCallAgentCard(msg, childKey)) {\n elements.push(\n <MessageContent\n key={msg.id}\n message={msg}\n enableTypewriter={config.enableTypewriter}\n typewriterSpeed={config.typewriterSpeed}\n onArtifactClick={onArtifactClick}\n onHITLSubmit={onHITLSubmit}\n renderToolResult={renderToolResult}\n />\n )\n }\n if (childKey) renderChildGroup(childKey, msg.taskPurpose)\n })\n\n // 兜底:父 turn 缺失(被切片到别的 client 桶 / 历史窗口外 / 写入失败)时,\n // 仍把所有未匹配的 child group 在末尾追加渲染,避免子 agent 整组消失。\n childrenMap.forEach((_children, childKey) => {\n if (!renderedChildKeys.has(childKey)) renderChildGroup(childKey)\n })\n\n return <>{elements}</>\n}\n\nexport default RoundMessageList\n","import type { Round } from '../types'\n\nexport function organizeMessagesByLevel(messages: Round['messages']): {\n rootMessages: Round['messages']\n childrenMap: Map<string, Round['messages']>\n} {\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 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","import type { Round } from '../types'\n\ntype Message = Round['messages'][0]\n\nexport function isCallAgentToolCard(msg: Message): boolean {\n if (!msg.toolPhase) return false\n const name = (msg.toolName || '').toLowerCase()\n return name.includes('call_agent') || name.includes('callagent')\n}\n\n/**\n * 是否应跳过 root 层 call_agent 工具卡的渲染。\n *\n * 触发条件:root msg 自身是 call_agent 工具卡,且其 toolCallId/callBatchId 已经\n * 命中 childrenMap(即对应子 Agent 已经被渲染为 ChildAgentCard)。\n *\n * 设计:避免外层 \"派遣 xxx (call_agent) 生成中…\" 提示与下方 ChildAgentCard 自带\n * 状态徽章(running / completed)同时出现的视觉冗余。childKey 未命中时仍渲染外层\n * 占位,直到子 Agent 第一条消息到达由 ChildAgentCard 接管。\n */\nexport function shouldSkipRootCallAgentCard(\n msg: Message,\n childKey: string | null,\n): boolean {\n return childKey != null && isCallAgentToolCard(msg)\n}\n\nexport interface ChildGroupEntry {\n agentInstanceId: number\n firstChild: Message\n children: Message[]\n}\n\n/**\n * Group child messages by agentInstanceId.\n * Returns an array of groups, each with the first child and remaining children.\n */\nexport function groupChildMessages(children: Message[]): ChildGroupEntry[] {\n const groupMap = new Map<number, Message[]>()\n for (const child of children) {\n const group = groupMap.get(child.agentInstanceId) || []\n group.push(child)\n groupMap.set(child.agentInstanceId, group)\n }\n const entries: ChildGroupEntry[] = []\n groupMap.forEach((groupChildren, agentInstanceId) => {\n entries.push({\n agentInstanceId,\n firstChild: groupChildren[0],\n children: groupChildren.slice(1),\n })\n })\n return entries\n}\n","import React, { 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 ToolCardBuffering from './ToolCardBuffering'\nimport { ThinkChunk } from './message/ThinkChunk'\nimport { HITLWaitCard } from './message/HITLWaitCard'\nimport { ArtifactCard } from './message/ArtifactCard'\nimport { McpToolEvent } from './message/McpToolEvent'\nimport { LegacyToolLine } from './message/LegacyToolLine'\nimport { JsonRenderCard } from './JsonRender/JsonRenderCard'\nimport { useGenUI } from './JsonRender/GenUIContext'\nimport { isMcpEvent, matchLegacyToolLine } from '../utils/messageParser'\nimport { useTypewriter } from '../hooks/useTypewriter'\nimport './MessageContent.css'\n\nconst math = createMathPlugin({ singleDollarTextMath: true })\nconst streamdownPlugins = { code, mermaid, math, cjk }\n\n/**\n * JETP-083 WS3.7.5 + WS3.7.6 + A3 — render a terminal/pending lifecycle\n * marker above a spec card so the user sees:\n *\n * - \"Cancelled — {reason}\" overlay when the backend pushed `/_meta/cancelled`\n * (agent superseded, user cancelled, budget GC).\n * - \"Error — {error_code}\" overlay when the backend pushed `/_meta/error`\n * (e.g. patch_rounds_exceeded from WS1.1).\n * - \"Awaiting your input\" ribbon when the connecting principal is among\n * `pendingHILs[].resolved_recipients` (or `includeSelf=true` in the\n * summary projection). Hydrated on connect by `useGenUIPending`.\n * - \"Awaiting {N} approvals\" softer banner when the spec has a pending\n * HIL but the connecting principal is *not* one of the recipients —\n * pure visibility (multi-agent / Phase 2 cross-user scenario).\n *\n * Lifecycle entries take precedence over pending (a cancelled spec is no\n * longer awaiting anything). All visuals are pure CSS classes on\n * `.jr-spec-ribbon-*`; host themes may restyle.\n */\nconst SpecStatusRibbon: React.FC<{ specId: string }> = ({ specId }) => {\n const ctx = useGenUI()\n if (!ctx) return null\n const lifecycle = ctx.specLifecycleBySpecId?.get(specId)\n if (lifecycle) {\n if (lifecycle.state === 'cancelled') {\n return (\n <div className=\"jr-spec-ribbon jr-spec-ribbon-cancelled\" role=\"status\">\n <span className=\"jr-spec-ribbon-icon\" aria-hidden={true}>⛔</span>\n <span className=\"jr-spec-ribbon-label\">Cancelled</span>\n {lifecycle.reason ? (\n <span className=\"jr-spec-ribbon-detail\">{lifecycle.reason}</span>\n ) : null}\n </div>\n )\n }\n if (lifecycle.state === 'error') {\n return (\n <div className=\"jr-spec-ribbon jr-spec-ribbon-error\" role=\"status\">\n <span className=\"jr-spec-ribbon-icon\" aria-hidden={true}>⚠️</span>\n <span className=\"jr-spec-ribbon-label\">Error</span>\n <span className=\"jr-spec-ribbon-detail\">{lifecycle.errorCode}</span>\n </div>\n )\n }\n }\n const pending = ctx.pendingHILBySpecId?.get(specId)\n if (pending) {\n if (pending.recipientsSummary?.includeSelf) {\n return (\n <div className=\"jr-spec-ribbon jr-spec-ribbon-await-self\" role=\"status\">\n <span className=\"jr-spec-ribbon-icon\" aria-hidden={true}>✋</span>\n <span className=\"jr-spec-ribbon-label\">Awaiting your input</span>\n </div>\n )\n }\n const count = pending.recipientsSummary?.recipientCount ?? 0\n return (\n <div className=\"jr-spec-ribbon jr-spec-ribbon-await-other\" role=\"status\">\n <span className=\"jr-spec-ribbon-icon\" aria-hidden={true}>⏳</span>\n <span className=\"jr-spec-ribbon-label\">\n {count > 0 ? `Awaiting ${count} recipient${count === 1 ? '' : 's'}` : 'Awaiting input'}\n </span>\n </div>\n )\n }\n return null\n}\n\nconst GenUIPageIndicator: React.FC<{ specId: string; patchCount: number }> = ({ specId, patchCount }) => {\n const ctx = useGenUI()\n return (\n <div className=\"jr-page-indicator-wrap\">\n <SpecStatusRibbon specId={specId} />\n <div\n className=\"jr-page-indicator jr-page-indicator-clickable\"\n onClick={() => ctx?.openPageViewer?.(specId)}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') ctx?.openPageViewer?.(specId) }}\n >\n <span className=\"jr-page-indicator-icon\">📊</span>\n <span className=\"jr-page-indicator-text\">Dashboard opened in viewer panel</span>\n <span className=\"jr-page-indicator-badge\">{patchCount} patches</span>\n </div>\n </div>\n )\n}\n\nconst GenUICard: React.FC<{\n specId: string\n patches: string[]\n /**\n * JETP-083 WS3.7.7 follow-up — agent instance that emitted this message\n * (and therefore this spec). Forwarded to ActionBridge so HIL submissions\n * carry a non-zero ``agent_instance_id`` Form field on the wire (FastAPI\n * declares the field as required; missing it produced 422).\n */\n agentInstanceId?: number\n}> = ({ specId, patches, agentInstanceId }) => {\n const ctx = useGenUI()\n console.log('[JETP-033] GenUICard render:', {\n specId,\n patchCount: patches.length,\n hasContext: !!ctx,\n firstPatch: patches[0]?.substring(0, 80),\n })\n if (!ctx) {\n console.warn('[JETP-033] GenUIProvider context is null — GenUIProvider not mounted?')\n return null\n }\n return (\n <div className=\"jr-card-wrap\">\n <SpecStatusRibbon specId={specId} />\n <JsonRenderCard\n specId={specId}\n patches={patches}\n adapter={ctx.adapter}\n sessionId={ctx.sessionId}\n clientId={ctx.clientId}\n agentWaiting={ctx.agentWaiting}\n agentInstanceId={agentInstanceId}\n registry={ctx.registry}\n />\n </div>\n )\n}\n\nconst MessageContent: React.FC<MessageContentProps> = memo(({\n message,\n enableTypewriter = true,\n typewriterSpeed = 30,\n onArtifactClick,\n onHITLSubmit,\n renderToolResult,\n observedInstanceStates,\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 message.id,\n )\n\n // Think\n if (message.contentType === 'think') {\n return <ThinkChunk content={content} isThinking={isTyping} />\n }\n\n // HITL form\n if (message.contentType === 'json_schema_wait' || message.contentType === 'json_schema' || message.contentType === 'html_schema') {\n return <HITLWaitCard content={content} hitlRequest={message.hitlRequest} onHITLSubmit={onHITLSubmit} />\n }\n\n // Artifacts\n if (message.contentType === 'artifact' && (message.artifacts || message.artifact)) {\n const artifacts = message.artifacts || (message.artifact ? [message.artifact] : [])\n return (\n <div className=\"ycw-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 // GenUI (JETP-033)\n if (message.contentType === 'gen_ui_card' || message.contentType === 'gen_ui_page') {\n if (message.specId && message.uiPatches && message.uiPatches.length > 0) {\n if (message.renderMode === 'page') {\n return <GenUIPageIndicator specId={message.specId} patchCount={message.uiPatches.length} />\n }\n return (\n <GenUICard\n specId={message.specId}\n patches={message.uiPatches}\n agentInstanceId={message.agentInstanceId}\n />\n )\n }\n return null\n }\n\n // Tool phase (structured tool cards)\n if (message.toolPhase) {\n if (renderToolResult && message.uiConfig?.display_type) {\n const custom = renderToolResult(message.uiConfig.display_type, {\n tool_name: message.toolName || '',\n display_type: message.uiConfig.display_type,\n args: message.argsPreview ? (typeof message.argsPreview === 'string' ? { raw: message.argsPreview } : (message.argsPreview as unknown as Record<string, unknown>)) : {},\n status: message.toolPhase === 'complete' ? 'completed' : message.toolPhase === 'error' ? 'failed' : 'running',\n ui_config: message.uiConfig,\n })\n if (custom !== null && custom !== undefined) return <>{custom}</>\n }\n return <ToolCardBuffering message={message} observedInstanceStates={observedInstanceStates} />\n }\n\n // MCP tool events\n if (isMcpEvent(message)) {\n return <McpToolEvent message={message} content={content} />\n }\n\n // Legacy tool line (regex fallback)\n const legacyMatch = matchLegacyToolLine(content)\n if (legacyMatch) {\n return <LegacyToolLine match={legacyMatch} />\n }\n\n // Plain text → typewriter + 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=\"ycw-streaming-cursor\" />}\n </div>\n )\n})\n\nexport default MessageContent\n","import React, { useMemo, useRef, memo } from 'react'\nimport type { AggregatedMessage, PoolAgent, PoolAgentAction } 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\nfunction isCallAgentTool(name: string | undefined): boolean {\n if (!name) return false\n const lower = name.toLowerCase()\n return lower.includes('call_agent') || lower.includes('callagent')\n}\n\nfunction pickLatestAction(actions: PoolAgentAction[]): PoolAgentAction | undefined {\n for (let i = actions.length - 1; i >= 0; i--) {\n if (actions[i]?.status === 'running') return actions[i]\n }\n return actions.length > 0 ? actions[actions.length - 1] : undefined\n}\n\ninterface ToolCardBufferingProps {\n message: AggregatedMessage\n observedInstanceStates?: Map<number, PoolAgent>\n}\n\nconst ToolCardBuffering: React.FC<ToolCardBufferingProps> = memo(({ message, observedInstanceStates }) => {\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 const resultContent = message.contentChunks.join('')\n const hasResult = resultContent.trim().length > 0\n\n // For call_agent tool cards (level >= 2 child agents), show the child's latest action\n const showChildActivity = isCallAgentTool(message.toolName) && phase !== 'complete' && phase !== 'error'\n let childLatestAction: PoolAgentAction | undefined\n if (showChildActivity && observedInstanceStates) {\n // Find child agent entry — try matching by callee_agent_instance_id from args, or scan all running agents\n const calleeId = parsedArgs?.callee_agent_instance_id as number | undefined\n const childEntry = calleeId != null ? observedInstanceStates.get(calleeId) : undefined\n if (childEntry?.recent_actions) {\n childLatestAction = pickLatestAction(childEntry.recent_actions)\n }\n }\n\n return (\n <div className={`ycw-tool-card-buffering ${config.className}`}>\n <Renderer\n message={message}\n uiConfig={uiConfig}\n parsedArgs={parsedArgs}\n phase={phase}\n />\n {showChildActivity && childLatestAction && (\n <div className=\"ycw-tool-child-activity\">\n <span className={`ycw-tool-child-activity__dot ${childLatestAction.status === 'running' ? 'ycw-tool-child-activity__dot--running' : ''}`} />\n <span className=\"ycw-tool-child-activity__tool\">{childLatestAction.tool}</span>\n {childLatestAction.purpose && (\n <span className=\"ycw-tool-child-activity__purpose\">{childLatestAction.purpose}</span>\n )}\n </div>\n )}\n {hasResult && (\n <ToolResultRenderer content={resultContent} />\n )}\n </div>\n )\n})\n\nexport default ToolCardBuffering\n","import React from 'react'\nimport { useChatWidgetI18n } from '../../i18n'\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: '⚙️', className: 'ycw-phase-generating' },\n executing: { icon: '⏳', className: 'ycw-phase-executing' },\n complete: { icon: '✅', className: 'ycw-phase-complete' },\n error: { icon: '❌', className: 'ycw-phase-error' },\n} as const\n\nexport const PhaseLabel: React.FC<{ phase: string }> = ({ phase }) => {\n const cfg = phaseConfig[phase as keyof typeof phaseConfig]\n const { messages } = useChatWidgetI18n()\n const i18nLabels: Record<string, string> = {\n generating: messages['tool.phase.generating'],\n executing: messages['tool.phase.executing'],\n complete: messages['tool.phase.complete'],\n error: messages['tool.phase.error'],\n }\n const label = i18nLabels[phase] || phase\n return (\n <span className=\"ycw-tool-phase-label\">\n {label}\n {phase === 'generating' && (\n <span className=\"ycw-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=\"ycw-compact-tags\">\n {tags.slice(0, 5).map(t => (\n <span key={t.key} className=\"ycw-compact-tag\">{t.key}: {t.value}</span>\n ))}\n {tags.length > 5 && <span className=\"ycw-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=\"ycw-tool-card-header\"\n onClick={() => hasContent && setExpanded(!expanded)}\n style={{ cursor: hasContent ? 'pointer' : 'default' }}\n >\n <span className=\"ycw-tool-phase-icon\">📄</span>\n {taskPurpose ? (\n <>\n <span className=\"ycw-tool-card-name\">{taskPurpose}</span>\n <span className=\"ycw-tool-card-fn\">({toolName})</span>\n </>\n ) : (\n <span className=\"ycw-tool-card-name\">{toolName}</span>\n )}\n {shortPath && <code className=\"ycw-tool-card-path-inline\">{shortPath}</code>}\n <PhaseLabel phase={phase} />\n {hasContent && <span className=\"ycw-tool-card-expand\">{expanded ? '▼' : '▶'}</span>}\n </div>\n\n {/* Diff 风格预览(折叠态 + generating 态可见) */}\n {(hasContent || isGenerating) && !expanded && (\n <div className={`ycw-content-diff-preview${isGenerating ? ' ycw-streaming' : ''}`}>\n {isEdit && !isGenerating && oldPreviewLines.map((line, i) => (\n <div key={`old-${i}`} className=\"ycw-diff-line ycw-diff-remove\">\n <span className=\"ycw-diff-sign\">-</span>\n <span className=\"ycw-diff-text\">{line}</span>\n </div>\n ))}\n {previewLines.length > 0 ? previewLines.map((line, i) => (\n <div key={i} className=\"ycw-diff-line ycw-diff-add\">\n <span className=\"ycw-diff-sign\">+</span>\n <span className=\"ycw-diff-text\">\n {line}\n {isGenerating && i === previewLines.length - 1 && (\n <span className=\"ycw-streaming-block-cursor\" />\n )}\n </span>\n </div>\n )) : isGenerating && (\n <div className=\"ycw-diff-line ycw-diff-add\">\n <span className=\"ycw-diff-sign\">+</span>\n <span className=\"ycw-diff-text\">\n <span className=\"ycw-streaming-block-cursor\" />\n </span>\n </div>\n )}\n {!isGenerating && totalLines > MAX_PREVIEW_LINES && (\n <div className=\"ycw-diff-more\">... +{totalLines - MAX_PREVIEW_LINES} lines</div>\n )}\n </div>\n )}\n\n {/* 展开态:完整内容 */}\n {expanded && (\n <div className=\"ycw-content-renderer-body\">\n {headerValue && (\n <div className=\"ycw-content-renderer-path\">{headerValue}</div>\n )}\n <pre className=\"ycw-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=\"ycw-tool-card-header\">\n <span className=\"ycw-tool-phase-icon\">💻</span>\n {taskPurpose ? (\n <>\n <span className=\"ycw-tool-card-name\">{taskPurpose}</span>\n <span className=\"ycw-tool-card-fn\">({toolName})</span>\n </>\n ) : (\n <span className=\"ycw-tool-card-name\">{toolName}</span>\n )}\n <PhaseLabel phase={phase} />\n </div>\n {command && (\n <div className=\"ycw-command-renderer-terminal\">\n <span className=\"ycw-command-prompt\">$</span>\n <code className=\"ycw-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=\"ycw-tool-card-header\">\n <span className=\"ycw-tool-phase-icon\">{icon}</span>\n {taskPurpose ? (\n <>\n <span className=\"ycw-tool-card-name\">{taskPurpose}</span>\n <span className=\"ycw-tool-card-fn\">({toolName})</span>\n </>\n ) : (\n <span className=\"ycw-tool-card-name\">{toolName}</span>\n )}\n {primaryValue && (\n <span className=\"ycw-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=\"ycw-tool-card-header\">\n <span className=\"ycw-tool-phase-icon\">🔍</span>\n {taskPurpose ? (\n <>\n <span className=\"ycw-tool-card-name\">{taskPurpose}</span>\n <span className=\"ycw-tool-card-fn\">({toolName})</span>\n </>\n ) : (\n <span className=\"ycw-tool-card-name\">{toolName}</span>\n )}\n {queryValue && (\n <span className=\"ycw-query-inline\">\"{formatValue(queryValue)}\"</span>\n )}\n {headerValue && (\n <span className=\"ycw-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=\"ycw-tool-card-header\">\n <span className=\"ycw-tool-phase-icon\">{icon}</span>\n {taskPurpose ? (\n <>\n <span className=\"ycw-tool-card-name\">{taskPurpose}</span>\n <span className=\"ycw-tool-card-fn\">({toolName})</span>\n </>\n ) : (\n <span className=\"ycw-tool-card-name\">{toolName}</span>\n )}\n {pathValue && (\n <code className=\"ycw-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=\"ycw-tool-card-header\"\n onClick={() => hasDetail && setExpanded(!expanded)}\n style={{ cursor: hasDetail ? 'pointer' : 'default' }}\n >\n <span className=\"ycw-tool-phase-icon\">⏰</span>\n <span className=\"ycw-tool-card-name\">{toolLabel}</span>\n {(headerValue || primaryValue) && (\n <span className=\"ycw-trigger-title\">{formatValue(headerValue || primaryValue)}</span>\n )}\n <PhaseLabel phase={phase} />\n {hasDetail && <span className=\"ycw-tool-card-expand\">{expanded ? '▼' : '▶'}</span>}\n </div>\n {tags.length > 0 && <CompactTags tags={tags} />}\n {expanded && parsedArgs && (\n <div className=\"ycw-trigger-detail\">\n {Object.entries(parsedArgs)\n .filter(([k]) => !uiConfig.hide_fields?.includes(k))\n .map(([k, v]) => (\n <div key={k} className=\"ycw-trigger-row\">\n <span className=\"ycw-trigger-key\">{k}</span>\n <span className=\"ycw-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'\nimport { useChatWidgetI18n } from '../../i18n'\n\nconst ThinkingRenderer: React.FC<RendererProps> = ({ message, uiConfig, parsedArgs, phase }) => {\n const { t } = useChatWidgetI18n()\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=\"ycw-tool-card-header\">\n <span className=\"ycw-tool-phase-icon\">💭</span>\n <span className=\"ycw-tool-card-name\">{t('thinking.title')}</span>\n {stepInfo && <span className=\"ycw-thinking-step\">{t('thinking.step', { step: stepInfo })}</span>}\n <PhaseLabel phase={phase} />\n </div>\n {thought && (\n <div className=\"ycw-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=\"ycw-tool-card-header\"\n onClick={() => hasArgs && setExpanded(!expanded)}\n style={{ cursor: hasArgs ? 'pointer' : 'default' }}\n >\n <span className=\"ycw-tool-phase-icon\">⚙️</span>\n {taskPurpose ? (\n <>\n <span className=\"ycw-tool-card-name\">{taskPurpose}</span>\n <span className=\"ycw-tool-card-fn\">({toolName})</span>\n </>\n ) : (\n <span className=\"ycw-tool-card-name\">{toolName}</span>\n )}\n {headerValue && <code className=\"ycw-tool-card-path-inline\">{formatValue(headerValue)}</code>}\n <PhaseLabel phase={phase} />\n {hasArgs && <span className=\"ycw-tool-card-expand\">{expanded ? '▼' : '▶'}</span>}\n </div>\n {expanded && parsedArgs && (\n <div className=\"ycw-params-detail\">\n {Object.entries(parsedArgs)\n .filter(([k]) => !uiConfig?.hide_fields?.includes(k))\n .map(([k, v]) => (\n <div key={k} className=\"ycw-params-row\">\n <span className=\"ycw-params-key\">{k}:</span>\n <span className=\"ycw-params-value\">{formatValue(v)}</span>\n </div>\n ))}\n </div>\n )}\n </>\n )\n}\n\nexport default ParamsRenderer\n","import React, { useState } from 'react'\nimport { useInteractionDispatch } from '../../hooks/useInteractionDispatch'\nimport { useChatWidgetI18n } from '../../i18n'\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 const { t } = useChatWidgetI18n()\n const emitInteraction = useInteractionDispatch()\n return (\n <div className=\"ycw-tool-result-search\">\n {query && <div className=\"ycw-tool-result-search-query\">🔍 {query}</div>}\n <div className=\"ycw-tool-result-search-list\">\n {results.slice(0, 8).map((r, i) => (\n <a\n key={i}\n className=\"ycw-tool-result-search-item\"\n href={r.link}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={() => emitInteraction('link-click', r.link, { title: r.title, source: 'search-result' })}\n >\n <div className=\"ycw-search-item-title\">{r.title}</div>\n <div className=\"ycw-search-item-snippet\">{r.snippet}</div>\n {r.date && <span className=\"ycw-search-item-date\">{r.date}</span>}\n </a>\n ))}\n {results.length > 8 && (\n <div className=\"ycw-search-item-more\">{t('toolResult.more', { count: results.length - 8 })}</div>\n )}\n </div>\n </div>\n )\n}\n\nconst ScrapeResultView: React.FC<{ result: ScrapeResult }> = ({ result }) => {\n const emitInteraction = useInteractionDispatch()\n return (\n <div className=\"ycw-tool-result-scrape\">\n <a\n className=\"ycw-scrape-result-link\"\n href={result.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={() => emitInteraction('link-click', result.url, { title: result.title, source: 'scrape-result' })}\n >\n {result.title && <div className=\"ycw-scrape-result-title\">{result.title}</div>}\n <div className=\"ycw-scrape-result-url\">{result.url}</div>\n </a>\n {result.snippet && <div className=\"ycw-scrape-result-snippet\">{result.snippet}</div>}\n </div>\n )\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 { t } = useChatWidgetI18n()\n const [showAll, setShowAll] = useState(false)\n const display = showAll ? formatted : lines.slice(0, 12).join('\\n')\n\n return (\n <div className=\"ycw-tool-result-json\">\n <pre className=\"ycw-tool-result-json-code\">{display}</pre>\n {needsTruncation && !showAll && (\n <div className=\"ycw-tool-result-json-more\" onClick={() => setShowAll(true)}>\n {t('toolResult.expandAll', { count: lines.length })}\n </div>\n )}\n </div>\n )\n}\n\nconst ToolResultRenderer: React.FC<ToolResultRendererProps> = ({ content, defaultExpanded = false }) => {\n const emitInteraction = useInteractionDispatch()\n const { t } = useChatWidgetI18n()\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 t('toolResult.searchSummary', { count })\n }\n if (parsed && isScrapeResultShape(parsed)) {\n const title = parsed.title || new URL(parsed.url).hostname\n return t('toolResult.scrapeSummary', { 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=\"ycw-tool-result-section\">\n <div className=\"ycw-tool-result-header\" onClick={() => {\n emitInteraction('tool-result-toggle', summaryText, { expanded: !isExpanded })\n setIsExpanded(!isExpanded)\n }}>\n <span className=\"ycw-tool-result-label\">{t('toolResult.label')}</span>\n <span className=\"ycw-tool-result-summary\">{summaryText}</span>\n <span className={`ycw-collapse-arrow ${isExpanded ? 'ycw-expanded' : ''}`}>▼</span>\n </div>\n {isExpanded && (\n <div className=\"ycw-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=\"ycw-tool-result-text\">{content}</div>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport default ToolResultRenderer\n","import React, { useEffect, useState, useRef } 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 { useChatWidgetI18n } from '../../i18n'\nimport { useInteractionDispatch } from '../../hooks/useInteractionDispatch'\n\nconst math = createMathPlugin({ singleDollarTextMath: true })\nconst streamdownPlugins = { code, mermaid, math, cjk }\n\nexport const ThinkChunk: React.FC<{ content: string; isThinking?: boolean }> = ({ content, isThinking = false }) => {\n const { t } = useChatWidgetI18n()\n const emitInteraction = useInteractionDispatch()\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 ? t('thinking.inProgress') : t('thinking.completed'))\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 emitInteraction('think-toggle', 'think-chunk', { expanded: !isExpanded })\n setIsExpanded(!isExpanded)\n }\n\n return (\n <div className={`ycw-think-chunk ${isExpanded ? 'ycw-expanded' : ''} ${isActive ? 'ycw-thinking' : ''}`}>\n <div\n className=\"ycw-think-header\"\n onClick={handleToggle}\n >\n <div className=\"ycw-think-title\">\n <span className={`ycw-think-icon ${isActive ? 'ycw-thinking-animation' : ''}`}>💭</span>\n <span className=\"ycw-think-text\">{displayText}</span>\n {isActive && <span className=\"ycw-thinking-dots\"><span>.</span><span>.</span><span>.</span></span>}\n </div>\n <span className={`ycw-collapse-arrow ${(isExpanded || previewVisible) ? 'ycw-expanded' : ''}`}>\n ▼\n </span>\n </div>\n <div\n className={`ycw-think-preview ${previewVisible ? 'ycw-think-preview-open' : 'ycw-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=\"ycw-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","import React from 'react'\nimport type { MessageContentProps } from '../../types'\nimport { useChatWidgetI18n } from '../../i18n'\nimport SchemaFormRenderer from '../SchemaFormRenderer'\n\nexport const HITLWaitCard: React.FC<{\n content: string\n hitlRequest?: MessageContentProps['message']['hitlRequest']\n onHITLSubmit?: MessageContentProps['onHITLSubmit']\n}> = ({ content, hitlRequest, onHITLSubmit }) => {\n const { messages: i18n } = useChatWidgetI18n()\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 || i18n['hitl.wait.default']\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) || i18n['hitl.wait.default']\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) || i18n['hitl.wait.default']\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 || i18n['hitl.form.defaultTitle']\n\n const handleFormSubmit = async (values: Record<string, unknown>) => {\n if (!hitlRequest?.await_command_uuid) return\n const response = {\n await_command_uuid: hitlRequest.await_command_uuid,\n data: values,\n confirmed: true,\n }\n await onHITLSubmit?.(response)\n }\n\n return (\n <div className=\"ycw-hitl-form-card\">\n <div className=\"ycw-hitl-form-header\">\n <span className=\"ycw-hitl-form-icon\">📋</span>\n <span className=\"ycw-hitl-form-title\">{title}</span>\n </div>\n <div className=\"ycw-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=\"ycw-hitl-wait-card\">\n <div className=\"ycw-hitl-icon\">⏳</div>\n <div className=\"ycw-hitl-content\">\n <div className=\"ycw-hitl-text\">{displayText}</div>\n {hitlRequest?.await_command_uuid && (\n <div className=\"ycw-hitl-uuid\">ID: {hitlRequest.await_command_uuid.slice(0, 8)}...</div>\n )}\n </div>\n </div>\n )\n}\n","import React, { useState, useCallback } from 'react'\nimport { useChatWidgetI18n } from '../i18n'\nimport { renderNode, extractRules } from '../utils/schemaFormUtils'\nimport type { SchemaNode } from '../utils/schemaFormUtils'\nimport './SchemaFormRenderer.css'\n\ninterface SchemaFormRendererProps {\n schema: SchemaNode\n onSubmit?: (values: Record<string, unknown>) => void | Promise<void>\n awaitCommandUuid?: string\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 const { messages } = useChatWidgetI18n()\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 || messages['form.required.default']\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=\"ycw-schema-form-renderer\">\n {renderNode(schema, values, handleChange, errors)}\n \n <div className=\"ycw-schema-form-actions\">\n <button\n className=\"ycw-schema-submit-btn\"\n onClick={handleSubmit}\n disabled={isSubmitting}\n >\n {isSubmitting ? messages['form.submit.submitting'] : messages['form.submit.submit']}\n </button>\n </div>\n \n {awaitCommandUuid && (\n <div className=\"ycw-schema-form-meta\">\n <span className=\"ycw-meta-uuid\">{messages['form.requestId']}{awaitCommandUuid.slice(0, 8)}...</span>\n </div>\n )}\n </div>\n )\n}\n\nexport default SchemaFormRenderer\n","import React from 'react'\n\nexport interface 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\n}\n\nexport function 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=\"ycw-schema-card\">\n {children?.map((child) => renderNode(child, values, onChange, errors))}\n </div>\n )\n\n case 'FormChunk':\n if (schema) return renderNode(schema, values, onChange, errors)\n return children?.map((child) => renderNode(child, values, onChange, errors))\n\n case 'Form':\n return (\n <div key={nodeKey} className=\"ycw-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 return (\n <div key={nodeKey} className={`ycw-schema-form-item ${error ? 'ycw-has-error' : ''}`}>\n <label className=\"ycw-schema-form-label\">\n {required && <span className=\"ycw-required-mark\">*</span>}\n {label}\n </label>\n <div className=\"ycw-schema-form-control\">\n {children?.map((child) => renderNode(\n { ...child, name: name || child.name },\n values, onChange, errors,\n ))}\n </div>\n {error && <div className=\"ycw-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 return (\n <div key={nodeKey} className=\"ycw-schema-radio-group\">\n {options?.map((option) => (\n <label key={option.value} className=\"ycw-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=\"ycw-radio-checkmark\"></span>\n <span className=\"ycw-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 return (\n <div key={nodeKey} className=\"ycw-schema-checkbox-group\">\n {options?.map((option) => (\n <label key={option.value} className=\"ycw-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=\"ycw-checkbox-checkmark\"></span>\n <span className=\"ycw-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 return (\n <input\n key={nodeKey}\n type=\"text\"\n className=\"ycw-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 return (\n <textarea\n key={nodeKey}\n className=\"ycw-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 return (\n <select\n key={nodeKey}\n className=\"ycw-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 if (children && children.length > 0) {\n return children.map((child) => renderNode(child, values, onChange, errors))\n }\n return null\n }\n}\n\nexport function extractRules(\n node: SchemaNode,\n): Record<string, Array<{ required?: boolean; message?: string }>> {\n const rules: Record<string, Array<{ required?: boolean; message?: string }>> = {}\n const traverse = (n: SchemaNode) => {\n if (n.name && n.rules) rules[n.name] = n.rules\n if (n.children) n.children.forEach(traverse)\n if (n.schema) traverse(n.schema)\n }\n traverse(node)\n return rules\n}\n","import React from 'react'\nimport type { MessageContentProps } from '../../types'\nimport { useInteractionDispatch } from '../../hooks/useInteractionDispatch'\nimport { Icon } from '../Icon/Icon'\nimport { fileTypeIcon } from '../../utils/fileTypeIcon.js'\n\nexport const ArtifactCard: React.FC<{\n artifact: NonNullable<MessageContentProps['message']['artifact']>\n onClick?: () => void\n}> = ({ artifact, onClick }) => {\n const emitInteraction = useInteractionDispatch()\n const iconName = fileTypeIcon(artifact.name || artifact.type)\n\n return (\n <div\n className=\"ycw-artifact-card\"\n onClick={() => {\n emitInteraction('artifact-click', artifact.id, { name: artifact.name, type: artifact.type })\n onClick?.()\n }}\n data-artifact-id={artifact.id}\n data-artifact-name={artifact.name}\n data-artifact-mime={artifact.type}\n >\n <span className=\"ycw-artifact-icon\">\n <Icon name={iconName} size={18} aria-hidden />\n </span>\n <div className=\"ycw-artifact-info\">\n <div className=\"ycw-artifact-name\">{artifact.name}</div>\n <div className=\"ycw-artifact-meta\">{artifact.type}</div>\n </div>\n {artifact.size && (\n <span className=\"ycw-artifact-size\">{artifact.size}</span>\n )}\n </div>\n )\n}\n","import React from 'react'\nimport type { AggregatedMessage } from '../../types'\nimport { useChatWidgetI18n } from '../../i18n'\nimport { parseMcpToolInfo } from '../../utils/messageParser'\n\nexport const McpToolEvent: React.FC<{ message: AggregatedMessage; content: string }> = ({ message, content }) => {\n const { messages: i18n } = useChatWidgetI18n()\n const { toolName, toolLabel, statusIcon, statusClass } = parseMcpToolInfo(message, content)\n\n let statusText = ''\n if (message.notificationType === 'mcp_start') {\n statusText = i18n['tool.mcp.running']\n } else if (message.notificationType === 'mcp_end') {\n statusText = message.toolStatus === 'error' ? i18n['tool.mcp.error'] : i18n['tool.mcp.success']\n }\n\n return (\n <div className={`ycw-tool-execution ${statusClass}`}>\n <span className=\"ycw-tool-icon\">{statusIcon}</span>\n <span className=\"ycw-tool-text\">{toolLabel}{toolName && toolName !== toolLabel ? ` (${toolName})` : ''}</span>\n {statusText && <span className=\"ycw-tool-status\">{statusText}</span>}\n </div>\n )\n}\n","import type { AggregatedMessage } from '../types'\n\nexport interface McpToolInfo {\n toolName: string | null\n toolLabel: string\n statusIcon: string\n statusClass: string\n}\n\nconst TOOL_REGEX = /[🔧\\s]*(.+?)\\s*\\((\\w+)\\)/\nconst TOOL_EXEC_REGEX = /[🔧\\s]*execute tool:\\s*(\\S+)/\nconst TOOL_LINE_REGEX = /^[🔧\\s]*execute tool:\\s*(\\S+)\\s*$/m\n\nexport function parseMcpToolInfo(message: AggregatedMessage, content: string): McpToolInfo {\n const toolName = message.toolName || (() => {\n const match = content.match(TOOL_REGEX) || content.match(TOOL_EXEC_REGEX)\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\n if (message.notificationType === 'mcp_start') {\n statusIcon = '⏳'\n statusClass = 'ycw-tool-running'\n } else if (message.notificationType === 'mcp_end') {\n if (message.toolStatus === 'error') {\n statusIcon = '❌'\n statusClass = 'ycw-tool-error'\n } else {\n statusIcon = '✅'\n statusClass = 'ycw-tool-success'\n }\n } else {\n statusIcon = '🔧'\n statusClass = 'ycw-tool-running'\n }\n\n return { toolName, toolLabel, statusIcon, statusClass }\n}\n\nexport function isMcpEvent(message: AggregatedMessage): boolean {\n return !!message.notificationType && ['mcp_start', 'mcp_result', 'mcp_end'].includes(message.notificationType)\n}\n\nexport interface LegacyToolMatch {\n toolName: string\n beforeContent: string\n afterContent: string\n}\n\nexport function matchLegacyToolLine(content: string): LegacyToolMatch | null {\n const toolMatch = content.match(TOOL_LINE_REGEX)\n if (!toolMatch) return null\n\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 { toolName, beforeContent, afterContent }\n}\n","import React 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 { useChatWidgetI18n } from '../../i18n'\nimport type { LegacyToolMatch } from '../../utils/messageParser'\n\nconst math = createMathPlugin({ singleDollarTextMath: true })\nconst streamdownPlugins = { code, mermaid, math, cjk }\n\nexport const LegacyToolLine: React.FC<{ match: LegacyToolMatch }> = ({ match }) => {\n const { t } = useChatWidgetI18n()\n return (\n <>\n {match.beforeContent && (\n <div className=\"sd-message\">\n <Streamdown plugins={streamdownPlugins}>{match.beforeContent}</Streamdown>\n </div>\n )}\n <div className=\"ycw-tool-execution\">\n <span className=\"ycw-tool-icon\">🔧</span>\n <span className=\"ycw-tool-text\">{t('tool.executing', { name: match.toolName })}</span>\n </div>\n {match.afterContent && (\n <div className=\"sd-message\">\n <Streamdown plugins={streamdownPlugins}>{match.afterContent}</Streamdown>\n </div>\n )}\n </>\n )\n}\n","/**\n * JETP-033: JsonRenderCard — inline UI card rendered in the chat message stream.\n *\n * Renders a json-render Spec from accumulated JSONL patches delivered via\n * gen_ui_card SSE messages. Progressively builds the spec as patches arrive.\n */\n\nimport React from 'react'\nimport {\n Renderer,\n StateProvider,\n ActionProvider,\n VisibilityProvider,\n ValidationProvider,\n} from '@json-render/react'\nimport { useActionBridge } from './ActionBridge'\nimport { useGenUISpec } from './useGenUISpec'\nimport type { ChatWidgetAdapter } from '../../types.js'\nimport './JsonRenderCard.css'\n// CWRF-013 Phase 1 PR-P1-#3 — Tailwind v4 + scoped-preflight source CSS.\n// Same scope as JsonRenderViewer; both card and viewer must render shadcn\n// components inside `.ycw-shadcn` for the reset to apply consistently.\nimport '../../styles/shadcn.css'\n\nclass CardErrorBoundary extends React.Component<\n { children: React.ReactNode; specId: string },\n { error: Error | null }\n> {\n state = { error: null as Error | null }\n static getDerivedStateFromError(error: Error) { return { error } }\n componentDidCatch(err: Error) {\n console.error('[JETP-033] Card Renderer crashed for spec:', this.props.specId, err)\n }\n render() {\n if (this.state.error) {\n return (\n <div style={{ padding: 12, color: '#b91c1c', fontSize: 12, border: '1px solid #fca5a5', borderRadius: 8, background: '#fef2f2' }}>\n <strong>Card render error</strong>\n <pre style={{ whiteSpace: 'pre-wrap', marginTop: 6, fontSize: 11 }}>\n {this.state.error.message}\n </pre>\n </div>\n )\n }\n return this.props.children\n }\n}\n\nexport interface JsonRenderCardProps {\n specId: string\n patches: string[]\n loading?: boolean\n adapter: ChatWidgetAdapter\n sessionId: number | null\n /**\n * JETP-003 ADR-006 v1.1.2 / WS2.6 — current chat-widget client_id.\n * When provided, ActionBridge attaches it to every HIL submission so\n * /api/human-response can attribute the action to the originating window.\n */\n clientId?: string | null\n interactionId?: string\n agentWaiting?: boolean\n /**\n * JETP-083 WS3.7.7 follow-up — originating agent instance for trace_id /\n * file metadata on ``POST /api/human-response``. When omitted ActionBridge\n * sends ``0`` (sentinel; the field is observational for A2UI no-files\n * submissions but must be present on the wire because FastAPI declares\n * it as a required Form field).\n */\n agentInstanceId?: number\n registry: unknown\n}\n\nexport const JsonRenderCard: React.FC<JsonRenderCardProps> = ({\n specId,\n patches,\n loading = true,\n adapter,\n sessionId,\n clientId,\n interactionId,\n agentWaiting = false,\n agentInstanceId,\n registry,\n}) => {\n const { spec, store } = useGenUISpec(specId, patches, loading)\n\n const { handlers: actionHandlers, isLocked } = useActionBridge(specId, {\n adapter,\n sessionId,\n clientId,\n interactionId,\n agentWaiting,\n agentInstanceId,\n })\n\n console.log('[JETP-033] JsonRenderCard spec:', {\n specId,\n hasSpec: !!spec,\n root: spec?.root,\n elementKeys: spec?.elements ? Object.keys(spec.elements) : null,\n stateKeys: spec?.state ? Object.keys(spec.state) : null,\n hasStore: !!store,\n registryType: typeof registry,\n isLocked,\n })\n\n if (!spec?.root || !spec?.elements) return null\n\n const stateProviderProps = store\n ? { store }\n : { initialState: spec.state ?? {} }\n\n // JETP-033 WS3.7.7 follow-up — post-submit card lock.\n //\n // Once ``useActionBridge`` flips ``isLocked=true`` (user submitted a\n // HIL response, or the spec was already resolved on mount/hydrate),\n // wrap the rendered tree in a ``<fieldset disabled>``. This is the\n // single cleanest mechanism for blanket-disabling every native form\n // element (button / input / select / textarea / contenteditable…)\n // without having to teach every json-render component about a\n // ``disabled`` prop. CSS class ``jr-card-locked`` adds visual cues\n // (opacity, cursor) and ``pointer-events: none`` on non-form children\n // (e.g., div-based custom clickables that fieldset alone can't reach).\n //\n // Why not unmount the Renderer or strip handlers: we want the user\n // to still SEE their submitted values (rejected + comment text) and\n // any post-submit state updates the agent might push. The locked\n // form remains visible, just non-interactive.\n const rendererContent = (\n <Renderer\n spec={spec}\n registry={registry as never}\n loading={loading}\n />\n )\n\n return (\n <div\n className={`jr-card-container${isLocked ? ' jr-card-locked' : ''}`}\n data-spec-id={specId}\n data-locked={isLocked || undefined}\n >\n <CardErrorBoundary specId={specId}>\n <StateProvider {...stateProviderProps}>\n <VisibilityProvider>\n <ActionProvider handlers={actionHandlers}>\n {/*\n JETP-033 / CWRF-013 form-root-cause fix — ValidationProvider\n must wrap the Renderer for any spec that uses shadcn input\n primitives directly (Input / Textarea / Select / Slider /\n Switch / Checkbox / Radio). Those components call\n ``useValidation()`` which throws \"useValidation must be used\n within a ValidationProvider\" when no Provider is mounted.\n FormSection has its own native HTML controls and dodged the\n requirement; FormField + shadcn control composition (the\n LLM's preferred pattern) did not. Mounting a default\n ValidationProvider here gives every spec a working\n validation context with zero authoring overhead, so authors\n only need to push validators when they actually want\n custom rules.\n */}\n <ValidationProvider>\n {/* CWRF-013 Phase 1 PR-P1-#3 — `.ycw-shadcn` scope wrapper.\n Mirrors the wrapper in JsonRenderViewer so shadcn 36\n components (Phase 1 Tier 1.3.b) render with the same\n Tailwind preflight scope, regardless of whether the spec\n is shown as an inline card or full-page viewer. */}\n <div className=\"ycw-shadcn\">\n {isLocked ? (\n <fieldset disabled className=\"jr-card-lock-fieldset\">\n {rendererContent}\n </fieldset>\n ) : (\n rendererContent\n )}\n </div>\n </ValidationProvider>\n </ActionProvider>\n </VisibilityProvider>\n </StateProvider>\n </CardErrorBoundary>\n </div>\n )\n}\n\nexport default JsonRenderCard\n","/**\n * JETP-033: ActionBridge — unified action routing from json-render UI to backend.\n *\n * Registers a handler for every action defined in the catalog so that\n * ActionProvider's direct `handlers[resolved.action]` lookup always finds\n * a match. Each handler delegates to a unified dispatch function that\n * routes through the correct channel:\n *\n * - local: state-only (json-render built-in)\n * - data-fetch: adapter.getResourceContent → ctx.set(statePath)\n * - registered-mcp (act_*): HIL endpoint + action_id → backend allowlist\n * - hil-release: adapter.submitHITLResponse → release waiting agent\n * - multi-round: HIL endpoint, backend correlates rounds\n * - subscription-trigger: HIL endpoint → DataSubManager.pull_once\n * - client-only: export, navigate, clipboard\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { ActionHandler as JRActionHandler } from '@json-render/core'\nimport type { ChatWidgetAdapter, HITLResponse } from '../../types.js'\nimport catalog from '../JsonRender/domain/catalog.js'\nimport { useGenUI } from './GenUIContext'\n\n/**\n * JETP-033 WS3.7.7 follow-up (live bug 2026-05-12) — return shape for\n * ``useActionBridge``.\n *\n * Adds ``isLocked``: ``true`` once the user has submitted a HIL action\n * (hil-release / multi-round / subscription-trigger) on this spec, so the\n * card can disable every form input / button / select / actionable element\n * and prevent a double-submit. Without this, the post-submit card stays\n * fully interactive — repeated clicks fire late ``/api/human-response``\n * requests that the backend then has to short-circuit via\n * ``already_resolved`` (see ``hil_action_handler._handle_hil_release``)\n * which is a band-aid: the user-visible problem is that the card LOOKS\n * actionable when it isn't, and the second click might even submit to a\n * stale spec_id (the live bug that started this thread).\n *\n * Why not infer purely from ``pendingHILBySpecId`` removal: that signal\n * comes through ``useGenUIPending`` hydration, which arrives ~hundreds of\n * ms after the click (round-trip + push). Locking at the dispatch site\n * gives instant feedback. We additionally track \"was-pending and now\n * isn't\" via a ref so reload/hydrate of already-resolved cards also lock,\n * but the dispatch-side lock is the authoritative live signal.\n */\nexport interface ActionBridgeResult {\n handlers: Record<string, JRActionHandler>\n /**\n * Whether the card this hook serves should be visually + functionally\n * locked (no more clicks, inputs disabled, faded). Flipped to ``true``\n * the moment a HIL submission resolves on the wire, OR when this spec\n * was previously pending but no longer is (hydrate / late ack).\n */\n isLocked: boolean\n}\n\ntype ActionCategory =\n | 'local'\n | 'data-fetch'\n | 'registered-mcp'\n | 'hil-release'\n | 'multi-round'\n | 'subscription-trigger'\n | 'client-only'\n\ninterface ActionBridgeContext {\n adapter: ChatWidgetAdapter\n sessionId: number | null\n /**\n * JETP-003 ADR-006 v1.1.2 / WS2.6 — current chat-widget client_id\n * (V2 ``c_<22 base62>``). When provided, every HIL submission\n * (registered-mcp, hil-release, multi-round, subscription-trigger)\n * carries it back to /api/human-response so the backend can attribute\n * the action to the originating window. `null`/`undefined` are\n * tolerated during bootstrap (Stage A grayscale; jetagents emits\n * hip_client_id_missing_total Counter + WARN log).\n */\n clientId?: string | null\n interactionId?: string\n agentWaiting: boolean\n /**\n * JETP-083 WS3.7.7 follow-up — agent instance that emitted this spec.\n *\n * Backend ``POST /api/human-response`` declares ``agent_instance_id`` as\n * a required Form field (``Form(...)``); FastAPI rejects the request with\n * 422 when it's missing. The value is observational (trace_id derivation,\n * file metadata) for A2UI no-files HIL releases, so passing ``0`` is a\n * functionally safe sentinel — but threading the real instance id from\n * the originating message gives operators the right correlation in logs.\n *\n * When omitted, ActionBridge sends ``0`` to keep the wire shape valid.\n */\n agentInstanceId?: number\n}\n\ninterface ActionExecCtx {\n set: (path: string, value: unknown) => void\n get: (path: string) => unknown\n}\n\nfunction inferCategory(\n actionName: string,\n agentWaiting: boolean,\n): ActionCategory {\n if (actionName.startsWith('act_')) return 'registered-mcp'\n if (/^(fetch|load|refresh)/i.test(actionName)) return 'data-fetch'\n if (/^(submit|approve|reject)/i.test(actionName)) {\n return agentWaiting ? 'hil-release' : 'data-fetch'\n }\n if (/^(authorize|verify|confirm)/i.test(actionName)) return 'multi-round'\n if (/^(export|navigate|copy)/i.test(actionName)) return 'client-only'\n return 'local'\n}\n\nexport function useActionBridge(\n specId: string,\n bridgeCtx: ActionBridgeContext,\n): ActionBridgeResult {\n const { adapter, sessionId, clientId, interactionId, agentWaiting, agentInstanceId } = bridgeCtx\n\n // JETP-033 WS3.7.7 follow-up — dispatch-side lock signal.\n //\n // Flipped to ``true`` once a HIL-category dispatch (hil-release,\n // multi-round, subscription-trigger) resolves on the wire. Cannot be\n // un-flipped: HIL is a one-shot interaction per spec; if the agent\n // needs another round, it MUST emit a new spec (different spec_id),\n // which is a fresh ``JsonRenderCard`` instance with its own\n // ``useActionBridge`` invocation → starts at ``false`` again.\n const [hasSubmitted, setHasSubmitted] = useState(false)\n\n // JETP-083 WS3.7.7 follow-up — per-spec HIL waiting signal.\n //\n // Background: the previous `agentWaiting` came from\n // `executionStatus === 'running'` in ChatWidget.tsx, which is a\n // session-wide proxy. The moment the backend agent paused on a HIL\n // (`_await_genui_blocking`), the model stream ended → executionStatus\n // transitioned out of 'running' → `agentWaiting=false`. `inferCategory`\n // then mapped `submit/approve/reject` to **`data-fetch`** instead of\n // **`hil-release`**, and the data-fetch branch silently no-op'd\n // (`if (!resourceId || sessionId == null) return`) — observable symptom:\n // clicking the spec card produced **no** POST /api/human-response. The\n // monitor badge correctly showed \"等待人工\" (after the parallel patch)\n // but the card itself was dead.\n //\n // Fix: also consult `pendingHILBySpecId` (populated by `useGenUIPending`\n // hydration + `gen_ui_meta/pending` push). If THIS spec has an entry\n // there, the agent is, definitionally, waiting on this spec → route as\n // `hil-release`. This is per-spec, survives executionStatus transitions,\n // and aligns with the backend `HilRegistry` state instead of an inferred\n // stream proxy.\n //\n // Backward-compat: if the host doesn't supply `pendingHILBySpecId`\n // (GenUIContext absent, or hydration disabled) we fall back to the\n // previous `agentWaiting` flag — no regression for older embeddings.\n const genUICtx = useGenUI()\n const hasPendingHilForThisSpec = Boolean(\n genUICtx?.pendingHILBySpecId?.get(specId),\n )\n const effectiveAgentWaiting = agentWaiting || hasPendingHilForThisSpec\n // [HIL-DEBUG] Per-render state snapshot for the gating values that decide\n // hil-release vs. data-fetch routing. Logged only when the gating state\n // changes meaningfully (not every parent re-render) to keep noise down.\n useEffect(() => {\n console.log('[HIL-DEBUG] useActionBridge state', {\n specId,\n agentWaiting,\n hasPendingHilForThisSpec,\n effectiveAgentWaiting,\n pendingMapSize: genUICtx?.pendingHILBySpecId?.size ?? null,\n sessionId,\n clientId: clientId ?? null,\n interactionId: interactionId ?? null,\n })\n }, [\n specId,\n agentWaiting,\n hasPendingHilForThisSpec,\n effectiveAgentWaiting,\n sessionId,\n clientId,\n interactionId,\n genUICtx?.pendingHILBySpecId,\n ])\n\n const dispatch = useCallback(\n async (\n actionName: string,\n params: Record<string, unknown>,\n ctx: ActionExecCtx,\n ) => {\n const meta = (params as { __meta?: { category?: ActionCategory } })?.__meta\n const category = meta?.category ?? inferCategory(actionName, effectiveAgentWaiting)\n // JETP-083 WS3.7.7 follow-up — [HIL-DEBUG] dispatch tracing.\n // Logged once per user-initiated dispatch (clicks / form submits).\n // The user-visible symptom we're hunting is \"click → no network\": this\n // log line answers (a) was dispatch even reached, (b) what category did\n // we resolve, (c) what gating values produced that category.\n console.log('[HIL-DEBUG] ActionBridge.dispatch() entry', {\n actionName,\n category,\n specId,\n agentWaiting,\n hasPendingHilForThisSpec,\n effectiveAgentWaiting,\n sessionId,\n clientId,\n interactionId: interactionId ?? null,\n paramsKeys: params ? Object.keys(params) : [],\n explicitMetaCategory: meta?.category ?? null,\n })\n\n // JETP-003 ADR-006 v1.1.2 / WS2.6 — single helper to attach client_id\n // to every HIL submission shape used below. Avoids forgetting one branch\n // when adding new action categories. Treats null and undefined the\n // same (omit the field rather than send null).\n const withClientId = (resp: HITLResponse): HITLResponse => {\n if (clientId) resp.client_id = clientId\n return resp\n }\n // JETP-083 WS3.7.7 follow-up — every ``/api/human-response`` Form field\n // marked required by FastAPI (``session_id`` int, ``agent_instance_id``\n // int, ``await_command_uuid`` str) must be present on the wire, even\n // for no-files A2UI submissions. Pre-fix the adapter only populated\n // these inside the files-attached branch → 422 on the JSON path. We\n // attach them once here so every category (registered-mcp, hil-release,\n // multi-round, subscription-trigger) is wire-compliant.\n const withRequiredFormFields = (resp: HITLResponse): HITLResponse => {\n if (resp.session_id == null && sessionId != null) resp.session_id = sessionId\n if (resp.agent_instance_id == null) {\n // Sentinel ``0`` is functionally safe — the value is observational\n // (trace_id, file callee). Real id is preferred when threaded.\n resp.agent_instance_id = agentInstanceId ?? 0\n }\n return resp\n }\n const buildHilResponse = (resp: HITLResponse): HITLResponse =>\n withClientId(withRequiredFormFields(resp))\n\n switch (category) {\n case 'registered-mcp': {\n const { __actionName, __meta, __files, ...rest } = params\n const hilResponse: HITLResponse = buildHilResponse({\n await_command_uuid: interactionId ?? '',\n data: { __action: actionName, spec_id: specId, ...rest },\n confirmed: true,\n })\n if (Array.isArray(__files) && __files.length > 0) {\n hilResponse.files = __files as File[]\n }\n await adapter.submitHITLResponse(hilResponse)\n return\n }\n case 'data-fetch': {\n const resourceId = params.resourceId as string\n const targetStatePath = params.targetStatePath as string | undefined\n const loadingPath = params.loadingPath as string | undefined\n if (!resourceId || sessionId == null) {\n // [HIL-DEBUG] The silent no-op trap that masked HIL submissions\n // when effectiveAgentWaiting flipped to false. Surfacing it as a\n // warn makes the failure mode legible from the console.\n console.warn('[HIL-DEBUG] ActionBridge data-fetch noop', {\n actionName,\n specId,\n resourceId: resourceId ?? null,\n sessionId,\n hint:\n 'submit*/approve/reject hit data-fetch (agentWaiting=false). If you expected HIL release, the upstream agentWaiting + pendingHILBySpecId combination did not flip in time.',\n })\n return\n }\n try {\n if (loadingPath) ctx.set(loadingPath, true)\n const data = await adapter.getResourceContent(sessionId, resourceId)\n const parsed = typeof data.content === 'string'\n ? JSON.parse(data.content)\n : data.content\n if (targetStatePath) {\n ctx.set(targetStatePath, parsed)\n }\n } catch (err) {\n console.error('[ActionBridge] data-fetch failed:', err)\n } finally {\n if (loadingPath) ctx.set(loadingPath, false)\n }\n break\n }\n case 'hil-release': {\n const { __files, ...rawData } = (params.data ?? params) as Record<string, unknown>\n const hilResponse: HITLResponse = buildHilResponse({\n await_command_uuid: interactionId ?? '',\n data: {\n __action: actionName || 'submit',\n spec_id: specId,\n category: 'hil-release',\n ...rawData,\n },\n confirmed: true,\n })\n if (Array.isArray(__files) && __files.length > 0) {\n hilResponse.files = __files as File[]\n }\n console.log('[HIL-DEBUG] ActionBridge → adapter.submitHITLResponse (hil-release)', {\n actionName,\n specId,\n await_command_uuid: hilResponse.await_command_uuid,\n await_command_uuid_present: Boolean(hilResponse.await_command_uuid),\n client_id: hilResponse.client_id ?? null,\n session_id: hilResponse.session_id ?? null,\n dataKeys: Object.keys(hilResponse.data ?? {}),\n fileCount: hilResponse.files?.length ?? 0,\n })\n try {\n await adapter.submitHITLResponse(hilResponse)\n console.log('[HIL-DEBUG] ActionBridge ← submitHITLResponse resolved (hil-release)', { actionName, specId })\n // JETP-033 WS3.7.7 follow-up — lock card after successful\n // hil-release. Prevents the double-submit class of bugs\n // (live bug 2026-05-12) where the user could re-edit the\n // form and click Submit again on a spec the agent has\n // already moved past, producing late requests that\n // ``_handle_hil_release`` then has to short-circuit with\n // ``already_resolved`` — a path that should be exceptional,\n // not the default UX.\n setHasSubmitted(true)\n } catch (err) {\n console.error('[HIL-DEBUG] ActionBridge ← submitHITLResponse rejected (hil-release)', { actionName, specId, err })\n throw err\n }\n break\n }\n case 'multi-round': {\n const { __actionName, __meta, ...rest } = params\n const hilResponse: HITLResponse = buildHilResponse({\n await_command_uuid: interactionId ?? '',\n data: {\n __action: actionName || 'submit',\n spec_id: specId,\n category: 'multi-round',\n interaction_id: interactionId,\n ...rest,\n },\n confirmed: true,\n })\n await adapter.submitHITLResponse(hilResponse)\n // Same rationale as hil-release: lock after submit. Multi-round\n // continues the conversation via a NEW spec id (the next agent\n // round emits a fresh card), so we never need to unlock — the\n // new spec is a new card with its own useActionBridge state.\n setHasSubmitted(true)\n break\n }\n case 'subscription-trigger': {\n const hilResponse: HITLResponse = buildHilResponse({\n await_command_uuid: interactionId ?? '',\n data: {\n __action: '__subscription_pull',\n spec_id: specId,\n category: 'subscription-trigger',\n },\n confirmed: true,\n })\n await adapter.submitHITLResponse(hilResponse)\n // Subscription-trigger explicitly hands control back to the\n // backend's DataSubManager.pull_once; the spec is done as far\n // as user input is concerned.\n setHasSubmitted(true)\n break\n }\n case 'client-only': {\n if (/^navigate/i.test(actionName) && params.url) {\n window.open(String(params.url), '_blank', 'noopener')\n } else if (/^copy/i.test(actionName) && params.value != null) {\n try {\n await navigator.clipboard.writeText(String(params.value))\n } catch (err) {\n console.error('[ActionBridge] clipboard write failed:', err)\n }\n } else if (/^export/i.test(actionName)) {\n const format = String(params.format ?? 'html')\n const container = document.querySelector(`[data-spec-id=\"${specId}\"]`)\n if (!container) return\n if (format === 'pdf' && typeof window.print === 'function') {\n window.print()\n } else {\n const html = container.outerHTML\n const blob = new Blob([html], { type: 'text/html' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `report-${specId}.html`\n a.click()\n URL.revokeObjectURL(url)\n }\n }\n break\n }\n case 'local':\n default:\n break\n }\n },\n [adapter, sessionId, clientId, interactionId, specId, effectiveAgentWaiting, agentInstanceId],\n )\n\n // JETP-083 WS3.7.7 follow-up — stable handler map with latest-dispatch via ref.\n //\n // Why this needs a ref, not a fresh Proxy per `dispatch` change:\n //\n // `@json-render/react`'s `ActionProvider` does\n // `const [handlers, setHandlers] = useState(initialHandlers)`,\n // which **locks** the handlers Proxy to whatever this hook returned on\n // the FIRST render of the card. If we returned a new Proxy on every\n // `dispatch` change (e.g. when `effectiveAgentWaiting` flips after the\n // card mounts), ActionProvider would never see it — it keeps invoking\n // the *first* Proxy, whose closure captured the *stale* dispatch.\n //\n // Practical consequence: card mounts while `executionStatus === 'running'`\n // (agentWaiting=true), backend pauses on HIL, executionStatus transitions\n // out of 'running' so agentWaiting=false; the new ActionBridge dispatch\n // uses the corrected `effectiveAgentWaiting` (true via pendingHILBySpecId),\n // but ActionProvider keeps the old Proxy + old dispatch (which might still\n // have a workable category in many cases, but is subtly out-of-sync with\n // clientId/interactionId updates and gives \"no observable network\" when\n // the card was rendered while the agent had already paused).\n //\n // Fix: return ONE stable Proxy whose `get` trap calls `dispatchRef.current`.\n // We keep the ref in sync via `useEffect`. The Proxy reference stays the\n // same forever, so ActionProvider's `useState` lock-in becomes harmless.\n const dispatchRef = useRef(dispatch)\n useEffect(() => {\n dispatchRef.current = dispatch\n }, [dispatch])\n\n // JETP-033 WS3.7.7 follow-up — hydrate-path lock detection.\n //\n // ``hasSubmitted`` only covers the in-session live click. For two\n // other paths we also need to lock:\n // 1. Reload while a card was previously resolved — backend has no\n // pending HIL entry for it, but the spec elements are still\n // rendered (state store keeps the user's last entered values).\n // 2. Late hydration — pending entry briefly present then removed\n // by ``useGenUIPending``'s reconciliation against the registry.\n //\n // We track \"this spec was once pending, and now it isn't\" via a ref.\n // The ref survives re-renders but resets on remount (which is exactly\n // what we want: a NEW spec id = a new card = should NOT be locked).\n const wasPendingRef = useRef(false)\n useEffect(() => {\n if (hasPendingHilForThisSpec) {\n wasPendingRef.current = true\n }\n }, [hasPendingHilForThisSpec])\n const wasPendingAndNowResolved =\n wasPendingRef.current && !hasPendingHilForThisSpec\n\n const isLocked = hasSubmitted || wasPendingAndNowResolved\n\n const stableHandlers = useMemo(() => {\n const target: Record<string, JRActionHandler> = {}\n const actionNames = catalog.actionNames as string[]\n\n for (const name of actionNames) {\n target[name] = ((\n params: Record<string, unknown>,\n ctx: ActionExecCtx,\n ) => dispatchRef.current(name, params, ctx)) as JRActionHandler\n }\n\n return new Proxy(target, {\n get(obj, prop) {\n if (typeof prop !== 'string') return Reflect.get(obj, prop)\n // [HIL-DEBUG] Proxy.get tracing — fires on every ActionProvider\n // handler lookup. Keep this enabled while we investigate \"click ⇒\n // no network\". The cost is O(1) per click and a single console line.\n const isKnown = prop in obj\n console.log('[HIL-DEBUG] ActionBridge Proxy.get', {\n prop,\n isKnown,\n specId,\n })\n if (isKnown) return obj[prop]\n return ((\n params: Record<string, unknown>,\n ctx: ActionExecCtx,\n ) => dispatchRef.current(prop, params, ctx)) as JRActionHandler\n },\n })\n // Intentionally a once-per-mount memo (no deps): the Proxy is stable\n // and reads `dispatchRef.current` lazily for the latest dispatch.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n return { handlers: stableHandlers, isLocked }\n}\n","/**\n * JETP-033: GenUIContext — provides adapter, session, and registry context\n * to JsonRenderCard / JsonRenderViewer without prop-threading.\n */\n\nimport React, { createContext, useContext } from 'react'\nimport type { ChatWidgetAdapter, PendingHIL, SpecLifecycleEntry } from '../../types.js'\n\ninterface GenUIContextValue {\n adapter: ChatWidgetAdapter\n sessionId: number | null\n /**\n * JETP-003 ADR-006 v1.1.2 / WS2.6 — current chat-widget window/conversation\n * client_id (V2 ``c_<22 base62>``) propagated to ActionBridge / json-render\n * so HIL submissions carry attribution back to /api/human-response.\n *\n * `null` permitted during transient bootstrap (session being created, cid\n * being allocated). ActionBridge treats null/undefined the same — it just\n * omits the field, triggering Stage A grayscale telemetry on the server.\n */\n clientId?: string | null\n interactionId?: string\n agentWaiting: boolean\n registry: unknown\n openPageViewer?: (specId?: string) => void\n\n /**\n * JETP-083 WS3.7.6 + A3 follow-up — per-spec pending HIL summary, populated\n * by `useGenUIPending`. Spec cards rendered in MessageContent read this to\n * show an \"Awaiting your input\" ribbon when their spec_id has an entry.\n *\n * Empty / undefined when (a) widget host opts out of hydration, (b) backend\n * doesn't yet implement `/api/genui/pending` (supported=false), or\n * (c) session has no pending HILs.\n */\n pendingHILBySpecId?: Map<string, PendingHIL>\n\n /**\n * JETP-083 WS3.7.5 / JETP-033 WS1.1 + A1 follow-up — per-spec terminal\n * lifecycle marker (cancelled / error). Set by the aggregator's\n * `gen_ui_meta` handler when the backend pushes `/_meta/cancelled` or\n * `/_meta/error` JSON-Patch payloads. Spec cards render a state overlay\n * (cancelled banner, budget-exceeded notice) when present.\n */\n specLifecycleBySpecId?: Map<string, SpecLifecycleEntry>\n}\n\nconst GenUIContext = createContext<GenUIContextValue | null>(null)\n\nexport const GenUIProvider: React.FC<\n GenUIContextValue & { children: React.ReactNode }\n> = ({ children, ...value }) => (\n <GenUIContext.Provider value={value}>{children}</GenUIContext.Provider>\n)\n\nexport function useGenUI(): GenUIContextValue | null {\n return useContext(GenUIContext)\n}\n","import { useEffect, useState, useRef } from 'react'\nimport { snapToSafeBoundary } from '../utils/typewriterUtils'\n\n/**\n * Typewriter hook with baseline-watermark semantics.\n *\n * On first mount (or whenever `resetKey` changes), the current `content.length`\n * is treated as already revealed — the visible text snaps to the full content\n * with no animation. Only characters appended *after* that point are animated.\n *\n * This collapses every replay scenario into a single rule and removes the\n * \"history messages re-typing\" feel when scrolling back into older rounds:\n * - history-only round → mount with full content → no animation\n * - recovery + live tail → mount with recovered prefix → animate the tail\n * - fresh live message → mount with empty content → animate everything\n * - virtualized remount → mount with current snapshot → animate future deltas\n *\n * Returns [displayedContent, isTyping].\n */\nexport function useTypewriter(\n content: string,\n enabled: boolean,\n speed: number = 30,\n resetKey?: string,\n): [string, boolean] {\n const [displayedLength, setDisplayedLength] = useState(content.length)\n const [isTyping, setIsTyping] = useState(false)\n const rafRef = useRef<number | null>(null)\n const targetLengthRef = useRef(content.length)\n const displayedLengthRef = useRef(content.length)\n const lastResetKeyRef = useRef(resetKey)\n\n displayedLengthRef.current = displayedLength\n\n useEffect(() => {\n if (lastResetKeyRef.current === resetKey) return\n lastResetKeyRef.current = resetKey\n if (rafRef.current) {\n cancelAnimationFrame(rafRef.current)\n rafRef.current = null\n }\n setIsTyping(false)\n setDisplayedLength(content.length)\n displayedLengthRef.current = content.length\n targetLengthRef.current = content.length\n }, [resetKey, content.length])\n\n useEffect(() => {\n if (!enabled) {\n setDisplayedLength(content.length)\n displayedLengthRef.current = 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","/**\n * Typewriter safe-boundary utilities.\n * Ensures Markdown content is not truncated mid-fence or mid-formula.\n */\n\nexport function 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 * Snap a raw displayedLength to a Markdown-safe boundary:\n * 1. ``` fence line → jump to EOL\n * 2. Accumulating ``` → jump to EOL\n * 3. Inside $$ block → jump past closing $$\n * 4. Inside $ inline → jump past closing $\n */\nexport function 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 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 if (slice.endsWith('$') && length < content.length && content[length] === '$') {\n return snapToSafeBoundary(content, length + 1)\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 const totalDollars = countOccurrences(slice, '$')\n const singleDollars = totalDollars - 2 * ddCount\n if (singleDollars % 2 === 1) {\n let searchPos = length\n while (searchPos < content.length) {\n const idx = content.indexOf('$', searchPos)\n if (idx === -1) break\n if (idx + 1 < content.length && content[idx + 1] === '$') {\n searchPos = idx + 2\n continue\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 * 子 Agent 卡片组件\n * 可折叠,固定高度,内部滚动\n */\n\nimport React, { useState, useRef, useEffect } from 'react'\nimport type { ChildAgentCardProps, Artifact, PoolAgentAction } from '../types'\nimport { mergeConsecutiveThinkMessages } from '../types'\nimport MessageContent from './MessageContent'\nimport { useChatWidgetI18n } from '../i18n'\nimport { useInteractionDispatch } from '../hooks/useInteractionDispatch'\nimport { useChildAgentStatus } from '../hooks/useChildAgentStatus'\nimport { Icon } from './Icon/Icon'\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 onHITLSubmit,\n defaultExpanded = false,\n parentTaskPurpose,\n endedAgentInstanceIds,\n allRoundMessages,\n observedInstanceStates,\n}) => {\n const [isExpanded, setIsExpanded] = useState(defaultExpanded)\n const contentRef = useRef<HTMLDivElement>(null)\n const { messages } = useChatWidgetI18n()\n const emitInteraction = useInteractionDispatch()\n\n const heuristicStatus = useChildAgentStatus({ message, children, endedAgentInstanceIds, allRoundMessages })\n const observedEntry = observedInstanceStates?.get(message.agentInstanceId)\n const status = observedEntry\n ? (observedEntry.state === 'RUNNING' ? 'running' as const : 'completed' as const)\n : heuristicStatus\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 // Pick the most relevant recent action to show in the collapsed header:\n // prefer the latest running action; fall back to the most recent completed one.\n const recentActions: PoolAgentAction[] = observedEntry?.recent_actions ?? []\n let latestAction: PoolAgentAction | undefined\n for (let i = recentActions.length - 1; i >= 0; i--) {\n if (recentActions[i]?.status === 'running') { latestAction = recentActions[i]; break }\n }\n if (!latestAction && recentActions.length > 0) latestAction = recentActions[recentActions.length - 1]\n\n return (\n <div className={`ycw-child-agent-card ${isExpanded ? 'ycw-expanded' : ''}`}>\n <div \n className=\"ycw-child-agent-header\"\n onClick={() => {\n emitInteraction('child-agent-toggle', message.agentName || 'child-agent', { expanded: !isExpanded, agentInstanceId: message.agentInstanceId })\n setIsExpanded(!isExpanded)\n }}\n >\n <div className=\"ycw-child-agent-title\">\n <span className=\"ycw-card-title\">{cardTitle}</span>\n {!isExpanded && latestAction && (\n <span className={`ycw-child-agent-latest-action ${latestAction.status === 'running' ? 'ycw-action-running' : ''}`}>\n <span className=\"ycw-latest-action-tool\">{latestAction.tool}</span>\n {latestAction.purpose && (\n <span className=\"ycw-latest-action-purpose\">{latestAction.purpose}</span>\n )}\n </span>\n )}\n </div>\n <div className=\"ycw-child-agent-status\">\n <span className={`ycw-status-badge ycw-status-${status}`}>\n <span className={`ycw-status-icon ${status === 'running' ? 'ycw-spinning' : ''}`}>\n <Icon\n name={status === 'running' ? 'hourglass' : 'check'}\n size={14}\n aria-hidden={true}\n />\n </span>\n <span className=\"ycw-status-text\">{status === 'running' ? messages['childAgent.status.running'] : messages['childAgent.status.completed']}</span>\n </span>\n <span className={`ycw-collapse-arrow ${isExpanded ? 'ycw-expanded' : ''}`}>\n <Icon name=\"caretDown\" size={10} aria-hidden={true} />\n </span>\n </div>\n </div>\n \n {isExpanded && (\n <div \n className=\"ycw-child-agent-content\"\n ref={contentRef}\n style={{ maxHeight }}\n >\n <div className=\"ycw-child-agent-inner\">\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 onHITLSubmit={onHITLSubmit}\n observedInstanceStates={observedInstanceStates}\n />\n )}\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 onHITLSubmit={onHITLSubmit}\n observedInstanceStates={observedInstanceStates}\n />\n ))}\n </div>\n <div className=\"ycw-child-agent-footer\">\n <span className=\"ycw-footer-agent-icon\">\n <Icon name=\"robot\" size={12} aria-hidden={true} />\n </span>\n <span className=\"ycw-footer-agent-name\">{message.agentName}</span>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default ChildAgentCard\n","import { useMemo } from 'react'\nimport type { AggregatedMessage } from '../types'\n\nexport type ChildAgentStatus = 'running' | 'completed'\n\nexport interface UseChildAgentStatusOptions {\n message: AggregatedMessage\n children: AggregatedMessage[]\n endedAgentInstanceIds?: Set<number>\n allRoundMessages?: AggregatedMessage[]\n}\n\nexport function useChildAgentStatus(options: UseChildAgentStatusOptions): ChildAgentStatus {\n const { message, children, endedAgentInstanceIds, allRoundMessages } = options\n\n const allMessages = useMemo(() => [message, ...children], [message, children])\n\n const hasExplicitEnd = endedAgentInstanceIds != null && endedAgentInstanceIds.has(message.agentInstanceId)\n\n const hasActiveContent = allMessages.some(\n m => m.contentType === 'text' && m.contentChunks.join('').trim()\n )\n\n const hasInProgressTool = useMemo(() => {\n const fromAllMessages = allMessages.some(\n m => m.toolPhase === 'generating' || m.toolPhase === 'executing'\n )\n if (fromAllMessages) return true\n if (allRoundMessages == null) return false\n return allRoundMessages.some(\n m => m.agentInstanceId === message.agentInstanceId\n && (m.toolPhase === 'generating' || m.toolPhase === 'executing')\n )\n }, [allMessages, allRoundMessages, message.agentInstanceId])\n\n if (hasExplicitEnd) return 'completed'\n return hasActiveContent && !hasInProgressTool ? 'completed' : 'running'\n}\n","/**\n * RoundsView ── ChatWidget 主对话流的可复用渲染组件\n *\n * 设计目标:\n * 把 ChatWidget.tsx 里 `localRounds.map(...)` + RoundHeader + RoundMessageList\n * 的内联 markup 抽成单一组件,让:\n * 1. ChatWidget 内部两处(overlay / immersive 主区)共享同一份渲染逻辑;\n * 2. 外部消费者(如 yumiai-web 工作空间浮窗)能直接 import SDK 主流的\"对话气泡 +\n * 子 agent 卡 + 工具卡 + plan / todo 头\"完整一套,而不再自造样式。\n *\n * 不变量:\n * - 不依赖 ChatWidget 上下文,只接受 props(rounds + config + 可选 callback)。\n * - 调用方需保证某个祖先节点带 `.ycw` 主题 class(color/spacing token 的来源)。\n * - 只渲染 round 列表本身,不负责 header / sidebar / composer / 加载状态等。\n * scroll 容器、自动滚动到底部、上拉分页等也由调用方决定(保持组件原子)。\n *\n * 与 ChatWidget 主流的等价性:\n * markup 与 ChatWidget.tsx#1457-1474 / #1700-1722 完全一致:\n * <div class=\"ycw-message-list-container\">\n * <div class=\"ycw-message-list\">\n * {rounds.map(round => (\n * <Fragment>\n * {index > 0 && <div class=\"ycw-round-separator\">…</div>}\n * <div class=\"ycw-round-container\">\n * <RoundHeader … todoMap={todoMap} />\n * <RoundMessageList … observedInstanceStates={…} />\n * </div>\n * </Fragment>\n * ))}\n * </div>\n * </div>\n */\n\nimport React from 'react'\nimport { useChatWidgetI18n } from '../i18n'\nimport RoundHeader from './RoundHeader'\nimport RoundMessageList from './RoundMessageList'\nimport { DEFAULT_CONFIG } from '../types'\nimport type {\n Round,\n ChatWidgetConfig,\n TodoData,\n HITLResponse,\n ToolCallData,\n PoolAgent,\n Artifact,\n} from '../types'\nimport './RoundsView.css'\n\nexport interface RoundsViewProps {\n /** 待渲染的轮次列表(顺序 = 时间正序)。 */\n rounds: Round[]\n /** ChatWidget 配置;不传则用 DEFAULT_CONFIG。 */\n config?: ChatWidgetConfig\n /** controller.todoMap,传入则 RoundHeader 会显示 todo 进度。 */\n todoMap?: Map<string, TodoData>\n /** controller.poolObservation.instanceStates,子 Agent 卡用它判断 running/ended。 */\n observedInstanceStates?: Map<number, PoolAgent>\n /** Artifact 点击回调(chip 等位置打开预览时使用)。 */\n onArtifactClick?: (artifact: Artifact) => void\n /** HITL 表单提交回调。 */\n onHITLSubmit?: (response: HITLResponse) => Promise<void>\n /** 自定义 tool 渲染。 */\n renderToolResult?: (displayType: string, data: ToolCallData) => React.ReactNode | null\n /** 空态自定义;不传则不渲染任何东西(让外层贴自己的空态)。 */\n emptyFallback?: React.ReactNode\n /** 容器自定义 className(追加在 .ycw-message-list-container 上)。 */\n className?: string\n /** 测试钩子。 */\n testId?: string\n}\n\n/**\n * RoundsView ──「per-round Header + RoundMessageList」批量渲染。\n *\n * 注意:本组件只负责渲染当前传入的 rounds,**不做过滤 / 排序 / 去重**。\n * 调用方(如 ChatWidget per-cid 视图、yumiai-web 浮窗)自己根据\n * cid / sid / scope 把 controller.rounds 切片后再传进来。\n */\nconst RoundsView: React.FC<RoundsViewProps> = ({\n rounds,\n config,\n todoMap,\n observedInstanceStates,\n onArtifactClick,\n onHITLSubmit,\n renderToolResult,\n emptyFallback,\n className,\n testId,\n}) => {\n const { messages: i18n } = useChatWidgetI18n()\n const effectiveConfig = (config ?? DEFAULT_CONFIG) as Required<ChatWidgetConfig>\n\n if (rounds.length === 0) {\n if (emptyFallback === undefined) return null\n return (\n <div\n className={`ycw-message-list-container${className ? ` ${className}` : ''}`}\n data-testid={testId}\n >\n <div className=\"ycw-message-list\">{emptyFallback}</div>\n </div>\n )\n }\n\n return (\n <div\n className={`ycw-message-list-container${className ? ` ${className}` : ''}`}\n data-testid={testId}\n >\n <div className=\"ycw-message-list\">\n {rounds.map((round, index) => (\n <React.Fragment key={`rv-${round.interactionId ?? round.index}`}>\n {index > 0 && (\n <div className=\"ycw-round-separator\">{i18n['round.separator']}</div>\n )}\n <div className=\"ycw-round-container\" data-round={round.index}>\n <RoundHeader\n round={round}\n isPinned={false}\n config={effectiveConfig}\n todoMap={todoMap}\n />\n <RoundMessageList\n round={round}\n config={effectiveConfig}\n onArtifactClick={onArtifactClick}\n onHITLSubmit={onHITLSubmit}\n renderToolResult={renderToolResult}\n observedInstanceStates={observedInstanceStates}\n />\n </div>\n </React.Fragment>\n ))}\n </div>\n </div>\n )\n}\n\nexport default RoundsView\n","import React, { Suspense, lazy } from 'react'\nimport type { ResourceContent, XrefRecord, KicadCanvasSelectionPayload } from '../../types.js'\nimport { getFileCategory, getExtension, inferLanguage } from './utils/fileCategory'\nimport { contentToSrc } from './utils/contentUrl'\nimport { TextCore, CodeCore, MarkdownCore, JsonCore, ImageCore, VideoCore, AudioCore } from '../ViewerCore/index'\nimport HtmlViewer from './viewers/HtmlViewer'\nimport type { HtmlViewerSelectionState, HtmlProjectOptions } from './viewers/HtmlViewer'\nimport FallbackViewer from './viewers/FallbackViewer'\nimport GerberViewer from './viewers/GerberViewer'\nimport ViewerLoading from './viewers/ViewerLoading'\nimport { useChatWidgetI18n } from '../../i18n'\n\nconst PdfViewerCore = lazy(() => import('./viewers/PdfViewerCore'))\nconst KicadViewerCore = lazy(() => import('./viewers/KicadViewerCore'))\nconst ThreeViewerCore = lazy(() => import('./viewers/ThreeViewerCore'))\nconst StepViewerCore = lazy(() => import('./viewers/StepViewerCore'))\nconst WordCore = lazy(() => import('../ViewerCore/WordCore'))\nconst ExcelCore = lazy(() => import('../ViewerCore/ExcelCore'))\nconst PowerPointCore = lazy(() => import('../ViewerCore/PowerPointCore'))\n\nexport type { KicadCanvasSelectionPayload }\n\nexport interface FileViewerKicadOptions {\n /** 覆盖默认 KiCanvas 脚本 URL(也可用构建时 VITE_KICANVAS_SCRIPT_URL) */\n kicanvasScriptUrl?: string\n onKicadCanvasSelection?: (payload: KicadCanvasSelectionPayload) => void\n /** Sync kicanvas UI chrome + canvas background with chat-widget theme */\n kicanvasTheme?: import('./viewers/KicadViewerCore').KicanvasJpTheme\n /** Controlled view mode for external toggle */\n view?: 'canvas' | 'source'\n onViewChange?: (v: 'canvas' | 'source') => void\n /** Multi-file project files (CWRF-009) */\n files?: import('./viewers/KicadViewerCore').KicadFile[]\n /** True while project files are still being discovered */\n projectLoading?: boolean\n}\n\nexport interface FileViewerGerberOptions {\n onGerberSelection?: (payload: import('./viewers/GerberViewer').GerberLayerSelectPayload) => void\n}\n\nexport interface FileViewerPdfOptions {\n onImageSelect?: (sel: import('./viewers/PdfViewerCore').PdfImageSelection | null) => void\n}\n\nexport interface FileViewerProps {\n content: ResourceContent\n onXrefClick?: (xref: XrefRecord) => void\n onLinkClick?: (url: string) => void\n onHtmlSelectionChange?: (selection: HtmlViewerSelectionState | null) => void\n className?: string\n kicadOptions?: FileViewerKicadOptions\n gerberOptions?: FileViewerGerberOptions\n pdfOptions?: FileViewerPdfOptions\n /** CWRF-011: passthrough for multi-file HTML project options. */\n htmlOptions?: HtmlProjectOptions\n}\n\nconst FileViewer: React.FC<FileViewerProps> = ({ content, onXrefClick, onLinkClick, onHtmlSelectionChange, className, kicadOptions, gerberOptions, pdfOptions, htmlOptions }) => {\n const { t } = useChatWidgetI18n()\n const ext = getExtension(content.file_name)\n const category = getFileCategory(ext, content.mime_type)\n\n const xrefCb = onXrefClick ? (xref: unknown) => onXrefClick(xref as XrefRecord) : undefined\n\n const viewer = (() => {\n switch (category) {\n case 'markdown':\n return <div className=\"ycw-file-viewer-markdown\"><MarkdownCore content={content.content} onXrefClick={xrefCb} onLinkClick={onLinkClick} /></div>\n case 'code':\n return <div className=\"ycw-file-viewer-code\"><CodeCore content={content.content} language={content.language || inferLanguage(ext)} onXrefClick={xrefCb} onLinkClick={onLinkClick} /></div>\n case 'text':\n return <div className=\"ycw-file-viewer-text\"><TextCore content={content.content} onXrefClick={xrefCb} onLinkClick={onLinkClick} /></div>\n case 'image':\n return <div className=\"ycw-file-viewer-image\"><ImageCore src={contentToSrc(content)} alt={content.file_name} zoomInLabel={t('viewer.zoomIn')} zoomOutLabel={t('viewer.zoomOut')} resetLabel={t('viewer.zoomReset')} /></div>\n case 'video':\n return <div className=\"ycw-file-viewer-video\"><VideoCore src={contentToSrc(content)} mimeType={content.mime_type ?? undefined} /></div>\n case 'audio':\n return <div className=\"ycw-file-viewer-audio\"><AudioCore src={contentToSrc(content)} mimeType={content.mime_type ?? undefined} /></div>\n case 'html':\n return <HtmlViewer content={content.content} fileName={content.file_name} htmlOptions={htmlOptions} onSelectionChange={onHtmlSelectionChange} onXrefClick={xrefCb} onLinkClick={onLinkClick} />\n case 'json':\n return <div className=\"ycw-file-viewer-json\"><JsonCore data={content.content} onXrefClick={xrefCb} onLinkClick={onLinkClick} /></div>\n case 'pdf':\n return (\n <Suspense fallback={<ViewerLoading label={t('viewer.loadingPdf')} />}>\n <PdfViewerCore src={contentToSrc(content)} onImageSelect={pdfOptions?.onImageSelect} />\n </Suspense>\n )\n case 'kicad':\n return (\n <Suspense fallback={<ViewerLoading label={t('viewer.loadingKicad')} />}>\n <KicadViewerCore\n content={content.content}\n fileName={content.file_name}\n contentUrl={content.content_url}\n kicanvasScriptUrl={kicadOptions?.kicanvasScriptUrl}\n onCanvasSelection={kicadOptions?.onKicadCanvasSelection}\n kicanvasTheme={kicadOptions?.kicanvasTheme}\n view={kicadOptions?.view}\n onViewChange={kicadOptions?.onViewChange}\n files={kicadOptions?.files}\n />\n </Suspense>\n )\n case '3d':\n return (\n <Suspense fallback={<ViewerLoading label={t('viewer.loading3d')} />}>\n <ThreeViewerCore src={contentToSrc(content)} fileName={content.file_name} />\n </Suspense>\n )\n case 'step':\n return (\n <Suspense fallback={<ViewerLoading label={t('viewer.loadingStep')} />}>\n <StepViewerCore src={contentToSrc(content)} fileName={content.file_name} />\n </Suspense>\n )\n case 'gerber':\n return <GerberViewer content={content} onGerberSelection={gerberOptions?.onGerberSelection} />\n case 'word':\n return (\n <Suspense fallback={<ViewerLoading label={t('viewer.loadingWord')} />}>\n <WordCore src={contentToSrc(content)} onLinkClick={onLinkClick} loadingLabel={t('viewer.loadingWord')} />\n </Suspense>\n )\n case 'excel':\n return (\n <Suspense fallback={<ViewerLoading label={t('viewer.loadingExcel')} />}>\n {content.is_text_readable && !content.is_binary\n ? <ExcelCore content={content.content} loadingLabel={t('viewer.loadingExcel')} rowsLabel={t('viewer.excelRows')} columnsLabel={t('viewer.excelColumns')} onXrefClick={xrefCb} onLinkClick={onLinkClick} />\n : <ExcelCore src={contentToSrc(content)} loadingLabel={t('viewer.loadingExcel')} rowsLabel={t('viewer.excelRows')} columnsLabel={t('viewer.excelColumns')} />}\n </Suspense>\n )\n case 'powerpoint':\n return (\n <Suspense fallback={<ViewerLoading label={t('viewer.loadingPowerPoint')} />}>\n <PowerPointCore\n src={contentToSrc(content)}\n onLinkClick={onLinkClick}\n loadingLabel={t('viewer.loadingPowerPoint')}\n prevLabel={t('viewer.pptPrev')}\n nextLabel={t('viewer.pptNext')}\n slideLabel={t('viewer.pptSlide')}\n thumbnailsLabel={t('viewer.pptThumbnails')}\n />\n </Suspense>\n )\n default:\n return <FallbackViewer content={content} />\n }\n })()\n\n return (\n <div className={`ycw-file-viewer ${className || ''}`}>\n {viewer}\n </div>\n )\n}\n\nexport default FileViewer\n","import type { FileCategory } from '../../../types.js'\n\nconst CATEGORY_MAP: Record<string, FileCategory> = {\n '.md': 'markdown', '.mdx': 'markdown', '.markdown': 'markdown',\n\n '.py': 'code', '.pyi': 'code', '.pyw': 'code',\n '.js': 'code', '.jsx': 'code', '.mjs': 'code', '.cjs': 'code',\n '.ts': 'code', '.tsx': 'code', '.mts': 'code', '.cts': 'code',\n '.go': 'code', '.rs': 'code',\n '.c': 'code', '.h': 'code', '.cpp': 'code', '.cc': 'code', '.cxx': 'code', '.hpp': 'code',\n '.java': 'code', '.kt': 'code', '.kts': 'code', '.scala': 'code',\n '.rb': 'code', '.php': 'code', '.swift': 'code', '.dart': 'code',\n '.r': 'code', '.lua': 'code', '.zig': 'code',\n '.sh': 'code', '.bash': 'code', '.zsh': 'code', '.ps1': 'code',\n '.sql': 'code', '.graphql': 'code', '.gql': 'code',\n '.yaml': 'code', '.yml': 'code', '.toml': 'code',\n '.xml': 'code', '.xsl': 'code', '.xsd': 'code',\n '.css': 'code', '.scss': 'code', '.less': 'code',\n '.vue': 'code', '.svelte': 'code',\n '.ex': 'code', '.exs': 'code', '.erl': 'code',\n '.hs': 'code', '.ml': 'code', '.mli': 'code',\n '.proto': 'code', '.dockerfile': 'code',\n '.makefile': 'code', '.mk': 'code', '.cmake': 'code',\n\n '.txt': 'text', '.log': 'text',\n '.gitignore': 'text',\n\n '.csv': 'excel', '.tsv': 'excel',\n\n '.ini': 'code', '.cfg': 'code', '.conf': 'code',\n '.env': 'code', '.editorconfig': 'code',\n '.properties': 'code', '.rst': 'code',\n\n '.jpg': 'image', '.jpeg': 'image', '.png': 'image',\n '.gif': 'image', '.webp': 'image', '.svg': 'image',\n '.bmp': 'image', '.ico': 'image', '.avif': 'image',\n\n '.mp4': 'video', '.webm': 'video', '.mov': 'video',\n '.ogv': 'video', '.avi': 'video', '.mkv': 'video',\n\n '.mp3': 'audio', '.wav': 'audio', '.ogg': 'audio',\n '.m4a': 'audio', '.flac': 'audio', '.aac': 'audio',\n\n '.html': 'html', '.htm': 'html',\n\n '.json': 'json', '.jsonc': 'json', '.json5': 'json',\n '.geojson': 'json', '.webmanifest': 'json',\n\n '.pdf': 'pdf',\n\n '.kicad_sch': 'kicad', '.kicad_pcb': 'kicad',\n '.kicad_sym': 'kicad', '.kicad_pro': 'kicad',\n\n '.stl': '3d', '.obj': '3d', '.gltf': '3d', '.glb': '3d', '.3mf': '3d',\n\n '.step': 'step', '.stp': 'step', '.iges': 'step', '.igs': 'step',\n\n '.doc': 'word', '.docx': 'word', '.docm': 'word', '.dot': 'word',\n '.dotx': 'word', '.dotm': 'word', '.rtf': 'word', '.odt': 'word',\n '.xls': 'excel', '.xlsx': 'excel', '.xlsm': 'excel', '.xlt': 'excel',\n '.xltx': 'excel', '.xltm': 'excel', '.xlsb': 'excel', '.ods': 'excel',\n '.ppt': 'powerpoint', '.pptx': 'powerpoint', '.pptm': 'powerpoint',\n '.pot': 'powerpoint', '.potx': 'powerpoint', '.potm': 'powerpoint',\n '.pps': 'powerpoint', '.ppsx': 'powerpoint', '.ppsm': 'powerpoint', '.odp': 'powerpoint',\n\n '.gbr': 'gerber', '.gerber': 'gerber',\n '.gtl': 'gerber', '.gbl': 'gerber', '.gto': 'gerber', '.gbo': 'gerber',\n '.gts': 'gerber', '.gbs': 'gerber', '.gko': 'gerber', '.gm1': 'gerber',\n '.gm2': 'gerber', '.gm3': 'gerber', '.gm4': 'gerber', '.gbx': 'gerber',\n '.gtp': 'gerber', '.gbp': 'gerber',\n '.drl': 'gerber', '.dri': 'gerber',\n '.pho': 'gerber', '.art': 'gerber', '.rou': 'gerber',\n '.bot': 'gerber', '.top': 'gerber',\n '.sob': 'gerber', '.sot': 'gerber',\n '.smb': 'gerber', '.smt': 'gerber',\n '.ssb': 'gerber', '.sst': 'gerber',\n '.pmb': 'gerber', '.pmt': 'gerber',\n}\n\nexport function getFileCategory(ext: string, mimeType: string | null): FileCategory {\n const lower = ext.toLowerCase()\n\n if (lower in CATEGORY_MAP) return CATEGORY_MAP[lower]\n\n // G+数字 (.g2, .g3 ...) / GP+数字 (.gp1, .gp2 ...) — KiCad/Protel 内层铜箔\n if (/^\\.g\\d+$/.test(lower) || /^\\.gp\\d+$/.test(lower)) return 'gerber'\n\n if (mimeType) {\n if (mimeType.startsWith('image/')) return 'image'\n if (mimeType.startsWith('video/')) return 'video'\n if (mimeType.startsWith('audio/')) return 'audio'\n if (mimeType === 'application/pdf') return 'pdf'\n if (mimeType === 'text/html') return 'html'\n if (mimeType === 'application/json') return 'json'\n if (mimeType === 'text/markdown') return 'markdown'\n if (mimeType === 'text/csv' || mimeType === 'text/tab-separated-values') return 'excel'\n if (mimeType.startsWith('text/')) return 'text'\n if (/gerber/i.test(mimeType)) return 'gerber'\n if (mimeType.includes('wordprocessingml') || mimeType === 'application/msword') return 'word'\n if (mimeType.includes('spreadsheetml') || mimeType === 'application/vnd.ms-excel') return 'excel'\n if (mimeType.includes('presentationml') || mimeType === 'application/vnd.ms-powerpoint') return 'powerpoint'\n }\n\n return 'unknown'\n}\n\nexport function getExtension(fileName: string | undefined | null): string {\n if (!fileName) return ''\n const lastDot = fileName.lastIndexOf('.')\n if (lastDot < 0) return ''\n const parts = fileName.split('.')\n if (parts.length >= 3) {\n const doubleExt = '.' + parts.slice(-2).join('_')\n if (doubleExt in CATEGORY_MAP) return doubleExt\n }\n return fileName.substring(lastDot)\n}\n\nconst EXT_TO_LANG: Record<string, string> = {\n '.py': 'python', '.pyi': 'python', '.pyw': 'python',\n '.js': 'javascript', '.jsx': 'javascript', '.mjs': 'javascript', '.cjs': 'javascript',\n '.ts': 'typescript', '.tsx': 'typescript', '.mts': 'typescript', '.cts': 'typescript',\n '.go': 'go', '.rs': 'rust',\n '.c': 'c', '.h': 'c', '.cpp': 'cpp', '.cc': 'cpp', '.cxx': 'cpp', '.hpp': 'cpp',\n '.java': 'java', '.rb': 'ruby', '.php': 'php',\n '.swift': 'swift', '.kt': 'kotlin', '.kts': 'kotlin', '.scala': 'scala',\n '.r': 'r', '.lua': 'lua', '.zig': 'zig',\n '.sh': 'bash', '.bash': 'bash', '.zsh': 'bash', '.ps1': 'powershell',\n '.sql': 'sql', '.graphql': 'graphql', '.gql': 'graphql',\n '.yaml': 'yaml', '.yml': 'yaml', '.toml': 'toml',\n '.ini': 'ini', '.cfg': 'ini', '.conf': 'ini',\n '.env': 'bash', '.editorconfig': 'ini', '.properties': 'properties',\n '.rst': 'rst',\n '.xml': 'xml', '.xsl': 'xml', '.xsd': 'xml',\n '.css': 'css', '.scss': 'scss', '.less': 'less',\n '.vue': 'vue', '.svelte': 'svelte', '.dart': 'dart',\n '.ex': 'elixir', '.exs': 'elixir', '.erl': 'erlang',\n '.hs': 'haskell', '.ml': 'ocaml', '.mli': 'ocaml',\n '.proto': 'protobuf', '.dockerfile': 'dockerfile',\n '.makefile': 'makefile', '.mk': 'makefile', '.cmake': 'cmake',\n '.html': 'html', '.htm': 'html', '.json': 'json',\n '.md': 'markdown', '.mdx': 'markdown',\n}\n\nexport function inferLanguage(ext: string): string {\n return EXT_TO_LANG[ext.toLowerCase()] || 'text'\n}\n","import type { ResourceContent } from '../../../types.js'\n\n/**\n * Convert ResourceContent to a renderable source URL.\n * Priority: content_url > data URI (small binary) > Blob URL (large binary) > raw text.\n */\nexport function contentToSrc(res: ResourceContent): string {\n if (res.content_url) {\n return res.content_url\n }\n if (res.is_binary && res.mime_type && res.file_size && res.file_size < 2 * 1024 * 1024) {\n return `data:${res.mime_type};base64,${res.content}`\n }\n if (res.is_binary && res.mime_type) {\n const binary = atob(res.content)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)\n const blob = new Blob([bytes], { type: res.mime_type })\n return URL.createObjectURL(blob)\n }\n return res.content ?? ''\n}\n\nexport function formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n","import React, { useCallback } from 'react'\nimport type { ResourceContent } from '../../../types.js'\nimport { contentToSrc, formatFileSize } from '../utils/contentUrl'\nimport { useChatWidgetI18n } from '../../../i18n'\n\ninterface FallbackViewerProps {\n content: ResourceContent\n}\n\nconst FallbackViewer: React.FC<FallbackViewerProps> = ({ content }) => {\n const { t } = useChatWidgetI18n()\n const handleDownload = useCallback(() => {\n const src = contentToSrc(content)\n const a = document.createElement('a')\n a.href = src\n a.download = content.file_name\n a.click()\n if (src.startsWith('blob:')) URL.revokeObjectURL(src)\n }, [content])\n\n return (\n <div className=\"ycw-file-viewer-fallback\">\n <div className=\"ycw-fallback-icon\">📎</div>\n <div className=\"ycw-fallback-info\">\n <div className=\"ycw-fallback-name\">{content.file_name}</div>\n <div className=\"ycw-fallback-meta\">\n <span>{content.mime_type || t('viewer.fallback.unknownType')}</span>\n {content.file_size != null && (\n <span>{formatFileSize(content.file_size)}</span>\n )}\n </div>\n <div className=\"ycw-fallback-path\">{content.git_path}</div>\n </div>\n <button className=\"ycw-fallback-download\" onClick={handleDownload}>\n {t('viewer.fallback.download')}\n </button>\n </div>\n )\n}\n\nexport default FallbackViewer\n","import React from 'react'\nimport { useChatWidgetI18n } from '../../../i18n'\n\ninterface ViewerLoadingProps {\n label?: string\n}\n\nconst ViewerLoading: React.FC<ViewerLoadingProps> = ({ label }) => {\n const { t } = useChatWidgetI18n()\n return (\n <div className=\"ycw-file-viewer-loading\">\n <span className=\"loading-spinner\" />\n <span>{label ?? t('viewer.loading')}</span>\n </div>\n )\n}\n\nexport default ViewerLoading\n","import React, { useState, useCallback, useEffect, useMemo, useRef } from 'react'\nimport { Drawer, Button } from 'antd'\nimport type { ResourceContent, Artifact, XrefRecord, XrefRef, ChatWidgetAdapter } from '../../types.js'\nimport { getFileCategory, getExtension } from './utils/fileCategory'\nimport { contentToSrc, formatFileSize } from './utils/contentUrl'\nimport FileViewer from './FileViewer'\nimport ViewerLoading from './viewers/ViewerLoading'\nimport { useChatWidgetI18n } from '../../i18n'\nimport { useXrefScrollToTarget } from '../../hooks/useXrefScrollToTarget'\n\nconst MAX_STACK_DEPTH = 10\n\ninterface ViewerStackEntry {\n resource: ResourceContent\n artifact?: Artifact\n targetLocation?: string | null\n}\n\nexport interface FileViewerModalProps {\n open: boolean\n onClose: () => void\n initialResource: ResourceContent | null\n initialArtifact?: Artifact | null\n loading?: boolean\n error?: string | null\n adapter?: ChatWidgetAdapter\n sessionId?: number | null\n}\n\nconst CATEGORY_ICONS: Record<string, string> = {\n markdown: '📝', code: '💻', text: '📄', image: '🖼️',\n video: '🎬', audio: '🎵', html: '🌐', json: '📊',\n pdf: '📕', kicad: '📐', gerber: '🔌', '3d': '📦', step: '📦',\n unknown: '📎',\n}\n\nconst FileViewerModal: React.FC<FileViewerModalProps> = ({\n open, onClose, initialResource, initialArtifact,\n loading, error, adapter, sessionId,\n}) => {\n const { t } = useChatWidgetI18n()\n const [stack, setStack] = useState<ViewerStackEntry[]>([])\n const [isFullscreen, setIsFullscreen] = useState(false)\n const [navLoading, setNavLoading] = useState(false)\n const bodyRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (initialResource) {\n setStack([{ resource: initialResource, artifact: initialArtifact || undefined }])\n } else {\n setStack([])\n }\n }, [initialResource, initialArtifact])\n\n const currentEntry = stack[stack.length - 1]\n const canGoBack = stack.length > 1\n\n const handleXrefClick = useCallback(async (xref: XrefRecord) => {\n if (!xref.target_file_id || !adapter || !sessionId) return\n\n let resourceId = xref.target_file_id\n if (adapter.resolveXrefs) {\n try {\n const [meta] = await adapter.resolveXrefs([{\n uri: xref.target_resource,\n description: xref.description,\n relation: xref.relation as XrefRef['relation'],\n }])\n if (meta?.resource_id) resourceId = meta.resource_id\n } catch {\n // fall through with original targetFileId\n }\n }\n\n setNavLoading(true)\n try {\n const content = await adapter.getResourceContent(sessionId, resourceId)\n setStack(prev => {\n const next = [...prev, {\n resource: content,\n targetLocation: xref.target_location,\n }]\n return next.length > MAX_STACK_DEPTH ? next.slice(1) : next\n })\n } catch (err) {\n console.error('[FileViewerModal] Failed to load xref target:', err)\n } finally {\n setNavLoading(false)\n }\n }, [adapter, sessionId])\n\n useXrefScrollToTarget({\n targetLocation: currentEntry?.targetLocation,\n loading: !!(loading || navLoading),\n containerRef: bodyRef,\n })\n\n const handleClose = useCallback(() => {\n setStack([])\n setIsFullscreen(false)\n onClose()\n }, [onClose])\n\n const handleDownload = useCallback(() => {\n if (!currentEntry) return\n const src = contentToSrc(currentEntry.resource)\n const a = document.createElement('a')\n a.href = src\n a.download = currentEntry.resource.file_name\n a.click()\n if (src.startsWith('blob:')) URL.revokeObjectURL(src)\n }, [currentEntry])\n\n const handleBack = useCallback(() => {\n setStack(prev => prev.slice(0, -1))\n }, [])\n\n const currentCategory = useMemo(() => {\n if (!currentEntry) return 'unknown'\n const ext = getExtension(currentEntry.resource.file_name)\n return getFileCategory(ext, currentEntry.resource.mime_type)\n }, [currentEntry])\n\n const fileIcon = useMemo(\n () => CATEGORY_ICONS[currentCategory] || '📄',\n [currentCategory],\n )\n\n // KiCad / Gerber: resolve presigned URL for canvas & iframe embeds\n useEffect(() => {\n if (currentCategory !== 'kicad' && currentCategory !== 'gerber') return\n if (!currentEntry || !adapter || !sessionId) return\n if (currentEntry.resource.content_url) return\n\n let cancelled = false\n if (adapter.getResourceUrl) {\n adapter.getResourceUrl(sessionId, currentEntry.resource.resource_id)\n .then(url => {\n if (!cancelled && url) {\n setStack(prev => {\n const last = prev[prev.length - 1]\n if (!last) return prev\n return [...prev.slice(0, -1), { ...last, resource: { ...last.resource, content_url: url } }]\n })\n }\n })\n .catch(() => {})\n }\n return () => { cancelled = true }\n }, [currentCategory, currentEntry?.resource.resource_id, adapter, sessionId])\n\n return (\n <Drawer\n open={open}\n onClose={handleClose}\n styles={{ wrapper: { width: isFullscreen ? '100%' : 720 } }}\n title={\n <div className=\"ycw-fvm-header\">\n {canGoBack && (\n <Button type=\"text\" size=\"small\" onClick={handleBack}>{t('viewer.back')}</Button>\n )}\n <span className=\"ycw-fvm-icon\">{fileIcon}</span>\n <span className=\"ycw-fvm-title\">\n {currentEntry?.artifact?.name || currentEntry?.resource.file_name || t('viewer.defaultTitle')}\n </span>\n {stack.length > 1 && (\n <span className=\"ycw-fvm-depth\">{stack.length}</span>\n )}\n </div>\n }\n extra={\n <div className=\"ycw-fvm-actions\">\n <Button type=\"text\" size=\"small\" onClick={handleDownload} title={t('viewer.download')}>⬇</Button>\n <Button\n type=\"text\"\n size=\"small\"\n onClick={() => setIsFullscreen(!isFullscreen)}\n title={isFullscreen ? t('viewer.fullscreenExit') : t('viewer.fullscreen')}\n >\n {isFullscreen ? '⊡' : '⊞'}\n </Button>\n </div>\n }\n className=\"ycw-file-viewer-modal\"\n destroyOnClose\n >\n {currentEntry && (\n <div className=\"ycw-fvm-meta\">\n <span>{currentEntry.resource.mime_type || t('viewer.unknownType')}</span>\n {currentEntry.resource.file_size != null && (\n <span>{formatFileSize(currentEntry.resource.file_size)}</span>\n )}\n <span className=\"ycw-fvm-path\">{currentEntry.resource.git_path}</span>\n </div>\n )}\n\n <div className=\"ycw-fvm-body\" ref={bodyRef}>\n {(loading || navLoading) && <ViewerLoading label={t('viewer.loading')} />}\n {error && <div className=\"ycw-fvm-error\">{error}</div>}\n {currentEntry && !loading && !navLoading && !error && (\n <FileViewer\n content={currentEntry.resource}\n onXrefClick={handleXrefClick}\n />\n )}\n </div>\n </Drawer>\n )\n}\n\nexport default FileViewerModal\n","import { useEffect } from 'react'\n\ninterface UseXrefScrollToTargetOptions {\n targetLocation: string | null | undefined\n loading: boolean\n containerRef: React.RefObject<HTMLDivElement | null>\n}\n\n/**\n * After xref navigation, scroll the container to the heading\n * that matches targetLocation (§-prefixed or bare text).\n */\nexport function useXrefScrollToTarget({\n targetLocation,\n loading,\n containerRef,\n}: UseXrefScrollToTargetOptions): void {\n useEffect(() => {\n if (!targetLocation || loading) return\n const container = containerRef.current\n if (!container) return\n\n const bare = targetLocation.replace(/^§/, '')\n\n const findAndScroll = (): boolean => {\n const headings = container.querySelectorAll('h1, h2, h3, h4, h5, h6')\n for (const h of headings) {\n const text = (h.textContent || '').trim()\n if (\n text.includes(targetLocation) ||\n text.includes(bare) ||\n text.replace(/^[\\d.§]+\\s*/, '') === bare\n ) {\n h.scrollIntoView({ behavior: 'smooth', block: 'start' })\n return true\n }\n }\n return false\n }\n\n if (findAndScroll()) return\n\n const observer = new MutationObserver(() => {\n if (findAndScroll()) observer.disconnect()\n })\n observer.observe(container, { childList: true, subtree: true })\n const fallback = setTimeout(() => observer.disconnect(), 8000)\n return () => {\n observer.disconnect()\n clearTimeout(fallback)\n }\n }, [targetLocation, loading, containerRef])\n}\n","import React, { useState, useCallback, useEffect, useMemo, useRef } from 'react'\nimport type { ChatWidgetAdapter, FileReference } from '../../types.js'\nimport type { KicadFile } from './viewers/KicadViewerCore'\nimport type { HtmlFile } from './viewers/HtmlViewer/types.js'\nimport { contentToSrc, formatFileSize } from './utils/contentUrl'\nimport FileViewer from './FileViewer'\nimport ViewerLoading from './viewers/ViewerLoading'\nimport Breadcrumb from './Breadcrumb'\nimport { useSelectionBridge } from '../ContextBridge/useSelectionBridge'\nimport FloatingToolbar from '../ContextBridge/FloatingToolbar'\nimport { setCwrfClipboardRef } from '../ContextBridge/useSmartPaste'\nimport { useChatWidgetI18n } from '../../i18n'\nimport { useInteractionDispatch } from '../../hooks/useInteractionDispatch'\nimport { useFileViewerNavigation } from '../../hooks/useFileViewerNavigation'\nimport { useXrefScrollToTarget } from '../../hooks/useXrefScrollToTarget'\nimport { useNativeCopyInterceptor } from '../../hooks/useNativeCopyInterceptor'\nimport { Icon } from '../Icon/Icon'\nimport './FileViewer.css'\n\nconst KICAD_DESIGN_EXTS = [\n '.kicad_sch', '.kicad_pcb', '.kicad_pro',\n '.kicad_sym', '.kicad_mod', '.kicad_wks', '.kicad_dru',\n]\n\n// CWRF-011: extensions that participate in an HTML project bundle.\nconst HTML_PROJECT_EXTS = [\n '.html', '.htm',\n '.css',\n '.js', '.mjs', '.cjs',\n '.json', '.json5',\n '.svg',\n '.png', '.jpg', '.jpeg', '.gif', '.webp', '.avif', '.ico', '.bmp',\n '.woff', '.woff2', '.ttf', '.otf', '.eot',\n '.mp3', '.wav', '.ogg', '.m4a',\n '.mp4', '.webm', '.mov',\n '.txt', '.md',\n]\nconst HTML_TEXT_EXTS = new Set([\n '.html', '.htm', '.css', '.js', '.mjs', '.cjs',\n '.json', '.json5', '.svg', '.txt', '.md',\n])\nconst HTML_MIME_BY_EXT: Record<string, string> = {\n '.html': 'text/html', '.htm': 'text/html',\n '.css': 'text/css',\n '.js': 'text/javascript', '.mjs': 'text/javascript', '.cjs': 'text/javascript',\n '.json': 'application/json', '.json5': 'application/json',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg',\n '.gif': 'image/gif', '.webp': 'image/webp', '.avif': 'image/avif',\n '.ico': 'image/x-icon', '.bmp': 'image/bmp',\n '.woff': 'font/woff', '.woff2': 'font/woff2',\n '.ttf': 'font/ttf', '.otf': 'font/otf',\n '.eot': 'application/vnd.ms-fontobject',\n '.mp3': 'audio/mpeg', '.wav': 'audio/wav', '.ogg': 'audio/ogg', '.m4a': 'audio/mp4',\n '.mp4': 'video/mp4', '.webm': 'video/webm', '.mov': 'video/quicktime',\n '.txt': 'text/plain', '.md': 'text/markdown',\n}\nfunction htmlExtOf(name: string): string {\n const i = name.lastIndexOf('.')\n return i >= 0 ? name.slice(i).toLowerCase() : ''\n}\n\nexport interface FileViewerPanelProps {\n initialResource: import('../../types').ResourceContent | null\n initialArtifact?: import('../../types').Artifact | null\n loading?: boolean\n error?: string | null\n adapter?: ChatWidgetAdapter\n sessionId?: number | null\n onReference?: (ref: FileReference) => void\n onSelectionAsk?: (ref: FileReference) => void\n onBeforeCopy?: (ref: FileReference) => void\n onClose?: () => void\n onFullscreen?: () => void\n kicanvasScriptUrl?: string\n kicanvasTheme?: import('./viewers/KicadViewerCore').KicanvasJpTheme\n}\n\nconst FileViewerPanel: React.FC<FileViewerPanelProps> = ({\n initialResource, initialArtifact,\n loading, error, adapter, sessionId,\n onReference, onSelectionAsk, onBeforeCopy,\n onClose, onFullscreen, kicanvasScriptUrl, kicanvasTheme,\n}) => {\n const { t } = useChatWidgetI18n()\n const emitInteraction = useInteractionDispatch()\n\n const {\n stack,\n currentEntry,\n canGoBack,\n navLoading,\n currentCategory,\n fileIcon,\n breadcrumbItems,\n handleXrefClick,\n handleBack,\n handleBreadcrumbClick,\n } = useFileViewerNavigation({\n initialResource, initialArtifact, loading, adapter, sessionId,\n })\n\n // ── CWRF-009: .kicad_pro → multi-file project discovery (content mode, no presigned URLs) ──\n const [projectFiles, setProjectFiles] = useState<KicadFile[]>([])\n const [projectLoading, setProjectLoading] = useState(false)\n const isProFile = currentEntry?.resource.file_name?.toLowerCase().endsWith('.kicad_pro')\n\n useEffect(() => {\n if (!isProFile || !adapter?.listDirectoryFiles || !sessionId || !currentEntry) {\n setProjectFiles([])\n setProjectLoading(false)\n return\n }\n\n const gitPath = currentEntry.resource.git_path || currentEntry.resource.file_name || ''\n const dir = gitPath.substring(0, gitPath.lastIndexOf('/'))\n if (!dir) {\n setProjectFiles([])\n return\n }\n\n let cancelled = false\n setProjectLoading(true)\n\n const discover = async () => {\n const entries = await adapter.listDirectoryFiles!(sessionId, dir, {\n extensions: KICAD_DESIGN_EXTS,\n recursive: true,\n generateUrls: false,\n })\n if (cancelled) return\n\n const results = await Promise.allSettled(\n entries.map(e => adapter.getResourceContent(sessionId, e.resource_id)),\n )\n if (cancelled) return\n\n const files: KicadFile[] = []\n for (let i = 0; i < results.length; i++) {\n const r = results[i]!\n const entry = entries[i]!\n const relativePath = entry.git_path.startsWith(dir + '/')\n ? entry.git_path.substring(dir.length + 1)\n : entry.file_name\n if (r.status === 'fulfilled' && r.value.content) {\n files.push({ name: relativePath, content: r.value.content })\n }\n }\n\n if (!cancelled) {\n setProjectFiles(files)\n setProjectLoading(false)\n }\n }\n\n discover().catch(e => {\n console.error('[FileViewerPanel] KiCad project discovery failed:', e)\n if (!cancelled) {\n setProjectFiles([])\n setProjectLoading(false)\n }\n })\n\n return () => { cancelled = true }\n }, [isProFile, adapter, sessionId, currentEntry?.resource.resource_id])\n\n // ── CWRF-011: .html / .htm → multi-file HTML project discovery ───────────\n // Mirrors the KiCad discovery above. Lists sibling files via the adapter,\n // hydrates text bodies (CSS / JS / SVG / etc.) so the inline strategy can\n // inline them, and routes binary assets through their presigned URL so the\n // blob strategy can mint Blob URLs without re-downloading text bodies.\n const [htmlProjectFiles, setHtmlProjectFiles] = useState<HtmlFile[]>([])\n const [htmlProjectLoading, setHtmlProjectLoading] = useState(false)\n const isHtmlEntry = (() => {\n const fn = currentEntry?.resource.file_name?.toLowerCase() ?? ''\n return fn.endsWith('.html') || fn.endsWith('.htm')\n })()\n\n useEffect(() => {\n if (!isHtmlEntry || !adapter?.listDirectoryFiles || !sessionId || !currentEntry) {\n setHtmlProjectFiles([])\n setHtmlProjectLoading(false)\n return\n }\n const gitPath = currentEntry.resource.git_path || currentEntry.resource.file_name || ''\n const dir = gitPath.substring(0, gitPath.lastIndexOf('/'))\n if (!dir) {\n setHtmlProjectFiles([])\n setHtmlProjectLoading(false)\n return\n }\n\n let cancelled = false\n setHtmlProjectLoading(true)\n\n const discover = async () => {\n const entries = await adapter.listDirectoryFiles!(sessionId, dir, {\n extensions: HTML_PROJECT_EXTS,\n recursive: true,\n generateUrls: true,\n })\n if (cancelled) return\n\n // Phase 1: classify entries into URL-backed vs content-backed.\n const urlOnly: { name: string; url: string; mime: string; isText: boolean }[] = []\n const needContent: { name: string; resourceId: string; mime: string }[] = []\n\n for (const entry of entries) {\n const relativePath = entry.git_path.startsWith(dir + '/')\n ? entry.git_path.substring(dir.length + 1)\n : entry.file_name\n if (!relativePath || relativePath.startsWith('/') || relativePath.includes('..') || relativePath.includes('\\\\')) {\n continue\n }\n const ext = htmlExtOf(relativePath)\n const mime = HTML_MIME_BY_EXT[ext] ?? 'application/octet-stream'\n const isText = HTML_TEXT_EXTS.has(ext)\n if (entry.download_url) {\n urlOnly.push({ name: relativePath, url: entry.download_url, mime, isText })\n } else {\n needContent.push({ name: relativePath, resourceId: entry.resource_id, mime })\n }\n }\n\n // Phase 2: text files that came back URL-only must be hydrated to enable\n // inline strategy (which inlines `<style>` / `<script>` text bodies).\n // Binary files keep their URL.\n const textHydrationTargets = urlOnly.filter((f) => f.isText)\n const hydrated = await Promise.allSettled(\n textHydrationTargets.map((t) =>\n fetch(t.url, { credentials: 'include' as RequestCredentials }).then((r) => {\n if (!r.ok) throw new Error(`HTTP ${r.status} for ${t.name}`)\n return r.text().then((body) => ({ name: t.name, body }))\n }),\n ),\n )\n if (cancelled) return\n const hydratedMap = new Map<string, string>()\n for (const r of hydrated) {\n if (r.status === 'fulfilled') hydratedMap.set(r.value.name, r.value.body)\n }\n\n // Phase 3: resolve entries that had no presigned URL (workspace local files).\n const resolved = await Promise.allSettled(\n needContent.map((nc) => adapter.getResourceContent(sessionId, nc.resourceId)),\n )\n if (cancelled) return\n\n const files: HtmlFile[] = []\n for (const u of urlOnly) {\n if (u.isText) {\n const body = hydratedMap.get(u.name)\n if (body != null) {\n files.push({ name: u.name, content: body, mime: u.mime })\n } else {\n // Keep URL fallback so rewriteHtml can still swap the href.\n files.push({ name: u.name, url: u.url, mime: u.mime })\n }\n } else {\n files.push({ name: u.name, url: u.url, mime: u.mime })\n }\n }\n for (let i = 0; i < resolved.length; i++) {\n const r = resolved[i]!\n const meta = needContent[i]!\n if (r.status === 'fulfilled') {\n files.push({ name: meta.name, content: r.value.content ?? '', mime: meta.mime })\n }\n }\n\n if (!cancelled) {\n setHtmlProjectFiles(files)\n setHtmlProjectLoading(false)\n }\n }\n\n discover().catch((e) => {\n console.error('[FileViewerPanel] HTML project discovery failed:', e)\n if (!cancelled) {\n setHtmlProjectFiles([])\n setHtmlProjectLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [isHtmlEntry, adapter, sessionId, currentEntry?.resource.resource_id])\n\n const [kicadCanvasSnippet, setKicadCanvasSnippet] = useState<string | null>(null)\n const [kicadCanvasAnchor, setKicadCanvasAnchor] = useState<{ top: number; left: number } | null>(null)\n const [kicadView, setKicadView] = useState<'canvas' | 'source'>('canvas')\n const [gerberSnippet, setGerberSnippet] = useState<string | null>(null)\n const [gerberAnchor, setGerberAnchor] = useState<{ top: number; left: number } | null>(null)\n const bodyRef = useRef<HTMLDivElement>(null)\n\n const [htmlSelection, setHtmlSelection] = useState<{ text: string; rect: DOMRect } | null>(null)\n const handleHtmlSelectionChange = useCallback((sel: { text: string; rect: DOMRect } | null) => {\n setHtmlSelection(sel)\n }, [])\n\n const [pdfImageSel, setPdfImageSel] = useState<import('./viewers/PdfViewerCore').PdfImageSelection | null>(null)\n\n useEffect(() => {\n setKicadCanvasSnippet(null)\n setKicadCanvasAnchor(null)\n setKicadView('canvas')\n setGerberSnippet(null)\n setGerberAnchor(null)\n setPdfImageSel(null)\n }, [currentCategory, currentEntry?.resource.resource_id])\n\n useXrefScrollToTarget({\n targetLocation: currentEntry?.targetLocation,\n loading: !!(loading || navLoading),\n containerRef: bodyRef,\n })\n\n const handleDownload = useCallback(() => {\n if (!currentEntry) return\n emitInteraction('file-download', currentEntry.resource.file_name)\n const res = currentEntry.resource\n let src = contentToSrc(res)\n let revoke = src.startsWith('blob:')\n if (!src.startsWith('blob:') && !src.startsWith('data:') && !src.startsWith('http')) {\n const blob = new Blob([src], { type: res.mime_type || 'application/octet-stream' })\n src = URL.createObjectURL(blob)\n revoke = true\n }\n const a = document.createElement('a')\n a.href = src\n a.download = res.file_name\n a.click()\n if (revoke) URL.revokeObjectURL(src)\n }, [currentEntry, emitInteraction])\n\n const selectionContext = useMemo(() => {\n if (!currentEntry || !sessionId) return null\n return {\n resourceId: currentEntry.resource.resource_id,\n sessionId,\n fileName: currentEntry.resource.file_name,\n mimeType: currentEntry.resource.mime_type,\n }\n }, [currentEntry, sessionId])\n\n const { selection: domSelection, buildReference: domBuildReference, clearSelection: domClearSelection } = useSelectionBridge({\n containerRef: bodyRef,\n resourceContext: selectionContext ?? { resourceId: '', sessionId: 0, fileName: '' },\n enabled: !!selectionContext && currentCategory !== 'html',\n })\n\n const selection = currentCategory === 'html' ? htmlSelection : domSelection\n\n const buildReference = useCallback((): import('../../types').FileReference => {\n if (currentCategory === 'html' && htmlSelection && selectionContext) {\n return {\n resourceId: selectionContext.resourceId,\n sessionId: selectionContext.sessionId,\n fileName: selectionContext.fileName,\n mimeType: selectionContext.mimeType,\n selection: { text: htmlSelection.text },\n }\n }\n return domBuildReference()\n }, [currentCategory, htmlSelection, selectionContext, domBuildReference])\n\n const clearSelection = useCallback(() => {\n if (currentCategory === 'html') {\n setHtmlSelection(null)\n } else {\n domClearSelection()\n }\n }, [currentCategory, domClearSelection])\n\n // --- \"问一下\" button handler ---\n const handleAsk = useCallback(() => {\n if (!onReference) return\n const ref = buildReference()\n if (onSelectionAsk) {\n onSelectionAsk(ref)\n clearSelection()\n return\n }\n onReference(ref)\n clearSelection()\n }, [onReference, onSelectionAsk, buildReference, clearSelection])\n\n // --- \"📋\" toolbar copy: text → clipboard + cache reference ---\n const handleCopy = useCallback(() => {\n if (!selection) return\n const ref = buildReference()\n emitInteraction('message-copy', ref.resourceId, { fileName: ref.fileName, hasSelection: !!ref.selection })\n onBeforeCopy?.(ref)\n const sel = ref.selection\n const locParts: string[] = []\n if (sel?.page != null) locParts.push(sel.endPage != null ? `p.${sel.page}-${sel.endPage}` : `p.${sel.page}`)\n if (sel?.startLine != null) locParts.push(sel.endLine != null && sel.endLine !== sel.startLine ? `L${sel.startLine}-${sel.endLine}` : `L${sel.startLine}`)\n const prefix = locParts.length > 0 ? `[${ref.fileName} (${locParts.join(', ')})]\\n` : ''\n const clipText = prefix + selection.text\n setCwrfClipboardRef(clipText, ref)\n navigator.clipboard.writeText(clipText).catch(() => {})\n }, [selection, buildReference, onBeforeCopy, emitInteraction])\n\n useNativeCopyInterceptor({\n containerRef: bodyRef,\n buildReference,\n selectionContext,\n onCopy: (ref) => {\n emitInteraction('message-copy', ref.resourceId, { fileName: ref.fileName, source: 'native-copy' })\n },\n })\n\n // --- \"📎 引用此文件\" — available for ALL file types ---\n const handleReferenceWholeFile = useCallback(() => {\n if (!onReference || !currentEntry || !sessionId) return\n onReference({\n resourceId: currentEntry.resource.resource_id,\n sessionId,\n fileName: currentEntry.resource.file_name,\n mimeType: currentEntry.resource.mime_type,\n })\n }, [onReference, currentEntry, sessionId])\n\n // --- KiCad: 复制全文(KiCad 原文)到剪贴板,粘贴到输入框可得到完整原文 ---\n const handleCopyFullKicad = useCallback(() => {\n if (!currentEntry || !sessionId) return\n const raw = currentEntry.resource.content\n if (typeof raw !== 'string' || !raw.trim()) return\n const ref: FileReference = {\n resourceId: currentEntry.resource.resource_id,\n sessionId,\n fileName: currentEntry.resource.file_name,\n mimeType: currentEntry.resource.mime_type,\n selection: { text: raw },\n }\n emitInteraction('message-copy', ref.resourceId, { fileName: ref.fileName, source: 'kicad-full' })\n setCwrfClipboardRef(raw, ref)\n navigator.clipboard.writeText(raw).catch(() => {})\n }, [currentEntry, sessionId, emitInteraction])\n\n const handleAskKicadCanvas = useCallback(() => {\n if (!onReference || !currentEntry || !sessionId || !kicadCanvasSnippet?.trim()) return\n onReference({\n resourceId: currentEntry.resource.resource_id,\n sessionId,\n fileName: currentEntry.resource.file_name,\n mimeType: currentEntry.resource.mime_type,\n selection: { text: kicadCanvasSnippet.trim() },\n })\n setKicadCanvasSnippet(null)\n }, [onReference, currentEntry, sessionId, kicadCanvasSnippet])\n\n const handleCopyKicadCanvas = useCallback(() => {\n if (!currentEntry || !sessionId || !kicadCanvasSnippet?.trim()) return\n const ref: FileReference = {\n resourceId: currentEntry.resource.resource_id,\n sessionId,\n fileName: currentEntry.resource.file_name,\n mimeType: currentEntry.resource.mime_type,\n selection: { text: kicadCanvasSnippet.trim() },\n }\n emitInteraction('message-copy', ref.resourceId, { fileName: ref.fileName, source: 'kicad-canvas' })\n setCwrfClipboardRef(kicadCanvasSnippet.trim(), ref)\n navigator.clipboard.writeText(kicadCanvasSnippet.trim()).catch(() => {})\n }, [currentEntry, sessionId, kicadCanvasSnippet, emitInteraction])\n\n const handleAskGerber = useCallback(() => {\n if (!onReference || !currentEntry || !sessionId || !gerberSnippet?.trim()) return\n onReference({\n resourceId: currentEntry.resource.resource_id,\n sessionId,\n fileName: currentEntry.resource.file_name,\n mimeType: currentEntry.resource.mime_type,\n selection: { text: gerberSnippet.trim() },\n })\n setGerberSnippet(null)\n setGerberAnchor(null)\n }, [onReference, currentEntry, sessionId, gerberSnippet])\n\n const handleAskPdfImage = useCallback(() => {\n if (!onReference || !currentEntry || !sessionId || !pdfImageSel) return\n onReference({\n resourceId: currentEntry.resource.resource_id,\n sessionId,\n fileName: currentEntry.resource.file_name,\n mimeType: currentEntry.resource.mime_type,\n selection: {\n text: `[Image on page ${pdfImageSel.page}, index ${pdfImageSel.imageIndex}]`,\n page: pdfImageSel.page,\n imageSrc: pdfImageSel.imageSrc,\n },\n })\n setPdfImageSel(null)\n }, [onReference, currentEntry, sessionId, pdfImageSel])\n\n const handleCopyPdfImage = useCallback(() => {\n if (!pdfImageSel) return\n const a = document.createElement('a')\n a.href = pdfImageSel.imageSrc\n a.download = `page${pdfImageSel.page}_image${pdfImageSel.imageIndex}.png`\n a.click()\n setPdfImageSel(null)\n }, [pdfImageSel])\n\n const handleCopyGerber = useCallback(() => {\n if (!currentEntry || !sessionId || !gerberSnippet?.trim()) return\n const ref: FileReference = {\n resourceId: currentEntry.resource.resource_id,\n sessionId,\n fileName: currentEntry.resource.file_name,\n mimeType: currentEntry.resource.mime_type,\n selection: { text: gerberSnippet.trim() },\n }\n emitInteraction('message-copy', ref.resourceId, { fileName: ref.fileName, source: 'gerber-layer' })\n setCwrfClipboardRef(gerberSnippet.trim(), ref)\n navigator.clipboard.writeText(gerberSnippet.trim()).catch(() => {})\n setGerberSnippet(null)\n setGerberAnchor(null)\n }, [currentEntry, sessionId, gerberSnippet, emitInteraction])\n\n if (!currentEntry && !loading && !error) return null\n\n return (\n <div className=\"ycw-fvm-panel\">\n <div className=\"ycw-fvm-panel-header\">\n <div className=\"ycw-fvm-header\">\n {canGoBack && (\n <button className=\"ycw-fvm-btn ycw-fvm-btn-back\" onClick={handleBack}>{t('viewer.back')}</button>\n )}\n <span className=\"ycw-fvm-icon\">{fileIcon}</span>\n <span className=\"ycw-fvm-title\">\n {currentEntry?.artifact?.name || currentEntry?.resource.file_name || t('viewer.defaultTitle')}\n </span>\n {stack.length > 1 && (\n <span className=\"ycw-fvm-depth\">{stack.length}</span>\n )}\n </div>\n <div className=\"ycw-fvm-actions\">\n {onReference && currentCategory === 'kicad' && typeof currentEntry?.resource?.content === 'string' && currentEntry.resource.content.trim() && (\n <button\n className=\"ycw-fvm-btn ycw-fvm-btn-ref\"\n onClick={handleCopyFullKicad}\n title={t('viewer.copyFullKicadTitle')}\n >\n <Icon name=\"clipboard\" aria-hidden={true} />\n {' '}\n {t('viewer.copyFull')}\n </button>\n )}\n {onReference && (\n <button\n className=\"ycw-fvm-btn ycw-fvm-btn-ref\"\n onClick={handleReferenceWholeFile}\n title={t('viewer.referenceFileTitle')}\n >\n <Icon name=\"paperclip\" aria-hidden={true} />\n {' '}\n {t('viewer.referenceFile')}\n </button>\n )}\n <button className=\"ycw-fvm-btn\" onClick={handleDownload} title={t('viewer.download')}>⬇</button>\n {onFullscreen && (\n <button className=\"ycw-fvm-btn\" onClick={onFullscreen} title={t('viewer.fullscreen')}>⊞</button>\n )}\n {onClose && (\n <button className=\"ycw-fvm-btn\" onClick={onClose} title={t('viewer.close')}>✕</button>\n )}\n </div>\n </div>\n\n <Breadcrumb items={breadcrumbItems} onItemClick={handleBreadcrumbClick} />\n\n {currentEntry && (\n <div className=\"ycw-fvm-meta\">\n <span>{currentEntry.resource.mime_type || t('viewer.unknownType')}</span>\n {currentEntry.resource.file_size != null && (\n <span>{formatFileSize(currentEntry.resource.file_size)}</span>\n )}\n <span className=\"ycw-fvm-path\">{currentEntry.resource.git_path}</span>\n {currentCategory === 'kicad' && (\n <div className=\"ycw-kicad-view-toggle ycw-fvm-meta-toggle\">\n <button\n type=\"button\"\n className=\"ycw-kicad-toggle-btn\"\n data-state={kicadView === 'canvas' ? 'active' : undefined}\n onClick={() => setKicadView('canvas')}\n >\n {t('kicad.viewVisual')}\n </button>\n <button\n type=\"button\"\n className=\"ycw-kicad-toggle-btn\"\n data-state={kicadView === 'source' ? 'active' : undefined}\n onClick={() => setKicadView('source')}\n >\n {t('kicad.viewSource')}\n </button>\n </div>\n )}\n </div>\n )}\n\n <div className=\"ycw-fvm-body\" ref={bodyRef} style={{ position: 'relative' }}>\n {onReference && currentCategory === 'kicad' && kicadCanvasSnippet?.trim() && kicadCanvasAnchor && (\n <div\n className=\"ycw-cb-floating-toolbar\"\n style={{\n position: 'absolute',\n top: Math.max(0, kicadCanvasAnchor.top),\n left: Math.max(20, kicadCanvasAnchor.left),\n transform: 'translateX(-50%)',\n zIndex: 100,\n }}\n >\n <button className=\"ycw-cb-toolbar-btn ycw-cb-toolbar-btn-primary\" onClick={handleAskKicadCanvas}>\n {t('selection.ask')}\n </button>\n <button className=\"ycw-cb-toolbar-btn\" onClick={handleCopyKicadCanvas} title={t('viewer.copySnippet')}>\n 📋\n </button>\n </div>\n )}\n {onReference && currentCategory === 'kicad' && kicadCanvasSnippet?.trim() && !kicadCanvasAnchor && (\n <div\n className=\"ycw-cb-floating-toolbar\"\n style={{\n position: 'absolute', bottom: 12, left: '50%',\n transform: 'translateX(-50%)', zIndex: 100,\n }}\n >\n <button className=\"ycw-cb-toolbar-btn ycw-cb-toolbar-btn-primary\" onClick={handleAskKicadCanvas}>\n {t('selection.ask')}\n </button>\n <button className=\"ycw-cb-toolbar-btn\" onClick={handleCopyKicadCanvas} title={t('viewer.copySnippet')}>\n 📋\n </button>\n </div>\n )}\n {onReference && currentCategory === 'gerber' && gerberSnippet?.trim() && gerberAnchor && (\n <div\n className=\"ycw-cb-floating-toolbar\"\n style={{\n position: 'absolute',\n top: Math.max(0, gerberAnchor.top),\n left: Math.max(20, gerberAnchor.left),\n transform: 'translateX(-50%)',\n zIndex: 100,\n }}\n >\n <button className=\"ycw-cb-toolbar-btn ycw-cb-toolbar-btn-primary\" onClick={handleAskGerber}>\n {t('selection.ask')}\n </button>\n <button className=\"ycw-cb-toolbar-btn\" onClick={handleCopyGerber} title={t('viewer.copySnippet')}>\n 📋\n </button>\n </div>\n )}\n {onReference && currentCategory === 'gerber' && gerberSnippet?.trim() && !gerberAnchor && (\n <div\n className=\"ycw-cb-floating-toolbar\"\n style={{\n position: 'absolute', bottom: 12, left: '50%',\n transform: 'translateX(-50%)', zIndex: 100,\n }}\n >\n <button className=\"ycw-cb-toolbar-btn ycw-cb-toolbar-btn-primary\" onClick={handleAskGerber}>\n {t('selection.ask')}\n </button>\n <button className=\"ycw-cb-toolbar-btn\" onClick={handleCopyGerber} title={t('viewer.copySnippet')}>\n 📋\n </button>\n </div>\n )}\n {(loading || navLoading) && <ViewerLoading label={t('viewer.loading')} />}\n {error && <div className=\"ycw-fvm-error\">{error}</div>}\n {currentEntry && !loading && !navLoading && !error && (\n <FileViewer\n content={currentEntry.resource}\n onXrefClick={handleXrefClick}\n onLinkClick={(url) => emitInteraction('link-click', url, { source: 'xref-url' })}\n onHtmlSelectionChange={handleHtmlSelectionChange}\n kicadOptions={\n currentCategory === 'kicad'\n ? {\n kicanvasScriptUrl,\n kicanvasTheme,\n view: kicadView,\n onViewChange: setKicadView,\n files: projectFiles.length > 0 ? projectFiles : undefined,\n projectLoading,\n onKicadCanvasSelection: ({ snippet, anchorRect, items }) => {\n const combined = items && items.length > 1\n ? items.map((it) => it.snippet).filter(Boolean).join('\\n\\n')\n : snippet?.trim() || null\n setKicadCanvasSnippet(combined || null)\n if (anchorRect && combined && bodyRef.current) {\n const br = bodyRef.current.getBoundingClientRect()\n const relTop = anchorRect.top - br.top\n const relLeft = anchorRect.left - br.left\n const belowY = relTop + 48\n setKicadCanvasAnchor({\n top: Math.min(belowY, br.height - 52),\n left: relLeft,\n })\n } else {\n setKicadCanvasAnchor(null)\n }\n },\n }\n : undefined\n }\n gerberOptions={\n currentCategory === 'gerber'\n ? {\n onGerberSelection: ({ snippet, anchorRect }) => {\n setGerberSnippet(snippet || null)\n if (anchorRect && snippet && bodyRef.current) {\n const br = bodyRef.current.getBoundingClientRect()\n setGerberAnchor({\n top: Math.min(anchorRect.top, br.height - 52),\n left: Math.max(20, Math.min(anchorRect.left, br.width - 40)),\n })\n } else {\n setGerberAnchor(null)\n }\n },\n }\n : undefined\n }\n pdfOptions={\n currentCategory === 'pdf'\n ? { onImageSelect: setPdfImageSel }\n : undefined\n }\n htmlOptions={\n currentCategory === 'html'\n ? {\n files: htmlProjectFiles.length > 0 ? htmlProjectFiles : undefined,\n projectLoading: htmlProjectLoading,\n }\n : undefined\n }\n />\n )}\n {onReference && currentCategory === 'pdf' && pdfImageSel && (\n <div\n className=\"ycw-cb-floating-toolbar\"\n style={{\n position: 'absolute', bottom: 12, left: '50%',\n transform: 'translateX(-50%)', zIndex: 100,\n }}\n >\n <button className=\"ycw-cb-toolbar-btn ycw-cb-toolbar-btn-primary\" onClick={handleAskPdfImage}>\n {t('selection.ask')}\n </button>\n <button className=\"ycw-cb-toolbar-btn\" onClick={handleCopyPdfImage} title={t('viewer.download')}>\n ⬇\n </button>\n </div>\n )}\n {onReference && (\n <FloatingToolbar\n selection={selection}\n onAsk={handleAsk}\n onCopy={handleCopy}\n anchorRef={bodyRef}\n />\n )}\n </div>\n </div>\n )\n}\n\nexport default FileViewerPanel\n","import React from 'react'\nimport { useChatWidgetI18n } from '../../i18n'\n\nexport interface BreadcrumbItem {\n label: string\n icon?: string\n}\n\nexport interface BreadcrumbProps {\n items: BreadcrumbItem[]\n onItemClick: (index: number) => void\n}\n\nconst Breadcrumb: React.FC<BreadcrumbProps> = ({ items, onItemClick }) => {\n const { t } = useChatWidgetI18n()\n if (items.length <= 1) return null\n\n return (\n <nav className=\"ycw-fvm-breadcrumb\" aria-label={t('aria.fileNavigation')}>\n {items.map((item, i) => {\n const isLast = i === items.length - 1\n return (\n <React.Fragment key={i}>\n {i > 0 && <span className=\"ycw-fvm-breadcrumb-sep\">›</span>}\n {isLast ? (\n <span className=\"ycw-fvm-breadcrumb-current\" title={item.label}>\n {item.icon && <span className=\"ycw-fvm-breadcrumb-icon\">{item.icon}</span>}\n {item.label}\n </span>\n ) : (\n <button\n className=\"ycw-fvm-breadcrumb-link\"\n onClick={() => onItemClick(i)}\n title={item.label}\n >\n {item.icon && <span className=\"ycw-fvm-breadcrumb-icon\">{item.icon}</span>}\n {item.label}\n </button>\n )}\n </React.Fragment>\n )\n })}\n </nav>\n )\n}\n\nexport default Breadcrumb\n","import { useState, useEffect, useCallback, useRef } from 'react'\nimport type { FileReference } from '../../types.js'\n\nexport interface SelectionState {\n text: string\n rect: DOMRect\n startLine?: number\n endLine?: number\n /** PDF page number (1-based) from data-page attribute */\n page?: number\n endPage?: number\n}\n\nexport interface SelectionBridgeOptions {\n containerRef: React.RefObject<HTMLElement | null>\n resourceContext: {\n resourceId: string\n sessionId: number\n fileName: string\n mimeType?: string | null\n specId?: string\n }\n enabled?: boolean\n}\n\nexport function useSelectionBridge({\n containerRef,\n resourceContext,\n enabled = true,\n}: SelectionBridgeOptions) {\n const [selection, setSelection] = useState<SelectionState | null>(null)\n const debounceRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n\n const handleSelectionChange = useCallback(() => {\n if (!enabled) return\n const sel = window.getSelection()\n if (!sel || sel.isCollapsed || sel.rangeCount === 0) {\n setSelection(null)\n return\n }\n\n const container = containerRef.current\n if (!container) return\n\n const range = sel.getRangeAt(0)\n if (!container.contains(range.commonAncestorContainer)) {\n setSelection(null)\n return\n }\n\n const text = sel.toString().trim()\n if (!text) {\n setSelection(null)\n return\n }\n\n const rect = range.getBoundingClientRect()\n const startLine = findLineNumber(range.startContainer)\n const endLine = findLineNumber(range.endContainer)\n const page = findDataAttr(range.startContainer, 'data-page')\n const endPage = findDataAttr(range.endContainer, 'data-page')\n\n setSelection({\n text, rect, startLine, endLine,\n page,\n endPage: endPage !== page ? endPage : undefined,\n })\n }, [containerRef, enabled])\n\n useEffect(() => {\n if (!enabled) return\n\n const onSelectionChange = () => {\n if (debounceRef.current) clearTimeout(debounceRef.current)\n debounceRef.current = setTimeout(handleSelectionChange, 80)\n }\n\n document.addEventListener('selectionchange', onSelectionChange)\n return () => {\n document.removeEventListener('selectionchange', onSelectionChange)\n if (debounceRef.current) clearTimeout(debounceRef.current)\n }\n }, [handleSelectionChange, enabled])\n\n const buildReference = useCallback((): FileReference => {\n const ref: FileReference = {\n resourceId: resourceContext.resourceId,\n sessionId: resourceContext.sessionId,\n fileName: resourceContext.fileName,\n mimeType: resourceContext.mimeType,\n specId: resourceContext.specId,\n }\n if (selection) {\n ref.selection = {\n text: selection.text,\n startLine: selection.startLine,\n endLine: selection.endLine,\n page: selection.page,\n endPage: selection.endPage,\n }\n }\n return ref\n }, [selection, resourceContext])\n\n const clearSelection = useCallback(() => {\n window.getSelection()?.removeAllRanges()\n setSelection(null)\n }, [])\n\n return { selection, buildReference, clearSelection }\n}\n\nfunction findLineNumber(node: Node): number | undefined {\n return findDataAttr(node, 'data-line')\n}\n\nfunction findDataAttr(node: Node, attr: string): number | undefined {\n let el: HTMLElement | null =\n node.nodeType === Node.ELEMENT_NODE ? (node as HTMLElement) : node.parentElement\n while (el) {\n const v = el.getAttribute(attr)\n if (v) {\n const n = parseInt(v, 10)\n if (!isNaN(n)) return n\n }\n el = el.parentElement\n }\n return undefined\n}\n","import React, { useRef, useEffect, useState } from 'react'\nimport type { SelectionState } from './useSelectionBridge'\nimport { useChatWidgetI18n } from '../../i18n'\nimport { Icon } from '../Icon/Icon'\nimport './ContextBridge.css'\n\nexport interface FloatingToolbarProps {\n selection: SelectionState | null\n onAsk: () => void\n onCopy?: () => void\n anchorRef: React.RefObject<HTMLElement | null>\n}\n\nconst FloatingToolbar: React.FC<FloatingToolbarProps> = ({\n selection,\n onAsk,\n onCopy,\n anchorRef,\n}) => {\n const { t } = useChatWidgetI18n()\n const toolbarRef = useRef<HTMLDivElement>(null)\n const [pos, setPos] = useState<{ top: number; left: number } | null>(null)\n\n useEffect(() => {\n if (!selection || !anchorRef.current) {\n setPos(null)\n return\n }\n\n const containerRect = anchorRef.current.getBoundingClientRect()\n const selRect = selection.rect\n\n const top = selRect.top - containerRect.top - 36\n const left = selRect.left - containerRect.left + selRect.width / 2\n\n setPos({ top: Math.max(0, top), left: Math.max(20, left) })\n }, [selection, anchorRef])\n\n if (!selection || !pos) return null\n\n return (\n <div\n ref={toolbarRef}\n className=\"ycw-cb-floating-toolbar\"\n style={{\n top: pos.top,\n left: pos.left,\n transform: 'translateX(-50%)',\n }}\n >\n <button className=\"ycw-cb-toolbar-btn ycw-cb-toolbar-btn-primary\" onClick={onAsk}>\n <Icon name=\"chat\" aria-hidden={true} />\n {' '}\n {t('selection.ask')}\n </button>\n {onCopy && (\n <button className=\"ycw-cb-toolbar-btn\" onClick={onCopy}>\n <Icon name=\"clipboard\" aria-hidden={true} />\n </button>\n )}\n </div>\n )\n}\n\nexport default FloatingToolbar\n","import { useEffect, useCallback } from 'react'\nimport type { FileReference } from '../../types.js'\n\nconst CACHE_TTL_MS = 60_000\n\nlet _cached: { text: string; ref: FileReference; ts: number } | null = null\n\n/**\n * Store a FileReference alongside the copied text.\n * Called from the viewer's copy handlers (button & native Ctrl+C).\n */\nexport function setCwrfClipboardRef(text: string, ref: FileReference) {\n _cached = { text: text.trim(), ref, ts: Date.now() }\n}\n\nfunction consumeCache(pastedText: string): FileReference | null {\n if (!_cached) return null\n if (Date.now() - _cached.ts > CACHE_TTL_MS) {\n _cached = null\n return null\n }\n if (pastedText.trim() === _cached.text) {\n const ref = _cached.ref\n _cached = null\n return ref\n }\n return null\n}\n\nexport interface SmartPasteOptions {\n enabled: boolean\n onReference: (ref: FileReference) => void\n}\n\nexport function useSmartPaste({ enabled, onReference }: SmartPasteOptions) {\n const handlePaste = useCallback((e: ClipboardEvent) => {\n if (!enabled) return\n const data = e.clipboardData\n if (!data) return\n\n const text = data.getData('text/plain')\n\n const ref = text ? consumeCache(text) : null\n if (ref) {\n e.preventDefault()\n onReference(ref)\n }\n }, [enabled, onReference])\n\n useEffect(() => {\n if (!enabled) return\n document.addEventListener('paste', handlePaste)\n return () => document.removeEventListener('paste', handlePaste)\n }, [enabled, handlePaste])\n}\n","/**\n * useFileViewerNavigation — manages the navigation stack, xref navigation,\n * KiCad content_url resolution, and breadcrumb state for FileViewerPanel.\n */\n\nimport { useState, useCallback, useEffect, useMemo, useRef } from 'react'\nimport type { ResourceContent, Artifact, XrefRecord, XrefRef, ChatWidgetAdapter } from '../types'\nimport { getFileCategory, getExtension } from '../components/FileViewer/utils/fileCategory'\nimport { useInteractionDispatch } from './useInteractionDispatch'\n\nconst MAX_STACK_DEPTH = 10\n\nexport interface ViewerStackEntry {\n resource: ResourceContent\n artifact?: Artifact\n targetLocation?: string | null\n}\n\nexport interface BreadcrumbItem {\n label: string\n icon: string\n}\n\nconst CATEGORY_ICONS: Record<string, string> = {\n markdown: '📝', code: '💻', text: '📄', image: '🖼️',\n video: '🎬', audio: '🎵', html: '🌐', json: '📊',\n pdf: '📕', kicad: '📐', gerber: '🔌', '3d': '📦', step: '📦',\n unknown: '📎',\n}\n\nexport interface UseFileViewerNavigationOptions {\n initialResource: ResourceContent | null\n initialArtifact?: Artifact | null\n loading?: boolean\n adapter?: ChatWidgetAdapter\n sessionId?: number | null\n}\n\nexport function useFileViewerNavigation(options: UseFileViewerNavigationOptions) {\n const { initialResource, initialArtifact, loading, adapter, sessionId } = options\n const emitInteraction = useInteractionDispatch()\n\n const [stack, setStack] = useState<ViewerStackEntry[]>([])\n const [navLoading, setNavLoading] = useState(false)\n\n useEffect(() => {\n if (initialResource) {\n setStack([{ resource: initialResource, artifact: initialArtifact || undefined }])\n } else {\n setStack([])\n }\n }, [initialResource, initialArtifact])\n\n const currentEntry = stack[stack.length - 1]\n const canGoBack = stack.length > 1\n\n const handleXrefClick = useCallback(async (xref: XrefRecord) => {\n if (!xref.target_file_id || !adapter || !sessionId) return\n\n let resourceId = xref.target_file_id\n emitInteraction('xref-navigate', resourceId, { fileName: xref.description })\n if (adapter.resolveXrefs) {\n try {\n const [meta] = await adapter.resolveXrefs([{\n uri: xref.target_resource,\n description: xref.description,\n relation: xref.relation as XrefRef['relation'],\n }])\n if (meta?.resource_id) resourceId = meta.resource_id\n } catch {\n // fall through\n }\n }\n\n setNavLoading(true)\n try {\n const content = await adapter.getResourceContent(sessionId, resourceId)\n setStack(prev => {\n const next = [...prev, { resource: content, targetLocation: xref.target_location }]\n return next.length > MAX_STACK_DEPTH ? next.slice(1) : next\n })\n } catch (err) {\n console.error('[FileViewerPanel] Failed to load xref target:', err)\n } finally {\n setNavLoading(false)\n }\n }, [adapter, sessionId, emitInteraction])\n\n const handleBack = useCallback(() => {\n setStack(prev => prev.slice(0, -1))\n }, [])\n\n const handleBreadcrumbClick = useCallback((index: number) => {\n setStack(prev => prev.slice(0, index + 1))\n }, [])\n\n const breadcrumbItems = useMemo<BreadcrumbItem[]>(() => {\n return stack.map(entry => {\n const ext = getExtension(entry.resource.file_name)\n const cat = getFileCategory(ext, entry.resource.mime_type)\n return {\n label: entry.artifact?.name || entry.resource.file_name,\n icon: CATEGORY_ICONS[cat] || '📄',\n }\n })\n }, [stack])\n\n const currentCategory = useMemo(() => {\n if (!currentEntry) return 'unknown'\n const ext = getExtension(currentEntry.resource.file_name)\n return getFileCategory(ext, currentEntry.resource.mime_type)\n }, [currentEntry])\n\n const fileIcon = useMemo(() => CATEGORY_ICONS[currentCategory] || '📄', [currentCategory])\n\n // KiCad / Gerber: prefer direct HTTPS URL for engines & iframe embeds (presigned URL)\n useEffect(() => {\n if (currentCategory !== 'kicad' && currentCategory !== 'gerber') return\n if (!currentEntry || !adapter || !sessionId) return\n if (currentEntry.resource.content_url) return\n\n let cancelled = false\n if (adapter.getResourceUrl) {\n adapter.getResourceUrl(sessionId, currentEntry.resource.resource_id)\n .then(url => {\n if (!cancelled && url) {\n setStack(prev => {\n const last = prev[prev.length - 1]\n if (!last) return prev\n return [...prev.slice(0, -1), { ...last, resource: { ...last.resource, content_url: url } }]\n })\n }\n })\n .catch(() => {})\n }\n return () => { cancelled = true }\n }, [currentCategory, currentEntry?.resource.resource_id, adapter, sessionId])\n\n // KiCad blob URL fallback\n const kicadBlobUrlRef = useRef<string | null>(null)\n const kicadResourceIdRef = useRef<string | null>(null)\n useEffect(() => {\n if (currentCategory !== 'kicad' || !currentEntry) return\n const rid = currentEntry.resource.resource_id\n if (rid !== kicadResourceIdRef.current) {\n if (kicadBlobUrlRef.current) {\n URL.revokeObjectURL(kicadBlobUrlRef.current)\n kicadBlobUrlRef.current = null\n }\n kicadResourceIdRef.current = rid\n }\n if (currentEntry.resource.content_url) return\n const raw = currentEntry.resource.content\n if (typeof raw !== 'string' || !raw) return\n\n const mime = currentEntry.resource.mime_type || 'text/plain'\n const blob = new Blob([raw], { type: mime })\n const url = URL.createObjectURL(blob)\n kicadBlobUrlRef.current = url\n setStack(prev => {\n const last = prev[prev.length - 1]\n if (!last) return prev\n return [...prev.slice(0, -1), { ...last, resource: { ...last.resource, content_url: url } }]\n })\n }, [currentCategory, currentEntry?.resource.resource_id, currentEntry?.resource.content, currentEntry?.resource.content_url])\n\n useEffect(() => {\n return () => {\n if (kicadBlobUrlRef.current) {\n URL.revokeObjectURL(kicadBlobUrlRef.current)\n kicadBlobUrlRef.current = null\n }\n }\n }, [])\n\n return {\n stack,\n currentEntry,\n canGoBack,\n navLoading,\n currentCategory,\n fileIcon,\n breadcrumbItems,\n handleXrefClick,\n handleBack,\n handleBreadcrumbClick,\n }\n}\n","import { useEffect, useRef } from 'react'\nimport type { FileReference } from '../types'\nimport { setCwrfClipboardRef } from '../components/ContextBridge/useSmartPaste'\n\ninterface UseNativeCopyInterceptorOptions {\n containerRef: React.RefObject<HTMLDivElement | null>\n buildReference: () => FileReference\n selectionContext: {\n resourceId: string\n sessionId: number\n fileName: string\n mimeType?: string | null\n } | null\n onCopy?: (ref: FileReference) => void\n}\n\n/**\n * Intercept native Ctrl+C / Cmd+C within a container to inject\n * file-reference metadata into the clipboard cache.\n */\nexport function useNativeCopyInterceptor({\n containerRef,\n buildReference,\n selectionContext,\n onCopy,\n}: UseNativeCopyInterceptorOptions): void {\n const buildReferenceRef = useRef(buildReference)\n buildReferenceRef.current = buildReference\n const selectionContextRef = useRef(selectionContext)\n selectionContextRef.current = selectionContext\n const onCopyRef = useRef(onCopy)\n onCopyRef.current = onCopy\n\n const hasContent = !!selectionContext\n useEffect(() => {\n const container = containerRef.current\n if (!container) return\n\n const handleNativeCopy = (e: ClipboardEvent) => {\n const ctx = selectionContextRef.current\n if (!ctx) return\n\n const sel = window.getSelection()\n if (!sel || sel.isCollapsed || sel.rangeCount === 0) return\n\n const range = sel.getRangeAt(0)\n if (!container.contains(range.commonAncestorContainer)) return\n\n const text = sel.toString().trim()\n if (!text) return\n\n const ref = buildReferenceRef.current()\n if (ref.selection) {\n ref.selection.text = text\n } else {\n ref.selection = { text }\n }\n\n setCwrfClipboardRef(text, ref)\n onCopyRef.current?.(ref)\n e.clipboardData?.setData('text/plain', text)\n e.preventDefault()\n }\n\n container.addEventListener('copy', handleNativeCopy)\n return () => container.removeEventListener('copy', handleNativeCopy)\n }, [hasContent, containerRef])\n}\n","import React, { useMemo, useCallback } from 'react'\nimport type { XrefRecord } from '../../../types.js'\nimport { useInteractionDispatch } from '../../../hooks/useInteractionDispatch'\nimport './LinkCard.css'\n\ninterface LinkCardProps {\n xref: XrefRecord\n className?: string\n}\n\nconst LinkCard: React.FC<LinkCardProps> = ({ xref, className }) => {\n const emitInteraction = useInteractionDispatch()\n const url = xref.target_resource.replace(/^url:\\/\\//, 'https://')\n const parsedUrl = useMemo(() => {\n try { return new URL(url) } catch { return null }\n }, [url])\n\n const domain = parsedUrl?.hostname || url\n const faviconUrl = `https://www.google.com/s2/favicons?domain=${domain}&sz=32`\n const path = parsedUrl ? parsedUrl.pathname + parsedUrl.search : ''\n\n const handleClick = useCallback(() => {\n emitInteraction('link-click', url, { title: xref.description })\n window.open(url, '_blank', 'noopener,noreferrer')\n }, [url, emitInteraction, xref.description])\n\n return (\n <div className={`ycw-link-card ${className || ''}`} onClick={handleClick}>\n <img\n className=\"ycw-link-card-favicon\"\n src={faviconUrl}\n alt=\"\"\n width={16}\n height={16}\n onError={(e) => { (e.target as HTMLImageElement).style.display = 'none' }}\n />\n <div className=\"ycw-link-card-content\">\n <div className=\"ycw-link-card-title\">{xref.description}</div>\n <div className=\"ycw-link-card-url\">\n <span className=\"ycw-link-card-domain\">{domain}</span>\n {path && path !== '/' && <span className=\"ycw-link-card-path\">{path}</span>}\n </div>\n </div>\n <span className=\"ycw-link-card-relation\">{xref.relation}</span>\n </div>\n )\n}\n\nexport default LinkCard\n","import React from 'react'\nimport type { XrefRecord, XrefMeta } from '../../../types.js'\nimport './ResourceChip.css'\n\nconst FILE_ICONS: Record<string, string> = {\n 'py': '🐍', 'ts': '📘', 'tsx': '📘', 'js': '📒', 'jsx': '📒',\n 'go': '🔵', 'rs': '🦀', 'md': '📝', 'json': '📊', 'pdf': '📕',\n 'png': '🖼️', 'jpg': '🖼️', 'jpeg': '🖼️', 'svg': '🖼️',\n 'html': '🌐', 'css': '🎨',\n 'kicad_sch': '📐', 'kicad_pcb': '📐',\n 'step': '📦', 'stp': '📦', 'stl': '📦',\n}\n\ninterface ResourceChipProps {\n xref: XrefRecord\n meta?: XrefMeta\n onClick?: () => void\n className?: string\n}\n\nconst ResourceChip: React.FC<ResourceChipProps> = ({ xref, meta, onClick, className }) => {\n const displayName = meta?.file_name || xref.description\n const ext = displayName.includes('.') ? displayName.split('.').pop()! : ''\n const icon = FILE_ICONS[ext] || '📎'\n\n return (\n <span className={`ycw-resource-chip ${className || ''}`} onClick={onClick}>\n <span className=\"ycw-resource-chip-icon\">{icon}</span>\n <span className=\"ycw-resource-chip-name\">{displayName}</span>\n <span className=\"ycw-resource-chip-relation\">{xref.relation}</span>\n </span>\n )\n}\n\nexport default ResourceChip\n","import React, { useState, useCallback, useRef, useEffect } from 'react'\nimport './FileViewer.css'\n\nexport interface HoverPreviewProps {\n fileName: string\n mimeType?: string | null\n previewText?: string\n rect: DOMRect | null\n visible: boolean\n}\n\nconst HoverPreview: React.FC<HoverPreviewProps> = ({\n fileName,\n mimeType,\n previewText,\n rect,\n visible,\n}) => {\n const tooltipRef = useRef<HTMLDivElement>(null)\n const [pos, setPos] = useState<{ top: number; left: number } | null>(null)\n\n useEffect(() => {\n if (!visible || !rect) {\n setPos(null)\n return\n }\n const top = rect.bottom + 4\n const left = rect.left + rect.width / 2\n setPos({ top, left })\n }, [visible, rect])\n\n if (!visible || !pos) return null\n\n return (\n <div\n ref={tooltipRef}\n className=\"ycw-fvm-hover-preview\"\n style={{ top: pos.top, left: pos.left, transform: 'translateX(-50%)' }}\n >\n <div className=\"ycw-fvm-hover-preview-header\">\n <span className=\"ycw-fvm-hover-preview-icon\">📄</span>\n <span className=\"ycw-fvm-hover-preview-name\">{fileName}</span>\n </div>\n {mimeType && (\n <span className=\"ycw-fvm-hover-preview-type\">{mimeType}</span>\n )}\n {previewText && (\n <div className=\"ycw-fvm-hover-preview-text\">{previewText}</div>\n )}\n <div className=\"ycw-fvm-hover-preview-hint\">点击查看</div>\n </div>\n )\n}\n\nexport default HoverPreview\n\nexport interface UseHoverPreviewOptions {\n containerRef: React.RefObject<HTMLElement | null>\n onHover?: (artifactId: string) => void\n delay?: number\n}\n\nexport function useHoverPreview({\n containerRef,\n onHover,\n delay = 400,\n}: UseHoverPreviewOptions) {\n const [preview, setPreview] = useState<{\n fileName: string\n mimeType?: string\n rect: DOMRect\n } | null>(null)\n const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n\n const handleMouseOver = useCallback((e: MouseEvent) => {\n const target = (e.target as HTMLElement).closest('[data-artifact-id]') as HTMLElement | null\n if (!target) return\n\n if (timerRef.current) clearTimeout(timerRef.current)\n\n timerRef.current = setTimeout(() => {\n const rect = target.getBoundingClientRect()\n const fileName = target.getAttribute('data-artifact-name') || target.textContent || ''\n const mimeType = target.getAttribute('data-artifact-mime') || undefined\n setPreview({ fileName, mimeType, rect })\n onHover?.(target.getAttribute('data-artifact-id') || '')\n }, delay)\n }, [delay, onHover])\n\n const handleMouseOut = useCallback((e: MouseEvent) => {\n const target = (e.target as HTMLElement).closest('[data-artifact-id]')\n if (!target) return\n if (timerRef.current) clearTimeout(timerRef.current)\n setPreview(null)\n }, [])\n\n useEffect(() => {\n const el = containerRef.current\n if (!el) return\n el.addEventListener('mouseover', handleMouseOver)\n el.addEventListener('mouseout', handleMouseOut)\n return () => {\n el.removeEventListener('mouseover', handleMouseOver)\n el.removeEventListener('mouseout', handleMouseOut)\n if (timerRef.current) clearTimeout(timerRef.current)\n }\n }, [containerRef, handleMouseOver, handleMouseOut])\n\n const dismiss = useCallback(() => setPreview(null), [])\n\n return {\n previewVisible: !!preview,\n previewFileName: preview?.fileName || '',\n previewMimeType: preview?.mimeType,\n previewRect: preview?.rect || null,\n dismissPreview: dismiss,\n }\n}\n","import type { FileReference } from '../../types.js'\n\nexport interface SelectionData {\n text: string\n startLine?: number\n endLine?: number\n sectionId?: string\n jsonPath?: string\n timestamp?: number\n componentRef?: string\n}\n\nexport interface SnapshotData {\n dataUrl: string\n width: number\n height: number\n label?: string\n}\n\nexport interface ViewerInteractionAdapter {\n canSelectText: boolean\n canSelectRegion: boolean\n canCaptureSnapshot: boolean\n canReferenceByLine: boolean\n canReferenceBySection: boolean\n canReferenceByPath: boolean\n canReferenceByTimestamp: boolean\n canReferenceByComponent: boolean\n\n minPanelWidth: number\n preferredRatio: number\n\n getSelection(): SelectionData | null\n createSnapshot?(): SnapshotData\n createReference(selection: SelectionData): FileReference\n}\n\nexport const VIEWER_CAPABILITIES: Record<string, Partial<ViewerInteractionAdapter>> = {\n markdown: {\n canSelectText: true,\n canSelectRegion: false,\n canCaptureSnapshot: false,\n canReferenceByLine: false,\n canReferenceBySection: true,\n canReferenceByPath: false,\n canReferenceByTimestamp: false,\n canReferenceByComponent: false,\n minPanelWidth: 360,\n preferredRatio: 0.6,\n },\n code: {\n canSelectText: true,\n canSelectRegion: false,\n canCaptureSnapshot: false,\n canReferenceByLine: true,\n canReferenceBySection: false,\n canReferenceByPath: false,\n canReferenceByTimestamp: false,\n canReferenceByComponent: false,\n minPanelWidth: 400,\n preferredRatio: 0.6,\n },\n text: {\n canSelectText: true,\n canSelectRegion: false,\n canCaptureSnapshot: false,\n canReferenceByLine: true,\n canReferenceBySection: false,\n canReferenceByPath: false,\n canReferenceByTimestamp: false,\n canReferenceByComponent: false,\n minPanelWidth: 360,\n preferredRatio: 0.55,\n },\n json: {\n canSelectText: true,\n canSelectRegion: false,\n canCaptureSnapshot: false,\n canReferenceByLine: false,\n canReferenceBySection: false,\n canReferenceByPath: true,\n canReferenceByTimestamp: false,\n canReferenceByComponent: false,\n minPanelWidth: 400,\n preferredRatio: 0.6,\n },\n image: {\n canSelectText: false,\n canSelectRegion: true,\n canCaptureSnapshot: true,\n canReferenceByLine: false,\n canReferenceBySection: false,\n canReferenceByPath: false,\n canReferenceByTimestamp: false,\n canReferenceByComponent: false,\n minPanelWidth: 300,\n preferredRatio: 0.65,\n },\n video: {\n canSelectText: false,\n canSelectRegion: false,\n canCaptureSnapshot: true,\n canReferenceByLine: false,\n canReferenceBySection: false,\n canReferenceByPath: false,\n canReferenceByTimestamp: true,\n canReferenceByComponent: false,\n minPanelWidth: 400,\n preferredRatio: 0.65,\n },\n audio: {\n canSelectText: false,\n canSelectRegion: false,\n canCaptureSnapshot: false,\n canReferenceByLine: false,\n canReferenceBySection: false,\n canReferenceByPath: false,\n canReferenceByTimestamp: true,\n canReferenceByComponent: false,\n minPanelWidth: 300,\n preferredRatio: 0.5,\n },\n html: {\n canSelectText: false,\n canSelectRegion: false,\n canCaptureSnapshot: false,\n canReferenceByLine: false,\n canReferenceBySection: false,\n canReferenceByPath: false,\n canReferenceByTimestamp: false,\n canReferenceByComponent: false,\n minPanelWidth: 400,\n preferredRatio: 0.65,\n },\n pdf: {\n canSelectText: false,\n canSelectRegion: false,\n canCaptureSnapshot: false,\n canReferenceByLine: false,\n canReferenceBySection: false,\n canReferenceByPath: false,\n canReferenceByTimestamp: false,\n canReferenceByComponent: false,\n minPanelWidth: 400,\n preferredRatio: 0.65,\n },\n gerber: {\n canSelectText: false,\n canSelectRegion: false,\n canCaptureSnapshot: false,\n canReferenceByLine: false,\n canReferenceBySection: false,\n canReferenceByPath: false,\n canReferenceByTimestamp: false,\n canReferenceByComponent: false,\n minPanelWidth: 480,\n preferredRatio: 0.65,\n },\n kicad: {\n canSelectText: false,\n canSelectRegion: true,\n canCaptureSnapshot: true,\n canReferenceByLine: false,\n canReferenceBySection: false,\n canReferenceByPath: false,\n canReferenceByTimestamp: false,\n canReferenceByComponent: true,\n minPanelWidth: 500,\n preferredRatio: 0.7,\n },\n '3d': {\n canSelectText: false,\n canSelectRegion: false,\n canCaptureSnapshot: true,\n canReferenceByLine: false,\n canReferenceBySection: false,\n canReferenceByPath: false,\n canReferenceByTimestamp: false,\n canReferenceByComponent: true,\n minPanelWidth: 500,\n preferredRatio: 0.7,\n },\n step: {\n canSelectText: false,\n canSelectRegion: false,\n canCaptureSnapshot: true,\n canReferenceByLine: false,\n canReferenceBySection: false,\n canReferenceByPath: false,\n canReferenceByTimestamp: false,\n canReferenceByComponent: true,\n minPanelWidth: 500,\n preferredRatio: 0.7,\n },\n unknown: {\n canSelectText: false,\n canSelectRegion: false,\n canCaptureSnapshot: false,\n canReferenceByLine: false,\n canReferenceBySection: false,\n canReferenceByPath: false,\n canReferenceByTimestamp: false,\n canReferenceByComponent: false,\n minPanelWidth: 360,\n preferredRatio: 0.55,\n },\n}\n\nexport function getViewerCapabilities(category: string): Partial<ViewerInteractionAdapter> {\n return VIEWER_CAPABILITIES[category] || VIEWER_CAPABILITIES.unknown\n}\n","import React from 'react'\nimport type { ForeignRoundBadgeProps } from '../types'\nimport { useChatWidgetI18n } from '../i18n'\nimport './ForeignRoundBadge.css'\n\nconst ForeignRoundBadge: React.FC<ForeignRoundBadgeProps> = ({\n round,\n unreadCount,\n}) => {\n const { messages } = useChatWidgetI18n()\n\n return (\n <div className=\"ycw-foreign-round-badge\">\n <span\n className=\"ycw-foreign-badge-dot\"\n data-state={round.status}\n />\n <div className=\"ycw-foreign-badge-body\">\n <span className=\"ycw-foreign-badge-preview\">\n {round.userMessage || messages['round.noMessage']}\n </span>\n </div>\n {unreadCount > 0 && (\n <span className=\"ycw-foreign-badge-count\">\n {unreadCount > 99 ? '99+' : unreadCount}\n </span>\n )}\n </div>\n )\n}\n\nexport default ForeignRoundBadge\n","import React, { useRef, useState, useEffect, useCallback, useMemo } from 'react'\nimport type { FileReference } from '../../types.js'\nimport type { AttentionToast as ToastData } from '../../hooks/useAttentionManager'\nimport type { ViewerTab } from '../../hooks/useViewerTabs.js'\nimport { useDragResize } from './useDragResize'\nimport FloatingInput from '../ContextBridge/FloatingInput'\nimport AttentionToastList from './AttentionToast'\nimport ImmersiveShell from './ImmersiveShell'\nimport TabBar from './TabBar'\nimport { useChatWidgetI18n } from '../../i18n'\nimport { useInteractionDispatch } from '../../hooks/useInteractionDispatch'\nimport { useEscStack, ESC_PRIORITY } from '../../hooks/useEscStack.js'\nimport { useShortcuts, type ShortcutDef } from '../../hooks/useShortcuts.js'\nimport { useNarrowMode } from '../../hooks/useNarrowMode.js'\nimport './SplitPanel.css'\n\nexport interface SplitPanelProps {\n open: boolean\n position?: 'left' | 'right'\n defaultRatio?: number\n minPrimaryWidth?: number\n minSecondaryWidth?: number\n onClose: () => void\n children: React.ReactNode\n primaryContent: React.ReactNode\n\n immersive?: boolean\n onImmersiveChange?: (immersive: boolean) => void\n\n unreadCount?: number\n onChatFocus?: () => void\n\n references?: FileReference[]\n onImmersiveSend?: (text: string) => void\n onRemoveReference?: (index: number) => void\n\n toasts?: ToastData[]\n onDismissToast?: (id: string) => void\n onPauseToast?: (id: string) => void\n onResumeToast?: (id: string) => void\n\n tabs?: ViewerTab[]\n activeTabId?: string | null\n onTabSwitch?: (tabId: string) => void\n onTabClose?: (tabId: string) => void\n\n onRailHome?: () => void\n onRailWorkspace?: () => void\n onRailAnnotation?: () => void\n annotationCount?: number\n activeOverlay?: 'home' | 'workspace' | 'discussion' | 'annotation' | null\n\n overlayContent?: React.ReactNode\n fabContent?: React.ReactNode\n contextLabel?: string\n\n /** v2: Channel sidebar (replaces rail when provided) */\n sidebarContent?: React.ReactNode\n /** v2: Floating conversation windows layer */\n floatingLayerContent?: React.ReactNode\n}\n\nconst NARROW_BREAKPOINT = 640\nconst SCROLL_SAVE_KEY = 'cwrf-scroll-'\n\nconst SplitPanel: React.FC<SplitPanelProps> = ({\n open,\n position = 'right',\n defaultRatio = 0.6,\n minPrimaryWidth = 280,\n minSecondaryWidth = 360,\n onClose,\n children,\n primaryContent,\n immersive: immersiveProp,\n onImmersiveChange,\n unreadCount = 0,\n onChatFocus,\n references = [],\n onImmersiveSend,\n onRemoveReference,\n toasts = [],\n onDismissToast,\n onPauseToast,\n onResumeToast,\n tabs,\n activeTabId,\n onTabSwitch,\n onTabClose,\n onRailHome,\n onRailWorkspace,\n onRailAnnotation,\n annotationCount = 0,\n activeOverlay,\n overlayContent,\n fabContent,\n contextLabel,\n sidebarContent,\n floatingLayerContent,\n}) => {\n const { t } = useChatWidgetI18n()\n const emitInteraction = useInteractionDispatch()\n const containerRef = useRef<HTMLDivElement>(null)\n const primaryScrollRef = useRef<HTMLDivElement | null>(null)\n const secondaryScrollRef = useRef<HTMLDivElement | null>(null)\n const isNarrow = useNarrowMode(containerRef, NARROW_BREAKPOINT)\n const [showFloatingInput, setShowFloatingInput] = useState(false)\n\n const immersiveControlled = immersiveProp !== undefined\n const [immersiveLocal, setImmersiveLocal] = useState(false)\n const immersive = immersiveControlled ? immersiveProp : immersiveLocal\n\n const saveScrollPositions = useCallback(() => {\n try {\n const data: Record<string, number> = {}\n if (primaryScrollRef.current) data.primary = primaryScrollRef.current.scrollTop\n if (secondaryScrollRef.current) data.secondary = secondaryScrollRef.current.scrollTop\n sessionStorage.setItem(SCROLL_SAVE_KEY + 'positions', JSON.stringify(data))\n } catch { /* quota exceeded */ }\n }, [])\n\n const setImmersive = useCallback((v: boolean) => {\n emitInteraction('immersive-toggle', v ? 'enter' : 'exit', { immersive: v })\n saveScrollPositions()\n if (immersiveControlled) {\n onImmersiveChange?.(v)\n } else {\n setImmersiveLocal(v)\n onImmersiveChange?.(v)\n }\n }, [immersiveControlled, onImmersiveChange, saveScrollPositions, emitInteraction])\n\n const { ratio, dragging, dividerProps } = useDragResize({\n containerRef,\n minLeft: position === 'right' ? minPrimaryWidth : minSecondaryWidth,\n minRight: position === 'right' ? minSecondaryWidth : minPrimaryWidth,\n initialRatio: defaultRatio,\n })\n\n useEffect(() => {\n if (!open) setImmersive(false)\n }, [open, setImmersive])\n\n const restoreScrollPositions = useCallback(() => {\n try {\n const raw = sessionStorage.getItem(SCROLL_SAVE_KEY + 'positions')\n if (!raw) return\n const data = JSON.parse(raw) as Record<string, number>\n requestAnimationFrame(() => {\n if (primaryScrollRef.current && data.primary != null) {\n primaryScrollRef.current.scrollTop = data.primary\n }\n if (secondaryScrollRef.current && data.secondary != null) {\n secondaryScrollRef.current.scrollTop = data.secondary\n }\n })\n } catch { /* parse error */ }\n }, [])\n\n useEffect(() => {\n restoreScrollPositions()\n }, [immersive, restoreScrollPositions])\n\n const escExitImmersive = useCallback(() => {\n setImmersive(false)\n return true\n }, [setImmersive])\n\n const escClosePanel = useCallback(() => {\n onClose()\n return true\n }, [onClose])\n\n const escCloseFloatingInput = useCallback(() => {\n setShowFloatingInput(false)\n return true\n }, [])\n\n useEscStack(escCloseFloatingInput, showFloatingInput, ESC_PRIORITY.INLINE_INPUT)\n useEscStack(escExitImmersive, immersive && !showFloatingInput, ESC_PRIORITY.EXIT_IMMERSIVE)\n useEscStack(escClosePanel, open && !immersive, ESC_PRIORITY.OVERLAY)\n\n const splitShortcuts = useMemo<ShortcutDef[]>(() => [\n { key: 'l', meta: true, handler: () => setImmersive(!immersive) },\n { key: '/', meta: true, handler: () => setShowFloatingInput(prev => !prev) },\n ], [immersive, setImmersive])\n\n useShortcuts({ shortcuts: splitShortcuts, enabled: open })\n\n const handleImmersiveSend = useCallback((text: string) => {\n onImmersiveSend?.(text)\n setShowFloatingInput(false)\n }, [onImmersiveSend])\n\n const shouldStack = isNarrow && open\n const showSplit = open && !shouldStack && !immersive\n\n const primaryStyle: React.CSSProperties = showSplit\n ? { flexBasis: `${(1 - ratio) * 100}%`, flexShrink: 0, flexGrow: 0 }\n : {}\n\n const secondaryStyle: React.CSSProperties = showSplit\n ? { flexBasis: `${ratio * 100}%`, flexShrink: 0, flexGrow: 0 }\n : {}\n\n if (immersive) {\n const tabBarNode = tabs && tabs.length > 0 && onTabSwitch && onTabClose ? (\n <TabBar\n tabs={tabs}\n activeTabId={activeTabId ?? null}\n onTabClick={onTabSwitch}\n onTabClose={onTabClose}\n />\n ) : undefined\n\n return (\n <div className=\"ycw-split-panel-container ycw-split-panel-immersive\" ref={containerRef}>\n {/* AC-IMM-007: primaryContent stays in DOM for scroll preservation */}\n <div className=\"ycw-split-panel-primary-hidden\" style={{ display: 'none' }} aria-hidden=\"true\" ref={primaryScrollRef}>\n {primaryContent}\n </div>\n\n <ImmersiveShell\n unreadCount={unreadCount}\n annotationCount={annotationCount}\n onRailHome={onRailHome}\n onRailWorkspace={onRailWorkspace}\n onRailAnnotation={onRailAnnotation}\n onExitImmersive={() => setImmersive(false)}\n activeOverlay={activeOverlay}\n tabBar={tabBarNode}\n overlay={overlayContent}\n fab={fabContent}\n sidebar={sidebarContent}\n floatingLayer={floatingLayerContent}\n >\n <div ref={secondaryScrollRef} style={{ height: '100%' }}>\n {children}\n </div>\n </ImmersiveShell>\n\n <AttentionToastList\n toasts={toasts}\n onDismiss={onDismissToast || (() => {})}\n onPause={onPauseToast}\n onResume={onResumeToast}\n onClick={() => {\n setImmersive(false)\n onChatFocus?.()\n }}\n />\n\n <FloatingInput\n visible={showFloatingInput}\n references={references}\n onSend={handleImmersiveSend}\n onRemoveReference={onRemoveReference || (() => {})}\n onClose={() => setShowFloatingInput(false)}\n contextLabel={contextLabel}\n />\n </div>\n )\n }\n\n const splitTabBarNode = tabs && tabs.length > 0 && onTabSwitch && onTabClose ? (\n <TabBar\n tabs={tabs}\n activeTabId={activeTabId ?? null}\n onTabClick={onTabSwitch}\n onTabClose={onTabClose}\n />\n ) : undefined\n\n const filePanel = open && (\n <div className=\"ycw-split-panel-secondary\" style={secondaryStyle}>\n {splitTabBarNode && <div className=\"ycw-split-panel-tabbar-slot\">{splitTabBarNode}</div>}\n <div className=\"ycw-split-panel-secondary-body\" ref={secondaryScrollRef}>\n {children}\n </div>\n </div>\n )\n\n if (shouldStack) {\n return (\n <div className=\"ycw-split-panel-container ycw-split-panel-stacked\" ref={containerRef}>\n <div className=\"ycw-split-panel-primary ycw-split-panel-primary-hidden\">\n {primaryContent}\n </div>\n <div className=\"ycw-split-panel-overlay\">\n {filePanel}\n </div>\n {overlayContent}\n {fabContent}\n </div>\n )\n }\n\n const primary = (\n <div\n className={`ycw-split-panel-primary ${open ? 'ycw-split-panel-primary-compressed' : ''}`}\n style={primaryStyle}\n ref={primaryScrollRef}\n >\n {primaryContent}\n </div>\n )\n\n const divider = open && (\n <div\n className={`ycw-split-panel-divider ${dragging ? 'ycw-split-panel-divider-active' : ''}`}\n {...dividerProps}\n />\n )\n\n const isFileLeft = position === 'left'\n\n return (\n <div\n className={`ycw-split-panel-container ${open ? 'ycw-split-panel-open' : ''} ${dragging ? 'ycw-split-panel-dragging' : ''}`}\n ref={containerRef}\n >\n {isFileLeft ? (\n <>\n {filePanel}\n {divider}\n {primary}\n </>\n ) : (\n <>\n {primary}\n {divider}\n {filePanel}\n </>\n )}\n {overlayContent}\n {fabContent}\n </div>\n )\n}\n\nexport default SplitPanel\n","import { useState, useCallback, useRef, useEffect } from 'react'\n\nconst STORAGE_KEY = 'cwrf-split-panel-ratio'\n\nexport interface DragResizeOptions {\n containerRef: React.RefObject<HTMLElement | null>\n minLeft: number\n minRight: number\n initialRatio: number\n persist?: boolean\n}\n\nexport interface DividerProps {\n onMouseDown: (e: React.MouseEvent) => void\n onTouchStart: (e: React.TouchEvent) => void\n}\n\nexport function useDragResize({\n containerRef,\n minLeft,\n minRight,\n initialRatio,\n persist = true,\n}: DragResizeOptions): { ratio: number; dragging: boolean; dividerProps: DividerProps } {\n const [ratio, setRatio] = useState(() => {\n if (persist) {\n const saved = localStorage.getItem(STORAGE_KEY)\n if (saved) {\n const n = parseFloat(saved)\n if (!isNaN(n) && n >= 0.2 && n <= 0.8) return n\n }\n }\n return initialRatio\n })\n const [dragging, setDragging] = useState(false)\n const ratioRef = useRef(ratio)\n\n useEffect(() => {\n ratioRef.current = ratio\n if (persist) localStorage.setItem(STORAGE_KEY, String(ratio))\n }, [ratio, persist])\n\n const startDrag = useCallback((startX: number) => {\n setDragging(true)\n const container = containerRef.current\n if (!container) return\n\n const rect = container.getBoundingClientRect()\n const totalWidth = rect.width\n\n const onMove = (clientX: number) => {\n const offsetX = clientX - rect.left\n const leftWidth = offsetX\n const rightWidth = totalWidth - offsetX\n\n if (leftWidth < minLeft || rightWidth < minRight) return\n\n const newRatio = rightWidth / totalWidth\n ratioRef.current = Math.round(newRatio * 1000) / 1000\n setRatio(ratioRef.current)\n }\n\n const onMouseMove = (e: MouseEvent) => {\n e.preventDefault()\n requestAnimationFrame(() => onMove(e.clientX))\n }\n const onTouchMove = (e: TouchEvent) => {\n if (e.touches.length === 1) {\n requestAnimationFrame(() => onMove(e.touches[0].clientX))\n }\n }\n\n const onEnd = () => {\n setDragging(false)\n document.removeEventListener('mousemove', onMouseMove)\n document.removeEventListener('mouseup', onEnd)\n document.removeEventListener('touchmove', onTouchMove)\n document.removeEventListener('touchend', onEnd)\n document.body.style.userSelect = ''\n document.body.style.cursor = ''\n }\n\n document.body.style.userSelect = 'none'\n document.body.style.cursor = 'col-resize'\n document.addEventListener('mousemove', onMouseMove)\n document.addEventListener('mouseup', onEnd)\n document.addEventListener('touchmove', onTouchMove, { passive: false })\n document.addEventListener('touchend', onEnd)\n }, [containerRef, minLeft, minRight])\n\n const dividerProps: DividerProps = {\n onMouseDown: useCallback((e: React.MouseEvent) => {\n e.preventDefault()\n startDrag(e.clientX)\n }, [startDrag]),\n onTouchStart: useCallback((e: React.TouchEvent) => {\n if (e.touches.length === 1) startDrag(e.touches[0].clientX)\n }, [startDrag]),\n }\n\n return { ratio, dragging, dividerProps }\n}\n","import React, { useState, useCallback, useRef, useEffect } from 'react'\nimport type { FileReference } from '../../types.js'\nimport { useChatWidgetI18n } from '../../i18n'\nimport { Icon } from '../Icon/Icon'\nimport ContextChip from './ContextChip'\nimport './ContextBridge.css'\n\nexport interface FloatingInputProps {\n visible: boolean\n references: FileReference[]\n onSend: (text: string) => void\n onRemoveReference: (index: number) => void\n onClose: () => void\n placeholder?: string\n contextLabel?: string\n}\n\nconst FloatingInput: React.FC<FloatingInputProps> = ({\n visible,\n references,\n onSend,\n onRemoveReference,\n onClose,\n placeholder: placeholderProp,\n contextLabel,\n}) => {\n const { t } = useChatWidgetI18n()\n const placeholder = placeholderProp\n ?? (contextLabel\n ? t('context.inputPlaceholderWithFile', { fileName: contextLabel })\n : t('context.inputPlaceholder'))\n const [text, setText] = useState('')\n const inputRef = useRef<HTMLInputElement>(null)\n\n useEffect(() => {\n if (visible) {\n requestAnimationFrame(() => inputRef.current?.focus())\n }\n }, [visible])\n\n const handleSubmit = useCallback((e?: React.FormEvent) => {\n e?.preventDefault()\n const trimmed = text.trim()\n if (!trimmed) return\n onSend(trimmed)\n setText('')\n }, [text, onSend])\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n onClose()\n }\n }, [onClose])\n\n if (!visible) return null\n\n return (\n <div className=\"ycw-cb-floating-input-wrapper\">\n {references.length > 0 && (\n <div className=\"ycw-cb-floating-input-chips\">\n {references.map((ref, i) => (\n <ContextChip key={`${ref.resourceId}-${i}`} reference={ref} onRemove={() => onRemoveReference(i)} />\n ))}\n </div>\n )}\n <form className=\"ycw-cb-floating-input-bar\" onSubmit={handleSubmit}>\n <input\n ref={inputRef}\n className=\"ycw-cb-floating-input\"\n type=\"text\"\n value={text}\n onChange={e => setText(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n autoComplete=\"off\"\n />\n <button\n className=\"ycw-cb-floating-input-send\"\n type=\"submit\"\n disabled={!text.trim()}\n aria-label={t('context.send')}\n >\n <Icon name=\"arrowUp\" size={16} aria-hidden />\n </button>\n </form>\n </div>\n )\n}\n\nexport default FloatingInput\n","import React from 'react'\nimport type { FileReference } from '../../types.js'\nimport { useChatWidgetI18n } from '../../i18n'\nimport './ContextBridge.css'\n\nexport interface ContextChipProps {\n reference: FileReference\n onRemove?: () => void\n}\n\nconst ContextChip: React.FC<ContextChipProps> = ({ reference, onRemove }) => {\n const { t } = useChatWidgetI18n()\n const hasSelection = !!reference.selection?.text\n const preview = hasSelection\n ? reference.selection!.text.length > 40\n ? reference.selection!.text.slice(0, 40) + '…'\n : reference.selection!.text\n : null\n\n const lineRange = reference.selection?.startLine != null\n ? reference.selection.endLine != null && reference.selection.endLine !== reference.selection.startLine\n ? `L${reference.selection.startLine}-${reference.selection.endLine}`\n : `L${reference.selection.startLine}`\n : null\n\n return (\n <span className=\"ycw-cb-context-chip\" title={reference.selection?.text || reference.fileName}>\n <span className=\"ycw-cb-chip-icon\">📎</span>\n <span className=\"ycw-cb-chip-file\">{reference.fileName}</span>\n {lineRange && <span className=\"ycw-cb-chip-line\">{lineRange}</span>}\n {preview && <span className=\"ycw-cb-chip-preview\">{preview}</span>}\n {onRemove && (\n <button\n className=\"ycw-cb-chip-remove\"\n onClick={(e) => { e.stopPropagation(); onRemove() }}\n aria-label={t('context.removeReference')}\n >\n ✕\n </button>\n )}\n </span>\n )\n}\n\nexport default ContextChip\n","import React from 'react'\nimport type { AttentionToast as ToastData } from '../../hooks/useAttentionManager'\nimport { Icon } from '../Icon/Icon'\nimport './SplitPanel.css'\n\nexport interface AttentionToastListProps {\n toasts: ToastData[]\n onDismiss: (id: string) => void\n onPause?: (id: string) => void\n onResume?: (id: string) => void\n onClick?: () => void\n}\n\nconst AttentionToastList: React.FC<AttentionToastListProps> = ({\n toasts,\n onDismiss,\n onPause,\n onResume,\n onClick,\n}) => {\n if (toasts.length === 0) return null\n\n return (\n <div className=\"ycw-split-panel-toast-list\">\n {toasts.map(toast => (\n <div\n key={toast.id}\n className=\"ycw-split-panel-toast\"\n onClick={() => {\n onDismiss(toast.id)\n onClick?.()\n }}\n onMouseEnter={() => onPause?.(toast.id)}\n onMouseLeave={() => onResume?.(toast.id)}\n role=\"status\"\n aria-live=\"polite\"\n >\n <span className=\"ycw-split-panel-toast-icon\">\n <Icon name=\"chat\" size={14} aria-hidden />\n </span>\n <div className=\"ycw-split-panel-toast-content\">\n {toast.agentName && (\n <span className=\"ycw-split-panel-toast-agent\">{toast.agentName}</span>\n )}\n <span className=\"ycw-split-panel-toast-text\">{toast.text}</span>\n </div>\n </div>\n ))}\n </div>\n )\n}\n\nexport default AttentionToastList\n","import React from 'react'\nimport { Icon } from '../Icon/Icon'\nimport { useChatWidgetI18n } from '../../i18n'\nimport './ImmersiveShell.css'\n\nexport interface RailAction {\n id: string\n icon: React.ReactNode\n label: string\n badge?: number\n onClick: () => void\n active?: boolean\n}\n\nexport interface ImmersiveShellProps {\n children: React.ReactNode\n tabBar?: React.ReactNode\n /** v2: Channel sidebar replaces rail + overlays */\n sidebar?: React.ReactNode\n /** v2: Floating conversation windows layer */\n floatingLayer?: React.ReactNode\n /** v1 (legacy): overlay content — only rendered when sidebar is not provided */\n overlay?: React.ReactNode\n fab?: React.ReactNode\n unreadCount?: number\n annotationCount?: number\n onRailHome?: () => void\n onRailWorkspace?: () => void\n onRailAnnotation?: () => void\n onExitImmersive?: () => void\n activeOverlay?: 'home' | 'workspace' | 'discussion' | 'annotation' | null\n extraRailActions?: RailAction[]\n}\n\nconst ImmersiveShell: React.FC<ImmersiveShellProps> = ({\n children,\n tabBar,\n sidebar,\n floatingLayer,\n overlay,\n fab,\n unreadCount = 0,\n annotationCount = 0,\n onRailHome,\n onRailWorkspace,\n onRailAnnotation,\n onExitImmersive,\n activeOverlay,\n extraRailActions,\n}) => {\n const { t } = useChatWidgetI18n()\n\n const useSidebar = !!sidebar\n\n return (\n <div className={`ycw-immersive-shell ${useSidebar ? 'ycw-immersive-shell--sidebar' : ''}`}>\n {useSidebar ? (\n /* v2: Discord-style channel sidebar */\n sidebar\n ) : (\n /* v1: Icon rail */\n <nav className=\"ycw-immersive-rail\" aria-label=\"Immersive navigation\">\n <button\n className={`ycw-rail-btn ${activeOverlay === 'home' ? 'ycw-rail-btn--active' : ''}`}\n onClick={onRailHome}\n title={t('split.home')}\n aria-label={t('split.home')}\n data-testid=\"cwrf010-rail-home\"\n >\n <Icon name=\"house\" size={20} aria-hidden />\n {unreadCount > 0 && (\n <span className=\"ycw-rail-badge\">{unreadCount > 99 ? '99+' : unreadCount}</span>\n )}\n </button>\n\n <button\n className={`ycw-rail-btn ${activeOverlay === 'workspace' ? 'ycw-rail-btn--active' : ''}`}\n onClick={onRailWorkspace}\n title={t('split.workspace')}\n aria-label={t('split.workspace')}\n data-testid=\"cwrf010-rail-folder\"\n >\n <Icon name={activeOverlay === 'workspace' ? 'folderOpen' : 'folder'} size={20} aria-hidden />\n </button>\n\n <button\n className={`ycw-rail-btn ${activeOverlay === 'annotation' ? 'ycw-rail-btn--active' : ''}`}\n onClick={onRailAnnotation}\n title={t('split.annotation')}\n aria-label={t('split.annotation')}\n data-testid=\"cwrf010-rail-chat\"\n >\n <Icon name=\"chatCircleDots\" size={20} aria-hidden />\n {annotationCount > 0 && (\n <span className=\"ycw-rail-badge\">{annotationCount > 99 ? '99+' : annotationCount}</span>\n )}\n </button>\n\n {extraRailActions?.map(action => (\n <button\n key={action.id}\n className={`ycw-rail-btn ${action.active ? 'ycw-rail-btn--active' : ''}`}\n onClick={action.onClick}\n title={action.label}\n aria-label={action.label}\n >\n {action.icon}\n {action.badge != null && action.badge > 0 && (\n <span className=\"ycw-rail-badge\">{action.badge > 99 ? '99+' : action.badge}</span>\n )}\n </button>\n ))}\n\n <div className=\"ycw-rail-spacer\" />\n\n <button\n className=\"ycw-rail-btn ycw-rail-btn--exit\"\n onClick={onExitImmersive}\n title={t('split.exitFullscreen')}\n aria-label={t('split.exitFullscreen')}\n >\n <Icon name=\"arrowsIn\" size={20} aria-hidden />\n </button>\n </nav>\n )}\n\n <div className=\"ycw-immersive-content\">\n {tabBar && <div className=\"ycw-immersive-tabbar-slot\">{tabBar}</div>}\n <div className=\"ycw-immersive-viewer\">\n {children}\n {/* v2: floating windows live inside viewer so they're positioned relative to it */}\n {floatingLayer && (\n <div className=\"ycw-floating-container\">{floatingLayer}</div>\n )}\n </div>\n </div>\n\n {fab}\n {!useSidebar && overlay}\n </div>\n )\n}\n\nexport default ImmersiveShell\n","import React, { useRef, useEffect } from 'react'\nimport type { ViewerTab } from '../../hooks/useViewerTabs.js'\nimport { Icon } from '../Icon/Icon'\nimport { fileTypeIcon } from '../../utils/fileTypeIcon.js'\nimport { fileTypeColor } from '../../utils/fileTypeColor.js'\nimport { useChatWidgetI18n } from '../../i18n'\nimport './TabBar.css'\n\nexport interface TabBarProps {\n tabs: ViewerTab[]\n activeTabId: string | null\n onTabClick: (tabId: string) => void\n onTabClose: (tabId: string) => void\n maxVisible?: number\n}\n\nconst TabBar: React.FC<TabBarProps> = ({\n tabs,\n activeTabId,\n onTabClick,\n onTabClose,\n maxVisible = 8,\n}) => {\n const { t } = useChatWidgetI18n()\n const scrollRef = useRef<HTMLDivElement>(null)\n const activeRef = useRef<HTMLButtonElement>(null)\n\n useEffect(() => {\n if (activeRef.current) {\n activeRef.current.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' })\n }\n }, [activeTabId])\n\n if (tabs.length === 0) return null\n\n return (\n <div className=\"ycw-tab-bar\" role=\"tablist\">\n <div className=\"ycw-tab-bar-scroll\" ref={scrollRef}>\n {tabs.map(tab => {\n const isActive = tab.id === activeTabId\n const iconName = fileTypeIcon(tab.fileName || tab.mimeType || '')\n const colorVar = fileTypeColor(tab.fileName || '')\n\n return (\n <button\n key={tab.id}\n ref={isActive ? activeRef : undefined}\n className={`ycw-tab-item${isActive ? ' ycw-tab-item--active' : ''}${tab.isNew ? ' ycw-tab-item--new' : ''}`}\n role=\"tab\"\n aria-selected={isActive}\n onClick={() => onTabClick(tab.id)}\n title={tab.fileName}\n style={{ borderBottomColor: isActive ? `var(${colorVar}, currentColor)` : undefined }}\n >\n <Icon name={iconName} size={14} aria-hidden />\n <span className=\"ycw-tab-label\">{tab.fileName}</span>\n {tab.isNew && <span className=\"ycw-tab-new-badge\" />}\n {(tab.annotationCount ?? 0) > 0 && (\n <span className=\"ycw-tab-annotation-count\">{tab.annotationCount}</span>\n )}\n <span\n className=\"ycw-tab-close\"\n role=\"button\"\n aria-label={t('split.tabClose')}\n onClick={e => {\n e.stopPropagation()\n onTabClose(tab.id)\n }}\n >\n <Icon name=\"x\" size={12} aria-hidden />\n </span>\n </button>\n )\n })}\n </div>\n </div>\n )\n}\n\nexport default TabBar\n","type FileCategory =\n | 'sch' | 'pcb' | 'pro' | 'gerber' | 'pdf' | 'excel'\n | 'code' | 'image' | 'text' | 'json' | 'other'\n\nconst extToCategory: Record<string, FileCategory> = {\n '.kicad_sch': 'sch',\n '.kicad_sym': 'sch',\n '.kicad_pcb': 'pcb',\n '.kicad_mod': 'pcb',\n '.kicad_pro': 'pro',\n '.kicad_wks': 'pro',\n '.kicad_dru': 'pro',\n '.gbr': 'gerber', '.gtl': 'gerber', '.gbl': 'gerber',\n '.gbs': 'gerber', '.gts': 'gerber', '.gko': 'gerber',\n '.drl': 'gerber',\n '.pdf': 'pdf',\n '.xlsx': 'excel', '.xls': 'excel', '.csv': 'excel',\n '.py': 'code', '.ts': 'code', '.tsx': 'code', '.js': 'code',\n '.jsx': 'code', '.c': 'code', '.cpp': 'code', '.h': 'code',\n '.go': 'code', '.rs': 'code', '.java': 'code',\n '.html': 'code', '.css': 'code', '.json': 'json',\n '.xml': 'code', '.yaml': 'code', '.yml': 'code',\n '.png': 'image', '.jpg': 'image', '.jpeg': 'image',\n '.gif': 'image', '.svg': 'image', '.webp': 'image',\n '.md': 'text', '.txt': 'text', '.log': 'text', '.rst': 'text',\n}\n\nconst mimeToCategory: Array<[string, FileCategory]> = [\n ['application/pdf', 'pdf'],\n ['image/', 'image'],\n ['text/markdown', 'text'],\n ['text/plain', 'text'],\n ['text/html', 'code'],\n ['text/css', 'code'],\n ['text/javascript', 'code'],\n ['application/json', 'json'],\n]\n\nconst categoryToCssVar: Record<FileCategory, string> = {\n sch: '--ycw-file-color-sch',\n pcb: '--ycw-file-color-pcb',\n pro: '--ycw-file-color-pro',\n gerber: '--ycw-file-color-gerber',\n pdf: '--ycw-file-color-pdf',\n excel: '--ycw-file-color-excel',\n code: '--ycw-file-color-code',\n image: '--ycw-file-color-image',\n text: '--ycw-file-color-text',\n json: '--ycw-file-color-json',\n other: '--ycw-file-color-other',\n}\n\nexport function fileTypeCategory(mimeOrExt: string): FileCategory {\n if (!mimeOrExt) return 'other'\n const lower = mimeOrExt.toLowerCase()\n\n if (lower.startsWith('.') || lower.includes('.')) {\n const ext = lower.startsWith('.') ? lower : '.' + lower.split('.').pop()\n if (ext && ext in extToCategory) return extToCategory[ext]\n }\n\n for (const [prefix, cat] of mimeToCategory) {\n if (lower.startsWith(prefix)) return cat\n }\n\n return 'other'\n}\n\nexport function fileTypeColor(mimeOrExt: string): string {\n return categoryToCssVar[fileTypeCategory(mimeOrExt)]\n}\n","import { useEffect, useRef } from 'react'\nimport { randomUUID } from '../utils/randomUUID'\n\nexport type EscHandler = () => boolean | void\n\nconst _stack: Array<{ id: string; handler: EscHandler; priority: number }> = []\n\nlet _listenerAttached = false\n\nfunction attachGlobalListener() {\n if (_listenerAttached) return\n _listenerAttached = true\n document.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return\n for (let i = _stack.length - 1; i >= 0; i--) {\n const entry = _stack[i]\n const consumed = entry.handler()\n if (consumed !== false) {\n e.preventDefault()\n e.stopPropagation()\n return\n }\n }\n }, true)\n}\n\nexport const ESC_PRIORITY = {\n INLINE_INPUT: 60,\n FLOATING_TOOLBAR: 50,\n ANNOTATION_FAB: 40,\n OVERLAY: 30,\n EXIT_IMMERSIVE: 10,\n} as const\n\nexport function useEscStack(\n handler: EscHandler,\n active: boolean,\n priority: number = ESC_PRIORITY.OVERLAY,\n): void {\n const idRef = useRef(randomUUID())\n const handlerRef = useRef(handler)\n handlerRef.current = handler\n\n useEffect(() => {\n attachGlobalListener()\n }, [])\n\n useEffect(() => {\n if (!active) {\n const idx = _stack.findIndex(e => e.id === idRef.current)\n if (idx !== -1) _stack.splice(idx, 1)\n return\n }\n\n const existing = _stack.findIndex(e => e.id === idRef.current)\n const entry = {\n id: idRef.current,\n handler: () => handlerRef.current(),\n priority,\n }\n\n if (existing !== -1) {\n _stack[existing] = entry\n } else {\n _stack.push(entry)\n }\n _stack.sort((a, b) => b.priority - a.priority)\n\n return () => {\n const idx = _stack.findIndex(e => e.id === idRef.current)\n if (idx !== -1) _stack.splice(idx, 1)\n }\n }, [active, priority])\n}\n","import { useEffect, useRef } from 'react'\n\nexport interface ShortcutDef {\n key: string\n meta?: boolean\n shift?: boolean\n handler: () => void\n}\n\nexport interface UseShortcutsOptions {\n shortcuts: ShortcutDef[]\n enabled?: boolean\n}\n\nexport function useShortcuts({ shortcuts, enabled = true }: UseShortcutsOptions): void {\n const shortcutsRef = useRef(shortcuts)\n shortcutsRef.current = shortcuts\n\n useEffect(() => {\n if (!enabled) return\n\n function handleKeyDown(e: KeyboardEvent) {\n for (const def of shortcutsRef.current) {\n const metaMatch = def.meta ? (e.metaKey || e.ctrlKey) : !(e.metaKey || e.ctrlKey)\n const shiftMatch = def.shift ? e.shiftKey : !e.shiftKey\n if (e.key.toLowerCase() === def.key.toLowerCase() && metaMatch && shiftMatch) {\n e.preventDefault()\n def.handler()\n return\n }\n }\n }\n\n document.addEventListener('keydown', handleKeyDown)\n return () => document.removeEventListener('keydown', handleKeyDown)\n }, [enabled])\n}\n","import { useState, useEffect, useRef } from 'react'\n\nconst DEFAULT_BREAKPOINT = 768\n\nexport function useNarrowMode(\n containerRef: React.RefObject<HTMLElement | null>,\n breakpoint = DEFAULT_BREAKPOINT,\n): boolean {\n const [narrow, setNarrow] = useState(false)\n const observerRef = useRef<ResizeObserver | null>(null)\n\n useEffect(() => {\n const el = containerRef.current\n if (!el) return\n\n observerRef.current = new ResizeObserver(entries => {\n const width = entries[0]?.contentRect.width ?? 0\n setNarrow(width < breakpoint)\n })\n observerRef.current.observe(el)\n\n return () => {\n observerRef.current?.disconnect()\n observerRef.current = null\n }\n }, [containerRef, breakpoint])\n\n return narrow\n}\n","import { useState, useCallback, useRef, useEffect } from 'react'\nimport { randomUUID } from '../utils/randomUUID'\n\nexport interface NotificationConfig {\n sound: boolean\n toast: boolean\n toastDuration: number\n badgeAnimation: boolean\n}\n\nexport interface AttentionToast {\n id: string\n text: string\n agentName?: string\n timestamp: number\n}\n\ninterface ToastTimer {\n timeoutId: ReturnType<typeof setTimeout>\n remaining: number\n startedAt: number\n}\n\nconst DEFAULT_NOTIFICATION_CONFIG: NotificationConfig = {\n sound: false,\n toast: true,\n toastDuration: 4500,\n badgeAnimation: true,\n}\n\nexport interface UseAttentionManagerOptions {\n fileViewerOpen: boolean\n immersive: boolean\n config?: Partial<NotificationConfig>\n}\n\nexport function useAttentionManager({\n fileViewerOpen,\n immersive,\n config: configOverrides,\n}: UseAttentionManagerOptions) {\n const config: NotificationConfig = { ...DEFAULT_NOTIFICATION_CONFIG, ...configOverrides }\n const [unreadCount, setUnreadCount] = useState(0)\n const [toasts, setToasts] = useState<AttentionToast[]>([])\n const prevMessageCountRef = useRef(0)\n const toastTimers = useRef(new Map<string, ToastTimer>())\n\n const scheduleRemoval = useCallback((toastId: string, delay: number) => {\n const timeoutId = setTimeout(() => {\n toastTimers.current.delete(toastId)\n setToasts(prev => prev.filter(t => t.id !== toastId))\n }, delay)\n toastTimers.current.set(toastId, {\n timeoutId,\n remaining: delay,\n startedAt: Date.now(),\n })\n }, [])\n\n const trackNewMessage = useCallback((agentName?: string, preview?: string) => {\n if (!fileViewerOpen && !immersive) return\n\n setUnreadCount(prev => prev + 1)\n\n if (immersive && config.toast) {\n const toast: AttentionToast = {\n id: randomUUID(),\n text: preview || '新消息',\n agentName,\n timestamp: Date.now(),\n }\n setToasts(prev => [...prev.slice(-4), toast])\n scheduleRemoval(toast.id, config.toastDuration)\n }\n }, [fileViewerOpen, immersive, config.toast, config.toastDuration, scheduleRemoval])\n\n const clearUnread = useCallback(() => {\n setUnreadCount(0)\n }, [])\n\n const dismissToast = useCallback((id: string) => {\n const timer = toastTimers.current.get(id)\n if (timer) {\n clearTimeout(timer.timeoutId)\n toastTimers.current.delete(id)\n }\n setToasts(prev => prev.filter(t => t.id !== id))\n }, [])\n\n const pauseToast = useCallback((id: string) => {\n const timer = toastTimers.current.get(id)\n if (!timer) return\n clearTimeout(timer.timeoutId)\n timer.remaining -= Date.now() - timer.startedAt\n if (timer.remaining < 0) timer.remaining = 0\n }, [])\n\n const resumeToast = useCallback((id: string) => {\n const timer = toastTimers.current.get(id)\n if (!timer || timer.remaining <= 0) return\n scheduleRemoval(id, timer.remaining)\n }, [scheduleRemoval])\n\n useEffect(() => {\n if (!fileViewerOpen && !immersive) {\n for (const timer of toastTimers.current.values()) {\n clearTimeout(timer.timeoutId)\n }\n toastTimers.current.clear()\n setUnreadCount(0)\n setToasts([])\n }\n }, [fileViewerOpen, immersive])\n\n useEffect(() => {\n return () => {\n for (const timer of toastTimers.current.values()) {\n clearTimeout(timer.timeoutId)\n }\n }\n }, [])\n\n return {\n unreadCount,\n toasts,\n trackNewMessage,\n clearUnread,\n dismissToast,\n pauseToast,\n resumeToast,\n notificationConfig: config,\n }\n}\n","import { useCallback, useState } from 'react'\nimport type { ChatWidgetAdapter, Artifact, ResourceContent, ChatWidgetInteractionEvent } from '../types'\n\ntype DispatchFn = (event: ChatWidgetInteractionEvent) => void\n\nexport interface UseFileViewerOptions {\n adapter: ChatWidgetAdapter\n currentSessionId: number | null\n onArtifactClick?: (artifact: Artifact) => void\n errorMessage?: string\n dispatch?: DispatchFn | null\n}\n\nexport interface UseFileViewerReturn {\n viewerOpen: boolean\n viewerLoading: boolean\n viewerContent: ResourceContent | null\n viewerError: string | null\n viewerArtifact: Artifact | null\n immersive: boolean\n setImmersive: (v: boolean) => void\n openArtifact: (artifact: Artifact) => void\n closeViewer: () => void\n}\n\nexport function useFileViewer(options: UseFileViewerOptions): UseFileViewerReturn {\n const { adapter, currentSessionId, onArtifactClick, errorMessage = 'Failed to load', dispatch: dispatchOpt } = options\n const dispatch = dispatchOpt ?? null\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 const [immersive, setImmersive] = useState(false)\n\n const openArtifact = useCallback((artifact: Artifact) => {\n onArtifactClick?.(artifact)\n\n if (!currentSessionId) return\n\n dispatch?.({ type: 'viewer-open', target: artifact.id, metadata: { name: artifact.name }, timestamp: Date.now() })\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 || errorMessage)\n setViewerLoading(false)\n })\n }, [adapter, currentSessionId, onArtifactClick, errorMessage, dispatch])\n\n const closeViewer = useCallback(() => {\n dispatch?.({ type: 'viewer-close', target: viewerArtifact?.id || '', timestamp: Date.now() })\n setViewerOpen(false)\n }, [dispatch, viewerArtifact])\n\n return {\n viewerOpen,\n viewerLoading,\n viewerContent,\n viewerError,\n viewerArtifact,\n immersive,\n setImmersive,\n openArtifact,\n closeViewer,\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { Round, ExecutionStatus } from '../types'\n\nexport interface UseScrollManagerOptions {\n rounds: Round[]\n executionStatus: ExecutionStatus\n}\n\nexport interface UseScrollManagerReturn {\n messageListRef: React.RefObject<HTMLDivElement>\n isUserAtBottomRef: React.RefObject<boolean>\n pinnedInteractionId: string | null\n isTransitioning: boolean\n pendingScrollInteractionId: string | null\n setPendingScrollInteractionId: (id: string | null) => void\n handleScroll: (e: React.UIEvent<HTMLDivElement>) => void\n scrollToBottom: () => void\n getSpacerHeight: (interactionId: string) => number\n setPinnedInteractionId: (id: string | null) => void\n}\n\nconst HYSTERESIS_THRESHOLD = 30\nconst DEBOUNCE_DELAY = 150\nconst FADE_DURATION = 150\n\nexport function useScrollManager(options: UseScrollManagerOptions): UseScrollManagerReturn {\n const { rounds, executionStatus } = options\n\n const [pinnedInteractionId, setPinnedInteractionId] = useState<string | null>(null)\n const [isTransitioning, setIsTransitioning] = useState(false)\n const [pendingScrollInteractionId, setPendingScrollInteractionId] = useState<string | null>(null)\n const [containerHeight, setContainerHeight] = useState(0)\n const [roundHeights, setRoundHeights] = useState<Map<string, number>>(new Map())\n\n const messageListRef = useRef<HTMLDivElement>(null!)\n const scrollDebounceTimer = useRef<number | null>(null)\n const lastScrollTop = useRef(0)\n const isProgrammaticScrollRef = useRef(false)\n const clearScreenScrollTopRef = useRef<number | null>(null)\n const isUserAtBottomRef = useRef(true)\n const processedScrollRef = useRef<string | null>(null)\n const prevRoundsLenRef = useRef(0)\n\n const pinnedRoundId = pinnedInteractionId\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 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 if (rect.top <= viewportTop + 50) {\n return round.interactionId\n }\n\n if (i > 0) {\n if (rect.top <= viewportTop + 100) {\n return rounds[i - 1].interactionId\n }\n }\n }\n\n return rounds[0]?.interactionId || null\n }, [rounds])\n\n const updatePinnedArea = useCallback((interactionId: string | null) => {\n if (isTransitioning || interactionId === pinnedRoundId) return\n\n setIsTransitioning(true)\n\n setTimeout(() => {\n setPinnedInteractionId(interactionId)\n\n setTimeout(() => {\n setIsTransitioning(false)\n }, FADE_DURATION)\n }, FADE_DURATION)\n }, [isTransitioning, pinnedRoundId])\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 if (isProgrammaticScrollRef.current) {\n lastScrollTop.current = currentScrollTop\n return\n }\n\n const scrollBottom = target.scrollHeight - target.scrollTop - target.clientHeight\n isUserAtBottomRef.current = scrollBottom < 50\n\n if (scrollBottom < 50 && clearScreenScrollTopRef.current !== null) {\n clearScreenScrollTopRef.current = null\n }\n\n if (scrollDebounceTimer.current) {\n clearTimeout(scrollDebounceTimer.current)\n }\n\n const newPinnedRound = calculatePinnedRound()\n\n if (isTransitioning) {\n lastScrollTop.current = currentScrollTop\n return\n }\n\n if (newPinnedRound !== pinnedRoundId) {\n if (scrollDelta >= HYSTERESIS_THRESHOLD) {\n updatePinnedArea(newPinnedRound)\n lastScrollTop.current = currentScrollTop\n } else {\n scrollDebounceTimer.current = window.setTimeout(() => {\n if (!isTransitioning && !isProgrammaticScrollRef.current) {\n const confirmedRound = calculatePinnedRound()\n if (confirmedRound !== pinnedRoundId) {\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, pinnedRoundId])\n\n const scrollToBottom = useCallback(() => {\n if (!messageListRef.current) return\n messageListRef.current.scrollTop = messageListRef.current.scrollHeight\n }, [])\n\n const getSpacerHeight = useCallback((interactionId: string): number => {\n const roundHeight = roundHeights.get(interactionId) || 0\n return Math.max(0, containerHeight - roundHeight)\n }, [containerHeight, roundHeights])\n\n // Monitor container height changes\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 window.addEventListener('resize', updateHeight)\n return () => window.removeEventListener('resize', updateHeight)\n }, [])\n\n // Monitor round container heights\n useEffect(() => {\n if (!messageListRef.current) return\n\n const roundContainers = messageListRef.current.querySelectorAll('.ycw-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 // Clear-screen scroll effect\n useEffect(() => {\n if (!pendingScrollInteractionId || !messageListRef.current) return\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 processedScrollRef.current = targetInteractionId\n setPendingScrollInteractionId(null)\n\n isProgrammaticScrollRef.current = true\n clearScreenScrollTopRef.current = 0\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 const targetScrollTop = roundElement.offsetTop - 16 + 20\n container.scrollTop = Math.max(0, targetScrollTop)\n clearScreenScrollTopRef.current = container.scrollTop\n }\n }\n\n requestAnimationFrame(scrollToRoundTop)\n\n setTimeout(() => {\n isProgrammaticScrollRef.current = false\n }, 200)\n }, [rounds, pendingScrollInteractionId])\n\n // Auto-scroll on new messages\n useEffect(() => {\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 if (clearScreenScrollTopRef.current !== null) {\n const roundContainers = container.querySelectorAll('.ycw-round-container')\n const currentRoundElement = roundContainers[roundContainers.length - 1] as HTMLElement\n\n if (currentRoundElement) {\n const roundBottom = currentRoundElement.offsetTop + currentRoundElement.offsetHeight\n const visibleBottom = currentScrollTop + container.clientHeight\n\n if (roundBottom > visibleBottom) {\n const targetScrollTop = roundBottom - container.clientHeight\n const finalScrollTop = Math.max(targetScrollTop, clearScreenScrollTopRef.current)\n container.scrollTop = finalScrollTop\n }\n }\n return\n }\n\n if (isUserAtBottomRef.current) {\n container.scrollTop = maxScrollTop\n }\n })\n }, [rounds, executionStatus])\n\n // Pin to latest when first loaded\n useEffect(() => {\n if (rounds.length > 0 && !pinnedInteractionId) {\n setPinnedInteractionId(rounds[rounds.length - 1].interactionId)\n }\n }, [rounds, pinnedInteractionId])\n\n // Pin + scroll on new round\n useEffect(() => {\n if (rounds.length > prevRoundsLenRef.current && prevRoundsLenRef.current > 0) {\n const latest = rounds[rounds.length - 1]\n setPinnedInteractionId(latest.interactionId)\n if (pendingScrollInteractionId === '__pending__') {\n setPendingScrollInteractionId(latest.interactionId)\n }\n }\n prevRoundsLenRef.current = rounds.length\n }, [rounds.length])\n\n // Cleanup debounce timer\n useEffect(() => {\n return () => {\n if (scrollDebounceTimer.current) {\n clearTimeout(scrollDebounceTimer.current)\n }\n }\n }, [])\n\n return {\n messageListRef,\n isUserAtBottomRef,\n pinnedInteractionId,\n isTransitioning,\n pendingScrollInteractionId,\n setPendingScrollInteractionId,\n handleScroll,\n scrollToBottom,\n getSpacerHeight,\n setPinnedInteractionId,\n }\n}\n","import { useCallback, useContext, useRef, useState } from 'react'\nimport type { FileReference, ChatWidgetInteractionEvent } from '../types'\nimport { interpolate } from '../i18n/messages'\nimport type { ChatWidgetMessages } from '../i18n/messages'\nimport { I18nContext } from '../i18n/context'\n\ntype DispatchFn = (event: ChatWidgetInteractionEvent) => void\n\n/**\n * Build a reference-enriched message by prepending file reference blocks.\n * Uses i18n template for the header.\n */\nexport function buildEnrichedMessage(\n message: string,\n refs: FileReference[],\n messages?: ChatWidgetMessages,\n): string {\n if (refs.length === 0) return message\n const headerTemplate = messages?.['reference.header'] ?? '[Reference: {{fileName}}]'\n const refParts = refs.map(ref => {\n const header = interpolate(headerTemplate, { fileName: ref.fileName })\n const specSuffix = ref.specId ? ` [spec_id=${ref.specId}]` : ''\n if (ref.selection?.text) {\n const parts: string[] = []\n if (ref.selection.page != null) {\n parts.push(ref.selection.endPage != null\n ? `p.${ref.selection.page}-${ref.selection.endPage}`\n : `p.${ref.selection.page}`)\n }\n if (ref.selection.startLine != null) {\n parts.push(ref.selection.endLine != null && ref.selection.endLine !== ref.selection.startLine\n ? `L${ref.selection.startLine}-${ref.selection.endLine}`\n : `L${ref.selection.startLine}`)\n }\n const locationInfo = parts.length > 0 ? ` (${parts.join(', ')})` : ''\n return `${header}${specSuffix}${locationInfo}\\n\\`\\`\\`\\n${ref.selection.text}\\n\\`\\`\\``\n }\n return `${header}${specSuffix}`\n })\n return `${refParts.join('\\n\\n')}\\n\\n${message}`\n}\n\nexport interface UseReferenceManagerOptions {\n dispatch?: DispatchFn | null\n}\n\nexport interface UseReferenceManagerReturn {\n references: FileReference[]\n referencesRef: React.RefObject<FileReference[]>\n addReference: (ref: FileReference) => void\n removeReference: (index: number) => void\n clearReferences: () => void\n enrichMessage: (message: string) => string\n}\n\nexport function useReferenceManager(options?: UseReferenceManagerOptions): UseReferenceManagerReturn {\n const dispatch = options?.dispatch ?? null\n const messages = useContext(I18nContext)\n const [references, setReferences] = useState<FileReference[]>([])\n const referencesRef = useRef<FileReference[]>([])\n referencesRef.current = references\n\n const addReference = useCallback((ref: FileReference) => {\n dispatch?.({ type: 'reference-add', target: ref.resourceId, metadata: { fileName: ref.fileName }, timestamp: Date.now() })\n setReferences(prev => [...prev, ref])\n }, [dispatch])\n\n const removeReference = useCallback((index: number) => {\n const ref = referencesRef.current[index]\n if (ref) {\n dispatch?.({ type: 'reference-remove', target: ref.resourceId, metadata: { fileName: ref.fileName, index }, timestamp: Date.now() })\n }\n setReferences(prev => prev.filter((_, i) => i !== index))\n }, [dispatch])\n\n const clearReferences = useCallback(() => {\n setReferences([])\n }, [])\n\n const enrichMessage = useCallback((message: string): string => {\n const pendingRefs = referencesRef.current\n return buildEnrichedMessage(message, pendingRefs, messages)\n }, [messages])\n\n return {\n references,\n referencesRef,\n addReference,\n removeReference,\n clearReferences,\n enrichMessage,\n }\n}\n","import { useEffect, useState } from 'react'\n\nexport function useTypewriterTitle(title: string, speed: number = 50): {\n displayedTitle: string\n isTitleAnimating: boolean\n} {\n const [displayedTitle, setDisplayedTitle] = useState<string>('')\n const [isTitleAnimating, setIsTitleAnimating] = useState(false)\n\n useEffect(() => {\n if (!title) {\n setDisplayedTitle('')\n setIsTitleAnimating(false)\n return\n }\n\n if (title !== displayedTitle) {\n setIsTitleAnimating(true)\n let currentIndex = 0\n let cancelled = false\n let rafId: number | null = null\n let timeoutId: ReturnType<typeof setTimeout> | null = null\n\n const animateTitle = () => {\n if (cancelled) return\n if (currentIndex <= title.length) {\n setDisplayedTitle(title.slice(0, currentIndex))\n currentIndex++\n rafId = requestAnimationFrame(() => {\n if (cancelled) return\n timeoutId = setTimeout(animateTitle, speed)\n })\n } else {\n setIsTitleAnimating(false)\n }\n }\n\n setDisplayedTitle('')\n rafId = requestAnimationFrame(animateTitle)\n\n return () => {\n cancelled = true\n if (rafId !== null) cancelAnimationFrame(rafId)\n if (timeoutId !== null) clearTimeout(timeoutId)\n }\n }\n }, [title]) // eslint-disable-line react-hooks/exhaustive-deps\n\n return { displayedTitle, isTitleAnimating }\n}\n","import { useState, useEffect } from 'react'\n\nexport type ResolvedTheme = 'light' | 'dark' | 'midnight' | 'neumorphism'\n\nfunction getMediaQuery(): MediaQueryList | null {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return null\n return window.matchMedia('(prefers-color-scheme: dark)')\n}\n\nexport function useAutoTheme(theme: 'light' | 'dark' | 'midnight' | 'neumorphism' | 'auto' | undefined): ResolvedTheme {\n const [resolved, setResolved] = useState<ResolvedTheme>(() => {\n if (theme && theme !== 'auto') return theme\n return getMediaQuery()?.matches ? 'dark' : 'light'\n })\n\n useEffect(() => {\n if (theme && theme !== 'auto') {\n setResolved(theme)\n return\n }\n const mql = getMediaQuery()\n if (!mql) return\n const handler = (e: MediaQueryListEvent) => setResolved(e.matches ? 'dark' : 'light')\n setResolved(mql.matches ? 'dark' : 'light')\n mql.addEventListener('change', handler)\n return () => mql.removeEventListener('change', handler)\n }, [theme])\n\n return resolved\n}\n","/**\n * useChatOrchestration — consolidates orchestration logic\n * that was previously scattered across ChatWidget.tsx.\n *\n * Responsibilities:\n * - Wraps controller.sendMessage with reference enrichment + scroll prep\n * - Attention tracking (new messages → toast while viewer/immersive active)\n * - Immersive-send logic (auto-reference current file + send)\n */\n\nimport { useCallback, useEffect, useRef } from 'react'\nimport type { Round, HITLResponse, ResourceContent, ChatWidgetAdapter, FileReference, SelectedSkillRef, FileAttachment } from '../types'\nimport type { UseReferenceManagerReturn } from './useReferenceManager'\nimport type { UseFileUploadReturn } from './useFileUpload'\n\nexport interface UseChatOrchestrationOptions {\n controllerSendMessage: (message: string, agentId?: string, inlineRefs?: FileReference[], selectedSkills?: SelectedSkillRef[], overrideInstanceId?: number | null, clientId?: string, fileAttachments?: FileAttachment[], modelOverride?: import('../types').ModelOverride | null) => Promise<void>\n rounds: Round[]\n references: UseReferenceManagerReturn\n scrollPrep: {\n setPendingScrollInteractionId: (id: string) => void\n isUserAtBottomRef: React.MutableRefObject<boolean>\n }\n attention: {\n trackNewMessage: (agentName: string, preview?: string) => void\n }\n adapter: ChatWidgetAdapter\n currentSessionId: number | null\n viewerContent: ResourceContent | null\n onHITLSubmit?: (response: HITLResponse) => Promise<void>\n interactionDispatch: (event: import('../types').ChatWidgetInteractionEvent) => void\n fileUpload?: UseFileUploadReturn\n /**\n * 当前选中的任务话池 cid(v2 ``c_<22>``)。\n * sendMessage 在 caller 未显式传 ``clientId`` 时会回退到此值。\n * ChatWidget 维护一个 ref 同步该值。\n */\n defaultClientIdRef: React.MutableRefObject<string | null>\n}\n\nexport interface UseChatOrchestrationReturn {\n sendMessage: (message: string, agentId?: string, inlineRefs?: FileReference[], selectedSkills?: SelectedSkillRef[], overrideInstanceId?: number | null, clientId?: string, fileAttachments?: FileAttachment[], modelOverride?: import('../types').ModelOverride | null) => Promise<void>\n handleHITLSubmit: (response: HITLResponse) => Promise<void>\n handleImmersiveSend: (text: string) => void\n currentAgentIdRef: React.MutableRefObject<string>\n}\n\nexport function useChatOrchestration(options: UseChatOrchestrationOptions): UseChatOrchestrationReturn {\n const {\n controllerSendMessage,\n rounds,\n references,\n scrollPrep,\n attention,\n adapter,\n currentSessionId,\n viewerContent,\n onHITLSubmit,\n interactionDispatch,\n fileUpload,\n defaultClientIdRef,\n } = options\n\n const currentAgentIdRef = useRef<string>('agent-680')\n const fileUploadRef = useRef(fileUpload)\n fileUploadRef.current = fileUpload\n\n const sendMessage = useCallback(async (message: string, agentId: string = 'agent-680', _inlineRefs?: FileReference[], selectedSkills?: SelectedSkillRef[], overrideInstanceId?: number | null, clientId?: string, fileAttachments?: FileAttachment[], modelOverride?: import('../types').ModelOverride | null) => {\n const effectiveClientId = clientId ?? defaultClientIdRef.current ?? undefined\n currentAgentIdRef.current = agentId\n scrollPrep.setPendingScrollInteractionId('__pending__')\n scrollPrep.isUserAtBottomRef.current = true\n\n const enrichedMessage = references.enrichMessage(message)\n if (references.referencesRef.current.length > 0) references.clearReferences()\n\n const uploadedFiles = fileUploadRef.current?.readyFiles ?? []\n const allAttachments = [...uploadedFiles, ...(fileAttachments ?? [])]\n\n let finalMessage = enrichedMessage\n if (allAttachments.length > 0) {\n const attachmentLines = allAttachments.map(f =>\n `[附件: ${f.fileName} | resource_id: ${f.resourceId}${f.gitPath ? ` | path: ${f.gitPath}` : ''}]`\n )\n finalMessage = attachmentLines.join('\\n') + '\\n' + enrichedMessage\n }\n\n await controllerSendMessage(finalMessage, agentId, undefined, selectedSkills, overrideInstanceId, effectiveClientId, allAttachments.length > 0 ? allAttachments : undefined, modelOverride ?? null)\n\n if (uploadedFiles.length > 0) fileUploadRef.current?.clear()\n }, [controllerSendMessage, references, scrollPrep, defaultClientIdRef])\n\n // Attention tracking: notify when new messages arrive\n const prevMessageCountRef = useRef(0)\n useEffect(() => {\n const totalMessages = rounds.reduce((sum, r) => sum + r.messages.length, 0)\n if (totalMessages > prevMessageCountRef.current && prevMessageCountRef.current > 0) {\n const lastRound = rounds[rounds.length - 1]\n if (lastRound && lastRound.messages.length > 0) {\n const lastMsg = lastRound.messages[lastRound.messages.length - 1]\n attention.trackNewMessage(lastMsg.agentName, lastMsg.contentChunks[0]?.slice(0, 50))\n }\n }\n prevMessageCountRef.current = totalMessages\n }, [rounds, attention])\n\n const handleHITLSubmit = useCallback(async (response: HITLResponse) => {\n // JETP-003 ADR-006 v1.1.2 / WS2.6 — fallback-fill client_id for callers\n // that go through this orchestrator (the traditional HITL form path).\n // ActionBridge already fills client_id at construction time via\n // GenUIContext, so this fallback is for non-GenUI HIL surfaces (legacy\n // ask_human form, embedded clients, etc.). When defaultClientIdRef is\n // null during bootstrap we deliberately leave the field undefined so\n // jetagents Stage A grayscale telemetry can still fire and we don't\n // make up a client_id we don't have.\n const enriched: HITLResponse = response.client_id\n ? response\n : { ...response, ...(defaultClientIdRef.current ? { client_id: defaultClientIdRef.current } : {}) }\n interactionDispatch({ type: 'hitl-submit', target: enriched.await_command_uuid, metadata: { confirmed: enriched.confirmed }, timestamp: Date.now() })\n await adapter.submitHITLResponse(enriched)\n await onHITLSubmit?.(enriched)\n }, [adapter, onHITLSubmit, interactionDispatch, defaultClientIdRef])\n\n const handleImmersiveSend = useCallback((text: string) => {\n if (viewerContent && currentSessionId) {\n const alreadyRef = references.referencesRef.current.some(\n (r: FileReference) => r.resourceId === viewerContent.resource_id && !r.selection,\n )\n if (!alreadyRef) {\n references.addReference({\n resourceId: viewerContent.resource_id,\n sessionId: currentSessionId,\n fileName: viewerContent.file_name,\n mimeType: viewerContent.mime_type,\n })\n }\n }\n // sendMessage 在 session 被禁入 / cid bootstrap 失败时会 reject —— 这里是 fire-and-forget,\n // 没有 await/.catch 会变成 Unhandled Promise Rejection。错误已经被 ChatWidget 内部\n // 通过 onInteraction + SessionForbiddenBanner 通知,这里安全吞掉。\n void Promise.resolve(sendMessage(text, currentAgentIdRef.current)).catch(() => {})\n }, [viewerContent, currentSessionId, references, sendMessage])\n\n return {\n sendMessage,\n handleHITLSubmit,\n handleImmersiveSend,\n currentAgentIdRef,\n }\n}\n","import { useState, useCallback, useRef, useMemo } from 'react'\nimport type { ChatWidgetAdapter, UploadedFileInfo, FileAttachment } from '../types.js'\n\nexport interface UseFileUploadOptions {\n adapter: ChatWidgetAdapter\n sessionId?: number | null\n ensureSession?: () => Promise<number>\n pollIntervalMs?: number\n maxFileSize?: number\n onUploadSuccess?: () => void\n /**\n * JETP-058: ChatWidget 当前活跃的 v2 client_id(用户正在看的话池)。\n * 当 batch 第一次入队时被快照到 batch;后续 retry 复用同一 cid,\n * 让后端 _aggregate_turn 走 interaction_id 幂等键合并到同一 ARTIFACT_* 序列。\n * `null` 表示当前没有活跃话池(例如刚切到老 session 还未选择话池),\n * 此时 hook 会调 `ensureClientId()` 现场创建一个 v2 cid。\n */\n currentClientId?: string | null\n /**\n * JETP-058: 当 `currentClientId` 缺失时调用,返回一个新的 v2 client_id。\n * 通常来自 `useClientIdAllocator.createClient(sessionId, ...)`。\n * 若未提供且 `currentClientId` 也为 null,则上传立即失败(早失败 > 半成品入库)。\n */\n ensureClientId?: () => Promise<string>\n}\n\nexport interface UseFileUploadReturn {\n attachments: UploadedFileInfo[]\n readyFiles: FileAttachment[]\n isUploading: boolean\n addFiles: (files: File[]) => void\n removeFile: (resourceId: string) => void\n clear: () => void\n}\n\nconst DEFAULT_POLL_INTERVAL = 2000\nconst DEFAULT_MAX_FILE_SIZE = 500 * 1024 * 1024 // 500 MB\n\nlet _tempIdCounter = 0\nfunction nextTempId(): string {\n return `__temp_${++_tempIdCounter}_${Date.now()}`\n}\n\n/**\n * JETP-040: Shared hook managing the two-step file upload lifecycle.\n * 1. Upload files via adapter.uploadFiles() -> get resource IDs\n * 2. Poll adapter.getUploadStatus() until all files are 'ready' or 'error'\n */\nexport function useFileUpload(options: UseFileUploadOptions): UseFileUploadReturn {\n const { adapter, sessionId, ensureSession, pollIntervalMs = DEFAULT_POLL_INTERVAL, maxFileSize = DEFAULT_MAX_FILE_SIZE, onUploadSuccess, currentClientId, ensureClientId } = options\n const sessionIdRef = useRef(sessionId)\n sessionIdRef.current = sessionId\n const ensureSessionRef = useRef(ensureSession)\n ensureSessionRef.current = ensureSession\n const onUploadSuccessRef = useRef(onUploadSuccess)\n onUploadSuccessRef.current = onUploadSuccess\n const currentClientIdRef = useRef(currentClientId)\n currentClientIdRef.current = currentClientId\n const ensureClientIdRef = useRef(ensureClientId)\n ensureClientIdRef.current = ensureClientId\n const [attachments, setAttachments] = useState<UploadedFileInfo[]>([])\n const pollTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)\n const attachmentsRef = useRef<UploadedFileInfo[]>([])\n attachmentsRef.current = attachments\n\n const stopPolling = useCallback(() => {\n if (pollTimerRef.current) {\n clearInterval(pollTimerRef.current)\n pollTimerRef.current = null\n }\n }, [])\n\n const startPolling = useCallback(() => {\n if (pollTimerRef.current || !adapter.getUploadStatus) return\n\n pollTimerRef.current = setInterval(async () => {\n const current = attachmentsRef.current\n const processingIds = current\n .filter(a => a.status === 'processing' || a.status === 'uploading')\n .map(a => a.resourceId)\n .filter(id => !id.startsWith('__temp_'))\n\n if (processingIds.length === 0) {\n stopPolling()\n return\n }\n\n try {\n const result = await adapter.getUploadStatus!(processingIds)\n setAttachments(prev => prev.map(a => {\n const updated = result.data.files.find(f => f.resource_id === a.resourceId)\n if (!updated) return a\n const statusCode = updated.status\n let status: UploadedFileInfo['status'] = a.status\n if (statusCode === 1) status = 'processing'\n else if (statusCode === 2) status = 'ready'\n else if (statusCode < 0) status = 'error'\n return { ...a, status, progress: updated.progress ?? a.progress }\n }))\n } catch {\n // Polling failure is non-fatal; will retry next interval\n }\n }, pollIntervalMs)\n }, [adapter, pollIntervalMs, stopPolling])\n\n const addFiles = useCallback((files: File[]) => {\n if (!adapter.uploadFiles) return\n\n const validFiles = files.filter(f => f.size <= maxFileSize)\n if (validFiles.length === 0) return\n\n const placeholders: UploadedFileInfo[] = validFiles.map(f => ({\n resourceId: nextTempId(),\n fileName: f.name,\n localFile: f,\n status: 'uploading' as const,\n }))\n const tempIds = placeholders.map(p => p.resourceId)\n setAttachments(prev => [...prev, ...placeholders])\n\n // JETP-058: batch 入队即快照 cid(\"发起时取的 cid\"),后续 retry 都复用此 cid。\n // 这样 _aggregate_turn 的幂等键 (cid, interaction_id) 在 retry 时仍指向同一序列,\n // ARTIFACT_START/RESULT/END 自然合并、不会出现孤儿。\n let batchClientId: string | null = currentClientIdRef.current ?? null\n\n const doUpload = async () => {\n let resolvedSessionId = sessionIdRef.current ?? undefined\n if (resolvedSessionId == null && ensureSessionRef.current) {\n try {\n resolvedSessionId = await ensureSessionRef.current()\n } catch (err) {\n console.error('[useFileUpload] ensureSession failed, aborting upload:', err)\n setAttachments(prev => prev.map(a =>\n tempIds.includes(a.resourceId)\n ? { ...a, status: 'error' as const, error: 'Session creation failed' }\n : a\n ))\n return\n }\n }\n\n if (resolvedSessionId == null) {\n console.error('[useFileUpload] no sessionId available, aborting upload')\n setAttachments(prev => prev.map(a =>\n tempIds.includes(a.resourceId)\n ? { ...a, status: 'error' as const, error: 'No active session' }\n : a\n ))\n return\n }\n\n // JETP-058: 解析 cid(首跑时;retry 路径直接复用首跑的 batchClientId 不会再走这里)\n if (!batchClientId) {\n if (ensureClientIdRef.current) {\n try {\n batchClientId = await ensureClientIdRef.current()\n } catch (err) {\n console.error('[useFileUpload] ensureClientId failed, aborting upload:', err)\n setAttachments(prev => prev.map(a =>\n tempIds.includes(a.resourceId)\n ? { ...a, status: 'error' as const, error: 'Client allocation failed' }\n : a\n ))\n return\n }\n }\n if (!batchClientId) {\n console.error('[useFileUpload] no clientId available, aborting upload')\n setAttachments(prev => prev.map(a =>\n tempIds.includes(a.resourceId)\n ? { ...a, status: 'error' as const, error: 'No active client' }\n : a\n ))\n return\n }\n }\n\n console.log('[useFileUpload] calling adapter.uploadFiles, sessionId=', resolvedSessionId, 'clientId=', batchClientId, 'files=', validFiles.map(f => f.name))\n const result = await adapter.uploadFiles!(validFiles, resolvedSessionId, batchClientId)\n console.log('[useFileUpload] upload success:', result)\n\n const errorMap = new Map<string, string>()\n if (result.data?.errors) {\n for (const err of result.data.errors) {\n errorMap.set(err.original_filename, err.error ?? 'Upload rejected')\n }\n }\n\n setAttachments(prev => {\n const updated = [...prev]\n let tIdx = 0\n for (const fileResult of (result.data?.files ?? [])) {\n if (tIdx >= tempIds.length) break\n const idx = updated.findIndex(a => a.resourceId === tempIds[tIdx])\n if (idx !== -1) {\n const landed = !!fileResult.git_path\n updated[idx] = {\n resourceId: fileResult.resource_id,\n fileName: fileResult.original_filename,\n gitPath: fileResult.git_path,\n status: landed ? 'ready' : (fileResult.status === 2 ? 'ready' : 'processing'),\n }\n }\n tIdx++\n }\n // Mark remaining temp placeholders that were NOT matched by data.files\n for (let i = tIdx; i < tempIds.length; i++) {\n const idx = updated.findIndex(a => a.resourceId === tempIds[i])\n if (idx !== -1) {\n const fileName = updated[idx].fileName\n const errMsg = errorMap.get(fileName) ?? 'Upload failed'\n updated[idx] = { ...updated[idx], status: 'error', error: errMsg }\n }\n }\n return updated\n })\n startPolling()\n onUploadSuccessRef.current?.()\n }\n\n doUpload().catch((err) => {\n console.error('[useFileUpload] upload failed:', err)\n setAttachments(prev => prev.map(a =>\n tempIds.includes(a.resourceId)\n ? { ...a, status: 'error' as const, error: String(err?.message ?? 'Upload failed') }\n : a\n ))\n })\n }, [adapter, maxFileSize, startPolling])\n\n const removeFile = useCallback((resourceId: string) => {\n const att = attachmentsRef.current.find(a => a.resourceId === resourceId)\n setAttachments(prev => prev.filter(a => a.resourceId !== resourceId))\n\n if (att?.gitPath && adapter.deleteWorkspaceItems && sessionIdRef.current != null) {\n adapter.deleteWorkspaceItems(Number(sessionIdRef.current), [att.gitPath])\n .then(() => onUploadSuccessRef.current?.())\n .catch(e => console.error('[useFileUpload] workspace delete failed:', e))\n }\n }, [adapter])\n\n const clear = useCallback(() => {\n stopPolling()\n setAttachments([])\n }, [stopPolling])\n\n const readyFiles: FileAttachment[] = useMemo(() =>\n attachments\n .filter(a => a.status === 'ready')\n .map(a => ({ resourceId: a.resourceId, fileName: a.fileName, gitPath: a.gitPath })),\n [attachments],\n )\n\n const isUploading = attachments.some(a => a.status === 'uploading' || a.status === 'processing')\n\n return { attachments, readyFiles, isUploading, addFiles, removeFile, clear }\n}\n","import { useCallback, useState } from 'react'\nimport { randomUUID } from '../utils/randomUUID'\n\nexport interface ViewerTab {\n id: string\n resourceId: string\n fileName: string\n mimeType?: string\n isNew?: boolean\n isDirty?: boolean\n annotationCount?: number\n openedAt: number\n}\n\nexport interface UseViewerTabsReturn {\n tabs: ViewerTab[]\n activeTabId: string | null\n addTab: (tab: Omit<ViewerTab, 'id' | 'openedAt' | 'isNew'>) => string\n removeTab: (tabId: string) => void\n switchTab: (tabId: string) => void\n updateTab: (tabId: string, updates: Partial<ViewerTab>) => void\n getActiveTab: () => ViewerTab | null\n markSeen: (tabId: string) => void\n findByResourceId: (resourceId: string) => ViewerTab | undefined\n clearAll: () => void\n}\n\nexport function useViewerTabs(): UseViewerTabsReturn {\n const [tabs, setTabs] = useState<ViewerTab[]>([])\n const [activeTabId, setActiveTabId] = useState<string | null>(null)\n\n const addTab = useCallback(\n (tab: Omit<ViewerTab, 'id' | 'openedAt' | 'isNew'>) => {\n let resultId = ''\n setTabs((prev) => {\n const existing = prev.find((t) => t.resourceId === tab.resourceId)\n if (existing) {\n resultId = existing.id\n return prev\n }\n const id = randomUUID()\n resultId = id\n return [\n ...prev,\n { ...tab, id, openedAt: Date.now(), isNew: true },\n ]\n })\n return resultId\n },\n [],\n )\n\n const removeTab = useCallback((tabId: string) => {\n setTabs((prevTabs) => {\n const index = prevTabs.findIndex((t) => t.id === tabId)\n if (index === -1) return prevTabs\n\n const newTabs = prevTabs.filter((t) => t.id !== tabId)\n\n setActiveTabId((prevActive) => {\n if (prevActive !== tabId) return prevActive\n if (newTabs.length === 0) return null\n const nextRight = prevTabs[index + 1]\n const nextLeft = prevTabs[index - 1]\n return nextRight?.id ?? nextLeft?.id ?? null\n })\n\n return newTabs\n })\n }, [])\n\n const markSeen = useCallback((tabId: string) => {\n setTabs((prev) =>\n prev.map((t) => (t.id === tabId ? { ...t, isNew: false } : t)),\n )\n }, [])\n\n const switchTab = useCallback(\n (tabId: string) => {\n setActiveTabId(tabId)\n markSeen(tabId)\n },\n [markSeen],\n )\n\n const updateTab = useCallback(\n (tabId: string, updates: Partial<ViewerTab>) => {\n setTabs((prev) =>\n prev.map((t) => (t.id === tabId ? { ...t, ...updates } : t)),\n )\n },\n [],\n )\n\n const getActiveTab = useCallback(() => {\n if (activeTabId === null) return null\n return tabs.find((t) => t.id === activeTabId) ?? null\n }, [tabs, activeTabId])\n\n const findByResourceId = useCallback(\n (resourceId: string) =>\n tabs.find((t) => t.resourceId === resourceId),\n [tabs],\n )\n\n const clearAll = useCallback(() => {\n setTabs([])\n setActiveTabId(null)\n }, [])\n\n return {\n tabs,\n activeTabId,\n addTab,\n removeTab,\n switchTab,\n updateTab,\n getActiveTab,\n markSeen,\n findByResourceId,\n clearAll,\n }\n}\n","import { useEffect, useRef } from 'react'\nimport type { UseViewerTabsReturn } from './useViewerTabs.js'\n\nexport interface ArtifactRef {\n resourceId: string\n fileName: string\n mimeType?: string\n}\n\nexport interface UseAutoTabOptions {\n artifacts: ArtifactRef[]\n tabs: UseViewerTabsReturn\n enabled?: boolean\n autoOpenSplit?: () => void\n}\n\nexport function useAutoTab({\n artifacts,\n tabs,\n enabled = true,\n autoOpenSplit,\n}: UseAutoTabOptions): void {\n const prevIdsRef = useRef(new Set<string>())\n\n useEffect(() => {\n if (!enabled) return\n\n const prevIds = prevIdsRef.current\n const newArtifacts = artifacts.filter(a => !prevIds.has(a.resourceId))\n\n if (newArtifacts.length === 0) {\n prevIdsRef.current = new Set(artifacts.map(a => a.resourceId))\n return\n }\n\n const hadTabs = tabs.tabs.length > 0\n for (const artifact of newArtifacts) {\n tabs.addTab({\n resourceId: artifact.resourceId,\n fileName: artifact.fileName,\n mimeType: artifact.mimeType,\n })\n }\n\n if (!hadTabs && newArtifacts.length > 0) {\n autoOpenSplit?.()\n const first = tabs.tabs[0] ?? null\n if (first) tabs.switchTab(first.id)\n }\n\n prevIdsRef.current = new Set(artifacts.map(a => a.resourceId))\n }, [artifacts, enabled, tabs, autoOpenSplit])\n}\n","import { useState, useEffect, useCallback, useMemo, useRef } from 'react'\nimport type { ChatWidgetAdapter, DirectoryFileEntry } from '../types.js'\n\nfunction isInternalEntry(e: DirectoryFileEntry): boolean {\n const name = e.file_name\n if (name === '.gitkeep') return false\n if (!name || name[0] === '.' || name[0] === '_') return true\n const parts = (e.git_path ?? '').split('/')\n if (parts.some(p => p && p !== '.gitkeep' && (p[0] === '.' || p[0] === '_'))) return true\n if (parts.length > 0 && parts[0] === 'skills') return true\n return false\n}\n\nexport interface WorkspaceFile {\n resourceId: string\n fileName: string\n gitPath: string\n mimeType?: string\n downloadUrl?: string\n nodeType: string\n timestamp?: number\n}\n\nexport interface WorkspaceTreeNode {\n id: string\n name: string\n path: string\n type: 'file' | 'dir'\n children?: WorkspaceTreeNode[]\n file?: WorkspaceFile\n}\n\nexport interface UseWorkspaceFilesOptions {\n adapter: ChatWidgetAdapter\n sessionId: number | null\n pollIntervalMs?: number\n /** When this flips from false→true (WS reconnect), trigger an immediate refresh. */\n wsConnected?: boolean\n}\n\nexport interface UseWorkspaceFilesReturn {\n files: WorkspaceFile[]\n tree: WorkspaceTreeNode[]\n recentChanges: WorkspaceFile[]\n fileCount: number\n loading: boolean\n error: Error | null\n refresh: () => void\n}\n\nfunction buildTree(files: WorkspaceFile[]): WorkspaceTreeNode[] {\n const root: WorkspaceTreeNode[] = []\n const dirMap = new Map<string, WorkspaceTreeNode>()\n\n function ensureDir(segments: string[]): WorkspaceTreeNode[] {\n if (segments.length === 0) return root\n const path = segments.join('/')\n const existing = dirMap.get(path)\n if (existing) return existing.children!\n const parent = ensureDir(segments.slice(0, -1))\n const node: WorkspaceTreeNode = {\n id: `dir:${path}`,\n name: segments[segments.length - 1],\n path,\n type: 'dir',\n children: [],\n }\n parent.push(node)\n dirMap.set(path, node)\n return node.children!\n }\n\n for (const file of files) {\n const parts = file.gitPath\n ? file.gitPath.split('/').filter(Boolean)\n : [file.fileName]\n\n const fileName = parts.pop()!\n const parentChildren = ensureDir(parts)\n if (fileName === '.gitkeep') continue\n parentChildren.push({\n id: `file:${file.resourceId}`,\n name: fileName,\n path: file.gitPath || fileName,\n type: 'file',\n file,\n })\n }\n\n const sortNodes = (nodes: WorkspaceTreeNode[]) => {\n nodes.sort((a, b) => {\n if (a.type !== b.type) return a.type === 'dir' ? -1 : 1\n return a.name.localeCompare(b.name)\n })\n for (const n of nodes) {\n if (n.children) sortNodes(n.children)\n }\n }\n sortNodes(root)\n return root\n}\n\nfunction entryToFile(entry: DirectoryFileEntry): WorkspaceFile {\n return {\n resourceId: entry.resource_id,\n fileName: entry.file_name,\n gitPath: entry.git_path,\n downloadUrl: entry.download_url,\n nodeType: entry.node_type,\n }\n}\n\nexport function useWorkspaceFiles({\n adapter,\n sessionId,\n pollIntervalMs = 30_000,\n wsConnected,\n}: UseWorkspaceFilesOptions): UseWorkspaceFilesReturn {\n const [files, setFiles] = useState<WorkspaceFile[]>([])\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n const prevIdsRef = useRef(new Set<string>())\n const [recentIds, setRecentIds] = useState<Set<string>>(new Set())\n\n const fetchFiles = useCallback(async () => {\n if (sessionId == null || !adapter.listDirectoryFiles) return\n setLoading(true)\n try {\n const entries = await adapter.listDirectoryFiles(sessionId, '', {\n recursive: true,\n generateUrls: true,\n })\n const nt = (t: string) => (t ?? '').toLowerCase()\n const fileEntries = entries.filter(\n e => nt(e.node_type) !== 'directory' && nt(e.node_type) !== 'tree' && !isInternalEntry(e),\n )\n const mapped = fileEntries.map(entryToFile)\n setFiles(mapped)\n setError(null)\n\n const currentIds = new Set(mapped.map(f => f.resourceId))\n const newIds = new Set<string>()\n for (const id of currentIds) {\n if (!prevIdsRef.current.has(id)) newIds.add(id)\n }\n if (newIds.size > 0) {\n setRecentIds(prev => new Set([...prev, ...newIds]))\n setTimeout(() => {\n setRecentIds(prev => {\n const next = new Set(prev)\n for (const id of newIds) next.delete(id)\n return next\n })\n }, 5000)\n }\n prevIdsRef.current = currentIds\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setLoading(false)\n }\n }, [adapter, sessionId])\n\n useEffect(() => {\n fetchFiles()\n }, [fetchFiles])\n\n useEffect(() => {\n if (sessionId == null || pollIntervalMs <= 0) return\n const interval = setInterval(fetchFiles, pollIntervalMs)\n return () => clearInterval(interval)\n }, [fetchFiles, sessionId, pollIntervalMs])\n\n const prevWsConnectedRef = useRef(wsConnected)\n useEffect(() => {\n const prev = prevWsConnectedRef.current\n prevWsConnectedRef.current = wsConnected\n if (!prev && wsConnected) {\n fetchFiles()\n }\n }, [wsConnected, fetchFiles])\n\n const tree = useMemo(() => buildTree(files), [files])\n\n const recentChanges = useMemo(\n () => files.filter(f => recentIds.has(f.resourceId)),\n [files, recentIds],\n )\n\n return {\n files,\n tree,\n recentChanges,\n fileCount: files.length,\n loading,\n error,\n refresh: fetchFiles,\n }\n}\n","import { useCallback, useRef } from 'react'\n\nexport interface TreePersistState {\n expandedPaths: string[]\n scrollTop: number\n}\n\nconst STORAGE_PREFIX = 'cwrf010-tree-state-'\n\nexport function useTreePersist(sessionId: number | null) {\n const key = sessionId != null ? `${STORAGE_PREFIX}${sessionId}` : null\n const memoryRef = useRef<TreePersistState | null>(null)\n\n const load = useCallback((): TreePersistState | null => {\n if (!key) return null\n try {\n const raw = sessionStorage.getItem(key)\n if (raw) return JSON.parse(raw) as TreePersistState\n } catch { /* storage unavailable */ }\n return memoryRef.current\n }, [key])\n\n const save = useCallback((state: TreePersistState) => {\n memoryRef.current = state\n if (!key) return\n try {\n sessionStorage.setItem(key, JSON.stringify(state))\n } catch { /* quota exceeded */ }\n }, [key])\n\n return { load, save }\n}\n","import { useCallback, useMemo, useRef, useState } from 'react'\nimport type { Round } from '../types.js'\nimport {\n type AnnotationKind,\n type AnnotationAnchor,\n type AnnotationInteraction,\n type AnnotationMessage,\n isAnnotationMessage,\n extractResourceId,\n stripAnnotationMarker,\n buildAnnotationMarker,\n parseAnnotationKind,\n parseAnnotationAnchor,\n anchoredGroupKey,\n} from './annotationUtils.js'\nimport { InvalidClientIdError } from '../errors.js'\n\nconst V2_CID_RE = /^c_[A-Za-z0-9]{22}$/\n\nexport interface AnnotationAllocateOpts {\n /** 'file' for file-level, 'selection' for anchored. */\n kind: 'file' | 'selection'\n /** 资源 ID(必填,作为 context_preloads.source_uri / refId)。 */\n resourceId: string\n /** 选区 anchor(仅 selection 用,作为 context_preloads.rangeHash 的源数据)。 */\n anchor?: AnnotationAnchor\n /** 用于人类可读标题(如文件名 + 选区文本片段)。 */\n title?: string\n}\n\n/**\n * JETP-058 v2-only:批注/选区对话流的 v2 cid 分配器。\n * ChatWidget 注入闭包,内部组装 contextPreloads 后调 allocator.createClient。\n * 返回的 cid 必须是 v2 ``c_<22>``。\n */\nexport type AnnotationClientIdAllocator = (\n opts: AnnotationAllocateOpts,\n) => Promise<string>\n\nexport interface UseAnnotationsOptions {\n sendMessage: (message: string, agentId?: string, inlineRefs?: any[], selectedSkills?: any[], overrideInstanceId?: number | null, clientId?: string) => Promise<void>\n rounds: Round[]\n activeResourceId: string | null\n /**\n * JETP-058:分配 v2 cid。每个 (resourceId + anchor) 维度懒分配一次,缓存复用;\n * 失败时直接抛错(ChatWidget 通过 toast 暴露),不再静默 fallback `file:`/`sel:` 字面量。\n */\n allocateClientId: AnnotationClientIdAllocator\n}\n\nexport interface UseAnnotationsReturn {\n interactions: AnnotationInteraction[]\n activeInteractions: AnnotationInteraction[]\n fileLevelForResource: AnnotationInteraction | null\n anchoredForResource: AnnotationInteraction[]\n getMessages: (interactionId: string) => AnnotationMessage[]\n startFileLevelAnnotation: (resourceId: string, message: string) => Promise<void>\n startAnchoredAnnotation: (\n resourceId: string,\n anchor: AnnotationAnchor,\n message: string,\n ) => Promise<void>\n sendFollowUp: (interactionId: string, message: string) => Promise<void>\n isCreating: boolean\n}\n\nfunction extractAnnotationsFromRounds(rounds: Round[]): {\n interactions: AnnotationInteraction[]\n messagesByInteraction: Map<string, AnnotationMessage[]>\n} {\n const interactionMap = new Map<string, AnnotationInteraction>()\n const messagesByInteraction = new Map<string, AnnotationMessage[]>()\n\n for (const round of rounds) {\n const text = round.userMessage\n if (!text || !isAnnotationMessage(text)) continue\n\n const resourceId = extractResourceId(text)\n if (!resourceId) continue\n\n const kind = parseAnnotationKind(text)\n if (!kind) continue\n\n const anchor = kind === 'anchored' ? parseAnnotationAnchor(text) : undefined\n const ts = round.timestamp ? new Date(round.timestamp).getTime() : Date.now()\n\n const groupKey = kind === 'file-level'\n ? `fl:${resourceId}`\n : anchoredGroupKey(resourceId, anchor)\n\n let interaction = interactionMap.get(groupKey)\n if (!interaction) {\n // JETP-058 v2-only:clientId 必须由 BE 派生 v2 cid 写到 round.clientId 上;\n // 不再 fallback `file:${resourceId}` / `sel:${groupKey}` 字面量(v2-only 模式后端会拒)。\n // 历史数据已被 alembic 0026 改写到 v2 anchor cid,所以正常情况下 round.clientId 一定是 v2;\n // 极端情况下若仍为空(数据残缺),保持 undefined,由 sendFollowUp 时再走 allocator 现场分配。\n const clientId = round.clientId\n interaction = {\n id: groupKey,\n interactionIds: [],\n resourceId,\n kind,\n anchor,\n createdAt: ts,\n lastMessageAt: ts,\n preview: stripAnnotationMarker(text).slice(0, 80),\n clientId,\n }\n interactionMap.set(groupKey, interaction)\n messagesByInteraction.set(groupKey, [])\n }\n\n if (!interaction.interactionIds.includes(round.interactionId)) {\n interaction.interactionIds.push(round.interactionId)\n }\n\n const level0Msg = round.messages.find(m => m.level === 0 && m.agentInstanceId)\n if (level0Msg?.agentInstanceId) {\n interaction.agentInstanceId = level0Msg.agentInstanceId\n }\n\n const msgs = messagesByInteraction.get(groupKey)!\n msgs.push({\n role: 'user',\n text: stripAnnotationMarker(text),\n interactionId: round.interactionId,\n timestamp: ts,\n })\n\n for (const m of round.messages) {\n if (m.contentType === 'text' && m.contentChunks && m.contentChunks.length > 0) {\n msgs.push({\n role: 'assistant',\n text: m.contentChunks.join(''),\n interactionId: round.interactionId,\n timestamp: ts,\n })\n }\n }\n\n interaction.lastMessageAt = ts\n interaction.lastRoundCompleted = round.status === 'completed'\n }\n\n if (interactionMap.size > 0) {\n console.log('[Annotation] parsed', rounds.length, 'rounds →', interactionMap.size, 'interactions',\n [...interactionMap.entries()].map(([k, v]) =>\n `${k}: instanceId=${v.agentInstanceId ?? 'none'}, msgs=${messagesByInteraction.get(k)?.length ?? 0}`))\n }\n\n return {\n interactions: Array.from(interactionMap.values()),\n messagesByInteraction,\n }\n}\n\nexport function useAnnotations({\n sendMessage,\n rounds,\n activeResourceId,\n allocateClientId,\n}: UseAnnotationsOptions): UseAnnotationsReturn {\n const [isCreating, setIsCreating] = useState(false)\n\n const { interactions, messagesByInteraction } = useMemo(\n () => extractAnnotationsFromRounds(rounds),\n [rounds],\n )\n\n // JETP-058 v2-only:(groupKey) → v2 cid 的本地缓存。\n // 同一文件批注 / 同一选区的多轮 follow-up 复用同一个 cid,避免重复分配。\n // groupKey 与 extractAnnotationsFromRounds 内的派生规则一致:\n // file-level: `fl:${resourceId}` ;anchored: `anchoredGroupKey(resourceId, anchor)`。\n const annotationCidCacheRef = useRef<Map<string, string>>(new Map())\n // 单飞:同 groupKey 短时间内并发请求复用同一 Promise,避免后端创建多个空 client。\n const annotationCidInflightRef = useRef<Map<string, Promise<string>>>(new Map())\n\n const ensureAnnotationCid = useCallback(\n async (\n kind: 'file' | 'selection',\n resourceId: string,\n anchor: AnnotationAnchor | undefined,\n groupKey: string,\n title?: string,\n ): Promise<string> => {\n const cached = annotationCidCacheRef.current.get(groupKey)\n if (cached && V2_CID_RE.test(cached)) return cached\n const inflight = annotationCidInflightRef.current.get(groupKey)\n if (inflight) return inflight\n const job = (async () => {\n const cid = await allocateClientId({ kind, resourceId, anchor, title })\n if (!V2_CID_RE.test(cid)) {\n throw new InvalidClientIdError(\n `Annotation allocator returned non-v2 cid ${JSON.stringify(cid)}; expected ^c_[A-Za-z0-9]{22}$.`,\n 'legacy_format',\n null,\n )\n }\n annotationCidCacheRef.current.set(groupKey, cid)\n return cid\n })()\n annotationCidInflightRef.current.set(groupKey, job)\n job.finally(() => {\n annotationCidInflightRef.current.delete(groupKey)\n })\n return job\n },\n [allocateClientId],\n )\n\n const activeInteractions = useMemo(\n () =>\n activeResourceId\n ? interactions.filter(i => i.resourceId === activeResourceId)\n : [],\n [interactions, activeResourceId],\n )\n\n const fileLevelForResource = useMemo(\n () => activeInteractions.find(i => i.kind === 'file-level') ?? null,\n [activeInteractions],\n )\n\n const anchoredForResource = useMemo(\n () => activeInteractions.filter(i => i.kind === 'anchored'),\n [activeInteractions],\n )\n\n const getMessages = useCallback(\n (interactionId: string): AnnotationMessage[] =>\n messagesByInteraction.get(interactionId) ?? [],\n [messagesByInteraction],\n )\n\n const startFileLevelAnnotation = useCallback(\n async (resourceId: string, message: string) => {\n setIsCreating(true)\n try {\n const marker = buildAnnotationMarker('file-level', resourceId)\n const groupKey = `fl:${resourceId}`\n // JETP-058 v2-only:先分配 v2 cid,再 sendMessage;分配失败直接抛错。\n const cid = await ensureAnnotationCid('file', resourceId, undefined, groupKey)\n await sendMessage(`${marker} ${message}`, undefined, undefined, undefined, null, cid)\n } finally {\n setIsCreating(false)\n }\n },\n [sendMessage, ensureAnnotationCid],\n )\n\n const startAnchoredAnnotation = useCallback(\n async (resourceId: string, anchor: AnnotationAnchor, message: string) => {\n setIsCreating(true)\n try {\n const marker = buildAnnotationMarker('anchored', resourceId, anchor)\n const groupKey = anchoredGroupKey(resourceId, anchor)\n const title = anchor.text\n ? `选区: ${anchor.text.slice(0, 24)}${anchor.text.length > 24 ? '…' : ''}`\n : undefined\n const cid = await ensureAnnotationCid('selection', resourceId, anchor, groupKey, title)\n await sendMessage(`${marker} ${message}`, undefined, undefined, undefined, null, cid)\n } finally {\n setIsCreating(false)\n }\n },\n [sendMessage, ensureAnnotationCid],\n )\n\n const sendFollowUp = useCallback(\n async (interactionId: string, message: string) => {\n const interaction = interactions.find(i => i.id === interactionId)\n if (!interaction) return\n\n setIsCreating(true)\n try {\n const marker = interaction.kind === 'file-level'\n ? buildAnnotationMarker('file-level', interaction.resourceId)\n : buildAnnotationMarker('anchored', interaction.resourceId, interaction.anchor)\n const instanceId = interaction.agentInstanceId ?? null\n // JETP-058 v2-only:优先用 round 上已经写入的 v2 cid(alembic 0026 已改写历史),\n // 缺失时(极端残缺)通过 allocator 现场分配并缓存到本 hook。\n const groupKey = interaction.kind === 'file-level'\n ? `fl:${interaction.resourceId}`\n : interaction.id\n let cid: string\n if (interaction.clientId && V2_CID_RE.test(interaction.clientId)) {\n cid = interaction.clientId\n // 写回缓存让后续 follow-up 也能命中。\n annotationCidCacheRef.current.set(groupKey, cid)\n } else {\n cid = await ensureAnnotationCid(\n interaction.kind === 'file-level' ? 'file' : 'selection',\n interaction.resourceId,\n interaction.anchor,\n groupKey,\n )\n }\n await sendMessage(`${marker} ${message}`, undefined, undefined, undefined, instanceId, cid)\n } finally {\n setIsCreating(false)\n }\n },\n [sendMessage, interactions, ensureAnnotationCid],\n )\n\n return {\n interactions,\n activeInteractions,\n fileLevelForResource,\n anchoredForResource,\n getMessages,\n startFileLevelAnnotation,\n startAnchoredAnnotation,\n sendFollowUp,\n isCreating,\n }\n}\n","export type AnnotationKind = 'file-level' | 'anchored'\n\nexport interface AnnotationAnchor {\n text: string\n startLine?: number\n endLine?: number\n elementId?: string\n}\n\nexport interface AnnotationInteraction {\n id: string\n interactionIds: string[]\n resourceId: string\n kind: AnnotationKind\n anchor?: AnnotationAnchor\n createdAt: number\n lastMessageAt: number\n preview?: string\n lastRoundCompleted?: boolean\n agentInstanceId?: number\n /** JETP-045 P3-T01:Layer 1 子空间标识;旧名 channelId。 */\n clientId?: string\n}\n\nexport interface AnnotationMessage {\n role: 'user' | 'assistant'\n text: string\n interactionId: string\n timestamp?: number\n}\n\nconst ANNOTATION_KIND_RE = /\\[Annotation:(file-level|anchored):/\n\nconst FILE_LEVEL_MARKER_RE = /^\\[Annotation:file-level:\\s*([^\\]]+?)\\s*\\]/\n\nconst ANCHORED_WITH_LINES_RE =\n /^\\[Annotation:anchored:\\s*(.*):L(\\d+)-(\\d+)\\s+\"((?:[^\"\\\\]|\\\\.)*)\"\\]/\n\nconst ANCHORED_WITHOUT_LINES_RE =\n /^\\[Annotation:anchored:\\s*(.+)\\s+\"((?:[^\"\\\\]|\\\\.)*)\"\\]/\n\nexport function parseAnnotationKind(text: string): AnnotationKind | null {\n const m = text.match(/^\\[Annotation:(file-level|anchored):/)\n if (!m) return null\n return m[1] as AnnotationKind\n}\n\nexport function parseAnnotationAnchor(text: string): AnnotationAnchor | undefined {\n if (!text.startsWith('[Annotation:anchored:')) return undefined\n\n const withLines = text.match(ANCHORED_WITH_LINES_RE)\n if (withLines) {\n return {\n text: unescapeQuotes(withLines[4]),\n startLine: Number(withLines[2]),\n endLine: Number(withLines[3]),\n }\n }\n\n const withoutLines = text.match(ANCHORED_WITHOUT_LINES_RE)\n if (!withoutLines) return undefined\n\n return {\n text: unescapeQuotes(withoutLines[2]),\n }\n}\n\nexport function isAnnotationMessage(text: string): boolean {\n return ANNOTATION_KIND_RE.test(text)\n}\n\nexport function extractResourceId(text: string): string | null {\n const fl = text.match(FILE_LEVEL_MARKER_RE)\n if (fl) return fl[1].trim()\n\n const awl = text.match(ANCHORED_WITH_LINES_RE)\n if (awl) return awl[1].trim()\n\n const awol = text.match(ANCHORED_WITHOUT_LINES_RE)\n if (awol) return awol[1].trim()\n\n return null\n}\n\nexport function stripAnnotationMarker(text: string): string {\n const kind = parseAnnotationKind(text)\n if (!kind) return text\n\n if (kind === 'file-level') {\n const m = text.match(FILE_LEVEL_MARKER_RE)\n if (!m || m[0].length === 0) return text\n return text.slice(m[0].length).replace(/^\\s+/, '')\n }\n\n const withLines = text.match(ANCHORED_WITH_LINES_RE)\n if (withLines) {\n return text.slice(withLines[0].length).replace(/^\\s+/, '')\n }\n\n const withoutLines = text.match(ANCHORED_WITHOUT_LINES_RE)\n if (withoutLines) {\n return text.slice(withoutLines[0].length).replace(/^\\s+/, '')\n }\n\n return text\n}\n\nfunction escapeQuotes(s: string): string {\n return s.replace(/\"/g, '\\\\\"')\n}\n\nfunction unescapeQuotes(s: string): string {\n return s.replace(/\\\\\"/g, '\"')\n}\n\nfunction previewSlice(preview: string): string {\n return preview.slice(0, 20)\n}\n\n/**\n * Compute a stable grouping key for an anchored annotation.\n * Same resource + same line range (or same anchor text preview) → same key.\n */\nexport function anchoredGroupKey(\n resourceId: string,\n anchor?: AnnotationAnchor,\n): string {\n const start = anchor?.startLine\n const end = anchor?.endLine\n if (start != null && end != null) {\n return `an:${resourceId}:L${start}-${end}`\n }\n const preview = (anchor?.text ?? '').slice(0, 30)\n return `an:${resourceId}:${preview}`\n}\n\nexport function buildAnnotationMarker(\n kind: AnnotationKind,\n resourceId: string,\n anchor?: AnnotationAnchor,\n): string {\n if (kind === 'file-level') {\n return `[Annotation:file-level: ${resourceId}]`\n }\n\n const preview = escapeQuotes(previewSlice(anchor?.text ?? ''))\n\n const start = anchor?.startLine\n const end = anchor?.endLine\n if (start != null && end != null) {\n return `[Annotation:anchored: ${resourceId}:L${start}-${end} \"${preview}\"]`\n }\n\n return `[Annotation:anchored: ${resourceId} \"${preview}\"]`\n}\n","import React, { useMemo } from 'react'\nimport type { ChatWidgetAdapter } from '../types.js'\nimport { contentToSrc } from '../components/FileViewer/utils/contentUrl.js'\nimport { ResourceContext } from './ResourceContext.js'\nimport type { ResourceContextValue } from './ResourceContext.js'\n\ninterface ResourceProviderProps {\n adapter: ChatWidgetAdapter\n sessionId?: number\n children: React.ReactNode\n}\n\nexport const ResourceProvider: React.FC<ResourceProviderProps> = ({\n adapter,\n sessionId,\n children,\n}) => {\n const value = useMemo<ResourceContextValue>(() => ({\n sessionId,\n async resolveResource(resourceId: string) {\n if (!sessionId) throw new Error('ResourceProvider: no sessionId')\n const res = await adapter.getResourceContent(sessionId, resourceId)\n const url = contentToSrc(res)\n return {\n url: url.startsWith('data:') || url.startsWith('blob:') || url.startsWith('http') ? url : undefined,\n content: !res.is_binary ? res.content : undefined,\n contentUrl: res.content_url,\n mimeType: res.mime_type ?? undefined,\n fileName: res.file_name,\n isText: !res.is_binary,\n gitPath: res.git_path,\n }\n },\n resolvePreviewUrl: adapter.getPreviewUrl\n ? async (resourceId: string, format: 'html' | 'pdf') => {\n if (!sessionId) throw new Error('ResourceProvider: no sessionId')\n return adapter.getPreviewUrl!(sessionId, resourceId, format)\n }\n : undefined,\n listDirectoryFiles: adapter.listDirectoryFiles\n ? async (dirPrefix, options) => {\n if (!sessionId) throw new Error('ResourceProvider: no sessionId')\n return adapter.listDirectoryFiles!(sessionId, dirPrefix, options)\n }\n : undefined,\n }), [adapter, sessionId])\n\n return (\n <ResourceContext value={value}>\n {children}\n </ResourceContext>\n )\n}\n","/**\n * JETP-033: JsonRenderViewer — full-page dashboard in the SplitPanel FileViewer.\n *\n * Supports multiple jr-page specs with a tab bar for switching,\n * fullscreen mode, text-selection \"Ask\" (FloatingToolbar), and\n * a structured Spec Inspector for browsing complete {op} patches.\n */\n\nimport React, { useState, useCallback, useMemo, useRef, useEffect } from 'react'\nimport {\n Renderer,\n StateProvider,\n ActionProvider,\n VisibilityProvider,\n ValidationProvider,\n} from '@json-render/react'\nimport type { UIElement } from '@json-render/core'\nimport { useActionBridge } from './ActionBridge'\nimport { useGenUISpec } from './useGenUISpec'\nimport { useSelectionBridge } from '../ContextBridge/useSelectionBridge'\nimport FloatingToolbar from '../ContextBridge/FloatingToolbar'\nimport { setCwrfClipboardRef } from '../ContextBridge/useSmartPaste'\nimport { Icon } from '../Icon/Icon'\nimport { useChatWidgetI18n } from '../../i18n'\nimport type { ChatWidgetAdapter, FileReference } from '../../types.js'\nimport './JsonRenderViewer.css'\n// JETP-033 WS3.7.7 follow-up — share ``.jr-card-locked`` / ``.jr-card-lock-fieldset``\n// post-submit lock styles with JsonRenderCard. ``.jr-card-container``-scoped\n// rules in this file are inert here (viewer DOM doesn't use that class).\nimport './JsonRenderCard.css'\n// CWRF-013 Phase 1 PR-P1-#3 — Tailwind v4 + scoped-preflight source CSS.\n// Side-effect import so library bundles ship the `.ycw-shadcn` scope\n// definitions alongside the renderer. The wrapper <div className=\"ycw-shadcn\">\n// inside SinglePageRenderer anchors the scope; PRs P1-#4a / #4b / #4c\n// (shadcn 36 components) consume the utilities from inside the scope.\n// See docs/proposals/CWRF-013-a2ui-systematic-upgrade/01_dependency_upgrade/03_shadcn_integration.md §3.\nimport '../../styles/shadcn.css'\n\nclass RendererErrorBoundary extends React.Component<\n { children: React.ReactNode; specId: string },\n { error: Error | null }\n> {\n state = { error: null as Error | null }\n static getDerivedStateFromError(error: Error) { return { error } }\n componentDidCatch(err: Error) {\n console.error('[JETP-033] Renderer crashed for spec:', this.props.specId, err)\n }\n render() {\n if (this.state.error) {\n return (\n <div style={{ padding: 16, color: '#b91c1c', fontSize: 13 }}>\n <strong>Render error</strong>\n <pre style={{ whiteSpace: 'pre-wrap', marginTop: 8, fontSize: 12 }}>\n {this.state.error.message}\n </pre>\n </div>\n )\n }\n return this.props.children\n }\n}\n\n// ── Spec Inspector Panel ──\n\ninterface ParsedPatch {\n idx: number\n op: string\n path: string\n raw: string\n typeName?: string\n valid: boolean\n}\n\nconst SpecInspector: React.FC<{\n patches: ParsedPatch[]\n onAsk: (patchJson: string) => void\n onClose: () => void\n}> = ({ patches, onAsk, onClose }) => {\n const [expanded, setExpanded] = useState<number | null>(null)\n\n return (\n <div className=\"jr-inspector-panel\">\n <div className=\"jr-inspector-header\">\n <span className=\"jr-inspector-title\">Spec Inspector</span>\n <button className=\"jr-inspector-close\" onClick={onClose}>✕</button>\n </div>\n <div className=\"jr-inspector-list\">\n {patches.map(p => (\n <div key={p.idx} className={`jr-inspector-item ${expanded === p.idx ? 'expanded' : ''}`}>\n <div\n className=\"jr-inspector-item-header\"\n onClick={() => setExpanded(expanded === p.idx ? null : p.idx)}\n >\n <span className=\"jr-inspector-op\">{p.op}</span>\n <span className=\"jr-inspector-path\">{p.path}</span>\n {p.typeName && <span className=\"jr-inspector-type\">{p.typeName}</span>}\n <span className=\"jr-inspector-chevron\">{expanded === p.idx ? '▾' : '▸'}</span>\n </div>\n {expanded === p.idx && (\n <div className=\"jr-inspector-item-body\">\n <pre className=\"jr-inspector-json\">{formatPatchJson(p.raw)}</pre>\n <button\n className=\"jr-inspector-ask-btn\"\n onClick={() => onAsk(p.raw)}\n >\n <Icon name=\"chat\" aria-hidden={true} /> Ask\n </button>\n </div>\n )}\n </div>\n ))}\n </div>\n </div>\n )\n}\n\nfunction formatPatchJson(raw: string): string {\n try {\n return JSON.stringify(JSON.parse(raw), null, 2)\n } catch {\n return raw\n }\n}\n\nfunction parsePatchMeta(raw: string): { op: string; path: string; typeName?: string } {\n try {\n const obj = JSON.parse(raw) as { op?: string; path?: string; value?: { type?: string } }\n return {\n op: obj.op ?? '?',\n path: obj.path ?? '?',\n typeName: typeof obj.value === 'object' && obj.value?.type ? obj.value.type : undefined,\n }\n } catch {\n return { op: '?', path: raw.substring(0, 40) }\n }\n}\n\n// ── Page Entry ──\n\nexport interface GenUIPageEntry {\n specId: string\n patches: string[]\n loading?: boolean\n title?: string\n resourceId?: string\n}\n\nexport interface JsonRenderViewerProps {\n pages: GenUIPageEntry[]\n activeSpecId?: string\n onClose?: () => void\n onFullscreen?: () => void\n onReference?: (ref: FileReference) => void\n onSelectionAsk?: (ref: FileReference) => void\n onBeforeCopy?: (ref: FileReference) => void\n adapter: ChatWidgetAdapter\n sessionId: number | null\n /**\n * JETP-003 ADR-006 v1.1.2 / WS2.6 — current chat-widget client_id.\n * Forwarded into ActionBridge so HIL submissions from full-page dashboards\n * carry attribution to /api/human-response.\n */\n clientId?: string | null\n interactionId?: string\n agentWaiting?: boolean\n registry: unknown\n}\n\n// ── Single Page Renderer ──\n\nconst SinglePageRenderer: React.FC<{\n specId: string\n patches: string[]\n loading: boolean\n adapter: ChatWidgetAdapter\n sessionId: number | null\n clientId?: string | null\n interactionId?: string\n agentWaiting: boolean\n registry: unknown\n onTitleResolved?: (title: string) => void\n bodyRef: React.RefObject<HTMLDivElement | null>\n}> = ({\n specId, patches, loading, adapter, sessionId, clientId,\n interactionId, agentWaiting, registry, onTitleResolved, bodyRef,\n}) => {\n const { spec, store } = useGenUISpec(specId, patches, loading)\n\n const { handlers: actionHandlers, isLocked } = useActionBridge(specId, {\n adapter, sessionId, clientId, interactionId, agentWaiting,\n })\n\n const prevTitleRef = useRef<string>('')\n useEffect(() => {\n if (!spec?.root || !spec?.elements) return\n const rootEl = spec.elements[spec.root] as UIElement | undefined\n const title = (rootEl?.props as Record<string, unknown>)?.title as string ?? 'Dashboard'\n if (title !== prevTitleRef.current) {\n prevTitleRef.current = title\n onTitleResolved?.(title)\n }\n }, [spec, onTitleResolved])\n\n if (!spec?.root || !spec?.elements) {\n return (\n <div className=\"jr-viewer-loading\">\n <div className=\"jr-viewer-spinner\" />\n <span>Building dashboard...</span>\n </div>\n )\n }\n\n const stateProviderProps = store\n ? { store }\n : { initialState: spec.state ?? {} }\n\n // JETP-033 WS3.7.7 follow-up — same post-submit lock as JsonRenderCard.\n // Dashboard viewer can also host interactive specs (FormSection /\n // AppChrome topBar with submit / approve / reject actions — same JETP-083\n // WS3.7.7 fix that the deprecated DashboardLayout carried). Once locked,\n // wrap with ``<fieldset disabled>`` so the standalone share view (and\n // any embedded viewer) does not allow re-submission either.\n const renderedTree = (\n <Renderer\n spec={spec}\n registry={registry as never}\n loading={loading}\n />\n )\n\n return (\n <div\n className={`jr-viewer-page-body${isLocked ? ' jr-card-locked' : ''}`}\n ref={bodyRef}\n data-locked={isLocked || undefined}\n >\n <RendererErrorBoundary specId={specId}>\n <StateProvider {...stateProviderProps}>\n <VisibilityProvider>\n <ActionProvider handlers={actionHandlers}>\n {/*\n JETP-033 / CWRF-013 form-root-cause fix — see JsonRenderCard\n for the full rationale. shadcn input primitives call\n ``useValidation()`` which throws without a Provider, so we\n mount a default ValidationProvider here too. Mirrors the\n Card mount so any spec rendered through either surface\n (chat card or full-page viewer) gets a working validation\n context with zero authoring overhead.\n */}\n <ValidationProvider>\n {/*\n CWRF-013 Phase 1 PR-P1-#3 — `.ycw-shadcn` scope wrapper.\n Every renderer tree (incl. future shadcn 36 components from\n PRs P1-#4a / #4b / #4c) is rendered inside this wrapper so\n that the Tailwind v4 + scoped-preflight reset only affects\n descendants and never leaks to the host page. Existing 38\n BEM `.ycw-*` components keep working because their selectors\n are unaffected — `.ycw-shadcn` is a new sibling scope, not\n a replacement.\n */}\n <div className=\"ycw-shadcn\">\n {isLocked ? (\n <fieldset disabled className=\"jr-card-lock-fieldset\">\n {renderedTree}\n </fieldset>\n ) : (\n renderedTree\n )}\n </div>\n </ValidationProvider>\n </ActionProvider>\n </VisibilityProvider>\n </StateProvider>\n </RendererErrorBoundary>\n </div>\n )\n}\n\n// ── Main Viewer ──\n\nexport const JsonRenderViewer: React.FC<JsonRenderViewerProps> = ({\n pages,\n activeSpecId,\n onClose,\n onFullscreen,\n onReference,\n onSelectionAsk,\n onBeforeCopy,\n adapter,\n sessionId,\n clientId,\n interactionId,\n agentWaiting = false,\n registry,\n}) => {\n const [currentSpecId, setCurrentSpecId] = useState<string>(activeSpecId ?? pages[0]?.specId ?? '')\n const [fullscreen, setFullscreen] = useState(false)\n const [tabTitles, setTabTitles] = useState<Record<string, string>>({})\n const [inspectorOpen, setInspectorOpen] = useState(false)\n const [shareLoading, setShareLoading] = useState(false)\n const [shareResult, setShareResult] = useState<{ url: string; copied: boolean } | null>(null)\n const bodyRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (activeSpecId && activeSpecId !== currentSpecId) {\n setCurrentSpecId(activeSpecId)\n }\n }, [activeSpecId])\n\n const activePage = pages.find(p => p.specId === currentSpecId) ?? pages[pages.length - 1]\n\n // ── Selection bridge (same pattern as FileViewerPanel) ──\n const selectionContext = useMemo(() => {\n if (!activePage || !sessionId) return null\n return {\n resourceId: activePage.specId,\n sessionId,\n fileName: `${activePage.specId}.spec.jsonl`,\n specId: activePage.specId,\n }\n }, [activePage, sessionId])\n\n const {\n selection,\n buildReference: domBuildReference,\n clearSelection,\n } = useSelectionBridge({\n containerRef: bodyRef,\n resourceContext: selectionContext ?? { resourceId: '', sessionId: 0, fileName: '' },\n enabled: !!selectionContext,\n })\n\n const handleAsk = useCallback(() => {\n if (!onReference) return\n const ref = domBuildReference()\n onSelectionAsk?.(ref)\n onReference(ref)\n clearSelection()\n }, [onReference, onSelectionAsk, domBuildReference, clearSelection])\n\n const handleCopy = useCallback(() => {\n if (!selection) return\n const ref = domBuildReference()\n onBeforeCopy?.(ref)\n setCwrfClipboardRef(selection.text, ref)\n navigator.clipboard.writeText(selection.text).catch(() => {})\n }, [selection, domBuildReference, onBeforeCopy])\n\n // ── Spec Inspector: structured {op} patch browsing ──\n const parsedPatches = useMemo((): ParsedPatch[] => {\n if (!activePage) return []\n return activePage.patches.map((raw, idx) => {\n const meta = parsePatchMeta(raw)\n return { idx, ...meta, raw, valid: meta.op !== '?' }\n })\n }, [activePage])\n\n const handleInspectorAsk = useCallback((patchJson: string) => {\n if (!onReference || !sessionId || !activePage) return\n const ref: FileReference = {\n resourceId: activePage.specId,\n sessionId,\n fileName: `${activePage.specId}.spec.jsonl`,\n mimeType: 'application/json',\n specId: activePage.specId,\n selection: { text: patchJson },\n }\n onSelectionAsk?.(ref)\n onReference(ref)\n }, [onReference, onSelectionAsk, sessionId, activePage])\n\n const handleTitleResolved = useCallback((specId: string) => (title: string) => {\n setTabTitles(prev => {\n if (prev[specId] === title) return prev\n return { ...prev, [specId]: title }\n })\n }, [])\n\n const { t } = useChatWidgetI18n()\n\n const handleReferencePage = useCallback(() => {\n if (!onReference || !activePage || !sessionId) return\n onReference({\n resourceId: activePage.specId,\n sessionId,\n fileName: `${activePage.specId}.spec.jsonl`,\n mimeType: 'application/x-jr-page',\n specId: activePage.specId,\n })\n }, [onReference, activePage, sessionId])\n\n const toggleFullscreen = useCallback(() => {\n if (onFullscreen) {\n onFullscreen()\n } else {\n setFullscreen(f => !f)\n }\n }, [onFullscreen])\n\n if (!activePage) {\n return (\n <div className=\"jr-viewer-loading\">\n <span>No pages available</span>\n </div>\n )\n }\n\n const containerClass = `jr-viewer-container ${fullscreen ? 'jr-viewer-fullscreen' : ''}`\n\n const content = (\n <div className={containerClass} data-spec-id={activePage.specId}>\n <div className=\"jr-viewer-toolbar\">\n {pages.length > 1 ? (\n <div className=\"jr-viewer-tabs\">\n {pages.map((p, i) => (\n <button\n key={p.specId}\n className={`jr-viewer-tab ${p.specId === activePage.specId ? 'active' : ''}`}\n onClick={() => setCurrentSpecId(p.specId)}\n title={tabTitles[p.specId] ?? p.title ?? p.specId}\n >\n {tabTitles[p.specId] ?? p.title ?? `Page ${i + 1}`}\n </button>\n ))}\n </div>\n ) : (\n <span className=\"jr-viewer-title\">\n {tabTitles[activePage.specId] ?? activePage.title ?? 'Dashboard'}\n </span>\n )}\n <div className=\"jr-viewer-actions\">\n {activePage.resourceId && adapter?.shareArtifact && (\n <>\n <button\n className=\"jr-viewer-btn jr-viewer-btn-share\"\n onClick={async () => {\n if (shareLoading || !activePage.resourceId || !adapter.shareArtifact || sessionId == null) return\n setShareLoading(true)\n try {\n const result = await adapter.shareArtifact({\n artifactId: activePage.resourceId,\n sessionId: sessionId as number,\n title: tabTitles[activePage.specId] ?? activePage.title ?? 'Dashboard',\n artifactType: 'jr-page',\n })\n if (result) {\n const fullUrl = result.shareUrl.startsWith('http')\n ? result.shareUrl\n : `${window.location.origin}${result.shareUrl}`\n let copied = false\n try {\n await navigator.clipboard.writeText(fullUrl)\n copied = true\n } catch {\n try {\n const ta = document.createElement('textarea')\n ta.value = fullUrl\n ta.style.position = 'fixed'\n ta.style.opacity = '0'\n document.body.appendChild(ta)\n ta.select()\n copied = document.execCommand('copy')\n document.body.removeChild(ta)\n } catch { /* fallback also failed */ }\n }\n setShareResult({ url: fullUrl, copied })\n if (copied) {\n setTimeout(() => setShareResult(null), 3000)\n }\n }\n } finally {\n setShareLoading(false)\n }\n }}\n disabled={shareLoading}\n title=\"Share\"\n >\n {shareLoading\n ? <span className=\"jr-viewer-spinner-sm\" />\n : shareResult?.copied\n ? '✓ Copied'\n : <Icon name=\"share\" aria-hidden={true} />}\n </button>\n {shareResult && !shareResult.copied && (\n <div className=\"jr-viewer-share-fallback\">\n <input\n readOnly\n value={shareResult.url}\n onFocus={(e) => e.currentTarget.select()}\n onClick={(e) => e.currentTarget.select()}\n />\n <button onClick={() => {\n navigator.clipboard.writeText(shareResult.url)\n .then(() => { setShareResult({ url: shareResult.url, copied: true }); setTimeout(() => setShareResult(null), 3000) })\n .catch(() => {})\n }}>Copy</button>\n <button onClick={() => setShareResult(null)}>✕</button>\n </div>\n )}\n </>\n )}\n {onReference && (\n <button\n className=\"jr-viewer-btn jr-viewer-btn-ref\"\n onClick={handleReferencePage}\n title={t('viewer.referencePageTitle')}\n >\n <Icon name=\"paperclip\" aria-hidden={true} />\n {' '}\n {t('viewer.referencePage')}\n </button>\n )}\n <button\n className={`jr-viewer-btn ${inspectorOpen ? 'jr-viewer-btn-active' : ''}`}\n onClick={() => setInspectorOpen(v => !v)}\n title=\"Inspect spec patches\"\n >\n <Icon name=\"code\" aria-hidden={true} />\n </button>\n <button\n className=\"jr-viewer-btn\"\n onClick={toggleFullscreen}\n title={fullscreen ? 'Exit fullscreen' : 'Fullscreen'}\n >\n <Icon name={fullscreen ? 'arrowsIn' : 'arrowsOut'} size={16} aria-hidden />\n </button>\n {onClose && (\n <button className=\"jr-viewer-btn\" onClick={() => { if (fullscreen) setFullscreen(false); onClose() }}>\n Close\n </button>\n )}\n </div>\n </div>\n <div className=\"jr-viewer-body-row\">\n <div className=\"jr-viewer-content\">\n <SinglePageRenderer\n key={activePage.specId}\n specId={activePage.specId}\n patches={activePage.patches}\n loading={activePage.loading ?? false}\n adapter={adapter}\n sessionId={sessionId}\n clientId={clientId}\n interactionId={interactionId}\n agentWaiting={agentWaiting}\n registry={registry}\n onTitleResolved={handleTitleResolved(activePage.specId)}\n bodyRef={bodyRef}\n />\n {onReference && (\n <FloatingToolbar\n selection={selection}\n onAsk={handleAsk}\n onCopy={handleCopy}\n anchorRef={bodyRef}\n />\n )}\n </div>\n {inspectorOpen && (\n <SpecInspector\n patches={parsedPatches}\n onAsk={handleInspectorAsk}\n onClose={() => setInspectorOpen(false)}\n />\n )}\n </div>\n </div>\n )\n\n if (fullscreen && !onFullscreen) {\n return (\n <div className=\"jr-viewer-fullscreen-overlay\">\n {content}\n </div>\n )\n }\n\n return content\n}\n\nexport default JsonRenderViewer\n","import React, { useCallback, useEffect, useRef, useState } from 'react'\nimport type { PoolAgent, PoolAgentAction } from '../../types'\nimport type { ChatWidgetMessages } from '../../i18n'\nimport { Icon } from '../Icon/Icon'\nimport './PoolStatusPopover.css'\n\n// Deterministic palette — each agent gets a consistent color derived from its identity\nconst AVATAR_PALETTE = [\n { bg: '#EDE9FE', fg: '#7C3AED' }, // violet\n { bg: '#DBEAFE', fg: '#2563EB' }, // blue\n { bg: '#D1FAE5', fg: '#059669' }, // emerald\n { bg: '#FEF3C7', fg: '#D97706' }, // amber\n { bg: '#FCE7F3', fg: '#DB2777' }, // pink\n { bg: '#E0E7FF', fg: '#4338CA' }, // indigo\n { bg: '#CCFBF1', fg: '#0D9488' }, // teal\n { bg: '#FEE2E2', fg: '#DC2626' }, // red\n]\n\nfunction hashCode(s: string): number {\n let h = 0\n for (let i = 0; i < s.length; i++) {\n h = ((h << 5) - h + s.charCodeAt(i)) | 0\n }\n return Math.abs(h)\n}\n\nfunction agentColor(a: PoolAgent) {\n const seed = a.agent_alias || a.agent_id || String(a.agent_instance_id)\n return AVATAR_PALETTE[hashCode(seed) % AVATAR_PALETTE.length]\n}\n\nfunction agentInitial(a: PoolAgent): string {\n if (a.agent_alias) {\n const trimmed = a.agent_alias.trim()\n // CJK character → return first char\n if (/[\\u4e00-\\u9fff\\u3400-\\u4dbf]/.test(trimmed[0])) return trimmed[0]\n return trimmed[0].toUpperCase()\n }\n // \"agent-680\" → \"A\"\n if (a.agent_id) return a.agent_id[0].toUpperCase()\n return '#'\n}\n\nfunction agentDisplayName(a: PoolAgent): string {\n if (a.agent_alias) return a.agent_alias\n // \"agent-680\" + short instance suffix for disambiguation\n const idStr = String(a.agent_instance_id)\n const suffix = idStr.length > 4 ? idStr.slice(-4) : idStr\n return a.agent_id ? `${a.agent_id}·${suffix}` : `#${suffix}`\n}\n\n// JETP-083 WS3.7.7 follow-up: PAUSED sits between RUNNING and LOST so\n// pinned-on-human agents float to the top alongside actively running ones\n// (they are the ones the user needs to act on). LOST stays below to\n// preserve \"needs attention\" ordering; COMPLETED last.\nconst STATE_ORDER: Record<string, number> = { RUNNING: 0, PAUSED: 1, LOST: 2, COMPLETED: 3 }\n\nfunction stateSort(a: PoolAgent, b: PoolAgent): number {\n return (STATE_ORDER[a.state] ?? 4) - (STATE_ORDER[b.state] ?? 4)\n}\n\nfunction stateKey(state: string): 'running' | 'paused' | 'completed' | 'lost' | 'unknown' {\n switch (state) {\n case 'RUNNING': return 'running'\n // JETP-083 WS3.7.7 follow-up: backend emits state=\"PAUSED\" when the\n // agent is blocked in `_await_genui_blocking` (see runtime_monitor.py\n // agent_pool_status PAUSED projection). Without this case the agent\n // landed in the 'unknown' bucket and the popover showed 未知 / Unknown\n // — the live symptom reported on JETP-083 follow-up.\n case 'PAUSED': return 'paused'\n case 'COMPLETED': return 'completed'\n case 'LOST': return 'lost'\n default: return 'unknown'\n }\n}\n\nfunction isSuccessStatus(status: string): boolean {\n return status === 'completed' || status === 'success'\n}\n\nfunction actionStatusClass(status: string): string {\n if (status === 'running') return 'ycw-pool-action--running'\n if (isSuccessStatus(status)) return 'ycw-pool-action--completed'\n return 'ycw-pool-action--failed'\n}\n\nfunction actionStatusIcon(status: string): string {\n if (status === 'running') return '\\u25B6'\n if (isSuccessStatus(status)) return '\\u2713'\n return '\\u2717'\n}\n\nconst VISIBLE_ACTIONS_LIMIT = 5\n\n/** Pick actions to show: all running first, then most recent completed, capped. */\nfunction pickVisibleActions(actions: PoolAgentAction[]): PoolAgentAction[] {\n const running: PoolAgentAction[] = []\n const rest: PoolAgentAction[] = []\n for (const a of actions) {\n if (a.status === 'running') running.push(a)\n else rest.push(a)\n }\n const budget = VISIBLE_ACTIONS_LIMIT - running.length\n const tail = budget > 0 ? rest.slice(-budget) : []\n return [...running, ...tail]\n}\n\nexport interface PoolStatusPopoverProps {\n agents: PoolAgent[]\n sessionBusy: boolean\n connectionStatus: string\n i18n: ChatWidgetMessages\n}\n\nexport function PoolStatusPopover({ agents, sessionBusy, connectionStatus, i18n }: PoolStatusPopoverProps) {\n const [open, setOpen] = useState(false)\n const containerRef = useRef<HTMLDivElement>(null)\n\n const toggle = useCallback(() => setOpen(v => !v), [])\n\n useEffect(() => {\n if (!open) return\n const handler = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setOpen(false)\n }\n }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n }, [open])\n\n const running = agents.filter(a => a.state === 'RUNNING')\n // JETP-083 WS3.7.7 follow-up: surface paused-on-HIL agents at the badge\n // level so the user can tell \"X agents are waiting for me to click\"\n // from idle / running.\n const paused = agents.filter(a => a.state === 'PAUSED')\n const sorted = [...agents].sort(stateSort)\n\n const isError = connectionStatus === 'error'\n const isConnecting = connectionStatus === 'connecting'\n\n // Badge avatar stack prioritizes running agents (action in progress); if\n // there are no running but there are paused, stack the paused avatars so\n // the user sees who they need to respond to.\n const stackSource = running.length > 0 ? running : paused\n const showAvatarStack = stackSource.length > 0 && !isError && !isConnecting\n const previewAgents = showAvatarStack ? stackSource.slice(0, 3) : []\n const overflowCount = stackSource.length - previewAgents.length\n\n let badgeClass = 'ycw-pool-badge'\n let badgeText: string\n\n if (isError) {\n badgeClass += ' ycw-pool-badge--error'\n badgeText = i18n['status.error']\n } else if (isConnecting) {\n badgeClass += ' ycw-pool-badge--connecting'\n badgeText = i18n['status.connecting']\n } else if (running.length > 0) {\n badgeClass += ' ycw-pool-badge--active'\n badgeText = i18n['pool.collaborating'].replace('{{count}}', String(running.length))\n } else if (paused.length > 0) {\n // Distinct from running (no pulse, no \"working\" verb) and from idle\n // (the user is being asked to act). CSS may style ``--awaiting``\n // separately; absent custom CSS it falls back to the base badge look.\n badgeClass += ' ycw-pool-badge--awaiting'\n badgeText = i18n['pool.awaiting'].replace('{{count}}', String(paused.length))\n } else {\n badgeClass += ' ycw-pool-badge--idle'\n badgeText = i18n['pool.idle']\n }\n\n return (\n <div className=\"ycw-pool-status\" ref={containerRef}>\n <button\n className={badgeClass}\n onClick={toggle}\n aria-expanded={open}\n aria-haspopup=\"true\"\n title={badgeText}\n >\n {showAvatarStack ? (\n <span className=\"ycw-pool-badge__avatars\">\n {previewAgents.map((a, i) => {\n const color = agentColor(a)\n return (\n <span\n key={a.agent_instance_id}\n className=\"ycw-pool-badge__mini-avatar\"\n style={{\n backgroundColor: color.bg,\n color: color.fg,\n zIndex: previewAgents.length - i,\n }}\n >\n {agentInitial(a)}\n </span>\n )\n })}\n {overflowCount > 0 && (\n <span className=\"ycw-pool-badge__mini-avatar ycw-pool-badge__mini-overflow\">\n +{overflowCount}\n </span>\n )}\n </span>\n ) : (\n <Icon\n name={isError ? 'xCircle' : isConnecting ? 'hourglass' : 'usersThree'}\n size={16}\n aria-hidden\n />\n )}\n <span className=\"ycw-pool-badge__text\">{badgeText}</span>\n {running.length > 0 && !isError && !isConnecting && (\n <span className=\"ycw-pool-badge__pulse\" />\n )}\n </button>\n\n {open && (\n <div className=\"ycw-pool-popover\" role=\"dialog\" aria-label={i18n['pool.title']}>\n <div className=\"ycw-pool-popover__header\">\n <span className=\"ycw-pool-popover__title\">{i18n['pool.title']}</span>\n {agents.length > 0 && (\n <span className=\"ycw-pool-popover__count\">{agents.length}</span>\n )}\n </div>\n\n {sorted.length === 0 ? (\n <div className=\"ycw-pool-popover__empty\">{i18n['pool.empty']}</div>\n ) : (\n <ul className=\"ycw-pool-popover__list\">\n {sorted.map(a => {\n const sk = stateKey(a.state)\n const color = agentColor(a)\n const actions = pickVisibleActions(a.recent_actions ?? [])\n return (\n <li key={a.agent_instance_id} className={`ycw-pool-agent ycw-pool-agent--${sk}`}>\n <span\n className=\"ycw-pool-agent__avatar\"\n style={{ backgroundColor: color.bg, color: color.fg }}\n >\n {agentInitial(a)}\n <span className={`ycw-pool-agent__indicator ycw-pool-agent__indicator--${sk}`} />\n </span>\n <div className=\"ycw-pool-agent__detail\">\n <span className=\"ycw-pool-agent__info\">\n <span className=\"ycw-pool-agent__name\">{agentDisplayName(a)}</span>\n <span className={`ycw-pool-agent__state ycw-pool-agent__state--${sk}`}>\n {i18n[`pool.state.${sk}`]}\n </span>\n </span>\n {a.task_purpose && (\n <span className=\"ycw-pool-agent__purpose\" title={a.task_purpose}>\n {a.task_purpose}\n </span>\n )}\n {actions.length > 0 && (\n <ul className=\"ycw-pool-agent__actions\">\n {actions.map(act => (\n <li key={act.tool_call_id} className={`ycw-pool-action ${actionStatusClass(act.status)}`}>\n <span className=\"ycw-pool-action__icon\">{actionStatusIcon(act.status)}</span>\n <span className=\"ycw-pool-action__tool\">{act.tool}</span>\n {act.purpose && <span className=\"ycw-pool-action__purpose\">{act.purpose}</span>}\n </li>\n ))}\n </ul>\n )}\n </div>\n </li>\n )\n })}\n </ul>\n )}\n </div>\n )}\n </div>\n )\n}\n","import React, { useRef, useEffect, useCallback } from 'react'\nimport { Icon } from '../Icon/Icon'\nimport { useChatWidgetI18n } from '../../i18n'\nimport { useEscStack, ESC_PRIORITY } from '../../hooks/useEscStack.js'\nimport './ChatOverlay.css'\n\nexport interface ChatOverlayProps {\n children: React.ReactNode\n open: boolean\n onClose: () => void\n unreadCount?: number\n}\n\nconst ChatOverlay: React.FC<ChatOverlayProps> = ({\n children,\n open,\n onClose,\n unreadCount = 0,\n}) => {\n const { t } = useChatWidgetI18n()\n const sheetRef = useRef<HTMLDivElement>(null)\n const scrollTopRef = useRef(0)\n\n const escHandler = useCallback(() => {\n onClose()\n return true\n }, [onClose])\n\n useEscStack(escHandler, open, ESC_PRIORITY.OVERLAY)\n\n useEffect(() => {\n if (open && sheetRef.current) {\n sheetRef.current.scrollTop = scrollTopRef.current\n const firstFocusable = sheetRef.current.querySelector<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n )\n firstFocusable?.focus()\n }\n if (!open && sheetRef.current) {\n scrollTopRef.current = sheetRef.current.scrollTop\n }\n }, [open])\n\n if (!open) return null\n\n return (\n <div className=\"ycw-chat-overlay\" role=\"dialog\" aria-modal=\"true\" aria-label={t('split.home')}>\n <div className=\"ycw-chat-overlay-backdrop\" onClick={onClose} />\n <div className=\"ycw-chat-overlay-sheet\" ref={sheetRef}>\n <div className=\"ycw-chat-overlay-header\">\n <span className=\"ycw-chat-overlay-title\">{t('split.home')}</span>\n {unreadCount > 0 && (\n <span className=\"ycw-chat-overlay-badge\">{unreadCount}</span>\n )}\n <button\n className=\"ycw-chat-overlay-close\"\n onClick={onClose}\n aria-label={t('annotation.close')}\n >\n <Icon name=\"x\" size={18} aria-hidden />\n </button>\n </div>\n <div className=\"ycw-chat-overlay-body\">\n {children}\n </div>\n </div>\n </div>\n )\n}\n\nexport default ChatOverlay\n","import React, { useState, useCallback, useMemo, useRef, useEffect } from 'react'\nimport type { WorkspaceTreeNode, WorkspaceFile } from '../../hooks/useWorkspaceFiles.js'\nimport { Icon } from '../Icon/Icon'\nimport { fileTypeIcon } from '../../utils/fileTypeIcon.js'\nimport { fileTypeColor } from '../../utils/fileTypeColor.js'\nimport { useChatWidgetI18n } from '../../i18n'\nimport { useEscStack, ESC_PRIORITY } from '../../hooks/useEscStack.js'\nimport WorkspaceContextMenu from './WorkspaceContextMenu'\nimport type { CtxMenuAction } from './WorkspaceContextMenu'\nimport './WorkspacePanel.css'\n\nexport interface WorkspacePanelProps {\n open: boolean\n onClose: () => void\n tree: WorkspaceTreeNode[]\n recentChanges?: WorkspaceFile[]\n onSelectFile: (file: WorkspaceFile) => void\n highlightedIds?: Set<string>\n fileCount?: number\n initialExpandedPaths?: string[]\n onExpandStateChange?: (paths: string[]) => void\n onDownloadAll?: () => Promise<void>\n onUploadFiles?: (files: File[], targetDirectory?: string) => Promise<void>\n onCreateFolder?: (folderName: string, parentPath?: string) => Promise<void>\n onRename?: (oldPath: string, newName: string) => Promise<void>\n onDelete?: (paths: string[]) => Promise<void>\n onMove?: (sourcePaths: string[], targetDir: string) => Promise<void>\n onCopy?: (sourcePaths: string[], targetDir: string) => Promise<void>\n}\n\n// ── helper: collect all dir paths from the tree ──\n\nfunction collectDirPaths(nodes: WorkspaceTreeNode[], exclude?: string): string[] {\n const dirs: string[] = []\n for (const n of nodes) {\n if (n.type === 'dir') {\n if (n.path !== exclude) dirs.push(n.path)\n if (n.children) dirs.push(...collectDirPaths(n.children, exclude))\n }\n }\n return dirs\n}\n\n// ── TreeNode ──\n\ninterface TreeNodeProps {\n node: WorkspaceTreeNode\n expanded: Set<string>\n toggleExpand: (path: string) => void\n onSelect: (file: WorkspaceFile) => void\n highlighted: Set<string>\n depth: number\n searchQuery: string\n onUploadToDir?: (dirPath: string) => void\n onNewSubfolder?: (parentPath: string) => void\n newFolderParent: string | null\n newFolderName: string\n onNewFolderNameChange: (v: string) => void\n onNewFolderSubmit: () => void\n onNewFolderCancel: () => void\n newFolderInputRef: React.RefObject<HTMLInputElement | null>\n creatingFolder: boolean\n onContextMenu: (e: React.MouseEvent, node: WorkspaceTreeNode) => void\n renamingPath: string | null\n renameValue: string\n onRenameChange: (v: string) => void\n onRenameSubmit: () => void\n onRenameCancel: () => void\n renameInputRef: React.RefObject<HTMLInputElement | null>\n deletingPath: string | null\n onDeleteConfirm: () => void\n onDeleteCancel: () => void\n}\n\nconst TreeNode: React.FC<TreeNodeProps> = ({\n node, expanded, toggleExpand, onSelect, highlighted, depth, searchQuery,\n onUploadToDir, onNewSubfolder, newFolderParent, newFolderName,\n onNewFolderNameChange, onNewFolderSubmit, onNewFolderCancel,\n newFolderInputRef, creatingFolder,\n onContextMenu, renamingPath, renameValue, onRenameChange,\n onRenameSubmit, onRenameCancel, renameInputRef,\n deletingPath, onDeleteConfirm, onDeleteCancel,\n}) => {\n const isRenaming = renamingPath === node.path\n const isDeleting = deletingPath === node.path\n\n if (node.type === 'dir') {\n const isExpanded = expanded.has(node.path)\n\n if (isDeleting) {\n return (\n <div className=\"ycw-workspace-delete-bar\" style={{ marginLeft: `${12 + depth * 20}px` }}>\n <span>Delete \"{node.name}\"?</span>\n <button className=\"ycw-ws-del-confirm\" onClick={onDeleteConfirm}>Delete</button>\n <button className=\"ycw-ws-del-cancel\" onClick={onDeleteCancel}>Cancel</button>\n </div>\n )\n }\n\n return (\n <div role=\"treeitem\" aria-expanded={isExpanded} data-path={node.path}>\n <div className=\"ycw-workspace-tree-dir-row\">\n {isRenaming ? (\n <div className=\"ycw-workspace-rename-row\" style={{ paddingLeft: `${12 + depth * 20}px`, flex: 1 }}>\n <Icon name=\"folder\" size={16} aria-hidden />\n <input\n ref={renameInputRef}\n className=\"ycw-workspace-rename-input\"\n value={renameValue}\n onChange={e => onRenameChange(e.target.value)}\n onKeyDown={e => { if (e.key === 'Enter') onRenameSubmit(); if (e.key === 'Escape') onRenameCancel() }}\n />\n <button className=\"ycw-workspace-dir-action\" onClick={onRenameSubmit}><Icon name=\"check\" size={14} aria-hidden /></button>\n <button className=\"ycw-workspace-dir-action\" onClick={onRenameCancel}><Icon name=\"x\" size={14} aria-hidden /></button>\n </div>\n ) : (\n <>\n <button\n className=\"ycw-workspace-tree-node ycw-workspace-tree-dir\"\n style={{ paddingLeft: `${12 + depth * 20}px` }}\n onClick={() => toggleExpand(node.path)}\n onContextMenu={e => { e.preventDefault(); onContextMenu(e, node) }}\n >\n <Icon name={isExpanded ? 'caretDown' : 'caretRight'} size={12} aria-hidden />\n <Icon name={isExpanded ? 'folderOpen' : 'folder'} size={16} aria-hidden />\n <span className=\"ycw-workspace-node-name\">{node.name}</span>\n </button>\n <span className=\"ycw-workspace-dir-actions\">\n {onUploadToDir && (\n <button className=\"ycw-workspace-dir-action\" title=\"Upload here\" onClick={e => { e.stopPropagation(); onUploadToDir(node.path) }}>\n <Icon name=\"uploadSimple\" size={13} aria-hidden />\n </button>\n )}\n {onNewSubfolder && (\n <button className=\"ycw-workspace-dir-action\" title=\"New subfolder\" onClick={e => { e.stopPropagation(); onNewSubfolder(node.path) }}>\n <Icon name=\"folderPlus\" size={13} aria-hidden />\n </button>\n )}\n <button className=\"ycw-workspace-more-btn\" title=\"More\" onClick={e => { e.stopPropagation(); onContextMenu(e, node) }}>\n <Icon name=\"dotsThree\" size={14} aria-hidden />\n </button>\n </span>\n </>\n )}\n </div>\n {isExpanded && (\n <div role=\"group\">\n {newFolderParent === node.path && (\n <div className=\"ycw-workspace-new-folder-row\" style={{ paddingLeft: `${12 + (depth + 1) * 20}px` }}>\n <Icon name=\"folder\" size={16} aria-hidden />\n <input\n ref={newFolderInputRef}\n className=\"ycw-workspace-new-folder-input\"\n value={newFolderName}\n onChange={e => onNewFolderNameChange(e.target.value)}\n onKeyDown={e => { if (e.key === 'Enter') onNewFolderSubmit(); if (e.key === 'Escape') onNewFolderCancel() }}\n placeholder=\"Folder name\"\n disabled={creatingFolder}\n />\n <button className=\"ycw-workspace-dir-action\" onClick={onNewFolderSubmit} disabled={creatingFolder}>\n <Icon name={creatingFolder ? 'spinner' : 'check'} size={14} aria-hidden />\n </button>\n <button className=\"ycw-workspace-dir-action\" onClick={onNewFolderCancel}>\n <Icon name=\"x\" size={14} aria-hidden />\n </button>\n </div>\n )}\n {node.children?.map(child => (\n <TreeNode\n key={child.id}\n node={child}\n expanded={expanded}\n toggleExpand={toggleExpand}\n onSelect={onSelect}\n highlighted={highlighted}\n depth={depth + 1}\n searchQuery={searchQuery}\n onUploadToDir={onUploadToDir}\n onNewSubfolder={onNewSubfolder}\n newFolderParent={newFolderParent}\n newFolderName={newFolderName}\n onNewFolderNameChange={onNewFolderNameChange}\n onNewFolderSubmit={onNewFolderSubmit}\n onNewFolderCancel={onNewFolderCancel}\n newFolderInputRef={newFolderInputRef}\n creatingFolder={creatingFolder}\n onContextMenu={onContextMenu}\n renamingPath={renamingPath}\n renameValue={renameValue}\n onRenameChange={onRenameChange}\n onRenameSubmit={onRenameSubmit}\n onRenameCancel={onRenameCancel}\n renameInputRef={renameInputRef}\n deletingPath={deletingPath}\n onDeleteConfirm={onDeleteConfirm}\n onDeleteCancel={onDeleteCancel}\n />\n ))}\n </div>\n )}\n </div>\n )\n }\n\n // ── file node ──\n\n const file = node.file!\n const isHighlighted = highlighted.has(file.resourceId)\n const colorVar = fileTypeColor(file.fileName)\n const iconName = fileTypeIcon(file.fileName)\n\n if (searchQuery && !file.fileName.toLowerCase().includes(searchQuery)) {\n return null\n }\n\n if (isDeleting) {\n return (\n <div className=\"ycw-workspace-delete-bar\" style={{ marginLeft: `${12 + depth * 20}px` }}>\n <span>Delete \"{node.name}\"?</span>\n <button className=\"ycw-ws-del-confirm\" onClick={onDeleteConfirm}>Delete</button>\n <button className=\"ycw-ws-del-cancel\" onClick={onDeleteCancel}>Cancel</button>\n </div>\n )\n }\n\n if (isRenaming) {\n return (\n <div className=\"ycw-workspace-rename-row\" style={{ paddingLeft: `${12 + depth * 20}px` }}>\n <Icon name={iconName} size={16} aria-hidden />\n <input\n ref={renameInputRef}\n className=\"ycw-workspace-rename-input\"\n value={renameValue}\n onChange={e => onRenameChange(e.target.value)}\n onKeyDown={e => { if (e.key === 'Enter') onRenameSubmit(); if (e.key === 'Escape') onRenameCancel() }}\n />\n <button className=\"ycw-workspace-dir-action\" onClick={onRenameSubmit}><Icon name=\"check\" size={14} aria-hidden /></button>\n <button className=\"ycw-workspace-dir-action\" onClick={onRenameCancel}><Icon name=\"x\" size={14} aria-hidden /></button>\n </div>\n )\n }\n\n return (\n <div className=\"ycw-workspace-tree-file-row\">\n <button\n className={`ycw-workspace-tree-node ycw-workspace-tree-file${isHighlighted ? ' ycw-workspace-tree-node--new' : ''}`}\n style={{\n paddingLeft: `${12 + depth * 20}px`,\n borderLeftColor: `var(${colorVar}, transparent)`,\n flex: 1,\n minWidth: 0,\n }}\n onClick={() => onSelect(file)}\n onContextMenu={e => { e.preventDefault(); onContextMenu(e, node) }}\n role=\"treeitem\"\n data-resource-id={file.resourceId}\n draggable\n onDragStart={e => {\n e.dataTransfer.setData('application/x-ycw-file-ref', JSON.stringify({\n resourceId: file.resourceId,\n fileName: file.fileName,\n gitPath: file.gitPath,\n }))\n e.dataTransfer.effectAllowed = 'copy'\n }}\n >\n <span className=\"ycw-workspace-caret-spacer\" aria-hidden />\n <Icon name={iconName} size={16} aria-hidden />\n <span className=\"ycw-workspace-node-name\">{file.fileName}</span>\n </button>\n <button className=\"ycw-workspace-more-btn\" title=\"More\" onClick={e => { e.stopPropagation(); onContextMenu(e, node) }}>\n <Icon name=\"dotsThree\" size={14} aria-hidden />\n </button>\n </div>\n )\n}\n\n// ── Folder Picker (for move / copy) ──\n\nconst FolderPicker: React.FC<{\n dirs: string[]\n x: number\n y: number\n title: string\n onPick: (dir: string) => void\n onClose: () => void\n}> = ({ dirs, x, y, title, onPick, onClose }) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const handleClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) onClose()\n }\n document.addEventListener('mousedown', handleClick, true)\n return () => document.removeEventListener('mousedown', handleClick, true)\n }, [onClose])\n\n useEffect(() => {\n const el = ref.current\n if (!el) return\n const rect = el.getBoundingClientRect()\n if (rect.right > window.innerWidth) el.style.left = `${x - rect.width}px`\n if (rect.bottom > window.innerHeight) el.style.top = `${y - rect.height}px`\n }, [x, y])\n\n return (\n <div ref={ref} className=\"ycw-workspace-folder-picker\" style={{ left: x, top: y }} role=\"listbox\">\n <div className=\"ycw-workspace-folder-picker-title\">{title}</div>\n <button className=\"ycw-workspace-folder-pick-item\" onClick={() => onPick('')}>\n <Icon name=\"house\" size={14} aria-hidden /><span>/ (root)</span>\n </button>\n {dirs.map(d => (\n <button key={d} className=\"ycw-workspace-folder-pick-item\" onClick={() => onPick(d)}>\n <Icon name=\"folder\" size={14} aria-hidden /><span>{d}</span>\n </button>\n ))}\n </div>\n )\n}\n\n// ── Main Panel ──\n\nconst WorkspacePanel: React.FC<WorkspacePanelProps> = ({\n open,\n onClose,\n tree,\n recentChanges = [],\n onSelectFile,\n highlightedIds = new Set(),\n initialExpandedPaths = [],\n onExpandStateChange,\n onDownloadAll,\n onUploadFiles,\n onCreateFolder,\n onRename,\n onDelete,\n onMove,\n onCopy,\n}) => {\n const { t } = useChatWidgetI18n()\n const [searchQuery, setSearchQuery] = useState('')\n const [downloading, setDownloading] = useState(false)\n const [uploading, setUploading] = useState(false)\n const [isDragOver, setIsDragOver] = useState(false)\n const [expanded, setExpanded] = useState<Set<string>>(new Set(initialExpandedPaths))\n const [newFolderParent, setNewFolderParent] = useState<string | null>(null)\n const [newFolderName, setNewFolderName] = useState('')\n const [creatingFolder, setCreatingFolder] = useState(false)\n const searchRef = useRef<HTMLInputElement>(null)\n const scrollRef = useRef<HTMLDivElement>(null)\n const uploadInputRef = useRef<HTMLInputElement>(null)\n const newFolderInputRef = useRef<HTMLInputElement>(null)\n const renameInputRef = useRef<HTMLInputElement>(null)\n const dragCounterRef = useRef(0)\n const uploadTargetRef = useRef<string | undefined>(undefined)\n\n // context menu state\n const [ctxMenu, setCtxMenu] = useState<{ node: WorkspaceTreeNode; x: number; y: number } | null>(null)\n // inline rename state\n const [renamingPath, setRenamingPath] = useState<string | null>(null)\n const [renameValue, setRenameValue] = useState('')\n // inline delete state\n const [deletingPath, setDeletingPath] = useState<string | null>(null)\n // folder picker state (move / copy)\n const [folderPicker, setFolderPicker] = useState<{\n mode: 'move' | 'copy'; sourcePath: string; x: number; y: number\n } | null>(null)\n\n const hasFileOps = !!(onRename || onDelete || onMove || onCopy)\n\n const escHandler = useCallback(() => {\n if (ctxMenu) { setCtxMenu(null); return true }\n if (folderPicker) { setFolderPicker(null); return true }\n if (renamingPath) { setRenamingPath(null); return true }\n if (deletingPath) { setDeletingPath(null); return true }\n onClose()\n return true\n }, [onClose, ctxMenu, folderPicker, renamingPath, deletingPath])\n\n useEscStack(escHandler, open, ESC_PRIORITY.OVERLAY)\n\n useEffect(() => {\n if (open) requestAnimationFrame(() => searchRef.current?.focus())\n }, [open])\n\n const toggleExpand = useCallback((path: string) => {\n setExpanded(prev => {\n const next = new Set(prev)\n if (next.has(path)) next.delete(path)\n else next.add(path)\n onExpandStateChange?.([...next])\n return next\n })\n }, [onExpandStateChange])\n\n useEffect(() => {\n for (const file of recentChanges) {\n if (!file.gitPath) continue\n const parts = file.gitPath.split('/').filter(Boolean)\n parts.pop()\n let path = ''\n for (const part of parts) {\n path = path ? `${path}/${part}` : part\n setExpanded(prev => {\n if (prev.has(path)) return prev\n const next = new Set(prev)\n next.add(path)\n return next\n })\n }\n }\n }, [recentChanges])\n\n const lowerQuery = useMemo(() => searchQuery.toLowerCase(), [searchQuery])\n\n const handleSelect = useCallback((file: WorkspaceFile) => {\n onSelectFile(file)\n onClose()\n }, [onSelectFile, onClose])\n\n const handleDownloadAll = useCallback(async () => {\n if (!onDownloadAll || downloading) return\n setDownloading(true)\n try { await onDownloadAll() } finally { setDownloading(false) }\n }, [onDownloadAll, downloading])\n\n const handleUploadFiles = useCallback(async (files: File[], targetDir?: string) => {\n if (!onUploadFiles || uploading || files.length === 0) return\n setUploading(true)\n try { await onUploadFiles(files, targetDir) } finally { setUploading(false) }\n }, [onUploadFiles, uploading])\n\n const handleUploadInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(e.target.files ?? [])\n handleUploadFiles(files, uploadTargetRef.current)\n uploadTargetRef.current = undefined\n if (e.target) e.target.value = ''\n }, [handleUploadFiles])\n\n const startNewFolder = useCallback((parentPath?: string) => {\n setNewFolderParent(parentPath ?? '')\n setNewFolderName('')\n setTimeout(() => newFolderInputRef.current?.focus(), 50)\n }, [])\n\n const submitNewFolder = useCallback(async () => {\n const name = newFolderName.trim()\n if (!name || !onCreateFolder || creatingFolder) return\n setCreatingFolder(true)\n try {\n await onCreateFolder(name, newFolderParent || undefined)\n const newPath = newFolderParent ? `${newFolderParent}/${name}` : name\n setExpanded(prev => { const n = new Set(prev); n.add(newPath); return n })\n } finally {\n setCreatingFolder(false)\n setNewFolderParent(null)\n setNewFolderName('')\n }\n }, [newFolderName, newFolderParent, onCreateFolder, creatingFolder])\n\n const cancelNewFolder = useCallback(() => {\n setNewFolderParent(null)\n setNewFolderName('')\n }, [])\n\n // ── context menu handlers ──\n\n const handleCtxMenu = useCallback((e: React.MouseEvent, node: WorkspaceTreeNode) => {\n if (!hasFileOps) return\n e.preventDefault()\n setCtxMenu({ node, x: e.clientX, y: e.clientY })\n }, [hasFileOps])\n\n const handleCtxAction = useCallback((action: CtxMenuAction['id'], node: WorkspaceTreeNode) => {\n const pos = ctxMenu ? { x: ctxMenu.x, y: ctxMenu.y } : { x: 200, y: 200 }\n setCtxMenu(null)\n const path = node.path\n if (action === 'rename') {\n setRenamingPath(path)\n setRenameValue(node.name)\n setTimeout(() => renameInputRef.current?.focus(), 50)\n } else if (action === 'delete') {\n setDeletingPath(path)\n } else if (action === 'moveTo' || action === 'copyTo') {\n setFolderPicker({ mode: action === 'moveTo' ? 'move' : 'copy', sourcePath: path, ...pos })\n }\n }, [ctxMenu])\n\n const submitRename = useCallback(async () => {\n const name = renameValue.trim()\n if (!name || !renamingPath || !onRename) return\n try {\n await onRename(renamingPath, name)\n } catch (e) {\n console.error('[WorkspacePanel] rename failed:', e)\n } finally {\n setRenamingPath(null)\n setRenameValue('')\n }\n }, [renameValue, renamingPath, onRename])\n\n const cancelRename = useCallback(() => {\n setRenamingPath(null)\n setRenameValue('')\n }, [])\n\n const confirmDelete = useCallback(async () => {\n if (!deletingPath || !onDelete) return\n try {\n await onDelete([deletingPath])\n } catch (e) {\n console.error('[WorkspacePanel] delete failed:', e)\n } finally {\n setDeletingPath(null)\n }\n }, [deletingPath, onDelete])\n\n const cancelDelete = useCallback(() => setDeletingPath(null), [])\n\n const handleFolderPick = useCallback(async (targetDir: string) => {\n if (!folderPicker) return\n const { mode, sourcePath } = folderPicker\n try {\n if (mode === 'move' && onMove) await onMove([sourcePath], targetDir)\n else if (mode === 'copy' && onCopy) await onCopy([sourcePath], targetDir)\n } catch (e) {\n console.error(`[WorkspacePanel] ${mode} failed:`, e)\n }\n setFolderPicker(null)\n }, [folderPicker, onMove, onCopy])\n\n const allDirs = useMemo(() => collectDirPaths(tree, folderPicker?.sourcePath), [tree, folderPicker])\n\n // ── drag & drop ──\n\n const handleWorkspaceDragEnter = useCallback((e: React.DragEvent) => {\n if (!onUploadFiles) return\n e.preventDefault(); e.stopPropagation()\n dragCounterRef.current++\n if (e.dataTransfer.types.includes('Files')) setIsDragOver(true)\n }, [onUploadFiles])\n\n const handleWorkspaceDragOver = useCallback((e: React.DragEvent) => {\n if (!onUploadFiles) return\n e.preventDefault(); e.stopPropagation()\n e.dataTransfer.dropEffect = 'copy'\n }, [onUploadFiles])\n\n const handleWorkspaceDragLeave = useCallback((e: React.DragEvent) => {\n e.preventDefault(); e.stopPropagation()\n dragCounterRef.current--\n if (dragCounterRef.current <= 0) { dragCounterRef.current = 0; setIsDragOver(false) }\n }, [])\n\n const handleWorkspaceDrop = useCallback((e: React.DragEvent) => {\n e.preventDefault(); e.stopPropagation()\n dragCounterRef.current = 0; setIsDragOver(false)\n handleUploadFiles(Array.from(e.dataTransfer.files), undefined)\n }, [handleUploadFiles])\n\n if (!open) return null\n\n return (\n <div className=\"ycw-workspace-panel\">\n <div className=\"ycw-workspace-panel-backdrop\" onClick={onClose} />\n <div\n className={`ycw-workspace-panel-sheet${isDragOver ? ' ycw-workspace-panel-drag-over' : ''}`}\n onDragEnter={handleWorkspaceDragEnter}\n onDragOver={handleWorkspaceDragOver}\n onDragLeave={handleWorkspaceDragLeave}\n onDrop={handleWorkspaceDrop}\n >\n <div className=\"ycw-workspace-panel-header\">\n <span className=\"ycw-workspace-panel-title\">{t('workspace.title')}</span>\n <div className=\"ycw-workspace-panel-actions\">\n {onCreateFolder && (\n <button className=\"ycw-workspace-panel-action-btn\" onClick={() => startNewFolder()} disabled={creatingFolder} aria-label=\"New folder\" title=\"New folder\">\n <Icon name={creatingFolder ? 'spinner' : 'folderPlus'} size={16} aria-hidden />\n </button>\n )}\n {onUploadFiles && (\n <button className=\"ycw-workspace-panel-action-btn\" onClick={() => { uploadTargetRef.current = undefined; uploadInputRef.current?.click() }} disabled={uploading} aria-label=\"Upload files\" title=\"Upload files\">\n <Icon name={uploading ? 'spinner' : 'uploadSimple'} size={16} aria-hidden />\n </button>\n )}\n {onDownloadAll && tree.length > 0 && (\n <button className=\"ycw-workspace-panel-download\" onClick={handleDownloadAll} disabled={downloading} aria-label={t('workspace.downloadAll')} title={t('workspace.downloadAll')}>\n <Icon name={downloading ? 'spinner' : 'download'} size={16} aria-hidden />\n </button>\n )}\n <button className=\"ycw-workspace-panel-close\" onClick={onClose} aria-label={t('annotation.close')}>\n <Icon name=\"x\" size={18} aria-hidden />\n </button>\n </div>\n </div>\n\n <div className=\"ycw-workspace-search\">\n <Icon name=\"magnifyingGlass\" size={14} aria-hidden />\n <input\n ref={searchRef}\n className=\"ycw-workspace-search-input\"\n type=\"text\"\n value={searchQuery}\n onChange={e => setSearchQuery(e.target.value)}\n placeholder={t('workspace.searchPlaceholder')}\n autoComplete=\"off\"\n />\n </div>\n\n <div className=\"ycw-workspace-tree\" ref={scrollRef} role=\"tree\" aria-label={t('workspace.title')}>\n {newFolderParent === '' && (\n <div className=\"ycw-workspace-new-folder-row\" style={{ paddingLeft: '12px' }}>\n <Icon name=\"folder\" size={16} aria-hidden />\n <input\n ref={newFolderInputRef}\n className=\"ycw-workspace-new-folder-input\"\n value={newFolderName}\n onChange={e => setNewFolderName(e.target.value)}\n onKeyDown={e => { if (e.key === 'Enter') submitNewFolder(); if (e.key === 'Escape') cancelNewFolder() }}\n placeholder=\"Folder name\"\n disabled={creatingFolder}\n />\n <button className=\"ycw-workspace-dir-action\" onClick={submitNewFolder} disabled={creatingFolder}>\n <Icon name={creatingFolder ? 'spinner' : 'check'} size={14} aria-hidden />\n </button>\n <button className=\"ycw-workspace-dir-action\" onClick={cancelNewFolder}>\n <Icon name=\"x\" size={14} aria-hidden />\n </button>\n </div>\n )}\n {tree.length === 0 && newFolderParent !== '' ? (\n <div className=\"ycw-workspace-empty\">{t('workspace.empty')}</div>\n ) : (\n tree.map(node => (\n <TreeNode\n key={node.id}\n node={node}\n expanded={expanded}\n toggleExpand={toggleExpand}\n onSelect={handleSelect}\n highlighted={highlightedIds}\n depth={0}\n searchQuery={lowerQuery}\n onUploadToDir={onUploadFiles ? (dirPath) => { uploadTargetRef.current = dirPath; uploadInputRef.current?.click() } : undefined}\n onNewSubfolder={onCreateFolder ? (parentPath) => startNewFolder(parentPath) : undefined}\n newFolderParent={newFolderParent}\n newFolderName={newFolderName}\n onNewFolderNameChange={setNewFolderName}\n onNewFolderSubmit={submitNewFolder}\n onNewFolderCancel={cancelNewFolder}\n newFolderInputRef={newFolderInputRef}\n creatingFolder={creatingFolder}\n onContextMenu={handleCtxMenu}\n renamingPath={renamingPath}\n renameValue={renameValue}\n onRenameChange={setRenameValue}\n onRenameSubmit={submitRename}\n onRenameCancel={cancelRename}\n renameInputRef={renameInputRef}\n deletingPath={deletingPath}\n onDeleteConfirm={confirmDelete}\n onDeleteCancel={cancelDelete}\n />\n ))\n )}\n </div>\n\n {uploading && (\n <div className=\"ycw-workspace-upload-status\">\n <Icon name=\"spinner\" size={14} className=\"ycw-workspace-upload-spin\" aria-hidden />\n <span>Uploading...</span>\n </div>\n )}\n {onUploadFiles && (\n <input ref={uploadInputRef} type=\"file\" multiple className=\"ycw-workspace-upload-input\" onChange={handleUploadInputChange} tabIndex={-1} />\n )}\n {isDragOver && (\n <div className=\"ycw-workspace-drop-overlay\">\n <div className=\"ycw-workspace-drop-content\">\n <Icon name=\"uploadSimple\" size={36} weight=\"light\" className=\"ycw-workspace-drop-icon\" aria-hidden />\n <span className=\"ycw-workspace-drop-text\">Drop files to upload</span>\n </div>\n </div>\n )}\n </div>\n\n {ctxMenu && (\n <WorkspaceContextMenu\n node={ctxMenu.node}\n x={ctxMenu.x}\n y={ctxMenu.y}\n onAction={handleCtxAction}\n onClose={() => setCtxMenu(null)}\n />\n )}\n\n {folderPicker && (\n <FolderPicker\n dirs={allDirs}\n x={folderPicker.x || 200}\n y={folderPicker.y || 200}\n title={folderPicker.mode === 'move' ? 'Move to' : 'Copy to'}\n onPick={handleFolderPick}\n onClose={() => setFolderPicker(null)}\n />\n )}\n </div>\n )\n}\n\nexport default WorkspacePanel\n","import React, { useEffect, useRef, useCallback } from 'react'\nimport { Icon } from '../Icon/Icon'\nimport type { WorkspaceTreeNode } from '../../hooks/useWorkspaceFiles.js'\n\nexport interface CtxMenuAction {\n id: 'rename' | 'delete' | 'moveTo' | 'copyTo'\n label: string\n icon: 'pencilSimple' | 'x' | 'arrowRight' | 'copy'\n}\n\nconst FILE_ACTIONS: CtxMenuAction[] = [\n { id: 'rename', label: 'Rename', icon: 'pencilSimple' },\n { id: 'moveTo', label: 'Move to…', icon: 'arrowRight' },\n { id: 'copyTo', label: 'Copy to…', icon: 'copy' },\n { id: 'delete', label: 'Delete', icon: 'x' },\n]\n\nconst DIR_ACTIONS: CtxMenuAction[] = [\n { id: 'rename', label: 'Rename', icon: 'pencilSimple' },\n { id: 'moveTo', label: 'Move to…', icon: 'arrowRight' },\n { id: 'copyTo', label: 'Copy to…', icon: 'copy' },\n { id: 'delete', label: 'Delete', icon: 'x' },\n]\n\nexport interface WorkspaceContextMenuProps {\n node: WorkspaceTreeNode\n x: number\n y: number\n onAction: (action: CtxMenuAction['id'], node: WorkspaceTreeNode) => void\n onClose: () => void\n}\n\nconst WorkspaceContextMenu: React.FC<WorkspaceContextMenuProps> = ({ node, x, y, onAction, onClose }) => {\n const ref = useRef<HTMLDivElement>(null)\n\n const handleClickOutside = useCallback((e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) onClose()\n }, [onClose])\n\n useEffect(() => {\n document.addEventListener('mousedown', handleClickOutside, true)\n const handleKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() }\n document.addEventListener('keydown', handleKey)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside, true)\n document.removeEventListener('keydown', handleKey)\n }\n }, [handleClickOutside, onClose])\n\n useEffect(() => {\n const el = ref.current\n if (!el) return\n const rect = el.getBoundingClientRect()\n const vw = window.innerWidth\n const vh = window.innerHeight\n if (rect.right > vw) el.style.left = `${x - rect.width}px`\n if (rect.bottom > vh) el.style.top = `${y - rect.height}px`\n }, [x, y])\n\n const actions = node.type === 'dir' ? DIR_ACTIONS : FILE_ACTIONS\n\n return (\n <div\n ref={ref}\n className=\"ycw-workspace-ctx-menu\"\n style={{ left: x, top: y }}\n role=\"menu\"\n >\n {actions.map(a => (\n <button\n key={a.id}\n className={`ycw-workspace-ctx-item${a.id === 'delete' ? ' ycw-workspace-ctx-item--danger' : ''}`}\n role=\"menuitem\"\n onClick={() => { onAction(a.id, node); onClose() }}\n >\n <Icon name={a.icon} size={14} aria-hidden />\n <span>{a.label}</span>\n </button>\n ))}\n </div>\n )\n}\n\nexport default WorkspaceContextMenu\n","import React, { useState, useCallback, useEffect } from 'react'\nimport type { DiscussionFile } from '../../hooks/useDiscussions.js'\nimport type { ChatWidgetAdapter, PoolAgent } from '../../types.js'\nimport DiscussionViewer from './DiscussionViewer.js'\nimport { Icon } from '../Icon/Icon'\nimport { useChatWidgetI18n } from '../../i18n'\nimport { useEscStack, ESC_PRIORITY } from '../../hooks/useEscStack.js'\nimport './DiscussionPanel.css'\n\nexport interface DiscussionPanelProps {\n open: boolean\n onClose: () => void\n discussions: DiscussionFile[]\n newDiscussionIds?: Set<string>\n currentUserAlias?: string\n sessionId?: number\n adapter?: ChatWidgetAdapter\n poolAgents?: PoolAgent[]\n onRefresh?: () => void\n onPostMessage?: (\n discussionPath: string,\n body: string,\n messageType: string,\n mentions: string[],\n ) => Promise<import('../../types.js').PostDiscussionMessageResponse>\n}\n\nconst STATUS_ICON: Record<string, string> = {\n active: '🟢',\n converging: '🟡',\n resolved: '✅',\n archived: '📦',\n}\n\nconst STATUS_LABEL: Record<string, string> = {\n active: '进行中',\n converging: '收敛中',\n resolved: '已结论',\n archived: '已归档',\n}\n\nfunction formatDate(iso: string): string {\n try {\n return new Date(iso).toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' })\n } catch { return iso }\n}\n\nfunction lastMessagePreview(disc: DiscussionFile): string {\n if (disc.messages.length === 0) return '暂无消息'\n const last = disc.messages[disc.messages.length - 1]\n const prefix = last.speaker === 'user' ? '用户' : last.speaker\n const text = last.title ?? last.body.slice(0, 60)\n return `${prefix}: ${text}`\n}\n\nconst DiscussionCard: React.FC<{\n disc: DiscussionFile\n isNew: boolean\n onClick: () => void\n}> = ({ disc, isNew, onClick }) => (\n <button\n className={`ycw-disc-card ${isNew ? 'ycw-disc-card--new' : ''} ${disc.pendingReceiptCount > 0 ? 'ycw-disc-card--pending' : ''}`}\n onClick={onClick}\n >\n <div className=\"ycw-disc-card-top\">\n <span className=\"ycw-disc-card-status\">{STATUS_ICON[disc.meta.status] ?? '⬜'}</span>\n <span className=\"ycw-disc-card-topic\">{disc.meta.topic || disc.fileName}</span>\n <span className=\"ycw-disc-card-date\">{formatDate(disc.meta.created)}</span>\n </div>\n <div className=\"ycw-disc-card-preview\">{lastMessagePreview(disc)}</div>\n <div className=\"ycw-disc-card-footer\">\n <span className=\"ycw-disc-card-participants\">\n {disc.meta.participants.slice(0, 3).join(', ')}\n {disc.meta.participants.length > 3 && ` +${disc.meta.participants.length - 3}`}\n </span>\n <span className=\"ycw-disc-card-count\">\n {disc.messageCount} 条\n {disc.pendingReceiptCount > 0 && (\n <span className=\"ycw-disc-card-pending\">{disc.pendingReceiptCount} 待确认</span>\n )}\n </span>\n </div>\n </button>\n)\n\nconst DiscussionPanel: React.FC<DiscussionPanelProps> = ({\n open,\n onClose,\n discussions,\n newDiscussionIds = new Set(),\n currentUserAlias,\n sessionId,\n adapter,\n poolAgents,\n onRefresh,\n onPostMessage,\n}) => {\n const { t } = useChatWidgetI18n()\n const [selectedDisc, setSelectedDisc] = useState<DiscussionFile | null>(null)\n\n useEffect(() => {\n if (!selectedDisc) return\n const updated = discussions.find(d => d.gitPath === selectedDisc.gitPath)\n if (updated && updated !== selectedDisc) {\n setSelectedDisc(updated)\n } else if (!updated) {\n setSelectedDisc(null)\n }\n }, [discussions, selectedDisc])\n\n const escHandler = useCallback(() => {\n if (selectedDisc) {\n setSelectedDisc(null)\n return true\n }\n onClose()\n return true\n }, [onClose, selectedDisc])\n\n useEscStack(escHandler, open, ESC_PRIORITY.OVERLAY)\n\n const handleCardClick = useCallback((disc: DiscussionFile) => {\n setSelectedDisc(disc)\n }, [])\n\n const handleViewerClose = useCallback(() => {\n setSelectedDisc(null)\n }, [])\n\n if (!open) return null\n\n const active = discussions.filter(d => d.meta.status === 'active' || d.meta.status === 'converging')\n const resolved = discussions.filter(d => d.meta.status !== 'active' && d.meta.status !== 'converging')\n\n return (\n <div className=\"ycw-disc-panel\">\n <div className=\"ycw-disc-panel-backdrop\" onClick={onClose} />\n <div className=\"ycw-disc-panel-sheet\">\n {selectedDisc ? (\n <DiscussionViewer\n discussion={selectedDisc}\n currentUserAlias={currentUserAlias}\n sessionId={sessionId}\n adapter={adapter}\n poolAgents={poolAgents}\n onClose={handleViewerClose}\n onRefresh={onRefresh}\n onPostMessage={onPostMessage}\n />\n ) : (\n <>\n <div className=\"ycw-disc-panel-header\">\n <span className=\"ycw-disc-panel-title\">\n {t('discussion.title' as any) || '讨论'}\n </span>\n <button className=\"ycw-disc-panel-close\" onClick={onClose} aria-label={t('annotation.close')}>\n <Icon name=\"x\" size={18} aria-hidden />\n </button>\n </div>\n\n <div className=\"ycw-disc-panel-list\">\n {discussions.length === 0 ? (\n <div className=\"ycw-disc-panel-empty\">\n 暂无讨论\n </div>\n ) : (\n <>\n {active.length > 0 && (\n <div className=\"ycw-disc-section\">\n <div className=\"ycw-disc-section-label\">进行中 ({active.length})</div>\n {active.map(disc => (\n <DiscussionCard\n key={disc.resourceId}\n disc={disc}\n isNew={newDiscussionIds.has(disc.resourceId)}\n onClick={() => handleCardClick(disc)}\n />\n ))}\n </div>\n )}\n {resolved.length > 0 && (\n <div className=\"ycw-disc-section\">\n <div className=\"ycw-disc-section-label\">已完成 ({resolved.length})</div>\n {resolved.map(disc => (\n <DiscussionCard\n key={disc.resourceId}\n disc={disc}\n isNew={newDiscussionIds.has(disc.resourceId)}\n onClick={() => handleCardClick(disc)}\n />\n ))}\n </div>\n )}\n </>\n )}\n </div>\n </>\n )}\n </div>\n </div>\n )\n}\n\nexport default DiscussionPanel\n","import React, { useMemo, useRef, useEffect } from 'react'\nimport type { DiscussionFile, DiscussionMessage, ReadReceipt } from '../../hooks/useDiscussions.js'\nimport type { ChatWidgetAdapter, PoolAgent } from '../../types.js'\nimport DiscussionComposer from './DiscussionComposer.js'\nimport { Icon } from '../Icon/Icon'\nimport './DiscussionViewer.css'\n\nexport interface DiscussionViewerProps {\n discussion: DiscussionFile\n currentUserAlias?: string\n sessionId?: number\n adapter?: ChatWidgetAdapter\n poolAgents?: PoolAgent[]\n onClose: () => void\n onRefresh?: () => void\n onPostMessage?: (\n discussionPath: string,\n body: string,\n messageType: string,\n mentions: string[],\n ) => Promise<import('../../types.js').PostDiscussionMessageResponse>\n}\n\nconst TYPE_CONFIG: Record<DiscussionMessage['type'], { icon: string; label: string; className: string }> = {\n message: { icon: '', label: '', className: '' },\n finding: { icon: '💡', label: '发现', className: 'ycw-disc-msg--finding' },\n question: { icon: '❓', label: '问题', className: 'ycw-disc-msg--question' },\n proposal: { icon: '📋', label: '提议', className: 'ycw-disc-msg--proposal' },\n decision: { icon: '✅', label: '决策', className: 'ycw-disc-msg--decision' },\n action_item: { icon: '📌', label: '行动项', className: 'ycw-disc-msg--action' },\n}\n\nconst STATUS_LABEL: Record<string, string> = {\n active: '进行中',\n converging: '收敛中',\n resolved: '已结论',\n archived: '已归档',\n}\n\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso)\n return d.toLocaleString('zh-CN', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch { return iso }\n}\n\nfunction speakerInitial(name: string): string {\n if (name === 'user') return 'U'\n return name.charAt(0).toUpperCase()\n}\n\nfunction speakerColor(name: string): string {\n let hash = 0\n for (let i = 0; i < name.length; i++) {\n hash = name.charCodeAt(i) + ((hash << 5) - hash)\n }\n const hue = Math.abs(hash) % 360\n return `hsl(${hue}, 55%, 50%)`\n}\n\nconst ReceiptBar: React.FC<{ receipts: ReadReceipt[] }> = ({ receipts }) => {\n if (receipts.length === 0) return null\n return (\n <div className=\"ycw-disc-receipt-bar\">\n <span className=\"ycw-disc-receipt-label\">📬</span>\n {receipts.map((r) => (\n <span\n key={r.agent}\n className={`ycw-disc-receipt-item ${r.read ? 'ycw-disc-receipt--read' : 'ycw-disc-receipt--unread'}`}\n title={r.read ? `${r.agent} 已读` : `${r.agent} 未读`}\n >\n <span className=\"ycw-disc-receipt-icon\">{r.read ? '✓' : '○'}</span>\n <span className=\"ycw-disc-receipt-name\">{r.agent}</span>\n </span>\n ))}\n </div>\n )\n}\n\nconst MessageBubble: React.FC<{ msg: DiscussionMessage; isCurrentUser: boolean }> = ({ msg, isCurrentUser }) => {\n const cfg = TYPE_CONFIG[msg.type] || TYPE_CONFIG.message\n const color = speakerColor(msg.speaker)\n\n return (\n <div className={`ycw-disc-msg ${cfg.className} ${isCurrentUser ? 'ycw-disc-msg--self' : ''}`}>\n <div className=\"ycw-disc-msg-avatar\" style={{ background: color }}>\n {speakerInitial(msg.speaker)}\n </div>\n <div className=\"ycw-disc-msg-content\">\n <div className=\"ycw-disc-msg-header\">\n <span className=\"ycw-disc-msg-speaker\">{msg.speaker === 'user' ? '用户' : msg.speaker}</span>\n {cfg.label && (\n <span className={`ycw-disc-msg-type-badge ycw-disc-badge--${msg.type}`}>\n {cfg.icon} {cfg.label}\n </span>\n )}\n <span className=\"ycw-disc-msg-time\">{formatTime(msg.timestamp)}</span>\n {msg.mentions.length > 0 && (\n <span className=\"ycw-disc-msg-mentions\">\n → {msg.mentions.map(m => m === 'all' ? '@全体' : `@${m}`).join(', ')}\n </span>\n )}\n </div>\n {msg.title && <div className=\"ycw-disc-msg-title\">{msg.title}</div>}\n <div className=\"ycw-disc-msg-body\">{msg.body}</div>\n {msg.readReceipts && <ReceiptBar receipts={msg.readReceipts} />}\n </div>\n </div>\n )\n}\n\nconst DiscussionViewer: React.FC<DiscussionViewerProps> = ({\n discussion,\n currentUserAlias,\n sessionId,\n adapter,\n poolAgents,\n onClose,\n onRefresh,\n onPostMessage,\n}) => {\n const statusLabel = STATUS_LABEL[discussion.meta.status] ?? discussion.meta.status\n const messagesEndRef = useRef<HTMLDivElement>(null)\n\n const sortedMessages = useMemo(() => {\n return [...discussion.messages].sort((a, b) =>\n new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(),\n )\n }, [discussion.messages])\n\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })\n }, [sortedMessages.length])\n\n const maxMessages = discussion.meta.max_messages ?? 50\n const progress = discussion.messageCount / maxMessages\n const composerDisabled = discussion.meta.status === 'resolved' || discussion.meta.status === 'archived'\n const allowedTypes = discussion.meta.status === 'converging'\n ? ['decision', 'action_item']\n : undefined\n\n return (\n <div className=\"ycw-disc-viewer\">\n <div className=\"ycw-disc-viewer-header\">\n <div className=\"ycw-disc-viewer-header-left\">\n <button className=\"ycw-disc-viewer-back\" onClick={onClose}>\n <Icon name=\"arrowLeft\" size={16} aria-hidden />\n </button>\n <div className=\"ycw-disc-viewer-title-group\">\n <span className=\"ycw-disc-viewer-title\">{discussion.meta.topic}</span>\n <span className={`ycw-disc-status ycw-disc-status--${discussion.meta.status}`}>\n {statusLabel}\n </span>\n </div>\n </div>\n <div className=\"ycw-disc-viewer-participants\">\n {discussion.meta.participants.slice(0, 5).map(p => (\n <span\n key={p}\n className=\"ycw-disc-participant-pip\"\n style={{ background: speakerColor(p) }}\n title={p}\n >\n {speakerInitial(p)}\n </span>\n ))}\n {discussion.meta.participants.length > 5 && (\n <span className=\"ycw-disc-participant-more\">\n +{discussion.meta.participants.length - 5}\n </span>\n )}\n </div>\n </div>\n\n {/* Progress bar */}\n <div className=\"ycw-disc-progress\">\n <div\n className={`ycw-disc-progress-bar ${progress >= 0.9 ? 'ycw-disc-progress-bar--danger' : ''}`}\n style={{ width: `${Math.min(progress * 100, 100)}%` }}\n />\n <span className=\"ycw-disc-progress-text\">\n {discussion.messageCount}/{maxMessages}\n </span>\n </div>\n\n <div className=\"ycw-disc-viewer-messages\">\n {sortedMessages.length === 0 ? (\n <div className=\"ycw-disc-empty\">暂无讨论消息</div>\n ) : (\n sortedMessages.map((msg, i) => (\n <MessageBubble\n key={`${msg.speaker}-${msg.timestamp}-${i}`}\n msg={msg}\n isCurrentUser={msg.speaker === currentUserAlias || msg.speaker === 'user'}\n />\n ))\n )}\n <div ref={messagesEndRef} />\n </div>\n\n {/* Composer at bottom */}\n {!composerDisabled && adapter && sessionId != null && (\n <DiscussionComposer\n discussion={discussion}\n sessionId={sessionId}\n currentUser={currentUserAlias ?? 'user'}\n adapter={adapter}\n onMessageSent={onRefresh ?? (() => {})}\n onPostMessage={onPostMessage}\n allowedTypes={allowedTypes}\n poolAgents={poolAgents}\n />\n )}\n\n {composerDisabled && (\n <div className=\"ycw-disc-viewer-closed\">\n {discussion.meta.status === 'resolved' ? '✅ 讨论已结论' : '📦 讨论已归档'}\n </div>\n )}\n </div>\n )\n}\n\nexport default DiscussionViewer\n","import React, { useState, useCallback, useRef, useEffect } from 'react'\nimport type { DiscussionFile } from '../../hooks/useDiscussions.js'\nimport type { ChatWidgetAdapter, PoolAgent, PostDiscussionMessageResponse } from '../../types.js'\nimport MentionAutocomplete from './MentionAutocomplete.js'\n\nexport interface DiscussionComposerProps {\n discussion: DiscussionFile\n sessionId: number\n currentUser: string\n adapter: ChatWidgetAdapter\n onMessageSent: () => void\n onPostMessage?: (\n discussionPath: string,\n body: string,\n messageType: string,\n mentions: string[],\n ) => Promise<PostDiscussionMessageResponse>\n disabled?: boolean\n allowedTypes?: string[]\n poolAgents?: PoolAgent[]\n}\n\nconst MESSAGE_TYPES = [\n { value: 'message', label: '消息', icon: '💬' },\n { value: 'question', label: '提问', icon: '❓' },\n { value: 'proposal', label: '提议', icon: '📋' },\n { value: 'decision', label: '决策', icon: '✅' },\n { value: 'finding', label: '发现', icon: '💡' },\n { value: 'action_item', label: '行动项', icon: '📌' },\n]\n\nfunction parseMentionsFromText(text: string): string[] {\n const matches = text.match(/@(\\S+)/g)\n if (!matches) return []\n const seen = new Set<string>()\n const result: string[] = []\n for (const m of matches) {\n const alias = m.slice(1)\n if (alias && !seen.has(alias)) {\n seen.add(alias)\n result.push(alias)\n }\n }\n return result\n}\n\nconst DiscussionComposer: React.FC<DiscussionComposerProps> = ({\n discussion,\n sessionId,\n currentUser,\n adapter,\n onMessageSent,\n onPostMessage,\n disabled = false,\n allowedTypes,\n poolAgents = [],\n}) => {\n const [body, setBody] = useState('')\n const [messageType, setMessageType] = useState('message')\n const [sending, setSending] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [showMention, setShowMention] = useState(false)\n const [mentionTrigger, setMentionTrigger] = useState('')\n const [newParticipantHint, setNewParticipantHint] = useState<string | null>(null)\n const [lastResponse, setLastResponse] = useState<PostDiscussionMessageResponse | null>(null)\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n\n const availableTypes = allowedTypes\n ? MESSAGE_TYPES.filter(t => allowedTypes.includes(t.value))\n : MESSAGE_TYPES\n\n useEffect(() => {\n if (allowedTypes && !allowedTypes.includes(messageType)) {\n setMessageType(allowedTypes[0] ?? 'message')\n }\n }, [allowedTypes, messageType])\n\n const handleBodyChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const val = e.target.value\n setBody(val)\n\n const cursor = e.target.selectionStart ?? val.length\n const textBefore = val.slice(0, cursor)\n const atMatch = textBefore.match(/@(\\S*)$/)\n if (atMatch) {\n setShowMention(true)\n setMentionTrigger(atMatch[1])\n } else {\n setShowMention(false)\n setMentionTrigger('')\n }\n }, [])\n\n const handleMentionSelect = useCallback((alias: string, isNew: boolean) => {\n const textarea = textareaRef.current\n if (textarea) {\n const cursor = textarea.selectionStart ?? body.length\n const textBefore = body.slice(0, cursor)\n const atIdx = textBefore.lastIndexOf('@')\n if (atIdx >= 0) {\n const newText = body.slice(0, atIdx) + `@${alias} ` + body.slice(cursor)\n setBody(newText)\n }\n }\n\n if (isNew) {\n setNewParticipantHint(alias)\n setTimeout(() => setNewParticipantHint(null), 4000)\n }\n setShowMention(false)\n }, [body])\n\n const handleSend = useCallback(async () => {\n if (!body.trim() || disabled) return\n if (!onPostMessage && !adapter.postDiscussionMessage) return\n setSending(true)\n setError(null)\n const mentions = parseMentionsFromText(body)\n const trimmed = body.trim()\n try {\n let resp: PostDiscussionMessageResponse\n if (onPostMessage) {\n resp = await onPostMessage(discussion.gitPath, trimmed, messageType, mentions)\n } else {\n resp = await adapter.postDiscussionMessage!(sessionId, {\n discussion_path: discussion.gitPath,\n speaker: currentUser,\n message_type: messageType,\n mentions,\n body: trimmed,\n })\n if (resp.ok) onMessageSent()\n }\n setLastResponse(resp)\n if (resp.ok) {\n setBody('')\n if (resp.unresolved_mentions?.length) {\n setError(`以下 @mention 未能解析到 Agent: ${resp.unresolved_mentions.join(', ')}`)\n }\n } else {\n setError(resp.error || '发送失败')\n }\n } catch (e) {\n setError(String(e))\n } finally {\n setSending(false)\n }\n }, [body, adapter, sessionId, discussion.gitPath, currentUser, messageType, disabled, onMessageSent, onPostMessage])\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault()\n handleSend()\n }\n if (e.key === 'Escape' && showMention) {\n setShowMention(false)\n }\n }, [handleSend, showMention])\n\n if (!adapter.postDiscussionMessage) return null\n\n return (\n <div className=\"ycw-disc-composer\">\n {error && <div className=\"ycw-disc-composer-error\">{error}</div>}\n\n {newParticipantHint && (\n <div className=\"ycw-disc-composer-hint\">\n {newParticipantHint} 将被加入讨论\n </div>\n )}\n\n <div className=\"ycw-disc-composer-input-row\">\n <div className=\"ycw-disc-composer-textarea-wrap\">\n <textarea\n ref={textareaRef}\n className=\"ycw-disc-composer-textarea\"\n value={body}\n onChange={handleBodyChange}\n onKeyDown={handleKeyDown}\n placeholder={disabled ? '讨论已结束' : '输入消息,@ 提及其他参与者…'}\n disabled={disabled || sending}\n rows={2}\n />\n {showMention && (\n <MentionAutocomplete\n trigger={mentionTrigger}\n participants={discussion.meta.participants}\n poolAgents={poolAgents}\n onSelect={handleMentionSelect}\n onClose={() => setShowMention(false)}\n />\n )}\n </div>\n\n <div className=\"ycw-disc-composer-controls\">\n <select\n className=\"ycw-disc-composer-type-select\"\n value={messageType}\n onChange={e => setMessageType(e.target.value)}\n disabled={disabled || sending}\n >\n {availableTypes.map(t => (\n <option key={t.value} value={t.value}>{t.icon} {t.label}</option>\n ))}\n </select>\n\n <button\n className=\"ycw-disc-composer-send\"\n onClick={handleSend}\n disabled={disabled || sending || !body.trim()}\n type=\"button\"\n >\n {sending ? '…' : '发送'}\n </button>\n </div>\n </div>\n\n {lastResponse && lastResponse.ok && lastResponse.remaining_messages <= 10 && (\n <div className=\"ycw-disc-composer-remaining\">\n 剩余 {lastResponse.remaining_messages} 条消息额度\n </div>\n )}\n </div>\n )\n}\n\nexport default DiscussionComposer\n","import React, { useMemo } from 'react'\nimport type { PoolAgent } from '../../types.js'\n\nexport interface MentionAutocompleteProps {\n trigger: string\n participants: string[]\n poolAgents: PoolAgent[]\n onSelect: (alias: string, isNewParticipant: boolean) => void\n onClose: () => void\n}\n\nfunction stateIndicator(state: string): string {\n const s = state.toUpperCase()\n if (s === 'RUNNING' || s === 'WORKING' || s === 'BOOT') return '🟢'\n if (s === 'COMPLETED') return '⚪'\n return '⚫'\n}\n\nfunction instanceIdAbbr(id: number): string {\n if (!id) return ''\n const s = String(id)\n return s.length > 4 ? `…${s.slice(-4)}` : s\n}\n\nconst MentionItem: React.FC<{\n alias: string\n instanceId?: number\n showInstanceHint: boolean\n state: string\n isNew: boolean\n onClick: () => void\n}> = ({ alias, instanceId, showInstanceHint, state, isNew, onClick }) => (\n <button className=\"ycw-mention-item\" onClick={onClick} type=\"button\">\n <span className=\"ycw-mention-state\">{stateIndicator(state)}</span>\n <span className=\"ycw-mention-alias\">\n {alias}\n {showInstanceHint && instanceId ? (\n <span className=\"ycw-mention-instance-hint\">(#{instanceIdAbbr(instanceId)})</span>\n ) : null}\n </span>\n {isNew && <span className=\"ycw-mention-badge-new\">+ 加入讨论</span>}\n </button>\n)\n\nconst MentionAutocomplete: React.FC<MentionAutocompleteProps> = ({\n trigger,\n participants,\n poolAgents,\n onSelect,\n onClose,\n}) => {\n const { inGroup, outGroup } = useMemo(() => {\n const lowerTrigger = trigger.toLowerCase()\n const participantSet = new Set(participants)\n const poolByAlias = new Map<string, PoolAgent>()\n for (const a of poolAgents) {\n const alias = a.agent_alias ?? ''\n if (alias) poolByAlias.set(alias, a)\n }\n\n const inGroup: PoolAgent[] = []\n const seenAliases = new Set<string>()\n\n for (const alias of participants) {\n if (!alias) continue\n if (lowerTrigger && !alias.toLowerCase().includes(lowerTrigger)) continue\n const poolEntry = poolByAlias.get(alias)\n // JETP-074:PoolAgent.client_id 现在是 required;此处的 placeholder 不是真正\n // 的 pool entry,只为在 mention 下拉里显示该 alias 名字(不进 observation /\n // 不影响 cubicle 分组)。给一个空 sentinel 即可,类型层与 PoolAgent 兼容。\n inGroup.push(poolEntry ?? {\n agent_instance_id: 0,\n agent_id: alias,\n agent_alias: alias,\n state: 'UNKNOWN',\n client_id: '',\n })\n seenAliases.add(alias)\n }\n\n const outGroup: PoolAgent[] = []\n const seenIds = new Set<number>()\n for (const a of poolAgents) {\n const alias = a.agent_alias ?? ''\n const displayName = alias || a.agent_id\n if (seenAliases.has(alias) && alias) continue\n if (seenIds.has(a.agent_instance_id)) continue\n if (lowerTrigger && !displayName.toLowerCase().includes(lowerTrigger) && !a.agent_id.toLowerCase().includes(lowerTrigger)) continue\n outGroup.push(a)\n seenIds.add(a.agent_instance_id)\n if (alias) seenAliases.add(alias)\n }\n\n return { inGroup, outGroup }\n }, [trigger, participants, poolAgents])\n\n if (inGroup.length === 0 && outGroup.length === 0) return null\n\n return (\n <div className=\"ycw-mention-autocomplete\" onMouseDown={e => e.preventDefault()}>\n {inGroup.length > 0 && (\n <div className=\"ycw-mention-group\">\n <div className=\"ycw-mention-group-label\">当前参与者</div>\n {inGroup.map(a => (\n <MentionItem\n key={`${a.agent_alias ?? a.agent_id}-${a.agent_instance_id}`}\n alias={a.agent_alias ?? a.agent_id}\n instanceId={a.agent_instance_id}\n showInstanceHint={!a.agent_alias}\n state={a.state}\n isNew={false}\n onClick={() => {\n onSelect(a.agent_alias ?? a.agent_id, false)\n onClose()\n }}\n />\n ))}\n </div>\n )}\n {outGroup.length > 0 && (\n <div className=\"ycw-mention-group\">\n <div className=\"ycw-mention-group-label\">Session 中其他 Agent</div>\n {outGroup.map(a => (\n <MentionItem\n key={`${a.agent_alias ?? a.agent_id}-${a.agent_instance_id}`}\n alias={a.agent_alias ?? a.agent_id}\n instanceId={a.agent_instance_id}\n showInstanceHint={!a.agent_alias}\n state={a.state}\n isNew={true}\n onClick={() => {\n onSelect(a.agent_alias ?? a.agent_id, true)\n onClose()\n }}\n />\n ))}\n </div>\n )}\n </div>\n )\n}\n\nexport default MentionAutocomplete\n","import { useState, useEffect, useCallback, useMemo, useRef } from 'react'\nimport type { ChatWidgetAdapter, DirectoryFileEntry, MentionTarget, PoolAgent, PostDiscussionMessageResponse } from '../types.js'\n\nexport interface ReadReceipt {\n agent: string\n read: boolean\n}\n\nexport interface DiscussionMessage {\n speaker: string\n timestamp: string\n type: 'message' | 'finding' | 'question' | 'proposal' | 'decision' | 'action_item'\n mentions: string[]\n title?: string\n body: string\n readReceipts?: ReadReceipt[]\n}\n\nexport interface DiscussionMeta {\n topic: string\n created: string\n status: 'active' | 'converging' | 'resolved' | 'archived'\n participants: string[]\n max_messages?: number\n discussion_mode?: string\n converge_grace?: number\n tags?: string[]\n}\n\nexport interface DiscussionFile {\n resourceId: string\n fileName: string\n gitPath: string\n meta: DiscussionMeta\n messages: DiscussionMessage[]\n messageCount: number\n pendingReceiptCount: number\n}\n\nexport interface UseDiscussionsOptions {\n adapter: ChatWidgetAdapter\n sessionId: number | null\n currentUser?: string\n pollIntervalMs?: number\n wsConnected?: boolean\n poolAgents?: PoolAgent[]\n}\n\nexport interface UseDiscussionsReturn {\n discussions: DiscussionFile[]\n totalCount: number\n activeCount: number\n newDiscussionIds: Set<string>\n loading: boolean\n refresh: () => void\n refreshSingleDiscussion: (gitPath: string) => Promise<void>\n postMessage: (\n discussionPath: string,\n body: string,\n messageType: string,\n mentions: string[],\n ) => Promise<PostDiscussionMessageResponse>\n discussionUnread: number\n clearDiscussionUnread: () => void\n handleWsDiscussionUpdate: (event: Record<string, unknown>) => void\n}\n\nconst DISC_SUFFIX = '.disc.md'\n\nfunction isDiscussionFile(entry: DirectoryFileEntry): boolean {\n if (!entry.git_path) return false\n const parts = entry.git_path.split('/')\n return parts.length >= 2\n && parts[0] === 'discussions'\n && entry.file_name.endsWith(DISC_SUFFIX)\n}\n\nfunction stripQuotes(value: string): string {\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n return value.slice(1, -1)\n }\n return value\n}\n\nfunction coerceScalar(value: string): unknown {\n const v = stripQuotes(value.trim())\n if (v.startsWith('[') && v.endsWith(']')) {\n return v.slice(1, -1).split(',').map(s => stripQuotes(s.trim())).filter(Boolean)\n }\n if (/^-?\\d+$/.test(v)) return parseInt(v, 10)\n if (/^-?\\d+\\.\\d+$/.test(v)) return parseFloat(v)\n if (v === 'true' || v === 'false') return v === 'true'\n return v\n}\n\nfunction parseFrontMatter(raw: string): { meta: DiscussionMeta | null; bodyStart: number } {\n const trimmed = raw.trimStart()\n const leadingOffset = raw.length - trimmed.length\n if (!trimmed.startsWith('---')) return { meta: null, bodyStart: 0 }\n const afterOpen = trimmed.slice(3)\n const closeIdx = afterOpen.search(/\\n---\\s*(\\n|$)/)\n if (closeIdx === -1) return { meta: null, bodyStart: 0 }\n const yaml = afterOpen.slice(0, closeIdx)\n const closeMatch = afterOpen.slice(closeIdx).match(/\\n---\\s*(\\n|$)/)\n const closeLen = closeMatch ? closeMatch[0].length : 4\n const bodyStart = leadingOffset + 3 + closeIdx + closeLen\n\n const meta: Record<string, unknown> = {}\n const lines = yaml.split('\\n')\n let i = 0\n while (i < lines.length) {\n const line = lines[i]\n if (!line.trim() || line.trim().startsWith('#')) { i++; continue }\n const colonIdx = line.indexOf(':')\n if (colonIdx === -1) { i++; continue }\n const key = line.slice(0, colonIdx).trim()\n const rest = line.slice(colonIdx + 1).trim()\n if (rest === '') {\n const items: string[] = []\n let j = i + 1\n while (j < lines.length) {\n const next = lines[j]\n const m = next.match(/^\\s*-\\s+(.+)$/)\n if (!m) break\n items.push(stripQuotes(m[1].trim()))\n j++\n }\n if (items.length > 0) {\n meta[key] = items\n i = j\n continue\n }\n meta[key] = ''\n i++\n continue\n }\n meta[key] = coerceScalar(rest)\n i++\n }\n\n return {\n meta: {\n topic: String(meta.topic ?? ''),\n created: String(meta.created ?? ''),\n status: (['active', 'converging', 'resolved', 'archived'].includes(String(meta.status)) ? String(meta.status) : 'active') as DiscussionMeta['status'],\n participants: Array.isArray(meta.participants)\n ? (meta.participants as unknown[]).map(String)\n : [],\n max_messages: typeof meta.max_messages === 'number' ? meta.max_messages : undefined,\n discussion_mode: typeof meta.discussion_mode === 'string' ? meta.discussion_mode : undefined,\n converge_grace: typeof meta.converge_grace === 'number' ? meta.converge_grace : undefined,\n tags: Array.isArray(meta.tags) ? (meta.tags as unknown[]).map(String) : undefined,\n },\n bodyStart,\n }\n}\n\nconst DISC_MARKER_RE = /<!--\\s*@disc\\(([\\s\\S]*?)\\)\\s*-->/g\nconst KW_ARG_RE = /(\\w+)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|(\\[[^\\]]*\\])|([^,)\\s]+))/g\nconst RECEIPT_LINE_RE = /^- \\[([ x])\\] @(.+)$/\nconst RECEIPT_SECTION_RE = /📬\\s*回执[::]?\\s*\\n/\n\ninterface ParsedDiscHeader {\n speaker: string\n timestamp: string\n type: DiscussionMessage['type']\n mentions: string[]\n}\n\nfunction parseDiscHeader(inner: string): ParsedDiscHeader | null {\n const trimmed = inner.trim()\n if (!trimmed) return null\n\n if (/\\b\\w+\\s*=/.test(trimmed)) {\n const kwargs: Record<string, string> = {}\n let m: RegExpExecArray | null\n KW_ARG_RE.lastIndex = 0\n while ((m = KW_ARG_RE.exec(trimmed)) !== null) {\n const key = m[1]\n const value = m[2] ?? m[3] ?? m[4] ?? m[5] ?? ''\n kwargs[key] = value.trim()\n }\n const speaker = kwargs.sender || kwargs.from || kwargs.speaker || kwargs.agent || kwargs.role || ''\n if (!speaker) return null\n const ts = kwargs.ts || kwargs.timestamp || ''\n const rawType = (kwargs.type || kwargs.msg_type || 'message').trim()\n let mentionsRaw = kwargs.mentions || ''\n if (mentionsRaw.startsWith('[') && mentionsRaw.endsWith(']')) {\n mentionsRaw = mentionsRaw.slice(1, -1)\n }\n const mentions = mentionsRaw\n ? mentionsRaw.split(',').map(s => s.trim().replace(/^@/, '')).filter(Boolean)\n : []\n return {\n speaker,\n timestamp: ts,\n type: isValidType(rawType) ? rawType : 'message',\n mentions,\n }\n }\n\n const posMatch = trimmed.match(\n /^([^,]+?)\\s*,\\s*([^,]+?)\\s*,\\s*([^,\\)]+?)\\s*(?:,\\s*\\[([^\\]]*)\\]\\s*)?$/,\n )\n if (!posMatch) {\n const single = trimmed.match(/^([^,]+?)\\s*$/)\n if (!single) return null\n return { speaker: single[1].trim(), timestamp: '', type: 'message', mentions: [] }\n }\n const rawType = posMatch[3].trim()\n const mentionsRaw = posMatch[4] ?? ''\n const mentions = mentionsRaw\n ? mentionsRaw.split(',').map(s => s.trim().replace(/^@/, '')).filter(Boolean)\n : []\n return {\n speaker: posMatch[1].trim(),\n timestamp: posMatch[2].trim(),\n type: isValidType(rawType) ? rawType : 'message',\n mentions,\n }\n}\n\nfunction parseReceipts(text: string): { receipts: ReadReceipt[]; cleanBody: string } {\n const match = text.match(RECEIPT_SECTION_RE)\n if (!match || match.index == null) return { receipts: [], cleanBody: text }\n\n const before = text.slice(0, match.index).trimEnd()\n const after = text.slice(match.index + match[0].length)\n const receipts: ReadReceipt[] = []\n const remaining: string[] = []\n let inReceipts = true\n\n for (const line of after.split('\\n')) {\n if (inReceipts) {\n const rm = line.match(RECEIPT_LINE_RE)\n if (rm) {\n receipts.push({ agent: rm[2].trim(), read: rm[1] === 'x' })\n continue\n }\n if (line.trim() === '') continue\n inReceipts = false\n }\n remaining.push(line)\n }\n\n const cleanBody = remaining.length > 0\n ? before + '\\n' + remaining.join('\\n')\n : before\n\n return { receipts, cleanBody }\n}\n\nconst VALID_TYPES = ['message', 'finding', 'question', 'proposal', 'decision', 'action_item'] as const\n\nfunction isValidType(t: string): t is DiscussionMessage['type'] {\n return (VALID_TYPES as readonly string[]).includes(t)\n}\n\nexport function parseDiscussionMessages(raw: string): { meta: DiscussionMeta | null; messages: DiscussionMessage[] } {\n const { meta, bodyStart } = parseFrontMatter(raw)\n const body = raw.slice(bodyStart)\n const messages: DiscussionMessage[] = []\n\n const matches: { header: ParsedDiscHeader; markerStart: number; bodyStart: number }[] = []\n DISC_MARKER_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = DISC_MARKER_RE.exec(body)) !== null) {\n const header = parseDiscHeader(m[1])\n if (!header) continue\n matches.push({ header, markerStart: m.index, bodyStart: m.index + m[0].length })\n }\n\n for (let i = 0; i < matches.length; i++) {\n const { header, bodyStart: start } = matches[i]\n const end = i + 1 < matches.length ? matches[i + 1].markerStart : body.length\n const content = body.slice(start, end)\n\n const { receipts, cleanBody } = parseReceipts(content)\n\n const lines = cleanBody.trim().split('\\n')\n let title: string | undefined\n let bodyLines = lines\n if (lines[0]?.startsWith('###')) {\n title = lines[0].replace(/^###\\s*/, '').trim()\n bodyLines = lines.slice(1)\n }\n\n messages.push({\n speaker: header.speaker,\n timestamp: header.timestamp,\n type: header.type,\n mentions: header.mentions,\n title,\n body: bodyLines.join('\\n').trim(),\n readReceipts: receipts.length > 0 ? receipts : undefined,\n })\n }\n return { meta, messages }\n}\n\nexport function useDiscussions({\n adapter,\n sessionId,\n currentUser,\n pollIntervalMs = 30_000,\n wsConnected = false,\n poolAgents = [],\n}: UseDiscussionsOptions): UseDiscussionsReturn {\n const [discussions, setDiscussions] = useState<DiscussionFile[]>([])\n const [loading, setLoading] = useState(false)\n const prevIdsRef = useRef(new Set<string>())\n const [newIds, setNewIds] = useState<Set<string>>(new Set())\n const [unread, setUnread] = useState(0)\n\n const entryMapRef = useRef(new Map<string, DirectoryFileEntry>())\n\n const parseEntryContent = useCallback((entry: DirectoryFileEntry, content: string): DiscussionFile | null => {\n const { meta, messages } = parseDiscussionMessages(content)\n if (!meta) return null\n let pending = 0\n for (const msg of messages) {\n if (msg.readReceipts) {\n for (const r of msg.readReceipts) {\n if (!r.read) pending++\n }\n }\n }\n return {\n resourceId: entry.resource_id,\n fileName: entry.file_name,\n gitPath: entry.git_path,\n meta,\n messages,\n messageCount: messages.length,\n pendingReceiptCount: pending,\n }\n }, [])\n\n const fetchDiscussions = useCallback(async () => {\n if (sessionId == null || !adapter.listDirectoryFiles) return\n setLoading(true)\n try {\n const entries = await adapter.listDirectoryFiles(sessionId, 'discussions', {\n recursive: true,\n generateUrls: false,\n })\n const discEntries = entries.filter(isDiscussionFile)\n\n const newEntryMap = new Map<string, DirectoryFileEntry>()\n for (const e of discEntries) newEntryMap.set(e.git_path, e)\n entryMapRef.current = newEntryMap\n\n const results = (await Promise.all(\n discEntries.map(async (entry): Promise<DiscussionFile | null> => {\n if (!adapter.getResourceContent) return null\n try {\n const res = await adapter.getResourceContent(sessionId, entry.resource_id)\n const content = typeof res === 'string' ? res : (res as { content?: string })?.content ?? ''\n if (!content) return null\n return parseEntryContent(entry, content)\n } catch { return null }\n }),\n )).filter((d): d is DiscussionFile => d !== null)\n\n setDiscussions(results)\n\n const currentIds = new Set(results.map(d => d.resourceId))\n const freshIds = new Set<string>()\n for (const id of currentIds) {\n if (!prevIdsRef.current.has(id)) freshIds.add(id)\n }\n if (freshIds.size > 0) {\n setNewIds(prev => new Set([...prev, ...freshIds]))\n setTimeout(() => {\n setNewIds(prev => {\n const next = new Set(prev)\n for (const id of freshIds) next.delete(id)\n return next\n })\n }, 8000)\n }\n prevIdsRef.current = currentIds\n } catch { /* silent */ } finally {\n setLoading(false)\n }\n }, [adapter, sessionId, parseEntryContent])\n\n const refreshSingleDiscussion = useCallback(async (gitPath: string) => {\n if (sessionId == null || !adapter.getResourceContent) return\n const entry = entryMapRef.current.get(gitPath)\n if (!entry) {\n await fetchDiscussions()\n return\n }\n try {\n const res = await adapter.getResourceContent(sessionId, entry.resource_id)\n const content = typeof res === 'string' ? res : (res as { content?: string })?.content ?? ''\n if (!content) return\n const updated = parseEntryContent(entry, content)\n if (!updated) return\n setDiscussions(prev =>\n prev.map(d => d.gitPath === gitPath ? updated : d),\n )\n } catch {\n await fetchDiscussions()\n }\n }, [adapter, sessionId, parseEntryContent, fetchDiscussions])\n\n useEffect(() => { fetchDiscussions() }, [fetchDiscussions])\n\n const effectivePollInterval = wsConnected ? 15_000 : pollIntervalMs\n\n useEffect(() => {\n if (sessionId == null || effectivePollInterval <= 0) return\n const interval = setInterval(fetchDiscussions, effectivePollInterval)\n return () => clearInterval(interval)\n }, [fetchDiscussions, sessionId, effectivePollInterval])\n\n const activeCount = useMemo(\n () => discussions.filter(d => d.meta.status === 'active').length,\n [discussions],\n )\n\n const postMessage = useCallback(async (\n discussionPath: string,\n body: string,\n messageType: string,\n mentions: string[],\n ): Promise<PostDiscussionMessageResponse> => {\n if (!adapter.postDiscussionMessage || sessionId == null) {\n return { ok: false, message_index: 0, status: '', remaining_messages: 0, participants_changed: false, error: 'Discussion posting not available' }\n }\n\n const optimisticMsg: DiscussionMessage = {\n speaker: currentUser ?? 'user',\n timestamp: new Date().toISOString(),\n type: (messageType as DiscussionMessage['type']) || 'message',\n mentions,\n body,\n }\n setDiscussions(prev =>\n prev.map(d =>\n d.gitPath === discussionPath\n ? { ...d, messages: [...d.messages, optimisticMsg], messageCount: d.messageCount + 1 }\n : d,\n ),\n )\n\n const mentionTargets: MentionTarget[] = mentions.map(m => {\n const agent = poolAgents.find(a => (a.agent_alias ?? a.agent_id) === m)\n if (agent) {\n return {\n identifier: m,\n agent_id: agent.agent_id,\n agent_instance_id: agent.agent_instance_id || undefined,\n }\n }\n return { identifier: m }\n })\n\n const resp = await adapter.postDiscussionMessage(sessionId, {\n discussion_path: discussionPath,\n speaker: currentUser ?? 'user',\n message_type: messageType,\n mentions,\n mention_targets: mentionTargets,\n body,\n })\n if (resp.ok) {\n refreshSingleDiscussion(discussionPath)\n } else {\n setDiscussions(prev =>\n prev.map(d =>\n d.gitPath === discussionPath\n ? { ...d, messages: d.messages.filter(m => m !== optimisticMsg), messageCount: d.messageCount - 1 }\n : d,\n ),\n )\n }\n return resp\n }, [adapter, sessionId, currentUser, poolAgents, refreshSingleDiscussion])\n\n const handleWsDiscussionUpdate = useCallback((event: Record<string, unknown>) => {\n const discussion = event.discussion as string | undefined\n if (discussion && entryMapRef.current.has(discussion)) {\n refreshSingleDiscussion(discussion)\n } else {\n fetchDiscussions()\n }\n const mentions = event.mentions as string[] | undefined\n if (currentUser && mentions?.includes(currentUser)) {\n setUnread(prev => prev + 1)\n }\n }, [fetchDiscussions, refreshSingleDiscussion, currentUser])\n\n const clearDiscussionUnread = useCallback(() => { setUnread(0) }, [])\n\n return {\n discussions,\n totalCount: discussions.length,\n activeCount,\n newDiscussionIds: newIds,\n loading,\n refresh: fetchDiscussions,\n refreshSingleDiscussion,\n postMessage,\n discussionUnread: unread,\n clearDiscussionUnread,\n handleWsDiscussionUpdate,\n }\n}\n","import React, { useState, useCallback, useRef, useEffect } from 'react'\nimport { Icon } from '../Icon/Icon'\nimport { useChatWidgetI18n } from '../../i18n'\nimport { useEscStack, ESC_PRIORITY } from '../../hooks/useEscStack.js'\nimport './AnnotationFAB.css'\n\nexport interface AnnotationFABProps {\n resourceId: string | null\n fileName: string\n onSend: (message: string) => void\n visible: boolean\n expanded?: boolean\n onToggle?: (expanded: boolean) => void\n disabled?: boolean\n}\n\nconst AnnotationFAB: React.FC<AnnotationFABProps> = ({\n resourceId,\n fileName,\n onSend,\n visible,\n expanded: expandedProp,\n onToggle,\n disabled = false,\n}) => {\n const { t } = useChatWidgetI18n()\n const [expandedLocal, setExpandedLocal] = useState(false)\n const expanded = expandedProp !== undefined ? expandedProp : expandedLocal\n const [text, setText] = useState('')\n const inputRef = useRef<HTMLTextAreaElement>(null)\n\n const setExpanded = useCallback((val: boolean) => {\n if (onToggle) onToggle(val)\n else setExpandedLocal(val)\n }, [onToggle])\n\n const escHandler = useCallback(() => {\n setExpanded(false)\n return true\n }, [setExpanded])\n\n useEscStack(escHandler, expanded, ESC_PRIORITY.ANNOTATION_FAB)\n\n useEffect(() => {\n if (expanded) {\n requestAnimationFrame(() => inputRef.current?.focus())\n }\n }, [expanded])\n\n const handleSubmit = useCallback((e?: React.FormEvent) => {\n e?.preventDefault()\n const trimmed = text.trim()\n if (!trimmed || !resourceId) return\n onSend(trimmed)\n setText('')\n setExpanded(false)\n }, [text, resourceId, onSend, setExpanded])\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n handleSubmit()\n }\n }, [handleSubmit])\n\n if (!visible || !resourceId) return null\n\n if (!expanded) {\n return (\n <button\n className=\"ycw-annotation-fab-circle\"\n onClick={() => setExpanded(true)}\n title={t('annotation.fabLabel')}\n aria-label={t('annotation.fabLabel')}\n data-testid=\"cwrf010-annotation-fab\"\n >\n <Icon name=\"chatCircleDots\" size={24} weight=\"fill\" aria-hidden />\n </button>\n )\n }\n\n return (\n <div className=\"ycw-annotation-fab-card\" data-testid=\"cwrf010-annotation-fab-expanded\">\n <div className=\"ycw-annotation-fab-header\">\n <span className=\"ycw-annotation-fab-title\">\n {t('annotation.fabHeader', { fileName })}\n </span>\n <button\n className=\"ycw-annotation-fab-close\"\n onClick={() => setExpanded(false)}\n aria-label={t('annotation.close')}\n >\n <Icon name=\"x\" size={16} aria-hidden />\n </button>\n </div>\n <form className=\"ycw-annotation-fab-form\" onSubmit={handleSubmit}>\n <textarea\n ref={inputRef}\n className=\"ycw-annotation-fab-input\"\n value={text}\n onChange={e => setText(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={t('annotation.fileLevelPlaceholder')}\n rows={3}\n disabled={disabled}\n />\n <button\n className=\"ycw-annotation-fab-send\"\n type=\"submit\"\n disabled={!text.trim() || disabled}\n >\n <Icon name=\"arrowUp\" size={16} aria-hidden />\n </button>\n </form>\n </div>\n )\n}\n\nexport default AnnotationFAB\n","import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport type { FormEvent, KeyboardEvent, MouseEvent } from 'react'\nimport { Icon } from '../Icon/Icon.js'\nimport { useChatWidgetI18n } from '../../i18n/index.js'\nimport { useEscStack, ESC_PRIORITY } from '../../hooks/useEscStack.js'\nimport './AnnotationPanel.css'\n\nexport interface AnnotationPanelMessage {\n role: 'user' | 'assistant'\n text: string\n timestamp?: number\n}\n\nexport interface AnnotationPanelProps {\n open: boolean\n onClose: () => void\n fileLevelConversation: {\n id: string\n messages: AnnotationPanelMessage[]\n preview?: string\n } | null\n anchoredAnnotations: Array<{\n id: string\n anchor?: { text: string; startLine?: number; endLine?: number }\n messages: AnnotationPanelMessage[]\n preview?: string\n }>\n activeAnnotationId: string | null\n onSetActive: (id: string | null) => void\n onSendFollowUp: (annotationId: string, text: string) => void\n isCreating?: boolean\n}\n\nfunction lastMessageAt(messages: Array<{ timestamp?: number }>): number {\n return messages.reduce((acc, m) => Math.max(acc, m.timestamp ?? 0), 0)\n}\n\nfunction anchorMeta(anchor?: {\n text: string\n startLine?: number\n endLine?: number\n}): string | null {\n if (!anchor) return null\n const { startLine, endLine, text } = anchor\n if (startLine != null) {\n const line =\n endLine != null && endLine !== startLine\n ? `L${startLine}–L${endLine}`\n : `L${startLine}`\n return `${line}${text ? ` · ${text}` : ''}`\n }\n return text || null\n}\n\nconst MessageList: React.FC<{\n messages: AnnotationPanelMessage[]\n}> = ({ messages }) => (\n <div className=\"ycw-annotation-panel-messages\">\n {messages.map((m, i) => (\n <div\n key={`${m.role}-${i}-${m.timestamp ?? ''}`}\n className={`ycw-annotation-panel-row ycw-annotation-panel-row--${m.role}`}\n >\n <div\n className={`ycw-annotation-panel-bubble ycw-annotation-panel-bubble--${m.role}`}\n >\n {m.text}\n </div>\n </div>\n ))}\n </div>\n)\n\nconst MiniComposer: React.FC<{\n annotationId: string\n placeholder: string\n disabled: boolean\n onSend: (annotationId: string, text: string) => void\n}> = ({ annotationId, placeholder, disabled, onSend }) => {\n const [text, setText] = useState('')\n const submit = useCallback(() => {\n const t = text.trim()\n if (!t || disabled) return\n onSend(annotationId, t)\n setText('')\n }, [annotationId, disabled, onSend, text])\n\n const onSubmit = useCallback(\n (e: FormEvent) => {\n e.preventDefault()\n submit()\n },\n [submit],\n )\n\n const onKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n submit()\n }\n },\n [submit],\n )\n\n return (\n <form className=\"ycw-annotation-panel-composer\" onSubmit={onSubmit}>\n <textarea\n className=\"ycw-annotation-panel-composer-input\"\n rows={1}\n value={text}\n onChange={e => setText(e.target.value)}\n onKeyDown={onKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n aria-label={placeholder}\n />\n <button\n type=\"submit\"\n className=\"ycw-annotation-panel-composer-send\"\n disabled={!text.trim() || disabled}\n aria-label={placeholder}\n >\n <Icon name=\"arrowUp\" size={16} aria-hidden />\n </button>\n </form>\n )\n}\n\nconst AnnotationPanel: React.FC<AnnotationPanelProps> = ({\n open,\n onClose,\n fileLevelConversation,\n anchoredAnnotations,\n activeAnnotationId,\n onSetActive,\n onSendFollowUp,\n isCreating = false,\n}) => {\n const { t } = useChatWidgetI18n()\n const sheetRef = useRef<HTMLDivElement>(null)\n const scrollTopRef = useRef(0)\n\n const escHandler = useCallback(() => {\n onClose()\n return true\n }, [onClose])\n\n useEscStack(escHandler, open, ESC_PRIORITY.OVERLAY)\n\n const sortedAnchored = useMemo(() => {\n return [...anchoredAnnotations].sort((a, b) => {\n const tb = lastMessageAt(b.messages)\n const ta = lastMessageAt(a.messages)\n if (tb !== ta) return tb - ta\n return a.id.localeCompare(b.id)\n })\n }, [anchoredAnnotations])\n\n useEffect(() => {\n if (open && sheetRef.current) {\n sheetRef.current.scrollTop = scrollTopRef.current\n const firstFocusable = sheetRef.current.querySelector<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n )\n firstFocusable?.focus()\n }\n if (!open && sheetRef.current) {\n scrollTopRef.current = sheetRef.current.scrollTop\n }\n }, [open])\n\n const showEmpty =\n !fileLevelConversation && anchoredAnnotations.length === 0\n\n const activateUnlessComposer = useCallback(\n (id: string, e: MouseEvent) => {\n const el = e.target as HTMLElement\n if (el.closest('textarea, button, input, a')) return\n onSetActive(id)\n },\n [onSetActive],\n )\n\n if (!open) return null\n\n return (\n <div\n className=\"ycw-annotation-panel\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={t('annotation.title')}\n >\n <div\n className=\"ycw-annotation-panel-backdrop\"\n onClick={onClose}\n aria-hidden\n />\n <div className=\"ycw-annotation-panel-sheet\" ref={sheetRef}>\n <div className=\"ycw-annotation-panel-header\">\n <span className=\"ycw-annotation-panel-title\">\n {t('annotation.title')}\n </span>\n <button\n type=\"button\"\n className=\"ycw-annotation-panel-close\"\n onClick={onClose}\n aria-label={t('annotation.close')}\n >\n <Icon name=\"x\" size={18} aria-hidden />\n </button>\n </div>\n <div className=\"ycw-annotation-panel-body\">\n {showEmpty && (\n <div className=\"ycw-annotation-panel-empty\">\n {t('annotation.empty')}\n </div>\n )}\n {fileLevelConversation && (\n <div\n className={`ycw-annotation-panel-card${\n activeAnnotationId === fileLevelConversation.id\n ? ' ycw-annotation-panel-card--active'\n : ''\n }`}\n onClick={e =>\n activateUnlessComposer(fileLevelConversation.id, e)\n }\n >\n <div className=\"ycw-annotation-panel-card-header\">\n <div className=\"ycw-annotation-panel-card-title\">\n {t('annotation.fileLevelTitle')}\n </div>\n {fileLevelConversation.preview ? (\n <div className=\"ycw-annotation-panel-card-anchor\">\n {fileLevelConversation.preview}\n </div>\n ) : null}\n </div>\n <MessageList messages={fileLevelConversation.messages} />\n <MiniComposer\n annotationId={fileLevelConversation.id}\n placeholder={t('annotation.fileLevelPlaceholder')}\n disabled={isCreating}\n onSend={onSendFollowUp}\n />\n </div>\n )}\n {sortedAnchored.map(ann => {\n const meta = anchorMeta(ann.anchor)\n const title =\n ann.preview?.trim() ||\n ann.anchor?.text?.trim() ||\n ann.messages[0]?.text?.slice(0, 120) ||\n '…'\n const isActive = activeAnnotationId === ann.id\n return (\n <div\n key={ann.id}\n className={`ycw-annotation-panel-card${\n isActive ? ' ycw-annotation-panel-card--active' : ''\n }`}\n onClick={e => activateUnlessComposer(ann.id, e)}\n >\n <div className=\"ycw-annotation-panel-card-header\">\n <div className=\"ycw-annotation-panel-card-title\">{title}</div>\n {meta ? (\n <div className=\"ycw-annotation-panel-card-anchor\">\n {meta}\n </div>\n ) : null}\n </div>\n <MessageList messages={ann.messages} />\n <MiniComposer\n annotationId={ann.id}\n placeholder={t('annotation.replyPlaceholder')}\n disabled={isCreating}\n onSend={onSendFollowUp}\n />\n </div>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n\nexport default AnnotationPanel\n","import React, { useState, useCallback, useRef, useEffect, useMemo } from 'react'\nimport { Icon } from '../Icon/Icon'\nimport { useChatWidgetI18n } from '../../i18n'\nimport { useEscStack, ESC_PRIORITY } from '../../hooks/useEscStack.js'\nimport './InlineAnnotationInput.css'\n\nexport interface AnnotationAnchorRect {\n top: number\n left: number\n width: number\n height: number\n}\n\nexport interface InlineAnnotationInputProps {\n anchorRect: AnnotationAnchorRect\n anchorText?: string\n onSend: (message: string) => void\n onClose: () => void\n onFallback?: () => void\n placeholder?: string\n containerRect?: DOMRect\n}\n\nconst MIN_SPACE = 120\nconst MAX_ANCHOR_DISPLAY = 120\n\nconst InlineAnnotationInput: React.FC<InlineAnnotationInputProps> = ({\n anchorRect,\n anchorText,\n onSend,\n onClose,\n onFallback,\n placeholder,\n containerRect,\n}) => {\n const { t } = useChatWidgetI18n()\n const [text, setText] = useState('')\n const inputRef = useRef<HTMLTextAreaElement>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n const escHandler = useCallback(() => {\n onClose()\n return true\n }, [onClose])\n\n useEscStack(escHandler, true, ESC_PRIORITY.INLINE_INPUT)\n\n useEffect(() => {\n requestAnimationFrame(() => inputRef.current?.focus())\n }, [])\n\n const position = useMemo(() => {\n const viewportHeight = containerRect?.height ?? window.innerHeight\n const spaceBelow = viewportHeight - (anchorRect.top + anchorRect.height)\n const spaceAbove = anchorRect.top\n\n if (spaceBelow < MIN_SPACE && spaceAbove < MIN_SPACE) {\n onFallback?.()\n return null\n }\n\n const placeBelow = spaceBelow >= MIN_SPACE\n return {\n top: placeBelow ? anchorRect.top + anchorRect.height + 8 : undefined,\n bottom: placeBelow ? undefined : viewportHeight - anchorRect.top + 8,\n left: Math.max(8, anchorRect.left),\n }\n }, [anchorRect, containerRect, onFallback])\n\n const handleSubmit = useCallback((e?: React.FormEvent) => {\n e?.preventDefault()\n const trimmed = text.trim()\n if (!trimmed) return\n onSend(trimmed)\n setText('')\n onClose()\n }, [text, onSend, onClose])\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n handleSubmit()\n }\n }, [handleSubmit])\n\n if (!position) return null\n\n return (\n <div\n className=\"ycw-inline-annotation-input\"\n ref={containerRef}\n style={{\n position: 'absolute',\n top: position.top,\n bottom: position.bottom,\n left: position.left,\n zIndex: 'var(--ycw-z-toolbar, 30)' as unknown as number,\n }}\n >\n {anchorText && (\n <div className=\"ycw-inline-annotation-context\">\n <span className=\"ycw-inline-annotation-context-label\">{t('annotation.selectionLabel') ?? '选中内容'}</span>\n <span className=\"ycw-inline-annotation-context-text\">\n {anchorText.length > MAX_ANCHOR_DISPLAY ? anchorText.slice(0, MAX_ANCHOR_DISPLAY) + '…' : anchorText}\n </span>\n </div>\n )}\n <form className=\"ycw-inline-annotation-form\" onSubmit={handleSubmit}>\n <textarea\n ref={inputRef}\n className=\"ycw-inline-annotation-textarea\"\n value={text}\n onChange={e => setText(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder ?? t('annotation.inlineInputPlaceholder')}\n rows={2}\n />\n <div className=\"ycw-inline-annotation-actions\">\n <button\n className=\"ycw-inline-annotation-send\"\n type=\"submit\"\n disabled={!text.trim()}\n aria-label={t('context.send')}\n >\n <Icon name=\"arrowUp\" size={14} aria-hidden />\n </button>\n <button\n className=\"ycw-inline-annotation-cancel\"\n type=\"button\"\n onClick={onClose}\n aria-label={t('annotation.close')}\n >\n <Icon name=\"x\" size={14} aria-hidden />\n </button>\n </div>\n </form>\n </div>\n )\n}\n\nexport default InlineAnnotationInput\n","import React, { useCallback, useState } from 'react'\nimport { Icon } from '../Icon/Icon.js'\nimport { useChatWidgetI18n } from '../../i18n/index.js'\nimport './ChannelSidebar.css'\n\nexport interface ChannelItem {\n id: string\n label: string\n kind: 'chat' | 'file-qa' | 'selection-qa'\n unreadCount?: number\n isActive?: boolean\n resourceId?: string\n anchor?: { text: string; startLine?: number; endLine?: number }\n}\n\nexport interface ChannelCategory {\n id: string\n label: string\n iconName: string\n channels: ChannelItem[]\n}\n\nexport interface ChannelSidebarProps {\n categories: ChannelCategory[]\n onChannelClick: (clientId: string) => void\n onExitImmersive: () => void\n}\n\nconst ChannelSidebar: React.FC<ChannelSidebarProps> = ({\n categories,\n onChannelClick,\n onExitImmersive,\n}) => {\n const { t } = useChatWidgetI18n()\n const [collapsed, setCollapsed] = useState<Record<string, boolean>>({})\n\n const toggleCategory = useCallback((catId: string) => {\n setCollapsed(prev => ({ ...prev, [catId]: !prev[catId] }))\n }, [])\n\n return (\n <nav className=\"ycw-channel-sidebar\" aria-label=\"Channel navigation\">\n <div className=\"ycw-channel-sidebar-scroll\">\n {categories.map(cat => {\n const isCollapsed = !!collapsed[cat.id]\n const totalUnread = cat.channels.reduce((s, c) => s + (c.unreadCount ?? 0), 0)\n\n return (\n <div key={cat.id} className=\"ycw-channel-category\">\n <button\n type=\"button\"\n className=\"ycw-channel-category-header\"\n onClick={() => toggleCategory(cat.id)}\n aria-expanded={!isCollapsed}\n >\n <span className={`ycw-channel-caret ${isCollapsed ? 'ycw-channel-caret--collapsed' : ''}`}>\n <Icon name=\"caretDown\" size={10} aria-hidden />\n </span>\n <Icon name={cat.iconName as any} size={14} aria-hidden />\n <span className=\"ycw-channel-category-label\">{cat.label}</span>\n {isCollapsed && totalUnread > 0 && (\n <span className=\"ycw-channel-badge\">{totalUnread > 99 ? '99+' : totalUnread}</span>\n )}\n </button>\n\n {!isCollapsed && (\n <div className=\"ycw-channel-list\" role=\"list\">\n {cat.channels.map(ch => (\n <button\n key={ch.id}\n type=\"button\"\n className={`ycw-channel-item ${ch.isActive ? 'ycw-channel-item--active' : ''} ${(ch.unreadCount ?? 0) > 0 ? 'ycw-channel-item--unread' : ''}`}\n onClick={() => onChannelClick(ch.id)}\n role=\"listitem\"\n title={ch.label}\n >\n <span className=\"ycw-channel-hash\">#</span>\n <span className=\"ycw-channel-name\">{ch.label}</span>\n {(ch.unreadCount ?? 0) > 0 && (\n <span className=\"ycw-channel-badge\">\n {ch.unreadCount! > 99 ? '99+' : ch.unreadCount}\n </span>\n )}\n </button>\n ))}\n </div>\n )}\n </div>\n )\n })}\n </div>\n\n <div className=\"ycw-channel-sidebar-footer\">\n <button\n type=\"button\"\n className=\"ycw-channel-exit-btn\"\n onClick={onExitImmersive}\n title={t('split.exitFullscreen')}\n >\n <Icon name=\"arrowsIn\" size={16} aria-hidden />\n <span>{t('split.exitFullscreen')}</span>\n </button>\n </div>\n </nav>\n )\n}\n\nexport default ChannelSidebar\n","import React, {\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react'\nimport type { FormEvent, KeyboardEvent as ReactKeyboardEvent } from 'react'\nimport { Icon } from '../Icon/Icon.js'\nimport { useChatWidgetI18n } from '../../i18n/index.js'\nimport { useEscStack, ESC_PRIORITY } from '../../hooks/useEscStack.js'\nimport './FloatingConversation.css'\n\nexport interface FloatingMessage {\n role: 'user' | 'assistant'\n text: string\n timestamp?: string | number\n}\n\nexport interface FloatingConversationProps {\n /** JETP-045 P3-T02:Layer 1 子空间标识;旧 API 名 channelId(已弃用,由 PR-11 改名)。 */\n clientId: string\n title: string\n messages: FloatingMessage[]\n onSend: (clientId: string, text: string) => void\n onClose: () => void\n onFocus: () => void\n onMinimize: () => void\n onRestore: () => void\n onPositionChange: (pos: { x: number; y: number }) => void\n position: { x: number; y: number }\n zIndex: number\n minimized: boolean\n isLoading?: boolean\n highlightColor?: string\n anchorContext?: string\n}\n\nconst FloatingConversation: React.FC<FloatingConversationProps> = ({\n clientId,\n title,\n messages,\n onSend,\n onClose,\n onFocus,\n onMinimize,\n onRestore,\n onPositionChange,\n position,\n zIndex,\n minimized,\n isLoading,\n highlightColor,\n anchorContext,\n}) => {\n const { t } = useChatWidgetI18n()\n const [text, setText] = useState('')\n const dragRef = useRef<{ startX: number; startY: number; posX: number; posY: number } | null>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n const bodyRef = useRef<HTMLDivElement>(null)\n\n useEscStack(onClose, true, ESC_PRIORITY.OVERLAY)\n\n useEffect(() => {\n if (!minimized && bodyRef.current) {\n bodyRef.current.scrollTop = bodyRef.current.scrollHeight\n }\n }, [messages.length, minimized])\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if ((e.target as HTMLElement).closest('button, textarea, input')) return\n e.preventDefault()\n onFocus()\n dragRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n posX: position.x,\n posY: position.y,\n }\n\n const handleMouseMove = (ev: MouseEvent) => {\n if (!dragRef.current) return\n const dx = ev.clientX - dragRef.current.startX\n const dy = ev.clientY - dragRef.current.startY\n onPositionChange({\n x: dragRef.current.posX + dx,\n y: dragRef.current.posY + dy,\n })\n }\n\n const handleMouseUp = () => {\n dragRef.current = null\n document.removeEventListener('mousemove', handleMouseMove)\n document.removeEventListener('mouseup', handleMouseUp)\n }\n\n document.addEventListener('mousemove', handleMouseMove)\n document.addEventListener('mouseup', handleMouseUp)\n }, [onFocus, onPositionChange, position])\n\n const handleSend = useCallback(() => {\n const trimmed = text.trim()\n if (!trimmed) return\n onSend(clientId, trimmed)\n setText('')\n }, [clientId, onSend, text])\n\n const handleSubmit = useCallback((e: FormEvent) => {\n e.preventDefault()\n handleSend()\n }, [handleSend])\n\n const handleKeyDown = useCallback((e: ReactKeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n handleSend()\n }\n }, [handleSend])\n\n const posStyle: React.CSSProperties = {\n zIndex,\n ...(position.x < 0\n ? { right: Math.abs(position.x), top: position.y }\n : { left: position.x, top: position.y }),\n }\n\n return (\n <div\n ref={containerRef}\n className={`ycw-floating-conv ${minimized ? 'ycw-floating-conv--minimized' : ''}`}\n style={posStyle}\n onMouseDown={() => onFocus()}\n role=\"dialog\"\n aria-label={title}\n >\n {highlightColor && (\n <div className=\"ycw-floating-conv-accent\" style={{ background: highlightColor }} />\n )}\n\n <div\n className=\"ycw-floating-conv-header\"\n onMouseDown={handleMouseDown}\n >\n <span className=\"ycw-floating-conv-hash\">#</span>\n <span className=\"ycw-floating-conv-title\">{title}</span>\n <div className=\"ycw-floating-conv-controls\">\n <button\n type=\"button\"\n onClick={minimized ? onRestore : onMinimize}\n title={minimized ? t('split.home') : t('split.exitFullscreen')}\n >\n <Icon name={minimized ? 'arrowsOut' : 'minus'} size={14} aria-hidden />\n </button>\n <button type=\"button\" onClick={onClose} title={t('annotation.close')}>\n <Icon name=\"x\" size={14} aria-hidden />\n </button>\n </div>\n </div>\n\n {!minimized && (\n <>\n <div className=\"ycw-floating-conv-body\" ref={bodyRef}>\n {anchorContext && (\n <div className=\"ycw-floating-conv-anchor\">\n <span className=\"ycw-floating-conv-anchor-label\">{t('annotation.selectionLabel') ?? '选中内容'}</span>\n <span className=\"ycw-floating-conv-anchor-text\">\n {anchorContext.length > 200 ? anchorContext.slice(0, 200) + '…' : anchorContext}\n </span>\n </div>\n )}\n {messages.length === 0 && !anchorContext && (\n <div className=\"ycw-floating-conv-empty\">\n {t('annotation.empty')}\n </div>\n )}\n {messages.map((m, i) => (\n <div\n key={`${m.role}-${i}-${m.timestamp ?? ''}`}\n className={`ycw-floating-conv-msg ycw-floating-conv-msg--${m.role}`}\n >\n <div className={`ycw-floating-conv-bubble ycw-floating-conv-bubble--${m.role}`}>\n {m.text}\n </div>\n </div>\n ))}\n {isLoading && (\n <div className=\"ycw-floating-conv-msg ycw-floating-conv-msg--assistant\">\n <div className=\"ycw-floating-conv-bubble ycw-floating-conv-bubble--assistant ycw-floating-conv-loading\">\n <span /><span /><span />\n </div>\n </div>\n )}\n </div>\n\n <form className=\"ycw-floating-conv-composer\" onSubmit={handleSubmit}>\n <textarea\n className=\"ycw-floating-conv-input\"\n rows={1}\n value={text}\n onChange={e => setText(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={t('annotation.replyPlaceholder')}\n />\n <button\n type=\"submit\"\n className=\"ycw-floating-conv-send\"\n disabled={!text.trim()}\n >\n <Icon name=\"arrowUp\" size={16} aria-hidden />\n </button>\n </form>\n </>\n )}\n </div>\n )\n}\n\nexport default FloatingConversation\n","import { useState, useCallback, useMemo } from 'react'\n\n/**\n * JETP-045 P3-T04 / JETP-052 PR-10:浮动窗口的\"窗口 ID\"在协议层等价于 Layer 1 的 ``client_id``。\n *\n * v2(JETP-052)扩展:\n * - 浮动窗增加 `title` / `contextPreloads` 两个**纯 UI 元数据**字段;它们不参与身份/路由,\n * 仅供窗口标题、tooltip、上下文徽章渲染。\n * - 新增 `openWith({ clientId, title?, contextPreloads? })`:一次性带元数据创建/更新窗口。\n * - 新增 `updateMetadata(clientId, patch)`:对已打开窗口单独更新 metadata(不改 position/zIndex)。\n * - 旧 `open(clientId)` / `toggle(clientId)` API **完全保留**,向后兼容现有 `ch:` 命名空间用法。\n *\n * 协议红线 9(JETP-052 P9):本 hook 不做任何业务前缀解码,\n * `clientId` 在窗口管理视角是不可分割的字符串 ID。\n *\n * 任务话池模型(用户语义):每个浮窗对应一个任务话池 cid(v2 ``c_<22>``),\n * 浮窗之间完全对等,没有「主对话」概念。\n */\nexport type FloatingContextPreload = unknown\n\nexport interface FloatingWindow {\n clientId: string\n position: { x: number; y: number }\n minimized: boolean\n zIndex: number\n /** JETP-052: 窗口标题;UI 显示用,可缺省。 */\n title?: string\n /** JETP-052: 上下文元数据;UI 显示用(如\"基于 main.py\"徽章),可缺省。 */\n contextPreloads?: FloatingContextPreload[]\n}\n\nexport interface OpenWithOptions {\n clientId: string\n title?: string\n contextPreloads?: FloatingContextPreload[]\n}\n\nexport interface MetadataPatch {\n title?: string\n contextPreloads?: FloatingContextPreload[]\n}\n\nexport interface UseFloatingWindowsReturn {\n windows: FloatingWindow[]\n open: (clientId: string) => void\n openWith: (opts: OpenWithOptions) => void\n close: (clientId: string) => void\n toggle: (clientId: string) => void\n focus: (clientId: string) => void\n minimize: (clientId: string) => void\n restore: (clientId: string) => void\n updatePosition: (clientId: string, pos: { x: number; y: number }) => void\n updateMetadata: (clientId: string, patch: MetadataPatch) => void\n isOpen: (clientId: string) => boolean\n maxReached: boolean\n}\n\nconst MAX_WINDOWS = 3\nconst CASCADE_OFFSET = 30\nconst BASE_Z = 40\n\nfunction nextCascadePosition(existing: FloatingWindow[]): { x: number; y: number } {\n const baseX = -380\n const baseY = 80\n const offset = existing.length * CASCADE_OFFSET\n return { x: baseX - offset, y: baseY + offset }\n}\n\nfunction compactZIndices(windows: FloatingWindow[], focusId?: string): FloatingWindow[] {\n const sorted = [...windows].sort((a, b) => a.zIndex - b.zIndex)\n return sorted.map((w, i) => ({\n ...w,\n zIndex: BASE_Z + i + (w.clientId === focusId ? windows.length : 0),\n }))\n}\n\nexport function useFloatingWindows(): UseFloatingWindowsReturn {\n const [windows, setWindows] = useState<FloatingWindow[]>([])\n\n const open = useCallback((clientId: string) => {\n setWindows(prev => {\n const existing = prev.find(w => w.clientId === clientId)\n if (existing) {\n return compactZIndices(\n prev.map(w => w.clientId === clientId ? { ...w, minimized: false } : w),\n clientId,\n )\n }\n if (prev.length >= MAX_WINDOWS) return prev\n const pos = nextCascadePosition(prev)\n const newWin: FloatingWindow = {\n clientId,\n position: pos,\n minimized: false,\n zIndex: BASE_Z + prev.length,\n }\n return compactZIndices([...prev, newWin], clientId)\n })\n }, [])\n\n const openWith = useCallback((opts: OpenWithOptions) => {\n const { clientId, title, contextPreloads } = opts\n setWindows(prev => {\n const existing = prev.find(w => w.clientId === clientId)\n if (existing) {\n // 复用窗口:聚焦 + 取消最小化 + 更新 metadata(仅当显式传入时覆盖)\n const updated = prev.map(w => {\n if (w.clientId !== clientId) return w\n const next: FloatingWindow = { ...w, minimized: false }\n if (title !== undefined) next.title = title\n if (contextPreloads !== undefined) next.contextPreloads = contextPreloads\n return next\n })\n return compactZIndices(updated, clientId)\n }\n if (prev.length >= MAX_WINDOWS) return prev\n const pos = nextCascadePosition(prev)\n const newWin: FloatingWindow = {\n clientId,\n position: pos,\n minimized: false,\n zIndex: BASE_Z + prev.length,\n ...(title !== undefined ? { title } : {}),\n ...(contextPreloads !== undefined ? { contextPreloads } : {}),\n }\n return compactZIndices([...prev, newWin], clientId)\n })\n }, [])\n\n const close = useCallback((clientId: string) => {\n setWindows(prev => compactZIndices(prev.filter(w => w.clientId !== clientId)))\n }, [])\n\n const toggle = useCallback((clientId: string) => {\n setWindows(prev => {\n const existing = prev.find(w => w.clientId === clientId)\n if (existing) {\n return compactZIndices(prev.filter(w => w.clientId !== clientId))\n }\n if (prev.length >= MAX_WINDOWS) return prev\n const pos = nextCascadePosition(prev)\n const newWin: FloatingWindow = {\n clientId,\n position: pos,\n minimized: false,\n zIndex: BASE_Z + prev.length,\n }\n return compactZIndices([...prev, newWin], clientId)\n })\n }, [])\n\n const focus = useCallback((clientId: string) => {\n setWindows(prev => compactZIndices(prev, clientId))\n }, [])\n\n const minimize = useCallback((clientId: string) => {\n setWindows(prev =>\n prev.map(w => w.clientId === clientId ? { ...w, minimized: true } : w),\n )\n }, [])\n\n const restore = useCallback((clientId: string) => {\n setWindows(prev =>\n compactZIndices(\n prev.map(w => w.clientId === clientId ? { ...w, minimized: false } : w),\n clientId,\n ),\n )\n }, [])\n\n const updatePosition = useCallback((clientId: string, pos: { x: number; y: number }) => {\n setWindows(prev =>\n prev.map(w => w.clientId === clientId ? { ...w, position: pos } : w),\n )\n }, [])\n\n const updateMetadata = useCallback((clientId: string, patch: MetadataPatch) => {\n setWindows(prev => {\n const found = prev.find(w => w.clientId === clientId)\n if (!found) return prev\n return prev.map(w => {\n if (w.clientId !== clientId) return w\n const next: FloatingWindow = { ...w }\n if (patch.title !== undefined) next.title = patch.title\n if (patch.contextPreloads !== undefined) next.contextPreloads = patch.contextPreloads\n return next\n })\n })\n }, [])\n\n const isOpen = useCallback(\n (clientId: string) => windows.some(w => w.clientId === clientId),\n [windows],\n )\n\n const maxReached = useMemo(() => windows.length >= MAX_WINDOWS, [windows])\n\n return {\n windows,\n open,\n openWith,\n close,\n toggle,\n focus,\n minimize,\n restore,\n updatePosition,\n updateMetadata,\n isOpen,\n maxReached,\n }\n}\n","/**\n * JETP-052 PR-8 — `useClientIdAllocator`\n *\n * 工业级\"通过后端为新对话流分配 v2 client_id\"的前端能力。\n *\n * 设计契约(详见 `doc/proposals/JETP-052-client-id-semantics-rectification/00_protocol/03_session_client_relation.md`):\n * - **后端权威**:v2 `client_id`(``c_<22 base62>``)由 `POST /api/session/{sid}/clients` 分配;前端不允许\"派生\"。\n * - **AC-CID-FE-006 双击防抖**:同 `(sessionId, title, contextPreloads)` 短时间内重复请求会复用同一 inflight Promise。\n * 这避免用户连击\"新建对话\"按钮时创建多个空 client。去重粒度为 hook 实例(一个 chat-widget 一份 inflight 表)。\n * - **best-effort 兼容期导入**:`ensureLegacy` 用于把 localStorage 里的 v1 字面量迁移到后端 `clients` 表,\n * 失败不抛错(不阻塞用户输入)。\n *\n * 工业级可靠性:\n * - 全部 fetch 走 useAuthedFetch(默认 credentials: 'omit',跨源 + Bearer 与 CORS 兼容)。\n * - 4xx/5xx 抛带 `code/message/status` 的 `Error`,业务层可以 try/catch 走 toast。\n * - inflight 表用 ref 持有;不进入 React 渲染依赖、不会重复创建。\n * - SSR/Node 环境若调用直接走 `globalThis.fetch`(vitest jsdom 已内建)。\n */\nimport { useCallback, useMemo, useRef } from 'react'\nimport type { ChatWidgetAdapter } from '../types'\nimport { useAuthedFetch } from './useAuthedFetch'\n\nexport interface ContextPreload {\n /** 上下文类型,例如 ``'file'``、``'selection'``、``'manual'``。 */\n kind: string\n /** 资源路径(文件对话) */\n refPath?: string\n /** 资源 ID(已落库的文件) */\n refId?: string\n /** 选区哈希(选区对话) */\n rangeHash?: string\n /** 任意附加元数据(被后端透传,不参与路由) */\n meta?: Record<string, unknown>\n}\n\nexport interface CreateClientOptions {\n /** 客户端建议标题;后端会再做模型识别覆盖。 */\n title?: string\n /** 初始上下文(不参与 client_id 派生,仅元数据)。 */\n contextPreloads?: ContextPreload[]\n}\n\nexport interface CreateClientResponse {\n id: string\n title: string\n context_preloads: ContextPreload[]\n is_legacy: boolean\n archived: boolean\n last_active_at: number\n}\n\nexport interface UseClientIdAllocatorReturn {\n /**\n * 创建新 client;返回后端分配的 v2 client_id。\n * 双击防抖:相同 (sessionId, title, preloads) 内联 Promise 复用。\n */\n createClient: (sessionId: string | number, opts?: CreateClientOptions) => Promise<string>\n /**\n * 兼容期:把一个 legacy client_id 导入到后端 v2 `clients` 表(best-effort,不抛错)。\n */\n ensureLegacy: (sessionId: string | number, legacyId: string) => Promise<void>\n}\n\n/**\n * 公开 HttpError,便于上层 ChatWidget 用 ``err instanceof HttpError`` +\n * ``err.code === 'BUSINESS_ERROR'`` 区分网络错 vs 业务错(如 Session not allowed),\n * 给出对症的 UI 提示。\n */\nexport class HttpError extends Error {\n status: number\n code: string | null\n constructor(status: number, code: string | null, message: string) {\n super(message)\n this.status = status\n this.code = code\n this.name = 'HttpError'\n }\n}\n\nfunction inflightKey(sessionId: string | number, opts: CreateClientOptions | undefined): string {\n // 用 JSON.stringify 把 (sessionId, title, preloads) 折叠成稳定字符串。\n // 注意:preloads 顺序敏感是有意的——业务上不同顺序代表不同初始上下文堆叠。\n const title = (opts?.title ?? '').trim()\n const preloads = opts?.contextPreloads ?? []\n return `${String(sessionId)}\\x1f${title}\\x1f${JSON.stringify(preloads)}`\n}\n\n/**\n * 创建一个 client allocator hook。\n *\n * @param apiBase 可选 API 基地址(如 ``'https://api.example.com'``);缺省走同源相对路径。\n * @param opts.adapter JETP-056:完整 ChatWidgetAdapter;优先级最高,走 useAuthedFetch\n * 统一处理 Authorization / 401 → refreshAuth 重试 / onAuthFailure 通知。\n * @param opts.getAuthHeaders JETP-054 hotfix(兼容期保留):仅注入 JWT/Bearer 头。\n * adapter 未提供时使用;两者都未提供时退化为只走 cookie(向后兼容旧测试)。\n */\nexport function useClientIdAllocator(\n apiBase?: string,\n opts?: {\n adapter?: ChatWidgetAdapter | null\n getAuthHeaders?: () => Record<string, string>\n },\n): UseClientIdAllocatorReturn {\n const inflightRef = useRef<Map<string, Promise<string>>>(new Map())\n const baseRef = useRef<string>(apiBase ?? '')\n baseRef.current = apiBase ?? ''\n\n // JETP-056:优先用完整 adapter;否则把 getAuthHeaders 包成一个 shim adapter,\n // 这样 useAuthedFetch 仍然能注入鉴权头。两者都没有时 useAuthedFetch 退化为透明 fetch。\n const shimAdapter = useMemo<ChatWidgetAdapter | null>(() => {\n if (opts?.adapter) return opts.adapter\n if (opts?.getAuthHeaders) {\n return { getAuthHeaders: opts.getAuthHeaders } as unknown as ChatWidgetAdapter\n }\n return null\n }, [opts?.adapter, opts?.getAuthHeaders])\n const authedFetch = useAuthedFetch(shimAdapter)\n\n const buildUrl = useCallback((path: string) => {\n const base = baseRef.current.replace(/\\/+$/, '')\n return `${base}${path}`\n }, [])\n\n const createClient = useCallback(\n async (sessionId: string | number, opts?: CreateClientOptions): Promise<string> => {\n const key = inflightKey(sessionId, opts)\n const existing = inflightRef.current.get(key)\n if (existing) {\n console.debug('[ClientAlloc] createClient inflight reused', { sid: sessionId, key })\n return existing\n }\n\n const promise = (async (): Promise<string> => {\n const url = buildUrl(`/api/session/${encodeURIComponent(String(sessionId))}/clients`)\n console.debug('[ClientAlloc] FETCH POST', { sid: sessionId, url, title: opts?.title, stack: new Error().stack?.split('\\n').slice(2, 8).join(' | ') })\n // JETP-054 hotfix:后端 ClientCreateReq.context_preloads 是 Optional[dict]\n // (协议 03_session_client_relation §2.1:{kind, file_path?, selection_hash?, source_uri?}),\n // 旧实现兜底成 [] 会触发 422。这里仅在前端给到首条 preload 时才把它转成 dict 上送,\n // 没有就直接省略;ContextPreload[] 多条的语义后续迁移由 JETP-054 P3 处理。\n const firstPreload = opts?.contextPreloads?.[0]\n const body: Record<string, unknown> = {\n title: (opts?.title ?? '').trim() || undefined,\n }\n if (firstPreload && typeof firstPreload === 'object') {\n body.context_preloads = {\n kind: firstPreload.kind,\n ...(firstPreload.refPath ? { file_path: firstPreload.refPath } : {}),\n ...(firstPreload.rangeHash ? { selection_hash: firstPreload.rangeHash } : {}),\n ...(firstPreload.refId ? { source_uri: firstPreload.refId } : {}),\n ...(firstPreload.meta ? { meta: firstPreload.meta } : {}),\n }\n }\n let resp: Response\n try {\n resp = await authedFetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n } catch (e) {\n throw new HttpError(0, 'NETWORK', `network error: ${(e as Error).message}`)\n }\n if (!resp.ok) {\n let code: string | null = null\n let message = `HTTP ${resp.status}`\n try {\n const errJson = (await resp.json()) as {\n code?: string\n message?: string\n detail?: { code?: string; message?: string } | string\n }\n // FastAPI HTTPException 走 detail;ResponseModel.error 走 code/message\n if (errJson.detail && typeof errJson.detail === 'object') {\n code = errJson.detail.code ?? null\n message = errJson.detail.message ?? message\n } else if (typeof errJson.detail === 'string') {\n message = errJson.detail\n } else {\n code = errJson.code ?? null\n message = errJson.message ?? message\n }\n } catch {\n /* ignore parse error */\n }\n throw new HttpError(resp.status, code, message)\n }\n // jetagents 全站 ResponseModel 包裹: {code, session_id, message, data}\n // - 业务成功: HTTP 200 + code=200 + data={client 对象}\n // - 业务错误: HTTP 200 + code=400 + data={} + message=\"...\"(注意 HTTP 仍是 200,\n // resp.ok 为 true,所以**必须**显式判定 wrapper.code 才能识别\"非鉴权但业务拒绝\"\n // 的场景,例如 _verify_session_owner 返回的 \"Session not allowed\")。\n // 兼容: 极旧版本可能直接返回 plain client 对象(无 wrapper)。\n const wrapper = (await resp.json()) as\n | { code?: number; message?: string; data?: CreateClientResponse }\n | CreateClientResponse\n const isWrapped =\n wrapper && typeof wrapper === 'object' && 'code' in wrapper && 'data' in wrapper\n if (isWrapped) {\n const wrappedCode = (wrapper as { code?: number }).code\n if (typeof wrappedCode === 'number' && wrappedCode !== 200) {\n const businessMsg =\n ((wrapper as { message?: string }).message?.trim()) || `business error code=${wrappedCode}`\n // 用 wrapper.code 当 HttpError.status,便于上层 toast 直接用业务码做分支判断;\n // 同时 HTTP 真实 status 已经是 200,业务码才是真信号。\n throw new HttpError(wrappedCode, 'BUSINESS_ERROR', businessMsg)\n }\n }\n const data = (\n isWrapped\n ? (wrapper as { data?: CreateClientResponse }).data ?? (wrapper as CreateClientResponse)\n : (wrapper as CreateClientResponse)\n ) as CreateClientResponse\n const cid = data?.id\n if (typeof cid !== 'string' || !/^c_[A-Za-z0-9]{22}$/.test(cid)) {\n throw new HttpError(resp.status, 'INVALID_RESPONSE', `bad client_id from server: ${cid}`)\n }\n return cid\n })()\n\n inflightRef.current.set(key, promise)\n try {\n const cid = await promise\n return cid\n } finally {\n // inflight 仅用于\"同次创建去重\",结果回来即时清理;不缓存历史结果。\n inflightRef.current.delete(key)\n }\n },\n [authedFetch, buildUrl],\n )\n\n const ensureLegacy = useCallback(\n async (sessionId: string | number, legacyId: string): Promise<void> => {\n const url = buildUrl(`/api/session/${encodeURIComponent(String(sessionId))}/clients/legacy-import`)\n try {\n await authedFetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ legacy_ids: [legacyId] }),\n })\n } catch {\n /* best-effort:网络错误时静默;后端 _resolve_client_id 还会再走 ensure_legacy 兜底 */\n }\n },\n [authedFetch, buildUrl],\n )\n\n // 关键:把返回对象 useMemo 起来——createClient/ensureLegacy 已经各自 useCallback 稳定,\n // 但裸对象字面量每次 render 都是新引用,会污染上层 useCallback / useEffect 的依赖列表\n // (上层把 `clientIdAllocator` 整体放进 deps)→ 每次 render 都被判定为 deps 变化 → init-effect\n // 等下游会被反复触发,导致控制台被 \"[CW init-effect] enter\" 刷屏。\n return useMemo(() => ({ createClient, ensureLegacy }), [createClient, ensureLegacy])\n}\n","/**\n * JETP-052 PR-11 — `useBootLegacyImport`\n *\n * 应用启动后一次性把 localStorage 里残留的 v1 时代 `chat_widget:client_id_alias:*`\n * 字面量(如 ``main`` / ``file:<sha1>`` / ``sel:<hash>``)批量上报到后端\n * `POST /api/session/{sid}/clients/legacy-import`,让后端把它们补登记到 v2 `clients` 表,\n * 保留旧字面量并标记 `is_legacy=true`。\n *\n * 工业级保障:\n * - 同一 hook 实例内 (sessionId, ids) 仅触发一次:用 `Set<string>` 记录已上报的 sessionId。\n * - 失败静默:fetch 抛错时不影响后续业务(best-effort)。\n * - SSR/隐私模式:`scanLegacyClientIdsFromLocalStorage` 已做 try/catch;这里不再处理。\n * - 不依赖 `useEffect cleanup`(导入是单向幂等动作;卸载时无需回滚)。\n */\nimport { useEffect, useMemo, useRef } from 'react'\n\nimport type { ChatWidgetAdapter } from '../types'\nimport { scanLegacyClientIdsFromLocalStorage } from './useClientId'\nimport { useAuthedFetch } from './useAuthedFetch'\n\n/**\n * @param sessionId 当前 session ID;为 `null`/空则跳过。\n * @param apiBase 可选 API 基地址。\n * @param opts.adapter JETP-056:完整 ChatWidgetAdapter;走 useAuthedFetch 统一鉴权。\n * @param opts.getAuthHeaders JETP-054 hotfix(兼容期保留):仅注入 JWT/Bearer 头。\n */\nexport function useBootLegacyImport(\n sessionId: string | number | null,\n apiBase = '',\n opts?: {\n adapter?: ChatWidgetAdapter | null\n getAuthHeaders?: () => Record<string, string>\n },\n): void {\n const importedRef = useRef<Set<string>>(new Set())\n const baseRef = useRef<string>(apiBase)\n baseRef.current = apiBase\n\n const shimAdapter = useMemo<ChatWidgetAdapter | null>(() => {\n if (opts?.adapter) return opts.adapter\n if (opts?.getAuthHeaders) {\n return { getAuthHeaders: opts.getAuthHeaders } as unknown as ChatWidgetAdapter\n }\n return null\n }, [opts?.adapter, opts?.getAuthHeaders])\n const authedFetch = useAuthedFetch(shimAdapter)\n // 把 authedFetch 装进 ref,避免成为 effect 依赖导致重复触发 import;\n // 同一个 sid 仍由 importedRef 去重,幂等。\n const authedFetchRef = useRef(authedFetch)\n authedFetchRef.current = authedFetch\n\n useEffect(() => {\n if (sessionId === null || sessionId === undefined || sessionId === '') return\n const sidKey = String(sessionId)\n if (importedRef.current.has(sidKey)) return\n\n const legacyIds = scanLegacyClientIdsFromLocalStorage()\n if (legacyIds.length === 0) {\n // 标记完成,避免后续 sessionId 短时间内再次 mount 时无谓扫描;\n // 但若 sessionId 真的换了,下面的 effect 会重新走(因为 set 仅按 sessionId 去重)。\n importedRef.current.add(sidKey)\n return\n }\n\n importedRef.current.add(sidKey)\n const base = baseRef.current.replace(/\\/+$/, '')\n const url = `${base}/api/session/${encodeURIComponent(sidKey)}/clients/legacy-import`\n\n void (async () => {\n try {\n await authedFetchRef.current(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ legacy_ids: legacyIds }),\n })\n } catch {\n /* best-effort:网络错误时静默;后端 _resolve_client_id 会再走 ensure_legacy 兜底 */\n }\n })()\n }, [sessionId])\n}\n","/**\n * JETP-052 PR-8 — `useClientId` v2 工具函数\n *\n * 与 JETP-045 v1 的区别(彻底改语义):\n * - **v1**:前端\"派生\" `client_id`(``main`` / ``file:<sha1>`` / ``sel:<hash>``)→ 把\"业务对话类型\"和\"对话身份\"耦合。\n * - **v2**:`client_id` 是后端权威分配的扁平 UUID 风格 ``c_<22 base62>``;\n * 业务上下文(如初始文件路径、选区哈希)下沉为 `context_preloads` 元数据。\n *\n * 本模块仅暴露:\n * - 三个轻量校验工具:{@link isV2ClientId}、{@link isLegacyClientId}、{@link isValidClientId}\n * - localStorage 兼容期扫描:{@link scanLegacyClientIdsFromLocalStorage}\n *\n * 旧的 `deriveClientId` / `useClientId(ctx)` API 已删除;调用方应改用:\n * - {@link useClientIdAllocator}:通过后端 API 创建新 client。\n * - {@link useSessionClients}:列出 session 内所有 client。\n *\n * 协议红线 9(JETP-052 P9):除本文件 + `clients_repository.legacy decompose` 之外,\n * 业务代码 **禁止** 对 `client_id` 做 ``startswith('main')`` / ``startswith('file:')`` / ``startswith('sel:')`` 等前缀解码。\n */\n\n/** v2 client_id 格式:固定前缀 `c_` + 22 位 base62(共 24 字符)。 */\nconst V2_REGEX = /^c_[A-Za-z0-9]{22}$/\n\n/**\n * Legacy(v1)client_id 字符集:与后端 Pydantic / `00_protocol/01_client_id_v2.md` 对齐。\n *\n * 允许字符集 `[A-Za-z0-9._:-]`,长度 1..128。\n */\nconst LEGACY_REGEX = /^[A-Za-z0-9._:-]{1,128}$/\n\n/** localStorage 兼容期扫描前缀(与 JETP-045 v1 写入键保持一致,便于一次性导入)。 */\nconst LEGACY_STORAGE_PREFIX = 'chat_widget:client_id_alias:'\n\n/** 是否为 v2 扁平 client_id。 */\nexport function isV2ClientId(value: unknown): boolean {\n return typeof value === 'string' && V2_REGEX.test(value)\n}\n\n/** 是否为 v1(legacy)client_id;要求非 v2 且符合 legacy 字符集。 */\nexport function isLegacyClientId(value: unknown): boolean {\n if (typeof value !== 'string') return false\n if (V2_REGEX.test(value)) return false\n return LEGACY_REGEX.test(value)\n}\n\n/** 接受 v2 或 legacy 任一形态。 */\nexport function isValidClientId(value: unknown): boolean {\n return isV2ClientId(value) || isLegacyClientId(value)\n}\n\n/**\n * 扫描 localStorage 中所有 v1 时代写入的 legacy client_id 值。\n *\n * 使用场景:应用启动时一次性收集,调用 `POST /api/session/{sid}/clients/legacy-import`\n * 让后端为它们补登记到 v2 `clients` 表(保留旧字面量、置 `is_legacy=true`)。\n *\n * 工业级保障:\n * - SSR / 隐私模式下 `window` 或 `localStorage` 可能不可用 → try/catch 静默返回 `[]`。\n * - 跳过已是 v2 的条目(已经迁移过)。\n * - 自然去重(同一 legacy 字面量在多个键下只返回一次)。\n *\n * @returns 排序后的 legacy 字面量数组(升序)。\n */\nexport function scanLegacyClientIdsFromLocalStorage(): string[] {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return []\n } catch {\n return []\n }\n const result = new Set<string>()\n try {\n const len = window.localStorage.length\n for (let i = 0; i < len; i++) {\n const key = window.localStorage.key(i)\n if (!key || !key.startsWith(LEGACY_STORAGE_PREFIX)) continue\n let raw: string | null = null\n try {\n raw = window.localStorage.getItem(key)\n } catch {\n continue\n }\n if (!raw) continue\n if (V2_REGEX.test(raw)) continue\n if (!LEGACY_REGEX.test(raw)) continue\n result.add(raw)\n }\n } catch {\n /* 容量满 / 跨域 storage 异常 → 直接返回当前累积结果 */\n }\n return Array.from(result).sort()\n}\n","import React, { useEffect, useRef } from 'react'\nimport './SelectionHighlight.css'\n\nexport interface SelectionHighlightItem {\n id: string\n text: string\n startLine?: number\n endLine?: number\n color: string\n active: boolean\n}\n\nexport interface SelectionHighlightProps {\n highlights: SelectionHighlightItem[]\n containerRef?: React.RefObject<HTMLElement | null>\n}\n\nfunction applyHighlights(container: HTMLElement, highlights: SelectionHighlightItem[]) {\n container.querySelectorAll('mark[data-sel-highlight]').forEach(el => el.replaceWith(...el.childNodes))\n\n for (const hl of highlights) {\n if (hl.startLine != null && hl.endLine != null) {\n highlightByLines(container, hl)\n } else if (hl.text) {\n highlightByText(container, hl)\n }\n }\n}\n\nfunction highlightByLines(container: HTMLElement, hl: SelectionHighlightItem) {\n for (let line = hl.startLine!; line <= hl.endLine!; line++) {\n const lineEl = container.querySelector(`[data-line=\"${line}\"]`)\n if (lineEl) {\n const mark = document.createElement('mark')\n mark.setAttribute('data-sel-highlight', hl.id)\n mark.className = `ycw-sel-highlight ${hl.active ? 'ycw-sel-highlight--active' : ''}`\n mark.style.setProperty('--ycw-hl-color', hl.color)\n lineEl.parentNode?.insertBefore(mark, lineEl)\n mark.appendChild(lineEl)\n }\n }\n}\n\nfunction highlightByText(container: HTMLElement, hl: SelectionHighlightItem) {\n const preview = hl.text.slice(0, 60)\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT)\n let node: Text | null = null\n while ((node = walker.nextNode() as Text | null)) {\n const idx = node.textContent?.indexOf(preview) ?? -1\n if (idx === -1) continue\n\n const range = document.createRange()\n range.setStart(node, idx)\n range.setEnd(node, Math.min(idx + preview.length, node.textContent!.length))\n\n const mark = document.createElement('mark')\n mark.setAttribute('data-sel-highlight', hl.id)\n mark.className = `ycw-sel-highlight ${hl.active ? 'ycw-sel-highlight--active' : ''}`\n mark.style.setProperty('--ycw-hl-color', hl.color)\n\n try {\n range.surroundContents(mark)\n } catch {\n // surroundContents fails if range crosses element boundaries\n }\n break\n }\n}\n\nconst SelectionHighlight: React.FC<SelectionHighlightProps> = ({\n highlights,\n containerRef,\n}) => {\n const prevHighlightsRef = useRef<string>('')\n\n useEffect(() => {\n const container = containerRef?.current\n if (!container) return\n\n const key = JSON.stringify(highlights.map(h => ({ id: h.id, active: h.active })))\n if (key === prevHighlightsRef.current) return\n prevHighlightsRef.current = key\n\n applyHighlights(container, highlights)\n\n return () => {\n container.querySelectorAll('mark[data-sel-highlight]').forEach(el => el.replaceWith(...el.childNodes))\n }\n }, [highlights, containerRef])\n\n return null\n}\n\nexport default SelectionHighlight\n","/**\n * SessionForbiddenBanner — 当 useSessionClients 报错时(典型:HTTP 200 + ResponseModel.error\n * \"Session not allowed\",即用户不是 session member),主区不再 stuck 在\n * \"等待对话开始...\" 或反复 POST 创建空 cid,而是清晰告诉用户原因,并给出一个\n * \"申请加入此 session\" 的快捷按钮。\n *\n * 设计契约:\n * - 仅做 UI;副作用只有\"调用 self-join API + 触发 onJoined 回调\"。\n * - 调用 ``POST /api/v1/sessions/{sid}/self-join``(jetagents demo/dev 专用\n * feature-flag 端点;详见 jetagents/site/projects/api.py)。\n * - self-join 成功 → ``onJoined()`` 让上层 refresh sessionClients,\n * 重新走 init-effect 正常路径;失败(403 / feature flag 关 / 已是 member)→\n * 就地把后端 message 显示出来,不抛异常。\n *\n * 工业级保障:\n * - 同一个 sid + 同一次 banner 实例并发点击 → in-flight 单飞(按钮 disabled)。\n * - 失败重试不重置 banner;防止误操作。\n */\nimport React, { useCallback, useState } from 'react'\nimport type { ChatWidgetAdapter } from '../types'\nimport { useAuthedFetch } from '../hooks/useAuthedFetch'\n\nexport interface SessionForbiddenBannerProps {\n sessionId: string | number | null\n error: Error\n adapter?: ChatWidgetAdapter | null\n /** self-join 成功回调;上层应在此重新拉 useSessionClients 与 controller 历史。 */\n onJoined?: () => void\n /** 可选 API 基地址;缺省走当前域。 */\n apiBase?: string\n}\n\ninterface ResponseWrapper {\n code?: number\n message?: string\n detail?: { code?: string; message?: string } | string\n data?: unknown\n}\n\nfunction pickErrorMessage(wrapper: ResponseWrapper | null, fallback: string): string {\n if (!wrapper) return fallback\n if (wrapper.detail && typeof wrapper.detail === 'object') {\n const d = wrapper.detail\n if (d.message) return d.message\n } else if (typeof wrapper.detail === 'string') {\n return wrapper.detail\n }\n if (wrapper.message) return wrapper.message\n return fallback\n}\n\nexport const SessionForbiddenBanner: React.FC<SessionForbiddenBannerProps> = ({\n sessionId,\n error,\n adapter,\n onJoined,\n apiBase = '',\n}) => {\n const authedFetch = useAuthedFetch(adapter ?? null)\n const [joining, setJoining] = useState(false)\n const [joinError, setJoinError] = useState<string | null>(null)\n const [joined, setJoined] = useState(false)\n\n const handleJoin = useCallback(async () => {\n if (sessionId === null || sessionId === undefined || sessionId === '') return\n if (joining || joined) return\n setJoining(true)\n setJoinError(null)\n try {\n const base = apiBase.replace(/\\/+$/, '')\n const url = `${base}/api/v1/sessions/${encodeURIComponent(String(sessionId))}/self-join`\n const resp = await authedFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: '{}',\n })\n // 后端 self-join 是标准 FastAPI 路由,错误一律走 HTTP 4xx + {detail}(与\n // clients_manager 的 ResponseModel.error 不同,不会假装 200)。这里两种都兼容。\n if (!resp.ok) {\n let wrapper: ResponseWrapper | null = null\n try {\n wrapper = (await resp.json()) as ResponseWrapper\n } catch {\n /* ignore */\n }\n setJoinError(pickErrorMessage(wrapper, `HTTP ${resp.status}`))\n return\n }\n setJoined(true)\n onJoined?.()\n } catch (e) {\n setJoinError((e as Error).message || 'network error')\n } finally {\n setJoining(false)\n }\n }, [authedFetch, sessionId, joining, joined, apiBase, onJoined])\n\n if (sessionId === null || sessionId === undefined || sessionId === '') return null\n\n return (\n <div\n className=\"ycw-session-forbidden-banner\"\n role=\"alert\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '32px 24px',\n gap: 12,\n textAlign: 'center',\n opacity: 0.92,\n }}\n >\n <div style={{ fontSize: 28, lineHeight: 1 }} aria-hidden>\n 🔒\n </div>\n <div style={{ fontWeight: 600, fontSize: 14 }}>\n 无法加载此 session(id: {String(sessionId)})\n </div>\n <div\n style={{\n fontSize: 12,\n maxWidth: 420,\n color: 'var(--ycw-text-muted, #888)',\n wordBreak: 'break-all',\n }}\n >\n {error.message || '后端拒绝了此 session 的访问请求。'}\n </div>\n {!joined && (\n <button\n type=\"button\"\n onClick={handleJoin}\n disabled={joining}\n style={{\n marginTop: 4,\n padding: '6px 16px',\n border: '1px solid var(--ycw-border, #ddd)',\n borderRadius: 6,\n background: joining ? 'var(--ycw-bg-disabled, #f3f3f3)' : 'var(--ycw-primary, #2563eb)',\n color: joining ? 'var(--ycw-text-muted, #888)' : '#fff',\n cursor: joining ? 'wait' : 'pointer',\n fontSize: 13,\n }}\n >\n {joining ? '正在申请加入…' : '申请加入此 session'}\n </button>\n )}\n {joined && (\n <div style={{ fontSize: 12, color: 'var(--ycw-success, #16a34a)' }}>\n 已加入,正在重新加载…\n </div>\n )}\n {joinError && (\n <div\n style={{\n fontSize: 12,\n color: 'var(--ycw-error, #dc2626)',\n maxWidth: 420,\n wordBreak: 'break-all',\n }}\n >\n 加入失败:{joinError}\n </div>\n )}\n </div>\n )\n}\n\nexport default SessionForbiddenBanner\n","import { useCallback } from 'react'\nimport type { ChatWidgetAdapter } from '../types.js'\nimport type { UseSessionChannelReturn, AgentControlFrame } from './useSessionChannel.js'\n\nexport interface UseAgentControlOptions {\n channel: UseSessionChannelReturn | null\n adapter: ChatWidgetAdapter\n sessionId: number | null\n}\n\nexport function useAgentControl({\n channel,\n adapter,\n sessionId,\n}: UseAgentControlOptions) {\n const sendAction = useCallback(async (\n agentInstanceId: number,\n action: AgentControlFrame['action'],\n ) => {\n if (channel?.connected) {\n channel.sendControlFrame({ action, agentInstanceId })\n return\n }\n\n if (sessionId == null) return\n const ctrl = (adapter as unknown as Record<string, unknown>).controlAgent\n if (typeof ctrl === 'function') {\n await ctrl({ sessionId, agentInstanceId, action })\n }\n }, [channel, adapter, sessionId])\n\n const pause = useCallback(\n (agentInstanceId: number) => sendAction(agentInstanceId, 'pause'),\n [sendAction],\n )\n\n const resume = useCallback(\n (agentInstanceId: number) => sendAction(agentInstanceId, 'resume'),\n [sendAction],\n )\n\n /**\n * 停止 Agent —— 走 HTTP `POST /api/session/stop`(协作式取消,写 Redis 信号)。\n *\n * 不走 WS 的原因:\n * 1. 后端 `WS control_agent { action: \"stop\" }` 在 main.py 里 `hasattr(pool,\n * \"stop_agent_instance\")` 恒为 False,回落 `pool.stop_agent(session_id)` 时\n * 与 `SimpleAgentPool.stop_agent(session_id, agent_instance_id, propagate)`\n * 签名不匹配 → TypeError,**当前生产路径上 WS stop 失效**。\n * 2. HTTP 路径直接写共享 Redis key,跨 Pod 一致;不依赖 WS 是否在线。\n * 3. 后端幂等:键已为 `\"stop\"` 时直接 `success(data={})`,连点两次安全。\n *\n * 与 pause/resume 的差异:pause/resume 修改 pool 进程内状态,必须 WS 直送对应\n * Pod,**不能**改成 HTTP(会跨 Pod 找不到 pool);故只把 stop 单独 HTTP 化。\n *\n * 向后兼容:自定义 adapter 未实现 `stopAgent` 时回退到旧 WS `sendControlFrame`\n * 路径,避免破坏既有集成。\n */\n const stop = useCallback(async (agentInstanceId: number) => {\n if (sessionId != null) {\n const stopFn = (adapter as unknown as {\n stopAgent?: (p: { sessionId: number; agentInstanceId?: number }) => Promise<void>\n }).stopAgent\n if (typeof stopFn === 'function') {\n await stopFn({ sessionId, agentInstanceId })\n return\n }\n }\n // 兼容旧 adapter / 未提供 sessionId 的极端场景:尝试 WS 路径。\n if (channel?.connected) {\n channel.sendControlFrame({ action: 'stop', agentInstanceId })\n }\n }, [adapter, sessionId, channel])\n\n return { pause, resume, stop }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type {\n ChatWidgetAdapter,\n ListSessionsResponse,\n SessionListItem,\n} from '../types.js'\nimport { ChatWidgetAuthError } from '../errors.js'\n\nexport interface UseSessionListOptions {\n adapter: ChatWidgetAdapter | null | undefined\n /** 每页大小;默认 20。 */\n pageSize?: number\n /** 周期重拉间隔(毫秒);不传则不开启轮询。 */\n pollMs?: number\n /**\n * 外部触发重拉的版本号;任何递增即触发一次刷新。\n * 用于把\"会话发了第一条消息 / 接收到 SESSION_TITLE 通知\"等外部事件\n * 转译为列表刷新,无需调用方手工持有 ref。\n */\n refreshKey?: number\n /** 当前激活的会话 id;用于在删除时通知调用方\"激活的那条没了\"。 */\n activeSessionId?: number\n /**\n * 删除当前激活会话后的回调;典型用法是把 ChatWidget.sessionId 置 null\n * 并触发新会话或显示空态。\n */\n onActiveSessionRemoved?: (id: number) => void\n /** Adapter 抛 401 时的钩子;通常对接 LoginPage / tokenStore.clear。 */\n onAuthFailure?: () => void\n /** 通用错误回调;只在最近一次拉取失败时回调一次。 */\n onError?: (err: unknown) => void\n}\n\nexport interface UseSessionListReturn {\n sessions: SessionListItem[]\n loading: boolean\n page: number\n totalPages: number\n setPage: (page: number) => void\n refresh: () => void\n deleteSession: (id: number) => Promise<void>\n /** adapter 是否实现了 listSessions。 */\n supported: boolean\n /** adapter 是否实现了 deleteSession。 */\n canDelete: boolean\n /** 最近一次拉取/删除的错误对象;成功后清空。 */\n error: unknown\n}\n\n/**\n * 通用会话列表 hook:负责拉取、分页、轮询、可见性恢复、删除与认证失败处理。\n *\n * 设计原则:\n * 1. 不耦合 UI——只暴露状态与命令,便于宿主自行渲染(侧栏 / 抽屉 / 命令面板等)。\n * 2. Adapter 能力可选——`supported / canDelete` 透传 adapter 是否实现对应方法,\n * 让 UI 决定显示空态还是隐藏按钮。\n * 3. 删除操作乐观更新——先从本地列表移除再触发后台请求;失败则强制重拉拉回真值。\n */\nexport function useSessionList(options: UseSessionListOptions): UseSessionListReturn {\n const {\n adapter,\n pageSize = 20,\n pollMs,\n refreshKey,\n activeSessionId,\n onActiveSessionRemoved,\n onAuthFailure,\n onError,\n } = options\n\n const [sessions, setSessions] = useState<SessionListItem[]>([])\n const [loading, setLoading] = useState(false)\n const [page, setPage] = useState(1)\n const [total, setTotal] = useState(0)\n const [error, setError] = useState<unknown>(null)\n\n const supported = !!adapter?.listSessions\n const canDelete = !!adapter?.deleteSession\n\n const totalPages = Math.max(1, Math.ceil(total / pageSize))\n\n // 用 ref 持有最新回调,避免 effect 依赖抖动。\n const onAuthRef = useRef(onAuthFailure)\n const onErrRef = useRef(onError)\n useEffect(() => { onAuthRef.current = onAuthFailure }, [onAuthFailure])\n useEffect(() => { onErrRef.current = onError }, [onError])\n\n const fetchOnce = useCallback(async () => {\n if (!adapter?.listSessions) {\n setSessions([])\n setTotal(0)\n return\n }\n setLoading(true)\n try {\n const res: ListSessionsResponse = await adapter.listSessions({ page, pageSize })\n setSessions(res.items ?? [])\n setTotal(res.total ?? (res.items?.length ?? 0))\n setError(null)\n } catch (err) {\n setError(err)\n if (err instanceof ChatWidgetAuthError) {\n onAuthRef.current?.()\n } else {\n onErrRef.current?.(err)\n }\n } finally {\n setLoading(false)\n }\n }, [adapter, page, pageSize])\n\n useEffect(() => {\n void fetchOnce()\n }, [fetchOnce, refreshKey])\n\n // visibilitychange 重拉:从后台切回前台时拿到最新列表。\n useEffect(() => {\n if (typeof document === 'undefined') return\n const handler = () => {\n if (document.visibilityState === 'visible') void fetchOnce()\n }\n document.addEventListener('visibilitychange', handler)\n return () => document.removeEventListener('visibilitychange', handler)\n }, [fetchOnce])\n\n // 周期轮询。\n useEffect(() => {\n if (!pollMs || pollMs <= 0) return\n const id = setInterval(() => { void fetchOnce() }, pollMs)\n return () => clearInterval(id)\n }, [fetchOnce, pollMs])\n\n const refresh = useCallback(() => {\n void fetchOnce()\n }, [fetchOnce])\n\n const deleteSession = useCallback(\n async (id: number) => {\n if (!adapter?.deleteSession) return\n // 乐观更新。\n const prev = sessions\n setSessions(prev.filter(s => s.id !== id))\n try {\n await adapter.deleteSession(id)\n if (activeSessionId === id) {\n onActiveSessionRemoved?.(id)\n }\n // 删除可能跨页,刷一次以拿正确的 total / 当前页内容。\n void fetchOnce()\n } catch (err) {\n // 还原。\n setSessions(prev)\n setError(err)\n if (err instanceof ChatWidgetAuthError) {\n onAuthRef.current?.()\n } else {\n onErrRef.current?.(err)\n }\n throw err\n }\n },\n [adapter, sessions, activeSessionId, onActiveSessionRemoved, fetchOnce],\n )\n\n return {\n sessions,\n loading,\n page,\n totalPages,\n setPage,\n refresh,\n deleteSession,\n supported,\n canDelete,\n error,\n }\n}\n","import React, { useRef, useCallback, useImperativeHandle, forwardRef, useState } from 'react'\nimport type { FileReference, SkillSummary, UploadedFileInfo } from '../../types.js'\nimport { Icon } from '../Icon/Icon'\nimport { fileTypeIcon } from '../../utils/fileTypeIcon.js'\nimport './ContextBridge.css'\n\nexport interface RichInputHandle {\n insertChip: (ref: FileReference) => void\n insertSkillChip: (skill: SkillSummary) => void\n focus: () => void\n clear: () => void\n getText: () => string\n getReferences: () => FileReference[]\n getSkills: () => SkillSummary[]\n}\n\nexport interface RichInputProps {\n placeholder?: string\n disabled?: boolean\n onSubmit?: (text: string, references: FileReference[], skills: SkillSummary[]) => void\n onChipRemove?: (ref: FileReference) => void\n onSkillChipRemove?: (skill: SkillSummary) => void\n onSlashTrigger?: (prefix: string) => void\n onSlashDismiss?: () => void\n removeAriaLabel?: string\n skillRemoveAriaLabel?: string\n className?: string\n /** JETP-040: Callback when user selects local files for upload */\n onFilesSelected?: (files: File[]) => void\n /** JETP-040: Currently attached/uploading files */\n attachments?: UploadedFileInfo[]\n /** JETP-040: Remove an uploaded file attachment */\n onRemoveAttachment?: (resourceId: string) => void\n /** JETP-040: Whether file upload is supported (controls attach button visibility) */\n enableFileUpload?: boolean\n /** JETP-040: True while files are still uploading/processing — blocks send */\n isUploading?: boolean\n /**\n * 插在附件按钮(+)左侧的控件,例如 Agent 选择器。\n * 与 ``enableFileUpload`` 独立,保证顺序为:leading → 附件 → 输入区。\n */\n leadingControls?: React.ReactNode\n /**\n * 用于 ``getText()`` 序列化 skill chip 时的包裹模板。\n * 模板中的 ``{{name}}`` 会被替换为 ``{{SKILL:<displayName>}}`` 占位符,\n * 这样前端 ``parseUserMessage`` 仍能识别 chip 位置,\n * 同时上行 message text 自带模板前后缀(用户气泡 + 后端 prompt 同步)。\n * 不传则退化为只输出裸 ``{{SKILL:<displayName>}}``。\n */\n skillTextTemplate?: string\n}\n\nfunction createChipNode(ref: FileReference, onRemove: () => void, removeAriaLabel?: string): HTMLSpanElement {\n const chip = document.createElement('span')\n chip.className = 'ycw-cb-context-chip ycw-ri-chip'\n chip.contentEditable = 'false'\n chip.dataset.refJson = JSON.stringify(ref)\n chip.title = ref.selection?.text || ref.fileName\n\n const icon = document.createElement('span')\n icon.className = 'ycw-cb-chip-icon'\n icon.textContent = '📎'\n chip.appendChild(icon)\n\n const file = document.createElement('span')\n file.className = 'ycw-cb-chip-file'\n file.textContent = ref.fileName\n chip.appendChild(file)\n\n if (ref.selection?.startLine != null) {\n const line = document.createElement('span')\n line.className = 'ycw-cb-chip-line'\n const end = ref.selection.endLine\n line.textContent = end != null && end !== ref.selection.startLine\n ? `L${ref.selection.startLine}-${end}`\n : `L${ref.selection.startLine}`\n chip.appendChild(line)\n }\n\n if (ref.selection?.text) {\n const preview = document.createElement('span')\n preview.className = 'ycw-cb-chip-preview'\n const txt = ref.selection.text\n preview.textContent = txt.length > 40 ? txt.slice(0, 40) + '…' : txt\n chip.appendChild(preview)\n }\n\n const removeBtn = document.createElement('button')\n removeBtn.className = 'ycw-cb-chip-remove'\n removeBtn.textContent = '✕'\n removeBtn.type = 'button'\n if (removeAriaLabel) removeBtn.setAttribute('aria-label', removeAriaLabel)\n removeBtn.addEventListener('mousedown', (e) => {\n e.preventDefault()\n e.stopPropagation()\n onRemove()\n })\n chip.appendChild(removeBtn)\n\n return chip\n}\n\nfunction createSkillChipNode(skill: SkillSummary, onRemove: () => void, removeAriaLabel?: string): HTMLSpanElement {\n const chip = document.createElement('span')\n chip.className = 'ycw-cb-context-chip ycw-ri-chip ycw-ri-skill-chip'\n chip.contentEditable = 'false'\n chip.dataset.skillJson = JSON.stringify(skill)\n chip.title = skill.description || skill.displayName\n\n const label = document.createElement('span')\n label.className = 'ycw-ri-skill-chip-label'\n label.textContent = skill.displayName || skill.name\n chip.appendChild(label)\n\n const removeBtn = document.createElement('button')\n removeBtn.className = 'ycw-ri-chip-remove'\n removeBtn.textContent = '✕'\n removeBtn.type = 'button'\n if (removeAriaLabel) removeBtn.setAttribute('aria-label', removeAriaLabel)\n removeBtn.addEventListener('mousedown', (e) => {\n e.preventDefault()\n e.stopPropagation()\n onRemove()\n })\n chip.appendChild(removeBtn)\n\n return chip\n}\n\nconst ZWS = '\\u200B'\n\nconst RichInput = forwardRef<RichInputHandle, RichInputProps>(({\n placeholder = '',\n disabled = false,\n onSubmit,\n onChipRemove,\n onSkillChipRemove,\n onSlashTrigger,\n onSlashDismiss,\n removeAriaLabel,\n skillRemoveAriaLabel,\n className,\n onFilesSelected,\n attachments,\n onRemoveAttachment,\n enableFileUpload = false,\n isUploading = false,\n leadingControls,\n skillTextTemplate,\n}, ref) => {\n const skillTextTemplateRef = useRef(skillTextTemplate)\n skillTextTemplateRef.current = skillTextTemplate\n const editorRef = useRef<HTMLDivElement>(null)\n const fileInputRef = useRef<HTMLInputElement>(null)\n const dragCounterRef = useRef(0)\n const [isEmpty, setIsEmpty] = useState(true)\n const [isDragOver, setIsDragOver] = useState(false)\n\n const checkEmpty = useCallback(() => {\n const editor = editorRef.current\n if (!editor) return\n const raw = (editor.textContent ?? '').replace(/\\u200B/g, '').trim()\n const hasChips = editor.querySelector('.ycw-ri-chip') !== null\n setIsEmpty(!raw && !hasChips)\n }, [])\n\n const getReferences = useCallback((): FileReference[] => {\n const editor = editorRef.current\n if (!editor) return []\n const refs: FileReference[] = []\n editor.querySelectorAll('.ycw-ri-chip').forEach(chip => {\n try {\n const json = (chip as HTMLElement).dataset.refJson\n if (json) refs.push(JSON.parse(json))\n } catch { /* ignore corrupt chip */ }\n })\n return refs\n }, [])\n\n const getSkills = useCallback((): SkillSummary[] => {\n const editor = editorRef.current\n if (!editor) return []\n const skills: SkillSummary[] = []\n editor.querySelectorAll('.ycw-ri-skill-chip').forEach(chip => {\n try {\n const json = (chip as HTMLElement).dataset.skillJson\n if (json) skills.push(JSON.parse(json))\n } catch { /* ignore corrupt chip */ }\n })\n return skills\n }, [])\n\n const getText = useCallback((): string => {\n const editor = editorRef.current\n if (!editor) return ''\n let text = ''\n const walk = (node: Node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent ?? ''\n } else if (node.nodeType === Node.ELEMENT_NODE) {\n const el = node as HTMLElement\n if (el.classList.contains('ycw-ri-skill-chip')) {\n try {\n const skill: SkillSummary = JSON.parse(el.dataset.skillJson ?? '{}')\n const placeholder = `{{SKILL:${skill.displayName || skill.name}}}`\n const tpl = skillTextTemplateRef.current\n text += tpl ? tpl.replace(/\\{\\{name\\}\\}/g, placeholder) : placeholder\n } catch { /* fallback */ }\n return\n }\n if (el.classList.contains('ycw-ri-chip')) {\n try {\n const refData = JSON.parse(el.dataset.refJson ?? '{}')\n let marker = `[引用文件: ${refData.fileName}]`\n if (refData.selection?.startLine != null) {\n const range = refData.selection.endLine != null\n ? `${refData.selection.startLine}-${refData.selection.endLine}`\n : `${refData.selection.startLine}`\n marker += ` (L${range})`\n }\n if (refData.selection?.text) {\n marker += `\\n\\`\\`\\`\\n${refData.selection.text}\\n\\`\\`\\``\n }\n text += marker\n } catch { /* ignore corrupt chip */ }\n return\n }\n if (el.tagName === 'BR') { text += '\\n'; return }\n el.childNodes.forEach(walk)\n }\n }\n editor.childNodes.forEach(walk)\n return text.replace(/\\u200B/g, '').trim()\n }, [])\n\n const clear = useCallback(() => {\n const editor = editorRef.current\n if (!editor) return\n editor.innerHTML = ''\n checkEmpty()\n }, [checkEmpty])\n\n const focus = useCallback(() => {\n editorRef.current?.focus()\n }, [])\n\n const insertChip = useCallback((reference: FileReference) => {\n const editor = editorRef.current\n if (!editor) return\n\n const chip = createChipNode(reference, () => {\n chip.remove()\n checkEmpty()\n onChipRemove?.(reference)\n }, removeAriaLabel)\n\n const sel = window.getSelection()\n if (sel && sel.rangeCount > 0 && editor.contains(sel.anchorNode)) {\n const range = sel.getRangeAt(0)\n range.deleteContents()\n range.insertNode(chip)\n const spacer = document.createTextNode(ZWS)\n chip.after(spacer)\n range.setStartAfter(spacer)\n range.collapse(true)\n sel.removeAllRanges()\n sel.addRange(range)\n } else {\n const spacer = document.createTextNode(ZWS)\n editor.appendChild(chip)\n editor.appendChild(spacer)\n const range = document.createRange()\n range.setStartAfter(spacer)\n range.collapse(true)\n sel?.removeAllRanges()\n sel?.addRange(range)\n }\n\n editor.focus()\n checkEmpty()\n }, [checkEmpty])\n\n const insertSkillChip = useCallback((skill: SkillSummary) => {\n const editor = editorRef.current\n if (!editor) return\n\n const chip = createSkillChipNode(skill, () => {\n chip.remove()\n checkEmpty()\n onSkillChipRemove?.(skill)\n }, skillRemoveAriaLabel)\n\n const sel = window.getSelection()\n if (sel && sel.rangeCount > 0 && editor.contains(sel.anchorNode)) {\n const range = sel.getRangeAt(0)\n\n // Remove trailing slash trigger text (e.g. \"/ search text\")\n const textNode = sel.anchorNode\n if (textNode?.nodeType === Node.TEXT_NODE) {\n const content = textNode.textContent ?? ''\n const offset = sel.anchorOffset\n const beforeCursor = content.slice(0, offset)\n const slashIdx = beforeCursor.lastIndexOf('/')\n if (slashIdx >= 0) {\n const deleteRange = document.createRange()\n deleteRange.setStart(textNode, slashIdx)\n deleteRange.setEnd(textNode, offset)\n deleteRange.deleteContents()\n }\n }\n\n const freshRange = sel.getRangeAt(0)\n freshRange.insertNode(chip)\n const spacer = document.createTextNode(ZWS)\n chip.after(spacer)\n freshRange.setStartAfter(spacer)\n freshRange.collapse(true)\n sel.removeAllRanges()\n sel.addRange(freshRange)\n } else {\n const spacer = document.createTextNode(ZWS)\n editor.appendChild(chip)\n editor.appendChild(spacer)\n const range = document.createRange()\n range.setStartAfter(spacer)\n range.collapse(true)\n sel?.removeAllRanges()\n sel?.addRange(range)\n }\n\n editor.focus()\n checkEmpty()\n }, [checkEmpty, onSkillChipRemove, skillRemoveAriaLabel])\n\n useImperativeHandle(ref, () => ({\n insertChip,\n insertSkillChip,\n focus,\n clear,\n getText,\n getReferences,\n getSkills,\n }), [insertChip, insertSkillChip, focus, clear, getText, getReferences, getSkills])\n\n const handleInput = useCallback(() => {\n checkEmpty()\n\n if (!onSlashTrigger) return\n const sel = window.getSelection()\n if (!sel || sel.rangeCount === 0) { onSlashDismiss?.(); return }\n const node = sel.anchorNode\n if (!node || node.nodeType !== Node.TEXT_NODE) { onSlashDismiss?.(); return }\n\n const parent = node.parentElement\n if (parent?.classList.contains('ycw-ri-chip') || parent?.classList.contains('ycw-ri-skill-chip')) { onSlashDismiss?.(); return }\n\n const content = node.textContent ?? ''\n const offset = sel.anchorOffset\n const before = content.slice(0, offset)\n\n const slashIdx = before.lastIndexOf('/')\n if (slashIdx >= 0 && (slashIdx === 0 || before[slashIdx - 1] === ' ')) {\n const prefix = before.slice(slashIdx + 1)\n if (prefix.includes(' ')) {\n onSlashDismiss?.()\n } else {\n onSlashTrigger(prefix)\n }\n } else {\n onSlashDismiss?.()\n }\n }, [checkEmpty, onSlashTrigger, onSlashDismiss])\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n if (isUploading) return\n const text = getText()\n const refs = getReferences()\n const skills = getSkills()\n if (text || refs.length > 0 || skills.length > 0) {\n onSubmit?.(text, refs, skills)\n }\n }\n }, [getText, getReferences, getSkills, onSubmit, isUploading])\n\n const handlePaste = useCallback((e: React.ClipboardEvent) => {\n const files = Array.from(e.clipboardData.files)\n if (files.length > 0 && onFilesSelected) {\n e.preventDefault()\n onFilesSelected(files)\n return\n }\n e.preventDefault()\n const text = e.clipboardData.getData('text/plain')\n document.execCommand('insertText', false, text)\n const editor = editorRef.current\n if (editor) {\n requestAnimationFrame(() => {\n editor.scrollTop = editor.scrollHeight\n })\n }\n }, [onFilesSelected])\n\n const handleFileInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(e.target.files ?? [])\n if (files.length > 0) onFilesSelected?.(files)\n if (e.target) e.target.value = ''\n }, [onFilesSelected])\n\n const handleDragEnter = useCallback((e: React.DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n dragCounterRef.current++\n if (e.dataTransfer.types.includes('Files') || e.dataTransfer.types.includes('application/x-ycw-file-ref')) {\n setIsDragOver(true)\n }\n }, [])\n\n const handleDragOver = useCallback((e: React.DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n e.dataTransfer.dropEffect = 'copy'\n }, [])\n\n const handleDragLeave = useCallback((e: React.DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n dragCounterRef.current--\n if (dragCounterRef.current <= 0) {\n dragCounterRef.current = 0\n setIsDragOver(false)\n }\n }, [])\n\n const handleDrop = useCallback((e: React.DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n dragCounterRef.current = 0\n setIsDragOver(false)\n\n const wsRefData = e.dataTransfer.getData('application/x-ycw-file-ref')\n if (wsRefData) {\n try {\n const wsRef = JSON.parse(wsRefData) as FileReference\n const editor = editorRef.current\n if (!editor) return\n const chip = createChipNode(\n { ...wsRef, sessionId: wsRef.sessionId ?? 0 },\n () => { chip.remove(); checkEmpty(); onChipRemove?.(wsRef) },\n removeAriaLabel,\n )\n editor.appendChild(chip)\n editor.appendChild(document.createTextNode(ZWS))\n checkEmpty()\n } catch { /* invalid drop data */ }\n return\n }\n\n const files = Array.from(e.dataTransfer.files)\n if (files.length > 0 && onFilesSelected) {\n onFilesSelected(files)\n }\n }, [onFilesSelected, checkEmpty, onChipRemove, removeAriaLabel])\n\n const hasAttachments = attachments && attachments.length > 0\n\n return (\n <div\n className={`ycw-ri-container ${className || ''} ${disabled ? 'ycw-ri-disabled' : ''} ${isDragOver ? 'ycw-ri-drag-over' : ''}`}\n onClick={() => !disabled && editorRef.current?.focus()}\n onDragEnter={handleDragEnter}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n >\n {hasAttachments && (\n <div className=\"ycw-ri-attachments\">\n {attachments!.map(att => (\n <div key={att.resourceId || att.fileName} className={`ycw-ri-attachment-chip ycw-ri-attachment-${att.status}`}>\n <Icon name={fileTypeIcon(att.fileName)} size={16} weight=\"regular\" className=\"ycw-ri-attachment-icon\" />\n <div className=\"ycw-ri-attachment-info\">\n <span className=\"ycw-ri-attachment-name\">{att.fileName}</span>\n {att.gitPath && att.status === 'ready' && (\n <span className=\"ycw-ri-attachment-path\">{att.gitPath}</span>\n )}\n </div>\n <button\n type=\"button\"\n className=\"ycw-ri-attachment-remove\"\n onClick={(e) => { e.stopPropagation(); onRemoveAttachment?.(att.resourceId) }}\n aria-label=\"Remove attachment\"\n >\n <Icon name=\"x\" size={12} weight=\"bold\" />\n </button>\n </div>\n ))}\n </div>\n )}\n <div className=\"ycw-ri-editor-row\">\n {leadingControls ? (\n <div className=\"ycw-ri-leading-controls\" onClick={(e) => e.stopPropagation()}>\n {leadingControls}\n </div>\n ) : null}\n {enableFileUpload && (\n <button\n type=\"button\"\n className=\"ycw-ri-attach-btn\"\n onClick={(e) => { e.stopPropagation(); fileInputRef.current?.click() }}\n disabled={disabled}\n aria-label=\"Attach file\"\n title=\"Attach file\"\n >\n <Icon name=\"plus\" size={20} weight=\"regular\" />\n </button>\n )}\n <div className=\"ycw-ri-editor-wrap\">\n <div\n ref={editorRef}\n className=\"ycw-ri-editor\"\n contentEditable={!disabled}\n suppressContentEditableWarning\n onInput={handleInput}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n role=\"textbox\"\n aria-placeholder={placeholder}\n aria-disabled={disabled}\n />\n {isEmpty && !hasAttachments && <div className=\"ycw-ri-placeholder\">{placeholder}</div>}\n </div>\n </div>\n {enableFileUpload && (\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n className=\"ycw-ri-file-input\"\n onChange={handleFileInputChange}\n tabIndex={-1}\n />\n )}\n {isDragOver && (\n <div className=\"ycw-ri-drop-overlay\">\n <div className=\"ycw-ri-drop-content\">\n <Icon name=\"uploadSimple\" size={32} weight=\"light\" className=\"ycw-ri-drop-icon\" />\n <span className=\"ycw-ri-drop-text\">Drop files to attach</span>\n </div>\n </div>\n )}\n </div>\n )\n})\n\nRichInput.displayName = 'RichInput'\n\nexport default RichInput\n","/**\n * DefaultComposer — SDK 默认的对话输入组件。\n *\n * 把 RichInput + SkillSelector + useSkillOrchestration + 文件上传 + InteractionContext\n * 拼装成开箱即用的 footer composer。宿主只需要:\n *\n * <ChatWidget\n * ...\n * renderFooter={(api) => <DefaultComposer api={api} adapter={adapter} agentId={agentId} />}\n * />\n *\n * 之前 demo 端通过 deep import 内部模块自己拼装,现已收回为 SDK 公共组件,\n * 同时保留 deep import 路径不破坏既有调用方。\n */\nimport React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'\nimport RichInput from '../ContextBridge/RichInput.js'\nimport type { RichInputHandle } from '../ContextBridge/RichInput.js'\nimport { SkillSelector } from '../SkillSelector/SkillSelector.js'\nimport { useSkillOrchestration } from '../../hooks/useSkillOrchestration.js'\nimport { useChatWidgetI18n } from '../../i18n/context.js'\nimport { InteractionContext } from '../../hooks/useInteractionDispatch.js'\nimport { Icon } from '../Icon/Icon.js'\nimport type {\n SkillSummary,\n SelectedSkillRef,\n ChatWidgetAdapter,\n ChatWidgetAPI,\n FileReference,\n ModelOverride,\n} from '../../types.js'\nimport { ModelPicker } from './ModelPicker/index.js'\nimport type { ModelChoice } from './ModelPicker/index.js'\nimport { loadLastModelName, saveLastModelName } from './ModelPicker/index.js'\nimport { useAgentDefaultModel } from './ModelPicker/useAgentDefaultModel.js'\nimport './DefaultComposer.css'\n\nexport interface DefaultComposerProps {\n /** ChatWidget 通过 onReady 暴露的 API;DefaultComposer 内部据此发消息、订阅文件上传状态。 */\n api: ChatWidgetAPI | null\n /** 当前生效的 adapter,传给 useSkillOrchestration 拉取技能列表。 */\n adapter: ChatWidgetAdapter | null\n /**\n * 当用户提交时使用的 agentId。如果业务允许动态切换,请用 controlled props 在外层维护并传入。\n * 不传则不带 agentId(让 SDK 走默认)。\n */\n agentId?: string\n /**\n * 在输入行最前(「+」附件左侧)展示 Agent 下拉;与 ``agentId`` / ``onAgentIdChange`` 搭配使用。\n * 不传或空数组则不展示。\n */\n agentSelectOptions?: readonly { value: string; label: string }[]\n /** Agent 下拉变更时回调;提供 ``agentSelectOptions`` 时应传入以便受控更新。 */\n onAgentIdChange?: (agentId: string) => void\n /**\n * 是否处于忙碌态(running / compressing),决定 placeholder 与按钮是否可发送。\n * 通常由宿主从 ``onStatusChange`` 同步过来。\n */\n loading?: boolean\n /** 完全禁用输入。 */\n disabled?: boolean\n /**\n * 自定义提交 hook:返回 false 表示拦截发送(业务可在此做敏感词或字数校验等)。\n * 不传则直接调用 ``api.sendMessage``。\n */\n onBeforeSend?: (text: string, skills: SelectedSkillRef[]) => boolean | void\n /** 发送按钮文案;默认 'Send' / 加载中 '…'。 */\n sendLabel?: React.ReactNode\n /** 自定义 className,便于宿主套主题。 */\n className?: string\n /**\n * 是否启用 ModelPicker —— 在 agent 下拉旁边渲染一个\"本次发送使用的模型\"切换器。\n *\n * 三态:\n * · ``true``:始终渲染(adapter 不支持 ``listModels`` 时 ModelPicker 自身会降级到 inert 占位);\n * · ``false`` / 缺省:完全不渲染(向后兼容,老调用方零侵入);\n * · ``'auto'``:``adapter.listModels`` 为函数时渲染,否则不渲染。\n *\n * 数据&发送链路:\n * · 用 ``adapter.listModels({ groupBy:'basename' })`` 拉清单;\n * · 用 ``adapter.getAgentDefaultModel(agentId)`` 做\"agent 默认\"展示态定位;\n * · 用户选定后调 ``api.sendMessage(... , modelOverride={ name })``,\n * 由 adapter buildStreamBody 写入 body.model_override。\n *\n * 受控/非受控:见 ``modelValue`` / ``onModelChange``。\n */\n enableModelPicker?: boolean | 'auto'\n /**\n * 受控 modelChoice。``null`` = AUTO(不传 modelOverride,跟随 agent 默认)。\n * 不传时 DefaultComposer 走非受控模式,内部用 useState 管理,并按 ``agentId``\n * 持久化到 ``localStorage`` (``chat_widget_last_model_name:<agentId>``)。\n */\n modelValue?: ModelChoice\n onModelChange?: (next: ModelChoice) => void\n /**\n * 是否查询 ``adapter.getAgentDefaultModel`` 用于 ModelPicker 展示态定位。\n * 默认 true;游客态宿主可置 false 完全跳过请求。\n */\n enableAgentDefaultModelLookup?: boolean\n}\n\nconst DefaultComposer: React.FC<DefaultComposerProps> = ({\n api,\n adapter,\n agentId,\n agentSelectOptions,\n onAgentIdChange,\n loading = false,\n disabled = false,\n onBeforeSend,\n sendLabel,\n className,\n enableModelPicker = false,\n modelValue,\n onModelChange,\n enableAgentDefaultModelLookup = true,\n}) => {\n const fileUpload = api?.fileUpload\n const richInputRef = useRef<RichInputHandle>(null)\n const dispatch = useContext(InteractionContext)\n const { t } = useChatWidgetI18n()\n\n const resolvedAgentId = useMemo(() => {\n if (!agentSelectOptions?.length) return agentId\n if (agentId && agentSelectOptions.some((o) => o.value === agentId)) return agentId\n return agentSelectOptions[0].value\n }, [agentId, agentSelectOptions])\n\n // ModelPicker —— 受控/非受控自适应。\n // · 传入 modelValue(不为 undefined)→ 受控模式,外层负责持久化;\n // · 否则非受控模式,内部按 agentId 自动读写 localStorage(per-agent 桶)。\n const isControlled = modelValue !== undefined\n const [uncontrolledModel, setUncontrolledModel] = useState<ModelChoice>(() =>\n isControlled ? null : loadLastModelName(resolvedAgentId ?? ''),\n )\n // 切 agent 时把非受控的 modelChoice 切到该 agent 的 localStorage 值。\n useEffect(() => {\n if (isControlled) return\n setUncontrolledModel(loadLastModelName(resolvedAgentId ?? ''))\n }, [isControlled, resolvedAgentId])\n const currentModelChoice: ModelChoice = isControlled ? (modelValue ?? null) : uncontrolledModel\n const handleModelChange = useCallback(\n (next: ModelChoice) => {\n if (isControlled) {\n onModelChange?.(next)\n } else {\n setUncontrolledModel(next)\n if (resolvedAgentId) saveLastModelName(resolvedAgentId, next)\n onModelChange?.(next)\n }\n },\n [isControlled, onModelChange, resolvedAgentId],\n )\n\n const shouldRenderModelPicker = useMemo(() => {\n if (enableModelPicker === true) return true\n if (enableModelPicker === 'auto') {\n return !!adapter && typeof adapter.listModels === 'function'\n }\n return false\n }, [enableModelPicker, adapter])\n\n const agentDefaultModelLookupEnabled =\n enableAgentDefaultModelLookup && shouldRenderModelPicker\n const { info: agentDefaultModelInfo } = useAgentDefaultModel(\n adapter ?? ({} as ChatWidgetAdapter),\n agentDefaultModelLookupEnabled ? resolvedAgentId : undefined,\n { enabled: agentDefaultModelLookupEnabled && !!adapter },\n )\n\n useEffect(() => {\n if (!api) return\n api.setReferenceInsertHandler((ref: FileReference) => {\n richInputRef.current?.insertChip(ref)\n richInputRef.current?.focus()\n })\n return () => api.setReferenceInsertHandler(null)\n }, [api])\n\n const skill = useSkillOrchestration({ adapter, dispatch })\n\n const handleSlashTrigger = useCallback((prefix: string) => {\n if (skill.state.visible) {\n skill.handleSearch(prefix)\n } else {\n skill.handleSlashTrigger(prefix)\n }\n }, [skill])\n\n const handleSlashDismiss = useCallback(() => {\n if (skill.state.visible) skill.handleClose('blur')\n }, [skill])\n\n const handleSkillSelect = useCallback((s: SkillSummary) => {\n skill.handleSkillSelect(s)\n richInputRef.current?.insertSkillChip(s)\n richInputRef.current?.focus()\n }, [skill])\n\n const handleFilesSelected = useCallback((files: File[]) => {\n fileUpload?.addFiles(files)\n }, [fileUpload])\n\n const handleSubmit = useCallback((rawText: string, _refs: FileReference[], skills: SkillSummary[]) => {\n if (loading || !api) return\n const selectedSkills: SelectedSkillRef[] = skills.map(s => ({\n id: s.id,\n name: s.name,\n version: s.version,\n }))\n if (onBeforeSend) {\n const ok = onBeforeSend(rawText, selectedSkills)\n if (ok === false) return\n }\n // 只有 currentModelChoice 非空才下发 modelOverride;null = AUTO,保持原行为\n // (adapter.buildStreamBody 看到 null/缺省即不写 body.model_override)。\n const modelOverride: ModelOverride | null = currentModelChoice\n ? { name: currentModelChoice }\n : null\n // api.sendMessage 在如下场景会 reject(而非 resolve 后由 onError 通知):\n // - 当前 session 被后端拒绝(\"Session not allowed\"),ChatWidget 短路抛\n // InvalidClientIdError(reason='session_forbidden');\n // - 调用方传入了非 v2 client_id(reason='legacy_format');\n // - bootstrap 分配失败(reason='allocation_failed' / 'session_not_ready')。\n // composer 这里是 fire-and-forget,没有 await,必须显式 .catch 否则浏览器会\n // 抛 Unhandled Promise Rejection。错误已经在 ChatWidget 内部通过 onInteraction\n // / SessionForbiddenBanner 通知给宿主;这里只需安全吞掉,不要让用户看到红色控制台。\n void Promise.resolve(\n api.sendMessage(\n rawText,\n resolvedAgentId,\n undefined,\n selectedSkills,\n undefined,\n undefined,\n undefined,\n modelOverride,\n ),\n ).catch(() => {})\n richInputRef.current?.clear()\n richInputRef.current?.focus()\n }, [api, resolvedAgentId, loading, onBeforeSend, currentModelChoice])\n\n const handleKeyDownCapture = useCallback((e: React.KeyboardEvent) => {\n if (!skill.state.visible) return\n\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n e.stopPropagation()\n skill.state.moveDown(skill.data.skills.length)\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n e.stopPropagation()\n skill.state.moveUp(skill.data.skills.length)\n } else if (e.key === 'Enter' && !e.shiftKey) {\n const selected = skill.data.skills[skill.state.selectedIndex]\n if (selected) {\n e.preventDefault()\n e.stopPropagation()\n handleSkillSelect(selected)\n }\n } else if (e.key === 'Escape') {\n e.preventDefault()\n e.stopPropagation()\n skill.handleClose('escape')\n }\n }, [skill, handleSkillSelect])\n\n const placeholder = loading\n ? t('input.placeholderLoading')\n : t('input.placeholder')\n\n const agentSelectEl =\n agentSelectOptions && agentSelectOptions.length > 0 ? (\n <select\n className=\"ycw-composer-agent-select\"\n aria-label=\"Agent\"\n value={resolvedAgentId ?? ''}\n onChange={(e) => onAgentIdChange?.(e.target.value)}\n disabled={disabled || loading || !onAgentIdChange}\n >\n {agentSelectOptions.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n ) : null\n\n const modelPickerEl =\n shouldRenderModelPicker && adapter ? (\n <ModelPicker\n value={currentModelChoice}\n onChange={handleModelChange}\n adapter={adapter}\n disabled={disabled || loading}\n compact\n agentDefaultModelName={agentDefaultModelInfo?.name ?? null}\n />\n ) : null\n\n const agentLeading =\n agentSelectEl || modelPickerEl ? (\n <div className=\"ycw-composer-leading\">\n {agentSelectEl}\n {modelPickerEl}\n </div>\n ) : undefined\n\n const rootClass = className\n ? `ycw-composer ${className}`\n : 'ycw-composer'\n\n return (\n <div className={rootClass} onKeyDownCapture={handleKeyDownCapture}>\n <div className=\"ycw-composer-input-wrapper\">\n <SkillSelector\n visible={skill.state.visible}\n skills={skill.data.skills}\n loading={skill.data.loading}\n error={skill.data.error}\n selectedIndex={skill.state.selectedIndex}\n hasMore={skill.data.hasMore}\n emptyText={t('skill.empty')}\n loadingText={t('skill.loading')}\n errorText={t('skill.loadError')}\n loadMoreText={t('skill.loadMore')}\n selectorLabel={t('skill.selectorLabel')}\n onSelect={handleSkillSelect}\n onClose={() => skill.handleClose('blur')}\n onLoadMore={skill.data.loadMore}\n />\n <RichInput\n ref={richInputRef}\n placeholder={placeholder}\n disabled={disabled || loading}\n onSubmit={handleSubmit}\n onSlashTrigger={handleSlashTrigger}\n onSlashDismiss={handleSlashDismiss}\n skillRemoveAriaLabel={t('skill.removeLabel')}\n skillTextTemplate={t('skill.inlineLabel')}\n enableFileUpload={!!fileUpload?.enabled}\n onFilesSelected={handleFilesSelected}\n attachments={fileUpload?.attachments}\n onRemoveAttachment={fileUpload?.removeFile}\n isUploading={fileUpload?.isUploading}\n leadingControls={agentLeading}\n />\n </div>\n {renderActionButton()}\n </div>\n )\n\n /**\n * 渲染右下角动作按钮 —— 与 ChatGPT / Claude / Cursor 一致的\"Send ↔ Stop\"形态切换:\n *\n * - 空闲态:Send 按钮(旧行为)\n * - loading 态 + api.stopAgent 存在:Stop 按钮(红色调,点击触发协作式停止)\n * - loading 态 + api.stopAgent 不存在(旧 adapter 不支持):Send disabled \"…\"(旧行为,向后兼容)\n * - isUploading:Send disabled(旧行为,避免文件半传中途打断)\n *\n * 错误处理:api.stopAgent 内部已 catch 网络错误,本组件无需再 try/catch。\n */\n function renderActionButton() {\n const canStop = loading && typeof api?.stopAgent === 'function' && !fileUpload?.isUploading\n if (canStop) {\n return (\n <button\n type=\"button\"\n className=\"ycw-composer-send-btn ycw-composer-send-btn--stop\"\n onClick={() => { void api!.stopAgent!() }}\n disabled={disabled}\n title={t('agentControl.stop')}\n aria-label={t('agentControl.stop')}\n >\n <Icon name=\"stop\" size={14} aria-hidden />\n <span>{t('agentControl.stop')}</span>\n </button>\n )\n }\n return (\n <button\n type=\"button\"\n className=\"ycw-composer-send-btn\"\n onClick={() => {\n const text = richInputRef.current?.getText() ?? ''\n const skills = richInputRef.current?.getSkills() ?? []\n if (text || skills.length > 0) {\n handleSubmit(text, [], skills)\n }\n }}\n disabled={disabled || loading || !!fileUpload?.isUploading}\n >\n {loading ? (sendLabel ?? '…') : (sendLabel ?? 'Send')}\n </button>\n )\n }\n}\n\nexport default DefaultComposer\n","/**\n * SkillSelector — pure rendering component (JETP-032).\n *\n * Receives all data and callbacks as props; contains zero business logic.\n * All state management lives in useSkillOrchestration.\n */\n\nimport React, { useEffect, useRef } from 'react'\nimport type { SkillSummary } from '../../types.js'\nimport './SkillSelector.css'\n\nexport interface SkillSelectorProps {\n visible: boolean\n skills: SkillSummary[]\n loading: boolean\n error: string | null\n selectedIndex: number\n hasMore: boolean\n emptyText: string\n loadingText: string\n errorText: string\n loadMoreText: string\n selectorLabel: string\n onSelect: (skill: SkillSummary) => void\n onClose: () => void\n onLoadMore: () => void\n renderSkillIcon?: (skill: SkillSummary) => React.ReactNode\n}\n\nexport const SkillSelector: React.FC<SkillSelectorProps> = React.memo(function SkillSelector({\n visible,\n skills,\n loading,\n error,\n selectedIndex,\n hasMore,\n emptyText,\n loadingText,\n errorText,\n loadMoreText,\n selectorLabel,\n onSelect,\n onClose: _onClose,\n onLoadMore,\n renderSkillIcon,\n}) {\n const listRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (!visible || selectedIndex < 0) return\n const container = listRef.current\n if (!container) return\n const active = container.querySelector('.ycw-skill-selector-item-active') as HTMLElement | null\n active?.scrollIntoView({ block: 'nearest' })\n }, [visible, selectedIndex])\n\n if (!visible) return null\n\n return (\n <div\n ref={listRef}\n className=\"ycw-skill-selector\"\n role=\"listbox\"\n aria-label={selectorLabel}\n >\n {error && (\n <div className=\"ycw-skill-selector-error\">{errorText}</div>\n )}\n\n {loading && skills.length === 0 && !error && (\n <div className=\"ycw-skill-selector-loading\">{loadingText}</div>\n )}\n\n {!loading && !error && skills.length === 0 && (\n <div className=\"ycw-skill-selector-empty\">{emptyText}</div>\n )}\n\n {skills.map((skill, idx) => (\n <div\n key={skill.id}\n id={`ycw-skill-item-${skill.id}`}\n className={`ycw-skill-selector-item${idx === selectedIndex ? ' ycw-skill-selector-item-active' : ''}`}\n role=\"option\"\n aria-selected={idx === selectedIndex}\n onMouseDown={(e) => {\n e.preventDefault()\n onSelect(skill)\n }}\n >\n <span className=\"ycw-skill-selector-item-name\">\n {renderSkillIcon ? renderSkillIcon(skill) : null}\n {skill.displayName || skill.name}\n </span>\n {skill.description && (\n <span className=\"ycw-skill-selector-item-desc\">{skill.description}</span>\n )}\n </div>\n ))}\n\n {hasMore && !loading && (\n <div\n className=\"ycw-skill-selector-load-more\"\n onMouseDown={(e) => {\n e.preventDefault()\n onLoadMore()\n }}\n >\n {loadMoreText}\n </div>\n )}\n\n {loading && skills.length > 0 && (\n <div className=\"ycw-skill-selector-loading\">{loadingText}</div>\n )}\n </div>\n )\n})\n","/**\n * useSkillOrchestration — orchestration layer for skill selector (JETP-032).\n *\n * Composes useSkillData + useSkillSelectorState, connects to RichInput\n * (via ref), and dispatches InteractionEvents through the provided dispatch.\n */\n\nimport { useCallback, useRef } from 'react'\nimport type { SkillSummary, ChatWidgetAdapter, ChatWidgetInteractionEvent } from '../types.js'\nimport { useSkillData } from './useSkillData.js'\nimport type { UseSkillDataReturn } from './useSkillData.js'\nimport { useSkillSelectorState } from './useSkillSelectorState.js'\nimport type { UseSkillSelectorStateReturn } from './useSkillSelectorState.js'\nimport { useChatWidgetI18n } from '../i18n/context.js'\nimport { interpolate } from '../i18n/messages.js'\n\nexport interface UseSkillOrchestrationOptions {\n adapter: ChatWidgetAdapter | null\n dispatch?: ((event: ChatWidgetInteractionEvent) => void) | null\n}\n\nexport interface UseSkillOrchestrationReturn {\n data: UseSkillDataReturn\n state: UseSkillSelectorStateReturn\n handleSlashTrigger: (prefix: string) => void\n handleSkillSelect: (skill: SkillSummary) => void\n handleClose: (reason: 'escape' | 'blur' | 'select') => void\n handleSearch: (text: string) => void\n buildEnrichedText: (rawText: string) => string\n selectedSkillsRef: React.MutableRefObject<SkillSummary[]>\n}\n\nconst PLACEHOLDER_RE = /\\{\\{SKILL:(.+?)\\}\\}/g\n\nexport function useSkillOrchestration(options: UseSkillOrchestrationOptions): UseSkillOrchestrationReturn {\n const { adapter, dispatch } = options\n const { messages } = useChatWidgetI18n()\n const data = useSkillData({ adapter })\n const state = useSkillSelectorState()\n const selectedSkillsRef = useRef<SkillSummary[]>([])\n\n const emit = useCallback((type: ChatWidgetInteractionEvent['type'], target: string, metadata?: Record<string, unknown>) => {\n dispatch?.({ type, target, metadata, timestamp: Date.now() })\n }, [dispatch])\n\n const handleSlashTrigger = useCallback((prefix: string) => {\n emit('skill-popup-open', 'skill-selector', { trigger: 'slash' })\n data.search(prefix)\n state.open(data.skills.length)\n }, [emit, data, state])\n\n const handleSkillSelect = useCallback((skill: SkillSummary) => {\n selectedSkillsRef.current = [...selectedSkillsRef.current, skill]\n emit('skill-select', skill.id, { skillId: skill.id, skillName: skill.displayName })\n handleClose('select')\n }, [emit])\n\n const handleClose = useCallback((reason: 'escape' | 'blur' | 'select') => {\n state.close()\n data.reset()\n emit('skill-popup-close', 'skill-selector', { reason })\n }, [state, data, emit])\n\n const handleSearch = useCallback((text: string) => {\n data.search(text)\n emit('skill-search', 'skill-selector', { searchText: text })\n }, [data, emit])\n\n const buildEnrichedText = useCallback((rawText: string): string => {\n return rawText.replace(PLACEHOLDER_RE, (_match, name: string) => {\n const template = messages['skill.inlineLabel'] ?? '{{name}}'\n return interpolate(template, { name })\n })\n }, [messages])\n\n return {\n data,\n state,\n handleSlashTrigger,\n handleSkillSelect,\n handleClose,\n handleSearch,\n buildEnrichedText,\n selectedSkillsRef,\n }\n}\n","/**\n * useSkillData — data-fetching layer for skill selector (JETP-032).\n *\n * Manages: API calls to adapter.listSkills, debounced search,\n * pagination (append + dedupe), loading/error states.\n * Does NOT manage: UI visibility, keyboard navigation, or DOM.\n */\n\nimport { useState, useCallback, useRef, useEffect } from 'react'\nimport type { SkillSummary, SkillListResponse, ChatWidgetAdapter } from '../types.js'\n\nexport interface UseSkillDataOptions {\n adapter: ChatWidgetAdapter | null\n debounceMs?: number\n}\n\nexport interface UseSkillDataReturn {\n skills: SkillSummary[]\n loading: boolean\n error: string | null\n total: number\n hasMore: boolean\n search: (text: string) => void\n loadMore: () => void\n reset: () => void\n}\n\nexport function useSkillData(options: UseSkillDataOptions): UseSkillDataReturn {\n const { adapter, debounceMs = 300 } = options\n const [skills, setSkills] = useState<SkillSummary[]>([])\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [total, setTotal] = useState(0)\n const pageRef = useRef(1)\n const searchRef = useRef('')\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const fetchSkills = useCallback(async (searchText: string, page: number, append: boolean) => {\n if (!adapter?.listSkills) return\n setLoading(true)\n setError(null)\n try {\n const result: SkillListResponse = await adapter.listSkills({\n search: searchText || undefined,\n page,\n pageSize: 20,\n })\n setTotal(result.total)\n if (append) {\n setSkills((prev) => {\n const ids = new Set(prev.map((s) => s.id))\n const deduped = result.skills.filter((s) => !ids.has(s.id))\n return [...prev, ...deduped]\n })\n } else {\n setSkills(result.skills)\n }\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n setLoading(false)\n }\n }, [adapter])\n\n const search = useCallback((text: string) => {\n searchRef.current = text\n pageRef.current = 1\n if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current)\n debounceTimerRef.current = setTimeout(() => {\n fetchSkills(text, 1, false)\n }, debounceMs)\n }, [fetchSkills, debounceMs])\n\n const loadMore = useCallback(() => {\n if (loading) return\n pageRef.current += 1\n fetchSkills(searchRef.current, pageRef.current, true)\n }, [fetchSkills, loading])\n\n const reset = useCallback(() => {\n searchRef.current = ''\n pageRef.current = 1\n setSkills([])\n setTotal(0)\n setError(null)\n setLoading(false)\n if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current)\n }, [])\n\n useEffect(() => {\n return () => {\n if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current)\n }\n }, [])\n\n const hasMore = skills.length < total\n\n return { skills, loading, error, total, hasMore, search, loadMore, reset }\n}\n","/**\n * useSkillSelectorState — UI-state layer for skill selector (JETP-032).\n *\n * Manages: popup visibility, selected item index, keyboard navigation.\n * Does NOT manage: data fetching, adapter calls, or DOM insertion.\n */\n\nimport { useState, useCallback } from 'react'\n\nexport interface UseSkillSelectorStateReturn {\n visible: boolean\n selectedIndex: number\n open: (itemCount: number) => void\n close: () => void\n moveDown: (itemCount: number) => void\n moveUp: (itemCount: number) => void\n setSelectedIndex: (idx: number) => void\n}\n\nexport function useSkillSelectorState(): UseSkillSelectorStateReturn {\n const [visible, setVisible] = useState(false)\n const [selectedIndex, setSelectedIndex] = useState(0)\n\n const open = useCallback((_itemCount: number) => {\n setVisible(true)\n setSelectedIndex(0)\n }, [])\n\n const close = useCallback(() => {\n setVisible(false)\n setSelectedIndex(0)\n }, [])\n\n const moveDown = useCallback((itemCount: number) => {\n setSelectedIndex((prev) => (prev + 1) % Math.max(itemCount, 1))\n }, [])\n\n const moveUp = useCallback((itemCount: number) => {\n setSelectedIndex((prev) => (prev - 1 + Math.max(itemCount, 1)) % Math.max(itemCount, 1))\n }, [])\n\n return { visible, selectedIndex, open, close, moveDown, moveUp, setSelectedIndex }\n}\n","/**\n * ModelPicker —— 紧凑型 \"本次发送使用的模型\" 切换器。\n *\n * 使用:\n * <ModelPicker value={modelName} onChange={setModelName} adapter={adapter} compact />\n *\n * 语义(与 chat-widget 的 ``ModelOverride`` 对齐):\n * · ``value === null`` → AUTO,不传 modelOverride,使用 agent 注册的默认模型;\n * · ``value === 'claude-opus-4-6'`` / ``'qwen__qwen3-max'`` → 发送时透传\n * ``modelOverride.name``(完整 model_name,原样回传给 hip / model-lake)。\n *\n * 数据:``adapter.listModels({ groupBy: 'basename' })``。每条 item 是一个物理模型\n * basename,下挂多个 ``variants`` 对应实际渠道。UI 层呈现:\n * · 行主体显示 basename(如 ``qwen3-max``);\n * · 多渠道时右侧展开 chip 列让用户挑(``ali`` / ``openrouter`` 等);\n * · 单渠道时直接以 chip 形式静态显示,避免假动作。\n *\n * 不做的事(避免过度设计):\n * · 不分组(按 vendor / 按模态)—— 当前清单数十项,扁平 + chip 就够;\n * · 不做\"按 agent 推荐\"—— picker 只暴露硬覆盖,\"推荐\"属于 agent 默认 ModelMeta。\n *\n * 视觉风格刻意复用 AgentPicker.css 的 token / class —— 避免引入第二套尺寸基线。\n */\nimport { useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport { Icon } from '../../Icon/Icon.js'\nimport { useChatWidgetI18n } from '../../../i18n/context.js'\nimport type { ChatWidgetAdapter, ModelListVariant } from '../../../types.js'\nimport { useModels } from './useModels.js'\nimport { type ModelChoice, modelBasename, isShowModelChannels } from './modelRegistry.js'\nimport './AgentPicker.css'\nimport './ModelPicker.css'\n\nexport interface ModelPickerProps {\n /** 当前选择;null = AUTO(跟随 agent 默认) */\n value: ModelChoice\n onChange: (next: ModelChoice) => void\n adapter: ChatWidgetAdapter\n disabled?: boolean\n compact?: boolean\n /**\n * 当前 agent 在后端注册的默认模型 ``name`` —— **仅用于 picker 展示态**。\n *\n * 行为分两条线,必须分清:\n * · **展示态**:``value == null`` 且本字段命中清单时,trigger 文案 + AUTO 行 hint\n * 都自动定位到该模型,让用户一眼看到\"当前 agent 实际会用哪个 model\"。\n * · **发送态**:``value == null`` 时**永远**不带 ``modelOverride``,由后端按 agent 默认走。\n *\n * null / undefined / 没命中清单 → picker 退化为\"显示『默认模型』占位\"。\n */\n agentDefaultModelName?: string | null\n /**\n * 是否允许触发 listModels 请求。默认 true。\n * 游客态(未登录)使用:传 false → 内部 useModels enabled=false 不发请求,\n * 同时 trigger 走 inert 分支,hover 提示\"登录后可选模型\"。\n */\n enabled?: boolean\n}\n\n/** AUTO 项的稳定 key(不会与任何真实 model name 冲突,因为 model name 都是裸字符串) */\nconst AUTO_KEY = '__auto__'\n\ninterface MenuRow {\n key: string\n /** AUTO 行 = null;basename 行 = 第一个 available variant.name;选中 chip = 对应 variant.name */\n defaultChoice: ModelChoice\n title: string\n hint: string\n /**\n * basename 下的所有渠道变体;空数组 = AUTO 行。\n * 注意:``variants[i].name`` 已经是完整 model_name(含 ``__`` 前缀),可直接 onChange。\n *\n * **保留全部 variants(含不可用)**:内部 / 调试模式下 chip 区把不可用项置灰展示,\n * 让调试者一眼看到上游挂掉的渠道;对外模式根本不渲染 chip 区,只用 ``defaultChoice``。\n */\n variants: ModelListVariant[]\n}\n\n/**\n * variant.available 的\"非显式 false 即可用\"判定:与 hip 端 fail-safe 契约对齐。\n * - undefined → true(老版本 hip / 未联表 / status 接口故障 → fail-safe 当可用)\n * - true → true\n * - false → false(**唯一会被前端过滤掉**的情况)\n */\nfunction isVariantAvailable(v: ModelListVariant): boolean {\n return v.available !== false\n}\n\nexport function ModelPicker({\n value,\n onChange,\n adapter,\n disabled,\n compact,\n agentDefaultModelName,\n enabled = true,\n}: ModelPickerProps) {\n const { items, loading, error } = useModels(adapter, { enabled })\n const [open, setOpen] = useState(false)\n const wrapperRef = useRef<HTMLDivElement>(null)\n const triggerRef = useRef<HTMLButtonElement>(null)\n const menuId = useId()\n const { t } = useChatWidgetI18n()\n\n // \"是否暴露上游 channel/供应商\" 的运行时开关(env + localStorage 覆盖)。\n // 详见 modelRegistry.ts::isShowModelChannels。\n const showChannels = useMemo(() => isShowModelChannels(), [])\n\n /**\n * 在清单里按 model name 反查 (basename, channel)。\n * 两段匹配策略(次序很关键,不能颠倒):\n * 1. **严格相等**:用户主动选定的 variant 必须命中此分支,保留 channel 不被归一化覆盖。\n * 2. **basename 归一化**:jetagents 那侧 ``vendor/model`` 与 model-lake ``provider__model``\n * / 裸 ``model`` 都视为同一物理模型,靠 ``modelBasename`` 末段对比命中。\n * 命中后 channel 取该 basename 的 ``defaultVariant.channel``——语义是\n * \"该物理模型在我们清单里默认走哪个渠道\"。\n *\n * 注意:第二段匹配只用于**展示**,不影响发送。``value == null`` 永远不带 modelOverride。\n */\n const lookupName = useCallback(\n (name: string | null | undefined): { basename: string; channel: string } | null => {\n if (!name) return null\n for (const m of items) {\n const v = m.variants.find((x) => x.name === name)\n if (v) return { basename: m.basename, channel: v.channel }\n }\n const targetBase = modelBasename(name)\n for (const m of items) {\n if (m.basename === targetBase) {\n return { basename: m.basename, channel: m.defaultVariant.channel }\n }\n }\n return null\n },\n [items],\n )\n\n /** value 命中(用户主动选了某个 model) */\n const matched = useMemo(() => lookupName(value), [lookupName, value])\n /** agent 默认命中(用户没主动选时,picker 自动定位的目标) */\n const agentDefault = useMemo(() => lookupName(agentDefaultModelName), [lookupName, agentDefaultModelName])\n\n const rows: MenuRow[] = useMemo(() => {\n const autoHint =\n value == null && agentDefault\n ? showChannels\n ? t('modelPicker.auto.hint.knownChannel', {\n name: agentDefault.basename,\n channel: agentDefault.channel,\n })\n : t('modelPicker.auto.hint.knownBasename', { name: agentDefault.basename })\n : t('modelPicker.auto.hint.fallback')\n const head: MenuRow = {\n key: AUTO_KEY,\n defaultChoice: null,\n title: t('modelPicker.auto.title'),\n hint: autoHint,\n variants: [],\n }\n const list = items\n .map((m) => {\n const availableVariants = m.variants.filter(isVariantAvailable)\n return { m, availableVariants }\n })\n .filter(({ m, availableVariants }) => {\n if (m.anyAvailable === false) return false\n if (availableVariants.length === 0) return false\n return true\n })\n .map<MenuRow>(({ m, availableVariants }) => {\n let hint = ''\n if (showChannels) {\n hint =\n m.variants.length > 1\n ? t('modelPicker.row.hint.channelMulti', {\n available: availableVariants.length,\n total: m.variants.length,\n })\n : t('modelPicker.row.hint.channelSingle', {\n channel: m.defaultVariant.channel || '-',\n })\n } else if (availableVariants.length > 1) {\n hint = t('modelPicker.row.hint.versionMulti', { count: availableVariants.length })\n }\n return {\n key: m.basename,\n defaultChoice: availableVariants[0].name,\n title: m.basename,\n hint,\n variants: m.variants,\n }\n })\n return [head, ...list]\n }, [items, value, agentDefault, showChannels, t])\n\n /**\n * trigger 文案的\"显示 vs. 发送\"分裂:\n * · 用户选了(value!=null) → 主标签 = 选中 model 的 basename,副标签 = channel(仅 showChannels);\n * · 没选(AUTO) + agent 默认命中 → 主标签 = \"默认模型\" 占位,\n * 副标签 = agent 默认 basename(小字提示,让用户能看出实际会用什么,但不会和\"用户选了它\"混淆);\n * · 没选 + agent 默认未知 → 仅\"默认模型\" 占位。\n * 关键约束:本组件 ``onChange`` 在 value==null 时永不被自动调用,\n * 即\"看到的\"和\"发的\"两条线严格分开(AUTO 永远不带 modelOverride,\n * 不论副标签显示的是哪个 basename)。\n */\n const isAuto = value == null\n\n const currentLabel = isAuto\n ? t('modelPicker.fallback.placeholder')\n : (matched?.basename ?? value ?? t('modelPicker.fallback.placeholder'))\n\n // 副标签策略:\n // · AUTO + 有 agent 默认 → agent 默认 basename(让用户一眼看出实际会用什么,但跟主标签\n // \"默认模型\" 一起视觉上就是 \"默认(实际用:xxx)\",不会被误以为是用户选的);\n // · 用户选了 + showChannels → channel;\n // · 其他 → 不显示副标签。\n const currentSubLabel = isAuto\n ? agentDefault?.basename\n : (showChannels && matched?.channel ? matched.channel : undefined)\n\n const isStale = value != null && items.length > 0 && matched == null\n\n /**\n * 弹窗\"不能越过的上沿\":优先取最近的 ``[data-picker-boundary]`` 容器(HeroComposer\n * 的 shell),保证菜单永远落在 composer 内部、不遮挡输入框;\n * 找不到边界时**不设** inline ``maxHeight``,把决定权交回 AgentPicker.css 里的\n * fallback (``min(48vh, 360px)``) —— 这样像 chat-widget demo 这种没有 boundary 容器\n * 的宿主,菜单也不会铺满全屏。\n *\n * 找到 boundary 时再额外 clamp 到 360px 上限,避免大屏 hero 也把菜单撑得过高\n * (超过约 6-7 行后视觉重心反而失衡,菜单内部滚动更舒服)。\n */\n const [maxMenuH, setMaxMenuH] = useState<number | null>(null)\n useLayoutEffect(() => {\n if (!open) return\n const compute = () => {\n const trigger = triggerRef.current\n if (!trigger) return\n const boundary = trigger.closest('[data-picker-boundary]') as HTMLElement | null\n if (!boundary) {\n // 没有显式边界 → 让 CSS fallback 接管,避免 inline style 把 360px 上限抹掉。\n setMaxMenuH(null)\n return\n }\n const triggerTop = trigger.getBoundingClientRect().top\n const boundaryTop = boundary.getBoundingClientRect().top\n // gap (8px:menu 与 trigger 间距) + 内边距余量 8px = 16px\n const available = triggerTop - boundaryTop - 16\n // 下限 160px:太矮反而不可用;上限 360px:与 AgentPicker.css fallback 对齐。\n setMaxMenuH(Math.min(360, Math.max(160, available)))\n }\n compute()\n window.addEventListener('resize', compute)\n return () => window.removeEventListener('resize', compute)\n }, [open])\n\n const [activeIdx, setActiveIdx] = useState<number>(0)\n useEffect(() => {\n if (!open) return\n if (value == null) {\n setActiveIdx(0)\n return\n }\n const idx = items.findIndex((m) => m.variants.some((v) => v.name === value))\n setActiveIdx(idx >= 0 ? idx + 1 : 0)\n }, [open, items, value])\n\n useEffect(() => {\n if (!open) return\n const onDocDown = (e: MouseEvent) => {\n if (!wrapperRef.current?.contains(e.target as Node)) setOpen(false)\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setOpen(false)\n triggerRef.current?.focus()\n }\n }\n document.addEventListener('mousedown', onDocDown)\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('mousedown', onDocDown)\n document.removeEventListener('keydown', onKey)\n }\n }, [open])\n\n const select = useCallback(\n (row: MenuRow) => {\n onChange(row.defaultChoice)\n setOpen(false)\n triggerRef.current?.focus()\n },\n [onChange],\n )\n\n const selectVariant = useCallback(\n (variant: ModelListVariant) => {\n onChange(variant.name)\n setOpen(false)\n triggerRef.current?.focus()\n },\n [onChange],\n )\n\n const onTriggerKey = (e: React.KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n setOpen(true)\n }\n }\n\n const onMenuKey = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setActiveIdx((i) => (i + 1) % rows.length)\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n setActiveIdx((i) => (i - 1 + rows.length) % rows.length)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n const row = rows[activeIdx]\n if (row) select(row)\n }\n }\n\n const inert =\n !enabled ||\n typeof adapter.listModels !== 'function' ||\n (!loading && error != null && rows.length <= 1)\n\n if (inert) {\n const inertTitle = enabled\n ? t('modelPicker.inert.title')\n : t('modelPicker.guestLocked.title')\n return (\n <div className={`ycw-agent-picker${compact ? ' ycw-agent-picker--compact' : ''}`}>\n <button\n type=\"button\"\n className=\"ycw-agent-picker__trigger\"\n disabled\n title={inertTitle}\n data-testid={enabled ? 'model-picker-inert' : 'model-picker-guest-locked'}\n >\n <Icon name=\"cpu\" size={14} />\n <span className=\"ycw-agent-picker__name\">\n {enabled\n ? t('modelPicker.fallback.placeholder')\n : t('modelPicker.guestLocked.label')}\n </span>\n </button>\n </div>\n )\n }\n\n return (\n <div\n ref={wrapperRef}\n className={`ycw-agent-picker${compact ? ' ycw-agent-picker--compact' : ''}${open ? ' ycw-agent-picker--open' : ''}`}\n >\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"ycw-agent-picker__trigger\"\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-controls={menuId}\n disabled={disabled}\n onClick={() => setOpen((o) => !o)}\n onKeyDown={onTriggerKey}\n title={\n isStale\n ? t('modelPicker.trigger.title.stale', { name: currentLabel })\n : isAuto && agentDefault\n ? showChannels && agentDefault.channel\n ? t('modelPicker.trigger.title.agentDefault.withChannel', {\n name: agentDefault.basename,\n channel: agentDefault.channel,\n })\n : t('modelPicker.trigger.title.agentDefault', { name: agentDefault.basename })\n : t('modelPicker.trigger.title.current', { name: currentLabel })\n }\n >\n <Icon name=\"cpu\" size={14} />\n <span className=\"ycw-agent-picker__name\">\n {currentLabel}\n {currentSubLabel && (\n <span className=\"ycw-model-picker__trigger-channel\"> · {currentSubLabel}</span>\n )}\n </span>\n <Icon name=\"chevronDown\" size={12} className=\"ycw-agent-picker__chev\" />\n </button>\n\n {open && (\n <div\n id={menuId}\n className=\"ycw-agent-picker__menu\"\n role=\"listbox\"\n aria-label={t('modelPicker.menu.aria')}\n tabIndex={-1}\n onKeyDown={onMenuKey}\n style={maxMenuH != null ? { maxHeight: `${maxMenuH}px` } : undefined}\n >\n <div className=\"ycw-agent-picker__menu-head\">{t('modelPicker.menu.head')}</div>\n {loading && rows.length <= 1 && (\n <div className=\"ycw-agent-picker__item is-disabled\" role=\"option\" aria-disabled>\n <span className=\"ycw-agent-picker__item-icon\">\n <Icon name=\"cpu\" size={16} />\n </span>\n <span className=\"ycw-agent-picker__item-body\">\n <span className=\"ycw-agent-picker__item-title\">{t('modelPicker.loadingList')}</span>\n </span>\n </div>\n )}\n {rows.map((row, idx) => {\n const isAuto = row.variants.length === 0\n const isCurrent = isAuto\n ? value == null\n : matched?.basename === row.title\n const isActive = idx === activeIdx\n return (\n <div\n key={row.key}\n className={`ycw-agent-picker__item ycw-model-picker__row${isActive ? ' is-active' : ''}${isCurrent ? ' is-current' : ''}`}\n role=\"option\"\n aria-selected={isCurrent}\n onMouseEnter={() => setActiveIdx(idx)}\n >\n <button\n type=\"button\"\n className=\"ycw-model-picker__row-main\"\n onClick={() => select(row)}\n title={\n isAuto\n ? row.hint\n : showChannels\n ? t('modelPicker.row.title.pickDefault', { hint: row.hint || row.title })\n : t('modelPicker.row.title.pick', { name: row.title })\n }\n >\n <span className=\"ycw-agent-picker__item-icon\">\n <Icon name={isAuto ? 'sparkle' : 'cpu'} size={16} />\n </span>\n <span className=\"ycw-agent-picker__item-body\">\n <span className=\"ycw-agent-picker__item-title\">\n {row.title}\n {isCurrent && (\n <span className=\"ycw-agent-picker__current\" aria-hidden>\n ✓\n </span>\n )}\n </span>\n {row.hint && (\n <span className=\"ycw-agent-picker__item-desc\">{row.hint}</span>\n )}\n </span>\n </button>\n {showChannels && !isAuto && row.variants.length > 1 && (\n <div\n className=\"ycw-model-picker__chips\"\n role=\"group\"\n aria-label={t('modelPicker.chip.aria', { title: row.title })}\n >\n {row.variants.map((v) => {\n const chipActive = matched?.basename === row.title && matched.channel === v.channel\n const chipAvailable = isVariantAvailable(v)\n return (\n <button\n key={`${row.key}__${v.channel}__${v.name}`}\n type=\"button\"\n className={`ycw-model-picker__chip${chipActive ? ' is-active' : ''}${chipAvailable ? '' : ' is-unavailable'}`}\n onClick={(e) => {\n e.stopPropagation()\n if (!chipAvailable) return\n selectVariant(v)\n }}\n disabled={!chipAvailable}\n aria-disabled={!chipAvailable}\n title={\n chipAvailable\n ? t('modelPicker.chip.title.available', {\n channel: v.channel,\n name: v.name,\n })\n : t('modelPicker.chip.title.unavailable', { channel: v.channel })\n }\n >\n {v.channel}\n {!chipAvailable && (\n <span className=\"ycw-model-picker__chip-badge\" aria-hidden>\n ·\n </span>\n )}\n </button>\n )\n })}\n </div>\n )}\n </div>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n","/**\n * useModels —— 拉取 hip-server 提供的\"可选模型清单\"。\n *\n * 数据来源:``adapter.listModels({ groupBy: 'basename' })`` →\n * DefaultJetAgentsAdapter →\n * ``GET ${hipBaseUrl}/api/v1/models?group_by=basename`` →\n * hip-server 直接代理 model-lake `/unified/v1/models`,并把 ``__`` 视作 ``/``\n * 再聚合一层 basename,吞掉 openrouter 渠道的 \"provider__model\" 双胞胎。\n * 全程不走 fusion。\n *\n * 设计取舍:\n * · 仅在挂载时拉一次(外加显式 ``refresh()``)。模型清单是低频变更(运维改 channel\n * 才会变),按租户也不至于一分钟变一次;定时轮询会给 hip + model-lake 增加无意义压力。\n * · 失败 → 空清单 + ``error``,不抛;让 UI(ModelPicker)选择 fall back 到 AUTO(不\n * 展示选项 / 仅展示\"默认\"),与 widget 整体\"adapter 失效不应阻塞主链路\"的约定一致。\n * · adapter 不实现 ``listModels`` 时也走\"失败 → AUTO\"分支,避免老 adapter 强依赖。\n */\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type {\n ChatWidgetAdapter,\n ModelListItemBasenameGrouped,\n} from '../../../types.js'\n\nexport interface UseModelsResult {\n items: ModelListItemBasenameGrouped[]\n loading: boolean\n /** null = 没出过错 */\n error: string | null\n /** 手动强制重拉(如登录态切换、tenant 切换) */\n refresh: () => void\n}\n\nexport interface UseModelsOptions {\n /**\n * 是否允许触发 listModels 请求。默认 true(保持向后兼容)。\n *\n * 主要使用场景:游客态 marketing hero。访客没有 access_token,\n * 调 hip `GET /api/v1/models` 必然 401。把 enabled 显式设为 false → 完全跳过请求,\n * UI 自然走 inert 占位。\n */\n enabled?: boolean\n}\n\nexport function useModels(\n adapter: ChatWidgetAdapter,\n options: UseModelsOptions = {},\n): UseModelsResult {\n const { enabled = true } = options\n const [items, setItems] = useState<ModelListItemBasenameGrouped[]>([])\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [bump, setBump] = useState(0)\n const cancelledRef = useRef(false)\n\n useEffect(() => {\n cancelledRef.current = false\n if (!enabled || typeof adapter.listModels !== 'function') {\n // !enabled(游客态)或老 adapter:不发请求,保持空清单,UI 自然降级到 AUTO。\n setItems([])\n setError(null)\n setLoading(false)\n return () => {\n cancelledRef.current = true\n }\n }\n\n let alive = true\n setLoading(true)\n setError(null)\n adapter\n .listModels({ groupBy: 'basename' })\n .then((res) => {\n if (!alive || cancelledRef.current) return\n setItems(res.items ?? [])\n })\n .catch((err: unknown) => {\n if (!alive || cancelledRef.current) return\n const msg = err instanceof Error ? err.message : String(err)\n setError(msg)\n setItems([])\n })\n .finally(() => {\n if (!alive || cancelledRef.current) return\n setLoading(false)\n })\n\n return () => {\n alive = false\n cancelledRef.current = true\n }\n }, [adapter, bump, enabled])\n\n const refresh = useCallback(() => setBump((n) => n + 1), [])\n\n return { items, loading, error, refresh }\n}\n","/**\n * Model 注册表 / 持久化 helpers\n * --------------------------------------------------\n * 仅负责 \"AUTO sentinel + 持久化 + 校验 + basename 归一化\",\n * 真正的列表数据由 ``useModels`` hook 从 adapter 拉。\n *\n * 持久化语义(**per-agent**,key = ``chat_widget_last_model_name:${agentId}``):\n * · 空 / null → AUTO(跟随该 agent 注册的默认模型,不传 ``modelOverride``)\n * · 非空字符串 → 该 agent 下用户上次选择的 model name;进入 composer 时若该 name\n * 仍在清单内 → 复用,否则降级回 AUTO(不弹错,避免运维下线 model\n * 反向骚扰用户)\n *\n * 为什么按 agent 分桶(v2):\n * v1 用了一个全局 key,问题是切 agent 时残留上一个 agent 的选择,\n * ModelPicker 的\"value != null → 显示用户选择\"分支永远比\"value == null →\n * 定位 agent 默认\"分支优先,结果切 agent 完全看不到新 agent 的默认 model。\n * 按 agent 存储后,切到没选过的 agent → value=null → picker 自动定位 agent 默认;\n * 切回选过的 agent → value 复原 → picker 显示用户上次的选择。\n */\n\n/** AUTO 的字面量 sentinel;null 也等价 AUTO,但显式常量更便于代码对比。 */\nexport const MODEL_AUTO: null = null\n\nexport type ModelChoice = string | null\n\n/**\n * 把 model_name 归一为 \"物理模型 basename\",**必须与 hip-server\n * ``internal/remote/modellake/service.go::modelBasename`` 保持等价**。\n *\n * 规则:\n * 1. 把 ``__`` 视作 ``/``(model-lake 入库时 openrouter 渠道做的反规范化);\n * 2. 取归一化后最末段(``/`` 之后的部分)。\n *\n * 示例:\n * ``anthropic/claude-opus-4-6`` → ``claude-opus-4-6`` ← agent 配里的写法\n * ``anthropic__claude-opus-4-6`` → ``claude-opus-4-6`` ← model-lake openrouter 渠道\n * ``claude-opus-4-6`` → ``claude-opus-4-6`` ← model-lake 直连 anthropic\n * ``qwen__qwen3-max`` → ``qwen3-max``\n * ``gpt-5-mini`` → ``gpt-5-mini``\n *\n * 用途:让 ModelPicker 能把 jetagents 那侧的 ``vendor/model`` 命名跟\n * model-lake 列表里的各种渠道命名对齐,否则 agent 默认模型永远命中不了清单。\n *\n * 不能替代真正发后端的 ``ModelOverride.name`` —— 那是用户在 picker 里点中的\n * variant.name 原值,basename 仅作 UI 标签 / 反查 key。\n */\nexport function modelBasename(name: string): string {\n const normalized = name.replace(/__/g, '/')\n const i = normalized.lastIndexOf('/')\n if (i >= 0 && i < normalized.length - 1) return normalized.slice(i + 1)\n return normalized\n}\n\n/**\n * \"是否在 ModelPicker UI 里暴露上游 channel/供应商\" 的运行时开关。\n *\n * 决策动机:\n * 对外运营时,前台 picker 只该出现 ``claude-opus-4-6`` 这种纯模型名,\n * 不该把 ``anthropic`` / ``openrouter`` / ``ali`` / ``minimax`` 这些供应商抛给客户\n * (既泄漏供应链,也给\"为什么我看到俩 claude\"留下歧义)。\n * 但对内开发 / 调试 / QA / 公司内网体验,暴露 channel 是定位\"为啥这条请求走错通道\"\n * 的最快入口。所以这里做成可切换。\n *\n * 优先级(高 → 低):\n * 1. ``localStorage.chat_widget_show_model_channels``:浏览器即时生效,常用于 QA 临场切。\n * (兼容旧 key ``yumiai_show_model_channels``,逐步淘汰)\n * 2. ``VITE_SHOW_MODEL_CHANNELS``:构建时注入,决定 deploy 默认行为。\n * 3. 缺省:``false``——对外运营心智,宁可少露不可多露。\n *\n * 接受的 truthy 写法:``\"1\" | \"true\" | \"yes\" | \"on\"``(大小写无关)。\n * 其它(含空 / 任意未识别值)一律视为 false,避免笔误把后台模式误开成对外。\n */\nconst SHOW_CHANNELS_STORAGE_KEY = 'chat_widget_show_model_channels'\nconst SHOW_CHANNELS_STORAGE_KEY_LEGACY = 'yumiai_show_model_channels'\n\nfunction parseBoolish(v: string | undefined | null): boolean | null {\n if (v == null) return null\n const s = v.trim().toLowerCase()\n if (s === '') return null\n if (s === '1' || s === 'true' || s === 'yes' || s === 'on') return true\n if (s === '0' || s === 'false' || s === 'no' || s === 'off') return false\n return null\n}\n\n/**\n * 读取 ``import.meta.env`` 风格的构建时变量;用 try/catch 防御 SSR / node 测试态\n * 没有 import.meta.env 的环境抛错。仅识别 ``VITE_SHOW_MODEL_CHANNELS``。\n */\nfunction readBuildtimeShowChannels(): boolean | null {\n try {\n const env = (import.meta as unknown as { env?: Record<string, string | undefined> }).env\n return parseBoolish(env?.VITE_SHOW_MODEL_CHANNELS)\n } catch {\n return null\n }\n}\n\nexport function isShowModelChannels(): boolean {\n if (typeof window !== 'undefined') {\n try {\n const override = parseBoolish(window.localStorage.getItem(SHOW_CHANNELS_STORAGE_KEY))\n if (override != null) return override\n // 兼容旧 key(一旦读到就以旧值为准,避免 yumiai-web 老用户的 QA 配置一刀切失效)。\n const legacy = parseBoolish(window.localStorage.getItem(SHOW_CHANNELS_STORAGE_KEY_LEGACY))\n if (legacy != null) return legacy\n } catch {\n /* 隐私模式 / 配额满 → 走 env 兜底 */\n }\n }\n return readBuildtimeShowChannels() === true\n}\n\n/**\n * 旧版(v1)全局 key —— 仅保留作为\"一次性迁移读\",新代码不再写入该 key。\n * 等同清理:用户在新版下任意切一次 agent 就把 AUTO 落到新 key 上,旧 key 不影响逻辑。\n */\nconst LEGACY_GLOBAL_KEY = 'yumiai_last_model_name'\n\n/** v2 per-agent key 前缀,命名空间统一以 chat_widget_ 前缀。 */\nconst PER_AGENT_KEY_PREFIX = 'chat_widget_last_model_name:'\n/** yumiai-web 历史 per-agent 前缀,读时兜底兼容。 */\nconst PER_AGENT_KEY_PREFIX_LEGACY = 'yumiai_last_model_name:'\n\nfunction buildKey(agentId: string): string {\n return `${PER_AGENT_KEY_PREFIX}${agentId}`\n}\n\nfunction buildLegacyKey(agentId: string): string {\n return `${PER_AGENT_KEY_PREFIX_LEGACY}${agentId}`\n}\n\n/**\n * 读取该 agent 上次选择的 model name;返回 ``null`` 表示 AUTO(无 override)。\n * · 不做\"是否仍在清单内\"的校验 —— 那是 ``useModels`` 拉到清单后才能判定,\n * 在这一层强校验会把\"网络挂了但用户希望恢复\"的可恢复链路一并切断。\n * · ``agentId`` 为空时直接返回 AUTO,避免拼出 \"chat_widget_last_model_name:\" 这样的脏 key。\n * · 新 key 未命中时尝试旧 key(yumiai_*),命中则视为继承(不主动迁移写入,\n * 交给下次 saveLastModelName 顺手落到新 key)。\n */\nexport function loadLastModelName(agentId: string): ModelChoice {\n if (typeof window === 'undefined' || !agentId) return MODEL_AUTO\n try {\n const raw = window.localStorage.getItem(buildKey(agentId))\n if (raw) {\n const trimmed = raw.trim()\n return trimmed === '' ? MODEL_AUTO : trimmed\n }\n const legacyRaw = window.localStorage.getItem(buildLegacyKey(agentId))\n if (legacyRaw) {\n const trimmed = legacyRaw.trim()\n return trimmed === '' ? MODEL_AUTO : trimmed\n }\n return MODEL_AUTO\n } catch {\n return MODEL_AUTO\n }\n}\n\n/**\n * 写入该 agent 当前选择。``null`` / 空串 → 删除 key(恢复 AUTO)。\n * 静默失败(隐私模式 / 配额满都不应让 UI 崩)。\n *\n * **副作用**:第一次写入新 key 时顺便清掉旧的 v1 全局 key 与 yumiai 旧前缀 key,\n * 避免不同浏览器下用户看到不同行为。幂等,重复执行无副作用。\n */\nexport function saveLastModelName(agentId: string, name: ModelChoice): void {\n if (typeof window === 'undefined' || !agentId) return\n try {\n window.localStorage.removeItem(LEGACY_GLOBAL_KEY)\n window.localStorage.removeItem(buildLegacyKey(agentId))\n const key = buildKey(agentId)\n if (name == null || name.trim() === '') {\n window.localStorage.removeItem(key)\n return\n }\n window.localStorage.setItem(key, name)\n } catch {\n /* ignore */\n }\n}\n","/**\n * useAgentDefaultModel —— 按 agent_id 查询其后端注册的默认模型,\n * 仅供 ModelPicker 在\"用户未显式选择\"时把展示态自动定位到该模型。\n *\n * 数据链路:\n * ``adapter.getAgentDefaultModel(agentId)`` →\n * DefaultJetAgentsAdapter →\n * ``GET ${hipBaseUrl}/api/v1/agents/{agent_id}/default-model`` →\n * hip-server →(X-User-ID 透传)→ jetagents\n * ``GET /api/agent/{agent_id}/default-model`` →\n * ``DbMetaPool.get_agent_meta()._model.name``\n *\n * 设计取舍:\n * · **静默兜底,永不抛**。adapter 层已经把所有失败(业务 404 / 网络 / 超时 / 5xx)\n * 吞成 null;这里把\"未实现 / 还在 loading / 没 agentId\"也都视作 null。UI 永远\n * 拿到 null 或 ``{ name }``,写显示分支只需一个条件判断。\n * · 切换 agent 时立刻清旧值(不等新请求 resolve),避免 picker 闪现\"上一个 agent\n * 的默认模型\"——一闪而过的错位比\"短暂显示『默认模型』占位\"更让用户混乱。\n * · 不做 LRU 缓存:agent 数量有限(实测 < 10),切换频率低,每次新拉一次更省心。\n */\nimport { useEffect, useRef, useState } from 'react'\nimport type { ChatWidgetAdapter } from '../../../types.js'\n\nexport interface AgentDefaultModelInfo {\n name: string\n displayName?: string\n version?: string\n}\n\nexport interface UseAgentDefaultModelResult {\n /** null = 没查到 / 还没拉 / adapter 不支持 / 拉失败(任何一种) */\n info: AgentDefaultModelInfo | null\n loading: boolean\n}\n\nexport interface UseAgentDefaultModelOptions {\n /**\n * 是否允许触发后端请求。默认 true(保持向后兼容)。\n *\n * 主要使用场景:游客态。访客没有 access_token,调 hip 必然 401;\n * 把 enabled 显式设为 false 完全跳过请求。\n *\n * enabled === false 时:内部强制 setInfo(null) + loading 不动,行为等价于 agentId 为空。\n */\n enabled?: boolean\n}\n\nexport function useAgentDefaultModel(\n adapter: ChatWidgetAdapter,\n agentId: string | undefined,\n options: UseAgentDefaultModelOptions = {},\n): UseAgentDefaultModelResult {\n const { enabled = true } = options\n const [info, setInfo] = useState<AgentDefaultModelInfo | null>(null)\n const [loading, setLoading] = useState(false)\n const reqIdRef = useRef(0)\n\n useEffect(() => {\n setInfo(null)\n\n if (!enabled || !agentId || typeof adapter.getAgentDefaultModel !== 'function') {\n setLoading(false)\n return\n }\n\n const myReqId = ++reqIdRef.current\n setLoading(true)\n adapter\n .getAgentDefaultModel(agentId)\n .then((got) => {\n if (reqIdRef.current !== myReqId) return\n setInfo(got)\n })\n .catch(() => {\n if (reqIdRef.current !== myReqId) return\n setInfo(null)\n })\n .finally(() => {\n if (reqIdRef.current !== myReqId) return\n setLoading(false)\n })\n }, [adapter, agentId, enabled])\n\n return { info, loading }\n}\n","import React, { useCallback } from 'react'\nimport { useSessionList } from '../../hooks/useSessionList.js'\nimport type { ChatWidgetAdapter, SessionListItem } from '../../types.js'\nimport { useChatWidgetI18n } from '../../i18n/context.js'\nimport './SessionListPanel.css'\n\nexport interface SessionListPanelProps {\n adapter: ChatWidgetAdapter | null | undefined\n /** 当前激活会话;用于高亮 + 删除时的\"激活态消失\"判定。 */\n activeSessionId?: number\n /** 选中某条会话的回调。 */\n onSelectSession: (id: number) => void\n /** 点击\"新建会话\"按钮的回调;不传则不显示该按钮。 */\n onNewSession?: () => void\n /** 点击\"退出\"按钮的回调;不传则不显示该按钮。 */\n onLogout?: () => void\n /** 删除当前激活会话后的回调(典型用法是 setSessionId(undefined))。 */\n onActiveSessionRemoved?: (id: number) => void\n /** 401 钩子;缺省时由调用方在 adapter.onAuthFailure 里处理。 */\n onAuthFailure?: () => void\n /** 外部触发刷新的版本号;任何递增即重拉。 */\n refreshKey?: number\n /** 周期重拉间隔;不传不轮询。 */\n pollMs?: number\n /** 每页大小;默认 20。 */\n pageSize?: number\n /** 自定义标题;默认走 i18n。 */\n title?: React.ReactNode\n /** 删除前确认;返回 false 中止。默认走 window.confirm。 */\n confirmDelete?: (item: SessionListItem) => boolean | Promise<boolean>\n /** 自定义条目渲染(保留 onClick / 删除按钮包裹由组件负责)。 */\n renderItemTitle?: (item: SessionListItem) => React.ReactNode\n className?: string\n}\n\nconst DEFAULT_CONFIRM_DELETE = (item: SessionListItem, msg: string): boolean => {\n if (typeof window === 'undefined') return true\n return window.confirm(`${msg}\\n\\n#${item.id}`)\n}\n\n/**\n * 通用会话侧栏。可直接挂载,也可作为参考实现:复杂场景下推荐\n * 调用方自己用 `useSessionList` + 自有 UI 拼装。\n */\nexport const SessionListPanel: React.FC<SessionListPanelProps> = ({\n adapter,\n activeSessionId,\n onSelectSession,\n onNewSession,\n onLogout,\n onActiveSessionRemoved,\n onAuthFailure,\n refreshKey,\n pollMs,\n pageSize = 20,\n title,\n confirmDelete,\n renderItemTitle,\n className,\n}) => {\n const { t } = useChatWidgetI18n()\n const {\n sessions,\n loading,\n page,\n totalPages,\n setPage,\n deleteSession,\n supported,\n canDelete,\n } = useSessionList({\n adapter,\n pageSize,\n pollMs,\n refreshKey,\n activeSessionId,\n onActiveSessionRemoved,\n onAuthFailure,\n })\n\n const handleDelete = useCallback(\n async (e: React.MouseEvent, item: SessionListItem) => {\n e.stopPropagation()\n const ok = confirmDelete\n ? await confirmDelete(item)\n : DEFAULT_CONFIRM_DELETE(item, t('sessionList.deleteConfirm'))\n if (!ok) return\n try {\n await deleteSession(item.id)\n } catch {\n // useSessionList 已经把错误回滚 + 上报,这里吞一下避免冒泡到 React。\n }\n },\n [deleteSession, confirmDelete, t],\n )\n\n const renderTitle = (s: SessionListItem) => {\n if (renderItemTitle) return renderItemTitle(s)\n return s.sessionTitle || s.summary || t('sessionList.untitled')\n }\n\n const rootClass = ['ycw-session-list', className].filter(Boolean).join(' ')\n\n return (\n <div className={rootClass}>\n <div className=\"ycw-session-list__header\">\n <h3 className=\"ycw-session-list__title\">{title ?? t('sessionList.title')}</h3>\n <div className=\"ycw-session-list__actions\">\n {onNewSession && (\n <button\n type=\"button\"\n className=\"ycw-session-list__btn ycw-session-list__btn--new\"\n onClick={onNewSession}\n title={t('sessionList.newSession')}\n >\n {t('sessionList.newSession')}\n </button>\n )}\n {onLogout && (\n <button\n type=\"button\"\n className=\"ycw-session-list__btn ycw-session-list__btn--logout\"\n onClick={onLogout}\n title={t('sessionList.logout')}\n >\n {t('sessionList.logout')}\n </button>\n )}\n </div>\n </div>\n\n <div className=\"ycw-session-list__body\">\n {!supported && (\n <div className=\"ycw-session-list__empty\">{t('sessionList.unsupported')}</div>\n )}\n {supported && loading && sessions.length === 0 && (\n <div className=\"ycw-session-list__loading\">{t('sessionList.loading')}</div>\n )}\n {supported && sessions.map(s => (\n <div\n key={s.id}\n className={\n 'ycw-session-list__item' +\n (s.id === activeSessionId ? ' ycw-session-list__item--active' : '')\n }\n onClick={() => onSelectSession(s.id)}\n >\n <span className=\"ycw-session-list__item-title\">{renderTitle(s)}</span>\n {canDelete && (\n <button\n type=\"button\"\n className=\"ycw-session-list__delete\"\n onClick={e => void handleDelete(e, s)}\n title={t('sessionList.deleteTitle')}\n aria-label={t('sessionList.deleteTitle')}\n >\n ×\n </button>\n )}\n </div>\n ))}\n {supported && !loading && sessions.length === 0 && (\n <div className=\"ycw-session-list__empty\">{t('sessionList.empty')}</div>\n )}\n </div>\n\n {totalPages > 1 && (\n <div className=\"ycw-session-list__pagination\">\n <button\n type=\"button\"\n className=\"ycw-session-list__page-btn\"\n disabled={page <= 1}\n onClick={() => setPage(page - 1)}\n aria-label={t('sessionList.prevPage')}\n >\n {t('sessionList.prevPage')}\n </button>\n <span className=\"ycw-session-list__page-info\">\n {t('sessionList.pageInfo', { page, totalPages })}\n </span>\n <button\n type=\"button\"\n className=\"ycw-session-list__page-btn\"\n disabled={page >= totalPages}\n onClick={() => setPage(page + 1)}\n aria-label={t('sessionList.nextPage')}\n >\n {t('sessionList.nextPage')}\n </button>\n </div>\n )}\n </div>\n )\n}\n\nexport default SessionListPanel\n","/**\n * JETP-033: Build a serializable catalog fragment from the domain catalog\n * for inclusion in the send_message payload so the backend can assemble\n * accurate generation prompts (AC-CW-007).\n *\n * The fragment's field names and shapes must exactly match the Jinja2 template\n * variable expectations defined in 09_prompt_templates.md §3:\n * - catalog_component_defs[name] → {props_schema, description, has_children, events}\n * - catalog_example_props[name] → JSON string\n * - custom_actions[] → {name, description, params_schema}\n * - computed_functions[] → {name, params_hint, description}\n */\n\nimport catalog, { catalogDef } from '../components/JsonRender/domain/catalog.js'\n\nexport interface CatalogFragment {\n componentNames: string[]\n components: Record<string, {\n props_schema: string\n description: string\n has_children: boolean\n events: string[]\n }>\n exampleProps: Record<string, string>\n actions: Array<{ name: string; description: string; params_schema: string }>\n functions: Array<{ name: string; params_hint: string; description: string }>\n themeSchema: Record<string, string>\n prompt_hash: string\n}\n\n// --------------- Zod introspection helpers (Zod v4 + v3 compat) ---------------\n\nfunction defType(zodObj: unknown): string | undefined {\n if (!zodObj || typeof zodObj !== 'object') return undefined\n const def = (zodObj as Record<string, unknown>)._def as Record<string, unknown> | undefined\n if (!def) return undefined\n return (def.type as string) ?? (def.typeName as string) ?? undefined\n}\n\nfunction defField(zodObj: unknown, key: string): unknown {\n if (!zodObj || typeof zodObj !== 'object') return undefined\n const def = (zodObj as Record<string, unknown>)._def as Record<string, unknown> | undefined\n return def?.[key]\n}\n\nfunction getZodShape(zodObj: unknown): Record<string, unknown> | null {\n if (!zodObj || typeof zodObj !== 'object') return null\n const obj = zodObj as Record<string, unknown>\n\n // Zod v4: .shape is a plain object getter\n if ('shape' in obj && typeof obj.shape === 'object' && obj.shape !== null) {\n return obj.shape as Record<string, unknown>\n }\n\n // _def.shape — v4 uses plain object, v3 may use function\n if ('_def' in obj) {\n const def = obj._def as Record<string, unknown>\n if ('shape' in def) {\n const inner = def.shape\n if (typeof inner === 'function') {\n try { return inner() as Record<string, unknown> } catch { return null }\n }\n if (inner && typeof inner === 'object') return inner as Record<string, unknown>\n }\n }\n return null\n}\n\nfunction zodTypeToString(z: unknown, depth = 0): string {\n if (!z || typeof z !== 'object') return 'unknown'\n const tn = defType(z)\n if (!tn) return 'unknown'\n\n switch (tn) {\n // --- Zod v4 lowercase types ---\n case 'string': return 'string'\n case 'number': return 'number'\n case 'boolean': return 'boolean'\n case 'optional': return zodTypeToString(defField(z, 'innerType'), depth)\n case 'nullable': return zodTypeToString(defField(z, 'innerType'), depth) + '|null'\n case 'default': return zodTypeToString(defField(z, 'innerType'), depth)\n case 'array': {\n const inner = zodTypeToString(defField(z, 'element'), depth + 1)\n return inner.includes('|') ? `(${inner})[]` : `${inner}[]`\n }\n case 'enum': {\n const entries = defField(z, 'entries') as Record<string, string> | undefined\n if (entries) return Object.values(entries).map(v => `\"${v}\"`).join('|')\n return 'string'\n }\n case 'union': {\n const opts = defField(z, 'options') as unknown[] | undefined\n return opts ? opts.map(o => zodTypeToString(o, depth)).join('|') : 'unknown'\n }\n case 'object': {\n const shape = getZodShape(z)\n if (!shape) return '{}'\n const keys = Object.keys(shape)\n if (depth > 4 || keys.length > 12) return `{${keys.join(', ')}}`\n const parts = keys.map(k => {\n const opt = isOptional(shape[k])\n return `${k}${opt ? '?' : ''}: ${zodTypeToString(shape[k], depth + 1)}`\n })\n return `{${parts.join(', ')}}`\n }\n case 'record': return 'Record<string, unknown>'\n case 'literal': {\n const vals = defField(z, 'values')\n if (Array.isArray(vals)) return vals.map(v => typeof v === 'string' ? `\"${v}\"` : String(v)).join('|')\n const val = defField(z, 'value')\n if (val !== undefined) return typeof val === 'string' ? `\"${val}\"` : String(val)\n return 'unknown'\n }\n\n // --- Zod v3 compat (prefixed typeName) ---\n case 'ZodString': return 'string'\n case 'ZodNumber': return 'number'\n case 'ZodBoolean': return 'boolean'\n case 'ZodOptional': return zodTypeToString(defField(z, 'innerType'), depth)\n case 'ZodNullable': return zodTypeToString(defField(z, 'innerType'), depth) + '|null'\n case 'ZodDefault': return zodTypeToString(defField(z, 'innerType'), depth)\n case 'ZodArray': {\n const inner = zodTypeToString(defField(z, 'type'), depth + 1)\n return inner.includes('|') ? `(${inner})[]` : `${inner}[]`\n }\n case 'ZodEnum': {\n const vals = defField(z, 'values') as string[] | undefined\n return vals ? vals.map(v => `\"${v}\"`).join('|') : 'string'\n }\n case 'ZodUnion': {\n const opts = defField(z, 'options') as unknown[] | undefined\n return opts ? opts.map(o => zodTypeToString(o, depth)).join('|') : 'unknown'\n }\n case 'ZodObject': {\n const shape = getZodShape(z)\n if (!shape) return '{}'\n const keys = Object.keys(shape)\n if (depth > 4 || keys.length > 12) return `{${keys.join(', ')}}`\n const parts = keys.map(k => {\n const opt = isOptional(shape[k])\n return `${k}${opt ? '?' : ''}: ${zodTypeToString(shape[k], depth + 1)}`\n })\n return `{${parts.join(', ')}}`\n }\n case 'ZodRecord': return 'Record<string, unknown>'\n case 'ZodLiteral': {\n const val = defField(z, 'value')\n return typeof val === 'string' ? `\"${val}\"` : String(val)\n }\n case 'ZodUnknown': return 'unknown'\n default: return 'unknown'\n }\n}\n\nfunction isOptional(z: unknown): boolean {\n if (!z || typeof z !== 'object') return false\n const tn = defType(z)\n return tn === 'optional' || tn === 'default' || tn === 'ZodOptional' || tn === 'ZodDefault'\n}\n\nfunction serializeZodSchema(propsZod: unknown): string {\n const shape = getZodShape(propsZod)\n if (!shape) return '{}'\n const parts: string[] = []\n for (const key of Object.keys(shape)) {\n const fieldZod = shape[key]\n const opt = isOptional(fieldZod)\n parts.push(`${key}${opt ? '?' : ''}: ${zodTypeToString(fieldZod, 0)}`)\n }\n return `{${parts.join(', ')}}`\n}\n\nfunction buildExampleProps(propsZod: unknown): string {\n const shape = getZodShape(propsZod)\n if (!shape) return '{}'\n const obj: Record<string, unknown> = {}\n for (const key of Object.keys(shape)) {\n const fieldZod = shape[key]\n if (isOptional(fieldZod)) continue\n const type = zodTypeToString(fieldZod)\n if (type === 'string') obj[key] = `Example ${key}`\n else if (type === 'number') obj[key] = 0\n else if (type === 'boolean') obj[key] = true\n else if (type.endsWith('[]')) obj[key] = []\n else if (type.startsWith('\"')) obj[key] = type.replace(/\"/g, '').split('|')[0]\n else if (type === 'number|string') obj[key] = 0\n else obj[key] = `<${key}>`\n }\n try { return JSON.stringify(obj) } catch { return '{}' }\n}\n\n// --------------- hash ---------------\n\nfunction simpleHash(str: string): string {\n let hash = 0\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) - hash + str.charCodeAt(i)) | 0\n }\n return (hash >>> 0).toString(16).padStart(8, '0')\n}\n\n// --------------- style function metadata ---------------\n\nconst STYLE_FUNCTION_META: Array<{ name: string; params_hint: string; description: string }> = [\n { name: 'cardStyle', params_hint: 'mood: calm|alert|urgent|celebration', description: 'Mood-based card styling classes' },\n { name: 'colorScale', params_hint: 'value: number, min: number, max: number', description: 'Numeric value to green-yellow-red color' },\n { name: 'statusColor', params_hint: 'status: pass|fail|warning|pending|na', description: 'Status badge color' },\n]\n\n// --------------- main builder ---------------\n\nlet _cached: CatalogFragment | null = null\n\nexport function buildCatalogFragment(): CatalogFragment {\n if (_cached) return _cached\n\n const componentNames = catalog.componentNames as string[]\n\n const components: CatalogFragment['components'] = {}\n const exampleProps: CatalogFragment['exampleProps'] = {}\n\n for (const name of componentNames) {\n const def = catalogDef.components[name as keyof typeof catalogDef.components]\n if (!def) continue\n const defAny = def as Record<string, unknown>\n const slots = 'slots' in defAny && Array.isArray(defAny.slots) ? defAny.slots as string[] : []\n const events = 'events' in defAny && Array.isArray(defAny.events) ? defAny.events as string[] : []\n\n components[name] = {\n props_schema: serializeZodSchema(def.props),\n description: (defAny.description as string) ?? '',\n has_children: slots.length > 0,\n events,\n }\n\n exampleProps[name] = buildExampleProps(def.props)\n }\n\n const actions: CatalogFragment['actions'] = (catalog.actionNames as string[]).map((name) => {\n const def = catalogDef.actions[name as keyof typeof catalogDef.actions]\n return {\n name,\n description: (def?.description as string) ?? '',\n params_schema: def?.params ? serializeZodSchema(def.params) : '{}',\n }\n })\n\n const promptText = catalog.prompt()\n const prompt_hash = simpleHash(promptText)\n\n const themeSchema: Record<string, string> = {\n primary: 'string (hex color)',\n bg: 'string (hex color)',\n surface: 'string (hex color)',\n text: 'string (hex color)',\n textMuted: 'string (hex color)',\n success: 'string (hex color)',\n warning: 'string (hex color)',\n danger: 'string (hex color)',\n font: 'string (font family)',\n fontMono: 'string (monospace font family)',\n radius: 'string (CSS length)',\n spacing: 'string (CSS length)',\n }\n\n _cached = {\n componentNames,\n components,\n exampleProps,\n actions,\n functions: STYLE_FUNCTION_META,\n themeSchema,\n prompt_hash,\n }\n return _cached\n}\n","import type { ChatWidgetAdapter, GetSessionHistoryOptions, NotificationTurn, PaginatedHistoryResponse, ResourceContent, SessionDetail, HITLResponse, PendingHIL, SSEMessage, SkillListParams, SkillListResponse, SelectedSkillRef, DirectoryFileEntry, ListDirectoryFilesOptions, PoolStatusResponse, PostDiscussionMessageRequest, PostDiscussionMessageResponse, CreateDiscussionRequest, CreateDiscussionResponse, PoolAgent, FileUploadResult, FileUploadStatusResult, WorkspaceUploadResult, FileAttachment, ListSessionsParams, ListSessionsResponse, SessionListItem, ListModelsParams, ListModelsResponse, ModelListItemGrouped, ModelListItemRaw, ModelListItemBasenameGrouped, ModelListVariant } from '../types.js'\nimport { ChatWidgetAuthError, ChatWidgetNetworkError, InvalidClientIdError } from '../errors.js'\n\n// JETP-058 v2-only:所有 client_id 必须是 ``c_<22 base62>``。\n// 与后端 jetagents.site.db.repository.clients_repository.assert_v2_client_id 同源\n// (Pydantic / Notification / Routing 三方约束已统一到 v2)。\n// MAX_CIDS 与后端 session_manager.api._MAX_CIDS 对齐。\nconst V2_CID_RE = /^c_[A-Za-z0-9]{22}$/\nconst MAX_CIDS = 16\nimport { buildCatalogFragment } from '../hooks/useCatalogFragment.js'\n\n// JETP-058: upload 路径专用断言。前端不允许把空 / legacy / non-v2 的 cid 发到 /api/knowledge/upload/batch;\n// 否则后端 batch endpoint 会先 KMInvalidParamsException 422,下游 _aggregate_turn 也会抛 InvalidClientIdError。\n// 早失败避免半成品 task_infos 被写库。\nfunction assertV2ClientIdForUpload(value: unknown, where: string): asserts value is string {\n if (typeof value !== 'string' || !V2_CID_RE.test(value)) {\n throw new InvalidClientIdError(\n `${where}: client_id 必须为 v2 ^c_[A-Za-z0-9]{22}$ 格式 (JETP-058),收到 ${JSON.stringify(value)}`,\n 'legacy_format',\n )\n }\n}\n\nfunction anySignal(...signals: AbortSignal[]): AbortSignal {\n const ctrl = new AbortController()\n for (const s of signals) {\n if (s.aborted) { ctrl.abort(s.reason); return ctrl.signal }\n s.addEventListener('abort', () => ctrl.abort(s.reason), { once: true })\n }\n return ctrl.signal\n}\n\nexport interface DefaultJetAgentsAdapterOptions {\n baseUrl: string\n getToken: () => string | null\n refreshToken?: () => Promise<string | null>\n getOrgId?: () => string | null\n getUserId?: () => string | null\n hipBaseUrl?: string\n onAuthFailure?: () => void\n /**\n * 可选:每次请求前由上层动态返回额外 header。\n *\n * 设计目的:让宿主应用(例如 yumiai-web)把 i18n locale、tenant、feature flag 等\n * 横切关注点统一注入到 adapter 的所有 HTTP 出口(fetchJSON / fetchHipJSON /\n * fetchMultipart / SSE startStream),而无需修改 adapter 内部任何端点。\n *\n * 调用时机:每次构造请求 headers 时同步调用一次(在 `getAuthHeaders()` 中合并),\n * 因此实现侧可以读取最新的可变状态(如 currentLocale)而不需要重建 adapter。\n *\n * 优先级:同名 key 时,本钩子返回值会被 `getAuthHeaders()` 内已设置的鉴权字段覆盖\n * (Authorization / X-User-ID / X-User-Roles / X-Org-Id),但会高于 caller 在\n * fetchJSON(init.headers) 里传入的同名字段(caller 仍可通过显式传 header 覆盖)。\n *\n * 典型用法:\n * ```ts\n * new DefaultJetAgentsAdapter({\n * ...,\n * getExtraHeaders: () => ({\n * 'Accept-Language': getCurrentLocale(),\n * 'X-Locale': getCurrentLocale(),\n * }),\n * })\n * ```\n */\n getExtraHeaders?: () => Record<string, string> | undefined\n\n /**\n * 可选:每次构造 send_message body 时由上层动态返回客户端环境上下文。\n *\n * 设计目的:让宿主应用注入用户的 IANA 时区 / UTC offset / locale 等\n * **随消息一起上行**的元数据,与 `body.catalog_fragment` 走完全相同的\n * 路径(`buildStreamBody` 内部直接组装、不经过 params)。后端就能在\n * 生成提示词、日志、个性化回复时使用这些信息(例如\"按你的当地时间提醒\"\n * 或\"这条消息发自 Asia/Shanghai\")。\n *\n * 与 `getExtraHeaders` 的分工:\n * · header(getExtraHeaders):横切给所有 HTTP 端点,后端中间件统一处理。\n * · body.client_context(本钩子):仅 send_message 上行,与对话内容\n * 绑定持久化,便于后端 / Prompt 引擎在生成时引用。\n *\n * 调用时机:每次 `buildStreamBody()` 调用时同步执行一次,因此实现可以\n * 实时读取当前 locale / 系统时区,无需重建 adapter。\n *\n * 默认行为:钩子未提供 / 返回 `undefined` 字段时,由 SDK 内部用\n * `Intl.DateTimeFormat().resolvedOptions().timeZone` 兜底自动检测,\n * 保证 body.client_context 永远有合法字段(与 catalog_fragment 一样自治)。\n *\n * 典型用法:\n * ```ts\n * new DefaultJetAgentsAdapter({\n * ...,\n * getClientContext: () => snapshotClientContext(getCurrentLocale()),\n * })\n * ```\n *\n * 字段含义:\n * · timezone IANA tz name,如 'Asia/Shanghai'。\n * · timezoneOffsetMinutes 当前 UTC 偏移分钟(正东负西,与 ECMA\n * getTimezoneOffset 符号相反)。\n * · locale 当前 BCP47 locale,如 'zh-CN'。\n */\n getClientContext?: () => Partial<{\n timezone: string\n timezoneOffsetMinutes: number\n locale: string\n }> | undefined\n}\n\n/**\n * SDK 内部默认时区检测:仅在 `getClientContext` 未提供 / 字段缺失时兜底。\n *\n * 与宿主侧 yumiai-web/src/i18n/clientContext.ts 的 getCurrentTimezone() 行为\n * 完全等价(同样用 Intl + 'UTC' 兜底);这里独立实现以保证 SDK 在没有宿主\n * 注入时仍然自治可用,避免 SDK 反向依赖宿主。\n */\nfunction detectDefaultTimezone(): string {\n if (typeof Intl === 'undefined' || typeof Intl.DateTimeFormat !== 'function') {\n return 'UTC'\n }\n try {\n const tz = Intl.DateTimeFormat().resolvedOptions().timeZone\n return tz && tz.length > 0 ? tz : 'UTC'\n } catch {\n return 'UTC'\n }\n}\n\n/** 默认 UTC 偏移分钟(正东负西)。 */\nfunction detectDefaultTimezoneOffsetMinutes(): number {\n try {\n return -new Date().getTimezoneOffset()\n } catch {\n return 0\n }\n}\n\n/**\n * 把 `getClientContext()` 的返回值(任意字段可缺)和 SDK 内置默认值合并成\n * snake_case 的最终 body.client_context 载荷。\n *\n * 输出字段顺序固定,便于后端日志 / 截图 review。\n */\nfunction buildClientContextPayload(\n override: ReturnType<NonNullable<DefaultJetAgentsAdapterOptions['getClientContext']>> | undefined,\n): { timezone: string; timezone_offset_minutes: number; locale?: string } {\n const tz = override?.timezone && override.timezone.length > 0\n ? override.timezone\n : detectDefaultTimezone()\n // offset 是 number;显式判断 undefined 而不是真值,否则 0(UTC 用户)会被吞\n const offset = typeof override?.timezoneOffsetMinutes === 'number'\n ? override.timezoneOffsetMinutes\n : detectDefaultTimezoneOffsetMinutes()\n const payload: { timezone: string; timezone_offset_minutes: number; locale?: string } = {\n timezone: tz,\n timezone_offset_minutes: offset,\n }\n if (override?.locale && override.locale.length > 0) {\n payload.locale = override.locale\n }\n return payload\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; data: { 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.data.user_caller_instance }\n }\n\n async getSessionDetail(sessionId: number): Promise<SessionDetail> {\n const res = await this.fetchJSON<{ data?: SessionDetail } & SessionDetail>(`/api/session/detail/${sessionId}`)\n return (res.data ?? res) as SessionDetail\n }\n\n /**\n * 后端 ``GET /api/session/page`` 返回 ``{ items: DbSession[], total }``,\n * DbSession.to_dict() 字段名是 snake_case + ``session_title`` 而非 ``title``。\n * adapter 在这一层做规范化,向上层暴露统一的 ``SessionListItem``。\n */\n async listSessions(params?: ListSessionsParams): Promise<ListSessionsResponse> {\n const page = Math.max(1, params?.page ?? 1)\n const pageSize = Math.max(1, params?.pageSize ?? 20)\n const url = `/api/session/page?page=${page}&size=${pageSize}`\n const res = await this.fetchJSON<{\n data?: { items?: unknown[]; total?: number }\n items?: unknown[]\n total?: number\n }>(url)\n const payload = (res.data ?? res) as { items?: unknown[]; total?: number }\n const rawItems = Array.isArray(payload.items) ? payload.items : []\n const items: SessionListItem[] = rawItems.map((raw) => {\n const r = raw as Record<string, unknown>\n const sessionTitle = (r.session_title ?? r.sessionTitle ?? r.title) as string | null | undefined\n return {\n id: Number(r.id),\n sessionTitle: sessionTitle ?? null,\n summary: (r.summary as string | null | undefined) ?? null,\n createdAt: (r.created_at ?? r.createdAt) as string | null | undefined ?? null,\n updatedAt: (r.updated_at ?? r.updatedAt) as string | null | undefined ?? null,\n runningTime: (r.running_time ?? r.runningTime) as number | null | undefined ?? null,\n }\n })\n return {\n items,\n total: payload.total ?? items.length,\n page,\n pageSize,\n }\n }\n\n async deleteSession(sessionId: number): Promise<void> {\n await this.fetchJSON(`/api/session/${sessionId}`, { method: 'DELETE' })\n }\n\n async getSessionHistory(\n sessionId: number,\n options: GetSessionHistoryOptions,\n ): Promise<NotificationTurn[] | PaginatedHistoryResponse> {\n // JETP-057: 客户端 fail-fast 校验。\n // 1. 强约束 clientIds 必传 + 字符集 / 长度,避免发出注定 422 的请求;\n // 2. 与后端 _validate_query_client_ids 同源 → 出错信息形态对称;\n // 3. 自动 strip / 去重并保留首次出现次序,与 SQL 索引扫描顺序对齐。\n const clientIds = this._normalizeClientIdsOrThrow(options?.clientIds)\n\n const params = new URLSearchParams()\n // ⚠️ 多值用 append,不可拼成 ?client_ids=a,b(FastAPI 期望 repeatable)\n for (const cid of clientIds) params.append('client_ids', cid)\n if (options.pageSize) params.set('page_size', String(options.pageSize))\n if (options.beforeCursor) params.set('before_cursor', options.beforeCursor)\n if (options.includeInFlight) params.set('include_in_flight', 'true')\n const url = `/api/session/messages/${sessionId}?${params.toString()}`\n\n const res = await this.fetchJSON<{ data?: { turns?: NotificationTurn[]; has_more?: boolean; next_cursor?: string | null } }>(url)\n const payload = (res.data ?? res) as { turns?: NotificationTurn[]; has_more?: boolean; next_cursor?: string | null }\n\n if (payload.has_more !== undefined) {\n return {\n turns: payload.turns ?? [],\n has_more: payload.has_more,\n next_cursor: payload.next_cursor ?? null,\n } as PaginatedHistoryResponse\n }\n return payload.turns ?? (Array.isArray(payload) ? payload as unknown as NotificationTurn[] : [])\n }\n\n /**\n * JETP-058 v2-only — clientIds 参数规范化 + 严格校验。\n *\n * 与 JETP-057 差异:\n * - 旧实现允许 ``[A-Za-z0-9._:\\\\-/]+`` 字符集(兼容 ``main`` / ``file:*`` / ``sel:*``);\n * - 新实现仅接受 ``^c_[A-Za-z0-9]{22}$``,其它一律 ``RangeError`` fail-fast。\n *\n * 任何不合法都立刻抛错(fail-fast,不发请求);\n * 对调用方意味着:未派生出 v2 cid 之前不要调 getSessionHistory(与 controller skip 配合)。\n */\n private _normalizeClientIdsOrThrow(clientIds: unknown): string[] {\n if (!Array.isArray(clientIds)) {\n throw new TypeError('JETP-058: getSessionHistory 必传 options.clientIds: string[]')\n }\n if (clientIds.length === 0) {\n throw new RangeError(\n 'JETP-058: clientIds 不可为空;v2-only 模式下请至少传一个 c_<22> cid',\n )\n }\n if (clientIds.length > MAX_CIDS) {\n throw new RangeError(\n `JETP-058: clientIds 长度 ${clientIds.length} 超过上限 ${MAX_CIDS}`,\n )\n }\n const out: string[] = []\n const seen = new Set<string>()\n for (const raw of clientIds) {\n if (typeof raw !== 'string') {\n throw new TypeError(\n `JETP-058: clientIds 元素必须为 string,got ${typeof raw}`,\n )\n }\n const cid = raw.trim()\n if (!cid) {\n throw new RangeError('JETP-058: clientIds 含空字符串元素')\n }\n if (!V2_CID_RE.test(cid)) {\n throw new RangeError(\n `JETP-058: client_id 必须为 v2 c_<22> 形式(^c_[A-Za-z0-9]{22}$),收到 ${JSON.stringify(cid)};` +\n `legacy 字面量 'main' / 'file:*' / 'sel:*' 已不再接受,请改用 useClientIdAllocator.createClient`,\n )\n }\n if (seen.has(cid)) continue\n seen.add(cid)\n out.push(cid)\n }\n return out\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 const rc = (res.data ?? res) as ResourceContent\n\n if (rc.content_url && !rc.content) {\n const rawUrl = rc.content_url.startsWith('/')\n ? `${this.baseUrl}${rc.content_url}`\n : rc.content_url\n try {\n const rawResp = await this.authedFetch(rawUrl)\n if (rawResp.ok) {\n const blob = await rawResp.blob()\n rc.content_url = URL.createObjectURL(blob)\n }\n } catch {\n // fall through — viewer will show error via empty content\n }\n }\n\n return rc\n }\n\n async getResourceUrl(sessionId: number, resourceId: string): Promise<string> {\n const res = await this.fetchJSON<{ data?: { files?: Array<{ resource_id: string; download_url?: string; preview_url?: string }> } }>(\n `/api/workspace/file/list/${sessionId}`,\n { method: 'POST', body: JSON.stringify({}) },\n )\n const files = res.data?.files ?? []\n const file = files.find((f: { resource_id: string }) => f.resource_id === resourceId)\n const url = file?.download_url || file?.preview_url\n if (url) return url\n throw new Error('No download URL available for resource')\n }\n\n async getPreviewUrl(sessionId: number, resourceId: string, format: 'html' | 'pdf' = 'html'): Promise<string> {\n return `${this.baseUrl}/api/workspace/resource/${sessionId}/${resourceId}/preview?format=${format}`\n }\n\n async submitHITLResponse(response: HITLResponse): Promise<void> {\n // JETP-083 WS3.7.7 follow-up — uniform multipart/form-data transport.\n //\n // Backend contract: ``POST /api/human-response`` declares every field as\n // ``Form(...)`` (FastAPI). FastAPI's ``Form`` only parses\n // ``multipart/form-data`` and ``application/x-www-form-urlencoded`` —\n // a JSON body produces 422 Unprocessable Content on every field, with no\n // hint to the caller. The previous \"JSON when no files / FormData when\n // files\" branching was effectively broken for the no-files path (which\n // is the common A2UI HIL release case); the bug stayed latent because\n // older HIL flows always carried a file payload.\n //\n // Fix: always encode as ``FormData`` so the wire shape matches the\n // server-side parser. ``client_id`` rides as a Form field (also matches\n // WS2.5/2.6 server-side parsing of optional Form scalars).\n const fd = new FormData()\n if (response.session_id != null) fd.append('session_id', String(response.session_id))\n if (response.agent_instance_id != null) fd.append('agent_instance_id', String(response.agent_instance_id))\n // ``await_command_uuid`` is declared ``Optional[str] = Form(...)``: the\n // field MUST be present (Form(...) makes it required) but may be empty.\n // jetagents falls back to ``session._genui_await_uuids[spec_id]`` when\n // the value is empty for A2UI payloads, so an empty string is safe.\n fd.append('await_command_uuid', response.await_command_uuid ?? '')\n if (response.text) fd.append('text', response.text)\n if (response.data != null) fd.append('data', JSON.stringify(response.data))\n // JETP-003 ADR-006 v1.1.2 / WS2.6 — surface client_id as a Form field.\n if (response.client_id) fd.append('client_id', response.client_id)\n if (response.files?.length) {\n for (const f of response.files) fd.append('files', f)\n }\n // [HIL-DEBUG] Last hop before the wire.\n console.log('[HIL-DEBUG] adapter.submitHITLResponse() entry', {\n await_command_uuid: response.await_command_uuid ?? '',\n session_id: response.session_id ?? null,\n agent_instance_id: response.agent_instance_id ?? null,\n client_id: response.client_id ?? null,\n data_keys: Object.keys(response.data ?? {}),\n file_count: response.files?.length ?? 0,\n transport: 'multipart/form-data',\n baseUrl: this.baseUrl,\n })\n const url = `${this.baseUrl}/api/human-response`\n const res = await this.authedFetch(url, {\n method: 'POST',\n body: fd,\n })\n if (!res.ok) throw new Error(`HITL upload failed: HTTP ${res.status}`)\n }\n\n /**\n * JETP-083 WS3.7.6 — fetch pending Collaborative HIL entities for the\n * connecting principal (scoped to one session).\n *\n * Wire shape (jetagents `main.py:get_genui_pending`):\n * ```\n * GET /api/genui/pending?session_id=<int>\n * → { code: 200, data: { session_id, pending: [...PendingHIL...] } }\n * ```\n *\n * Field-name normalisation (snake_case → camelCase) is done here so\n * the SDK type surface stays idiomatic TS and `useGenUIPending` can\n * consume `PendingHIL[]` directly.\n *\n * Failure modes:\n * - HTTP error → throws (caller decides to toast / retry / silent drop).\n * - Empty list → returns `[]` (legitimate state — no pending HILs).\n * - Malformed payload → returns `[]` and logs warn (defensive; never\n * surfaces \"endpoint exists but data unusable\" as a hard error to\n * the widget reconnect path).\n */\n async getPendingHILs(sessionId: number): Promise<PendingHIL[]> {\n const url = `/api/genui/pending?session_id=${encodeURIComponent(String(sessionId))}`\n let raw: { code?: number; data?: { pending?: unknown[] }; pending?: unknown[] }\n try {\n raw = await this.fetchJSON(url)\n } catch (e) {\n throw e\n }\n const payload = (raw.data ?? raw) as { pending?: unknown[] }\n const items = Array.isArray(payload.pending) ? payload.pending : []\n const out: PendingHIL[] = []\n for (const it of items) {\n if (!it || typeof it !== 'object') continue\n const r = it as Record<string, unknown>\n try {\n const origin = (r.origin ?? {}) as Record<string, unknown>\n const originPrincipalRaw = origin.principal as Record<string, unknown> | null | undefined\n const recipients = (r.recipients_summary ?? {}) as Record<string, unknown>\n out.push({\n hilId: String(r.hil_id ?? ''),\n specId: String(r.spec_id ?? ''),\n sessionId: String(r.session_id ?? ''),\n state: (r.state ?? 'pending') as PendingHIL['state'],\n schemaVersion: (r.schema_version ?? 'v1') as PendingHIL['schemaVersion'],\n createdAt: (r.created_at as string | null) ?? null,\n lastUpdatedAt: (r.last_updated_at as string | null) ?? null,\n origin: {\n agentId: (origin.agent_id as string | null) ?? null,\n clientId: (origin.client_id as string | null) ?? null,\n principal: originPrincipalRaw\n ? {\n principalKind: originPrincipalRaw.principal_kind as string | undefined,\n principalKey: originPrincipalRaw.principal_key as string | undefined,\n realmId: originPrincipalRaw.realm_id as string | undefined,\n authInstanceId: originPrincipalRaw.auth_instance_id as string | undefined,\n }\n : null,\n },\n recipientsSummary: {\n delivery: (recipients.delivery ?? 'first_wins') as PendingHIL['recipientsSummary']['delivery'],\n selectorKind: (recipients.selector_kind ?? 'literal') as PendingHIL['recipientsSummary']['selectorKind'],\n recipientCount: Number(recipients.recipient_count ?? 0),\n includeSelf: Boolean(recipients.include_self ?? false),\n },\n })\n } catch {\n // Defensive: drop a single malformed entry rather than failing\n // the whole hydration. WS3.7.6 acceptance: hydration is best-effort.\n }\n }\n return out\n }\n\n /**\n * 触发协作式停止:`POST /api/session/stop`,由 jetagents handler 把\n * `agent:signal:stop:{session_id}:{interaction_id}=stop` 写入 Redis;\n * 运行时检查点(agent_state_machine_v2 / simple_agent_pool /\n * agent_executor / base_pusher)轮询同一 key 后 yield `StoppedAgentCommand`\n * 优雅退出,并由 pusher 推送 `CANCELED` 通知。详见 `ChatWidgetAdapter.stopAgent`。\n *\n * 实现细节:\n * - 复用 `fetchJSON`,自带 15s 超时、Bearer JWT 注入、401 单次 refresh 重试、\n * `ChatWidgetNetworkError` 抛出;与 widget 内其它 HTTP 出口策略对齐。\n * - body 必须包含 `command: 'stop'`:后端 `AgentControlRequest` 是\n * `Literal[\"pause\",\"resume\",\"stop\"]`,缺字段会被 Pydantic 拒为 422,即便\n * handler 实际只读 `session_id`。\n * - `agent_instance_id` 上行只是为了后端日志/未来兼容;当前 handler 不读。\n * - 业务码(如 `error(\"no event in session\")`)走 `code != 200` 分支,\n * 显式抛 `ChatWidgetNetworkError`,避免上层吞错;幂等场景(已停过)后端\n * 返回 `code: 200, data: {}`,本方法 resolve 不抛。\n */\n async stopAgent(params: { sessionId: number; agentInstanceId?: number }): Promise<void> {\n const body: Record<string, unknown> = {\n session_id: params.sessionId,\n command: 'stop',\n }\n if (params.agentInstanceId != null) {\n body.agent_instance_id = params.agentInstanceId\n }\n const res = await this.fetchJSON<{ code?: number; message?: string }>(\n '/api/session/stop',\n { method: 'POST', body: JSON.stringify(body) },\n )\n if (res?.code !== 200) {\n throw new ChatWidgetNetworkError(\n res?.message ?? `stop_session_failed (code=${res?.code ?? 'unknown'})`,\n typeof res?.code === 'number' ? res.code : 0,\n )\n }\n }\n\n getStreamUrl(): string {\n return `${this.baseUrl}/api/session/send_message`\n }\n\n getWsUrl(sessionId: number): string {\n const wsBase = this.baseUrl.replace(/^http/, 'ws')\n const wsUrl = `${wsBase}/ws/session/${sessionId}`\n return wsUrl\n }\n\n\n getAuthHeaders(): Record<string, string> {\n const headers: Record<string, string> = {}\n // 先放上层注入的 extra header(如 Accept-Language / X-Locale / 自定义 trace),\n // 鉴权字段随后写入会覆盖同名 key —— 鉴权永远不可被宿主 i18n hook 误覆盖。\n try {\n const extra = this.options.getExtraHeaders?.()\n if (extra) {\n for (const [k, v] of Object.entries(extra)) {\n if (typeof v === 'string' && v.length > 0) headers[k] = v\n }\n }\n } catch {\n // best-effort:上层钩子异常不应阻断请求\n }\n const token = this.options.getToken()\n if (token) {\n headers['Authorization'] = `Bearer ${token}`\n } else {\n headers['X-User-ID'] = this.options.getUserId?.() ?? '1'\n headers['X-User-Roles'] = 'user'\n }\n const orgId = this.options.getOrgId?.()\n if (orgId) {\n headers['X-Org-Id'] = orgId\n }\n return headers\n }\n\n async listSkills(params?: SkillListParams): Promise<SkillListResponse> {\n const searchParams = new URLSearchParams()\n searchParams.set('page', String(params?.page ?? 1))\n searchParams.set('page_size', String(params?.pageSize ?? 20))\n if (params?.search) searchParams.set('search', params.search)\n\n const raw = await this.fetchJSON<{\n skills: Array<{ id: string; name: string; display_name: string; description: string; version?: string; category?: string; tags?: string[] }>\n total: number\n page: number\n page_size: number\n }>(`/api/skills?${searchParams.toString()}`)\n\n return {\n skills: raw.skills.map((s) => ({\n id: s.id,\n name: s.name,\n displayName: s.display_name,\n description: s.description,\n version: s.version,\n category: s.category,\n tags: s.tags,\n })),\n total: raw.total,\n page: raw.page,\n pageSize: raw.page_size,\n }\n }\n\n buildStreamBody(params: {\n message: string\n agentId: string\n sessionId: number | null\n interactionId: string\n agentInstanceId?: number\n callerInstanceId?: number\n selectedSkills?: SelectedSkillRef[]\n activeSpecIds?: string[]\n /** JETP-045 Layer 1:客户端连接子空间标识(前端 owned)。 */\n clientId?: string\n /**\n * JETP-045 Phase 6 — Layer 1.5 物理连接 ID(``useConnectionId`` 派生)。\n * 用于后端 echo 抑制;缺省(旧调用方)时不写入 body,后端按\"未知连接\"处理。\n */\n connectionId?: string\n fileAttachments?: FileAttachment[]\n /**\n * 前端\"本次调用使用的模型\"覆盖项;缺省 / null 时不写入 body,\n * 后端按 agent 注册的默认 ``ModelMeta`` 走(与历史完全一致)。\n */\n modelOverride?: import('../types').ModelOverride | null\n }): object {\n // JETP-045 P7 / AC-CHANNEL-002:channel_id 已全栈撤回(v1.0),上下行 body 与\n // 前端业务路径都不再出现该字段;adapter 内部仅在 transformSSEMessage 边界保留对\n // 旧后端 raw.channel_id 的最小兜底(折叠到 client_id),不再暴露给上层。\n const agentEntry: Record<string, unknown> = {\n agent_id: '',\n custom_id: params.agentId,\n published_version: '1.0.0',\n url: 'local',\n type: '',\n agent_provider_id: 0,\n description: '',\n name: '',\n }\n if (params.agentInstanceId != null) {\n agentEntry.agent_instance_id = params.agentInstanceId\n }\n // JETP-032 chip_with_prefix:保留 ``{{SKILL:xxx}}`` 占位符原样上行。\n // 原因:后端会把 message echo 回 user_input turn,前端 ``parseUserMessage`` 据此\n // 还原 chip 胶囊视觉;如果在这里剥成裸名 ``xxx``,UI 气泡里的 chip 就会丢失。\n // 模板话术(\"先查看并使用…技能,去解决:\")已由 RichInput.getText() 在\n // 占位符前后包好,模型读到的语义也是连贯的。\n const contents: object[] = [{ type: 'text', content: params.message }]\n // JETP-058 v2-only:clientId 必须为 v2 ``c_<22>``。\n // 上游链路(ChatWidget.ensureClientId → controller.sendMessage)已经做过一遍校验,\n // adapter 这里再做一次 fail-fast,确保即便测试 / 第三方 caller 直接调 buildStreamBody,\n // 也不会让 legacy 字面量混入 send_message body 污染 routing/turn 表。\n const resolvedClientId = (params.clientId ?? '').trim()\n if (!/^c_[A-Za-z0-9]{22}$/.test(resolvedClientId)) {\n throw new InvalidClientIdError(\n `buildStreamBody requires a v2 client_id (^c_[A-Za-z0-9]{22}$); got ${JSON.stringify(params.clientId ?? null)}.`,\n /^(main|file:|sel:).*/.test(resolvedClientId) ? 'legacy_format' : 'missing',\n params.sessionId ?? null,\n )\n }\n const body: Record<string, unknown> = {\n // JETP-045 P3 §2.2 / AC-INTERACTION-001:interaction_id 必须显式上行,禁止后端走 default_factory 兜底\n interaction_id: params.interactionId,\n session_id: params.sessionId ?? -1,\n type: 'user_input',\n contents,\n agents: [agentEntry],\n tools: [],\n caller_instance_id: params.callerInstanceId != null ? String(params.callerInstanceId) : '-1',\n // JETP-045 P2 §2.3 / AC-CLIENT-006:client_id 上行,后端透传到 Notification / DB\n client_id: resolvedClientId,\n }\n // JETP-045 Phase 6 (P6-T05) / AC-CONN-003:connection_id 上行(snake_case,与\n // SourceEvent.connection_id Pydantic 字段对齐;后端 alias=connectionId 也支持驼峰)。\n // 缺省(旧前端 / 测试 mock)时不写入 → 后端按\"未知连接\"处理,向后兼容。\n if (params.connectionId && params.connectionId.trim()) {\n body.connection_id = params.connectionId.trim()\n }\n if (params.selectedSkills && params.selectedSkills.length > 0) {\n body.selectedSkills = params.selectedSkills\n }\n body.catalog_fragment = buildCatalogFragment()\n // 客户端环境上下文(IANA 时区 / UTC offset / locale)随消息上行。\n // 与 catalog_fragment 同一注入路径:SDK 自治、不经过 params;宿主通过\n // getClientContext 钩子可覆盖任意字段,缺省字段由内置 Intl 兜底,确保\n // 永远有合法的 timezone / offset 字段('UTC' / 0 兜底)。\n body.client_context = buildClientContextPayload(this.options.getClientContext?.())\n if (params.activeSpecIds && params.activeSpecIds.length > 0) {\n body.active_spec_ids = params.activeSpecIds\n }\n // model_override:仅当前端显式指定时下行;后端 ``ModelOverride`` Pydantic 校验\n // 名称非空、scope 合法,否则 422。snake_case 与后端 alias_generator=camel_to_snake 对齐。\n if (params.modelOverride && params.modelOverride.name) {\n const mo: Record<string, unknown> = { name: params.modelOverride.name }\n if (params.modelOverride.scope) mo.scope = params.modelOverride.scope\n if (params.modelOverride.settings && Object.keys(params.modelOverride.settings).length > 0) {\n mo.settings = params.modelOverride.settings\n }\n body.model_override = mo\n }\n return body\n }\n\n /**\n * Convert raw JetAgents Notification SSE to ChatWidget flat SSEMessage format.\n * Mirrors JetForge's AIStreamEvent.to_chat_widget_messages() logic.\n */\n transformSSEMessage(raw: Record<string, unknown>): SSEMessage[] | null {\n const rawType = String(raw.type ?? '')\n\n if (rawType === 'session_info' || rawType === 'connection_closing') {\n return [raw as unknown as SSEMessage]\n }\n\n // JETP-045 P7 / AC-CHANNEL-004:边界兜底 — 业务路径已无 channel_id,但旧后端仍可能下发,\n // 在 adapter 边界折叠到 client_id 后即丢弃;上层 SSEMessage / AggregatedMessage 不再可见。\n const resolveClientId = (r: Record<string, unknown>): string | undefined => {\n const v = (r.client_id ?? r.clientId ?? r.channel_id ?? r.channelId)\n return v == null ? undefined : String(v)\n }\n // JETP-045 P3 §2.1 / AC-INTERACTION-002:协议层 interaction_id 优先;event_source_id / id 兼容\n const resolveInteractionId = (r: Record<string, unknown>): string =>\n String(r.interaction_id ?? r.interactionId ?? r.event_source_id ?? r.id ?? '')\n\n // JETP-045 Phase 6:finish / error / 业务帧 共同的 connection_id_from 解析\n const earlyConnectionIdFromRaw = raw.connection_id_from ?? raw.connectionIdFrom\n const earlyConnectionIdFrom = earlyConnectionIdFromRaw == null || earlyConnectionIdFromRaw === ''\n ? undefined\n : String(earlyConnectionIdFromRaw)\n\n if (rawType === 'finish') {\n const cid = resolveClientId(raw)\n return [{\n type: 'finish',\n interaction_id: resolveInteractionId(raw),\n session_id: raw.session_id as number,\n client_id: cid,\n connection_id_from: earlyConnectionIdFrom,\n } as unknown as SSEMessage]\n }\n\n if (rawType === 'error') {\n const cid = resolveClientId(raw)\n return [{\n type: 'error',\n interaction_id: resolveInteractionId(raw),\n content_type: 'text',\n content: String(raw.content ?? raw.message ?? 'Unknown error'),\n client_id: cid,\n connection_id_from: earlyConnectionIdFrom,\n } as unknown as SSEMessage]\n }\n\n const ext = (raw.ext as Record<string, unknown>) ?? {}\n const cid = resolveClientId(raw)\n\n // JETP-045 P4 (P2-T04):透传后端 NodeNotification/Notification.stream_uuid,\n // 供 useMessageAggregator.messageKey 主分支聚合使用。\n // 旧后端不下发该字段 → undefined → 走兜底分支保持向后兼容。\n const streamUuidRaw = raw.stream_uuid ?? raw.streamUuid\n const streamUuid = streamUuidRaw == null || streamUuidRaw === ''\n ? undefined\n : String(streamUuidRaw)\n\n // JETP-045 P5 (P2-T10):透传后端 turn_index(实时 SSE/WS 帧)。\n // 旧后端不下发 → undefined → useChatWidgetController 不推进 cursor。\n const turnIndexRaw = raw.turn_index ?? raw.turnIndex\n const turnIndex =\n typeof turnIndexRaw === 'number'\n ? turnIndexRaw\n : (typeof turnIndexRaw === 'string' && turnIndexRaw !== ''\n ? Number(turnIndexRaw)\n : undefined)\n // JETP-045 P5:透传 callee_instance_id;旧后端通常用 agent_instance_id 表达\n // callee(top-level instance),这里同时回退 agent_instance_id 保证 cursor key 可建。\n const calleeRaw = raw.callee_instance_id ?? raw.calleeInstanceId ?? raw.agent_instance_id\n const calleeInstanceId =\n typeof calleeRaw === 'number'\n ? calleeRaw\n : (typeof calleeRaw === 'string' && calleeRaw !== ''\n ? Number(calleeRaw)\n : undefined)\n\n // JETP-045 Phase 6 (P6-T05) / AC-CONN-005:透传后端 Notification.connection_id_from。\n // 旧后端不下发 → undefined → useMessageAggregator 走非 echo 分支,保持向后兼容。\n const connectionIdFrom = earlyConnectionIdFrom\n\n const base: Record<string, unknown> = {\n interaction_id: resolveInteractionId(raw),\n agent_instance_id: raw.agent_instance_id ?? 0,\n call_batch_id: String(raw.call_batch_id ?? 0),\n parent_call_batch_id: raw.parent_call_batch_id != null ? String(raw.parent_call_batch_id) : null,\n level: raw.level ?? 0,\n agent_name: raw.agent_name ?? raw.agent_id ?? 'Assistant',\n task_purpose: ext.task_purpose ?? null,\n notification_type: rawType,\n tool_name: ext.tool_name ?? null,\n tool_call_id: ext.tool_call_id ?? null,\n tool_status: ext.status ?? null,\n args_preview: ext.args_preview ?? null,\n ui_config: ext.ui_config ?? null,\n parent_tool_call_id: ext.parent_tool_call_id ?? null,\n timestamp: String(raw.timestamp ?? ''),\n caller_type: raw.caller_type,\n client_id: cid,\n stream_uuid: streamUuid,\n turn_index: turnIndex,\n callee_instance_id: calleeInstanceId,\n connection_id_from: connectionIdFrom,\n }\n\n const contents = raw.contents as Array<{ type?: string; content?: unknown }> | undefined\n\n const MCP_LIFECYCLE_TYPES = new Set([\n 'mcp_generating', 'mcp_start', 'mcp_end',\n 'compression_started', 'compression_completed',\n ])\n\n if (!contents || contents.length === 0) {\n if (MCP_LIFECYCLE_TYPES.has(rawType)) {\n return [{ ...base, content_type: 'text', content: '' } as unknown as SSEMessage]\n }\n return null\n }\n\n return contents.map((c) => {\n const contentValue = c.content\n const cAny = c as Record<string, unknown>\n const msg: Record<string, unknown> = {\n ...base,\n content_type: c.type ?? 'text',\n content: typeof contentValue === 'string' ? contentValue : JSON.stringify(contentValue ?? ''),\n }\n if (cAny.spec_id) msg.spec_id = cAny.spec_id\n if (cAny.render_mode) msg.render_mode = cAny.render_mode\n return msg as unknown as SSEMessage\n })\n }\n\n async shareArtifact(params: {\n artifactId: string\n sessionId: number\n title?: string\n artifactType?: 'file' | 'jr-page'\n shareType?: 1 | 2\n }): Promise<{ shareCode: string; shareUrl: string; password?: string } | null> {\n try {\n const hipBaseUrl = this.options.hipBaseUrl ?? ''\n const url = `${hipBaseUrl}/api/v1/artifact-share`\n const body: Record<string, unknown> = {\n artifact_id: params.artifactId,\n session_id: params.sessionId,\n share_type: params.shareType ?? 1,\n title: params.title,\n artifact_type: params.artifactType ?? 'jr-page',\n }\n const response = await this.authedFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n const json = await response.json() as { code?: number; data?: { share_code: string; password?: string } }\n\n let shareCode: string | undefined\n if (response.status === 409 && json.data?.share_code) {\n shareCode = json.data.share_code\n } else if (response.ok && json.data?.share_code) {\n shareCode = json.data.share_code\n }\n\n if (!shareCode) return null\n return {\n shareCode,\n shareUrl: `${hipBaseUrl}/share/${shareCode}`,\n password: json.data?.password,\n }\n } catch {\n return null\n }\n }\n\n async listDirectoryFiles(\n sessionId: number,\n dirPrefix: string,\n options?: ListDirectoryFilesOptions,\n ): Promise<DirectoryFileEntry[]> {\n const params = new URLSearchParams()\n params.set('git_path', dirPrefix)\n if (options?.recursive !== undefined) {\n params.set('recursive', String(options.recursive))\n }\n if (options?.generateUrls !== undefined) {\n params.set('generate_urls', String(options.generateUrls))\n }\n if (options?.extensions) {\n for (const ext of options.extensions) {\n params.append('extensions', ext)\n }\n }\n const res = await this.fetchJSON<{\n data: { items?: DirectoryFileEntry[] }\n }>(`/api/workspace/files/${sessionId}?${params.toString()}`)\n return res.data?.items ?? []\n }\n\n async getPoolStatus(sessionId: number): Promise<PoolStatusResponse> {\n return this.fetchJSON<PoolStatusResponse>(`/api/monitor/pool/${sessionId}`)\n }\n\n /**\n * 拉取可选模型清单。**走 hip-server,不走 fusion**(见 ChatWidgetAdapter.listModels 注释)。\n *\n * - hipBaseUrl 缺省时直接抛错(拒绝 fall back 到 ``baseUrl``,避免误把 jetagents\n * 当成模型注册表);这种配置下上层 picker 应表现为\"未启用模型选择\"。\n * - 后端约定:响应体 ``{ success, data: { items, total } }``;这里把内层 data 拆出来\n * 给上层,与其他 adapter 方法风格一致。\n * - hip 端字段是 snake_case(``default_channel``);在这一层做一次转 camelCase,\n * 上游业务永远只见 camelCase。\n */\n async listModels<TGroup extends 'basename' | 'name' | 'none' = 'basename'>(\n params?: ListModelsParams & { groupBy?: TGroup },\n ): Promise<\n ListModelsResponse<\n TGroup extends 'basename'\n ? ModelListItemBasenameGrouped\n : TGroup extends 'name'\n ? ModelListItemGrouped\n : ModelListItemRaw\n >\n > {\n // hipBaseUrl 为空 → 走相对 URL,与本类内其他 hip 调用(如 shareArtifact)保持\n // 一致,让 yumiai-web 的 vite dev proxy(/api/v1/models → HIP_TARGET) 接管转发。\n const hipBaseUrl = this.options.hipBaseUrl ?? ''\n const groupBy = (params?.groupBy ?? 'basename') as 'basename' | 'name' | 'none'\n const qs =\n groupBy === 'basename'\n ? '?group_by=basename'\n : groupBy === 'name'\n ? '?group_by=name'\n : ''\n\n const raw = await this.fetchHipJSON<{\n success?: boolean\n data?: { items?: unknown[]; total?: number }\n }>(hipBaseUrl, `/api/v1/models${qs}`)\n const payload = raw.data ?? { items: [], total: 0 }\n const rawItems = Array.isArray(payload.items) ? payload.items : []\n\n // 字段读取兜底:available / any_available / available_channels 都是 hip 端\n // 新加的\"软信号\"字段,老版本 hip 不返回——adapter 这层**不补 true 兜底**,\n // 透出 undefined 让 ModelPicker 那一侧按\"未定义即视为可用\"处理(与 types.ts 注释一致)。\n const readAvailable = (r: Record<string, unknown>): boolean | undefined =>\n typeof r.available === 'boolean' ? r.available : undefined\n const readAnyAvailable = (r: Record<string, unknown>): boolean | undefined => {\n const v = (r.any_available ?? r.anyAvailable) as unknown\n return typeof v === 'boolean' ? v : undefined\n }\n const readStringArray = (v: unknown): string[] | undefined =>\n Array.isArray(v) ? (v as unknown[]).map(String) : undefined\n\n if (groupBy === 'basename') {\n const toVariant = (v: unknown): ModelListVariant => {\n const r = (v ?? {}) as Record<string, unknown>\n return {\n name: String(r.name ?? ''),\n channel: String(r.channel ?? ''),\n created: typeof r.created === 'number' ? (r.created as number) : 0,\n available: readAvailable(r),\n }\n }\n const items: ModelListItemBasenameGrouped[] = rawItems.map((it) => {\n const r = it as Record<string, unknown>\n const variants = Array.isArray(r.variants) ? (r.variants as unknown[]).map(toVariant) : []\n const defaultRaw = (r.default_variant ?? r.defaultVariant) as unknown\n return {\n basename: String(r.basename ?? ''),\n variants,\n // hip 后端字段 snake_case;同时兼容 camelCase 以防未来后端归一化。\n defaultVariant: defaultRaw\n ? toVariant(defaultRaw)\n : (variants[0] ?? { name: '', channel: '', created: 0 }),\n created: typeof r.created === 'number' ? (r.created as number) : 0,\n anyAvailable: readAnyAvailable(r),\n }\n })\n return { items, total: payload.total ?? items.length } as ListModelsResponse<\n TGroup extends 'basename'\n ? ModelListItemBasenameGrouped\n : TGroup extends 'name'\n ? ModelListItemGrouped\n : ModelListItemRaw\n >\n }\n\n if (groupBy === 'name') {\n const items: ModelListItemGrouped[] = rawItems.map((it) => {\n const r = it as Record<string, unknown>\n return {\n name: String(r.name ?? ''),\n channels: Array.isArray(r.channels) ? (r.channels as string[]) : [],\n availableChannels: readStringArray(r.available_channels ?? r.availableChannels),\n defaultChannel: String((r.default_channel ?? r.defaultChannel) ?? ''),\n created: typeof r.created === 'number' ? (r.created as number) : 0,\n anyAvailable: readAnyAvailable(r),\n }\n })\n return { items, total: payload.total ?? items.length } as ListModelsResponse<\n TGroup extends 'basename'\n ? ModelListItemBasenameGrouped\n : TGroup extends 'name'\n ? ModelListItemGrouped\n : ModelListItemRaw\n >\n }\n\n const items: ModelListItemRaw[] = rawItems.map((it) => {\n const r = it as Record<string, unknown>\n return {\n id: String(r.id ?? ''),\n name: String(r.name ?? ''),\n channel: String(r.channel ?? ''),\n created: typeof r.created === 'number' ? (r.created as number) : 0,\n available: readAvailable(r),\n }\n })\n return { items, total: payload.total ?? items.length } as ListModelsResponse<\n TGroup extends 'basename'\n ? ModelListItemBasenameGrouped\n : TGroup extends 'name'\n ? ModelListItemGrouped\n : ModelListItemRaw\n >\n }\n\n /**\n * 拉取 agent 在后端注册的默认模型,仅供 picker 展示态使用。\n *\n * 三态全部吞成 null(详见 ChatWidgetAdapter.getAgentDefaultModel 注释):\n * - 业务找不到:hip 返回 ``{ success: false, error.code: 'NOT_FOUND' }``(HTTP 200);\n * - 上游异常 / 网络 / 超时 / 5xx:fetchHipJSON 抛 ChatWidgetNetworkError,这里 catch 后返回 null;\n * - 200 但 ``data.name`` 缺失:当作脏数据,返回 null。\n *\n * 这种策略避免\"agent 默认模型查不到\"阻塞用户输入;实在需要追错的话看 ``console.warn``。\n */\n async getAgentDefaultModel(agentId: string): Promise<{ name: string; displayName?: string; version?: string } | null> {\n if (!agentId) return null\n const hipBaseUrl = this.options.hipBaseUrl ?? ''\n try {\n const raw = await this.fetchHipJSON<{\n success?: boolean\n data?: { name?: string; display_name?: string; displayName?: string; version?: string }\n error?: { code?: string; message?: string }\n }>(hipBaseUrl, `/api/v1/agents/${encodeURIComponent(agentId)}/default-model`)\n\n if (raw?.success === false) return null\n\n const name = raw?.data?.name\n if (!name) return null\n\n return {\n name,\n displayName: raw.data?.display_name ?? raw.data?.displayName,\n version: raw.data?.version,\n }\n } catch (err) {\n // 故意降级:picker 展示用的查询,故障时让\"显示默认模型\"兜底,不阻塞用户。\n // 真要排错时这条 warn 是入口;正式环境 noisy 时可以再降级到 debug。\n console.warn('[chat-widget] getAgentDefaultModel failed, fall back to placeholder:', err)\n return null\n }\n }\n\n async postDiscussionMessage(\n sessionId: number,\n req: PostDiscussionMessageRequest,\n ): Promise<PostDiscussionMessageResponse> {\n return this.fetchJSON<PostDiscussionMessageResponse>(\n `/api/session/${sessionId}/discussion/message`,\n { method: 'POST', body: JSON.stringify(req) },\n )\n }\n\n // JETP-075 — user-initiated discussion creation. Adapter port that lets\n // host (yumiai-web WorkspaceCore) trigger backend `.disc.md` materialization\n // and receive the resolved `discussion_path` for floating-window binding.\n // Wire shape mirrors postDiscussionMessage; backend protocol §00.\n async createDiscussion(\n sessionId: number,\n req: CreateDiscussionRequest,\n ): Promise<CreateDiscussionResponse> {\n return this.fetchJSON<CreateDiscussionResponse>(\n `/api/session/${sessionId}/discussion/create`,\n { method: 'POST', body: JSON.stringify(req) },\n )\n }\n\n async getPoolAgents(sessionId: number): Promise<PoolAgent[]> {\n const res = await this.fetchJSON<PoolStatusResponse>(`/api/monitor/pool/${sessionId}`)\n return res.agents ?? []\n }\n\n async downloadWorkspaceZip(sessionId: number): Promise<void> {\n const url = `${this.baseUrl}/api/workspace/files/${sessionId}/download`\n const res = await this.authedFetch(url)\n if (!res.ok) throw new Error(`Download failed: HTTP ${res.status}`)\n return this._saveBlobResponse(res, sessionId)\n }\n\n private async _saveBlobResponse(res: Response, sessionId: number): Promise<void> {\n const disposition = res.headers.get('content-disposition')\n let filename = `workspace_${sessionId}.zip`\n if (disposition) {\n const match = disposition.match(/filename=\"?([^\";\\s]+)\"?/)\n if (match) filename = match[1]\n }\n const blob = await res.blob()\n const a = document.createElement('a')\n a.href = URL.createObjectURL(blob)\n a.download = filename\n document.body.appendChild(a)\n a.click()\n setTimeout(() => {\n URL.revokeObjectURL(a.href)\n a.remove()\n }, 100)\n }\n\n async uploadFiles(files: File[], sessionId: number | undefined, clientId: string): Promise<FileUploadResult> {\n assertV2ClientIdForUpload(clientId, 'uploadFiles')\n console.log('[Adapter] uploadFiles called, files=', files.map(f => f.name), 'sessionId=', sessionId, 'clientId=', clientId, 'baseUrl=', this.baseUrl)\n const fd = new FormData()\n for (const f of files) fd.append('files', f)\n if (sessionId != null) {\n fd.append('session_id', String(sessionId))\n fd.append('target_directory', 'upload')\n }\n fd.append('client_id', clientId)\n return this.fetchMultipart<FileUploadResult>('/api/knowledge/upload/batch', fd)\n }\n\n async getUploadStatus(resourceIds: string[]): Promise<FileUploadStatusResult> {\n return this.fetchJSON<FileUploadStatusResult>('/api/knowledge/upload/status/batch', {\n method: 'POST',\n body: JSON.stringify({ resource_ids: resourceIds }),\n })\n }\n\n async uploadWorkspaceFiles(\n sessionId: number,\n files: File[],\n options: { targetDirectory?: string; clientId: string },\n ): Promise<WorkspaceUploadResult> {\n assertV2ClientIdForUpload(options?.clientId, 'uploadWorkspaceFiles')\n const fd = new FormData()\n for (const f of files) fd.append('files', f)\n fd.append('session_id', String(sessionId))\n fd.append('target_directory', options.targetDirectory ?? 'upload')\n fd.append('client_id', options.clientId)\n return this.fetchMultipart<WorkspaceUploadResult>('/api/knowledge/upload/batch', fd)\n }\n\n async createWorkspaceDirectory(\n sessionId: number,\n dirName: string,\n parentPath?: string,\n ): Promise<{ code: number; message: string }> {\n const dirPath = parentPath ? `${parentPath}/${dirName}` : dirName\n const url = `${this.baseUrl}/api/knowledge/workspace/mkdir`\n const res = await this.authedFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ session_id: sessionId, dir_path: dirPath }),\n })\n return res.json()\n }\n\n private async _wsPost(path: string, body: Record<string, unknown>): Promise<{ code: number; message: string }> {\n const res = await this.authedFetch(`${this.baseUrl}/api/knowledge${path}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n return res.json()\n }\n\n async renameWorkspaceItem(sessionId: number, oldPath: string, newName: string) {\n return this._wsPost('/workspace/rename', { session_id: sessionId, old_path: oldPath, new_name: newName })\n }\n\n async deleteWorkspaceItems(sessionId: number, paths: string[]) {\n return this._wsPost('/workspace/delete', { session_id: sessionId, paths })\n }\n\n async moveWorkspaceItems(sessionId: number, sourcePaths: string[], targetDir: string) {\n return this._wsPost('/workspace/move', { session_id: sessionId, source_paths: sourcePaths, target_dir: targetDir })\n }\n\n async copyWorkspaceItems(sessionId: number, sourcePaths: string[], targetDir: string) {\n return this._wsPost('/workspace/copy', { session_id: sessionId, source_paths: sourcePaths, target_dir: targetDir })\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 fetchHipJSON<T>(hipBaseUrl: string, path: string, init?: RequestInit): Promise<T> {\n const url = `${hipBaseUrl}${path}`\n const response = await this.authedFetch(url, {\n ...init,\n headers: {\n 'Content-Type': 'application/json',\n ...(init?.headers as Record<string, string> | undefined),\n },\n })\n\n if (!response.ok) {\n throw new ChatWidgetNetworkError(\n `HIP request failed: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n\n return response.json() as Promise<T>\n }\n\n private async fetchMultipart<T>(path: string, body: FormData): Promise<T> {\n const url = `${this.baseUrl}${path}`\n console.log('[Adapter] fetchMultipart POST', url)\n const response = await this.authedFetch(url, {\n method: 'POST',\n body,\n })\n console.log('[Adapter] fetchMultipart response:', response.status, response.statusText)\n if (!response.ok) {\n throw new ChatWidgetNetworkError(\n `Upload failed: ${response.status} ${response.statusText}`,\n response.status,\n )\n }\n return response.json() as Promise<T>\n }\n\n private static readonly FETCH_TIMEOUT_MS = 15_000\n\n private async fetchJSON<T>(path: string, init?: RequestInit): Promise<T> {\n const url = `${this.baseUrl}${path}`\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), DefaultJetAgentsAdapter.FETCH_TIMEOUT_MS)\n const signal = init?.signal\n ? anySignal(init.signal, controller.signal)\n : controller.signal\n\n try {\n const response = await this.authedFetch(url, {\n ...init,\n signal,\n headers: {\n 'Content-Type': 'application/json',\n ...(init?.headers as Record<string, string> | undefined),\n },\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 } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') {\n throw new ChatWidgetNetworkError(`Request timeout: ${path}`, 0)\n }\n throw err\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * JETP-056 P2 — adapter 内部所有 HTTP 出口统一走这一条路径:\n * - 自动注入 `getAuthHeaders()`(caller header 优先级更高,可覆盖);\n * - 401 → `refreshAuth()` 单次重试;重试仍非 401 直接返回(让 caller 处理 200/4xx/5xx);\n * - refresh 失败或重试仍 401 → `onAuthFailure()` + 抛 `ChatWidgetAuthError`;\n * - 不消费 body,返回 raw `Response`,让 caller 决定 `.json()` / `.blob()` / 错误处理。\n *\n * 这是 adapter 侧\"统一鉴权 + 401 兜底\"的唯一出口,等价于 React 侧的 `useAuthedFetch`。\n * 散落 fetch(HITL upload / artifact-share / mkdir / wsPost / resource raw / download zip)\n * 都已收敛到此方法,避免漏注 401 处理与 token 漂移。\n */\n private async authedFetch(url: string, init?: RequestInit): Promise<Response> {\n const callerHeaders = (init?.headers as Record<string, string> | undefined) ?? {}\n const buildHeaders = () => ({\n ...this.getAuthHeaders(),\n ...callerHeaders,\n })\n\n let response = await fetch(url, { ...init, headers: buildHeaders() })\n if (response.status !== 401) return response\n\n const refreshed = await this.refreshAuth()\n if (refreshed) {\n response = await fetch(url, { ...init, headers: buildHeaders() })\n if (response.status !== 401) return response\n }\n this.onAuthFailure()\n throw new ChatWidgetAuthError('Authentication failed')\n }\n}\n","import type { ExecutionStatus } from '../types'\nimport type { ChatWidgetMessages } from '../i18n'\nimport type { IconName } from '../components/Icon/Icon'\n\nexport function getStatusDisplay(\n sessionBusy: boolean,\n connectionStatus: string,\n executionStatus: ExecutionStatus,\n i18n: ChatWidgetMessages,\n): { icon: string; iconName: IconName; text: string } {\n if (connectionStatus === 'connecting') {\n return { icon: '', iconName: 'hourglass', text: i18n['status.connecting'] }\n }\n if (executionStatus === 'compressing') {\n return { icon: '', iconName: 'compress', text: i18n['status.compressing'] }\n }\n if (connectionStatus === 'error') {\n return { icon: '', iconName: 'xCircle', text: i18n['status.error'] }\n }\n if (sessionBusy || executionStatus === 'running') {\n return { icon: '', iconName: 'spinner', text: i18n['status.running'] }\n }\n return { icon: '', iconName: 'circle', text: i18n['status.idle'] }\n}\n","import React from 'react'\nimport type { AgentInstanceState } from '../../hooks/useSessionChannel.js'\nimport { Icon } from '../Icon/Icon'\nimport { useChatWidgetI18n } from '../../i18n'\nimport { useEscStack, ESC_PRIORITY } from '../../hooks/useEscStack.js'\nimport './AgentGroupPanel.css'\n\nexport interface AgentGroupPanelProps {\n open: boolean\n onClose: () => void\n agents: Map<number, AgentInstanceState>\n onPause: (agentInstanceId: number) => void\n onResume: (agentInstanceId: number) => void\n onStop: (agentInstanceId: number) => void\n}\n\nconst statusColor: Record<string, string> = {\n running: 'var(--ycw-color-success, #22c55e)',\n paused: 'var(--ycw-color-warning, #f59e0b)',\n finished: 'var(--ycw-color-text-tertiary, #999)',\n stopped: 'var(--ycw-color-danger, #ef4444)',\n error: 'var(--ycw-color-danger, #ef4444)',\n}\n\nconst AgentGroupPanel: React.FC<AgentGroupPanelProps> = ({\n open,\n onClose,\n agents,\n onPause,\n onResume,\n onStop,\n}) => {\n const { t } = useChatWidgetI18n()\n\n useEscStack(() => { onClose(); return true }, open, ESC_PRIORITY.OVERLAY)\n\n if (!open) return null\n\n const agentList = Array.from(agents.values()).sort(\n (a, b) => a.agentInstanceId - b.agentInstanceId,\n )\n\n return (\n <div className=\"ycw-agent-group-panel\">\n <div className=\"ycw-agent-group-backdrop\" onClick={onClose} />\n <div className=\"ycw-agent-group-sheet\">\n <div className=\"ycw-agent-group-header\">\n <span className=\"ycw-agent-group-title\">\n {t('agentControl.groupTitle')}\n </span>\n <button className=\"ycw-agent-group-close\" onClick={onClose} aria-label={t('annotation.close')}>\n <Icon name=\"x\" size={18} aria-hidden />\n </button>\n </div>\n\n <div className=\"ycw-agent-group-list\">\n {agentList.length === 0 && (\n <div className=\"ycw-agent-group-empty\">No active agents</div>\n )}\n {agentList.map(agent => (\n <div key={agent.agentInstanceId} className=\"ycw-agent-group-item\">\n <span\n className=\"ycw-agent-group-dot\"\n style={{ background: statusColor[agent.status] || statusColor.running }}\n />\n <div className=\"ycw-agent-group-info\">\n <span className=\"ycw-agent-group-name\">\n {agent.name || `Agent #${agent.agentInstanceId}`}\n </span>\n <span className=\"ycw-agent-group-status\">{agent.status}</span>\n </div>\n <div className=\"ycw-agent-group-actions\">\n {agent.status === 'running' && (\n <>\n <button\n className=\"ycw-agent-group-btn\"\n onClick={() => onPause(agent.agentInstanceId)}\n title={t('agentControl.pause')}\n >\n <Icon name=\"pause\" size={14} aria-hidden />\n </button>\n <button\n className=\"ycw-agent-group-btn ycw-agent-group-btn--danger\"\n onClick={() => onStop(agent.agentInstanceId)}\n title={t('agentControl.stop')}\n >\n <Icon name=\"stop\" size={14} aria-hidden />\n </button>\n </>\n )}\n {agent.status === 'paused' && (\n <>\n <button\n className=\"ycw-agent-group-btn\"\n onClick={() => onResume(agent.agentInstanceId)}\n title={t('agentControl.resume')}\n >\n <Icon name=\"play\" size={14} aria-hidden />\n </button>\n <button\n className=\"ycw-agent-group-btn ycw-agent-group-btn--danger\"\n onClick={() => onStop(agent.agentInstanceId)}\n title={t('agentControl.stop')}\n >\n <Icon name=\"stop\" size={14} aria-hidden />\n </button>\n </>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n\nexport default AgentGroupPanel\n","import React, { useMemo } from 'react'\nimport { ResourceContext } from './ResourceContext.js'\nimport type { ResourceContextValue } from './ResourceContext.js'\n\ninterface ShareResourceProviderProps {\n /** Base URL for the share API (e.g., \"https://api.example.com/share\") */\n shareBaseUrl: string\n /** Share token for authentication */\n shareToken?: string\n children: React.ReactNode\n}\n\nexport const ShareResourceProvider: React.FC<ShareResourceProviderProps> = ({\n shareBaseUrl,\n shareToken,\n children,\n}) => {\n const value = useMemo<ResourceContextValue>(() => ({\n async resolveResource(resourceId: string) {\n const url = `${shareBaseUrl}/resource/${resourceId}`\n const headers: Record<string, string> = {\n 'Accept': 'application/json',\n }\n if (shareToken) {\n headers['Authorization'] = `Bearer ${shareToken}`\n }\n\n const res = await fetch(url, { headers })\n if (!res.ok) {\n throw new Error(`Share resource fetch failed: HTTP ${res.status}`)\n }\n\n const data = await res.json()\n return {\n url: data.download_url || data.content_url,\n content: data.content,\n contentUrl: data.content_url,\n mimeType: data.mime_type,\n fileName: data.file_name,\n isText: !data.is_binary,\n }\n },\n async resolvePreviewUrl(resourceId: string, format: 'html' | 'pdf') {\n return `${shareBaseUrl}/resource/${resourceId}/preview?format=${format}`\n },\n }), [shareBaseUrl, shareToken])\n\n return (\n <ResourceContext value={value}>\n {children}\n </ResourceContext>\n )\n}\n"],"mappings":"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","names":["React","useCallback","useEffect","useMemo","useRef","useState","useCallback","useContext","useEffect","useMemo","useRef","useState","round","useRef","useCallback","useEffect","useRef","useState","useCallback","useCallback","useState","useRef","useCallback","useEffect","useCallback","useEffect","useRef","useState","next","existing","type","useRef","useState","useCallback","useEffect","useCallback","useEffect","useRef","useState","useCallback","useEffect","useRef","useState","code","useState","useRef","useCallback","useEffect","start","rawContent","msg","useRef","useEffect","useCallback","useMemo","useContext","useState","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useMemo","useEffect","useState","jsx","useState","useEffect","jsx","useState","useCallback","useMemo","useRef","useEffect","jsx","jsxs","useState","useCallback","useMemo","useRef","t","useEffect","useMemo","jsx","jsxs","useMemo","useRef","useState","useEffect","useCallback","jsx","jsxs","useRef","useState","useEffect","useCallback","jsx","jsxs","round","useMemo","formatTime","useMemo","jsx","jsxs","ATTACHMENT_RE","ATTACH_ROW_HEIGHT","round","useMemo","memo","Streamdown","code","mermaid","createMathPlugin","cjk","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","useState","jsx","jsxs","useRef","useMemo","Renderer","useEffect","useState","useRef","Streamdown","code","cjk","jsx","jsxs","code","cjk","useState","useRef","useEffect","t","Streamdown","useState","useCallback","jsx","jsxs","jsx","jsxs","useState","useCallback","jsx","jsxs","start","jsx","jsxs","jsx","jsxs","Streamdown","code","mermaid","createMathPlugin","cjk","Fragment","jsx","jsxs","math","createMathPlugin","streamdownPlugins","code","mermaid","cjk","Streamdown","React","useCallback","useEffect","useMemo","useRef","useState","createContext","useContext","jsx","useState","useEffect","useCallback","useRef","useMemo","jsx","jsxs","React","registry","useEffect","useState","useRef","useState","useRef","useEffect","Fragment","jsx","jsxs","math","createMathPlugin","streamdownPlugins","code","mermaid","cjk","memo","Streamdown","useState","useRef","useEffect","useMemo","jsx","jsxs","useState","useRef","useEffect","Fragment","jsx","round","React","jsx","jsxs","round","React","useCallback","jsx","jsxs","useCallback","jsx","jsxs","jsx","useState","useCallback","useEffect","useMemo","useRef","useEffect","jsx","jsxs","useState","useRef","useEffect","useCallback","useMemo","useState","useCallback","useEffect","useMemo","useRef","React","jsx","jsxs","React","useState","useEffect","useCallback","useRef","useRef","useEffect","useState","jsx","jsxs","useRef","useState","useEffect","useEffect","useCallback","useState","useCallback","useEffect","useMemo","useRef","MAX_STACK_DEPTH","CATEGORY_ICONS","useState","useEffect","useCallback","useMemo","useRef","useEffect","useRef","useRef","useEffect","jsx","jsxs","useState","useEffect","t","useRef","useCallback","useMemo","useMemo","useCallback","jsx","jsxs","useMemo","useCallback","jsx","jsxs","useState","useCallback","useRef","useEffect","jsx","jsxs","useRef","useState","useEffect","useCallback","jsx","jsxs","round","useRef","useState","useEffect","useCallback","useMemo","useState","useCallback","useRef","useEffect","useState","useCallback","useRef","useEffect","jsx","jsxs","jsx","jsxs","useState","useRef","useEffect","useCallback","jsx","jsxs","jsx","jsxs","useRef","useEffect","fileTypeColor","jsx","jsxs","useRef","useEffect","fileTypeColor","useEffect","useRef","useRef","useEffect","useEffect","useRef","useState","useEffect","useRef","Fragment","jsx","jsxs","useRef","useState","useCallback","useEffect","useMemo","useState","useCallback","useRef","useEffect","useState","useRef","useCallback","useEffect","useCallback","useState","useCallback","useEffect","useRef","useState","round","useCallback","useContext","useRef","useState","useContext","useState","useRef","useCallback","useEffect","useState","useState","useEffect","useCallback","useEffect","useRef","useState","useCallback","useRef","useMemo","useCallback","useState","useState","useCallback","useEffect","useRef","useState","useEffect","useCallback","useMemo","useRef","useCallback","useRef","useCallback","useMemo","useRef","useState","start","round","useState","useMemo","useRef","useCallback","useMemo","jsx","useMemo","React","useState","useCallback","useMemo","useRef","useEffect","Renderer","StateProvider","ActionProvider","VisibilityProvider","ValidationProvider","Fragment","jsx","jsxs","React","useState","registry","useRef","useEffect","Renderer","StateProvider","VisibilityProvider","ActionProvider","ValidationProvider","useMemo","useCallback","useCallback","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useCallback","useEffect","useRef","useEffect","useCallback","jsx","jsxs","useRef","useCallback","useEffect","useState","useCallback","useMemo","useRef","useEffect","useEffect","useRef","useCallback","jsx","jsxs","useRef","useCallback","useEffect","Fragment","jsx","jsxs","fileTypeColor","useRef","useEffect","useState","useCallback","useMemo","useState","useCallback","useEffect","useMemo","useRef","useEffect","useState","useCallback","useRef","useEffect","useMemo","jsx","jsxs","inGroup","outGroup","jsx","jsxs","useState","useRef","useEffect","useCallback","jsx","jsxs","useRef","useMemo","useEffect","Fragment","jsx","jsxs","STATUS_ICON","jsxs","jsx","STATUS_ICON","useState","useEffect","useCallback","Fragment","useState","useEffect","useCallback","useMemo","useRef","rawType","mentionsRaw","mentions","start","useState","useCallback","useRef","useEffect","jsx","jsxs","useState","useRef","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","jsx","jsxs","useState","useCallback","useRef","useMemo","useEffect","useState","useCallback","useRef","useEffect","useMemo","jsx","jsxs","useState","useRef","useCallback","useEffect","useMemo","useCallback","useState","jsx","jsxs","useState","useCallback","useCallback","useEffect","useRef","useState","Fragment","jsx","jsxs","useState","useRef","useEffect","useCallback","useState","useCallback","useMemo","useCallback","useMemo","useRef","code","useRef","useMemo","useCallback","opts","useEffect","useMemo","useRef","useRef","useMemo","useEffect","useEffect","useRef","useRef","useEffect","useCallback","useState","jsx","jsxs","useState","useCallback","Fragment","jsx","jsxs","useMemo","useRef","useState","useCallback","useEffect","round","React","useCallback","stop","useCallback","useEffect","useRef","useState","useState","useRef","useEffect","useCallback","useRef","useCallback","useState","jsx","jsxs","useRef","useState","useCallback","placeholder","useCallback","useContext","useEffect","useMemo","useRef","useState","React","useEffect","useRef","jsx","jsxs","React","SkillSelector","useRef","useEffect","useCallback","useRef","useState","useCallback","useRef","useEffect","useState","useCallback","useRef","useCallback","useCallback","useEffect","useMemo","useRef","useState","useCallback","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useMemo","useCallback","useEffect","isAuto","useEffect","useRef","useState","jsx","jsxs","useRef","useContext","useMemo","useState","useEffect","useCallback","useCallback","jsx","jsxs","useCallback","_cached","V2_CID_RE","cid","items","Fragment","jsx","jsxs","useMemo","jsx","useMemo"]}
|