@huyooo/ai-chat-frontend-react 0.2.14 → 0.2.16

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.
Files changed (76) hide show
  1. package/dist/index.css +0 -1
  2. package/dist/index.js +1 -5418
  3. package/package.json +4 -5
  4. package/dist/index.css.map +0 -1
  5. package/dist/index.js.map +0 -1
  6. package/src/adapter.ts +0 -68
  7. package/src/components/ChatPanel.tsx +0 -553
  8. package/src/components/common/ConfirmDialog.css +0 -136
  9. package/src/components/common/ConfirmDialog.tsx +0 -91
  10. package/src/components/common/CopyButton.css +0 -22
  11. package/src/components/common/CopyButton.tsx +0 -46
  12. package/src/components/common/IndexingSettings.css +0 -207
  13. package/src/components/common/IndexingSettings.tsx +0 -398
  14. package/src/components/common/SettingsPanel.css +0 -337
  15. package/src/components/common/SettingsPanel.tsx +0 -215
  16. package/src/components/common/Toast.css +0 -50
  17. package/src/components/common/Toast.tsx +0 -38
  18. package/src/components/common/ToggleSwitch.css +0 -52
  19. package/src/components/common/ToggleSwitch.tsx +0 -20
  20. package/src/components/header/ChatHeader.css +0 -285
  21. package/src/components/header/ChatHeader.tsx +0 -376
  22. package/src/components/input/AtFilePicker.css +0 -147
  23. package/src/components/input/AtFilePicker.tsx +0 -519
  24. package/src/components/input/ChatInput.css +0 -283
  25. package/src/components/input/ChatInput.tsx +0 -575
  26. package/src/components/input/DropdownSelector.css +0 -231
  27. package/src/components/input/DropdownSelector.tsx +0 -333
  28. package/src/components/input/ImagePreviewModal.css +0 -124
  29. package/src/components/input/ImagePreviewModal.tsx +0 -118
  30. package/src/components/input/at-views/AtBranchView.tsx +0 -34
  31. package/src/components/input/at-views/AtBrowserView.tsx +0 -34
  32. package/src/components/input/at-views/AtChatsView.tsx +0 -34
  33. package/src/components/input/at-views/AtDocsView.tsx +0 -34
  34. package/src/components/input/at-views/AtFilesView.tsx +0 -168
  35. package/src/components/input/at-views/AtTerminalsView.tsx +0 -34
  36. package/src/components/input/at-views/AtViewStyles.css +0 -143
  37. package/src/components/input/at-views/index.ts +0 -9
  38. package/src/components/message/ContentRenderer.css +0 -9
  39. package/src/components/message/MessageBubble.css +0 -193
  40. package/src/components/message/MessageBubble.tsx +0 -240
  41. package/src/components/message/PartsRenderer.css +0 -12
  42. package/src/components/message/PartsRenderer.tsx +0 -168
  43. package/src/components/message/WelcomeMessage.css +0 -221
  44. package/src/components/message/WelcomeMessage.tsx +0 -93
  45. package/src/components/message/parts/CollapsibleCard.css +0 -80
  46. package/src/components/message/parts/CollapsibleCard.tsx +0 -80
  47. package/src/components/message/parts/ErrorPart.css +0 -9
  48. package/src/components/message/parts/ErrorPart.tsx +0 -40
  49. package/src/components/message/parts/ImagePart.css +0 -49
  50. package/src/components/message/parts/ImagePart.tsx +0 -54
  51. package/src/components/message/parts/SearchPart.css +0 -44
  52. package/src/components/message/parts/SearchPart.tsx +0 -63
  53. package/src/components/message/parts/TextPart.css +0 -579
  54. package/src/components/message/parts/TextPart.tsx +0 -213
  55. package/src/components/message/parts/ThinkingPart.css +0 -9
  56. package/src/components/message/parts/ThinkingPart.tsx +0 -48
  57. package/src/components/message/parts/ToolCallPart.css +0 -246
  58. package/src/components/message/parts/ToolCallPart.tsx +0 -289
  59. package/src/components/message/parts/ToolResultPart.css +0 -67
  60. package/src/components/message/parts/index.ts +0 -13
  61. package/src/components/message/parts/visual-predicate.ts +0 -43
  62. package/src/components/message/parts/visual-render.ts +0 -19
  63. package/src/components/message/parts/visual.ts +0 -12
  64. package/src/components/message/welcome-types.ts +0 -46
  65. package/src/context/AutoRunConfigContext.tsx +0 -13
  66. package/src/context/ChatAdapterContext.tsx +0 -8
  67. package/src/context/ChatInputContext.tsx +0 -40
  68. package/src/context/RenderersContext.tsx +0 -35
  69. package/src/hooks/useChat.ts +0 -1569
  70. package/src/hooks/useImageUpload.ts +0 -345
  71. package/src/hooks/useVoiceInput.ts +0 -454
  72. package/src/hooks/useVoiceToTextInput.ts +0 -87
  73. package/src/index.ts +0 -151
  74. package/src/styles.css +0 -330
  75. package/src/types/index.ts +0 -196
  76. package/src/utils/fileIcon.ts +0 -49
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/types/index.ts","../src/hooks/useChat.ts","../src/context/ChatInputContext.tsx","../src/context/RenderersContext.tsx","../src/components/ChatPanel.tsx","../src/components/header/ChatHeader.tsx","../src/components/message/WelcomeMessage.tsx","../src/components/message/welcome-types.ts","../src/components/message/MessageBubble.tsx","../src/components/message/PartsRenderer.tsx","../src/components/message/parts/CollapsibleCard.tsx","../src/components/message/parts/TextPart.tsx","../src/components/message/parts/visual-predicate.ts","../src/components/message/parts/visual-render.ts","../src/components/message/parts/ThinkingPart.tsx","../src/components/message/parts/SearchPart.tsx","../src/components/message/parts/ToolCallPart.tsx","../src/components/input/DropdownSelector.tsx","../src/components/common/CopyButton.tsx","../src/components/message/parts/ImagePart.tsx","../src/components/message/parts/ErrorPart.tsx","../src/components/input/ChatInput.tsx","../src/components/input/AtFilePicker.tsx","../src/utils/fileIcon.ts","../src/components/input/at-views/AtFilesView.tsx","../src/components/input/at-views/AtDocsView.tsx","../src/components/input/at-views/AtTerminalsView.tsx","../src/components/input/at-views/AtChatsView.tsx","../src/components/input/at-views/AtBranchView.tsx","../src/components/input/at-views/AtBrowserView.tsx","../src/components/input/ImagePreviewModal.tsx","../src/hooks/useImageUpload.ts","../src/hooks/useVoiceToTextInput.ts","../src/hooks/useVoiceInput.ts","../src/components/common/ConfirmDialog.tsx","../src/components/common/Toast.tsx","../src/components/common/SettingsPanel.tsx","../src/components/common/ToggleSwitch.tsx","../src/components/common/IndexingSettings.tsx","../src/index.ts"],"sourcesContent":["/**\n * AI Chat 前端类型定义\n * 核心类型从 bridge-electron 导出,保持类型一致性\n * \n * 架构:消息内容使用 ContentPart 数组,支持流式渲染和自定义 UI\n */\n\n// 从 bridge-electron 导入类型\nimport type {\n ChatMode as ChatModeType,\n ThinkingMode as ThinkingModeType,\n SessionRecord as SessionRecordType,\n MessageRecord as MessageRecordType,\n ModelOption as ModelOptionType,\n ProviderType as ProviderTypeType,\n} from '@huyooo/ai-chat-bridge-electron/renderer'\n\n// 重新导出核心类型\nexport type ChatMode = ChatModeType\nexport type ThinkingMode = ThinkingModeType\nexport type SessionRecord = SessionRecordType\nexport type MessageRecord = MessageRecordType\nexport type ModelOption = ModelOptionType\nexport type ProviderType = ProviderTypeType\n\n// ==================== Content Part 类型 ====================\n// \n// 架构说明:\n// 1. 内置类型:text, code, thinking, search, tool_call, image, error\n// 2. 扩展类型:weather, stock 等业务类型(通过 partRenderers 注册渲染器)\n// 3. 工具执行完成后,如果定义了 resultType,直接生成对应类型的 Part(如 weather)\n// 4. 前端通过 partRenderers 统一渲染所有 Part 类型\n\n/** 搜索结果 */\nexport interface SearchResult {\n title: string\n url: string\n snippet: string\n}\n\n/** 文本内容 Part */\nexport interface TextPart {\n type: 'text'\n text: string\n}\n\n/** 代码块 Part(从 text 中解析,或直接返回)*/\nexport interface CodePart {\n type: 'code'\n content: string\n language?: string\n}\n\n/** 思考过程 Part */\nexport interface ThinkingPart {\n type: 'thinking'\n text: string\n status: 'running' | 'done'\n duration?: number // 秒\n}\n\n/** 搜索 Part */\nexport interface SearchPart {\n type: 'search'\n query?: string\n results?: SearchResult[]\n status: 'running' | 'done'\n}\n\n/** 工具调用 Part(仅展示执行过程,结果由具体类型 Part 渲染)*/\nexport interface ToolCallPart {\n type: 'tool_call'\n id: string\n name: string\n args?: Record<string, unknown>\n status: 'pending' | 'running' | 'done' | 'error' | 'cancelled' | 'skipped'\n // 注意:不再有 result 字段,结果由工具的 resultType 指定的 Part 类型渲染\n /** 工具执行输出(用于 execute_command 等需要展示 stdout/stderr 的工具) */\n output?: {\n stdout?: string\n stderr?: string\n }\n}\n\n/** 图片 Part */\nexport interface ImagePart {\n type: 'image'\n url: string\n}\n\n/** 错误 Part */\nexport interface ErrorPart {\n type: 'error'\n message: string\n category?: string\n retryable?: boolean\n}\n\n// ==================== 扩展 Part 类型(业务类型)====================\n\n/** 天气 Part(由 get_weather 工具生成)*/\nexport interface WeatherPart {\n type: 'weather'\n city: string\n temperature: number\n condition: string\n humidity: number\n wind: string\n reportTime?: string\n province?: string\n}\n\n/** 自定义 Part 基础接口(用于扩展)*/\nexport interface CustomPart {\n type: string\n [key: string]: unknown\n}\n\n/** 内置 Part 联合类型 */\nexport type BuiltinPart =\n | TextPart\n | CodePart\n | ThinkingPart\n | SearchPart\n | ToolCallPart\n | ImagePart\n | ErrorPart\n\n/** 内容 Part 联合类型(包含内置和扩展类型)*/\nexport type ContentPart = BuiltinPart | WeatherPart | CustomPart\n\n/** 内置 Part 类型字符串 */\nexport type BuiltinPartType = BuiltinPart['type']\n\n/** 内容 Part 类型字符串 */\nexport type ContentPartType = string\n\n/** 步骤折叠模式 */\nexport type StepsExpandedType = 'open' | 'close' | 'auto'\n\n// ==================== 消息类型 ====================\n\n/** 错误详情(结构化错误信息) */\nexport interface ErrorDetails {\n category?: string\n message: string\n code?: string\n statusCode?: number\n retryable?: boolean\n retryAfter?: number\n}\n\n/** 聊天消息(前端显示用)- 新架构:基于 parts 数组 */\nexport interface ChatMessage {\n id: string\n role: 'user' | 'assistant'\n /** 内容 parts 数组 - 核心渲染数据 */\n parts: ContentPart[]\n /** 生成此消息时使用的模型 */\n model?: string\n /** 生成此消息时使用的模式 (ask/agent) */\n mode?: string\n /** 生成此消息时是否启用 web 搜索 */\n webSearchEnabled?: boolean\n /** 生成此消息时是否启用深度思考 */\n thinkingEnabled?: boolean\n /** 用户上传的图片(仅用户消息) */\n images?: string[]\n /** 是否正在加载 */\n loading?: boolean\n /** 是否已复制 */\n copied?: boolean\n /** 消息时间戳 */\n timestamp?: number\n /** 错误详情(如果有错误) */\n error?: ErrorDetails\n /** 是否被用户中止 */\n aborted?: boolean\n}\n\n/** 获取消息的纯文本内容(用于复制、保存等) */\nexport function getMessageText(message: ChatMessage): string {\n return message.parts\n .filter((p): p is TextPart => p.type === 'text')\n .map(p => p.text)\n .join('')\n}\n\n/** 输入区配置快照(用于历史回溯/重发) */\nexport interface ChatInputOptions {\n mode: ChatMode\n model: string\n webSearchEnabled: boolean\n thinkingEnabled: boolean\n}\n\n","/**\n * useChat Hook\n * 管理聊天状态和与后端的通信\n * \n * 新架构:\n * - 使用 Map 存储每个会话的独立状态\n * - 多会话可同时进行,互不干扰\n * - 切换 tab 不会停止正在进行的请求\n * - ContentPart 数组存储消息内容,支持流式渲染和自定义 UI\n */\n\nimport { useState, useCallback, useRef, useMemo, useEffect } from 'react'\nimport type {\n ChatAdapter,\n ChatEvent as BridgeChatEvent,\n ChatMode,\n SessionRecord,\n MessageRecord,\n AutoRunConfig,\n} from '@huyooo/ai-chat-bridge-electron/renderer'\nimport type { \n ChatMessage,\n ContentPart,\n TextPart,\n ThinkingPart,\n SearchPart,\n ToolCallPart,\n ErrorPart,\n SearchResult,\n} from '../types'\n\n// 扩展事件类型:允许 bridge 端新增事件时前端不被类型卡死\ntype ChatEvent = Omit<BridgeChatEvent, 'type'> & {\n type: BridgeChatEvent['type'] | 'tool_call_output'\n}\n\n// ==================== @ 上下文(文件引用) ====================\n// 约定:AtFilePicker 插入的格式为单行 \"@<path>\",通常以换行分隔\nconst AT_LINE_RE = /^\\s*@\\s*(.+?)\\s*$/\nconst MAX_FILE_CHARS = 20_000\n\nfunction stripAtContextLines(text: string): string {\n return text\n .split('\\n')\n .filter((line) => !AT_LINE_RE.test(line))\n .join('\\n')\n .trim()\n}\n\nfunction extractAtContextRefs(text: string): { refs: string[]; cleanedText: string } {\n const refs: string[] = []\n const kept: string[] = []\n\n for (const line of text.split('\\n')) {\n const m = line.match(AT_LINE_RE)\n if (m?.[1]) {\n refs.push(m[1])\n } else {\n kept.push(line)\n }\n }\n\n return {\n refs: Array.from(new Set(refs.map((r) => r.trim()).filter(Boolean))),\n cleanedText: kept.join('\\n').trim(),\n }\n}\n\nasync function buildPromptWithAtContext(adapter: ChatAdapter, text: string): Promise<string> {\n const { refs, cleanedText } = extractAtContextRefs(text)\n if (refs.length === 0) return text\n\n const blocks: string[] = []\n\n for (const ref of refs) {\n const resolved = (await adapter.resolvePath?.(ref)) || ref\n\n try {\n const stat = await adapter.stat?.(resolved)\n if (stat?.isDirectory) {\n const items = await adapter.listDir?.(resolved)\n const listing = (items || [])\n .slice(0, 200)\n .map((f) => `${f.isDirectory ? 'DIR ' : 'FILE'} ${f.path}`)\n .join('\\n')\n blocks.push(\n `【目录】${resolved}\\n` +\n '```text\\n' +\n (listing || '(空目录/无法列出)') +\n '\\n```'\n )\n continue\n }\n\n const content = await adapter.readFile?.(resolved)\n if (typeof content === 'string') {\n const truncated = content.length > MAX_FILE_CHARS\n ? content.slice(0, MAX_FILE_CHARS) + `\\n\\n... (已截断,原始长度 ${content.length})`\n : content\n blocks.push(\n `【文件】${resolved}\\n` +\n '```text\\n' +\n truncated +\n '\\n```'\n )\n } else {\n blocks.push(`【引用】${resolved}\\n(无法读取文件内容)`)\n }\n } catch (error) {\n blocks.push(`【引用】${resolved}\\n(读取失败:${error instanceof Error ? error.message : String(error)})`)\n }\n }\n\n const question = cleanedText || stripAtContextLines(text) || text\n return `以下是用户通过 @ 引用提供的上下文:\\n\\n${blocks.join('\\n\\n')}\\n\\n用户问题:\\n${question}`\n}\n\n/** 生成唯一 ID */\nfunction generateId(): string {\n return Date.now().toString(36) + Math.random().toString(36).substr(2)\n}\n\n/** 获取消息的纯文本内容 */\nfunction extractTextContent(parts: ContentPart[]): string {\n return parts\n .filter((p): p is TextPart => p.type === 'text')\n .map(p => p.text)\n .join('')\n}\n\n/** 判断事件是否需要保存到数据库 */\nfunction shouldSaveEvent(event: ChatEvent): boolean {\n return (\n event.type === 'thinking_end' ||\n event.type === 'tool_call_result' ||\n event.type === 'text_delta' ||\n event.type === 'done' ||\n event.type === 'error' ||\n event.type === 'abort'\n )\n}\n\n/** 解析工具调用结果 */\nfunction parseToolResult(result: unknown): unknown | null {\n if (result === undefined || result === null) return null\n if (typeof result === 'string') {\n try {\n return JSON.parse(result)\n } catch {\n return result\n }\n }\n return result\n}\n\n/** 转换存储的消息为显示格式 */\nfunction convertToMessage(record: MessageRecord): ChatMessage {\n // timestamp 统一为 number(毫秒时间戳),不受 JSON 序列化影响\n // 如果收到非 number 类型,说明数据异常,直接使用 0\n const timestamp = typeof record.timestamp === 'number' && Number.isFinite(record.timestamp)\n ? record.timestamp\n : 0\n let parts: ContentPart[] = []\n \n if (record.steps) {\n try {\n const steps = JSON.parse(record.steps)\n for (const step of steps) {\n if (step.type === 'thinking') {\n parts.push({\n type: 'thinking',\n text: step.text || '',\n status: step.status || 'done',\n duration: step.duration,\n })\n } else if (step.type === 'search') {\n parts.push({\n type: 'search',\n query: step.query,\n results: step.results,\n status: step.status || 'done',\n })\n } else if (step.type === 'tool_call') {\n parts.push({\n type: 'tool_call',\n id: step.id,\n name: step.name,\n args: step.args,\n result: parseToolResult(step.result),\n status: step.status || 'done',\n output: step.output,\n })\n } else if (step.type === 'text') {\n parts.push({\n type: 'text',\n text: step.text || '',\n })\n } else if (step.type === 'error') {\n parts.push({\n type: 'error',\n message: step.message || '',\n category: step.category,\n })\n }\n }\n } catch {\n // 解析失败,忽略 steps\n }\n }\n \n if (record.content && !parts.some(p => p.type === 'text')) {\n parts.push({ type: 'text', text: record.content })\n }\n \n if (parts.length === 0) {\n parts.push({ type: 'text', text: '' })\n }\n\n return {\n id: record.id,\n role: record.role,\n parts,\n images: record.images ?? [],\n model: record.model || undefined,\n mode: record.mode || undefined,\n webSearchEnabled: record.webSearchEnabled ?? undefined,\n thinkingEnabled: record.thinkingEnabled ?? undefined,\n loading: false,\n timestamp,\n }\n}\n\n/** 会话状态 */\ninterface SessionState {\n messages: ChatMessage[]\n isLoading: boolean\n abortController: AbortController | null\n /** 当前进行中的 assistant 消息 ID(用于取消/落地状态,避免依赖 message.loading 的不稳定性) */\n activeAssistantMessageId: string | null\n}\n\n/** 副作用定义 */\nexport interface SideEffect {\n type: string\n success: boolean\n data?: unknown\n message?: string\n}\n\n/** 工具完成事件数据 */\nexport interface ToolCompleteEvent {\n name: string\n result: unknown\n /** \n * 工具声明的副作用列表\n * 前端可根据此字段处理通知、刷新文件列表等\n */\n sideEffects?: SideEffect[]\n}\n\nexport interface UseChatOptions {\n adapter: ChatAdapter\n defaultModel?: string\n defaultMode?: ChatMode\n onToolComplete?: (event: ToolCompleteEvent) => void\n autoRunConfig?: AutoRunConfig\n}\n\n/**\n * 聊天状态管理 Hook\n * \n * 核心架构:\n * - sessionStatesRef: Map<sessionId, SessionState> 存储每个会话的独立状态\n * - 多会话可同时进行请求,互不干扰\n * - 切换 tab 不会停止任何正在进行的请求\n */\nexport function useChat(options: UseChatOptions) {\n const {\n adapter,\n defaultModel = 'anthropic/claude-opus-4.5',\n defaultMode = 'agent',\n onToolComplete,\n // autoRunConfig 现在从数据库读取,不再从 props 传入\n } = options\n\n // ==================== 会话状态存储 ====================\n const sessionStatesRef = useRef(new Map<string, SessionState>())\n const [stateVersion, setStateVersion] = useState(0)\n\n // ==================== 工具开关配置(从数据库读取) ====================\n /** 启用的工具名称列表(undefined 表示全部启用) */\n const [enabledTools, setEnabledTools] = useState<string[] | undefined>(undefined)\n const enabledToolsRef = useRef<string[] | undefined>(enabledTools)\n enabledToolsRef.current = enabledTools\n\n /** 所有可用工具列表(用于设置面板) */\n const [allTools, setAllTools] = useState<Array<{ name: string; description: string }>>([])\n\n // ==================== 自动运行配置(从数据库读取) ====================\n // 默认配置\n const DEFAULT_AUTO_RUN_CONFIG: AutoRunConfig = {\n mode: 'run-everything',\n }\n\n const [autoRunConfig, setAutoRunConfig] = useState<AutoRunConfig>(DEFAULT_AUTO_RUN_CONFIG)\n const autoRunConfigRef = useRef(autoRunConfig)\n autoRunConfigRef.current = autoRunConfig\n\n /** 从数据库加载自动运行配置 */\n const loadAutoRunConfig = useCallback(async () => {\n if (!adapter.getAllSettings) return\n \n try {\n const settings = await adapter.getAllSettings()\n const configJson = settings['autoRunConfig']\n \n if (configJson) {\n const config = JSON.parse(configJson) as AutoRunConfig\n // 合并配置,确保新增字段有默认值\n setAutoRunConfig({ ...DEFAULT_AUTO_RUN_CONFIG, ...config })\n }\n } catch (error) {\n console.error('[useChat] 加载 autoRunConfig 失败:', error)\n }\n }, [adapter])\n\n /** 保存自动运行配置到数据库 */\n const saveAutoRunConfig = useCallback(async (config: AutoRunConfig) => {\n if (!adapter.setSetting) return\n \n try {\n await adapter.setSetting('autoRunConfig', JSON.stringify(config))\n setAutoRunConfig(config)\n } catch (error) {\n console.error('[useChat] 保存 autoRunConfig 失败:', error)\n throw error\n }\n }, [adapter])\n\n /** 从数据库加载工具开关配置 */\n const loadEnabledTools = useCallback(async () => {\n if (!adapter.getAllSettings) return\n\n try {\n const settings = await adapter.getAllSettings()\n const toolsJson = settings['enabledTools']\n if (!toolsJson) {\n setEnabledTools(undefined)\n return\n }\n\n const parsed = JSON.parse(toolsJson) as unknown\n if (Array.isArray(parsed) && parsed.every((x) => typeof x === 'string')) {\n setEnabledTools(parsed)\n } else {\n setEnabledTools(undefined)\n }\n } catch (error) {\n console.error('[useChat] 加载 enabledTools 失败:', error)\n }\n }, [adapter])\n\n /** 保存工具开关配置到数据库 */\n const saveEnabledTools = useCallback(async (tools: string[] | undefined) => {\n if (!adapter.setSetting) return\n\n try {\n if (tools === undefined) {\n // 全部启用:删除配置(使用默认行为)\n await adapter.deleteSetting?.('enabledTools')\n setEnabledTools(undefined)\n return\n }\n\n await adapter.setSetting('enabledTools', JSON.stringify(tools))\n setEnabledTools(tools)\n } catch (error) {\n console.error('[useChat] 保存 enabledTools 失败:', error)\n throw error\n }\n }, [adapter])\n\n /** 加载所有工具列表 */\n const loadAllTools = useCallback(async () => {\n if (!adapter.getAllTools) {\n console.warn('[useChat] adapter.getAllTools 不存在')\n return\n }\n\n try {\n const tools = await adapter.getAllTools()\n setAllTools(tools)\n } catch (error) {\n console.error('[useChat] 加载工具列表失败:', error)\n }\n }, [adapter])\n\n // 初始化时加载配置\n useEffect(() => {\n loadAutoRunConfig()\n loadEnabledTools()\n loadAllTools()\n }, [loadAutoRunConfig, loadEnabledTools, loadAllTools])\n\n // 强制重新渲染\n const forceUpdate = useCallback(() => setStateVersion(v => v + 1), [])\n\n // 获取或创建会话状态\n const getSessionState = useCallback((sessionId: string): SessionState => {\n if (!sessionStatesRef.current.has(sessionId)) {\n sessionStatesRef.current.set(sessionId, {\n messages: [],\n isLoading: false,\n abortController: null,\n activeAssistantMessageId: null,\n })\n }\n return sessionStatesRef.current.get(sessionId)!\n }, [])\n\n // ==================== 全局状态 ====================\n const [sessions, setSessions] = useState<SessionRecord[]>([])\n const [currentSessionId, setCurrentSessionId] = useState<string | null>(null)\n const currentSessionIdRef = useRef<string | null>(null)\n \n // 同步 ref\n currentSessionIdRef.current = currentSessionId\n\n // 配置状态\n const [modeState, setModeState] = useState<ChatMode>(defaultMode)\n const [modelState, setModelState] = useState(defaultModel)\n const [webSearchState, setWebSearchState] = useState(true)\n const [thinkingState, setThinkingState] = useState(true)\n\n // refs for async access\n const modeRef = useRef(modeState)\n const modelRef = useRef(modelState)\n const webSearchRef = useRef(webSearchState)\n const thinkingRef = useRef(thinkingState)\n const sessionsRef = useRef(sessions)\n\n modeRef.current = modeState\n modelRef.current = modelState\n webSearchRef.current = webSearchState\n thinkingRef.current = thinkingState\n sessionsRef.current = sessions\n\n // ==================== 计算属性 ====================\n const messages = useMemo(() => {\n // 触发 stateVersion 依赖\n void stateVersion\n if (!currentSessionId) return []\n const state = sessionStatesRef.current.get(currentSessionId)\n return state?.messages || []\n }, [currentSessionId, stateVersion])\n\n const isLoading = useMemo(() => {\n void stateVersion\n if (!currentSessionId) return false\n const state = sessionStatesRef.current.get(currentSessionId)\n return state?.isLoading || false\n }, [currentSessionId, stateVersion])\n\n // ==================== 会话管理 ====================\n const loadSessions = useCallback(async () => {\n try {\n const list = await adapter.getSessions()\n setSessions(list)\n if (list.length > 0 && !currentSessionIdRef.current) {\n // 选择第一个未隐藏的会话,如果都隐藏了则选第一个\n const firstVisible = list.find(s => !s.hidden) || list[0]\n setCurrentSessionId(firstVisible.id)\n // 加载消息\n const state = getSessionState(firstVisible.id)\n if (state.messages.length === 0) {\n const savedMessages = await adapter.getMessages(firstVisible.id)\n state.messages = savedMessages.map(convertToMessage)\n forceUpdate()\n }\n // 同步配置\n setModeState(firstVisible.mode)\n setModelState(firstVisible.model)\n setWebSearchState(firstVisible.webSearchEnabled)\n setThinkingState(firstVisible.thinkingEnabled)\n }\n } catch (error) {\n console.error('加载会话失败:', error)\n }\n }, [adapter, getSessionState, forceUpdate])\n\n const switchSession = useCallback(async (sessionId: string) => {\n if (currentSessionIdRef.current === sessionId) return\n\n setCurrentSessionId(sessionId)\n \n // 无状态架构:不需要同步历史到后端\n // 发送消息时会传递历史,后端不维护状态\n\n const state = getSessionState(sessionId)\n\n if (state.messages.length === 0) {\n try {\n const savedMessages = await adapter.getMessages(sessionId)\n state.messages = savedMessages.map(convertToMessage)\n forceUpdate()\n } catch (error) {\n console.error('加载消息失败:', error)\n state.messages = []\n forceUpdate()\n }\n }\n\n const session = sessionsRef.current.find((s) => s.id === sessionId)\n if (session) {\n setModeState(session.mode)\n setModelState(session.model)\n setWebSearchState(session.webSearchEnabled)\n setThinkingState(session.thinkingEnabled)\n }\n }, [adapter, getSessionState, forceUpdate])\n\n const createNewSession = useCallback(async () => {\n try {\n const session = await adapter.createSession({\n title: '新对话',\n model: modelRef.current,\n mode: modeRef.current,\n webSearchEnabled: webSearchRef.current,\n thinkingEnabled: thinkingRef.current,\n })\n setSessions(prev => [session, ...prev])\n \n sessionStatesRef.current.set(session.id, {\n messages: [],\n isLoading: false,\n abortController: null,\n activeAssistantMessageId: null,\n })\n \n setCurrentSessionId(session.id)\n forceUpdate()\n } catch (error) {\n console.error('创建会话失败:', error)\n }\n }, [adapter, forceUpdate])\n\n const deleteSession = useCallback(async (sessionId: string) => {\n try {\n const state = sessionStatesRef.current.get(sessionId)\n if (state?.isLoading && state.abortController) {\n state.abortController.abort()\n adapter.cancel()\n }\n \n await adapter.deleteSession(sessionId)\n setSessions(prev => prev.filter((s) => s.id !== sessionId))\n sessionStatesRef.current.delete(sessionId)\n\n if (currentSessionIdRef.current === sessionId) {\n const remainingSessions = sessionsRef.current.filter(s => s.id !== sessionId)\n if (remainingSessions.length > 0) {\n setCurrentSessionId(remainingSessions[0].id)\n } else {\n setCurrentSessionId(null)\n }\n }\n forceUpdate()\n } catch (error) {\n console.error('删除会话失败:', error)\n }\n }, [adapter, forceUpdate])\n\n const hideSession = useCallback(async (sessionId: string, hidden: boolean) => {\n try {\n await adapter.updateSession(sessionId, { hidden })\n setSessions(prev => prev.map((s) =>\n s.id === sessionId ? { ...s, hidden } : s\n ))\n } catch (error) {\n console.error('更新会话隐藏状态失败:', error)\n }\n }, [adapter])\n\n const clearAllSessions = useCallback(async () => {\n try {\n for (const [, state] of sessionStatesRef.current) {\n if (state.isLoading && state.abortController) {\n state.abortController.abort()\n }\n }\n adapter.cancel()\n \n for (const session of sessionsRef.current) {\n await adapter.deleteSession(session.id)\n }\n setSessions([])\n sessionStatesRef.current.clear()\n await createNewSession()\n } catch (error) {\n console.error('清空所有会话失败:', error)\n }\n }, [adapter, createNewSession])\n\n const hideOtherSessions = useCallback(async () => {\n if (!currentSessionIdRef.current) return\n try {\n for (const session of sessionsRef.current) {\n if (session.id !== currentSessionIdRef.current && !session.hidden) {\n await adapter.updateSession(session.id, { hidden: true })\n }\n }\n setSessions(prev => prev.map((s) =>\n s.id === currentSessionIdRef.current ? s : { ...s, hidden: true }\n ))\n } catch (error) {\n console.error('隐藏其他会话失败:', error)\n }\n }, [adapter])\n\n const exportCurrentSession = useCallback((): string | null => {\n if (!currentSessionIdRef.current) return null\n const session = sessionsRef.current.find((s) => s.id === currentSessionIdRef.current)\n if (!session) return null\n\n const state = sessionStatesRef.current.get(currentSessionIdRef.current)\n const msgs = state?.messages || []\n\n return JSON.stringify({\n session: {\n id: session.id,\n title: session.title,\n model: session.model,\n mode: session.mode,\n createdAt: session.createdAt,\n updatedAt: session.updatedAt,\n },\n messages: msgs.map((msg) => ({\n id: msg.id,\n role: msg.role,\n parts: msg.parts,\n model: msg.model,\n mode: msg.mode,\n timestamp: msg.timestamp,\n })),\n exportedAt: new Date().toISOString(),\n }, null, 2)\n }, [])\n\n const deleteCurrentSession = useCallback(async () => {\n if (currentSessionIdRef.current) {\n await deleteSession(currentSessionIdRef.current)\n }\n }, [deleteSession])\n\n // ==================== 消息更新 ====================\n const updateSessionMessage = useCallback((\n sessionId: string, \n messageIndex: number, \n event: ChatEvent\n ) => {\n const state = sessionStatesRef.current.get(sessionId)\n if (!state) return\n\n const msg = state.messages[messageIndex]\n if (!msg) return\n\n const updatedMsg = { ...msg }\n let parts = [...updatedMsg.parts]\n\n switch (event.type) {\n case 'thinking_start': {\n parts.push({ type: 'thinking', text: '', status: 'running' })\n break\n }\n\n case 'thinking_delta': {\n const data = event.data as { content: string }\n // 查找最后一个 running 状态的 thinking part\n const lastThinkingIndex = parts.findLastIndex(\n p => p.type === 'thinking' && p.status === 'running'\n )\n if (lastThinkingIndex >= 0) {\n // 追加到现有的 running thinking part\n const part = parts[lastThinkingIndex] as ThinkingPart\n parts[lastThinkingIndex] = { ...part, text: part.text + data.content }\n }\n // ⚠️ 关键修复:如果没有 running 的 thinking part,忽略此事件(不创建新的)\n // thinking_start 事件负责创建,thinking_delta 只负责追加\n break\n }\n\n case 'thinking_end': {\n const data = event.data as { duration: number }\n const lastThinkingIndex = parts.findLastIndex(\n p => p.type === 'thinking' && p.status === 'running'\n )\n if (lastThinkingIndex >= 0) {\n const part = parts[lastThinkingIndex] as ThinkingPart\n parts[lastThinkingIndex] = {\n ...part,\n status: 'done',\n duration: Math.round(data.duration / 1000),\n }\n }\n break\n }\n\n case 'search_start': {\n const data = event.data as { query?: string }\n const searchPart: SearchPart = { type: 'search', query: data.query, status: 'running' }\n\n // UX:搜索结果事件可能在 text_delta 之后才到达(Provider 侧以 annotation/结果到达为准)\n // 若直接 push,会导致\"搜索卡片\"显示在回答之后。\n // 这里优先插入到第一个 text part 之前(通常在 thinking 后面),保持视觉顺序符合用户预期。\n const firstTextIndex = parts.findIndex(p => p.type === 'text')\n if (firstTextIndex >= 0) {\n parts.splice(firstTextIndex, 0, searchPart)\n } else {\n parts.push(searchPart)\n }\n break\n }\n\n case 'search_result': {\n const data = event.data as { results: SearchResult[] }\n const lastSearchIndex = parts.findLastIndex(p => p.type === 'search')\n if (lastSearchIndex >= 0) {\n const part = parts[lastSearchIndex] as SearchPart\n parts[lastSearchIndex] = { ...part, results: data.results, status: 'done' }\n }\n break\n }\n\n case 'search_end': {\n const lastSearchIndex = parts.findLastIndex(\n p => p.type === 'search' && p.status === 'running'\n )\n if (lastSearchIndex >= 0) {\n const part = parts[lastSearchIndex] as SearchPart\n parts[lastSearchIndex] = { ...part, status: 'done' }\n }\n break\n }\n\n case 'tool_approval_request': {\n const data = event.data as { id: string; name: string; args: Record<string, unknown> }\n \n // 如果当前模式是自动执行,直接批准(处理发送消息后切换模式的情况)\n if (autoRunConfigRef.current.mode === 'run-everything') {\n adapter.respondToolApproval?.(data.id, true)\n // 不创建 pending 状态,等待 tool_call_start 事件\n break\n }\n \n // manual 模式:创建 pending 状态等待用户确认\n const existingIndex = parts.findIndex(\n p => p.type === 'tool_call' && (p as ToolCallPart).id === data.id\n )\n if (existingIndex >= 0) {\n // 更新现有 part 为 pending\n const part = parts[existingIndex] as ToolCallPart\n parts[existingIndex] = { ...part, status: 'pending' }\n } else {\n // 创建新的 pending part\n parts.push({\n type: 'tool_call',\n id: data.id,\n name: data.name,\n args: data.args,\n status: 'pending',\n })\n }\n break\n }\n\n case 'tool_call_start': {\n const data = event.data as { id: string; name: string; args: Record<string, unknown> }\n // 检查是否已存在 pending 状态的 part\n const existingIndex = parts.findIndex(\n p => p.type === 'tool_call' && (p as ToolCallPart).id === data.id\n )\n if (existingIndex >= 0) {\n // 更新现有 part 为 running\n const part = parts[existingIndex] as ToolCallPart\n parts[existingIndex] = { ...part, status: 'running' }\n } else {\n // 创建新的 running part\n parts.push({\n type: 'tool_call',\n id: data.id,\n name: data.name,\n args: data.args,\n status: 'running',\n })\n }\n break\n }\n\n case 'tool_call_result': {\n const data = event.data as { \n id: string\n name: string\n result: string\n success: boolean\n resultType?: string // 结果类型(用于生成具体类型的 Part)\n }\n \n let parsedResult: unknown = data.result\n try {\n parsedResult = JSON.parse(data.result)\n } catch {\n // 保持原始字符串\n }\n\n // 判断状态:检查是否是跳过或取消操作\n const isSkipped = typeof parsedResult === 'object' && parsedResult !== null && \n 'skipped' in parsedResult && (parsedResult as { skipped?: boolean }).skipped === true\n const isCancelled = typeof parsedResult === 'object' && parsedResult !== null && \n 'cancelled' in parsedResult && (parsedResult as { cancelled?: boolean }).cancelled === true\n const status: 'done' | 'error' | 'cancelled' | 'skipped' = \n isSkipped ? 'skipped' : (isCancelled ? 'cancelled' : (data.success ? 'done' : 'error'))\n\n // 查找对应的 tool_call 并更新状态\n const toolCallIndex = parts.findIndex(\n p => p.type === 'tool_call' && (p as ToolCallPart).id === data.id\n )\n \n if (toolCallIndex >= 0) {\n // 更新 tool_call 状态(不再包含 result 字段)\n const toolCall = parts[toolCallIndex] as ToolCallPart\n parts[toolCallIndex] = {\n ...toolCall,\n status,\n }\n } else {\n // 如果没有对应的 tool_call,创建一个新的\n parts.push({\n type: 'tool_call',\n id: data.id,\n name: data.name,\n args: {},\n status,\n })\n }\n\n // 如果工具定义了 resultType 且执行成功,生成对应类型的 Part\n if (data.resultType && data.success && typeof parsedResult === 'object' && parsedResult !== null) {\n // 找到 tool_call 的位置,在其后插入结果 Part\n const updatedToolCallIndex = parts.findIndex(\n p => p.type === 'tool_call' && (p as ToolCallPart).id === data.id\n )\n \n // 创建具体类型的 Part(如 { type: 'weather', city: '北京', ... })\n const resultPart = {\n type: data.resultType,\n ...parsedResult as Record<string, unknown>,\n }\n \n // 检查是否已存在同类型的结果 Part(避免重复)\n const existingResultIndex = parts.findIndex(\n (p, i) => i > updatedToolCallIndex && p.type === data.resultType\n )\n \n if (existingResultIndex >= 0) {\n // 更新现有的结果 Part\n parts[existingResultIndex] = resultPart\n } else {\n // 插到对应 tool_call 之后\n const insertAt = updatedToolCallIndex >= 0 ? updatedToolCallIndex + 1 : parts.length\n parts.splice(insertAt, 0, resultPart)\n }\n }\n\n if (onToolComplete) {\n // 从事件数据中获取副作用声明\n const sideEffects = (data as { sideEffects?: SideEffect[] }).sideEffects\n onToolComplete({\n name: data.name,\n result: parsedResult,\n sideEffects,\n })\n }\n break\n }\n\n case 'tool_call_output': {\n const data = event.data as { id: string; name: string; stream: 'stdout' | 'stderr'; chunk: string }\n const toolCallIndex = parts.findIndex(\n p => p.type === 'tool_call' && (p as ToolCallPart).id === data.id\n )\n if (toolCallIndex >= 0) {\n const toolCall = parts[toolCallIndex] as ToolCallPart\n const prevStdout = toolCall.output?.stdout ?? ''\n const prevStderr = toolCall.output?.stderr ?? ''\n const MAX = 120_000\n\n const nextOutput =\n data.stream === 'stdout'\n ? { stdout: (prevStdout + (data.chunk || '')).slice(-MAX), stderr: prevStderr }\n : { stdout: prevStdout, stderr: (prevStderr + (data.chunk || '')).slice(-MAX) }\n\n parts[toolCallIndex] = {\n ...toolCall,\n output: nextOutput,\n }\n }\n break\n }\n\n case 'text_delta': {\n const data = event.data as { content: string }\n \n parts = parts.map(p => \n p.type === 'search' && p.status === 'running' \n ? { ...p, status: 'done' as const } \n : p\n )\n \n // 查找最后一个 text part\n const lastTextIndex = parts.findLastIndex(p => p.type === 'text')\n \n // 检查最后一个 part 是否是已完成的工具调用/思考\n // 如果是,说明这是新一轮的文本输出,应该创建新的 text part\n //\n // 注意:search 结果可能会在文本输出过程中到达(甚至夹在 text_delta 中间),\n // 如果把 search(done) 也作为“新一轮文本”的边界,会导致文本被拆成多个 TextPart。\n const lastPart = parts[parts.length - 1]\n const shouldCreateNew = lastPart && (\n (lastPart.type === 'tool_call' && ['done', 'error', 'skipped', 'cancelled'].includes((lastPart as ToolCallPart).status)) ||\n (lastPart.type === 'thinking' && (lastPart as ThinkingPart).status === 'done')\n )\n \n if (shouldCreateNew || lastTextIndex < 0) {\n // 创建新的 text part\n parts.push({ type: 'text', text: data.content })\n } else {\n // 追加到现有的 text part\n const part = parts[lastTextIndex] as TextPart\n parts[lastTextIndex] = { ...part, text: part.text + data.content }\n }\n break\n }\n\n case 'error': {\n const data = event.data as { category?: string; message: string; retryable?: boolean }\n \n parts = parts.map(p => {\n if (p.type === 'thinking' && p.status === 'running') return { ...p, status: 'done' as const }\n if (p.type === 'search' && p.status === 'running') return { ...p, status: 'done' as const }\n if (p.type === 'tool_call' && p.status === 'running') return { ...p, status: 'error' as const }\n return p\n })\n \n parts.push({\n type: 'error',\n message: data.message,\n category: data.category,\n retryable: data.retryable,\n })\n \n updatedMsg.loading = false\n updatedMsg.error = data\n break\n }\n\n case 'abort': {\n parts = parts.map(p => {\n if (p.type === 'thinking' && p.status === 'running') return { ...p, status: 'done' as const }\n if (p.type === 'search' && p.status === 'running') return { ...p, status: 'done' as const }\n if (p.type === 'tool_call' && p.status === 'running') return { ...p, status: 'cancelled' as const }\n return p\n })\n updatedMsg.loading = false\n updatedMsg.aborted = true\n break\n }\n\n case 'done':\n updatedMsg.loading = false\n break\n }\n\n updatedMsg.parts = parts\n state.messages = [...state.messages]\n state.messages[messageIndex] = updatedMsg\n forceUpdate()\n }, [onToolComplete, forceUpdate])\n\n /**\n * 保存消息到数据库\n */\n const saveMessageToDb = useCallback(async (\n sessionId: string,\n messageIndex: number,\n messageId: string\n ) => {\n const state = sessionStatesRef.current.get(sessionId)\n if (!state) return\n \n const msg = state.messages[messageIndex]\n if (!msg) return\n \n try {\n await adapter.updateMessage?.({\n id: messageId,\n content: extractTextContent(msg.parts),\n steps: JSON.stringify(msg.parts),\n })\n } catch (error) {\n console.error('[useChat/react] 保存消息失败:', error)\n }\n }, [adapter])\n\n /**\n * 统一的事件处理函数:更新UI并保存到数据库\n * 保证UI更新和DB保存的原子性\n */\n const handleEvent = useCallback(async (\n sessionId: string,\n messageIndex: number,\n event: ChatEvent,\n messageId: string,\n options: { saveToDb: boolean } = { saveToDb: false }\n ) => {\n // 1. 先更新UI\n updateSessionMessage(sessionId, messageIndex, event)\n \n // 2. 如果需要保存,立即保存(保证UI和DB一致)\n if (options.saveToDb && shouldSaveEvent(event)) {\n await saveMessageToDb(sessionId, messageIndex, messageId)\n }\n }, [updateSessionMessage, saveMessageToDb])\n\n // ==================== 发送消息 ====================\n const sendMessage = useCallback(async (text: string, images?: string[]) => {\n // 允许只发送图片(text 为空但有图片)\n const hasContent = text.trim() || (images && images.length > 0)\n if (!hasContent) return\n \n let sessionId = currentSessionIdRef.current\n \n if (sessionId) {\n const currentState = sessionStatesRef.current.get(sessionId)\n if (currentState?.isLoading) {\n console.warn('[useChat] 当前会话正在进行中,请等待完成')\n return\n }\n }\n\n if (!sessionId) {\n try {\n const session = await adapter.createSession({\n title: '新对话',\n model: modelRef.current,\n mode: modeRef.current,\n })\n setSessions(prev => [session, ...prev])\n sessionStatesRef.current.set(session.id, {\n messages: [],\n isLoading: false,\n abortController: null,\n activeAssistantMessageId: null,\n })\n setCurrentSessionId(session.id)\n sessionId = session.id\n } catch (error) {\n console.error('创建会话失败:', error)\n return\n }\n }\n\n const state = getSessionState(sessionId)\n\n const userMsg: ChatMessage = {\n id: generateId(),\n role: 'user',\n parts: [{ type: 'text', text }],\n images,\n timestamp: Date.now(),\n }\n state.messages = [...state.messages, userMsg]\n forceUpdate()\n\n try {\n // 关键:传入 userMsg.id,确保\"重新发送/分叉\"能用同一个 id 做锚点更新/删除\n await adapter.saveMessage({\n id: userMsg.id,\n sessionId,\n role: 'user',\n content: text,\n images: images || [],\n })\n\n if (state.messages.length === 1) {\n const title = text.trim() \n ? text.slice(0, 20) + (text.length > 20 ? '...' : '')\n : (images && images.length > 0 ? '图片消息' : '新对话')\n await adapter.updateSession(sessionId, { title })\n setSessions(prev => prev.map((s) =>\n s.id === sessionId ? { ...s, title } : s\n ))\n }\n } catch (error) {\n console.error('保存消息失败:', error)\n }\n\n const assistantMsgIndex = state.messages.length\n const assistantMsgId = generateId() // 保存消息 ID 用于后续更新\n const assistantMsg: ChatMessage = {\n id: assistantMsgId,\n role: 'assistant',\n parts: [],\n model: modelRef.current,\n mode: modeRef.current,\n webSearchEnabled: webSearchRef.current,\n thinkingEnabled: thinkingRef.current,\n loading: true,\n timestamp: Date.now(),\n }\n state.messages = [...state.messages, assistantMsg]\n \n // 创建本次请求专用的 abortController(避免多请求竞态条件)\n const requestAbortController = new AbortController()\n state.isLoading = true\n state.abortController = requestAbortController\n state.activeAssistantMessageId = assistantMsgId\n forceUpdate()\n \n const sendModel = modelRef.current\n const sendMode = modeRef.current\n const sendWebSearch = webSearchRef.current\n const sendThinking = thinkingRef.current\n const sendEnabledTools = enabledToolsRef.current\n\n // 【关键】立即保存助手消息到数据库(初始状态)\n try {\n await adapter.saveMessage({\n id: assistantMsgId,\n sessionId,\n role: 'assistant',\n content: '',\n model: sendModel,\n mode: sendMode,\n webSearchEnabled: sendWebSearch,\n thinkingEnabled: sendThinking,\n steps: '[]',\n })\n } catch (error) {\n console.error('创建助手消息失败:', error)\n }\n\n // 增量保存函数\n const saveMessageProgress = async () => {\n const msg = state.messages[assistantMsgIndex]\n if (!msg) return\n try {\n await adapter.updateMessage?.({\n id: assistantMsgId,\n content: extractTextContent(msg.parts),\n steps: JSON.stringify(msg.parts),\n })\n } catch (error) {\n console.error('更新消息失败:', error)\n }\n }\n\n try {\n // 构建历史消息(不包括刚添加的用户消息和助手占位消息)\n const history = state.messages.slice(0, -2).map(msg => ({\n role: msg.role as 'user' | 'assistant' | 'system' | 'tool',\n // history 中去掉 @ 引用行(避免后续轮次出现“空引用”干扰)\n content: stripAtContextLines(extractTextContent(msg.parts)),\n }))\n \n const cleanAutoRunConfig: AutoRunConfig = { ...autoRunConfigRef.current }\n const promptMessage = await buildPromptWithAtContext(adapter, text)\n\n for await (const event of adapter.sendMessage(\n promptMessage,\n {\n mode: sendMode,\n model: sendModel,\n enableWebSearch: sendWebSearch,\n thinkingMode: sendThinking ? 'enabled' : 'disabled',\n enabledTools: sendEnabledTools,\n autoRunConfig: cleanAutoRunConfig,\n history, // 传递历史消息\n },\n images,\n sessionId // 传递 sessionId 用于事件过滤\n )) {\n // 使用本次请求专用的 abortController 检查(避免被新请求覆盖)\n if (requestAbortController.signal.aborted) break\n\n // 统一处理事件:更新UI并保存到数据库\n await handleEvent(sessionId, assistantMsgIndex, event, assistantMsgId, {\n saveToDb: true, // 重要事件需要保存\n })\n\n if (event.type === 'done' || event.type === 'error') {\n break\n }\n }\n } catch (error) {\n console.error('发送消息失败:', error)\n await handleEvent(\n sessionId,\n assistantMsgIndex,\n {\n type: 'error',\n data: { message: error instanceof Error ? error.message : String(error) },\n },\n assistantMsgId,\n { saveToDb: true }\n )\n } finally {\n state.isLoading = false\n \n const finalMsg = state.messages[assistantMsgIndex]\n if (finalMsg) {\n state.messages = [...state.messages]\n state.messages[assistantMsgIndex] = { ...finalMsg, loading: false }\n }\n\n // 【关键】最终保存一次,确保所有内容都被持久化\n await saveMessageToDb(sessionId, assistantMsgIndex, assistantMsgId)\n\n state.abortController = null\n state.activeAssistantMessageId = null\n forceUpdate()\n }\n }, [adapter, getSessionState, handleEvent, saveMessageToDb, forceUpdate])\n\n // ==================== 其他方法 ====================\n const patchPartsAsAborted = useCallback((parts: ContentPart[]): ContentPart[] => {\n return parts.map((p) => {\n if (p.type === 'thinking' && (p as ThinkingPart).status === 'running') {\n return { ...(p as ThinkingPart), status: 'done' as const }\n }\n if (p.type === 'search' && (p as SearchPart).status === 'running') {\n return { ...(p as SearchPart), status: 'done' as const }\n }\n if (p.type === 'tool_call') {\n const tool = p as ToolCallPart\n if (tool.status === 'running' || tool.status === 'pending') {\n return { ...tool, status: 'cancelled' as const }\n }\n }\n return p\n })\n }, [])\n\n const cancelActiveAssistantMessage = useCallback((sessionId: string) => {\n const state = sessionStatesRef.current.get(sessionId)\n if (!state) return\n if (!state.activeAssistantMessageId) return\n const idx = state.messages.findIndex((m) => m.id === state.activeAssistantMessageId)\n if (idx < 0) return\n const msg = state.messages[idx]\n state.messages = [...state.messages]\n state.messages[idx] = {\n ...msg,\n loading: false,\n aborted: true,\n parts: patchPartsAsAborted(msg.parts),\n }\n }, [patchPartsAsAborted])\n\n const cancelRequest = useCallback(() => {\n if (!currentSessionIdRef.current) return\n const sessionId = currentSessionIdRef.current\n const state = sessionStatesRef.current.get(sessionId)\n\n // 先做 UI 即时落地:精准命中本轮 assistant 消息\n cancelActiveAssistantMessage(sessionId)\n if (state) {\n state.abortController?.abort()\n state.isLoading = false\n state.activeAssistantMessageId = null\n forceUpdate()\n }\n adapter.cancel()\n }, [adapter, forceUpdate, cancelActiveAssistantMessage])\n\n const copyMessage = useCallback(async (messageId: string) => {\n if (!currentSessionIdRef.current) return\n const state = sessionStatesRef.current.get(currentSessionIdRef.current)\n if (!state) return\n\n const msg = state.messages.find((m) => m.id === messageId)\n if (!msg) return\n\n try {\n const textContent = extractTextContent(msg.parts)\n await navigator.clipboard.writeText(textContent)\n \n state.messages = state.messages.map((m) =>\n m.id === messageId ? { ...m, copied: true } : m\n )\n forceUpdate()\n \n setTimeout(() => {\n const s = sessionStatesRef.current.get(currentSessionIdRef.current!)\n if (s) {\n s.messages = s.messages.map((m) =>\n m.id === messageId ? { ...m, copied: false } : m\n )\n forceUpdate()\n }\n }, 2000)\n } catch (err) {\n console.error('复制失败:', err)\n }\n }, [forceUpdate])\n\n /** 从指定索引重新发送消息(编辑后重发,分叉:删除其后的所有消息并重新生成) */\n const resendFromIndex = useCallback(async (index: number, text: string) => {\n if (!currentSessionIdRef.current) return\n const sessionId = currentSessionIdRef.current\n const state = sessionStatesRef.current.get(sessionId)\n if (!state) return\n\n const targetMsg = state.messages[index]\n if (!targetMsg || targetMsg.role !== 'user') {\n // 容错:如果传入的不是 user 消息索引,退化为普通发送\n sendMessage(text)\n return\n }\n\n // 如果当前会话正在生成,先取消,避免并发造成状态错乱\n if (state.isLoading) {\n state.abortController?.abort()\n adapter.cancel()\n state.isLoading = false\n state.abortController = null\n }\n\n // 1) UI:保留该条 user 消息,并更新文本;删除其后的所有消息(分叉)\n const updatedUserMsg: ChatMessage = {\n ...targetMsg,\n parts: [{ type: 'text', text }],\n }\n state.messages = [...state.messages.slice(0, index), updatedUserMsg]\n forceUpdate()\n\n // 2) DB:删除该 user 消息之后的所有消息(用于分叉)\n // 新架构:只使用 messageId 作为锚点(更稳定),后端用 messageId 查 timestamp 再删除\n try {\n await adapter.deleteMessagesAfterMessageId(sessionId, updatedUserMsg.id)\n } catch (error) {\n console.error('[useChat/react] deleteMessagesAfterMessageId 失败:', error)\n }\n\n // 3) DB:更新该条 user 消息内容(需要保证 saveMessage 使用同一个 id)\n try {\n await adapter.updateMessage?.({\n id: updatedUserMsg.id,\n content: text,\n })\n } catch (error) {\n console.warn('[useChat/react] updateMessage(user) 失败,已忽略:', error)\n }\n\n // 4) 从该 user 消息继续生成 assistant(不再新建 user 消息)\n const assistantMsgIndex = state.messages.length\n const assistantMsgId = generateId()\n const assistantMsg: ChatMessage = {\n id: assistantMsgId,\n role: 'assistant',\n parts: [],\n model: modelRef.current,\n mode: modeRef.current,\n webSearchEnabled: webSearchRef.current,\n thinkingEnabled: thinkingRef.current,\n loading: true,\n timestamp: Date.now(),\n }\n state.messages = [...state.messages, assistantMsg]\n\n const requestAbortController = new AbortController()\n state.isLoading = true\n state.abortController = requestAbortController\n state.activeAssistantMessageId = assistantMsgId\n forceUpdate()\n\n // 保存当前配置快照\n const sendModel = modelRef.current\n const sendMode = modeRef.current\n const sendWebSearch = webSearchRef.current\n const sendThinking = thinkingRef.current\n const sendEnabledTools = enabledToolsRef.current\n\n // 立即保存助手消息到数据库(初始状态)\n try {\n await adapter.saveMessage({\n id: assistantMsgId,\n sessionId,\n role: 'assistant',\n content: '',\n model: sendModel,\n mode: sendMode,\n webSearchEnabled: sendWebSearch,\n thinkingEnabled: sendThinking,\n steps: '[]',\n })\n } catch (error) {\n console.error('[useChat/react] 创建 assistant 消息失败:', error)\n }\n\n // 使用统一的事件处理函数\n\n try {\n // history:取该 user 消息之前的消息(不包含当前 user)\n const history = state.messages.slice(0, index).map(msg => ({\n role: msg.role as 'user' | 'assistant' | 'system' | 'tool',\n content: stripAtContextLines(extractTextContent(msg.parts)),\n }))\n\n const cleanAutoRunConfig: AutoRunConfig = { ...autoRunConfigRef.current }\n const images = updatedUserMsg.images\n const promptMessage = await buildPromptWithAtContext(adapter, text)\n\n for await (const event of adapter.sendMessage(\n promptMessage,\n {\n mode: sendMode,\n model: sendModel,\n enableWebSearch: sendWebSearch,\n thinkingMode: sendThinking ? 'enabled' : 'disabled',\n enabledTools: sendEnabledTools,\n autoRunConfig: cleanAutoRunConfig,\n history,\n },\n images,\n sessionId\n )) {\n if (requestAbortController.signal.aborted) break\n \n // 统一处理事件:更新UI并保存到数据库\n await handleEvent(sessionId, assistantMsgIndex, event, assistantMsgId, {\n saveToDb: true, // 重要事件需要保存\n })\n \n if (event.type === 'done' || event.type === 'error') break\n }\n } catch (error) {\n console.error('[useChat/react] 分叉重发失败:', error)\n await handleEvent(\n sessionId,\n assistantMsgIndex,\n {\n type: 'error',\n data: { message: error instanceof Error ? error.message : String(error) },\n },\n assistantMsgId,\n { saveToDb: true }\n )\n } finally {\n // 收尾:取消 loading 状态\n const s = sessionStatesRef.current.get(sessionId)\n if (s) {\n s.isLoading = false\n s.abortController = null\n s.activeAssistantMessageId = null\n const finalMsg = s.messages[assistantMsgIndex]\n if (finalMsg) {\n s.messages[assistantMsgIndex] = { ...finalMsg, loading: false }\n }\n forceUpdate()\n }\n // 【关键】最终保存一次,确保所有内容都被持久化\n await saveMessageToDb(sessionId, assistantMsgIndex, assistantMsgId)\n }\n }, [adapter, forceUpdate, sendMessage, handleEvent, saveMessageToDb])\n\n const regenerateMessage = useCallback((messageIndex: number) => {\n if (!currentSessionIdRef.current) return\n const state = sessionStatesRef.current.get(currentSessionIdRef.current)\n if (!state) return\n\n if (messageIndex > 0 && state.messages[messageIndex - 1]?.role === 'user') {\n const userIndex = messageIndex - 1\n const userMsg = state.messages[userIndex]\n const userText = extractTextContent(userMsg.parts)\n void resendFromIndex(userIndex, userText)\n }\n }, [resendFromIndex])\n\n const setWorkingDirectory = useCallback((dir: string) => {\n if (adapter.setCwd) {\n adapter.setCwd(dir)\n }\n }, [adapter])\n\n // ==================== 返回 ====================\n return {\n sessions,\n currentSessionId,\n messages,\n isLoading,\n mode: modeState,\n model: modelState,\n webSearch: webSearchState,\n thinking: thinkingState,\n\n loadSessions,\n switchSession,\n createNewSession,\n deleteSession,\n deleteCurrentSession,\n hideSession,\n clearAllSessions,\n hideOtherSessions,\n exportCurrentSession,\n\n sendMessage,\n cancelRequest,\n copyMessage,\n regenerateMessage,\n resendFromIndex,\n\n setMode: (value: ChatMode) => {\n setModeState(value)\n if (currentSessionIdRef.current) {\n adapter.updateSession(currentSessionIdRef.current, { mode: value }).catch((e: Error) =>\n console.error('更新会话 mode 失败:', e)\n )\n }\n },\n setModel: (value: string) => {\n setModelState(value)\n if (currentSessionIdRef.current) {\n adapter.updateSession(currentSessionIdRef.current, { model: value }).catch((e: Error) =>\n console.error('更新会话 model 失败:', e)\n )\n }\n },\n setWebSearch: (value: boolean) => {\n setWebSearchState(value)\n if (currentSessionIdRef.current) {\n adapter.updateSession(currentSessionIdRef.current, { webSearchEnabled: value }).catch((e: Error) =>\n console.error('更新会话 webSearchEnabled 失败:', e)\n )\n }\n },\n setThinking: (value: boolean) => {\n setThinkingState(value)\n if (currentSessionIdRef.current) {\n adapter.updateSession(currentSessionIdRef.current, { thinkingEnabled: value }).catch((e: Error) =>\n console.error('更新会话 thinkingEnabled 失败:', e)\n )\n }\n },\n\n setWorkingDirectory,\n\n // 工具批准对话框\n\n // 自动运行配置\n autoRunConfig,\n loadAutoRunConfig,\n saveAutoRunConfig,\n\n // 工具管理\n enabledTools,\n allTools,\n saveEnabledTools,\n }\n}\n","/**\n * 全局 ChatInput 状态 Context\n * 用于在 MessageBubble 中的 ChatInput 共享和修改全局状态\n */\n\nimport { createContext, useContext, type ReactNode, type FC } from 'react'\nimport type { ChatMode, ModelOption } from '../types'\nimport type { ChatAdapter } from '@huyooo/ai-chat-bridge-electron/renderer'\n\nexport interface ChatInputContextValue {\n mode: ChatMode\n model: string\n models: ModelOption[]\n webSearch: boolean\n thinking: boolean\n isLoading: boolean\n /** Electron adapter(用于 @ 文件选择) */\n adapter?: ChatAdapter\n // cwd 已解耦,不再通过 context 传递\n // FileBrowser 会直接通过 adapter.setCwd() 同步到 Agent\n setMode: (value: ChatMode) => void\n setModel: (value: string) => void\n setWebSearch: (value: boolean) => void\n setThinking: (value: boolean) => void\n}\n\nconst ChatInputContext = createContext<ChatInputContextValue | null>(null)\n\ninterface ChatInputProviderProps {\n value: ChatInputContextValue\n children: ReactNode\n}\n\nexport const ChatInputProvider: FC<ChatInputProviderProps> = ({ value, children }) => {\n return <ChatInputContext.Provider value={value}>{children}</ChatInputContext.Provider>\n}\n\nexport function useChatInputContext(): ChatInputContextValue | null {\n return useContext(ChatInputContext)\n}\n","/**\n * Part 渲染器上下文\n * 用于注入自定义 Part 类型渲染器(如 weather, stock 等)\n */\n\nimport { createContext, type ComponentType, type ReactNode, type FC } from 'react'\n\n/** Part 渲染器 Props(每个自定义渲染器接收的 props) */\nexport interface PartRendererProps {\n [key: string]: unknown\n}\n\n/** Part 渲染器映射(key: part.type, value: 渲染组件) */\nexport type PartRenderers = Record<string, ComponentType<PartRendererProps>>\n\n/** Part 渲染器上下文 */\nexport const PartRenderersContext = createContext<PartRenderers>({})\n\n/** Part 渲染器 Provider Props */\ninterface PartRenderersProviderProps {\n partRenderers?: PartRenderers\n children: ReactNode\n}\n\n/** Part 渲染器 Provider */\nexport const PartRenderersProvider: FC<PartRenderersProviderProps> = ({\n partRenderers = {},\n children,\n}) => {\n return (\n <PartRenderersContext.Provider value={partRenderers}>\n {children}\n </PartRenderersContext.Provider>\n )\n}\n","/**\n * ChatPanel Component\n * 与 Vue 版本 ChatPanel.vue 保持一致\n */\n\nimport { useEffect, useRef, useCallback, useMemo, useState, forwardRef, useImperativeHandle, type ComponentType } from 'react'\nimport { Icon } from '@iconify/react'\nimport { useChat, type ToolCompleteEvent } from '../hooks/useChat'\nimport type { ImageData } from '../adapter'\nimport type { ChatAdapter, ModelOption, ChatMode } from '@huyooo/ai-chat-bridge-electron/renderer'\nimport type { AutoRunConfig } from '@huyooo/ai-chat-bridge-electron/renderer'\nimport { ChatHeader } from './header/ChatHeader'\nimport { WelcomeMessage } from './message/WelcomeMessage'\nimport type { WelcomeConfig } from './message/welcome-types'\nimport { MessageBubble } from './message/MessageBubble'\nimport { ChatInput, type ChatInputHandle } from './input/ChatInput'\nimport { ChatInputProvider } from '../context/ChatInputContext'\nimport { PartRenderersProvider, type PartRenderers } from '../context/RenderersContext'\nimport { ConfirmDialog } from './common/ConfirmDialog'\nimport { Toast } from './common/Toast'\n// ToolApprovalDialog 已移除,工具批准现在内嵌在 ToolCallPart 中\nimport { SettingsPanel } from './common/SettingsPanel'\n\n/** ChatPanel 暴露给外部的方法 */\nexport interface ChatPanelHandle {\n /** 设置输入框内容 */\n setInputText: (text: string) => void\n /** 在光标位置插入文本(用于 @ 上下文) */\n insertInputText: (text: string) => void\n /** 聚焦输入框 */\n focusInput: () => void\n /** 发送消息 */\n sendMessage: (text: string) => void\n /** 设置当前工作目录 */\n setCwd: (dir: string) => void\n}\n\ninterface ChatPanelProps {\n /** Adapter 实例 */\n adapter: ChatAdapter\n /** 默认模型 */\n defaultModel?: string\n /** 默认模式 */\n defaultMode?: ChatMode\n /** 可用模型列表 */\n models?: ModelOption[]\n /** 隐藏标题栏 */\n hideHeader?: boolean\n /** 关闭回调(有此属性时显示关闭按钮) */\n onClose?: () => void\n /** 工具执行完成回调 */\n onToolComplete?: (event: ToolCompleteEvent) => void\n /** 自定义类名 */\n className?: string\n /** 欢迎页配置 */\n welcomeConfig?: Partial<WelcomeConfig>\n /** 自定义 Part 渲染器 - 根据 part.type 选择渲染组件(如 weather, stock 等) */\n partRenderers?: PartRenderers\n /** \n * 执行步骤折叠模式\n * - 'open': 始终展开\n * - 'close': 始终折叠\n * - 'auto': 执行时展开,完成后折叠\n */\n stepsExpandedType?: 'open' | 'close' | 'auto'\n}\n\nexport const ChatPanel = forwardRef<ChatPanelHandle, ChatPanelProps>(({\n adapter,\n defaultModel = 'anthropic/claude-opus-4.5',\n defaultMode = 'agent',\n models: propModels,\n hideHeader = false,\n onClose,\n onToolComplete,\n className = '',\n welcomeConfig,\n partRenderers = {},\n stepsExpandedType = 'auto',\n}, ref) => {\n const messagesRef = useRef<HTMLDivElement>(null)\n const inputRef = useRef<ChatInputHandle>(null)\n\n // 是否应该自动滚动(用户在底部附近时才自动滚动)\n const [shouldAutoScroll, setShouldAutoScroll] = useState(true)\n // 距离底部多少像素内算\"在底部\"\n const SCROLL_THRESHOLD = 25\n // 上次滚动位置(用于检测滚动方向)\n const lastScrollTopRef = useRef(0)\n // 是否正在程序化滚动(用于区分用户手动滚动)\n const isProgrammaticScrollRef = useRef(false)\n\n // 设置面板状态\n const [settingsPanelVisible, setSettingsPanelVisible] = useState(false)\n\n // 从后端获取模型列表,如果传入了 models 则使用传入的\n const [models, setModels] = useState<ModelOption[]>(propModels || [])\n\n // 确认弹窗状态\n const [confirmDialog, setConfirmDialog] = useState<{\n visible: boolean\n title: string\n message: string\n type: 'info' | 'warning' | 'danger'\n confirmText: string\n onConfirm: () => void\n }>({\n visible: false,\n title: '确认',\n message: '',\n type: 'warning',\n confirmText: '确定',\n onConfirm: () => {},\n })\n\n /** 显示确认弹窗 */\n const showConfirm = useCallback((options: {\n title?: string\n message: string\n type?: 'info' | 'warning' | 'danger'\n confirmText?: string\n onConfirm: () => void\n }) => {\n setConfirmDialog({\n visible: true,\n title: options.title || '确认',\n message: options.message,\n type: options.type || 'warning',\n confirmText: options.confirmText || '确定',\n onConfirm: options.onConfirm,\n })\n }, [])\n\n // Toast 消息状态\n const [toast, setToast] = useState<{\n visible: boolean\n message: string\n type: 'info' | 'success' | 'warning' | 'error'\n }>({ visible: false, message: '', type: 'info' })\n\n /** 显示 Toast 消息 */\n const showToast = useCallback((message: string, type: 'info' | 'success' | 'warning' | 'error' = 'info') => {\n setToast({ visible: true, message, type })\n }, [])\n\n const {\n sessions,\n currentSessionId,\n messages,\n isLoading,\n mode,\n model,\n webSearch,\n thinking,\n loadSessions,\n switchSession,\n createNewSession,\n deleteSession,\n hideSession,\n clearAllSessions,\n hideOtherSessions,\n exportCurrentSession,\n sendMessage,\n cancelRequest,\n copyMessage,\n regenerateMessage,\n resendFromIndex,\n setMode,\n setModel,\n setWebSearch,\n setThinking,\n setWorkingDirectory,\n autoRunConfig,\n saveAutoRunConfig,\n // 工具管理\n allTools,\n enabledTools,\n saveEnabledTools,\n } = useChat({\n adapter,\n defaultModel,\n defaultMode,\n onToolComplete,\n })\n\n const handleCancelToolCall = useCallback((_toolCallId: string) => {\n cancelRequest()\n }, [cancelRequest])\n\n // 暴露给外部的方法\n useImperativeHandle(ref, () => ({\n setInputText: (text: string) => {\n inputRef.current?.setText(text)\n },\n insertInputText: (text: string) => {\n inputRef.current?.insertText(text)\n },\n focusInput: () => {\n inputRef.current?.focus()\n },\n sendMessage: (text: string) => {\n sendMessage(text)\n },\n setCwd: setWorkingDirectory,\n }), [sendMessage, setWorkingDirectory])\n\n // 初始化\n useEffect(() => {\n loadSessions()\n }, [loadSessions])\n\n // 从后端获取模型列表\n useEffect(() => {\n adapter.getModels()\n .then(setModels)\n .catch((err) => console.warn('获取模型列表失败:', err))\n }, [adapter])\n\n // 注意:cwd 已解耦,不再通过 prop 传递\n // FileBrowser 会直接通过 adapter.setCwd() 同步到 Agent\n // getCwdTool 会自动从 Agent 的 context.cwd 读取最新值\n\n // 检查是否在底部附近\n const isNearBottom = useCallback((): boolean => {\n if (!messagesRef.current) return true\n const { scrollTop, scrollHeight, clientHeight } = messagesRef.current\n return scrollHeight - scrollTop - clientHeight < SCROLL_THRESHOLD\n }, [])\n\n // 处理滚动事件(优化:检测滚动方向,区分程序化滚动)\n const handleScroll = useCallback(() => {\n if (!messagesRef.current) return\n \n // 忽略程序化滚动触发的事件\n if (isProgrammaticScrollRef.current) return\n \n const { scrollTop } = messagesRef.current\n const isScrollingUp = scrollTop < lastScrollTopRef.current\n lastScrollTopRef.current = scrollTop\n \n // 用户向上滚动时,立即停止自动滚动\n if (isScrollingUp) {\n setShouldAutoScroll(false)\n return\n }\n \n // 用户向下滚动到底部附近时,恢复自动滚动\n if (isNearBottom()) {\n setShouldAutoScroll(true)\n }\n }, [isNearBottom])\n\n // 滚动到底部\n const scrollToBottom = useCallback((force = false) => {\n if (messagesRef.current && (force || shouldAutoScroll)) {\n // 标记为程序化滚动,避免触发 handleScroll 逻辑\n isProgrammaticScrollRef.current = true\n messagesRef.current.scrollTop = messagesRef.current.scrollHeight\n lastScrollTopRef.current = messagesRef.current.scrollTop\n // 强制滚动时才恢复自动滚动\n if (force) {\n setShouldAutoScroll(true)\n }\n // 延迟重置标志,确保 scroll 事件已处理\n requestAnimationFrame(() => {\n isProgrammaticScrollRef.current = false\n })\n }\n }, [shouldAutoScroll])\n\n // 消息变化时滚动(只在用户在底部时)\n useEffect(() => {\n scrollToBottom()\n }, [messages, scrollToBottom])\n\n // 发送新消息时强制滚动到底部\n const prevIsLoadingRef = useRef(isLoading)\n useEffect(() => {\n // 开始加载时(发送消息时)强制滚动到底部\n if (isLoading && !prevIsLoadingRef.current) {\n scrollToBottom(true)\n }\n prevIsLoadingRef.current = isLoading\n }, [isLoading, scrollToBottom])\n\n // 发送消息\n const handleSend = useCallback((text: string, images?: ImageData[]) => {\n // 将 ImageData[] 转换为 string[] (data URL)\n const imageUrls = images?.map(img => `data:${img.mimeType};base64,${img.base64}`)\n sendMessage(text, imageUrls)\n }, [sendMessage])\n\n // @ 上下文\n const handleAtContext = useCallback(() => {\n // TODO: 实现 @ 上下文\n console.log('@ 上下文')\n }, [])\n\n // 快捷操作\n const handleQuickAction = useCallback(\n (text: string) => {\n sendMessage(text)\n },\n [sendMessage]\n )\n\n // 重新发送(编辑后)\n const handleResend = useCallback(\n (index: number, text: string) => {\n // 与 Vue 版一致:使用分叉重发(以当前索引为锚点,删除后续并继续生成)\n resendFromIndex(index, text)\n },\n [resendFromIndex]\n )\n\n // 创建新会话(重置输入框状态)\n const handleNewSession = useCallback(async () => {\n await createNewSession()\n // 重置输入框状态\n inputRef.current?.clear()\n }, [createNewSession])\n\n // 关闭\n const handleClose = useCallback(() => {\n onClose?.()\n }, [onClose])\n\n // 设置\n const handleSettings = useCallback(() => {\n setSettingsPanelVisible(true)\n }, [])\n\n // 保存设置(静默保存)\n const handleSaveSettings = useCallback(async (config: AutoRunConfig) => {\n try {\n await saveAutoRunConfig(config)\n } catch (error) {\n console.error('保存设置失败:', error)\n showToast('保存设置失败', 'error')\n }\n }, [saveAutoRunConfig, showToast])\n\n const handleUpdateEnabledTools = useCallback(async (tools: string[] | undefined) => {\n try {\n await saveEnabledTools(tools)\n } catch (error) {\n console.error('保存工具开关失败:', error)\n showToast('保存工具开关失败', 'error')\n }\n }, [saveEnabledTools, showToast])\n\n // 模式变更现在在 ToolCallPart 中处理,不再需要此函数\n\n // 清空所有对话\n const handleClearAll = useCallback(() => {\n showConfirm({\n title: '清空所有对话',\n message: '确定要清空所有对话吗?此操作不可恢复。',\n type: 'danger',\n confirmText: '清空',\n onConfirm: () => clearAllSessions(),\n })\n }, [showConfirm, clearAllSessions])\n\n // 关闭其他对话\n const handleCloseOthers = useCallback(async () => {\n await hideOtherSessions()\n }, [hideOtherSessions])\n\n // 导出对话\n const handleExport = useCallback(() => {\n const data = exportCurrentSession()\n if (!data) {\n showToast('当前会话没有内容可导出', 'warning')\n return\n }\n\n // 创建下载链接\n const blob = new Blob([data], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n const session = sessions.find((s) => s.id === currentSessionId)\n const filename = `chat-${session?.title || 'export'}-${new Date().toISOString().slice(0, 10)}.json`\n a.href = url\n a.download = filename\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n URL.revokeObjectURL(url)\n }, [exportCurrentSession, sessions, currentSessionId, showToast])\n\n // 复制会话 ID\n const handleCopyId = useCallback(async () => {\n if (!currentSessionId) return\n try {\n await navigator.clipboard.writeText(currentSessionId)\n showToast('已复制会话 ID', 'success')\n } catch (error) {\n console.error('复制失败:', error)\n }\n }, [currentSessionId, showToast])\n\n // 反馈\n const handleFeedback = useCallback(() => {\n console.log('反馈')\n }, [])\n\n // 全局 input 状态 context value\n const inputContextValue = useMemo(\n () => ({\n mode,\n model,\n models,\n webSearch,\n thinking,\n isLoading,\n adapter,\n // cwd 已解耦,不再通过 prop 传递\n // FileBrowser 会直接通过 adapter.setCwd() 同步到 Agent\n // getCwdTool 会自动从 Agent 的 context.cwd 读取最新值\n setMode,\n setModel,\n setWebSearch,\n setThinking,\n }),\n [mode, model, models, webSearch, thinking, isLoading, adapter, setMode, setModel, setWebSearch, setThinking]\n )\n\n return (\n <ChatInputProvider value={inputContextValue}>\n <PartRenderersProvider partRenderers={partRenderers}>\n <div className={`chat-panel ${className}`.trim()}>\n {/* 确认弹窗 */}\n <ConfirmDialog\n visible={confirmDialog.visible}\n title={confirmDialog.title}\n message={confirmDialog.message}\n type={confirmDialog.type}\n confirmText={confirmDialog.confirmText}\n onConfirm={() => {\n setConfirmDialog((prev) => ({ ...prev, visible: false }))\n confirmDialog.onConfirm()\n }}\n onCancel={() => setConfirmDialog((prev) => ({ ...prev, visible: false }))}\n />\n\n {/* Toast 消息 */}\n <Toast\n visible={toast.visible}\n message={toast.message}\n type={toast.type}\n onClose={() => setToast((prev) => ({ ...prev, visible: false }))}\n />\n\n {/* 工具批准现在内嵌在 ToolCallPart 中,不再需要全局对话框 */}\n\n {/* 设置面板 */}\n <SettingsPanel\n visible={settingsPanelVisible}\n config={autoRunConfig}\n allTools={allTools}\n enabledTools={enabledTools}\n onUpdateEnabledTools={handleUpdateEnabledTools}\n onChange={handleSaveSettings}\n onClose={() => setSettingsPanelVisible(false)}\n />\n\n {/* 顶部标题栏 */}\n {!hideHeader && (\n <ChatHeader\n sessions={sessions}\n currentSessionId={currentSessionId}\n showClose={!!onClose}\n onNewSession={handleNewSession}\n onSwitchSession={switchSession}\n onDeleteSession={deleteSession}\n onHideSession={hideSession}\n onClose={handleClose}\n onClearAll={handleClearAll}\n onCloseOthers={handleCloseOthers}\n onExport={handleExport}\n onCopyId={handleCopyId}\n onFeedback={handleFeedback}\n onSettings={handleSettings}\n />\n )}\n\n {/* 消息列表容器 */}\n <div className=\"messages-wrapper\">\n <div ref={messagesRef} className=\"messages-container chat-scrollbar\" onScroll={handleScroll}>\n {messages.length === 0 ? (\n <WelcomeMessage config={welcomeConfig} onQuickAction={handleQuickAction} />\n ) : (\n messages.map((msg, index) => (\n <MessageBubble\n key={msg.id}\n role={msg.role}\n parts={msg.parts}\n model={msg.model}\n mode={msg.mode}\n images={msg.images}\n copied={msg.copied}\n loading={msg.loading}\n timestamp={msg.timestamp}\n stepsExpandedType={stepsExpandedType}\n adapter={adapter}\n onCancelToolCall={handleCancelToolCall}\n autoRunConfig={autoRunConfig}\n onSaveConfig={saveAutoRunConfig}\n onCopy={() => copyMessage(msg.id)}\n onRegenerate={() => regenerateMessage(index)}\n onSend={(text) => handleResend(index, text)}\n />\n ))\n )}\n </div>\n {/* 滚动到底部按钮 */}\n {!shouldAutoScroll && messages.length > 0 && (\n <button\n className=\"scroll-to-bottom-btn\"\n onClick={() => scrollToBottom(true)}\n title=\"滚动到底部\"\n >\n <Icon icon=\"lucide:arrow-down\" width={16} />\n </button>\n )}\n </div>\n\n {/* 输入区域 */}\n <ChatInput\n ref={inputRef}\n isLoading={isLoading}\n mode={mode}\n model={model}\n models={models}\n webSearchEnabled={webSearch}\n thinkingEnabled={thinking}\n onSend={handleSend}\n onCancel={cancelRequest}\n onModeChange={setMode}\n onModelChange={setModel}\n onWebSearchChange={setWebSearch}\n onThinkingChange={setThinking}\n onAtContext={handleAtContext}\n />\n </div>\n </PartRenderersProvider>\n </ChatInputProvider>\n )\n})\n\n// 添加 displayName 以便于调试\nChatPanel.displayName = 'ChatPanel'\n","/**\n * ChatHeader Component\n * 与 Vue 版本 ChatHeader.vue 保持一致\n */\n\nimport { useState, useRef, useEffect, useCallback, type FC } from 'react'\nimport './ChatHeader.css'\nimport { Icon } from '@iconify/react'\nimport type { SessionRecord } from '../../types'\n\ninterface ChatHeaderProps {\n /** 当前会话列表 */\n sessions: SessionRecord[]\n /** 当前会话 ID */\n currentSessionId?: string | null\n /** 是否显示关闭按钮 */\n showClose?: boolean\n /** 创建新会话 */\n onNewSession?: () => void\n /** 切换会话 */\n onSwitchSession?: (sessionId: string) => void\n /** 删除会话 */\n onDeleteSession?: (sessionId: string) => void\n /** 隐藏/显示会话(在 tab 栏关闭但不删除) */\n onHideSession?: (sessionId: string, hidden: boolean) => void\n /** 关闭面板 */\n onClose?: () => void\n /** 清空所有对话 */\n onClearAll?: () => void\n /** 关闭其他对话 */\n onCloseOthers?: () => void\n /** 导出对话 */\n onExport?: () => void\n /** 复制请求 ID */\n onCopyId?: () => void\n /** 反馈 */\n onFeedback?: () => void\n /** Agent 设置 */\n onSettings?: () => void\n}\n\n/** 获取日期分组标签 */\nfunction getDateGroupLabel(date: Date | string): string {\n const d = new Date(date)\n const now = new Date()\n\n // 重置时间部分,只比较日期\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n const target = new Date(d.getFullYear(), d.getMonth(), d.getDate())\n const diff = today.getTime() - target.getTime()\n const days = Math.floor(diff / (1000 * 60 * 60 * 24))\n\n if (days === 0) return '今天'\n if (days === 1) return '昨天'\n\n // 其他显示具体日期\n const month = d.getMonth() + 1\n const day = d.getDate()\n return `${month}月${day}日`\n}\n\n/** 格式化时间(HH:mm) */\nfunction formatTime(date: Date | string): string {\n const d = new Date(date)\n const hours = String(d.getHours()).padStart(2, '0')\n const minutes = String(d.getMinutes()).padStart(2, '0')\n return `${hours}:${minutes}`\n}\n\n/** 按日期分组会话 */\ninterface SessionGroup {\n label: string\n sessions: SessionRecord[]\n}\n\nfunction groupSessionsByDate(sessions: SessionRecord[]): SessionGroup[] {\n const groups = new Map<string, SessionRecord[]>()\n\n for (const session of sessions) {\n const label = getDateGroupLabel(session.updatedAt)\n const group = groups.get(label)\n if (group) {\n group.push(session)\n } else {\n groups.set(label, [session])\n }\n }\n\n return Array.from(groups.entries()).map(([label, groupSessions]) => ({\n label,\n sessions: groupSessions,\n }))\n}\n\n/** 获取显示标题 */\nfunction getDisplayTitle(title: string): string {\n return title === '新对话' ? 'New Chat' : title\n}\n\nexport const ChatHeader: FC<ChatHeaderProps> = ({\n sessions,\n currentSessionId,\n showClose = false,\n onNewSession,\n onSwitchSession,\n onDeleteSession,\n onHideSession,\n onClose,\n onClearAll,\n onCloseOthers,\n onExport,\n onCopyId,\n onFeedback,\n onSettings,\n}) => {\n const [historyOpen, setHistoryOpen] = useState(false)\n const [moreMenuOpen, setMoreMenuOpen] = useState(false)\n\n const historyRef = useRef<HTMLDivElement>(null)\n const moreMenuRef = useRef<HTMLDivElement>(null)\n\n // 可见的会话(使用 sessions 的 hidden 字段)\n const visibleSessions = sessions.filter((s) => !s.hidden)\n\n // 点击外部关闭菜单\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as HTMLElement\n if (historyRef.current && !historyRef.current.contains(target)) {\n setHistoryOpen(false)\n }\n if (moreMenuRef.current && !moreMenuRef.current.contains(target)) {\n setMoreMenuOpen(false)\n }\n }\n\n document.addEventListener('click', handleClickOutside)\n return () => document.removeEventListener('click', handleClickOutside)\n }, [])\n\n // 切换历史面板\n const toggleHistory = useCallback(() => {\n setHistoryOpen((prev) => !prev)\n setMoreMenuOpen(false)\n }, [])\n\n // 切换更多菜单\n const toggleMore = useCallback(() => {\n setMoreMenuOpen((prev) => !prev)\n setHistoryOpen(false)\n }, [])\n\n // 从历史新建\n const handleNewFromHistory = useCallback(() => {\n onNewSession?.()\n setHistoryOpen(false)\n }, [onNewSession])\n\n // 选择历史\n const handleSelectHistory = useCallback(\n (sessionId: string) => {\n const session = sessions.find((s) => s.id === sessionId)\n // 如果被隐藏了,恢复显示\n if (session?.hidden) {\n onHideSession?.(sessionId, false)\n }\n onSwitchSession?.(sessionId)\n setHistoryOpen(false)\n },\n [sessions, onSwitchSession, onHideSession]\n )\n\n // 隐藏 tab(触发回调由父组件持久化到数据库)\n const handleHideTab = useCallback(\n (sessionId: string, e: React.MouseEvent) => {\n e.stopPropagation()\n onHideSession?.(sessionId, true)\n if (sessionId === currentSessionId) {\n const remaining = sessions.filter((s) => s.id !== sessionId && !s.hidden)\n if (remaining.length > 0) {\n onSwitchSession?.(remaining[0].id)\n } else {\n // 最后一个 tab 被关闭,创建新会话\n onNewSession?.()\n }\n }\n },\n [currentSessionId, sessions, onSwitchSession, onNewSession, onHideSession]\n )\n\n // 删除会话\n const handleDeleteSession = (sessionId: string, e: React.MouseEvent) => {\n e.stopPropagation()\n onDeleteSession?.(sessionId)\n }\n\n // 菜单操作\n const handleMenuAction = (action: string) => {\n setMoreMenuOpen(false)\n switch (action) {\n case 'clear-all':\n onClearAll?.()\n break\n case 'close-others':\n onCloseOthers?.()\n break\n case 'export':\n onExport?.()\n break\n case 'copy-id':\n onCopyId?.()\n break\n case 'feedback':\n onFeedback?.()\n break\n case 'settings':\n onSettings?.()\n break\n }\n }\n\n return (\n <div className=\"chat-header\">\n {/* 左侧:Tabs 可滚动区域 */}\n <div className=\"tabs-container\">\n {visibleSessions.length === 0 ? (\n <span className=\"tab-item active\">New Chat</span>\n ) : (\n visibleSessions.map((session) => {\n const isActive = session.id === currentSessionId\n return (\n <div\n key={session.id}\n className={`tab-item${isActive ? ' active' : ''}`}\n onClick={() => onSwitchSession?.(session.id)}\n title={session.title}\n >\n <span className=\"tab-title\">{getDisplayTitle(session.title)}</span>\n <button\n className=\"tab-close\"\n onClick={(e) => handleHideTab(session.id, e)}\n title=\"关闭标签\"\n >\n <Icon icon=\"lucide:x\" width={18} />\n </button>\n </div>\n )\n })\n )}\n </div>\n\n {/* 右侧:操作按钮 */}\n <div className=\"header-actions\">\n {/* 新建会话 */}\n <button className=\"icon-btn\" onClick={onNewSession} title=\"新建对话\">\n <Icon icon=\"lucide:plus\" width={18} />\n </button>\n\n {/* 历史记录 */}\n <div ref={historyRef} className=\"dropdown-container\">\n <button\n className={`icon-btn${historyOpen ? ' active' : ''}`}\n onClick={(e) => {\n e.stopPropagation()\n toggleHistory()\n }}\n title=\"历史记录\"\n >\n <Icon icon=\"lucide:clock\" width={18} />\n </button>\n\n {/* 历史记录面板 */}\n {historyOpen && (\n <div className=\"dropdown-panel history-panel\">\n <div className=\"panel-header\">\n <span>历史记录</span>\n <button className=\"icon-btn small\" title=\"新建对话\" onClick={handleNewFromHistory}>\n <Icon icon=\"lucide:plus\" width={18} />\n </button>\n </div>\n <div className=\"panel-content chat-scrollbar\">\n {sessions.length === 0 ? (\n <div className=\"empty-state\">暂无历史对话</div>\n ) : (\n groupSessionsByDate(sessions).map((group) => (\n <div key={group.label}>\n <div className=\"history-group-label\">{group.label}</div>\n {group.sessions.map((session) => {\n const isCurrent = session.id === currentSessionId\n return (\n <div\n key={session.id}\n className={`history-item${isCurrent ? ' active' : ''}`}\n onClick={() => handleSelectHistory(session.id)}\n >\n <span className=\"history-title\">{session.title}</span>\n <span className=\"history-time\">{formatTime(session.updatedAt)}</span>\n <button\n className=\"history-action-btn delete\"\n title=\"删除\"\n onClick={(e) => handleDeleteSession(session.id, e)}\n >\n <Icon icon=\"lucide:trash-2\" width={18} />\n </button>\n </div>\n )\n })}\n </div>\n ))\n )}\n </div>\n </div>\n )}\n </div>\n\n {/* 更多选项 */}\n <div ref={moreMenuRef} className=\"dropdown-container\">\n <button\n className={`icon-btn${moreMenuOpen ? ' active' : ''}`}\n onClick={(e) => {\n e.stopPropagation()\n toggleMore()\n }}\n title=\"更多选项\"\n >\n <Icon icon=\"lucide:more-horizontal\" width={18} />\n </button>\n\n {/* 更多选项菜单 */}\n {moreMenuOpen && (\n <div className=\"dropdown-panel more-panel\">\n <button className=\"menu-item\" onClick={() => handleMenuAction('clear-all')}>\n <Icon icon=\"lucide:trash-2\" width={18} />\n <span>清空所有对话</span>\n </button>\n <button className=\"menu-item\" onClick={() => handleMenuAction('close-others')}>\n <Icon icon=\"lucide:x-circle\" width={18} />\n <span>关闭其他对话</span>\n </button>\n <div className=\"menu-divider\" />\n <button className=\"menu-item\" onClick={() => handleMenuAction('export')}>\n <Icon icon=\"lucide:download\" width={18} />\n <span>导出对话</span>\n </button>\n <button className=\"menu-item\" onClick={() => handleMenuAction('copy-id')}>\n <Icon icon=\"lucide:copy\" width={18} />\n <span>复制请求 ID</span>\n </button>\n <div className=\"menu-divider\" />\n <button className=\"menu-item\" onClick={() => handleMenuAction('feedback')}>\n <Icon icon=\"lucide:message-square\" width={18} />\n <span>反馈</span>\n </button>\n <button className=\"menu-item\" onClick={() => handleMenuAction('settings')}>\n <Icon icon=\"lucide:settings\" width={18} />\n <span>Agent 设置</span>\n </button>\n </div>\n )}\n </div>\n\n {/* 关闭按钮 */}\n {showClose && (\n <button className=\"icon-btn\" onClick={onClose} title=\"关闭\">\n <Icon icon=\"lucide:x\" width={18} />\n </button>\n )}\n\n {/* 设置按钮 */}\n <button className=\"icon-btn\" onClick={onSettings} title=\"设置\">\n <Icon icon=\"lucide:settings\" width={18} />\n </button>\n </div>\n </div>\n )\n}\n","/**\n * WelcomeMessage Component\n * 与 Vue 版本 WelcomeMessage.vue 保持一致\n */\n\nimport { type FC, useMemo } from 'react'\nimport './WelcomeMessage.css'\nimport { Icon } from '@iconify/react'\nimport { type WelcomeConfig, defaultWelcomeConfig } from './welcome-types'\n\ninterface WelcomeMessageProps {\n /** 欢迎页配置(可部分配置,未配置项使用默认值) */\n config?: Partial<WelcomeConfig>\n /** 快捷操作回调 */\n onQuickAction: (text: string) => void\n}\n\nexport const WelcomeMessage: FC<WelcomeMessageProps> = ({ config: propsConfig, onQuickAction }) => {\n // 合并配置\n const config = useMemo<WelcomeConfig>(() => ({\n title: propsConfig?.title ?? defaultWelcomeConfig.title,\n subtitle: propsConfig?.subtitle ?? defaultWelcomeConfig.subtitle,\n icon: propsConfig?.icon ?? defaultWelcomeConfig.icon,\n features: propsConfig?.features ?? defaultWelcomeConfig.features,\n tasks: propsConfig?.tasks ?? defaultWelcomeConfig.tasks,\n }), [propsConfig])\n\n // 根据任务数量动态选择网格布局\n const tasksGridClass = useMemo(() => {\n const count = config.tasks.length\n if (count === 1) return 'tasks-grid tasks-single'\n if (count === 2) return 'tasks-grid tasks-two'\n if (count === 3) return 'tasks-grid tasks-three'\n return 'tasks-grid tasks-multi'\n }, [config.tasks.length])\n\n return (\n <div className=\"welcome-message\">\n {/* 标题区域 */}\n <div className=\"welcome-header\">\n <div className=\"welcome-title-row\">\n <Icon icon={config.icon} width={28} className=\"welcome-icon\" />\n <h2 className=\"welcome-title\">{config.title}</h2>\n </div>\n <p className=\"welcome-subtitle\">{config.subtitle}</p>\n </div>\n\n {/* 能力标签 */}\n {config.features.length > 0 && (\n <div className=\"features-section\">\n <div className=\"section-header\">\n <Icon icon=\"lucide:zap\" width={14} className=\"section-icon\" />\n <span className=\"section-title\">支持的能力</span>\n </div>\n <div className=\"features-list\">\n {config.features.map((feature) => (\n <div key={feature.name} className=\"feature-tag\">\n <Icon icon={feature.icon} width={14} className=\"feature-icon\" />\n <span>{feature.name}</span>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* 快捷操作 */}\n {config.tasks.length > 0 && (\n <div className=\"tasks-section\">\n <div className=\"section-header\">\n <Icon icon=\"lucide:rocket\" width={14} className=\"section-icon\" />\n <span className=\"section-title\">快捷操作</span>\n </div>\n <div className={tasksGridClass}>\n {config.tasks.map((task) => (\n <button\n key={task.name}\n className=\"task-card\"\n onClick={() => onQuickAction(task.prompt)}\n >\n <Icon icon={task.icon} width={18} className=\"task-icon\" />\n <div className=\"task-content\">\n <div className=\"task-name\">{task.name}</div>\n <div className=\"task-desc\">{task.desc}</div>\n </div>\n <Icon icon=\"lucide:arrow-right\" width={14} className=\"task-arrow\" />\n </button>\n ))}\n </div>\n </div>\n )}\n </div>\n )\n}\n","/** 功能项 */\nexport interface WelcomeFeature {\n name: string;\n icon: string;\n}\n\n/** 快捷任务 */\nexport interface WelcomeTask {\n name: string;\n desc: string;\n prompt: string;\n icon: string;\n}\n\n/** 欢迎页配置 */\nexport interface WelcomeConfig {\n /** 标题 */\n title: string;\n /** 副标题 */\n subtitle: string;\n /** 图标 */\n icon: string;\n /** 功能列表 */\n features: WelcomeFeature[];\n /** 快捷任务 */\n tasks: WelcomeTask[];\n}\n\n/** 默认配置 */\nexport const defaultWelcomeConfig: WelcomeConfig = {\n title: 'AI 助手',\n subtitle: '智能对话 · 文档分析 · 内容创作',\n icon: 'lucide:sparkles',\n features: [\n { name: '上下文引用', icon: 'lucide:at-sign' },\n { name: '图片分析', icon: 'lucide:image' },\n { name: '深度思考', icon: 'lucide:sparkles' },\n { name: '联网搜索', icon: 'lucide:globe' },\n ],\n tasks: [\n { name: '总结内容', desc: '快速总结文档要点', prompt: '帮我总结一下这段内容的主要要点', icon: 'lucide:file-text' },\n { name: '翻译文本', desc: '多语言翻译助手', prompt: '帮我翻译这段文字', icon: 'lucide:languages' },\n { name: '写作助手', desc: '帮助撰写文章', prompt: '帮我写一篇关于以下主题的文章:', icon: 'lucide:pen-tool' },\n { name: '问答对话', desc: '回答各种问题', prompt: '我想了解一下:', icon: 'lucide:message-circle' },\n ],\n};\n","/**\n * MessageBubble Component\n * 新架构:使用 ContentPart 数组渲染消息内容\n */\n\nimport { useMemo, type FC } from 'react'\nimport './MessageBubble.css'\nimport { Icon } from '@iconify/react'\nimport { PartsRenderer } from './PartsRenderer'\nimport { ChatInput } from '../input/ChatInput'\nimport { useChatInputContext } from '../../context/ChatInputContext'\nimport type { ContentPart, TextPart, ToolCallPart, SearchPart, ThinkingPart, ModelOption } from '../../types'\nimport type { ChatAdapter } from '../../adapter'\nimport type { AutoRunConfig } from '@huyooo/ai-chat-bridge-electron/renderer'\n\ninterface MessageBubbleProps {\n role: 'user' | 'assistant'\n /** 内容 parts 数组 - 新架构核心 */\n parts: ContentPart[]\n /** 生成此消息时使用的模型 */\n model?: string\n /** 生成此消息时使用的模式 (ask/agent) */\n mode?: string\n /** 用户上传的图片 */\n images?: string[]\n /** 是否正在加载 */\n loading?: boolean\n /** 是否已复制 */\n copied?: boolean\n /** 消息时间戳 */\n timestamp?: Date | string | number\n onCopy?: () => void\n onRegenerate?: () => void\n /** 编辑用户消息后重新发送 */\n onSend?: (text: string) => void\n /** 步骤折叠模式 */\n stepsExpandedType?: 'open' | 'close' | 'auto'\n /** 工具调用相关 - 通过 props 传递 */\n adapter?: ChatAdapter\n /** 取消工具调用(通常会中止当前请求/流式输出) */\n onCancelToolCall?: (toolCallId: string) => void\n autoRunConfig?: AutoRunConfig\n onSaveConfig?: (config: AutoRunConfig) => Promise<void>\n}\n\n/** 获取模型显示名称 */\nfunction getModelDisplayName(modelId: string, models?: ModelOption[]): string {\n // 优先从传入的 models 中查找\n const found = models?.find((m) => m.modelId === modelId)\n if (found) return found.displayName\n // 后备:提取模型名称(前端不应该依赖后端包)\n return modelId.split('/').pop() || modelId\n}\n\n/** 格式化时间显示 */\nfunction formatTime(timestamp?: Date | string | number): string {\n if (!timestamp) return ''\n const date = new Date(timestamp)\n const year = date.getFullYear()\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n const hours = String(date.getHours()).padStart(2, '0')\n const minutes = String(date.getMinutes()).padStart(2, '0')\n return `${year}-${month}-${day} ${hours}:${minutes}`\n}\n\nexport const MessageBubble: FC<MessageBubbleProps> = ({\n role,\n parts,\n model,\n mode,\n images,\n loading,\n copied,\n timestamp,\n onCopy,\n onRegenerate,\n onSend,\n stepsExpandedType = 'auto',\n adapter,\n onCancelToolCall,\n autoRunConfig,\n onSaveConfig,\n}) => {\n const isUser = role === 'user'\n const formattedTime = formatTime(timestamp)\n const inputContext = useChatInputContext()\n\n // 提取用户消息的文本内容\n const userText = useMemo(() => {\n return parts\n .filter((p): p is TextPart => p.type === 'text')\n .map(p => p.text)\n .join('')\n }, [parts])\n\n // 是否有内容(用于显示操作按钮)\n const hasContent = useMemo(() => {\n return parts.some(p => \n (p.type === 'text' && (p as TextPart).text) || \n p.type === 'thinking' ||\n p.type === 'search' ||\n p.type === 'tool_call'\n )\n }, [parts])\n\n // loading 状态:决定显示什么类型的指示器\n // text: 文字提示(等待状态时)\n // none: 不显示(有正在进行的活动)\n const loadingState = useMemo<{ type: 'text' | 'none'; text?: string }>(() => {\n if (!loading) {\n return { type: 'none' }\n }\n \n // 分模式显示:ask 模式直接生成回答,agent 模式规划下一步\n const waitingText = mode === 'ask' ? '正在生成回答...' : '正在规划下一步...'\n \n // 没有任何 parts 时,显示等待\n if (parts.length === 0) {\n return { type: 'text', text: waitingText }\n }\n \n // 检查是否有正在进行的活动(如果有,不需要显示等待提示)\n const hasActiveActivity = parts.some(part => {\n // 思考正在进行\n if (part.type === 'thinking' && (part as ThinkingPart).status === 'running') {\n return true\n }\n // 搜索正在进行\n if (part.type === 'search' && (part as SearchPart).status === 'running') {\n return true\n }\n // 工具调用正在进行(running 或 pending)\n if (part.type === 'tool_call') {\n const status = (part as ToolCallPart).status\n if (status === 'running' || status === 'pending') {\n return true\n }\n }\n return false\n })\n \n // 有正在进行的活动 → 不显示等待提示(活动本身有状态显示)\n if (hasActiveActivity) {\n return { type: 'none' }\n }\n \n // 检查最后一个 part 是否是正在流式输出的文本\n const lastPart = parts[parts.length - 1]\n if (lastPart.type === 'text') {\n // 文本正在流式输出 → 不显示等待提示\n return { type: 'none' }\n }\n \n // 没有任何正在进行的活动,但 loading=true → 显示等待提示\n // 这包括:工具执行完成后、思考完成后、搜索完成后等\"空窗期\"\n return { type: 'text', text: waitingText }\n }, [loading, parts, mode])\n\n return (\n <div className={`message-bubble ${role}`}>\n {/* 用户消息 */}\n {isUser ? (\n onSend && inputContext ? (\n <ChatInput\n variant=\"message\"\n value={userText}\n images={images}\n mode={inputContext.mode}\n model={inputContext.model}\n models={inputContext.models}\n webSearchEnabled={inputContext.webSearch}\n thinkingEnabled={inputContext.thinking}\n isLoading={inputContext.isLoading}\n onSend={onSend}\n onModeChange={inputContext.setMode}\n onModelChange={inputContext.setModel}\n onWebSearchChange={inputContext.setWebSearch}\n onThinkingChange={inputContext.setThinking}\n />\n ) : (\n <div className=\"user-content\">\n <div className=\"user-text\">{userText}</div>\n {images && images.length > 0 && (\n <div className=\"user-images\">\n {images.map((img, i) => (\n <img key={i} src={img} className=\"user-image\" alt=\"\" />\n ))}\n </div>\n )}\n {formattedTime && <div className=\"message-time user-time\">{formattedTime}</div>}\n </div>\n )\n ) : (\n /* 助手消息 - 使用 PartsRenderer 渲染 */\n <>\n <div className=\"assistant-content\">\n <PartsRenderer \n parts={parts} \n expandedType={stepsExpandedType}\n adapter={adapter}\n onCancelToolCall={onCancelToolCall}\n autoRunConfig={autoRunConfig}\n onSaveConfig={onSaveConfig}\n />\n \n {/* 加载指示器:等待状态时显示 */}\n {loadingState.type === 'text' && (\n <div className={`loading-indicator${parts.length > 0 ? ' has-content-above' : ''}`}>\n <span className=\"loading-text\">{loadingState.text}</span>\n <span className=\"loading-shimmer\"></span>\n </div>\n )}\n </div>\n\n {/* 操作按钮 */}\n {hasContent && loading === false && (\n <div className=\"message-actions\">\n {/* 左侧:模型信息 */}\n <div className=\"message-meta\">\n {model && <span className=\"model-name\">{getModelDisplayName(model, inputContext?.models)}</span>}\n {mode && <span className=\"mode-badge\">{mode === 'ask' ? 'Ask' : 'Agent'}</span>}\n </div>\n {/* 右侧:时间和按钮 */}\n <div className=\"action-buttons\">\n {formattedTime && <span className=\"message-time assistant-time\">{formattedTime}</span>}\n <button className={`action-btn${copied ? ' copied' : ''}`} onClick={onCopy} title=\"复制\">\n <Icon icon={copied ? 'lucide:check' : 'lucide:copy'} width={14} />\n </button>\n <button className=\"action-btn\" onClick={onRegenerate} title=\"重新生成\">\n <Icon icon=\"lucide:refresh-cw\" width={14} />\n </button>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n )\n}\n","import { useContext, useMemo, type FC, type ComponentType } from 'react'\nimport type { \n ContentPart, \n StepsExpandedType, \n TextPart as TextPartType, \n ThinkingPart as ThinkingPartType, \n SearchPart as SearchPartType, \n ToolCallPart as ToolCallPartType, \n ImagePart as ImagePartType, \n ErrorPart as ErrorPartType,\n} from '../../types'\nimport type { ChatAdapter } from '../../adapter'\nimport type { AutoRunConfig } from '@huyooo/ai-chat-bridge-electron/renderer'\nimport { PartRenderersContext } from '../../context/RenderersContext'\nimport { \n TextPart, \n ThinkingPart, \n SearchPart, \n ImagePart,\n ErrorPart,\n} from './parts'\nimport { ToolCallPart } from './parts/ToolCallPart'\nimport './PartsRenderer.css'\n\n/** Part 渲染器映射类型 */\ntype PartRenderers = Record<string, ComponentType<Record<string, unknown>>>\n\ninterface PartsRendererProps {\n parts: ContentPart[]\n expandedType?: StepsExpandedType\n /** 自定义 Part 渲染器(props 传入优先级高于 context) */\n partRenderers?: PartRenderers\n // 工具调用相关\n adapter?: ChatAdapter\n onCancelToolCall?: (toolCallId: string) => void\n autoRunConfig?: AutoRunConfig\n onSaveConfig?: (config: AutoRunConfig) => Promise<void>\n}\n\n// ==================== 类型守卫函数 ====================\n\nfunction isText(part: ContentPart): part is TextPartType {\n return part.type === 'text'\n}\n\nfunction isThinking(part: ContentPart): part is ThinkingPartType {\n return part.type === 'thinking'\n}\n\nfunction isSearch(part: ContentPart): part is SearchPartType {\n return part.type === 'search'\n}\n\nfunction isToolCall(part: ContentPart): part is ToolCallPartType {\n return part.type === 'tool_call'\n}\n\nfunction isImage(part: ContentPart): part is ImagePartType {\n return part.type === 'image'\n}\n\nfunction isError(part: ContentPart): part is ErrorPartType {\n return part.type === 'error'\n}\n\nexport const PartsRenderer: FC<PartsRendererProps> = ({ \n parts,\n expandedType = 'auto',\n partRenderers: propRenderers,\n adapter,\n onCancelToolCall,\n autoRunConfig,\n onSaveConfig,\n}) => {\n // 从 context 获取渲染器,props 优先\n const contextRenderers = useContext(PartRenderersContext)\n const partRenderers = propRenderers ?? contextRenderers\n\n /** 可见的 parts */\n const visibleParts = useMemo(() => parts, [parts])\n\n const renderPart = (part: ContentPart) => {\n // 先检查是否有自定义渲染器\n const CustomRenderer = partRenderers[part.type]\n if (CustomRenderer) {\n return <CustomRenderer {...part} />\n }\n\n // 内置类型渲染(使用类型守卫)\n if (isText(part)) {\n return <TextPart text={part.text} />\n }\n \n if (isThinking(part)) {\n return (\n <ThinkingPart \n text={part.text}\n status={part.status}\n duration={part.duration}\n expandedType={expandedType}\n />\n )\n }\n \n if (isSearch(part)) {\n return (\n <SearchPart \n query={part.query}\n results={part.results}\n status={part.status}\n expandedType={expandedType}\n />\n )\n }\n \n if (isToolCall(part)) {\n return (\n <ToolCallPart \n id={part.id}\n name={part.name}\n args={part.args}\n output={part.output}\n status={part.status}\n expandedType={expandedType}\n adapter={adapter}\n onCancelToolCall={onCancelToolCall}\n autoRunConfig={autoRunConfig}\n onSaveConfig={onSaveConfig}\n />\n )\n }\n \n if (isImage(part)) {\n return <ImagePart url={part.url} />\n }\n \n if (isError(part)) {\n return (\n <ErrorPart \n message={part.message}\n category={part.category}\n retryable={part.retryable}\n />\n )\n }\n \n // 未知类型,显示 JSON\n return (\n <div className=\"unknown-part\">\n <pre>{JSON.stringify(part, null, 2)}</pre>\n </div>\n )\n }\n\n return (\n <div className=\"parts-renderer\">\n {visibleParts.map((part, index) => (\n <div \n key={index} \n className=\"part-item\"\n style={{ marginTop: index > 0 ? '8px' : '0' }}\n >\n {renderPart(part)}\n </div>\n ))}\n </div>\n )\n}\n","import type { FC, ReactNode } from 'react'\nimport { Icon } from '@iconify/react'\nimport './CollapsibleCard.css'\n\ninterface CollapsibleCardProps {\n /** 图标名称 */\n icon: string\n /** 图标颜色 */\n iconColor?: string\n /** 标题 */\n title: string\n /** 标题颜色 */\n titleColor?: string\n /** 副标题 */\n subtitle?: string\n /** 是否展开 */\n expanded: boolean\n /** 展开状态变化回调 */\n onExpandedChange: (expanded: boolean) => void\n /** 图标是否旋转(加载状态) */\n spinning?: boolean\n /** 是否可折叠(显示 chevron) */\n collapsible?: boolean\n /** 子内容 */\n children?: ReactNode\n /** Header 操作按钮 */\n headerActions?: ReactNode\n}\n\nexport const CollapsibleCard: FC<CollapsibleCardProps> = ({\n icon,\n iconColor = 'var(--chat-accent, #3b82f6)',\n title,\n titleColor,\n subtitle,\n expanded,\n onExpandedChange,\n spinning = false,\n collapsible = true,\n children,\n headerActions,\n}) => {\n return (\n <div className={`collapsible-card ${expanded ? 'expanded' : ''}`}>\n <div className=\"card-header\">\n <div \n className={`card-header-left ${collapsible ? 'clickable' : ''}`} \n onClick={() => collapsible && onExpandedChange(!expanded)}\n >\n <div className=\"card-icon\" style={{ color: iconColor }}>\n {spinning ? (\n <Icon icon=\"lucide:loader-2\" width={14} className=\"spinning\" />\n ) : (\n <Icon icon={icon} width={14} />\n )}\n </div>\n <span className=\"card-title\" style={titleColor ? { color: titleColor } : undefined}>\n {title}\n </span>\n {subtitle && <span className=\"card-subtitle\">{subtitle}</span>}\n </div>\n <div className=\"card-header-right\">\n {headerActions}\n {collapsible && (\n <Icon\n icon={expanded ? 'lucide:chevron-up' : 'lucide:chevron-down'}\n width={14}\n className=\"card-chevron\"\n onClick={(e) => {\n e.stopPropagation()\n onExpandedChange(!expanded)\n }}\n />\n )}\n </div>\n </div>\n {expanded && <div className=\"card-content\">{children}</div>}\n </div>\n )\n}\n","import { useEffect, useState, useCallback, useRef, type FC } from 'react'\nimport {\n createStreamParseState,\n finishStreamParse,\n parseContentStream,\n highlightCode,\n renderMarkdown,\n initMermaid,\n renderMermaidDiagrams,\n encodeMermaidCodeToBase64Url,\n type ContentBlock,\n type StreamParseState,\n} from '@huyooo/ai-chat-shared'\nimport {\n canVisualizeLatex,\n isLatexLanguage,\n isMermaidLanguage,\n renderFencedLatexToHtml,\n shouldShowVisualToggle,\n} from './visual'\n// KaTeX CSS for LaTeX rendering\nimport 'katex/dist/katex.min.css'\nimport './TextPart.css'\n\n// 初始化 Mermaid(模块加载时执行一次)\ninitMermaid()\n\ninterface TextPartProps {\n text: string\n}\n\nexport const TextPart: FC<TextPartProps> = ({ text }) => {\n const containerRef = useRef<HTMLDivElement>(null)\n const streamStateRef = useRef<StreamParseState>(createStreamParseState())\n const lastTextRef = useRef<string>('')\n const autoSwitchedVisualRef = useRef<Set<string>>(new Set())\n\n // 渲染块(流式解析:代码块未闭合时也以 code block 展示)\n const [blocks, setBlocks] = useState<ContentBlock[]>([])\n\n // 记录哪些 mermaid block 要显示图表(默认 undefined/false = 显示代码)\n const [visualShowMap, setVisualShowMap] = useState<Record<string, boolean>>({})\n \n // 复制状态\n const [copiedId, setCopiedId] = useState<string | null>(null)\n\n // 复制代码\n const copyCode = useCallback(async (content: string, id: string) => {\n try {\n await navigator.clipboard.writeText(content)\n setCopiedId(id)\n setTimeout(() => setCopiedId(null), 2000)\n } catch (err) {\n console.error('复制失败:', err)\n }\n }, [])\n \n if (!text) return null\n\n // text 变化:增量喂给流式解析器,并在 mermaid 代码块闭合后自动切换到图表视图\n useEffect(() => {\n const prev = lastTextRef.current\n const current = text || ''\n\n let nextState = streamStateRef.current\n if (prev && current.startsWith(prev)) {\n const delta = current.slice(prev.length)\n if (delta) nextState = parseContentStream(delta, nextState)\n } else {\n nextState = createStreamParseState()\n nextState = parseContentStream(current, nextState)\n }\n\n streamStateRef.current = nextState\n lastTextRef.current = current\n\n const nextBlocks = finishStreamParse(nextState)\n setBlocks(nextBlocks)\n\n // mermaid:未闭合时保持代码视图;闭合后自动切到图表视图并触发渲染\n const inProgressVisualId =\n nextState.inCodeBlock &&\n (['mermaid', 'latex', 'katex', 'tex'].includes((nextState.codeLanguage || '').toLowerCase()))\n ? nextState.codeBlockId\n : null\n\n const completedVisualIds: string[] = []\n for (const b of nextState.blocks) {\n if (b.type !== 'code') continue\n const lang = (b.language || '').toLowerCase()\n if (!['mermaid', 'latex', 'katex', 'tex'].includes(lang)) continue\n if (inProgressVisualId && b.id === inProgressVisualId) continue\n if (['latex', 'katex', 'tex'].includes(lang) && !canVisualizeLatex(b.content)) continue\n if (!autoSwitchedVisualRef.current.has(b.id)) completedVisualIds.push(b.id)\n }\n\n if (completedVisualIds.length > 0) {\n for (const id of completedVisualIds) autoSwitchedVisualRef.current.add(id)\n setVisualShowMap((prevMap) => {\n const nextMap = { ...prevMap }\n for (const id of completedVisualIds) {\n if (nextMap[id] === undefined) nextMap[id] = true\n }\n return nextMap\n })\n\n window.setTimeout(() => {\n if (containerRef.current) renderMermaidDiagrams(containerRef.current)\n }, 0)\n }\n }, [text])\n\n const toggleVisualView = (id: string) => {\n const willShowVisual = !visualShowMap[id]\n setVisualShowMap((prev) => ({ ...prev, [id]: willShowVisual }))\n\n // 切换到图表模式时,需要在 DOM 更新后触发渲染\n if (willShowVisual) {\n window.setTimeout(() => {\n if (containerRef.current) {\n renderMermaidDiagrams(containerRef.current)\n }\n }, 0)\n }\n }\n\n return (\n <div className=\"text-part\" ref={containerRef}>\n {blocks.map((block) => {\n if (block.type === 'text') {\n return (\n <div \n key={block.id} \n className=\"text-block\" \n dangerouslySetInnerHTML={{ __html: renderMarkdown(block.content) }}\n />\n )\n } else if (block.type === 'code') {\n const isMermaid = isMermaidLanguage(block.language)\n const isLatex = isLatexLanguage(block.language)\n const canVisualizeLatexBlock = isLatex && canVisualizeLatex(block.content)\n // 默认显示代码(undefined/false),闭合后自动切到可视化(true)\n const showVisual = !!visualShowMap[block.id]\n return (\n <div key={block.id} className=\"code-block-wrapper\">\n <div className=\"code-header\">\n <span className=\"code-language\">{block.language || 'plaintext'}</span>\n <div className=\"code-actions\">\n {shouldShowVisualToggle(block.language, block.content) && (\n <button\n className=\"code-action-btn\"\n onClick={() => toggleVisualView(block.id)}\n title={showVisual ? '切换为代码视图' : '切换为可视化视图'}\n >\n {/* 切换图标 */}\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <polyline points=\"17 1 21 5 17 9\"></polyline>\n <path d=\"M3 11V9a4 4 0 0 1 4-4h14\"></path>\n <polyline points=\"7 23 3 19 7 15\"></polyline>\n <path d=\"M21 13v2a4 4 0 0 1-4 4H3\"></path>\n </svg>\n <span>切换视图</span>\n </button>\n )}\n <button \n className=\"code-action-btn\"\n onClick={() => copyCode(block.content, block.id)}\n title={copiedId === block.id ? '已复制' : '复制代码'}\n >\n {copiedId !== block.id ? (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect>\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path>\n </svg>\n ) : (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n )}\n <span>{copiedId === block.id ? '已复制' : '复制'}</span>\n </button>\n </div>\n </div>\n {/* Mermaid: 闭合后自动切换到图表视图 */}\n {isMermaid && showVisual && (\n <div\n className=\"mermaid-placeholder\"\n data-mermaid-code-b64={encodeMermaidCodeToBase64Url(block.content)}\n >\n <div className=\"mermaid-loading\">加载图表中...</div>\n </div>\n )}\n {/* LaTeX: 闭合后自动切换到渲染视图 */}\n {isLatex && showVisual && canVisualizeLatexBlock && (\n <div\n className=\"latex-rendered\"\n dangerouslySetInnerHTML={{ __html: renderFencedLatexToHtml(block.content) }}\n />\n )}\n {(!(isMermaid || isLatex) || !showVisual || (isLatex && !canVisualizeLatexBlock)) && (\n <pre className=\"code-block\"><code\n className={block.language ? `language-${block.language}` : ''}\n dangerouslySetInnerHTML={{ __html: highlightCode(block.content, block.language) }}\n /></pre>\n )}\n </div>\n )\n }\n return null\n })}\n </div>\n )\n}\n","function normalizeLanguage(lang?: string): string {\n return (lang || '').trim().toLowerCase()\n}\n\nexport function isMermaidLanguage(lang?: string): boolean {\n return normalizeLanguage(lang) === 'mermaid'\n}\n\nexport function isLatexLanguage(lang?: string): boolean {\n const l = normalizeLanguage(lang)\n return l === 'latex' || l === 'katex' || l === 'tex'\n}\n\nexport function isLatexDocument(code: string): boolean {\n const t = (code || '').trim()\n return /\\\\documentclass\\b|\\\\usepackage\\b|\\\\begin\\{document\\}|\\\\end\\{document\\}/.test(t)\n}\n\nexport function canVisualizeLatex(code: string): boolean {\n const t = (code || '').trim()\n if (!t) return false\n if (isLatexDocument(t)) return false\n return true\n}\n\nexport function hasLatexDelimiters(code: string): boolean {\n const t = (code || '').trim()\n if (!t) return false\n return (\n /\\$\\$[\\s\\S]*\\$\\$/.test(t) ||\n /\\\\\\[[\\s\\S]*\\\\\\]/.test(t) ||\n /\\\\\\([\\s\\S]*\\\\\\)/.test(t) ||\n /(?<!\\$)\\$(?!\\$)[\\s\\S]*?\\$(?!\\$)/.test(t)\n )\n}\n\nexport function shouldShowVisualToggle(lang?: string, code?: string): boolean {\n if (isMermaidLanguage(lang)) return true\n if (isLatexLanguage(lang)) return canVisualizeLatex(code || '')\n return false\n}\n\n\n","import { renderMarkdown } from '@huyooo/ai-chat-shared'\nimport { canVisualizeLatex, hasLatexDelimiters } from './visual-predicate'\n\nexport function renderFencedLatexToHtml(code: string): string {\n const t = (code || '').trim()\n if (!t) return ''\n\n if (!canVisualizeLatex(t)) {\n return renderMarkdown(\n `> 不支持将完整 LaTeX 文档作为公式渲染,请切换到代码视图查看。\\n\\n\\`\\`\\`latex\\n${t}\\n\\`\\`\\``\n )\n }\n\n if (hasLatexDelimiters(t)) return renderMarkdown(t)\n\n return renderMarkdown(`$$\\n${t}\\n$$`)\n}\n\n\n","import { useState, useEffect, type FC } from 'react'\nimport { CollapsibleCard } from './CollapsibleCard'\nimport type { StepsExpandedType } from '../../../types'\nimport './ThinkingPart.css'\n\ninterface ThinkingPartProps {\n text: string\n status: 'running' | 'done'\n duration?: number\n expandedType?: StepsExpandedType\n}\n\nexport const ThinkingPart: FC<ThinkingPartProps> = ({ \n text, \n status, \n duration,\n expandedType = 'auto'\n}) => {\n // 根据模式计算初始状态\n const getInitialExpanded = () => {\n if (expandedType === 'open') return true\n if (expandedType === 'close') return false\n // auto: 运行时展开\n return status === 'running'\n }\n \n const [expanded, setExpanded] = useState(getInitialExpanded)\n \n // auto 模式下:状态变化时自动折叠/展开\n useEffect(() => {\n if (expandedType === 'auto') {\n setExpanded(status === 'running')\n }\n }, [status, expandedType])\n\n return (\n <CollapsibleCard\n icon=\"lucide:lightbulb\"\n iconColor=\"var(--chat-accent, #f59e0b)\"\n title={status === 'running' ? '思考中...' : '思考完成'}\n subtitle={duration && status === 'done' ? `(${duration}s)` : undefined}\n expanded={expanded}\n onExpandedChange={setExpanded}\n >\n <div className=\"thinking-content\">{text}</div>\n </CollapsibleCard>\n )\n}\n","import { useState, useEffect, type FC } from 'react'\nimport { CollapsibleCard } from './CollapsibleCard'\nimport type { SearchResult, StepsExpandedType } from '../../../types'\nimport './SearchPart.css'\n\ninterface SearchPartProps {\n query?: string\n results?: SearchResult[]\n status: 'running' | 'done'\n expandedType?: StepsExpandedType\n}\n\nexport const SearchPart: FC<SearchPartProps> = ({ \n results, \n status,\n expandedType = 'auto'\n}) => {\n // 根据模式计算初始状态\n const getInitialExpanded = () => {\n if (expandedType === 'open') return true\n if (expandedType === 'close') return false\n // auto: 运行时展开\n return status === 'running'\n }\n \n const [expanded, setExpanded] = useState(getInitialExpanded)\n \n // auto 模式下:状态变化时自动折叠/展开\n useEffect(() => {\n if (expandedType === 'auto') {\n setExpanded(status === 'running')\n }\n }, [status, expandedType])\n\n return (\n <CollapsibleCard\n icon=\"lucide:search\"\n iconColor=\"var(--chat-accent, #3b82f6)\"\n title={status === 'running' ? '搜索中...' : `搜索完成 (${results?.length || 0} 条结果)`}\n spinning={status === 'running'}\n expanded={expanded}\n onExpandedChange={setExpanded}\n >\n {results && results.length > 0 && (\n <div className=\"search-results\">\n {results.map((item, i) => (\n <a \n key={i} \n href={item.url} \n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"search-item\"\n >\n <div className=\"search-item-title\">{item.title}</div>\n <div className=\"search-item-snippet\">{item.snippet}</div>\n <div className=\"search-item-url\">{item.url}</div>\n </a>\n ))}\n </div>\n )}\n </CollapsibleCard>\n )\n}\n","import { useState, useMemo, useEffect, useCallback, useRef } from 'react'\nimport type { FC } from 'react'\nimport { Icon } from '@iconify/react'\nimport { DropdownSelector } from '../../input/DropdownSelector'\nimport { CollapsibleCard } from './CollapsibleCard'\nimport { CopyButton } from '../../common/CopyButton'\nimport { highlightCode } from '@huyooo/ai-chat-shared'\nimport type { ChatAdapter } from '../../../adapter'\nimport type { AutoRunConfig, AutoRunMode } from '@huyooo/ai-chat-bridge-electron/renderer'\nimport type { StepsExpandedType } from '../../../types'\nimport './ToolCallPart.css'\n\ninterface ToolCallPartProps {\n id: string\n name: string\n args?: Record<string, unknown>\n output?: {\n stdout?: string\n stderr?: string\n }\n status: 'pending' | 'running' | 'done' | 'error' | 'cancelled' | 'skipped'\n expandedType?: StepsExpandedType\n adapter?: ChatAdapter\n onCancelToolCall?: (toolCallId: string) => void\n autoRunConfig?: AutoRunConfig\n onSaveConfig?: (config: AutoRunConfig) => Promise<void>\n}\n\nconst modeOptions = [\n { value: 'manual', label: '执行前询问我' },\n { value: 'run-everything', label: '自动执行' },\n]\n\nconst statusIcons: Record<string, string> = {\n error: 'lucide:x-circle',\n done: 'lucide:check-circle',\n running: 'lucide:loader-2',\n pending: 'lucide:clock',\n cancelled: 'lucide:ban',\n skipped: 'lucide:skip-forward',\n}\n\nconst statusColors: Record<string, string> = {\n error: 'var(--chat-error, #ef4444)',\n done: 'var(--chat-success, #22c55e)',\n running: 'var(--chat-accent, #3b82f6)',\n pending: 'var(--chat-text-muted, #888)',\n cancelled: 'var(--chat-warning, #f59e0b)',\n skipped: 'var(--chat-text-muted, #888)',\n}\n\nconst statusDisplayIcons: Record<string, string> = {\n done: 'lucide:check-circle-2',\n error: 'lucide:x-circle',\n cancelled: 'lucide:ban',\n skipped: 'lucide:skip-forward',\n}\n\nconst statusTexts: Record<string, string> = {\n done: '成功',\n error: '错误',\n cancelled: '已取消',\n skipped: '已跳过',\n}\n\nexport const ToolCallPart: FC<ToolCallPartProps> = ({\n id,\n name,\n args,\n output,\n status,\n expandedType = 'auto',\n adapter,\n onCancelToolCall,\n autoRunConfig,\n onSaveConfig,\n}) => {\n const currentMode = autoRunConfig?.mode ?? 'run-everything'\n\n // 参数类型:'json' | 'command' | 'text'\n const argsType = useMemo(() => {\n if (name === 'execute_command' && args?.command) {\n return 'command'\n }\n if (args && Object.keys(args).length > 0) {\n return 'json'\n }\n return 'text'\n }, [name, args])\n\n // 参数文本(格式化后的)\n const argsText = useMemo(() => {\n if (name === 'execute_command' && args?.command) {\n return String(args.command)\n }\n if (args && Object.keys(args).length > 0) {\n try {\n // JSON 格式化:2 空格缩进\n return JSON.stringify(args, null, 2)\n } catch {\n return String(args)\n }\n }\n return name\n }, [name, args])\n\n // JSON 高亮后的 HTML\n const highlightedJson = useMemo(() => {\n if (argsType === 'json') {\n return highlightCode(argsText, 'json')\n }\n return ''\n }, [argsType, argsText])\n\n // 折叠状态\n const [expanded, setExpanded] = useState(() => {\n if (expandedType === 'open') return true\n if (expandedType === 'close') return false\n return status === 'pending' || status === 'running'\n })\n\n useEffect(() => {\n if (expandedType === 'auto') {\n setExpanded(status === 'pending' || status === 'running')\n }\n }, [status, expandedType])\n\n // 标题\n const title = useMemo(() => {\n const suffixes: Record<string, string> = {\n pending: ' - 等待确认',\n running: ' - 执行中...',\n error: ' - 执行失败',\n done: ' - 执行完成',\n cancelled: ' - 已取消',\n skipped: ' - 已跳过',\n }\n return name + (suffixes[status] ?? '')\n }, [name, status])\n\n // 操作\n const handleModeChange = useCallback(async (value: string) => {\n if (!onSaveConfig || !autoRunConfig) return\n await onSaveConfig({ ...autoRunConfig, mode: value as AutoRunMode })\n }, [onSaveConfig, autoRunConfig])\n\n const handleSkip = useCallback(async () => {\n await adapter?.respondToolApproval?.(id, false)\n }, [adapter, id])\n\n const handleRun = useCallback(async () => {\n await adapter?.respondToolApproval?.(id, true)\n }, [adapter, id])\n\n const handleCancel = useCallback(() => {\n if (onCancelToolCall) {\n onCancelToolCall(id)\n return\n }\n adapter?.cancel?.()\n }, [adapter, id, onCancelToolCall])\n\n const hasOutput = Boolean(output?.stdout || output?.stderr)\n const [activeStream, setActiveStream] = useState<'stdout' | 'stderr'>('stdout')\n const activeOutputText = useMemo(() => {\n return activeStream === 'stdout' ? (output?.stdout ?? '') : (output?.stderr ?? '')\n }, [activeStream, output])\n\n const saveLog = useCallback(() => {\n const stdout = output?.stdout ?? ''\n const stderr = output?.stderr ?? ''\n const content =\n `# tool: ${name}\\n` +\n `# id: ${id}\\n` +\n `# time: ${new Date().toISOString()}\\n\\n` +\n `===== STDOUT =====\\n${stdout}\\n\\n` +\n `===== STDERR =====\\n${stderr}\\n`\n\n const blob = new Blob([content], { type: 'text/plain;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `tool-${name}-${id}.log`\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n URL.revokeObjectURL(url)\n }, [id, name, output])\n\n // 模式切换时自动执行\n const prevModeRef = useRef(currentMode)\n useEffect(() => {\n const prevMode = prevModeRef.current\n if (prevMode === 'manual' && currentMode === 'run-everything' && status === 'pending') {\n handleRun()\n }\n prevModeRef.current = currentMode\n }, [currentMode, status, handleRun])\n\n return (\n <CollapsibleCard\n icon={statusIcons[status] ?? 'lucide:clock'}\n iconColor={statusColors[status] ?? 'var(--chat-text-muted, #888)'}\n title={title}\n expanded={expanded}\n onExpandedChange={setExpanded}\n spinning={status === 'running'}\n headerActions={<CopyButton text={argsText} title=\"复制\" />}\n >\n {/* 参数内容 */}\n <pre className={`tool-args ${argsType}`}>\n {argsType === 'json' ? (\n <code dangerouslySetInnerHTML={{ __html: highlightedJson }} />\n ) : (\n argsText\n )}\n </pre>\n\n {/* 输出面板(stdout/stderr) */}\n {hasOutput && (\n <div className=\"output-panel\">\n <div className=\"output-header\">\n <div className=\"output-tabs\">\n <button\n className={`tab${activeStream === 'stdout' ? ' active' : ''}`}\n type=\"button\"\n onClick={() => setActiveStream('stdout')}\n >\n 正常输出\n </button>\n <button\n className={`tab${activeStream === 'stderr' ? ' active' : ''}`}\n type=\"button\"\n onClick={() => setActiveStream('stderr')}\n >\n 异常/告警输出\n </button>\n </div>\n <div className=\"output-actions\">\n <button className=\"btn btn-save\" type=\"button\" onClick={saveLog}>\n <Icon icon=\"lucide:download\" width={14} />\n 保存日志\n </button>\n <CopyButton text={activeOutputText} title=\"复制输出\" />\n </div>\n </div>\n <pre className=\"output-body chat-scrollbar\"><code>{activeOutputText || '(无输出)'}</code></pre>\n </div>\n )}\n \n {/* 底部操作区 */}\n <div className=\"tool-footer\">\n <DropdownSelector\n value={currentMode}\n options={modeOptions}\n onSelect={handleModeChange}\n />\n \n <div className=\"tool-actions\">\n {status === 'pending' ? (\n <>\n <button className=\"btn btn-skip\" onClick={handleSkip}>跳过</button>\n <button className=\"btn btn-run\" onClick={handleRun}>\n 运行\n <Icon icon=\"lucide:arrow-right\" width={14} />\n </button>\n </>\n ) : status === 'running' ? (\n <>\n <span className=\"status-text running\">\n <Icon icon=\"lucide:loader-2\" width={14} className=\"spinning\" />\n 运行中\n </span>\n <button className=\"btn btn-cancel\" onClick={handleCancel}>\n <Icon icon=\"lucide:x\" width={14} />\n 取消\n </button>\n </>\n ) : (\n <span className={`status-text ${status}`}>\n <Icon icon={statusDisplayIcons[status] ?? 'lucide:clock'} width={14} />\n {statusTexts[status] ?? ''}\n </span>\n )}\n </div>\n </div>\n </CollapsibleCard>\n )\n}\n","/**\n * DropdownSelector Component\n * 与 Vue 版本 DropdownSelector.vue 保持一致\n * 前端只负责渲染,分组数据由后端提供\n */\n\nimport { useState, useRef, useCallback, useEffect, useMemo, useLayoutEffect } from 'react';\nimport { Icon } from '@iconify/react';\nimport './DropdownSelector.css';\n\n/** 下拉选项 */\nexport interface DropdownOption {\n value: string;\n label: string;\n icon?: string;\n /** 分组名称(由后端决定,前端只负责渲染) */\n group?: string;\n /** 模型特性信息(用于 hover 提示) */\n tooltip?: {\n /** 可用功能列表 */\n features?: string[];\n /** 开销信息(数组,分行显示) */\n cost?: string[];\n /** 其他描述信息 */\n description?: string;\n };\n}\n\n/** 分组后的选项(由后端提供) */\nexport interface GroupedOptions {\n [groupName: string]: DropdownOption[];\n}\n\ninterface DropdownSelectorProps {\n /** 当前选中的值 */\n value: string;\n /** 选项列表(扁平列表) */\n options?: DropdownOption[];\n /** 分组后的选项(优先级高于 options,由后端提供) */\n groupedOptions?: GroupedOptions;\n /** 占位符文本 */\n placeholder?: string;\n /** 选择回调 */\n onSelect?: (value: string) => void;\n /** 是否禁用 */\n disabled?: boolean;\n /** 下拉菜单对齐方式 */\n align?: 'left' | 'right';\n}\n\nexport function DropdownSelector({\n value,\n options,\n groupedOptions,\n placeholder = '请选择',\n onSelect,\n disabled = false,\n align = 'left',\n}: DropdownSelectorProps) {\n const selectorRef = useRef<HTMLDivElement>(null);\n const tooltipRef = useRef<HTMLDivElement>(null);\n const hoveredItemRef = useRef<HTMLElement | null>(null);\n const [menuOpen, setMenuOpen] = useState(false);\n const [dropdownDirection, setDropdownDirection] = useState<'up' | 'down'>('up');\n const [hoveredOption, setHoveredOption] = useState<DropdownOption | null>(null);\n const [tooltipPosition, setTooltipPosition] = useState({ top: 0, left: 0 });\n\n // 检查是否有选项\n const hasOptions = useMemo(() => {\n if (groupedOptions && Object.keys(groupedOptions).length > 0) {\n return Object.values(groupedOptions).some(group => group.length > 0);\n }\n return options && options.length > 0;\n }, [options, groupedOptions]);\n\n // 当前选中的选项(从扁平列表或分组数据中查找)\n const currentOption = useMemo(() => {\n if (groupedOptions) {\n for (const group of Object.values(groupedOptions)) {\n const found = group.find(opt => opt.value === value);\n if (found) return found;\n }\n }\n return options?.find(opt => opt.value === value);\n }, [value, options, groupedOptions]);\n\n // 排序后的选项(扁平列表模式使用)\n const sortedOptions = useMemo(() => {\n if (!options) return [];\n return [...options].sort((a, b) => a.label.localeCompare(b.label));\n }, [options]);\n\n /**\n * 计算下拉方向(根据可用空间)\n */\n const calculateDropdownDirection = useCallback((): 'up' | 'down' => {\n if (!selectorRef.current) return 'up';\n const rect = selectorRef.current.getBoundingClientRect();\n const spaceAbove = rect.top;\n const spaceBelow = window.innerHeight - rect.bottom;\n // 如果上方空间小于 200px 且下方空间更大,则向下弹出\n return spaceAbove < 200 && spaceBelow > spaceAbove ? 'down' : 'up';\n }, []);\n\n /**\n * 切换菜单\n */\n const toggleMenu = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n if (disabled) return;\n if (!menuOpen) {\n setDropdownDirection(calculateDropdownDirection());\n }\n setMenuOpen((prev) => !prev);\n },\n [menuOpen, calculateDropdownDirection, disabled]\n );\n\n /**\n * 选择选项\n */\n const selectOption = useCallback(\n (optValue: string) => {\n onSelect?.(optValue);\n setMenuOpen(false);\n },\n [onSelect]\n );\n\n /**\n * 处理选项 hover 事件\n */\n const handleItemHover = useCallback((event: React.MouseEvent<HTMLDivElement>, opt: DropdownOption) => {\n const target = event.currentTarget as HTMLElement;\n hoveredItemRef.current = target;\n setHoveredOption(opt);\n \n if (!opt.tooltip) {\n setTooltipPosition({ top: 0, left: 0 });\n return;\n }\n \n if (!target) return;\n \n const rect = target.getBoundingClientRect();\n // 提示框初始位置:右侧,距离 8px\n setTooltipPosition({\n top: rect.top,\n left: rect.right + 8,\n });\n }, []);\n\n /**\n * 当提示框显示后,调整位置(避免超出视口)\n * 使用 requestAnimationFrame 确保 tooltip 已完成渲染\n */\n useLayoutEffect(() => {\n if (!hoveredOption?.tooltip || !hoveredItemRef.current) return;\n \n // 使用 rAF 确保 tooltip 已渲染完成\n const rafId = requestAnimationFrame(() => {\n if (!tooltipRef.current || !hoveredItemRef.current) return;\n \n const tooltip = tooltipRef.current;\n const item = hoveredItemRef.current;\n const itemRect = item.getBoundingClientRect();\n const tooltipRect = tooltip.getBoundingClientRect();\n \n let top = itemRect.top;\n let left = itemRect.right + 8;\n \n // 检查是否会超出视口右侧\n if (left + tooltipRect.width > window.innerWidth) {\n // 显示在左侧\n left = itemRect.left - tooltipRect.width - 8;\n }\n \n // 检查是否会超出视口底部\n if (top + tooltipRect.height > window.innerHeight) {\n top = window.innerHeight - tooltipRect.height - 8;\n }\n \n // 检查是否会超出视口顶部\n if (top < 8) {\n top = 8;\n }\n \n setTooltipPosition({ top, left });\n });\n \n return () => cancelAnimationFrame(rafId);\n }, [hoveredOption]);\n\n /**\n * 点击外部关闭菜单\n */\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as HTMLElement;\n if (selectorRef.current && !selectorRef.current.contains(target)) {\n setMenuOpen(false);\n }\n };\n\n document.addEventListener('click', handleClickOutside);\n return () => document.removeEventListener('click', handleClickOutside);\n }, []);\n\n return (\n <div \n ref={selectorRef} \n className={`dropdown-selector${disabled ? ' disabled' : ''}`}\n onClick={!disabled ? toggleMenu : undefined}\n >\n {currentOption?.icon && <Icon icon={currentOption.icon} width={14} />}\n <span className=\"selector-text\">{currentOption?.label || placeholder}</span>\n <Icon icon=\"lucide:chevron-down\" width={14} className=\"chevron\" />\n\n {menuOpen && (\n <div\n className={`dropdown-menu dropdown-${dropdownDirection}${align === 'right' ? ' dropdown-align-right' : ''}`}\n onClick={(e) => e.stopPropagation()}\n >\n {/* 空状态 */}\n {!hasOptions && (\n <div className=\"dropdown-empty\">暂无数据</div>\n )}\n\n {/* 分组模式:使用后端返回的分组数据 */}\n {groupedOptions && Object.keys(groupedOptions).length > 0 ? (\n <>\n {Object.entries(groupedOptions).map(([groupName, groupItems]) => (\n <div key={groupName}>\n <div className=\"group-title\">{groupName}</div>\n {groupItems.map((opt) => (\n <div\n key={opt.value}\n className=\"dropdown-item-wrapper\"\n onMouseEnter={(e) => handleItemHover(e, opt)}\n onMouseLeave={() => {\n setHoveredOption(null);\n hoveredItemRef.current = null;\n }}\n >\n <button\n className={`dropdown-item${value === opt.value ? ' active' : ''}`}\n onClick={() => selectOption(opt.value)}\n >\n {opt.icon && <Icon icon={opt.icon} width={14} />}\n <span className=\"option-label\">{opt.label}</span>\n <span className=\"option-right\">\n {value === opt.value && <Icon icon=\"lucide:check\" width={14} className=\"check-icon\" />}\n </span>\n </button>\n </div>\n ))}\n </div>\n ))}\n </>\n ) : (\n /* 扁平列表模式:无分组数据时使用 */\n sortedOptions.map((opt) => (\n <div\n key={opt.value}\n className=\"dropdown-item-wrapper\"\n onMouseEnter={(e) => handleItemHover(e, opt)}\n onMouseLeave={() => {\n setHoveredOption(null);\n hoveredItemRef.current = null;\n }}\n >\n <button\n className={`dropdown-item${value === opt.value ? ' active' : ''}`}\n onClick={() => selectOption(opt.value)}\n >\n {opt.icon && <Icon icon={opt.icon} width={14} />}\n <span className=\"option-label\">{opt.label}</span>\n <span className=\"option-right\">\n {value === opt.value && <Icon icon=\"lucide:check\" width={14} className=\"check-icon\" />}\n </span>\n </button>\n </div>\n ))\n )}\n </div>\n )}\n\n {/* Hover 提示:不使用 Portal,采用 fixed 定位避免 overflow 裁剪,同时样式保持组件内可控 */}\n {hoveredOption?.tooltip && (\n <div\n ref={tooltipRef}\n className=\"ai-chat-model-tooltip\"\n style={{\n position: 'fixed',\n top: `${tooltipPosition.top}px`,\n left: `${tooltipPosition.left}px`,\n zIndex: 10000,\n }}\n >\n {hoveredOption.tooltip.features && hoveredOption.tooltip.features.length > 0 && (\n <div className=\"ai-chat-model-tooltip__section\">\n <div className=\"ai-chat-model-tooltip__title\">可用功能</div>\n <div className=\"ai-chat-model-tooltip__features\">\n {hoveredOption.tooltip.features.map((feature) => (\n <div key={feature} className=\"ai-chat-model-tooltip__feature\">\n <Icon icon=\"lucide:check\" width={12} className=\"ai-chat-model-tooltip__check\" />\n <span>{feature}</span>\n </div>\n ))}\n </div>\n </div>\n )}\n {hoveredOption.tooltip.cost && hoveredOption.tooltip.cost.length > 0 && (\n <div className=\"ai-chat-model-tooltip__section\">\n <div className=\"ai-chat-model-tooltip__title\">开销</div>\n <div className=\"ai-chat-model-tooltip__cost\">\n {hoveredOption.tooltip.cost.map((line, i) => (\n <div key={i}>{line}</div>\n ))}\n </div>\n </div>\n )}\n {hoveredOption.tooltip.description && (\n <div className=\"ai-chat-model-tooltip__section\">\n <div className=\"ai-chat-model-tooltip__description\">{hoveredOption.tooltip.description}</div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { FC, useState, useCallback } from 'react'\nimport { Icon } from '@iconify/react'\nimport './CopyButton.css'\n\ninterface CopyButtonProps {\n /** 要复制的文本 */\n text: string\n /** 按钮标题 */\n title?: string\n /** 图标大小 */\n size?: number\n /** 复制成功回调 */\n onCopy?: (text: string) => void\n}\n\nexport const CopyButton: FC<CopyButtonProps> = ({\n text,\n title = '复制',\n size = 14,\n onCopy,\n}) => {\n const [copied, setCopied] = useState(false)\n\n const handleCopy = useCallback(async (e: React.MouseEvent) => {\n e.stopPropagation()\n try {\n await navigator.clipboard.writeText(text)\n setCopied(true)\n onCopy?.(text)\n setTimeout(() => setCopied(false), 2000)\n } catch (err) {\n console.error('复制失败:', err)\n }\n }, [text, onCopy])\n\n return (\n <button\n className={`copy-btn ${copied ? 'copied' : ''}`}\n title={copied ? '已复制' : title}\n onClick={handleCopy}\n >\n <Icon icon={copied ? 'lucide:check' : 'lucide:copy'} width={size} />\n </button>\n )\n}\n\n","import { useState, type FC } from 'react'\nimport { Icon } from '@iconify/react'\nimport './ImagePart.css'\n\ninterface ImagePartProps {\n url: string\n alt?: string\n}\n\nexport const ImagePart: FC<ImagePartProps> = ({ url, alt }) => {\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState(false)\n\n const handleLoad = () => {\n setLoading(false)\n setError(false)\n }\n\n const handleError = () => {\n setLoading(false)\n setError(true)\n }\n\n const openPreview = () => {\n window.open(url, '_blank')\n }\n\n return (\n <div className=\"image-part\">\n {!error && (\n <img \n src={url} \n alt={alt || '图片'}\n className=\"image-content\"\n onClick={openPreview}\n onLoad={handleLoad}\n onError={handleError}\n style={{ display: loading ? 'none' : 'block' }}\n />\n )}\n {loading && !error && (\n <div className=\"image-loading\">\n <Icon icon=\"lucide:loader-2\" width={24} className=\"spinning\" />\n </div>\n )}\n {error && (\n <div className=\"image-error\">\n <Icon icon=\"lucide:image-off\" width={24} />\n <span>图片加载失败</span>\n </div>\n )}\n </div>\n )\n}\n","import { useState, type FC } from 'react'\nimport { CollapsibleCard } from './CollapsibleCard'\nimport './ErrorPart.css'\n\ninterface ErrorPartProps {\n message: string\n category?: string\n retryable?: boolean\n}\n\n/** 分类标签映射 */\nconst categoryLabels: Record<string, string> = {\n api: 'API 错误',\n network: '网络错误',\n timeout: '请求超时',\n auth: '认证失败',\n rate_limit: '请求限流',\n server: '服务器错误',\n unknown: '未知错误',\n}\n\nexport const ErrorPart: FC<ErrorPartProps> = ({ message, category }) => {\n // 默认展开显示错误信息\n const [expanded, setExpanded] = useState(true)\n \n const categoryLabel = categoryLabels[category || 'unknown'] || category || '请求失败'\n\n return (\n <CollapsibleCard\n icon=\"lucide:alert-circle\"\n iconColor=\"var(--chat-error, #ef4444)\"\n title={categoryLabel}\n titleColor=\"var(--chat-error, #ef4444)\"\n expanded={expanded}\n onExpandedChange={setExpanded}\n >\n <div className=\"error-content\">{message}</div>\n </CollapsibleCard>\n )\n}\n","/**\n * ChatInput Component\n * 与 Vue 版本 ChatInput.vue 保持一致\n */\n\nimport { useState, useRef, useCallback, useEffect, forwardRef, useImperativeHandle, useLayoutEffect, useMemo } from 'react';\nimport './ChatInput.css';\nimport { Icon } from '@iconify/react';\nimport type { ChatMode, ModelOption } from '../../types';\nimport { AtFilePicker } from './AtFilePicker';\nimport { ImagePreviewModal } from './ImagePreviewModal';\nimport { DropdownSelector } from './DropdownSelector';\nimport type { DropdownOption } from './DropdownSelector';\nimport { useChatInputContext } from '../../context/ChatInputContext';\nimport { useImageUpload } from '../../hooks/useImageUpload';\nimport { useVoiceToTextInput } from '../../hooks/useVoiceToTextInput';\nimport type { ImageData } from '../../adapter';\n\n/** ChatInput 暴露给外部的方法 */\nexport interface ChatInputHandle {\n /** 设置输入框内容 */\n setText: (text: string) => void;\n /** 聚焦输入框 */\n focus: () => void;\n /** 清空输入框 */\n clear: () => void;\n /** 在光标位置插入文本(用于 @ 上下文) */\n insertText: (text: string) => void;\n /** 添加图片 */\n addImages: (files: File[]) => void;\n}\n\ninterface ChatInputProps {\n /** 变体模式:input-底部输入框,message-历史消息 */\n variant?: 'input' | 'message';\n /** 受控值(用于历史消息编辑) */\n value?: string;\n /** 图片数据(用于历史消息编辑) */\n images?: string[];\n isLoading?: boolean;\n mode?: ChatMode;\n model?: string;\n /** 模型列表(tooltip 由后端下发,前端仅透传渲染) */\n models?: ModelOption[];\n webSearchEnabled?: boolean;\n thinkingEnabled?: boolean;\n onSend?: (text: string, images?: ImageData[]) => void;\n onCancel?: () => void;\n onAtContext?: () => void;\n onModeChange?: (mode: ChatMode) => void;\n onModelChange?: (model: string) => void;\n onWebSearchChange?: (enabled: boolean) => void;\n onThinkingChange?: (enabled: boolean) => void;\n}\n\n/** 模式配置 */\nconst MODE_OPTIONS: DropdownOption[] = [\n { value: 'agent', label: 'Agent', icon: 'lucide:zap' },\n { value: 'ask', label: 'Ask', icon: 'lucide:message-circle' },\n];\n\nexport const ChatInput = forwardRef<ChatInputHandle, ChatInputProps>(\n (\n {\n variant = 'input',\n value = '',\n images = [],\n isLoading = false,\n mode = 'agent',\n model = '',\n models = [],\n webSearchEnabled = false,\n thinkingEnabled = false,\n onSend,\n onCancel,\n onModeChange,\n onModelChange,\n onWebSearchChange,\n onThinkingChange,\n },\n ref\n ) => {\n const isMessageVariant = variant === 'message';\n\n const inputContext = useChatInputContext();\n const adapter = inputContext?.adapter;\n // cwd 已解耦,不再通过 context 传递\n\n const [inputText, setInputText] = useState(value);\n const [isFocused, setIsFocused] = useState(false);\n\n // 图片上传(使用 hook)\n const imageUpload = useImageUpload();\n const imageInputRef = useRef<HTMLInputElement>(null);\n\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const atSelectorRef = useRef<HTMLDivElement>(null);\n\n // @ 文件选择面板\n const [atPickerVisible, setAtPickerVisible] = useState(false);\n const replaceRangeRef = useRef<{ start: number; end: number } | null>(null);\n const pendingCaretRef = useRef<number | null>(null);\n const pendingFocusRef = useRef(false);\n const prevValueRef = useRef(value);\n\n // 触发文件选择\n const triggerImageUpload = useCallback(() => {\n imageInputRef.current?.click();\n }, []);\n\n // 模型选项\n // 模型选项:tooltip/能力由后端(ai-chat-core)统一提供,前端只负责渲染\n const modelOptions = useMemo<DropdownOption[]>(\n () =>\n models.map((m) => ({\n value: m.modelId,\n label: m.displayName,\n tooltip: m.tooltip,\n })),\n [models]\n );\n\n // 当前模型是否支持深度思考\n const currentModelSupportsThinking = useMemo(() => {\n const currentModel = models.find(m => m.modelId === model);\n return currentModel?.supportsThinking ?? false;\n }, [models, model]);\n\n const closeAtPicker = useCallback(() => {\n setAtPickerVisible(false);\n replaceRangeRef.current = null;\n pendingFocusRef.current = true;\n }, []);\n\n const applyAtPath = useCallback(\n (path: string) => {\n const el = inputRef.current;\n const current = el?.value ?? inputText;\n const insert = `@${path}\\n`;\n const range = replaceRangeRef.current;\n\n let nextText = current;\n let nextCaret = 0;\n\n if (range && current.slice(range.start, range.end) === '@') {\n nextText = current.slice(0, range.start) + insert + current.slice(range.end);\n nextCaret = range.start + insert.length;\n } else if (el) {\n const start = el.selectionStart ?? current.length;\n const end = el.selectionEnd ?? start;\n nextText = current.slice(0, start) + insert + current.slice(end);\n nextCaret = start + insert.length;\n } else {\n nextText = current + insert;\n nextCaret = nextText.length;\n }\n\n setInputText(nextText);\n pendingCaretRef.current = nextCaret;\n pendingFocusRef.current = true;\n\n closeAtPicker();\n },\n [closeAtPicker, inputText]\n );\n\n // 切换 @ 选择器\n const toggleAtPicker = useCallback(() => {\n if (!adapter) return;\n if (!atPickerVisible) {\n replaceRangeRef.current = null;\n }\n setAtPickerVisible((prev) => !prev);\n }, [adapter, atPickerVisible]);\n\n // 同步外部 value\n useEffect(() => {\n setInputText(value);\n }, [value]);\n\n // 同步外部 images(用于历史消息编辑)\n // 使用 JSON.stringify 比较,避免空数组引用变化导致无限循环\n const imagesKey = JSON.stringify(images);\n useEffect(() => {\n if (images?.length) {\n imageUpload.initImages(images);\n } else {\n imageUpload.clearImages();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [imagesKey]);\n\n // 是否显示工具栏\n const showToolbar = !isMessageVariant || isFocused;\n\n // 占位符\n const placeholder = mode === 'ask' ? '有什么问题想问我?' : '描述任务,@ 添加上下文';\n\n // 是否有内容可发送\n const hasContent = useMemo(() => {\n return inputText.trim() || imageUpload.hasImages;\n }, [inputText, imageUpload.hasImages]);\n\n const voiceCtl = useVoiceToTextInput({\n adapter,\n inputText,\n setInputText,\n hasImages: imageUpload.hasImages,\n isLoading,\n });\n const voiceInput = voiceCtl.voiceInput;\n const toggleVoiceInput = useCallback(async () => {\n await voiceCtl.toggleVoice();\n // 停止/取消后聚焦输入框\n if (voiceInput.status === 'recording' || voiceInput.status === 'connecting') {\n pendingFocusRef.current = true;\n pendingCaretRef.current = null;\n }\n }, [voiceCtl, voiceInput.status]);\n\n // 自动调整高度\n const adjustTextareaHeight = useCallback(() => {\n if (inputRef.current) {\n inputRef.current.style.height = 'auto';\n const scrollHeight = inputRef.current.scrollHeight;\n inputRef.current.style.height = `${Math.min(scrollHeight, 150)}px`;\n }\n }, []);\n\n // 统一在 DOM commit 后调整高度/光标\n useLayoutEffect(() => {\n adjustTextareaHeight();\n const el = inputRef.current;\n if (!el) return;\n\n if (pendingFocusRef.current) {\n el.focus();\n pendingFocusRef.current = false;\n }\n if (pendingCaretRef.current !== null) {\n const pos = pendingCaretRef.current;\n pendingCaretRef.current = null;\n el.setSelectionRange(pos, pos);\n }\n }, [inputText, adjustTextareaHeight]);\n\n // 暴露给外部的方法\n useImperativeHandle(\n ref,\n () => ({\n setText: (text: string) => {\n setInputText(text);\n pendingCaretRef.current = text.length;\n pendingFocusRef.current = false;\n },\n focus: () => {\n inputRef.current?.focus();\n },\n clear: () => {\n setInputText('');\n imageUpload.clearImages();\n // 重置语音输入状态\n if (voiceInput.status !== 'idle') {\n voiceInput.cancel();\n }\n // 重置 @ 选择器\n setAtPickerVisible(false);\n replaceRangeRef.current = null;\n // 重置输入框高度\n if (inputRef.current) {\n inputRef.current.style.height = 'auto';\n }\n pendingCaretRef.current = 0;\n },\n insertText: (text: string) => {\n if (!text) return;\n const el = inputRef.current;\n const current = inputText;\n if (!el) {\n setInputText(current + text);\n pendingCaretRef.current = (current + text).length;\n return;\n }\n const start = el.selectionStart ?? current.length;\n const end = el.selectionEnd ?? start;\n const next = current.slice(0, start) + text + current.slice(end);\n setInputText(next);\n pendingCaretRef.current = start + text.length;\n pendingFocusRef.current = true;\n },\n addImages: (files: File[]) => {\n imageUpload.addImages(files);\n },\n }),\n [inputText, imageUpload]\n );\n\n // 发送或取消\n const handleSendOrCancel = useCallback(() => {\n if (isLoading) {\n onCancel?.();\n return;\n }\n\n const text = inputText.trim();\n if (!text && !imageUpload.hasImages) return;\n\n // 获取图片数据\n const images = imageUpload.imageData.length > 0 ? imageUpload.imageData : undefined;\n\n onSend?.(text, images);\n\n if (!isMessageVariant) {\n setInputText('');\n imageUpload.clearImages();\n if (inputRef.current) {\n inputRef.current.style.height = 'auto';\n }\n pendingCaretRef.current = 0;\n pendingFocusRef.current = true;\n } else {\n setIsFocused(false);\n }\n }, [isLoading, inputText, imageUpload, isMessageVariant, onCancel, onSend]);\n\n // 处理键盘事件\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (voiceCtl.handleKeyDownForVoice(e)) return;\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSendOrCancel();\n }\n },\n [handleSendOrCancel, voiceCtl]\n );\n\n // 点击外部关闭菜单\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as HTMLElement;\n // 关闭 @ 选择器\n if (!target.closest('.at-picker-wrapper')) {\n setAtPickerVisible(false);\n }\n if (isMessageVariant && containerRef.current && !containerRef.current.contains(target)) {\n setIsFocused(false);\n }\n };\n\n document.addEventListener('click', handleClickOutside);\n return () => document.removeEventListener('click', handleClickOutside);\n }, [isMessageVariant]);\n\n return (\n <div\n className={`chat-input${isMessageVariant ? ' message-variant' : ''}`.trim()}\n onDragOver={imageUpload.handleDragOver}\n onDragLeave={imageUpload.handleDragLeave}\n onDrop={imageUpload.handleDrop}\n >\n <div\n ref={containerRef}\n className={`input-container${isFocused ? ' focused' : ''}${imageUpload.isDragOver ? ' drag-over' : ''}${voiceInput.status === 'connecting' ? ' connecting' : ''}${voiceInput.isRecording ? ' recording' : ''}`.trim()}\n >\n {/* 图片预览区 */}\n {imageUpload.hasImages && (\n <div className=\"images-preview\">\n {imageUpload.images.map((img, i) => (\n <div key={i} className=\"image-preview-item\">\n <img\n src={img.dataUrl}\n alt=\"预览\"\n className=\"image-thumbnail\"\n onClick={() => imageUpload.openPreview(i)}\n />\n <button\n className=\"image-remove-btn\"\n title=\"移除图片\"\n onClick={(e) => {\n e.stopPropagation();\n imageUpload.removeImage(i);\n }}\n >\n <Icon icon=\"lucide:x\" width={10} />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {/* 图片预览弹窗 */}\n <ImagePreviewModal\n visible={imageUpload.previewVisible}\n images={imageUpload.imageUrls}\n initialIndex={imageUpload.previewIndex}\n onClose={imageUpload.closePreview}\n onIndexChange={imageUpload.setPreviewIndex}\n />\n\n {/* 输入框 */}\n <div className=\"input-field-wrapper\">\n <textarea\n ref={inputRef}\n value={inputText}\n placeholder={placeholder}\n rows={1}\n className=\"input-field chat-scrollbar\"\n readOnly={voiceInput.isRecording}\n spellCheck={false}\n autoCorrect=\"off\"\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n onChange={(e) => {\n const next = e.target.value;\n const prev = prevValueRef.current;\n prevValueRef.current = next;\n setInputText(next);\n\n // 检测是否新增输入了 '@',用事件驱动打开面板\n if (adapter && next.length === prev.length + 1) {\n const cursor = e.target.selectionStart ?? next.length;\n const inserted = next.slice(cursor - 1, cursor);\n if (inserted === '@') {\n replaceRangeRef.current = { start: cursor - 1, end: cursor };\n setAtPickerVisible(true);\n }\n }\n }}\n onInput={adjustTextareaHeight}\n onKeyDown={handleKeyDown}\n onFocus={() => setIsFocused(true)}\n onPaste={imageUpload.handlePaste}\n />\n </div>\n\n {/* 底部控制栏 */}\n {showToolbar && (\n <div className=\"input-controls\">\n {/* 左侧 */}\n <div className=\"input-left\">\n {/* 模式选择 */}\n <DropdownSelector\n value={mode}\n options={MODE_OPTIONS}\n onSelect={(v) => onModeChange?.(v as ChatMode)}\n />\n\n {/* 模型选择(分组显示:原生和 OpenRouter) */}\n <DropdownSelector \n value={model} \n options={modelOptions}\n onSelect={(v) => onModelChange?.(v)} \n />\n </div>\n\n {/* 右侧 */}\n <div className=\"input-right\">\n {/* 深度思考(ask 模式隐藏,仅支持的模型显示) */}\n {mode !== 'ask' && currentModelSupportsThinking && (\n <button\n className={`toggle-btn${thinkingEnabled ? ' active' : ''}`}\n title=\"深度思考\"\n onClick={() => onThinkingChange?.(!thinkingEnabled)}\n >\n <Icon icon=\"lucide:sparkles\" width={18} />\n </button>\n )}\n\n {/* 联网搜索(ask 模式隐藏) */}\n {mode !== 'ask' && (\n <button\n className={`toggle-btn${webSearchEnabled ? ' active' : ''}`}\n title=\"联网搜索\"\n onClick={() => onWebSearchChange?.(!webSearchEnabled)}\n >\n <Icon icon=\"lucide:globe\" width={18} />\n </button>\n )}\n\n {/* 图片上传按钮 */}\n <button className=\"icon-btn\" title=\"添加图片\" onClick={triggerImageUpload}>\n <Icon icon=\"lucide:image\" width={18} />\n </button>\n <input\n ref={imageInputRef}\n type=\"file\"\n accept=\"image/*\"\n multiple\n className=\"hidden-input\"\n onChange={imageUpload.handleImageSelect}\n />\n\n {/* @ 上下文选择器 */}\n <div\n ref={atSelectorRef}\n className=\"at-picker-wrapper\"\n onClick={(e) => {\n e.stopPropagation();\n toggleAtPicker();\n }}\n >\n <button className=\"icon-btn\" title=\"提及上下文 (@)\">\n <Icon icon=\"lucide:at-sign\" width={18} />\n </button>\n\n {/* @ 下拉菜单 */}\n {adapter && (\n <AtFilePicker\n visible={atPickerVisible}\n adapter={adapter}\n // initialDir 已移除,cwd 已解耦\n anchorEl={atSelectorRef.current}\n onClose={closeAtPicker}\n onSelect={applyAtPath}\n />\n )}\n </div>\n\n {/* 方案 A:录音按钮 + 发送按钮独立(停止录音入口永不消失) */}\n <button\n className={`voice-btn${voiceInput.status === 'connecting' ? ' connecting' : ''}${voiceInput.isRecording ? ' recording' : ''}`}\n title={\n voiceInput.status === 'connecting'\n ? '正在连接,点击取消'\n : voiceInput.isRecording\n ? '点击停止'\n : '点击录音'\n }\n onClick={() => toggleVoiceInput().catch(() => {})}\n disabled={isLoading || !adapter}\n >\n {voiceInput.status === 'connecting' ? (\n <Icon icon=\"lucide:loader-2\" width={18} className=\"spin\" />\n ) : voiceInput.isRecording ? (\n <Icon icon=\"streamline-flex:button-pause-circle-remix\" width={18} />\n ) : (\n <Icon icon=\"lucide:mic\" width={18} />\n )}\n </button>\n\n <button\n className={`send-btn${isLoading ? ' loading' : ''}`}\n title={\n isLoading\n ? '停止'\n : voiceInput.status === 'connecting'\n ? '语音连接中,先取消/停止'\n : voiceInput.isRecording\n ? '录音中,先停止'\n : isMessageVariant\n ? '重新发送'\n : '发送'\n }\n onClick={handleSendOrCancel}\n disabled={(!hasContent && !isLoading) || voiceInput.isRecording || voiceInput.status === 'connecting'}\n >\n {isLoading ? (\n <Icon icon=\"streamline-flex:button-pause-circle-remix\" width={18} />\n ) : (\n <Icon icon=\"uil:message\" width={18} />\n )}\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n );\n }\n);\n\n// 添加 displayName 以便于调试\nChatInput.displayName = 'ChatInput';\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport { Icon } from '@iconify/react'\nimport type { ChatAdapter } from '../../adapter'\nimport { getFileIcon, basename, dirname } from '../../utils/fileIcon'\nimport {\n AtFilesView,\n AtDocsView,\n AtTerminalsView,\n AtChatsView,\n AtBranchView,\n AtBrowserView,\n} from './at-views'\nimport type { AtFilesViewHandle, AtPlaceholderViewHandle } from './at-views'\nimport './AtFilePicker.css'\n\nexport interface AtFilePickerProps {\n visible: boolean\n adapter: ChatAdapter\n initialDir?: string\n /** 锚点元素(用于定位下拉面板) */\n anchorEl?: HTMLElement | null\n onClose: () => void\n onSelect: (path: string) => void\n}\n\n// ============ 常量 ============\nconst RECENT_KEY = 'ai-chat.at.recentPaths'\nconst MAX_RECENT = 6\nconst DROPDOWN_WIDTH = 332\nconst DROPDOWN_MIN_HEIGHT = 200 // 最小高度\nconst DROPDOWN_MAX_HEIGHT = 600 // 最大高度(大屏幕时充分利用)\n\n// 分类定义\ntype CategoryId = 'files' | 'docs' | 'terminals' | 'chats' | 'branch' | 'browser'\n\ninterface Category {\n id: CategoryId\n label: string\n icon: string\n placeholder: string\n}\n\nconst categories: Category[] = [\n { id: 'files', label: '文件和文件夹', icon: 'lucide:folder-open', placeholder: '搜索文件和文件夹...' },\n { id: 'docs', label: '文档', icon: 'lucide:book-open', placeholder: '搜索文档...' },\n { id: 'terminals', label: '终端', icon: 'lucide:terminal', placeholder: '搜索终端...' },\n { id: 'chats', label: '历史对话', icon: 'lucide:message-square', placeholder: '搜索历史对话...' },\n { id: 'branch', label: '分支差异', icon: 'lucide:git-branch', placeholder: '搜索分支差异...' },\n { id: 'browser', label: '网页', icon: 'lucide:globe', placeholder: '搜索网页...' },\n]\n\ntype ViewType = 'categories' | CategoryId\n\n// 视图组件的 ref 句柄类型\ntype ViewHandle = AtFilesViewHandle | AtPlaceholderViewHandle\n\nexport function AtFilePicker({\n visible,\n adapter,\n initialDir,\n anchorEl,\n onClose,\n onSelect,\n}: AtFilePickerProps) {\n const searchRef = useRef<HTMLInputElement>(null)\n const bodyRef = useRef<HTMLDivElement>(null)\n const viewRef = useRef<ViewHandle>(null)\n const [query, setQuery] = useState('')\n const [currentView, setCurrentView] = useState<ViewType>('categories')\n const [activeKey, setActiveKey] = useState('')\n const [recentList, setRecentList] = useState<string[]>([])\n const [viewActiveIndex, setViewActiveIndex] = useState(-1)\n const [viewItemCount, setViewItemCount] = useState(0)\n const [dropdownStyle, setDropdownStyle] = useState<React.CSSProperties>({})\n const [isScrolling, setIsScrolling] = useState(false)\n const scrollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n // ============ 下拉面板定位 ============\n const updateDropdownPosition = useCallback(() => {\n if (!anchorEl) {\n setDropdownStyle({})\n return\n }\n\n const rect = anchorEl.getBoundingClientRect()\n const viewportHeight = window.innerHeight\n const viewportWidth = window.innerWidth\n\n // 计算上方和下方的可用空间(预留 16px 边距)\n const spaceAbove = rect.top - 16\n const spaceBelow = viewportHeight - rect.bottom - 16\n\n // 决定向上还是向下展开\n const openUp = spaceAbove > spaceBelow\n\n // 计算可用高度\n const availableHeight = openUp ? spaceAbove : spaceBelow\n \n // 计算最大高度:\n // 1. 优先使用可用空间(确保不超出窗口)\n // 2. 如果可用空间很大,限制在全局最大高度(大屏幕时充分利用但不浪费)\n // 3. 同时不能超过视口高度的 80%\n const viewportMaxHeight = viewportHeight * 0.8\n const maxHeight = Math.min(\n availableHeight, // 使用可用空间(确保不超出窗口)\n DROPDOWN_MAX_HEIGHT, // 但不超过全局最大高度(大屏幕时限制在 600px)\n viewportMaxHeight // 也不能超过视口的 80%\n )\n\n // 计算水平位置,确保不超出右边界\n let left = rect.right - DROPDOWN_WIDTH\n if (left < 8) left = 8\n if (left + DROPDOWN_WIDTH > viewportWidth - 8) {\n left = viewportWidth - DROPDOWN_WIDTH - 8\n }\n\n if (openUp) {\n setDropdownStyle({\n position: 'fixed',\n left: `${left}px`,\n bottom: `${viewportHeight - rect.top + 6}px`,\n top: 'auto',\n maxHeight: `${maxHeight}px`,\n })\n } else {\n setDropdownStyle({\n position: 'fixed',\n left: `${left}px`,\n top: `${rect.bottom + 6}px`,\n bottom: 'auto',\n maxHeight: `${maxHeight}px`,\n })\n }\n }, [anchorEl])\n\n // ============ 工具函数 ============\n const loadRecent = useCallback(() => {\n try {\n const raw = localStorage.getItem(RECENT_KEY)\n if (!raw) {\n setRecentList([])\n return\n }\n const list = JSON.parse(raw) as unknown\n if (Array.isArray(list)) {\n setRecentList(list.filter((x) => typeof x === 'string').slice(0, MAX_RECENT))\n } else {\n setRecentList([])\n }\n } catch {\n setRecentList([])\n }\n }, [])\n\n const pushRecent = useCallback((path: string) => {\n setRecentList(prev => {\n const next = [path, ...prev.filter((p) => p !== path)].slice(0, MAX_RECENT)\n try {\n localStorage.setItem(RECENT_KEY, JSON.stringify(next))\n } catch {\n // ignore\n }\n return next\n })\n }, [])\n\n const getSearchPlaceholder = useCallback((): string => {\n if (currentView === 'categories') return '添加文件、文件夹、文档...'\n const cat = categories.find((c) => c.id === currentView)\n return cat?.placeholder || 'Search...'\n }, [currentView])\n\n // ============ 过滤 ============\n const filteredRecent = useMemo(() => {\n if (currentView !== 'categories') return []\n const q = query.trim().toLowerCase()\n if (!q) return recentList\n return recentList.filter((p) => p.toLowerCase().includes(q))\n }, [currentView, query, recentList])\n\n // ============ 视图切换 ============\n const goBackToCategories = useCallback(() => {\n setCurrentView('categories')\n setQuery('')\n setActiveKey('')\n setViewActiveIndex(-1)\n requestAnimationFrame(() => searchRef.current?.focus())\n }, [])\n\n const handleCategoryClick = useCallback((cat: Category) => {\n setCurrentView(cat.id)\n setQuery('')\n setActiveKey('')\n setViewActiveIndex(-1)\n requestAnimationFrame(() => searchRef.current?.focus())\n }, [])\n\n // ============ 选择与关闭 ============\n const handleEsc = useCallback(() => {\n if (currentView !== 'categories') {\n goBackToCategories()\n } else {\n onClose()\n }\n }, [currentView, goBackToCategories, onClose])\n\n const selectPath = useCallback((path: string) => {\n pushRecent(path)\n onSelect(path)\n }, [pushRecent, onSelect])\n\n // ============ 滚动处理 ============\n // 处理滚动事件\n const handleScroll = useCallback(() => {\n // 标记正在滚动\n setIsScrolling(true)\n \n // 清除之前的定时器\n if (scrollTimerRef.current) {\n clearTimeout(scrollTimerRef.current)\n }\n \n // 滚动停止后 150ms 才允许鼠标事件(确保滚动完全停止)\n scrollTimerRef.current = setTimeout(() => {\n setIsScrolling(false)\n scrollTimerRef.current = null\n }, 150)\n }, [])\n\n // ============ 键盘导航 ============\n // 包装的 setActiveKey,检查滚动状态\n const handleSetActiveKey = useCallback((key: string) => {\n // 如果正在滚动,完全忽略鼠标悬停事件\n // 因为滚动时鼠标位置不变,但元素在移动,会不断触发 mouseenter\n if (isScrolling) return\n setActiveKey(key)\n }, [isScrolling])\n\n // 包装的 setViewActiveIndex,检查滚动状态\n const handleSetViewActiveIndex = useCallback((index: number) => {\n // 如果正在滚动,完全忽略鼠标悬停事件\n // 因为滚动时鼠标位置不变,但元素在移动,会不断触发 mouseenter\n if (isScrolling) return\n setViewActiveIndex(index)\n }, [isScrolling])\n\n // 滚动到选中的元素\n const scrollToActive = useCallback(() => {\n requestAnimationFrame(() => {\n if (!bodyRef.current) return\n\n let activeElement: HTMLElement | null = null\n\n if (currentView === 'categories') {\n // 分类视图:找到对应 activeKey 的按钮\n if (activeKey.startsWith('recent:')) {\n const idx = Number(activeKey.split(':')[1] || -1)\n // 在最近文件列表中查找\n const recentSection = bodyRef.current.querySelector('.at-picker-recent')\n if (recentSection) {\n const buttons = recentSection.querySelectorAll('.at-picker-item')\n if (idx >= 0 && idx < buttons.length) {\n activeElement = buttons[idx] as HTMLElement\n }\n }\n } else if (activeKey.startsWith('cat:')) {\n const idx = Number(activeKey.split(':')[1] || -1)\n // 在分类列表中查找\n const categorySection = bodyRef.current.querySelector('.at-picker-section:not(.at-picker-recent)')\n if (categorySection) {\n const buttons = categorySection.querySelectorAll('.at-picker-item')\n if (idx >= 0 && idx < buttons.length) {\n activeElement = buttons[idx] as HTMLElement\n }\n }\n }\n } else {\n // 子视图:找到对应 activeIndex 的元素\n const activeItems = bodyRef.current.querySelectorAll('.at-view-item.active')\n if (activeItems.length > 0) {\n activeElement = activeItems[0] as HTMLElement\n }\n }\n\n // 滚动到视窗内\n if (activeElement) {\n // 使用 requestAnimationFrame 确保 DOM 已更新\n requestAnimationFrame(() => {\n activeElement?.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'nearest',\n })\n // 滚动事件会通过 handleScroll 自动处理 isScrolling 状态\n })\n }\n })\n }, [currentView, activeKey, filteredRecent.length])\n\n const move = useCallback((delta: number) => {\n if (currentView === 'categories') {\n const recentCount = filteredRecent.length\n const catCount = categories.length\n const total = recentCount + catCount\n if (total === 0) return\n\n let pos = -1\n if (activeKey.startsWith('recent:')) {\n pos = Number(activeKey.split(':')[1] || -1)\n } else if (activeKey.startsWith('cat:')) {\n pos = recentCount + Number(activeKey.split(':')[1] || -1)\n }\n\n const next = pos < 0 ? 0 : (pos + delta + total) % total\n // 直接更新 activeKey,确保状态立即更新\n if (next < recentCount) {\n setActiveKey(`recent:${next}`)\n } else {\n setActiveKey(`cat:${next - recentCount}`)\n }\n // 立即滚动,滚动事件会自动处理 isScrolling 状态\n scrollToActive()\n } else {\n const total = viewItemCount\n if (total === 0) return\n\n const current = viewActiveIndex\n const next = current < 0 ? 0 : (current + delta + total) % total\n // 直接更新 viewActiveIndex,确保状态立即更新\n setViewActiveIndex(next)\n // 立即滚动,滚动事件会自动处理 isScrolling 状态\n scrollToActive()\n }\n }, [currentView, filteredRecent.length, activeKey, viewItemCount, viewActiveIndex, scrollToActive])\n\n const confirmActive = useCallback(() => {\n if (currentView === 'categories') {\n if (activeKey.startsWith('recent:')) {\n const idx = Number(activeKey.split(':')[1])\n const p = filteredRecent[idx]\n if (p) selectPath(p)\n } else if (activeKey.startsWith('cat:')) {\n const idx = Number(activeKey.split(':')[1])\n const cat = categories[idx]\n if (cat) handleCategoryClick(cat)\n }\n } else {\n viewRef.current?.confirmActive()\n }\n }, [currentView, activeKey, filteredRecent, selectPath, handleCategoryClick])\n\n // ============ 键盘事件处理 ============\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n move(1)\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n move(-1)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n confirmActive()\n } else if (e.key === 'Escape') {\n e.preventDefault()\n handleEsc()\n }\n }, [move, confirmActive, handleEsc])\n\n // ============ 生命周期 ============\n useEffect(() => {\n if (!visible) return\n loadRecent()\n setQuery('')\n setActiveKey('')\n setCurrentView('categories')\n setViewActiveIndex(-1)\n updateDropdownPosition()\n requestAnimationFrame(() => searchRef.current?.focus())\n }, [visible, loadRecent, updateDropdownPosition])\n\n // 窗口大小变化时更新位置\n useEffect(() => {\n if (!visible) return\n const handleResize = () => updateDropdownPosition()\n window.addEventListener('resize', handleResize)\n window.addEventListener('scroll', handleResize, true)\n return () => {\n window.removeEventListener('resize', handleResize)\n window.removeEventListener('scroll', handleResize, true)\n // 清理滚动定时器\n if (scrollTimerRef.current) {\n clearTimeout(scrollTimerRef.current)\n scrollTimerRef.current = null\n }\n }\n }, [visible, updateDropdownPosition])\n\n // anchorEl 变化时更新位置\n useEffect(() => {\n if (visible) {\n updateDropdownPosition()\n }\n }, [visible, anchorEl, updateDropdownPosition])\n\n if (!visible) return null\n\n // 渲染子视图组件\n const renderViewComponent = () => {\n const commonProps = {\n query,\n activeIndex: viewActiveIndex,\n onSelect: selectPath,\n onSetActive: handleSetViewActiveIndex,\n onUpdateCount: setViewItemCount,\n }\n\n switch (currentView) {\n case 'files':\n return <AtFilesView ref={viewRef} adapter={adapter} initialDir={initialDir} {...commonProps} />\n case 'docs':\n return <AtDocsView ref={viewRef} {...commonProps} />\n case 'terminals':\n return <AtTerminalsView ref={viewRef} {...commonProps} />\n case 'chats':\n return <AtChatsView ref={viewRef} {...commonProps} />\n case 'branch':\n return <AtBranchView ref={viewRef} {...commonProps} />\n case 'browser':\n return <AtBrowserView ref={viewRef} {...commonProps} />\n default:\n return null\n }\n }\n\n return createPortal(\n <div className=\"at-picker-dropdown\" style={dropdownStyle} onClick={(e) => e.stopPropagation()}>\n {/* 头部:搜索框 */}\n <div className=\"at-picker-header\">\n {currentView !== 'categories' ? (\n <button className=\"at-picker-back\" onClick={goBackToCategories}>\n <Icon icon=\"lucide:arrow-left\" width={14} />\n </button>\n ) : (\n <Icon icon=\"lucide:search\" width={14} className=\"at-picker-search-icon\" />\n )}\n <input\n ref={searchRef}\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n className=\"at-picker-search\"\n type=\"text\"\n placeholder={getSearchPlaceholder()}\n spellCheck={false}\n autoCorrect=\"off\"\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n onKeyDown={handleKeyDown}\n />\n </div>\n\n <div \n ref={bodyRef} \n className={`at-picker-body chat-scrollbar${isScrolling ? ' is-scrolling' : ''}`}\n onScroll={handleScroll}\n >\n {/* 分类视图 */}\n {currentView === 'categories' ? (\n <>\n {/* 最近文件 */}\n {filteredRecent.length > 0 && (\n <div className=\"at-picker-section at-picker-recent\">\n <div className=\"at-picker-list\">\n {filteredRecent.map((p, i) => (\n <button\n key={p}\n className={`at-picker-item${activeKey === `recent:${i}` ? ' active' : ''}`}\n onMouseEnter={() => handleSetActiveKey(`recent:${i}`)}\n onClick={() => selectPath(p)}\n >\n <Icon icon={getFileIcon(p)} width={14} className=\"at-picker-item-icon\" />\n <span className=\"at-picker-item-name\">{basename(p)}</span>\n <span className=\"at-picker-item-path\">{dirname(p)}</span>\n </button>\n ))}\n </div>\n </div>\n )}\n\n {/* 分类列表 */}\n <div className=\"at-picker-section\">\n <div className=\"at-picker-list\">\n {categories.map((cat, i) => (\n <button\n key={cat.id}\n className={`at-picker-item at-picker-category${activeKey === `cat:${i}` ? ' active' : ''}`}\n onMouseEnter={() => handleSetActiveKey(`cat:${i}`)}\n onClick={() => handleCategoryClick(cat)}\n >\n <Icon icon={cat.icon} width={14} className=\"at-picker-item-icon\" />\n <span className=\"at-picker-item-name\">{cat.label}</span>\n <Icon icon=\"lucide:chevron-right\" width={12} className=\"at-picker-chevron\" />\n </button>\n ))}\n </div>\n </div>\n </>\n ) : (\n renderViewComponent()\n )}\n </div>\n\n <div className=\"at-picker-footer\">\n <span className=\"at-picker-hint\">↑↓ 导航 · Enter 选择 · Esc {currentView === 'categories' ? '关闭' : '返回'}</span>\n </div>\n </div>,\n document.body\n )\n}\n","/**\n * 根据文件名或路径获取对应的图标\n */\nexport function getFileIcon(nameOrPath: string): string {\n const name = basename(nameOrPath).toLowerCase();\n const ext = name.includes('.') ? name.slice(name.lastIndexOf('.')) : '';\n\n if (ext === '.vue') return 'vscode-icons:file-type-vue';\n if (ext === '.tsx') return 'vscode-icons:file-type-reactts';\n if (ext === '.jsx') return 'vscode-icons:file-type-reactjs';\n if (ext === '.ts') return 'vscode-icons:file-type-typescript';\n if (ext === '.js') return 'vscode-icons:file-type-js';\n if (ext === '.css') return 'vscode-icons:file-type-css';\n if (ext === '.scss' || ext === '.sass') return 'vscode-icons:file-type-scss';\n if (ext === '.less') return 'vscode-icons:file-type-less';\n if (ext === '.json') return 'vscode-icons:file-type-json';\n if (ext === '.yaml' || ext === '.yml') return 'vscode-icons:file-type-yaml';\n if (ext === '.xml') return 'vscode-icons:file-type-xml';\n if (ext === '.md') return 'vscode-icons:file-type-markdown';\n if (ext === '.txt') return 'vscode-icons:file-type-text';\n if (['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.ico'].includes(ext)) {\n return 'vscode-icons:file-type-image';\n }\n if (ext === '.html' || ext === '.htm') return 'vscode-icons:file-type-html';\n if (ext === '.py') return 'vscode-icons:file-type-python';\n if (ext === '.go') return 'vscode-icons:file-type-go';\n if (ext === '.rs') return 'vscode-icons:file-type-rust';\n if (ext === '.sh' || ext === '.bash' || ext === '.zsh') return 'vscode-icons:file-type-shell';\n\n return 'lucide:file';\n}\n\n/**\n * 获取路径的文件名部分\n */\nexport function basename(p: string): string {\n const normalized = p.replace(/\\\\/g, '/');\n const idx = normalized.lastIndexOf('/');\n return idx >= 0 ? normalized.slice(idx + 1) || normalized : normalized;\n}\n\n/**\n * 获取路径的目录部分\n */\nexport function dirname(p: string): string {\n const normalized = p.replace(/\\\\/g, '/');\n const idx = normalized.lastIndexOf('/');\n return idx > 0 ? normalized.slice(0, idx) : '';\n}\n","import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, forwardRef } from 'react'\nimport { Icon } from '@iconify/react'\nimport type { ChatAdapter } from '../../../adapter'\n\ninterface FileInfo {\n name: string\n path: string\n isDirectory: boolean\n}\nimport { getFileIcon } from '../../../utils/fileIcon'\nimport './AtViewStyles.css'\n\nexport interface AtFilesViewProps {\n adapter: ChatAdapter\n initialDir?: string\n query: string\n activeIndex: number\n onSelect: (path: string) => void\n onSetActive: (index: number) => void\n onUpdateCount: (count: number) => void\n}\n\nexport interface AtFilesViewHandle {\n getActivePath: () => string | null\n confirmActive: () => void\n}\n\nexport const AtFilesView = forwardRef<AtFilesViewHandle, AtFilesViewProps>(({\n adapter,\n initialDir,\n query,\n activeIndex,\n onSelect,\n onSetActive,\n onUpdateCount,\n}, ref) => {\n const [loading, setLoading] = useState(false)\n const [currentPath, setCurrentPath] = useState('')\n const [entries, setEntries] = useState<FileInfo[]>([])\n const initializedRef = useRef(false)\n\n // 过滤后的文件列表\n const filteredEntries = useMemo(() => {\n const q = query.trim().toLowerCase()\n if (!q) return entries\n return entries.filter((f) => f.name.toLowerCase().includes(q))\n }, [entries, query])\n\n // 通知父组件条目数量变化\n useEffect(() => {\n onUpdateCount(filteredEntries.length)\n }, [filteredEntries.length, onUpdateCount])\n\n // 加载目录\n const loadDir = useCallback(async (dir: string) => {\n if (!adapter.listDir) return\n setLoading(true)\n try {\n const resolved = (await adapter.resolvePath?.(dir)) || dir\n const list = await adapter.listDir(resolved)\n const sorted = [...list].sort((a, b) => {\n if (a.isDirectory !== b.isDirectory) return a.isDirectory ? -1 : 1\n return a.name.localeCompare(b.name)\n })\n setEntries(sorted)\n setCurrentPath(resolved)\n onSetActive(-1)\n } finally {\n setLoading(false)\n }\n }, [adapter, onSetActive])\n\n // 返回上级目录\n const goUp = useCallback(async () => {\n if (!adapter.parentDir) return\n const parent = await adapter.parentDir(currentPath)\n if (parent && parent !== currentPath) {\n await loadDir(parent)\n }\n }, [adapter, currentPath, loadDir])\n\n // 返回主目录\n const goHome = useCallback(async () => {\n if (!adapter.homeDir) return\n const home = await adapter.homeDir()\n await loadDir(home)\n }, [adapter, loadDir])\n\n // 点击条目\n const handleEntryClick = useCallback((f: FileInfo) => {\n if (f.isDirectory) {\n loadDir(f.path)\n return\n }\n onSelect(f.path)\n }, [loadDir, onSelect])\n\n // 暴露给父组件的方法\n useImperativeHandle(ref, () => ({\n getActivePath: () => {\n if (activeIndex < 0) return null\n return filteredEntries[activeIndex]?.path || null\n },\n confirmActive: () => {\n const entry = filteredEntries[activeIndex]\n if (entry) {\n handleEntryClick(entry)\n }\n },\n }), [activeIndex, filteredEntries, handleEntryClick])\n\n // 初始加载\n useEffect(() => {\n if (initializedRef.current) return\n initializedRef.current = true\n \n const init = async () => {\n const dir = initialDir || (adapter.homeDir ? await adapter.homeDir() : '')\n if (dir) await loadDir(dir)\n }\n init()\n }, [adapter, initialDir, loadDir])\n\n return (\n <div className=\"at-files-view\">\n <div className=\"at-view-section-title\">文件和文件夹</div>\n\n {/* 路径栏 */}\n <div className=\"at-view-pathbar\">\n <button className=\"at-view-pathbtn\" title=\"返回上级\" onClick={goUp}>\n <Icon icon=\"lucide:arrow-up\" width={12} />\n </button>\n <button className=\"at-view-pathbtn\" title=\"主目录\" onClick={goHome}>\n <Icon icon=\"lucide:home\" width={12} />\n </button>\n <div className=\"at-view-pathtext\" title={currentPath || ''}>\n {currentPath || '-'}\n </div>\n </div>\n\n {/* 文件列表 */}\n <div className=\"at-view-list\">\n {loading ? (\n <div className=\"at-view-empty\">加载中...</div>\n ) : filteredEntries.length === 0 ? (\n <div className=\"at-view-empty\">\n {query.trim() ? '没有找到匹配项' : '目录为空'}\n </div>\n ) : (\n filteredEntries.map((f, i) => (\n <button\n key={f.path}\n className={`at-view-item${activeIndex === i ? ' active' : ''}`}\n onMouseEnter={() => onSetActive(i)}\n onClick={() => handleEntryClick(f)}\n >\n <Icon icon={f.isDirectory ? 'lucide:folder' : getFileIcon(f.name)} width={14} className=\"at-view-item-icon\" />\n <span className=\"at-view-item-name\">{f.name}</span>\n <span className=\"at-view-item-path\">{f.path}</span>\n </button>\n ))\n )}\n </div>\n </div>\n )\n})\n\nAtFilesView.displayName = 'AtFilesView'\n","import { forwardRef, useImperativeHandle } from 'react'\nimport { Icon } from '@iconify/react'\nimport './AtViewStyles.css'\n\nexport interface AtPlaceholderViewProps {\n query: string\n activeIndex: number\n onSelect: (path: string) => void\n onSetActive: (index: number) => void\n onUpdateCount: (count: number) => void\n}\n\nexport interface AtPlaceholderViewHandle {\n getActivePath: () => string | null\n confirmActive: () => void\n}\n\nexport const AtDocsView = forwardRef<AtPlaceholderViewHandle, AtPlaceholderViewProps>((_, ref) => {\n useImperativeHandle(ref, () => ({\n getActivePath: () => null,\n confirmActive: () => {},\n }), [])\n\n return (\n <div className=\"at-placeholder-view\">\n <Icon icon=\"lucide:book-open\" width={32} className=\"at-placeholder-icon\" />\n <div className=\"at-placeholder-title\">文档</div>\n <div className=\"at-placeholder-desc\">功能待实现</div>\n <div className=\"at-placeholder-hint\">将支持引用项目文档、API 文档等</div>\n </div>\n )\n})\n\nAtDocsView.displayName = 'AtDocsView'\n","import { forwardRef, useImperativeHandle } from 'react'\nimport { Icon } from '@iconify/react'\nimport './AtViewStyles.css'\n\nexport interface AtPlaceholderViewProps {\n query: string\n activeIndex: number\n onSelect: (path: string) => void\n onSetActive: (index: number) => void\n onUpdateCount: (count: number) => void\n}\n\nexport interface AtPlaceholderViewHandle {\n getActivePath: () => string | null\n confirmActive: () => void\n}\n\nexport const AtTerminalsView = forwardRef<AtPlaceholderViewHandle, AtPlaceholderViewProps>((_, ref) => {\n useImperativeHandle(ref, () => ({\n getActivePath: () => null,\n confirmActive: () => {},\n }), [])\n\n return (\n <div className=\"at-placeholder-view\">\n <Icon icon=\"lucide:terminal\" width={32} className=\"at-placeholder-icon\" />\n <div className=\"at-placeholder-title\">终端</div>\n <div className=\"at-placeholder-desc\">功能待实现</div>\n <div className=\"at-placeholder-hint\">将支持引用终端输出、命令历史等</div>\n </div>\n )\n})\n\nAtTerminalsView.displayName = 'AtTerminalsView'\n","import { forwardRef, useImperativeHandle } from 'react'\nimport { Icon } from '@iconify/react'\nimport './AtViewStyles.css'\n\nexport interface AtPlaceholderViewProps {\n query: string\n activeIndex: number\n onSelect: (path: string) => void\n onSetActive: (index: number) => void\n onUpdateCount: (count: number) => void\n}\n\nexport interface AtPlaceholderViewHandle {\n getActivePath: () => string | null\n confirmActive: () => void\n}\n\nexport const AtChatsView = forwardRef<AtPlaceholderViewHandle, AtPlaceholderViewProps>((_, ref) => {\n useImperativeHandle(ref, () => ({\n getActivePath: () => null,\n confirmActive: () => {},\n }), [])\n\n return (\n <div className=\"at-placeholder-view\">\n <Icon icon=\"lucide:message-square\" width={32} className=\"at-placeholder-icon\" />\n <div className=\"at-placeholder-title\">历史对话</div>\n <div className=\"at-placeholder-desc\">功能待实现</div>\n <div className=\"at-placeholder-hint\">将支持引用之前的对话记录</div>\n </div>\n )\n})\n\nAtChatsView.displayName = 'AtChatsView'\n","import { forwardRef, useImperativeHandle } from 'react'\nimport { Icon } from '@iconify/react'\nimport './AtViewStyles.css'\n\nexport interface AtPlaceholderViewProps {\n query: string\n activeIndex: number\n onSelect: (path: string) => void\n onSetActive: (index: number) => void\n onUpdateCount: (count: number) => void\n}\n\nexport interface AtPlaceholderViewHandle {\n getActivePath: () => string | null\n confirmActive: () => void\n}\n\nexport const AtBranchView = forwardRef<AtPlaceholderViewHandle, AtPlaceholderViewProps>((_, ref) => {\n useImperativeHandle(ref, () => ({\n getActivePath: () => null,\n confirmActive: () => {},\n }), [])\n\n return (\n <div className=\"at-placeholder-view\">\n <Icon icon=\"lucide:git-branch\" width={32} className=\"at-placeholder-icon\" />\n <div className=\"at-placeholder-title\">分支差异</div>\n <div className=\"at-placeholder-desc\">功能待实现</div>\n <div className=\"at-placeholder-hint\">将支持引用当前分支与主分支的差异</div>\n </div>\n )\n})\n\nAtBranchView.displayName = 'AtBranchView'\n","import { forwardRef, useImperativeHandle } from 'react'\nimport { Icon } from '@iconify/react'\nimport './AtViewStyles.css'\n\nexport interface AtPlaceholderViewProps {\n query: string\n activeIndex: number\n onSelect: (path: string) => void\n onSetActive: (index: number) => void\n onUpdateCount: (count: number) => void\n}\n\nexport interface AtPlaceholderViewHandle {\n getActivePath: () => string | null\n confirmActive: () => void\n}\n\nexport const AtBrowserView = forwardRef<AtPlaceholderViewHandle, AtPlaceholderViewProps>((_, ref) => {\n useImperativeHandle(ref, () => ({\n getActivePath: () => null,\n confirmActive: () => {},\n }), [])\n\n return (\n <div className=\"at-placeholder-view\">\n <Icon icon=\"lucide:globe\" width={32} className=\"at-placeholder-icon\" />\n <div className=\"at-placeholder-title\">网页</div>\n <div className=\"at-placeholder-desc\">功能待实现</div>\n <div className=\"at-placeholder-hint\">将支持引用网页内容、URL 等</div>\n </div>\n )\n})\n\nAtBrowserView.displayName = 'AtBrowserView'\n","import { useCallback, useEffect, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport { Icon } from '@iconify/react'\nimport './ImagePreviewModal.css'\n\ninterface ImagePreviewModalProps {\n visible: boolean\n images: string[]\n initialIndex?: number\n onClose: () => void\n onIndexChange?: (index: number) => void\n}\n\nexport function ImagePreviewModal({\n visible,\n images,\n initialIndex = 0,\n onClose,\n onIndexChange,\n}: ImagePreviewModalProps) {\n const [currentIndex, setCurrentIndex] = useState(initialIndex)\n\n // 重置索引\n useEffect(() => {\n if (visible) {\n setCurrentIndex(initialIndex)\n }\n }, [visible, initialIndex])\n\n // 通知父组件索引变化\n useEffect(() => {\n onIndexChange?.(currentIndex)\n }, [currentIndex, onIndexChange])\n\n // 上一张\n const prev = useCallback(() => {\n if (currentIndex > 0) {\n setCurrentIndex(currentIndex - 1)\n }\n }, [currentIndex])\n\n // 下一张\n const next = useCallback(() => {\n if (currentIndex < images.length - 1) {\n setCurrentIndex(currentIndex + 1)\n }\n }, [currentIndex, images.length])\n\n // 键盘导航\n useEffect(() => {\n if (!visible) return\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose()\n } else if (e.key === 'ArrowLeft') {\n prev()\n } else if (e.key === 'ArrowRight') {\n next()\n }\n }\n document.addEventListener('keydown', handleKeyDown)\n return () => document.removeEventListener('keydown', handleKeyDown)\n }, [visible, onClose, prev, next])\n\n if (!visible) return null\n\n const currentSrc = images[currentIndex] || ''\n\n return createPortal(\n <div className=\"image-preview-modal\" onClick={onClose}>\n {/* 顶部栏 */}\n <div className=\"preview-header\" onClick={(e) => e.stopPropagation()}>\n {images.length > 1 && (\n <div className=\"preview-counter\">\n {currentIndex + 1} / {images.length}\n </div>\n )}\n <button className=\"preview-close-btn\" title=\"关闭 (Esc)\" onClick={onClose}>\n <Icon icon=\"lucide:x\" width={18} />\n </button>\n </div>\n\n {/* 左导航 */}\n {images.length > 1 && (\n <button\n className={`preview-nav-btn preview-nav-prev${currentIndex <= 0 ? ' disabled' : ''}`}\n disabled={currentIndex <= 0}\n onClick={(e) => {\n e.stopPropagation()\n prev()\n }}\n >\n <Icon icon=\"lucide:chevron-left\" width={20} />\n </button>\n )}\n\n {/* 主图片区域 */}\n <div className=\"preview-main\" onClick={(e) => e.stopPropagation()}>\n <img src={currentSrc} alt=\"预览\" className=\"preview-image\" />\n </div>\n\n {/* 右导航 */}\n {images.length > 1 && (\n <button\n className={`preview-nav-btn preview-nav-next${currentIndex >= images.length - 1 ? ' disabled' : ''}`}\n disabled={currentIndex >= images.length - 1}\n onClick={(e) => {\n e.stopPropagation()\n next()\n }}\n >\n <Icon icon=\"lucide:chevron-right\" width={20} />\n </button>\n )}\n </div>,\n document.body\n )\n}\n","/**\n * 图片上传 hook\n * 处理图片选择、粘贴、拖拽、预览等功能\n * 与 Vue 版本 useImageUpload.ts 保持一致\n */\n\nimport { useState, useCallback, useMemo } from 'react';\n\n/** 内部图片数据结构(包含预览用的 dataUrl) */\nexport interface ImageItem {\n dataUrl: string;\n base64: string;\n mimeType: string;\n}\n\n/** 导出给外部使用的图片数据格式 */\nexport interface ImageData {\n base64: string;\n mimeType: string;\n}\n\n/** useImageUpload 配置项 */\ninterface UseImageUploadOptions {\n /** 最大图片数量,默认 5 */\n maxImages?: number;\n /** 单张图片最大大小(字节),默认 10MB */\n maxSize?: number;\n /** 图片最大宽度,默认 4000px(避免超过 API 像素限制) */\n maxWidth?: number;\n /** 图片最大高度,默认 4000px(避免超过 API 像素限制) */\n maxHeight?: number;\n /** 压缩质量 0-1,默认 0.85 */\n quality?: number;\n}\n\n/**\n * 图片上传 hook\n * @param options 配置项\n */\nexport function useImageUpload(options: UseImageUploadOptions = {}) {\n const { \n maxImages = 5, \n maxSize = 10 * 1024 * 1024,\n maxWidth = 4000,\n maxHeight = 4000,\n quality = 0.85\n } = options;\n\n // 图片列表\n const [images, setImages] = useState<ImageItem[]>([]);\n\n // 拖拽状态\n const [isDragOver, setIsDragOver] = useState(false);\n\n // 预览状态\n const [previewVisible, setPreviewVisible] = useState(false);\n const [previewIndex, setPreviewIndex] = useState(0);\n\n // 图片 URL 数组(用于预览组件)\n const imageUrls = useMemo(() => images.map((img) => img.dataUrl), [images]);\n\n // 导出格式的图片数据\n const imageData = useMemo<ImageData[]>(\n () =>\n images.map((img) => ({\n base64: img.base64,\n mimeType: img.mimeType,\n })),\n [images]\n );\n\n // 是否有图片\n const hasImages = images.length > 0;\n\n /**\n * 压缩图片到指定尺寸\n * @param file 原始图片文件\n * @returns 压缩后的 ImageItem\n */\n const compressImage = useCallback((file: File): Promise<ImageItem> => {\n return new Promise((resolve, reject) => {\n // 使用 FileReader 读取文件为 data URL(避免 CSP 对 blob URL 的限制)\n const reader = new FileReader();\n \n reader.onload = () => {\n const dataUrl = reader.result as string;\n const img = new Image();\n \n img.onload = () => {\n let { width, height } = img;\n \n // 计算缩放比例\n if (width > maxWidth || height > maxHeight) {\n const ratio = Math.min(maxWidth / width, maxHeight / height);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n \n // 创建 canvas 进行压缩\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n \n const ctx = canvas.getContext('2d');\n if (!ctx) {\n reject(new Error('无法创建 canvas context'));\n return;\n }\n \n ctx.drawImage(img, 0, 0, width, height);\n \n // 转换为 dataUrl(JPEG 格式以减小体积)\n const mimeType = file.type === 'image/png' ? 'image/png' : 'image/jpeg';\n const compressedDataUrl = canvas.toDataURL(mimeType, quality);\n const base64 = compressedDataUrl.split(',')[1];\n \n resolve({\n dataUrl: compressedDataUrl,\n base64,\n mimeType,\n });\n };\n \n img.onerror = () => {\n reject(new Error('图片加载失败'));\n };\n \n img.src = dataUrl;\n };\n \n reader.onerror = () => {\n reject(new Error('读取文件失败'));\n };\n \n reader.readAsDataURL(file);\n });\n }, [maxWidth, maxHeight, quality]);\n\n /**\n * 读取图片文件为 base64(带压缩)\n */\n const readImageFile = useCallback((file: File): Promise<ImageItem> => {\n return compressImage(file);\n }, [compressImage]);\n\n /**\n * 处理文件列表\n */\n const processFiles = useCallback(\n async (files: File[]) => {\n const remaining = maxImages - images.length;\n const toProcess = files.slice(0, remaining);\n\n const newImages: ImageItem[] = [];\n for (const file of toProcess) {\n if (file.size > maxSize) {\n console.warn(`图片 ${file.name} 超过大小限制 (${Math.round(maxSize / 1024 / 1024)}MB)`);\n continue;\n }\n try {\n const imageItem = await readImageFile(file);\n newImages.push(imageItem);\n } catch (err) {\n console.error('读取图片失败:', err);\n }\n }\n\n if (newImages.length > 0) {\n setImages((prev) => [...prev, ...newImages]);\n }\n },\n [images.length, maxImages, maxSize, readImageFile]\n );\n\n /**\n * 处理文件选择事件\n */\n const handleImageSelect = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n const files = event.target.files;\n if (files) {\n processFiles(Array.from(files));\n }\n // 清空 input 以便再次选择相同文件\n event.target.value = '';\n },\n [processFiles]\n );\n\n /**\n * 处理粘贴事件\n */\n const handlePaste = useCallback(\n (event: React.ClipboardEvent) => {\n const items = event.clipboardData?.items;\n if (!items) return;\n\n const imageFiles: File[] = [];\n for (const item of Array.from(items)) {\n if (item.type.startsWith('image/')) {\n const file = item.getAsFile();\n if (file) imageFiles.push(file);\n }\n }\n\n if (imageFiles.length > 0) {\n event.preventDefault();\n processFiles(imageFiles);\n }\n },\n [processFiles]\n );\n\n /**\n * 处理拖拽悬停事件\n */\n const handleDragOver = useCallback((event: React.DragEvent) => {\n event.preventDefault();\n if (event.dataTransfer?.types.includes('Files')) {\n setIsDragOver(true);\n }\n }, []);\n\n /**\n * 处理拖拽离开事件\n */\n const handleDragLeave = useCallback(() => {\n setIsDragOver(false);\n }, []);\n\n /**\n * 处理拖拽放下事件\n */\n const handleDrop = useCallback(\n (event: React.DragEvent) => {\n event.preventDefault();\n setIsDragOver(false);\n const files = event.dataTransfer?.files;\n if (files) {\n const imageFiles = Array.from(files).filter((f) => f.type.startsWith('image/'));\n processFiles(imageFiles);\n }\n },\n [processFiles]\n );\n\n /**\n * 打开图片预览\n */\n const openPreview = useCallback((index: number) => {\n setPreviewIndex(index);\n setPreviewVisible(true);\n }, []);\n\n /**\n * 关闭图片预览\n */\n const closePreview = useCallback(() => {\n setPreviewVisible(false);\n }, []);\n\n /**\n * 移除指定索引的图片\n */\n const removeImage = useCallback((index: number) => {\n setImages((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n /**\n * 清空所有图片\n */\n const clearImages = useCallback(() => {\n setImages([]);\n }, []);\n\n /**\n * 添加图片文件\n */\n const addImages = useCallback(\n (files: File[]) => {\n processFiles(files);\n },\n [processFiles]\n );\n\n /**\n * 从 data URL 字符串数组初始化图片(用于历史消息编辑)\n * @param data data URL 字符串数组\n */\n const initImages = useCallback((data: string[]) => {\n const items: ImageItem[] = [];\n for (const item of data) {\n if (item.startsWith('data:')) {\n // data URL 格式: data:image/png;base64,xxxxx\n const matches = item.match(/^data:([^;]+);base64,(.+)$/);\n if (matches) {\n items.push({\n dataUrl: item,\n base64: matches[2],\n mimeType: matches[1],\n });\n }\n } else {\n // 普通 URL,只能作为预览显示\n items.push({\n dataUrl: item,\n base64: '',\n mimeType: 'image/unknown',\n });\n }\n }\n setImages(items);\n }, []);\n\n return {\n // 状态\n images,\n isDragOver,\n previewVisible,\n previewIndex,\n setPreviewIndex,\n\n // 计算属性\n imageUrls,\n imageData,\n hasImages,\n\n // 事件处理\n handleImageSelect,\n handlePaste,\n handleDragOver,\n handleDragLeave,\n handleDrop,\n\n // 预览控制\n openPreview,\n closePreview,\n\n // 图片操作\n removeImage,\n clearImages,\n addImages,\n initImages,\n };\n}\n","/**\n * 将语音识别(useVoiceInput)封装成“写入输入框”的高内聚控制层\n * - 处理 prefix(追加模式)\n * - 处理实时同步到 inputText\n * - 处理 Enter:语音中 Enter 停止/取消语音(不发送)\n * - 输出按钮状态/禁用逻辑(ChatInput 只负责渲染)\n */\n\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\nimport type { ChatAdapter } from '@huyooo/ai-chat-bridge-electron/renderer';\nimport { useVoiceInput } from './useVoiceInput';\n\nexport function useVoiceToTextInput(opts: {\n adapter: ChatAdapter | undefined;\n inputText: string;\n setInputText: (v: string) => void;\n hasImages: boolean;\n isLoading: boolean;\n}) {\n const { adapter, inputText, setInputText, hasImages, isLoading } = opts;\n const voiceInput = useVoiceInput(adapter);\n const prefixRef = useRef('');\n\n const isVoiceActive = useMemo(\n () => voiceInput.status === 'connecting' || voiceInput.status === 'recording',\n [voiceInput.status]\n );\n\n // 实时同步语音识别文本到输入框(追加模式)\n useEffect(() => {\n if (!isVoiceActive) return;\n const prefix = prefixRef.current;\n const t = voiceInput.currentText;\n const next = prefix ? (t ? `${prefix} ${t}` : prefix) : t;\n setInputText(next);\n }, [isVoiceActive, setInputText, voiceInput.currentText]);\n\n const toggleVoice = useCallback(async () => {\n if (isLoading) return;\n if (!adapter) return;\n\n if (voiceInput.status === 'connecting') {\n voiceInput.cancel();\n setInputText(prefixRef.current);\n prefixRef.current = '';\n return;\n }\n\n if (voiceInput.status === 'recording') {\n await voiceInput.stop();\n prefixRef.current = '';\n return;\n }\n\n prefixRef.current = inputText.trim();\n await voiceInput.start();\n }, [adapter, inputText, isLoading, setInputText, voiceInput]);\n\n const sendDisabled = useMemo(() => {\n if (isLoading) return false; // 允许停止生成\n if (isVoiceActive) return true;\n return !inputText.trim() && !hasImages;\n }, [hasImages, inputText, isLoading, isVoiceActive]);\n\n const handleKeyDownForVoice = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (!isVoiceActive) return false;\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n toggleVoice().catch(() => {});\n return true;\n }\n return false;\n },\n [isVoiceActive, toggleVoice]\n );\n\n return {\n voiceInput,\n isVoiceActive,\n toggleVoice,\n sendDisabled,\n handleKeyDownForVoice,\n };\n}\n\n\n","/**\n * 语音输入 hook(React)\n *\n * 浏览器录音 + Electron bridge ASR(WebSocket)实时转写。\n * 与 Vue 版本 useVoiceInput.ts 逻辑保持一致,但使用 React state。\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ChatAdapter, AsrResultData } from '@huyooo/ai-chat-bridge-electron/renderer';\n\nexport type VoiceInputStatus = 'idle' | 'connecting' | 'recording' | 'processing' | 'error';\n\nexport interface VoiceInputConfig {\n sampleRate?: number;\n sendInterval?: number;\n enablePunc?: boolean;\n enableItn?: boolean;\n}\n\nexport interface UseVoiceInputReturn {\n status: VoiceInputStatus;\n isRecording: boolean;\n currentText: string;\n finalText: string;\n error: string | null;\n start: () => Promise<void>;\n stop: () => Promise<string>;\n cancel: () => void;\n}\n\nfunction float32ToInt16(float32Array: Float32Array): Int16Array {\n const int16Array = new Int16Array(float32Array.length);\n for (let i = 0; i < float32Array.length; i++) {\n const s = Math.max(-1, Math.min(1, float32Array[i]));\n int16Array[i] = s < 0 ? s * 0x8000 : s * 0x7fff;\n }\n return int16Array;\n}\n\nfunction resample(audioData: Float32Array, fromSampleRate: number, toSampleRate: number): Float32Array {\n if (fromSampleRate === toSampleRate) return audioData;\n\n const ratio = fromSampleRate / toSampleRate;\n const newLength = Math.round(audioData.length / ratio);\n const result = new Float32Array(newLength);\n\n for (let i = 0; i < newLength; i++) {\n const srcIndex = i * ratio;\n const srcIndexFloor = Math.floor(srcIndex);\n const srcIndexCeil = Math.min(srcIndexFloor + 1, audioData.length - 1);\n const t = srcIndex - srcIndexFloor;\n result[i] = audioData[srcIndexFloor] * (1 - t) + audioData[srcIndexCeil] * t;\n }\n\n return result;\n}\n\n// 全局预热标志:确保只预热一次(避免多个组件实例重复预热)\nlet asrWarmupDone = false;\n\nasync function setupAudioWorkletCapture(opts: {\n audioContext: AudioContext;\n source: MediaStreamAudioSourceNode;\n chunkSize: number;\n onChunk: (chunk: Float32Array) => void;\n}): Promise<{\n cleanup: () => void;\n}> {\n const { audioContext, source, chunkSize, onChunk } = opts;\n\n const workletCode = `\nclass PcmCaptureProcessor extends AudioWorkletProcessor {\n constructor(options) {\n super();\n const size = (options && options.processorOptions && options.processorOptions.chunkSize) || 4096;\n this._chunkSize = size;\n this._buf = new Float32Array(size);\n this._offset = 0;\n }\n process(inputs, outputs) {\n const input = inputs && inputs[0] && inputs[0][0];\n const output = outputs && outputs[0] && outputs[0][0];\n if (!input) return true;\n if (output) output.set(input);\n\n let i = 0;\n while (i < input.length) {\n const remain = this._chunkSize - this._offset;\n const take = Math.min(remain, input.length - i);\n this._buf.set(input.subarray(i, i + take), this._offset);\n this._offset += take;\n i += take;\n if (this._offset >= this._chunkSize) {\n const out = this._buf;\n this.port.postMessage(out, [out.buffer]);\n this._buf = new Float32Array(this._chunkSize);\n this._offset = 0;\n }\n }\n return true;\n }\n}\nregisterProcessor('pcm-capture', PcmCaptureProcessor);\n`;\n\n const blob = new Blob([workletCode], { type: 'text/javascript' });\n const url = URL.createObjectURL(blob);\n await audioContext.audioWorklet.addModule(url);\n URL.revokeObjectURL(url);\n\n const workletNode = new AudioWorkletNode(audioContext, 'pcm-capture', {\n numberOfInputs: 1,\n numberOfOutputs: 1,\n channelCount: 1,\n processorOptions: { chunkSize },\n });\n\n const silentGain = audioContext.createGain();\n silentGain.gain.value = 0;\n\n const onMessage = (event: MessageEvent) => {\n const data = event.data;\n if (data instanceof Float32Array) {\n onChunk(data);\n return;\n }\n if (data instanceof ArrayBuffer) {\n onChunk(new Float32Array(data));\n }\n };\n workletNode.port.addEventListener('message', onMessage);\n workletNode.port.start();\n\n source.connect(workletNode);\n workletNode.connect(silentGain);\n silentGain.connect(audioContext.destination);\n\n return {\n cleanup: () => {\n try {\n workletNode.port.removeEventListener('message', onMessage);\n } catch {\n // ignore\n }\n try {\n workletNode.disconnect();\n } catch {\n // ignore\n }\n try {\n silentGain.disconnect();\n } catch {\n // ignore\n }\n },\n };\n}\n\nexport function useVoiceInput(adapter: ChatAdapter | undefined, config: VoiceInputConfig = {}): UseVoiceInputReturn {\n const { sampleRate = 16000, sendInterval = 200, enablePunc = true, enableItn = true } = config;\n\n // 自动预热 ASR 连接(仅首次调用,延迟执行,避免阻塞初始化)\n useEffect(() => {\n if (adapter && !asrWarmupDone && typeof adapter.asrWarmup === 'function') {\n asrWarmupDone = true;\n // 延迟 800ms 预热,避免与首屏渲染竞争资源\n const timer = setTimeout(() => {\n adapter.asrWarmup?.().catch(() => {\n // 静默失败,不影响功能\n });\n }, 800);\n return () => clearTimeout(timer);\n }\n }, [adapter]);\n\n const [status, setStatus] = useState<VoiceInputStatus>('idle');\n const [currentText, setCurrentText] = useState('');\n const [finalText, setFinalText] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n const statusRef = useRef<VoiceInputStatus>('idle');\n const currentTextRef = useRef('');\n const finalTextRef = useRef('');\n\n const mediaStreamRef = useRef<MediaStream | null>(null);\n const audioContextRef = useRef<AudioContext | null>(null);\n const workletCleanupRef = useRef<(() => void) | null>(null);\n const sourceRef = useRef<MediaStreamAudioSourceNode | null>(null);\n const audioBufferRef = useRef<Float32Array[]>([]);\n const sendTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const cleanupFnsRef = useRef<Array<() => void>>([]);\n\n // UI 维度的“正在录音”:包含连接中的瞬间(避免用户误以为没点到)\n const isRecording = useMemo(() => status === 'connecting' || status === 'recording', [status]);\n\n // 同步到 refs,避免音频回调/计时器读取到旧闭包\n useEffect(() => {\n statusRef.current = status;\n }, [status]);\n useEffect(() => {\n currentTextRef.current = currentText;\n }, [currentText]);\n useEffect(() => {\n finalTextRef.current = finalText;\n }, [finalText]);\n\n const setStatusSafe = useCallback((next: VoiceInputStatus) => {\n statusRef.current = next;\n setStatus(next);\n }, []);\n\n const cleanup = useCallback(() => {\n if (sendTimerRef.current) {\n clearInterval(sendTimerRef.current);\n sendTimerRef.current = null;\n }\n\n if (workletCleanupRef.current) {\n workletCleanupRef.current();\n workletCleanupRef.current = null;\n }\n\n if (sourceRef.current) {\n try {\n sourceRef.current.disconnect();\n } catch {\n // ignore\n }\n sourceRef.current = null;\n }\n\n if (audioContextRef.current) {\n audioContextRef.current.close().catch(() => {});\n audioContextRef.current = null;\n }\n\n if (mediaStreamRef.current) {\n mediaStreamRef.current.getTracks().forEach((t) => t.stop());\n mediaStreamRef.current = null;\n }\n\n cleanupFnsRef.current.forEach((fn) => fn());\n cleanupFnsRef.current = [];\n\n audioBufferRef.current = [];\n }, []);\n\n const sendAudioChunk = useCallback(async () => {\n if (!adapter?.asrSendAudio) return;\n const buf = audioBufferRef.current;\n if (!buf.length) return;\n\n const totalLength = buf.reduce((sum, arr) => sum + arr.length, 0);\n const merged = new Float32Array(totalLength);\n let offset = 0;\n for (const chunk of buf) {\n merged.set(chunk, offset);\n offset += chunk.length;\n }\n audioBufferRef.current = [];\n\n const pcmData = float32ToInt16(merged);\n const result = await adapter.asrSendAudio(pcmData.buffer);\n if (!result.success) {\n // 不中断录音,只记录错误\n // eslint-disable-next-line no-console\n console.error('[VoiceInput] 发送音频失败:', result.error);\n }\n }, [adapter]);\n\n const start = useCallback(async () => {\n // 防抖:连接中/录音中不重复 start(避免多次点击造成状态错乱)\n if (statusRef.current === 'connecting' || statusRef.current === 'recording') return;\n\n if (!adapter) {\n setError('Adapter 未初始化');\n setStatusSafe('error');\n return;\n }\n if (!adapter.asrStart) {\n setError('语音识别功能不可用');\n setStatusSafe('error');\n return;\n }\n\n setError(null);\n setCurrentText('');\n setFinalText('');\n setStatusSafe('connecting');\n\n try {\n mediaStreamRef.current = await navigator.mediaDevices.getUserMedia({\n audio: {\n channelCount: 1,\n sampleRate: { ideal: sampleRate },\n echoCancellation: true,\n noiseSuppression: true,\n },\n });\n\n audioContextRef.current = new AudioContext({ sampleRate });\n const actualSampleRate = audioContextRef.current.sampleRate;\n\n if (adapter.onAsrResult) {\n const off = adapter.onAsrResult((data: { result: AsrResultData; isLast: boolean }) => {\n const text = data.result.result?.text || '';\n setCurrentText(text);\n if (data.isLast) setFinalText(text);\n });\n cleanupFnsRef.current.push(off);\n }\n\n if (adapter.onAsrError) {\n const off = adapter.onAsrError((err: { message: string }) => {\n // eslint-disable-next-line no-console\n console.error('[VoiceInput] ASR 错误:', err.message);\n setError(err.message);\n setStatusSafe('error');\n });\n cleanupFnsRef.current.push(off);\n }\n\n if (adapter.onAsrClosed) {\n const off = adapter.onAsrClosed(() => {\n if (statusRef.current === 'recording') {\n setStatusSafe('idle');\n }\n });\n cleanupFnsRef.current.push(off);\n }\n\n const ctx = audioContextRef.current;\n const stream = mediaStreamRef.current;\n if (!ctx || !stream) throw new Error('AudioContext 或 MediaStream 初始化失败');\n\n const startResult = await adapter.asrStart({\n format: 'pcm',\n sampleRate,\n enablePunc,\n enableItn,\n showUtterances: true,\n });\n\n if (!startResult.success) {\n throw new Error(startResult.error || 'ASR 启动失败');\n }\n\n // 连接成功后再开始接收语音(降低复杂度)\n sourceRef.current = ctx.createMediaStreamSource(stream);\n if (typeof AudioWorkletNode === 'undefined' || !ctx.audioWorklet) {\n throw new Error('当前环境不支持 AudioWorkletNode(无法启动语音录制)');\n }\n const { cleanup: off } = await setupAudioWorkletCapture({\n audioContext: ctx,\n source: sourceRef.current,\n chunkSize: 4096,\n onChunk: (chunk) => {\n if (statusRef.current !== 'recording') return;\n const resampled = resample(chunk, actualSampleRate, sampleRate);\n audioBufferRef.current.push(new Float32Array(resampled));\n },\n });\n workletCleanupRef.current = off;\n\n sendTimerRef.current = setInterval(() => {\n sendAudioChunk().catch(() => {});\n }, sendInterval);\n\n setStatusSafe('recording');\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n setError(msg);\n setStatusSafe('error');\n cleanup();\n }\n }, [adapter, cleanup, enableItn, enablePunc, sampleRate, sendAudioChunk, sendInterval, setStatusSafe]);\n\n const stop = useCallback(async (): Promise<string> => {\n // 连接中点击停止:按“取消”处理,保证状态立刻回到 idle\n if (statusRef.current === 'connecting') {\n if (adapter?.asrStop) {\n adapter.asrStop().catch(() => {});\n }\n cleanup();\n setCurrentText('');\n setFinalText('');\n setError(null);\n setStatusSafe('idle');\n return '';\n }\n if (statusRef.current !== 'recording') return finalTextRef.current || currentTextRef.current;\n\n setStatusSafe('processing');\n\n try {\n await sendAudioChunk();\n if (adapter?.asrFinish) {\n await adapter.asrFinish();\n }\n\n // 等待最终结果(最多 3s)\n await new Promise<void>((resolve) => {\n const startAt = Date.now();\n const timer = setInterval(() => {\n if (Date.now() - startAt > 3000) {\n clearInterval(timer);\n resolve();\n return;\n }\n if (finalTextRef.current) {\n clearInterval(timer);\n resolve();\n }\n }, 100);\n });\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n setError(msg);\n } finally {\n cleanup();\n setStatusSafe('idle');\n }\n\n return finalTextRef.current || currentTextRef.current;\n }, [adapter, cleanup, sendAudioChunk, setStatusSafe]);\n\n const cancel = useCallback(() => {\n if (adapter?.asrStop) {\n adapter.asrStop().catch(() => {});\n }\n cleanup();\n setCurrentText('');\n setFinalText('');\n setError(null);\n setStatusSafe('idle');\n }, [adapter, cleanup, setStatusSafe]);\n\n useEffect(() => {\n return () => cancel();\n }, [cancel]);\n\n return {\n status,\n isRecording,\n currentText,\n finalText,\n error,\n start,\n stop,\n cancel,\n };\n}\n\n\n","/**\n * ConfirmDialog Component\n * 自定义确认弹窗组件\n */\n\nimport { type FC, useEffect } from 'react'\nimport { createPortal } from 'react-dom'\nimport { Icon } from '@iconify/react'\nimport './ConfirmDialog.css'\n\ninterface ConfirmDialogProps {\n /** 是否显示 */\n visible: boolean\n /** 标题 */\n title?: string\n /** 消息内容 */\n message: string\n /** 类型:info | warning | danger */\n type?: 'info' | 'warning' | 'danger'\n /** 确认按钮文字 */\n confirmText?: string\n /** 取消按钮文字 */\n cancelText?: string\n /** 确认回调 */\n onConfirm?: () => void\n /** 取消回调 */\n onCancel?: () => void\n}\n\nexport const ConfirmDialog: FC<ConfirmDialogProps> = ({\n visible,\n title = '确认',\n message,\n type = 'warning',\n confirmText = '确定',\n cancelText = '取消',\n onConfirm,\n onCancel,\n}) => {\n // ESC 键关闭\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && visible) {\n onCancel?.()\n }\n }\n document.addEventListener('keydown', handleKeyDown)\n return () => document.removeEventListener('keydown', handleKeyDown)\n }, [visible, onCancel])\n\n // 阻止滚动\n useEffect(() => {\n if (visible) {\n document.body.style.overflow = 'hidden'\n } else {\n document.body.style.overflow = ''\n }\n return () => {\n document.body.style.overflow = ''\n }\n }, [visible])\n\n if (!visible) return null\n\n const iconMap = {\n info: 'lucide:info',\n warning: 'lucide:alert-triangle',\n danger: 'lucide:alert-circle',\n }\n\n return createPortal(\n <div className=\"confirm-dialog-overlay\" onClick={onCancel}>\n <div className=\"confirm-dialog\" onClick={(e) => e.stopPropagation()}>\n <div className=\"confirm-dialog-header\">\n <Icon icon={iconMap[type]} className={`icon ${type}`} width={18} />\n <span className=\"title\">{title}</span>\n </div>\n <div className=\"confirm-dialog-content\">{message}</div>\n <div className=\"confirm-dialog-footer\">\n <button className=\"btn btn-cancel\" onClick={onCancel}>\n {cancelText}\n </button>\n <button className={`btn btn-${type}`} onClick={onConfirm}>\n {confirmText}\n </button>\n </div>\n </div>\n </div>,\n document.body\n )\n}\n","import { FC, useEffect } from 'react'\nimport { createPortal } from 'react-dom'\nimport './Toast.css'\n\ninterface ToastProps {\n visible: boolean\n message: string\n type?: 'info' | 'success' | 'warning' | 'error'\n duration?: number\n onClose: () => void\n}\n\nexport const Toast: FC<ToastProps> = ({\n visible,\n message,\n type = 'info',\n duration = 2000,\n onClose,\n}) => {\n // 自动关闭\n useEffect(() => {\n if (visible && duration > 0) {\n const timer = setTimeout(() => {\n onClose()\n }, duration)\n return () => clearTimeout(timer)\n }\n }, [visible, duration, onClose])\n\n if (!visible) return null\n\n return createPortal(\n <div className=\"toast-container\">\n <div className={`toast toast-${type}`}>{message}</div>\n </div>,\n document.body\n )\n}\n","/**\n * 设置面板组件\n * 用于配置 AutoRunConfig\n */\n\nimport { useState, useCallback, useMemo } from 'react'\nimport { Icon } from '@iconify/react'\nimport type { AutoRunConfig, AutoRunMode } from '@huyooo/ai-chat-bridge-electron/renderer'\nimport { DropdownSelector, type DropdownOption } from '../input/DropdownSelector'\nimport { ToggleSwitch } from './ToggleSwitch'\nimport { IndexingSettings } from './IndexingSettings'\nimport './SettingsPanel.css'\n\ninterface SettingsPanelProps {\n visible: boolean\n config: AutoRunConfig\n /** 所有可用工具列表(用于工具管理) */\n allTools?: Array<{ name: string; description: string }>\n /** 启用的工具名称列表(undefined 表示全部启用) */\n enabledTools?: string[] | undefined\n /** 更新工具开关(持久化由上层处理) */\n onUpdateEnabledTools?: (tools: string[] | undefined) => void\n onClose: () => void\n onChange: (config: AutoRunConfig) => void\n}\n\nconst sections = [\n { id: 'agent', label: 'Agent', icon: 'solar:link-round-angle-line-duotone' },\n { id: 'indexing', label: '索引与文档', icon: 'lucide:database' },\n] as const\n\nexport function SettingsPanel({ visible, config, allTools, enabledTools, onUpdateEnabledTools, onClose, onChange }: SettingsPanelProps) {\n const [currentSection, setCurrentSection] = useState<string>('agent')\n\n const currentSectionLabel = useMemo(\n () => sections.find(s => s.id === currentSection)?.label ?? '',\n [currentSection]\n )\n\n // 模式选项\n const modeOptions: DropdownOption[] = [\n { value: 'run-everything', label: '运行所有内容(自动执行)' },\n { value: 'manual', label: '手动批准(每次执行前询问)' },\n ]\n\n /** 更新配置项 */\n const updateConfig = useCallback(<K extends keyof AutoRunConfig>(key: K, value: AutoRunConfig[K]) => {\n onChange({ ...config, [key]: value })\n }, [config, onChange])\n\n /** 处理模式变化 */\n const handleModeChange = useCallback((value: string) => {\n updateConfig('mode', value as AutoRunMode)\n }, [updateConfig])\n\n /** 处理遮罩点击 */\n const handleOverlayClick = useCallback((e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose()\n }\n }, [onClose])\n\n const allToolNames = useMemo(() => (allTools ?? []).map((t) => t.name), [allTools])\n\n /** 判断工具是否启用 */\n const isToolEnabled = useCallback((toolName: string): boolean => {\n // undefined 表示全部启用\n if (enabledTools === undefined) return true\n return enabledTools.includes(toolName)\n }, [enabledTools])\n\n /** 处理工具开关切换 */\n const handleToolToggle = useCallback((toolName: string, checked: boolean) => {\n if (!onUpdateEnabledTools) return\n\n // undefined = 全部启用\n if (enabledTools === undefined) {\n if (checked) return\n onUpdateEnabledTools(allToolNames.filter((n) => n !== toolName))\n return\n }\n\n const set = new Set(enabledTools)\n if (checked) set.add(toolName)\n else set.delete(toolName)\n\n // 如果全部启用,回到 undefined(更符合默认语义)\n if (allToolNames.length > 0 && set.size === allToolNames.length) {\n onUpdateEnabledTools(undefined)\n return\n }\n\n onUpdateEnabledTools(Array.from(set))\n }, [enabledTools, allToolNames, onUpdateEnabledTools])\n\n /** 一键禁用所有工具 */\n const handleDisableAllTools = useCallback(() => {\n onUpdateEnabledTools?.([])\n }, [onUpdateEnabledTools])\n\n const isAllToolsDisabled = useMemo(\n () => enabledTools !== undefined && enabledTools.length === 0,\n [enabledTools]\n )\n\n const handleEnableAllTools = useCallback(() => {\n // 恢复默认:undefined 表示全部启用\n onUpdateEnabledTools?.(undefined)\n }, [onUpdateEnabledTools])\n\n if (!visible) return null\n\n return (\n <div className=\"settings-panel-overlay\" onClick={handleOverlayClick}>\n <div className=\"settings-panel\">\n {/* 左侧导航 */}\n <div className=\"settings-sidebar\">\n <div className=\"sidebar-header\">\n <h3 className=\"sidebar-title\">设置</h3>\n </div>\n <div className=\"sidebar-content\">\n {sections.map((section) => (\n <button\n key={section.id}\n className={`sidebar-item${currentSection === section.id ? ' active' : ''}`}\n onClick={() => setCurrentSection(section.id)}\n >\n <Icon icon={section.icon} width={18} />\n <span>{section.label}</span>\n </button>\n ))}\n </div>\n </div>\n\n {/* 右侧内容 */}\n <div className=\"settings-content\">\n <div className=\"content-header\">\n <h2 className=\"content-title\">{currentSectionLabel}</h2>\n <button className=\"close-btn\" onClick={onClose}>\n <Icon icon=\"lucide:x\" width={20} />\n </button>\n </div>\n <div className=\"content-body\">\n {/* Agent 设置 */}\n {currentSection === 'agent' && (\n <>\n {/* 自动运行模式 */}\n <div className=\"setting-item\">\n <div className=\"setting-info\">\n <div className=\"setting-label\">自动运行模式</div>\n <div className=\"setting-description\">控制工具执行的自动运行行为</div>\n </div>\n <div className=\"setting-control\">\n <DropdownSelector\n value={config.mode ?? 'run-everything'}\n options={modeOptions}\n align=\"right\"\n onSelect={handleModeChange}\n />\n </div>\n </div>\n\n {/* 工具管理 */}\n <div className=\"setting-section\">\n <div className=\"setting-section-header\">\n <div className=\"setting-info\">\n <div className=\"setting-label\">工具管理</div>\n <div className=\"setting-description\">控制哪些工具可以被 AI 使用</div>\n </div>\n <button\n className=\"disable-all-btn\"\n onClick={isAllToolsDisabled ? handleEnableAllTools : handleDisableAllTools}\n disabled={!allTools?.length}\n >\n {isAllToolsDisabled ? '启用所有工具' : '禁用所有工具'}\n </button>\n </div>\n\n <div className=\"tools-list\">\n {allTools && allTools.length > 0 ? (\n allTools.map((tool) => (\n <div key={tool.name} className=\"tool-item\">\n <div className=\"tool-info\">\n <div className=\"tool-name\">{tool.name}</div>\n <div className=\"tool-description\">{tool.description}</div>\n </div>\n <ToggleSwitch\n checked={isToolEnabled(tool.name)}\n onChange={(checked) => handleToolToggle(tool.name, checked)}\n />\n </div>\n ))\n ) : (\n <div className=\"no-tools\">\n <div>暂无可用工具</div>\n <div className=\"no-tools-hint\">\n 工具需要在创建 Electron Bridge 时通过 <code>tools</code> 参数注入\n </div>\n </div>\n )}\n </div>\n </div>\n </>\n )}\n\n {/* 索引与文档设置 */}\n {currentSection === 'indexing' && (\n <IndexingSettings />\n )}\n </div>\n </div>\n </div>\n </div>\n )\n}\n","import type { FC } from 'react'\nimport './ToggleSwitch.css'\n\ninterface ToggleSwitchProps {\n checked?: boolean\n onChange: (value: boolean) => void\n}\n\nexport const ToggleSwitch: FC<ToggleSwitchProps> = ({ checked = false, onChange }) => {\n return (\n <label className=\"toggle-switch\">\n <input\n type=\"checkbox\"\n checked={checked}\n onChange={(e) => onChange(e.target.checked)}\n />\n <span className=\"toggle-slider\"></span>\n </label>\n )\n}\n","import { useState, useEffect, useCallback, useRef } from 'react'\nimport { Icon } from '@iconify/react'\nimport { ConfirmDialog } from './ConfirmDialog'\nimport './IndexingSettings.css'\n\nexport function IndexingSettings() {\n // 索引状态\n const [indexedFiles, setIndexedFiles] = useState(0)\n const [isIndexing, setIsIndexing] = useState(false)\n const [currentFile, setCurrentFile] = useState<string | null>(null)\n const [progressPercentage, setProgressPercentage] = useState(100)\n const [progressIndexed, setProgressIndexed] = useState(0)\n const [progressTotal, setProgressTotal] = useState(0)\n const [currentStage, setCurrentStage] = useState<'scanning' | 'parsing' | 'embedding' | 'storing' | 'done' | null>(null)\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)\n const [indexSize, setIndexSize] = useState('0 B')\n const [lastUpdated, setLastUpdated] = useState<string | null>(null)\n const cancelIndexingRef = useRef(false)\n\n /** 格式化文件大小 */\n const formatSize = useCallback((bytes: number): string => {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`\n }, [])\n\n /** 格式化日期 */\n const formatDate = useCallback((date: Date): string => {\n const now = new Date()\n const diff = now.getTime() - date.getTime()\n const days = Math.floor(diff / (1000 * 60 * 60 * 24))\n \n if (days === 0) {\n const hours = Math.floor(diff / (1000 * 60 * 60))\n if (hours === 0) {\n const minutes = Math.floor(diff / (1000 * 60))\n return minutes <= 1 ? '刚刚' : `${minutes} 分钟前`\n }\n return `${hours} 小时前`\n }\n \n if (days === 1) return '昨天'\n if (days < 7) return `${days} 天前`\n if (days < 30) return `${Math.floor(days / 7)} 周前`\n if (days < 365) return `${Math.floor(days / 30)} 个月前`\n return date.toLocaleDateString('zh-CN', { year: 'numeric', month: 'short', day: 'numeric' })\n }, [])\n\n /** 获取索引统计信息 */\n const fetchIndexStats = useCallback(async () => {\n try {\n const bridge = (window as any).aiChatBridge\n if (bridge?.getIndexStats) {\n const stats = await bridge.getIndexStats()\n setIndexedFiles(stats.totalDocuments || 0)\n setIndexSize(formatSize(stats.indexSize || 0))\n setLastUpdated(stats.lastUpdated ? formatDate(new Date(stats.lastUpdated)) : null)\n } else {\n // Bridge 方法未实现,显示默认值\n setIndexedFiles(0)\n setIndexSize('0 B')\n setLastUpdated(null)\n console.warn('getIndexStats 方法未在 bridge 中实现')\n }\n } catch (error) {\n console.error('获取索引统计失败:', error)\n // 出错时显示默认值\n setIndexedFiles(0)\n setIndexSize('0 B')\n setLastUpdated(null)\n }\n }, [formatSize, formatDate])\n\n\n // 进度监听器清理函数引用\n const progressCleanupRef = useRef<(() => void) | null>(null)\n\n /** 设置进度监听器 */\n const setupProgressListener = useCallback(() => {\n // 如果已有监听器,先清理\n if (progressCleanupRef.current) {\n progressCleanupRef.current()\n progressCleanupRef.current = null\n }\n \n const bridge = (window as any).aiChatBridge\n if (!bridge?.onIndexProgress) {\n return\n }\n \n // 订阅进度更新(始终监听,即使没有主动触发索引)\n progressCleanupRef.current = bridge.onIndexProgress((progress: {\n indexed: number\n total: number\n currentFile?: string\n stage: string\n error?: string\n }) => {\n if (progress.error) {\n console.error('索引错误:', progress.error)\n setIsIndexing(false)\n setCurrentFile(null)\n return\n }\n \n if (progress.stage === 'cancelled') {\n setIsIndexing(false)\n setCurrentStage(null)\n setCurrentFile(null)\n cancelIndexingRef.current = true\n return\n }\n \n // 如果收到进度更新,说明正在索引\n if (progress.stage !== 'done') {\n setIsIndexing(true)\n }\n \n // 更新阶段\n setCurrentStage(progress.stage as 'scanning' | 'parsing' | 'embedding' | 'storing' | 'done' | null)\n \n // 扫描阶段:total 为 0,使用 indexed 表示已扫描的文件数\n if (progress.stage === 'scanning') {\n setProgressIndexed(progress.indexed)\n setProgressTotal(0)\n setProgressPercentage(0) // 扫描阶段不显示百分比\n } else {\n setProgressIndexed(progress.indexed)\n setProgressTotal(progress.total)\n setProgressPercentage(progress.total > 0 \n ? Math.round((progress.indexed / progress.total) * 100) \n : 0)\n }\n setCurrentFile(progress.currentFile || null)\n \n if (progress.stage === 'done') {\n setIsIndexing(false)\n setCurrentStage(null)\n setCurrentFile(null)\n // 同步完成后刷新统计\n fetchIndexStats()\n }\n })\n }, [fetchIndexStats])\n\n /** 检查索引状态并恢复进度显示 */\n const checkIndexStatus = useCallback(async () => {\n const bridge = (window as any).aiChatBridge\n if (!bridge?.getIndexStatus) {\n return\n }\n \n try {\n const status = await bridge.getIndexStatus()\n if (status.isIndexing && status.lastProgress) {\n // 如果有正在进行的索引任务,恢复进度显示\n setIsIndexing(true)\n const progress = status.lastProgress\n \n // 恢复进度状态\n setCurrentStage(progress.stage as 'scanning' | 'parsing' | 'embedding' | 'storing' | 'done' | null)\n \n if (progress.stage === 'scanning') {\n setProgressIndexed(progress.indexed)\n setProgressTotal(0)\n setProgressPercentage(0)\n } else {\n setProgressIndexed(progress.indexed)\n setProgressTotal(progress.total)\n setProgressPercentage(progress.total > 0 \n ? Math.round((progress.indexed / progress.total) * 100) \n : 0)\n }\n \n setCurrentFile(progress.currentFile || null)\n }\n } catch (error) {\n console.error('检查索引状态失败:', error)\n }\n }, [])\n\n /** 同步索引 */\n const handleSync = useCallback(async () => {\n if (isIndexing) return\n \n const bridge = (window as any).aiChatBridge\n if (!bridge?.syncIndex) {\n console.error('syncIndex 方法未在 bridge 中实现')\n return\n }\n \n // 确保进度监听器已设置\n if (!progressCleanupRef.current) {\n setupProgressListener()\n }\n \n setIsIndexing(true)\n cancelIndexingRef.current = false\n setProgressPercentage(0)\n setProgressIndexed(0)\n setProgressTotal(0)\n setCurrentStage(null)\n setCurrentFile(null)\n \n try {\n await bridge.syncIndex()\n } catch (error) {\n if (!cancelIndexingRef.current) {\n console.error('同步索引失败:', error)\n }\n setIsIndexing(false)\n setCurrentFile(null)\n }\n }, [isIndexing, setupProgressListener])\n\n /** 取消索引 */\n const handleCancelIndex = useCallback(async () => {\n cancelIndexingRef.current = true\n setIsIndexing(false)\n setCurrentFile(null)\n \n const bridge = (window as any).aiChatBridge\n if (bridge?.cancelIndex) {\n try {\n await bridge.cancelIndex()\n } catch (error) {\n console.error('取消索引失败:', error)\n }\n }\n }, [])\n\n /** 删除索引 */\n const handleDeleteIndex = useCallback(async () => {\n if (isIndexing) return\n \n setShowDeleteConfirm(false)\n \n const bridge = (window as any).aiChatBridge\n if (!bridge?.deleteIndex) {\n console.error('deleteIndex 方法未在 bridge 中实现')\n return\n }\n \n try {\n await bridge.deleteIndex()\n \n // 刷新统计\n await fetchIndexStats()\n } catch (error) {\n console.error('删除索引失败:', error)\n }\n }, [isIndexing, fetchIndexStats])\n\n // 组件挂载时获取统计信息、注册监听器、检查索引状态并设置进度监听\n useEffect(() => {\n const init = async () => {\n const bridge = (window as any).aiChatBridge\n \n // 注册索引进度监听器\n if (bridge?.registerIndexListener) {\n try {\n await bridge.registerIndexListener()\n } catch (error) {\n console.error('注册索引进度监听器失败:', error)\n }\n }\n \n await fetchIndexStats()\n setupProgressListener()\n await checkIndexStatus()\n }\n init()\n }, [fetchIndexStats, setupProgressListener, checkIndexStatus])\n\n // 组件卸载时清理进度监听器\n useEffect(() => {\n return () => {\n const bridge = (window as any).aiChatBridge\n \n // 注销索引进度监听器\n if (bridge?.unregisterIndexListener) {\n try {\n bridge.unregisterIndexListener()\n } catch (error) {\n console.error('注销索引进度监听器失败:', error)\n }\n }\n \n if (progressCleanupRef.current) {\n progressCleanupRef.current()\n progressCleanupRef.current = null\n }\n }\n }, [])\n\n return (\n <div className=\"indexing-settings\">\n {/* 代码库索引部分 */}\n <div className=\"setting-item indexing-section\">\n <div className=\"setting-info\">\n <div className=\"setting-label\">代码库索引</div>\n <p className=\"setting-description\">\n 嵌入代码库以改进上下文理解和知识。所有数据(嵌入向量、元数据和代码)都存储在本地。\n </p>\n <div className=\"indexing-content\">\n {/* 进度条 */}\n <div className=\"progress-container\">\n <div className=\"progress-bar\">\n <div \n className=\"progress-fill\" \n style={{ width: `${progressPercentage}%` }}\n ></div>\n </div>\n <div className=\"progress-text\">\n {isIndexing ? (\n currentStage === 'scanning' ? (\n <span>正在扫描文件... (已扫描 {progressIndexed.toLocaleString()} 个文件)</span>\n ) : (\n <span>{progressPercentage}% ({progressIndexed}/{progressTotal})</span>\n )\n ) : (\n <span>{indexedFiles.toLocaleString()} 个文件</span>\n )}\n </div>\n </div>\n\n {/* 统计信息 */}\n {!isIndexing && indexedFiles > 0 && (\n <div className=\"stats-info\">\n <div className=\"stat-item\">\n <Icon icon=\"lucide:database\" width={14} />\n <span>索引大小: {indexSize}</span>\n </div>\n {lastUpdated && (\n <div className=\"stat-item\">\n <Icon icon=\"lucide:clock\" width={14} />\n <span>最后更新: {lastUpdated}</span>\n </div>\n )}\n </div>\n )}\n\n {/* 当前文件信息 */}\n {isIndexing && currentFile && (\n <div className=\"current-file\">\n <Icon icon=\"lucide:file-text\" width={14} />\n <span className=\"file-path\">{currentFile}</span>\n </div>\n )}\n\n {/* 操作按钮 */}\n <div className=\"action-buttons\">\n {!isIndexing ? (\n <button \n className=\"edit-btn\"\n onClick={handleSync}\n >\n <Icon icon=\"lucide:refresh-cw\" width={16} />\n <span>同步</span>\n </button>\n ) : (\n <button \n className=\"edit-btn\"\n onClick={handleCancelIndex}\n >\n <Icon icon=\"lucide:x\" width={16} />\n <span>取消</span>\n </button>\n )}\n <button \n className=\"edit-btn delete-btn\"\n disabled={isIndexing}\n onClick={() => setShowDeleteConfirm(true)}\n >\n <Icon icon=\"lucide:trash-2\" width={16} />\n <span>删除索引</span>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {/* 删除确认对话框 */}\n <ConfirmDialog\n visible={showDeleteConfirm}\n type=\"danger\"\n title=\"删除索引\"\n message={`确定要删除所有索引吗?\\n\\n这将删除 ${indexedFiles.toLocaleString()} 个文件的索引数据(${indexSize}),此操作无法撤销。`}\n confirmText=\"删除\"\n cancelText=\"取消\"\n onConfirm={handleDeleteIndex}\n onCancel={() => setShowDeleteConfirm(false)}\n />\n </div>\n )\n}\n\n","/**\n * @huyooo/ai-chat-frontend-react\n *\n * AI Chat 前端组件库 - React 版本\n *\n * 新架构:使用 ContentPart 数组渲染消息内容\n * - 支持流式渲染\n * - 支持自定义 Part 类型渲染(如 weather, stock)\n * - 支持思考、搜索、工具调用等多种内容类型\n */\n\n// CSS 变量默认值(与 vue 版本保持一致:入口自动注入)\nimport './styles.css'\n\n// ==================== 核心类型 ====================\n\n// 从 bridge-electron 重新导出通信相关类型\nexport type {\n ChatAdapter,\n ChatEvent,\n ChatEventType,\n ChatOptions,\n ChatMode,\n ThinkingMode,\n SessionRecord,\n MessageRecord,\n ModelOption,\n ProviderType,\n} from '@huyooo/ai-chat-bridge-electron/renderer'\n\n// 导出 adapter 辅助类型\nexport type {\n ThinkingData,\n ToolCallData,\n ToolResultData,\n ImageData,\n SendMessageOptions,\n CreateSessionOptions,\n UpdateSessionOptions,\n SaveMessageOptions,\n} from './adapter'\n\n// 导出消息和内容类型\nexport type {\n // 消息类型\n ChatMessage,\n // ContentPart 类型\n ContentPart,\n ContentPartType,\n TextPart,\n ThinkingPart,\n SearchPart,\n ToolCallPart,\n ImagePart,\n ErrorPart,\n // 搜索结果\n SearchResult,\n // 错误详情\n ErrorDetails,\n // 输入配置\n ChatInputOptions,\n} from './types'\n\n// 导出工具函数\nexport { getMessageText } from './types'\n\n// ==================== Hooks ====================\n\nexport { useChat } from './hooks/useChat'\nexport type { UseChatOptions, ToolCompleteEvent, SideEffect } from './hooks/useChat'\n\n// ==================== Context ====================\n\nexport { ChatInputProvider, useChatInputContext } from './context/ChatInputContext'\nexport type { ChatInputContextValue } from './context/ChatInputContext'\n\n// Part 渲染器上下文\nexport { PartRenderersProvider, PartRenderersContext } from './context/RenderersContext'\nexport type { PartRenderers, PartRendererProps } from './context/RenderersContext'\n\n// ==================== 主组件 ====================\n\nexport { ChatPanel } from './components/ChatPanel'\nexport type { ChatPanelHandle } from './components/ChatPanel'\n\n// ==================== 消息组件 ====================\n\nexport { MessageBubble } from './components/message/MessageBubble'\nexport { PartsRenderer } from './components/message/PartsRenderer'\n\n// Part 渲染组件\nexport {\n TextPart as TextPartComponent,\n ThinkingPart as ThinkingPartComponent,\n SearchPart as SearchPartComponent,\n ToolCallPart as ToolCallPartComponent,\n ImagePart as ImagePartComponent,\n ErrorPart as ErrorPartComponent,\n} from './components/message/parts'\n\n// ==================== 其他组件 ====================\n\n// 输入组件\nexport { ChatInput } from './components/input/ChatInput'\n\n// Header 组件\nexport { ChatHeader } from './components/header/ChatHeader'\n\n// 欢迎消息组件\nexport { WelcomeMessage } from './components/message/WelcomeMessage'\nexport type { WelcomeConfig, WelcomeFeature, WelcomeTask } from './components/message/welcome-types'\nexport { defaultWelcomeConfig } from './components/message/welcome-types'\n\n// 通用组件\nexport { ConfirmDialog } from './components/common/ConfirmDialog'\nexport { Toast } from './components/common/Toast'\n\n// ==================== 工具渲染器相关 ====================\n\n// 从 ai-chat-shared 重新导出(用于自定义工具渲染器)\nexport type {\n ContentBlockType,\n ContentBlock,\n TextBlock as TextBlockType,\n CodeBlock as CodeBlockType,\n WeatherData,\n SearchResultItem,\n} from '@huyooo/ai-chat-shared'\nexport { parseContent, highlightCode, getLanguageDisplayName, renderMarkdown } from '@huyooo/ai-chat-shared'\n\n/**\n * 使用说明:\n *\n * 1. 导入样式:\n * import '@huyooo/ai-chat-frontend-react/style.css'\n *\n * 2. 基本使用:\n * import { ChatPanel } from '@huyooo/ai-chat-frontend-react'\n * import { createElectronAdapter } from '@huyooo/ai-chat-bridge-electron/renderer'\n * const adapter = createElectronAdapter()\n * <ChatPanel adapter={adapter} cwd=\"/path/to/dir\" />\n *\n * 3. 自定义 Part 渲染器(新架构):\n * import WeatherCard from './WeatherCard'\n * const partRenderers = { weather: WeatherCard }\n * <ChatPanel adapter={adapter} partRenderers={partRenderers} />\n *\n * 4. 使用 useChat hook 自定义 UI:\n * import { useChat } from '@huyooo/ai-chat-frontend-react'\n * const { messages, sendMessage, ... } = useChat({ adapter })\n */\n"],"mappings":"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","names":["options","createContext","jsx","useEffect","useRef","useCallback","useMemo","useState","forwardRef","useImperativeHandle","Icon","useState","useRef","useEffect","useCallback","jsx","useState","useRef","useEffect","useCallback","useMemo","Icon","jsx","jsxs","useMemo","Icon","useMemo","Icon","useContext","useMemo","Icon","jsx","jsxs","Icon","useEffect","useState","useCallback","useRef","renderMarkdown","jsx","jsxs","useRef","useState","useCallback","useEffect","renderMarkdown","useState","useEffect","jsx","useState","useEffect","useState","useEffect","jsx","jsxs","useState","useEffect","useState","useMemo","useEffect","useCallback","useRef","Icon","useState","useRef","useCallback","useEffect","useMemo","Icon","jsx","jsxs","useRef","useState","useMemo","useCallback","useEffect","Icon","useState","useCallback","Icon","jsx","useState","useCallback","Icon","highlightCode","Fragment","jsx","jsxs","useMemo","highlightCode","useState","useEffect","useCallback","useRef","Icon","useState","Icon","jsx","jsxs","useState","Icon","useState","jsx","useState","jsx","useContext","useMemo","useState","useRef","useCallback","useEffect","forwardRef","useImperativeHandle","useLayoutEffect","useMemo","Icon","useCallback","useEffect","useMemo","useRef","useState","Icon","useCallback","useEffect","useMemo","useRef","useState","Icon","jsx","jsxs","useState","useRef","useMemo","useEffect","useCallback","Icon","forwardRef","useImperativeHandle","Icon","jsx","jsxs","forwardRef","useImperativeHandle","Icon","forwardRef","useImperativeHandle","Icon","jsx","jsxs","forwardRef","useImperativeHandle","Icon","forwardRef","useImperativeHandle","Icon","jsx","jsxs","forwardRef","useImperativeHandle","Icon","forwardRef","useImperativeHandle","Icon","jsx","jsxs","forwardRef","useImperativeHandle","Icon","forwardRef","useImperativeHandle","Icon","jsx","jsxs","forwardRef","useImperativeHandle","Icon","Fragment","jsx","jsxs","useRef","useState","useCallback","useMemo","useEffect","jsx","jsxs","Icon","Fragment","useCallback","useEffect","useState","createPortal","Icon","jsx","jsxs","useState","useEffect","useCallback","createPortal","Icon","useState","useCallback","useMemo","useCallback","useEffect","useMemo","useRef","useCallback","useEffect","useMemo","useRef","useState","off","useRef","useMemo","useEffect","useCallback","jsx","jsxs","forwardRef","useState","useRef","useCallback","useMemo","useEffect","useLayoutEffect","useImperativeHandle","images","Icon","Fragment","jsx","jsxs","formatTime","useMemo","Icon","useEffect","createPortal","Icon","jsx","jsxs","useEffect","createPortal","Icon","useEffect","createPortal","jsx","useEffect","createPortal","useState","useCallback","useMemo","Icon","jsx","jsxs","useState","useEffect","useCallback","useRef","Icon","jsx","jsxs","useState","useRef","useCallback","useEffect","Icon","Fragment","jsx","jsxs","useState","useMemo","modeOptions","useCallback","Icon","jsx","jsxs","forwardRef","useRef","useState","useCallback","useImperativeHandle","useEffect","useMemo","Icon","highlightCode","renderMarkdown"]}