@huyooo/ai-chat-frontend-react 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +368 -0
- package/dist/index.css +2575 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +378 -135
- package/dist/index.js +3956 -1042
- package/dist/index.js.map +1 -1
- package/dist/style.css +48 -987
- package/package.json +7 -4
- package/src/adapter.ts +10 -70
- package/src/components/ChatPanel.tsx +373 -117
- package/src/components/common/ConfirmDialog.css +136 -0
- package/src/components/common/ConfirmDialog.tsx +91 -0
- package/src/components/common/CopyButton.css +22 -0
- package/src/components/common/CopyButton.tsx +46 -0
- package/src/components/common/IndexingSettings.css +207 -0
- package/src/components/common/IndexingSettings.tsx +398 -0
- package/src/components/common/SettingsPanel.css +256 -0
- package/src/components/common/SettingsPanel.tsx +120 -0
- package/src/components/common/Toast.css +50 -0
- package/src/components/common/Toast.tsx +38 -0
- package/src/components/common/ToggleSwitch.css +52 -0
- package/src/components/common/ToggleSwitch.tsx +20 -0
- package/src/components/header/ChatHeader.css +285 -0
- package/src/components/header/ChatHeader.tsx +376 -0
- package/src/components/input/AtFilePicker.css +147 -0
- package/src/components/input/AtFilePicker.tsx +519 -0
- package/src/components/input/ChatInput.css +204 -0
- package/src/components/input/ChatInput.tsx +506 -0
- package/src/components/input/DropdownSelector.css +159 -0
- package/src/components/input/DropdownSelector.tsx +195 -0
- package/src/components/input/ImagePreviewModal.css +124 -0
- package/src/components/input/ImagePreviewModal.tsx +118 -0
- package/src/components/input/at-views/AtBranchView.tsx +34 -0
- package/src/components/input/at-views/AtBrowserView.tsx +34 -0
- package/src/components/input/at-views/AtChatsView.tsx +34 -0
- package/src/components/input/at-views/AtDocsView.tsx +34 -0
- package/src/components/input/at-views/AtFilesView.tsx +168 -0
- package/src/components/input/at-views/AtTerminalsView.tsx +34 -0
- package/src/components/input/at-views/AtViewStyles.css +143 -0
- package/src/components/input/at-views/index.ts +9 -0
- package/src/components/message/ContentRenderer.css +9 -0
- package/src/components/message/ContentRenderer.tsx +63 -0
- package/src/components/message/MessageBubble.css +190 -0
- package/src/components/message/MessageBubble.tsx +231 -0
- package/src/components/message/PartsRenderer.css +4 -0
- package/src/components/message/PartsRenderer.tsx +114 -0
- package/src/components/message/ToolResultRenderer.tsx +21 -0
- package/src/components/message/WelcomeMessage.css +221 -0
- package/src/components/message/WelcomeMessage.tsx +93 -0
- package/src/components/message/blocks/CodeBlock.tsx +60 -0
- package/src/components/message/blocks/TextBlock.tsx +15 -0
- package/src/components/message/blocks/blocks.css +141 -0
- package/src/components/message/blocks/index.ts +6 -0
- package/src/components/message/parts/CollapsibleCard.css +78 -0
- package/src/components/message/parts/CollapsibleCard.tsx +77 -0
- package/src/components/message/parts/ErrorPart.css +9 -0
- package/src/components/message/parts/ErrorPart.tsx +40 -0
- package/src/components/message/parts/ImagePart.css +50 -0
- package/src/components/message/parts/ImagePart.tsx +54 -0
- package/src/components/message/parts/SearchPart.css +44 -0
- package/src/components/message/parts/SearchPart.tsx +63 -0
- package/src/components/message/parts/TextPart.css +10 -0
- package/src/components/message/parts/TextPart.tsx +20 -0
- package/src/components/message/parts/ThinkingPart.css +9 -0
- package/src/components/message/parts/ThinkingPart.tsx +48 -0
- package/src/components/message/parts/ToolCallPart.css +220 -0
- package/src/components/message/parts/ToolCallPart.tsx +285 -0
- package/src/components/message/parts/ToolResultPart.css +68 -0
- package/src/components/message/parts/ToolResultPart.tsx +96 -0
- package/src/components/message/parts/index.ts +11 -0
- package/src/components/message/tool-results/DefaultToolResult.tsx +26 -0
- package/src/components/message/tool-results/SearchResults.tsx +69 -0
- package/src/components/message/tool-results/WeatherCard.tsx +63 -0
- package/src/components/message/tool-results/index.ts +7 -0
- package/src/components/message/tool-results/tool-results.css +179 -0
- package/src/components/message/welcome-types.ts +46 -0
- package/src/context/AutoRunConfigContext.tsx +13 -0
- package/src/context/ChatAdapterContext.tsx +8 -0
- package/src/context/ChatInputContext.tsx +40 -0
- package/src/context/RenderersContext.tsx +41 -0
- package/src/hooks/useChat.ts +855 -237
- package/src/hooks/useImageUpload.ts +253 -0
- package/src/index.ts +96 -39
- package/src/styles.css +48 -987
- package/src/types/index.ts +172 -103
- package/src/utils/fileIcon.ts +49 -0
- package/src/components/ChatInput.tsx +0 -368
- package/src/components/chat/messages/ExecutionSteps.tsx +0 -234
- package/src/components/chat/messages/MessageBubble.tsx +0 -130
- package/src/components/chat/ui/ChatHeader.tsx +0 -301
- package/src/components/chat/ui/WelcomeMessage.tsx +0 -107
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapter.ts","../src/hooks/useChat.ts","../src/components/ChatPanel.tsx","../src/types/index.ts","../src/components/chat/ui/ChatHeader.tsx","../src/components/chat/ui/WelcomeMessage.tsx","../src/components/chat/messages/MessageBubble.tsx","../src/components/chat/messages/ExecutionSteps.tsx","../src/components/ChatInput.tsx"],"sourcesContent":["/**\n * Chat Adapter 辅助类型和工具\n * 核心 ChatAdapter 接口从 bridge-electron 导入\n */\n\nimport type { ChatAdapter, ChatMode, ThinkingMode } from '@huyooo/ai-chat-bridge-electron/renderer'\nimport type { SearchResult } from './types'\n\n/** 思考数据 */\nexport interface ThinkingData {\n content: string\n isComplete: boolean\n}\n\n/** 工具调用数据 */\nexport interface ToolCallData {\n name: string\n args: Record<string, unknown>\n}\n\n/** 工具结果数据 */\nexport interface ToolResultData {\n name: string\n result: string\n}\n\n/** 图片数据 */\nexport interface ImageData {\n base64: string\n mimeType: string\n}\n\n/** 发送消息选项 */\nexport interface SendMessageOptions {\n mode: ChatMode\n model: string\n enableWebSearch: boolean\n thinkingMode: ThinkingMode\n}\n\n/** 创建会话选项 */\nexport interface CreateSessionOptions {\n title: string\n model: string\n mode: ChatMode\n}\n\n/** 更新会话选项 */\nexport interface UpdateSessionOptions {\n title?: string\n model?: string\n mode?: ChatMode\n}\n\n/** 保存消息选项 */\nexport interface SaveMessageOptions {\n sessionId: string\n role: 'user' | 'assistant'\n content: string\n thinking?: string\n toolCalls?: string\n searchResults?: string\n}\n\n/**\n * 创建空 Adapter(用于测试或无后端场景)\n * 返回一个最小实现的 ChatAdapter\n */\nexport function createNullAdapter(): ChatAdapter {\n return {\n async getModels() {\n return []\n },\n async getSessions() {\n return []\n },\n async getSession() {\n return null\n },\n async createSession(params) {\n return {\n id: Date.now().toString(),\n appId: null,\n userId: null,\n title: params?.title || '新对话',\n model: params?.model || '',\n mode: (params?.mode || 'agent') as ChatMode,\n createdAt: new Date(),\n updatedAt: new Date(),\n }\n },\n async updateSession() {\n return null\n },\n async deleteSession() {},\n async getMessages() {\n return []\n },\n async saveMessage(params) {\n return {\n id: Date.now().toString(),\n sessionId: params.sessionId,\n role: params.role,\n content: params.content,\n thinking: params.thinking || null,\n toolCalls: params.toolCalls || null,\n searchResults: params.searchResults || null,\n operationIds: null,\n timestamp: new Date(),\n }\n },\n async deleteMessagesAfter() {},\n async getOperations() {\n return []\n },\n async getTrashItems() {\n return []\n },\n async restoreFromTrash() {\n return undefined\n },\n async *sendMessage() {\n yield { type: 'text', data: '无可用的 Adapter' }\n yield { type: 'done', data: '' }\n },\n cancel() {},\n }\n}\n","/**\n * useChat Hook\n * 管理聊天状态和与后端的通信\n * 使用 Adapter 模式解耦后端通信\n * \n * 与 Vue 版本 useChat composable 保持一致\n */\n\nimport { useState, useCallback, useRef } from 'react'\nimport type {\n ChatAdapter,\n ChatProgress,\n ChatMode,\n SessionRecord,\n MessageRecord,\n} from '@huyooo/ai-chat-bridge-electron/renderer'\nimport { createNullAdapter } from '../adapter'\nimport type { ChatMessage, SearchResult, ToolCall } from '../types'\n\n/** 生成唯一 ID */\nfunction generateId(): string {\n return Date.now().toString(36) + Math.random().toString(36).substr(2)\n}\n\n/** 转换存储的消息为显示格式 */\nfunction convertToMessage(record: MessageRecord): ChatMessage {\n return {\n id: record.id,\n role: record.role,\n content: record.content,\n thinking: record.thinking || undefined,\n thinkingComplete: true,\n toolCalls: record.toolCalls ? JSON.parse(record.toolCalls) : undefined,\n searchResults: record.searchResults ? JSON.parse(record.searchResults) : undefined,\n searching: false,\n timestamp: record.timestamp,\n }\n}\n\nexport interface UseChatOptions {\n /** Adapter 实例 */\n adapter?: ChatAdapter\n /** 默认模型 */\n defaultModel?: string\n /** 默认模式 */\n defaultMode?: ChatMode\n}\n\n/**\n * 聊天状态管理 Hook\n */\nexport function useChat(options: UseChatOptions = {}) {\n const {\n adapter = createNullAdapter(),\n defaultModel = 'anthropic/claude-opus-4.5',\n defaultMode = 'agent',\n } = options\n\n // 会话状态\n const [sessions, setSessions] = useState<SessionRecord[]>([])\n const [currentSessionId, setCurrentSessionId] = useState<string | null>(null)\n const [messages, setMessages] = useState<ChatMessage[]>([])\n\n // 配置状态\n const [mode, setModeState] = useState<ChatMode>(defaultMode)\n const [model, setModelState] = useState(defaultModel)\n const [webSearch, setWebSearchState] = useState(true)\n const [thinking, setThinkingState] = useState(true)\n\n // 加载状态\n const [isLoading, setIsLoading] = useState(false)\n\n // 取消控制器\n const abortControllerRef = useRef<AbortController | null>(null)\n\n // 用于在回调中访问最新状态\n const sessionsRef = useRef(sessions)\n const messagesRef = useRef(messages)\n const currentSessionIdRef = useRef(currentSessionId)\n const modeRef = useRef(mode)\n const modelRef = useRef(model)\n const webSearchRef = useRef(webSearch)\n const thinkingRef = useRef(thinking)\n\n // 同步 ref\n sessionsRef.current = sessions\n messagesRef.current = messages\n currentSessionIdRef.current = currentSessionId\n modeRef.current = mode\n modelRef.current = model\n webSearchRef.current = webSearch\n thinkingRef.current = thinking\n\n /** 加载会话列表 */\n const loadSessions = useCallback(async () => {\n try {\n const list = await adapter.getSessions()\n setSessions(list)\n // 如果有会话且没有当前会话,选择最新的\n if (list.length > 0 && !currentSessionIdRef.current) {\n const firstSession = list[0]\n setCurrentSessionId(firstSession.id)\n const savedMessages = await adapter.getMessages(firstSession.id)\n setMessages(savedMessages.map(convertToMessage))\n setModeState(firstSession.mode)\n setModelState(firstSession.model)\n }\n } catch (error) {\n console.error('加载会话失败:', error)\n }\n }, [adapter])\n\n /** 切换会话 */\n const switchSession = useCallback(async (sessionId: string) => {\n if (currentSessionIdRef.current === sessionId) return\n\n setCurrentSessionId(sessionId)\n\n try {\n const savedMessages = await adapter.getMessages(sessionId)\n setMessages(savedMessages.map(convertToMessage))\n\n // 更新配置\n const session = sessionsRef.current.find((s) => s.id === sessionId)\n if (session) {\n setModeState(session.mode)\n setModelState(session.model)\n }\n } catch (error) {\n console.error('加载消息失败:', error)\n setMessages([])\n }\n }, [adapter])\n\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 })\n setSessions(prev => [session, ...prev])\n setCurrentSessionId(session.id)\n setMessages([])\n } catch (error) {\n console.error('创建会话失败:', error)\n }\n }, [adapter])\n\n /** 删除会话 */\n const deleteSession = useCallback(async (sessionId: string) => {\n try {\n await adapter.deleteSession(sessionId)\n setSessions(prev => prev.filter((s) => s.id !== sessionId))\n\n // 如果删除的是当前会话,切换到下一个\n if (currentSessionIdRef.current === sessionId) {\n const remaining = sessionsRef.current.filter((s) => s.id !== sessionId)\n if (remaining.length > 0) {\n await switchSession(remaining[0].id)\n } else {\n setCurrentSessionId(null)\n setMessages([])\n }\n }\n } catch (error) {\n console.error('删除会话失败:', error)\n }\n }, [adapter, switchSession])\n\n /** 删除当前会话 */\n const deleteCurrentSession = useCallback(async () => {\n if (currentSessionIdRef.current) {\n await deleteSession(currentSessionIdRef.current)\n }\n }, [deleteSession])\n\n /** 更新消息 */\n const updateMessage = useCallback((index: number, progress: ChatProgress) => {\n setMessages(prev => {\n const newMessages = [...prev]\n const msg = { ...newMessages[index] }\n if (!msg) return prev\n\n switch (progress.type) {\n case 'thinking': {\n const thinkingData = progress.data as { content: string; isComplete: boolean }\n if (thinkingData.content) {\n msg.thinking = (msg.thinking || '') + thinkingData.content\n }\n msg.thinkingComplete = thinkingData.isComplete\n break\n }\n\n case 'search_start':\n msg.searching = true\n break\n\n case 'search_result': {\n msg.searching = false\n const searchData = progress.data as { results: SearchResult[] }\n msg.searchResults = searchData.results || []\n break\n }\n\n case 'tool_call': {\n const toolData = progress.data as { name: string; args: Record<string, unknown> }\n if (!msg.toolCalls) msg.toolCalls = []\n msg.toolCalls = [...msg.toolCalls, {\n name: toolData.name,\n args: toolData.args,\n status: 'running' as const,\n }]\n break\n }\n\n case 'tool_result': {\n const resultData = progress.data as { name: string; result: string }\n if (msg.toolCalls) {\n msg.toolCalls = msg.toolCalls.map((t: ToolCall) => {\n if (t.name === resultData.name && t.status === 'running') {\n return { ...t, result: resultData.result, status: 'success' as const }\n }\n return t\n })\n }\n break\n }\n\n case 'text_delta':\n msg.content = (msg.content || '') + (progress.data as string)\n break\n\n case 'text':\n if (!msg.content) {\n msg.content = progress.data as string\n }\n break\n\n case 'error':\n msg.content = (msg.content || '') + `\\n\\n❌ 错误: ${progress.data}`\n break\n }\n\n newMessages[index] = msg\n return newMessages\n })\n }, [])\n\n /** 发送消息 */\n const sendMessage = useCallback(async (text: string, images?: string[]) => {\n if (!text.trim() || isLoading) return\n\n // 如果没有当前会话,先创建\n let sessionId = currentSessionIdRef.current\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 setCurrentSessionId(session.id)\n sessionId = session.id\n } catch (error) {\n console.error('创建会话失败:', error)\n return\n }\n }\n\n // 添加用户消息\n const userMsg: ChatMessage = {\n id: generateId(),\n role: 'user',\n content: text,\n images,\n timestamp: new Date(),\n }\n \n const currentMessages = messagesRef.current\n setMessages([...currentMessages, userMsg])\n\n // 保存用户消息\n try {\n await adapter.saveMessage({\n sessionId,\n role: 'user',\n content: text,\n })\n\n // 更新会话标题(如果是第一条消息)\n if (currentMessages.length === 0) {\n const title = text.slice(0, 20) + (text.length > 20 ? '...' : '')\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 // 创建助手消息\n const assistantMsgIndex = currentMessages.length + 1\n const assistantMsg: ChatMessage = {\n id: generateId(),\n role: 'assistant',\n content: '',\n toolCalls: [],\n thinkingComplete: false,\n searching: false,\n loading: true,\n timestamp: new Date(),\n }\n setMessages(prev => [...prev, assistantMsg])\n\n setIsLoading(true)\n abortControllerRef.current = new AbortController()\n\n try {\n // 使用异步迭代器接收消息流\n for await (const progress of adapter.sendMessage(\n text,\n {\n mode: modeRef.current,\n model: modelRef.current,\n enableWebSearch: webSearchRef.current,\n thinkingMode: thinkingRef.current ? 'enabled' : 'disabled',\n },\n images\n )) {\n // 检查是否被取消\n if (abortControllerRef.current?.signal.aborted) break\n\n updateMessage(assistantMsgIndex, progress)\n\n if (progress.type === 'done' || progress.type === 'error') {\n break\n }\n }\n } catch (error) {\n console.error('发送消息失败:', error)\n updateMessage(assistantMsgIndex, {\n type: 'error',\n data: error instanceof Error ? error.message : String(error),\n })\n } finally {\n setIsLoading(false)\n\n // 标记加载完成并保存\n setMessages(prev => {\n const newMessages = [...prev]\n const finalMsg = newMessages[assistantMsgIndex]\n if (finalMsg) {\n newMessages[assistantMsgIndex] = { ...finalMsg, loading: false }\n\n // 保存助手消息\n if (sessionId) {\n adapter.saveMessage({\n sessionId,\n role: 'assistant',\n content: finalMsg.content,\n thinking: finalMsg.thinking,\n toolCalls: finalMsg.toolCalls ? JSON.stringify(finalMsg.toolCalls) : undefined,\n searchResults: finalMsg.searchResults\n ? JSON.stringify(finalMsg.searchResults)\n : undefined,\n }).catch((e: Error) => console.error('保存助手消息失败:', e))\n }\n }\n return newMessages\n })\n\n abortControllerRef.current = null\n }\n }, [adapter, isLoading, updateMessage])\n\n /** 取消请求 */\n const cancelRequest = useCallback(() => {\n adapter.cancel()\n abortControllerRef.current?.abort()\n setIsLoading(false)\n }, [adapter])\n\n /** 复制消息 */\n const copyMessage = useCallback(async (messageId: string) => {\n const msg = messagesRef.current.find((m) => m.id === messageId)\n if (!msg) return\n\n try {\n await navigator.clipboard.writeText(msg.content)\n setMessages(prev => prev.map((m) =>\n m.id === messageId ? { ...m, copied: true } : m\n ))\n setTimeout(() => {\n setMessages(prev => prev.map((m) =>\n m.id === messageId ? { ...m, copied: false } : m\n ))\n }, 2000)\n } catch (err) {\n console.error('复制失败:', err)\n }\n }, [])\n\n /** 重新生成消息 */\n const regenerateMessage = useCallback((messageIndex: number) => {\n const currentMsgs = messagesRef.current\n if (messageIndex > 0 && currentMsgs[messageIndex - 1]?.role === 'user') {\n const userMsg = currentMsgs[messageIndex - 1]\n setMessages(prev => prev.slice(0, messageIndex - 1))\n sendMessage(userMsg.content, userMsg.images)\n }\n }, [sendMessage])\n\n /** 设置工作目录 */\n const setWorkingDirectory = useCallback((dir: string) => {\n if (adapter.setWorkingDir) {\n adapter.setWorkingDir(dir)\n }\n }, [adapter])\n\n // 配置方法\n const setMode = useCallback((value: ChatMode) => setModeState(value), [])\n const setModel = useCallback((value: string) => setModelState(value), [])\n const setWebSearch = useCallback((value: boolean) => setWebSearchState(value), [])\n const setThinking = useCallback((value: boolean) => setThinkingState(value), [])\n\n return {\n // 状态\n sessions,\n currentSessionId,\n messages,\n isLoading,\n mode,\n model,\n webSearch,\n thinking,\n\n // 会话方法\n loadSessions,\n switchSession,\n createNewSession,\n deleteSession,\n deleteCurrentSession,\n\n // 消息方法\n sendMessage,\n cancelRequest,\n copyMessage,\n regenerateMessage,\n\n // 配置方法\n setMode,\n setModel,\n setWebSearch,\n setThinking,\n\n // 工具方法\n setWorkingDirectory,\n }\n}\n","/**\n * ChatPanel Component\n * 与 Vue 版本 ChatPanel.vue 保持一致\n */\n\nimport { useEffect, useRef, useCallback, type FC, type ReactNode } from 'react'\nimport { useChat } from '../hooks/useChat'\nimport type { ChatAdapter, ModelConfig, ChatMode } from '@huyooo/ai-chat-bridge-electron/renderer'\nimport { DEFAULT_MODELS } from '../types'\nimport { ChatHeader } from './chat/ui/ChatHeader'\nimport { WelcomeMessage } from './chat/ui/WelcomeMessage'\nimport { MessageBubble } from './chat/messages/MessageBubble'\nimport { ChatInput } from './ChatInput'\n\ninterface ChatPanelProps {\n /** Adapter 实例 */\n adapter?: ChatAdapter\n /** 工作目录 */\n workingDir?: string\n /** 默认模型 */\n defaultModel?: string\n /** 默认模式 */\n defaultMode?: ChatMode\n /** 可用模型列表 */\n models?: ModelConfig[]\n /** 隐藏标题栏 */\n hideHeader?: boolean\n /** 关闭回调(有此属性时显示关闭按钮) */\n onClose?: () => void\n /** 自定义类名 */\n className?: string\n /** 自定义 Markdown 渲染器 */\n renderMarkdown?: (content: string) => ReactNode\n}\n\nexport const ChatPanel: FC<ChatPanelProps> = ({\n adapter,\n workingDir,\n defaultModel = 'anthropic/claude-opus-4.5',\n defaultMode = 'agent',\n models = DEFAULT_MODELS,\n hideHeader = false,\n onClose,\n className = '',\n renderMarkdown,\n}) => {\n const messagesRef = useRef<HTMLDivElement>(null)\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 sendMessage,\n cancelRequest,\n copyMessage,\n regenerateMessage,\n setMode,\n setModel,\n setWebSearch,\n setThinking,\n setWorkingDirectory,\n } = useChat({\n adapter,\n defaultModel,\n defaultMode,\n })\n\n // 选中的图片\n // const [selectedImages, setSelectedImages] = useState<string[]>([])\n\n // 初始化\n useEffect(() => {\n loadSessions()\n }, [loadSessions])\n\n // 工作目录变化时更新\n useEffect(() => {\n if (workingDir) {\n setWorkingDirectory(workingDir)\n }\n }, [workingDir, setWorkingDirectory])\n\n // 滚动到底部\n const scrollToBottom = useCallback(() => {\n if (messagesRef.current) {\n messagesRef.current.scrollTop = messagesRef.current.scrollHeight\n }\n }, [])\n\n // 消息变化时滚动\n useEffect(() => {\n scrollToBottom()\n }, [messages, scrollToBottom])\n\n // 发送消息\n const handleSend = useCallback(\n (text: string) => {\n sendMessage(text)\n },\n [sendMessage]\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 // 删除当前消息及后续消息,然后重新发送\n // 这里简化处理,实际需要更完善的逻辑\n sendMessage(text)\n },\n [sendMessage]\n )\n\n // 关闭\n const handleClose = useCallback(() => {\n onClose?.()\n }, [onClose])\n\n // 清空所有对话\n const handleClearAll = useCallback(() => {\n console.log('清空所有对话')\n }, [])\n\n // 关闭其他对话\n const handleCloseOthers = useCallback(() => {\n console.log('关闭其他对话')\n }, [])\n\n // 导出对话\n const handleExport = useCallback(() => {\n console.log('导出对话')\n }, [])\n\n // 复制请求 ID\n const handleCopyId = useCallback(() => {\n if (currentSessionId) {\n navigator.clipboard.writeText(currentSessionId)\n console.log('已复制请求 ID:', currentSessionId)\n }\n }, [currentSessionId])\n\n // 反馈\n const handleFeedback = useCallback(() => {\n console.log('反馈')\n }, [])\n\n // 设置\n const handleSettings = useCallback(() => {\n console.log('Agent 设置')\n }, [])\n\n return (\n <div className={`chat-panel ${className}`.trim()}>\n {/* 顶部标题栏 */}\n {!hideHeader && (\n <ChatHeader\n sessions={sessions}\n currentSessionId={currentSessionId}\n showClose={!!onClose}\n onNewSession={createNewSession}\n onSwitchSession={switchSession}\n onDeleteSession={deleteSession}\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 ref={messagesRef} className=\"messages-container\">\n {messages.length === 0 ? (\n <WelcomeMessage onQuickAction={handleQuickAction} />\n ) : (\n messages.map((msg, index) => (\n <MessageBubble\n key={msg.id}\n role={msg.role}\n content={msg.content}\n images={msg.images}\n thinking={msg.thinking}\n thinkingComplete={msg.thinkingComplete}\n searchResults={msg.searchResults}\n searching={msg.searching}\n toolCalls={msg.toolCalls}\n copied={msg.copied}\n loading={msg.loading}\n onCopy={() => copyMessage(msg.id)}\n onRegenerate={() => regenerateMessage(index)}\n onSend={(text) => handleResend(index, text)}\n renderMarkdown={renderMarkdown}\n />\n ))\n )}\n </div>\n\n {/* 输入区域 */}\n <ChatInput\n selectedImages={[]}\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 />\n </div>\n )\n}\n","/**\n * AI Chat 前端类型定义\n * 核心类型(ChatAdapter, SessionRecord, MessageRecord 等)从 bridge-electron 导出\n * 这里只定义前端特有的类型\n */\n\n// 从 bridge-electron 导入类型(用于本文件)\nimport type {\n ChatMode as ChatModeType,\n ModelConfig as ModelConfigType,\n ModelProvider as ModelProviderType,\n ThinkingMode as ThinkingModeType,\n SessionRecord as SessionRecordType,\n MessageRecord as MessageRecordType,\n} from '@huyooo/ai-chat-bridge-electron/renderer'\n\n// 重新导出核心类型\nexport type ChatMode = ChatModeType\nexport type ModelConfig = ModelConfigType\nexport type ModelProvider = ModelProviderType\nexport type ThinkingMode = ThinkingModeType\nexport type SessionRecord = SessionRecordType\nexport type MessageRecord = MessageRecordType\n\n/** 搜索结果 */\nexport interface SearchResult {\n title: string\n url: string\n snippet: string\n}\n\n/** 工具调用 */\nexport interface ToolCall {\n name: string\n args?: Record<string, unknown>\n result?: string\n status: 'running' | 'success' | 'error'\n}\n\n/** 聊天消息(前端显示用) */\nexport interface ChatMessage {\n id: string\n role: 'user' | 'assistant'\n content: string\n images?: string[]\n thinking?: string\n thinkingComplete?: boolean\n searchResults?: SearchResult[]\n searching?: boolean\n toolCalls?: ToolCall[]\n copied?: boolean\n loading?: boolean\n timestamp?: Date\n}\n\n/** 默认模型列表 */\nexport const DEFAULT_MODELS: ModelConfigType[] = [\n {\n provider: 'openrouter',\n model: 'anthropic/claude-opus-4.5',\n displayName: 'Claude Opus 4.5',\n supportsTools: true,\n supportsWebSearch: true,\n supportedThinkingModes: ['enabled', 'disabled'],\n },\n {\n provider: 'doubao',\n model: 'doubao-seed-1-6-251015',\n displayName: 'Doubao Seed',\n supportsTools: true,\n supportsWebSearch: true,\n supportedThinkingModes: ['enabled', 'disabled'],\n },\n {\n provider: 'deepseek',\n model: 'deepseek-v3-1-terminus',\n displayName: 'DeepSeek V3',\n supportsTools: true,\n supportsWebSearch: true,\n supportedThinkingModes: ['enabled', 'disabled'],\n },\n {\n provider: 'qwen',\n model: 'qwen3-max-preview',\n displayName: 'Qwen Max',\n supportsTools: true,\n supportsWebSearch: true,\n supportedThinkingModes: ['enabled', 'disabled'],\n },\n {\n provider: 'gemini',\n model: 'gemini-3-pro-preview',\n displayName: 'Gemini 3 Pro',\n supportsTools: true,\n supportsWebSearch: true,\n supportedThinkingModes: ['enabled', 'disabled'],\n },\n]\n\n// ================ 以下为向后兼容的类型 ================\n\n/** @deprecated 使用 SessionRecord */\nexport interface ChatSession {\n id: string\n title: string\n messages: ChatMessage[]\n createdAt: Date\n updatedAt: Date\n}\n\n/** 音视频操作类型 */\nexport interface MediaOperation {\n id: string\n type: 'clip' | 'transcode' | 'merge' | 'extract_audio' | 'add_subtitle' | 'analyze'\n description: string\n sourceFiles: string[]\n targetFile?: string\n parameters?: Record<string, unknown>\n status?: 'pending' | 'applied' | 'rejected'\n preview?: string\n}\n\n/** @deprecated 使用字符串枚举 */\nexport type AiModel = 'gemini-3-pro-preview' | 'gemini-3-pro-image-preview'\n\nexport enum FileType {\n FOLDER = 'folder',\n IMAGE = 'image',\n VIDEO = 'video',\n AUDIO = 'audio',\n TEXT = 'text',\n PDF = 'pdf',\n CODE = 'code',\n ARCHIVE = 'archive',\n OTHER = 'other'\n}\n\nexport interface DiffStat {\n file: string\n additions: number\n deletions: number\n type: 'modified' | 'added' | 'deleted'\n}\n","/**\n * ChatHeader Component\n * 与 Vue 版本 ChatHeader.vue 保持一致\n */\n\nimport { useState, useRef, useEffect, useCallback, type FC } from 'react'\nimport { Plus, Clock, MoreHorizontal, X, MessageSquare, Pencil, Trash2 } from 'lucide-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 /** 关闭面板 */\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 formatTime(date: Date | string | undefined): string {\n if (!date) return ''\n const d = new Date(date)\n const now = new Date()\n const diff = now.getTime() - d.getTime()\n const days = Math.floor(diff / (1000 * 60 * 60 * 24))\n \n if (days === 0) {\n return d.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })\n } else if (days === 1) {\n return '昨天'\n } else if (days < 7) {\n return `${days}天前`\n } else {\n return d.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' })\n }\n}\n\nexport const ChatHeader: FC<ChatHeaderProps> = ({\n sessions,\n currentSessionId,\n showClose = false,\n onNewSession,\n onSwitchSession,\n onDeleteSession,\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 const [hiddenTabs, setHiddenTabs] = useState<Set<string>>(new Set())\n\n const historyRef = useRef<HTMLDivElement>(null)\n const moreMenuRef = useRef<HTMLDivElement>(null)\n\n // 可见的会话\n const visibleSessions = sessions.filter((s) => !hiddenTabs.has(s.id))\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 handleSwitchSession = useCallback(\n (sessionId: string) => {\n onSwitchSession?.(sessionId)\n setHistoryOpen(false)\n },\n [onSwitchSession]\n )\n\n // 隐藏 tab\n const handleHideTab = useCallback(\n (sessionId: string, e: React.MouseEvent) => {\n e.stopPropagation()\n setHiddenTabs((prev) => new Set([...prev, sessionId]))\n if (sessionId === currentSessionId) {\n const remaining = sessions.filter((s) => s.id !== sessionId && !hiddenTabs.has(s.id))\n if (remaining.length > 0) {\n onSwitchSession?.(remaining[0].id)\n }\n }\n },\n [currentSessionId, sessions, hiddenTabs, onSwitchSession]\n )\n\n // 删除会话\n const handleDeleteSession = (sessionId: string, e: React.MouseEvent) => {\n e.stopPropagation()\n if (window.confirm('确定要删除这个对话吗?')) {\n onDeleteSession?.(sessionId)\n }\n }\n\n // 菜单项点击\n const handleMenuClick = (callback?: () => void) => {\n callback?.()\n setMoreMenuOpen(false)\n }\n\n return (\n <div className=\"chat-header\">\n {/* 左侧:Tabs */}\n <div className=\"chat-tabs\">\n {visibleSessions.length === 0 ? (\n <span className=\"chat-tab active\">\n <span className=\"chat-tab-title\">New Chat</span>\n </span>\n ) : (\n visibleSessions.map((session) => {\n const title = session.title === '新对话' ? 'New Chat' : session.title\n const isActive = session.id === currentSessionId\n return (\n <div\n key={session.id}\n className={`chat-tab${isActive ? ' active' : ''}`}\n onClick={() => handleSwitchSession(session.id)}\n title={session.title}\n >\n <span className=\"chat-tab-title\">{title}</span>\n <span\n className=\"chat-tab-close\"\n onClick={(e) => handleHideTab(session.id, e)}\n title=\"关闭标签\"\n >\n <X size={12} />\n </span>\n </div>\n )\n })\n )}\n </div>\n\n {/* 右侧:操作按钮 */}\n <div className=\"chat-header-actions\">\n {/* 新建会话 */}\n <button className=\"header-btn\" onClick={onNewSession} title=\"新建对话\">\n <Plus size={14} />\n </button>\n\n {/* 历史记录 */}\n <div ref={historyRef} style={{ position: 'relative' }}>\n <button\n className={`header-btn${historyOpen ? ' active' : ''}`}\n onClick={(e) => {\n e.stopPropagation()\n setHistoryOpen(!historyOpen)\n setMoreMenuOpen(false)\n }}\n title=\"历史记录\"\n >\n <Clock size={14} />\n </button>\n\n {/* 历史记录面板 */}\n {historyOpen && (\n <div className=\"history-panel\">\n {sessions.length === 0 ? (\n <div className=\"history-empty\">暂无历史对话</div>\n ) : (\n sessions.map((session) => {\n const isCurrent = session.id === currentSessionId\n return (\n <div\n key={session.id}\n className={`history-item${isCurrent ? ' active' : ''}`}\n >\n <button\n className=\"history-item-content\"\n onClick={() => handleSwitchSession(session.id)}\n >\n <MessageSquare size={12} />\n <span className=\"history-item-title\">\n {session.title === '新对话' ? 'New Chat' : session.title}\n </span>\n <span className=\"history-item-time\">\n {isCurrent ? 'Current' : formatTime(session.updatedAt)}\n </span>\n </button>\n <div className=\"history-item-actions\">\n <button className=\"history-action-btn\" title=\"编辑\">\n <Pencil size={10} />\n </button>\n <button\n className=\"history-action-btn delete\"\n title=\"删除\"\n onClick={(e) => handleDeleteSession(session.id, e)}\n >\n <Trash2 size={10} />\n </button>\n </div>\n </div>\n )\n })\n )}\n </div>\n )}\n </div>\n\n {/* 更多选项 */}\n <div ref={moreMenuRef} style={{ position: 'relative' }}>\n <button\n className={`header-btn${moreMenuOpen ? ' active' : ''}`}\n onClick={(e) => {\n e.stopPropagation()\n setMoreMenuOpen(!moreMenuOpen)\n setHistoryOpen(false)\n }}\n title=\"更多选项\"\n >\n <MoreHorizontal size={14} />\n </button>\n\n {/* 更多选项菜单 */}\n {moreMenuOpen && (\n <div className=\"more-menu\">\n {showClose && (\n <button className=\"menu-item\" onClick={() => handleMenuClick(onClose)}>\n <span>关闭对话</span>\n <span className=\"menu-shortcut\">⌘ W</span>\n </button>\n )}\n {onClearAll && (\n <button className=\"menu-item\" onClick={() => handleMenuClick(onClearAll)}>\n 清空所有对话\n </button>\n )}\n {onCloseOthers && (\n <button className=\"menu-item\" onClick={() => handleMenuClick(onCloseOthers)}>\n 关闭其他对话\n </button>\n )}\n \n {(showClose || onClearAll || onCloseOthers) && <div className=\"menu-divider\" />}\n \n {onExport && (\n <button className=\"menu-item\" onClick={() => handleMenuClick(onExport)}>\n 导出对话\n </button>\n )}\n {onCopyId && (\n <button className=\"menu-item\" onClick={() => handleMenuClick(onCopyId)}>\n 复制请求 ID\n </button>\n )}\n {onFeedback && (\n <button className=\"menu-item\" onClick={() => handleMenuClick(onFeedback)}>\n 反馈\n </button>\n )}\n \n {(onExport || onCopyId || onFeedback) && onSettings && <div className=\"menu-divider\" />}\n \n {onSettings && (\n <button className=\"menu-item\" onClick={() => handleMenuClick(onSettings)}>\n Agent 设置\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n )\n}\n","/**\n * WelcomeMessage Component\n * 与 Vue 版本 WelcomeMessage.vue 保持一致\n */\n\nimport { type FC } from 'react'\nimport { Wand2, ImageIcon, Video, Terminal } from 'lucide-react'\n\ninterface WelcomeMessageProps {\n /** 快捷操作回调 */\n onQuickAction: (text: string) => void\n}\n\n/** 快捷操作配置 */\nconst QUICK_ACTIONS = [\n {\n id: 'txt2img',\n Icon: Wand2,\n label: '文生图',\n desc: 'AI 绘制创意图像',\n prompt: '帮我生成一张图片:',\n gradient: 'purple',\n iconColor: 'purple',\n featured: true,\n },\n {\n id: 'img2img',\n Icon: ImageIcon,\n label: '图生图',\n desc: '风格迁移',\n prompt: '基于这张图片进行风格转换',\n gradient: 'blue',\n iconColor: 'blue',\n featured: false,\n },\n {\n id: 'img2vid',\n Icon: Video,\n label: '图生视频',\n desc: '动态化',\n prompt: '将这张图片转换成视频',\n gradient: 'emerald',\n iconColor: 'emerald',\n featured: false,\n },\n {\n id: 'cmd',\n Icon: Terminal,\n label: '执行命令',\n desc: '系统管理',\n prompt: '执行命令:',\n gradient: 'orange',\n iconColor: 'orange',\n featured: true,\n },\n]\n\nexport const WelcomeMessage: FC<WelcomeMessageProps> = ({ onQuickAction }) => {\n return (\n <div className=\"welcome-message\">\n {/* 动态极光背景 */}\n <div className=\"welcome-glow purple\" />\n <div className=\"welcome-glow blue\" />\n\n {/* 标题区域 */}\n <div className=\"welcome-title-area\">\n <h1 className=\"welcome-title\">\n Create\n <br />\n <span className=\"welcome-title-accent\">Everything</span>\n </h1>\n <p className=\"welcome-subtitle\">释放 AI 的无限创造力</p>\n </div>\n\n {/* 快捷操作网格 */}\n <div className=\"quick-actions\">\n {QUICK_ACTIONS.map((action) => (\n <button\n key={action.id}\n className={`quick-action-btn${action.featured ? ' featured' : ''}`}\n onClick={() => onQuickAction(action.prompt)}\n >\n {/* 卡片背景渐变 */}\n <div className={`quick-action-gradient ${action.gradient}`} />\n\n {/* 图标 */}\n <action.Icon className={`quick-action-icon ${action.iconColor}`} />\n\n {/* 文字 */}\n <div className=\"quick-action-text\">\n <span className=\"quick-action-label\">{action.label}</span>\n <span className=\"quick-action-desc\">{action.desc}</span>\n </div>\n\n {/* 装饰性光斑 */}\n <div className=\"quick-action-glow\" />\n </button>\n ))}\n </div>\n\n {/* 底部装饰 */}\n <div className=\"welcome-footer\">\n <div className=\"welcome-footer-line\" />\n </div>\n </div>\n )\n}\n","/**\n * MessageBubble Component\n * 与 Vue 版本 MessageBubble.vue 保持一致\n */\n\nimport { type FC, type ReactNode } from 'react'\nimport { Copy, Check, RefreshCw } from 'lucide-react'\nimport { ExecutionSteps } from './ExecutionSteps'\nimport { ChatInput } from '../../ChatInput'\nimport type { SearchResult, ToolCall } from '../../../types'\n\ninterface MessageBubbleProps {\n role: 'user' | 'assistant'\n content: string\n images?: string[]\n thinking?: string\n thinkingComplete?: boolean\n thinkingDuration?: number\n searchResults?: SearchResult[]\n searching?: boolean\n toolCalls?: ToolCall[]\n copied?: boolean\n loading?: boolean\n onCopy?: () => void\n onRegenerate?: () => void\n /** 编辑用户消息后重新发送 */\n onSend?: (text: string) => void\n /** 自定义 Markdown 渲染器 */\n renderMarkdown?: (content: string) => ReactNode\n}\n\n/** 默认 Markdown 渲染(简单处理) */\nfunction defaultRenderMarkdown(content: string): ReactNode {\n // 简单的 Markdown 处理:代码块\n const parts = content.split(/(```[\\s\\S]*?```)/g)\n \n return parts.map((part, i) => {\n if (part.startsWith('```') && part.endsWith('```')) {\n const code = part.slice(3, -3)\n const firstLine = code.indexOf('\\n')\n const lang = firstLine > 0 ? code.slice(0, firstLine).trim() : ''\n const codeContent = firstLine > 0 ? code.slice(firstLine + 1) : code\n return (\n <pre key={i}>\n <code>{codeContent}</code>\n </pre>\n )\n }\n // 处理行内代码\n const inlineParts = part.split(/(`[^`]+`)/g)\n return (\n <span key={i}>\n {inlineParts.map((p, j) => {\n if (p.startsWith('`') && p.endsWith('`')) {\n return <code key={j}>{p.slice(1, -1)}</code>\n }\n return p\n })}\n </span>\n )\n })\n}\n\nexport const MessageBubble: FC<MessageBubbleProps> = ({\n role,\n content,\n images,\n thinking,\n thinkingComplete = true,\n thinkingDuration,\n searchResults,\n searching,\n toolCalls,\n copied,\n loading,\n onCopy,\n onRegenerate,\n onSend,\n renderMarkdown = defaultRenderMarkdown,\n}) => {\n const isUser = role === 'user'\n\n return (\n <div className=\"message-bubble\">\n {/* 用户消息 - 复用 ChatInput 组件 */}\n {isUser ? (\n <ChatInput\n variant=\"message\"\n value={content}\n selectedImages={images}\n onSend={onSend}\n />\n ) : (\n /* AI 消息 */\n <div className=\"assistant-message\">\n {/* 执行步骤列表 */}\n <ExecutionSteps\n loading={loading}\n hasContent={!!content}\n thinking={thinking}\n thinkingComplete={thinkingComplete}\n thinkingDuration={thinkingDuration}\n searching={searching}\n searchResults={searchResults}\n toolCalls={toolCalls}\n />\n\n {/* 消息内容 */}\n {content && (\n <div className=\"message-content\">\n {renderMarkdown(content)}\n </div>\n )}\n\n {/* 操作按钮 */}\n {content && !loading && (\n <div className=\"message-actions\">\n <button className={`action-btn${copied ? ' copied' : ''}`} onClick={onCopy} title=\"复制\">\n {copied ? <Check size={14} /> : <Copy size={14} />}\n </button>\n <button className=\"action-btn\" onClick={onRegenerate} title=\"重新生成\">\n <RefreshCw size={14} />\n </button>\n </div>\n )}\n </div>\n )}\n </div>\n )\n}\n","/**\n * ExecutionSteps Component\n * 与 Vue 版本 ExecutionSteps.vue 保持一致\n */\n\nimport { useState, type FC, type ReactNode } from 'react'\nimport {\n ChevronDown,\n ChevronUp,\n Sparkles,\n Globe,\n FileText,\n FileEdit,\n Terminal,\n Search,\n Folder,\n FolderPlus,\n Trash2,\n Image,\n Video,\n Wrench,\n ExternalLink,\n} from 'lucide-react'\nimport type { SearchResult, ToolCall } from '../../../types'\n\ninterface ExecutionStepsProps {\n /** 是否正在加载 */\n loading?: boolean\n /** 是否有消息内容 */\n hasContent?: boolean\n /** 思考内容 */\n thinking?: string\n /** 思考是否完成 */\n thinkingComplete?: boolean\n /** 思考耗时 */\n thinkingDuration?: number\n /** 是否正在搜索 */\n searching?: boolean\n /** 搜索结果 */\n searchResults?: SearchResult[]\n /** 工具调用列表 */\n toolCalls?: ToolCall[]\n}\n\n/** 步骤项组件 */\ninterface StepItemProps {\n icon: ReactNode\n title: string\n status: 'running' | 'completed' | 'error'\n extra?: string\n detail?: ReactNode\n defaultExpanded?: boolean\n}\n\nconst StepItem: FC<StepItemProps> = ({\n icon,\n title,\n status,\n extra,\n detail,\n defaultExpanded = false,\n}) => {\n const [expanded, setExpanded] = useState(defaultExpanded)\n const isRunning = status === 'running'\n const hasDetail = !!detail\n\n return (\n <div className=\"step-item\">\n <button\n className={`step-header${isRunning ? ' running' : ''}`}\n onClick={() => hasDetail && setExpanded(!expanded)}\n disabled={!hasDetail}\n style={{ cursor: hasDetail ? 'pointer' : 'default' }}\n >\n <span className={`step-icon${isRunning ? ' pulse' : ''}`}>{icon}</span>\n <span className=\"step-title\">{title}</span>\n {hasDetail && (\n expanded ? <ChevronUp className=\"step-chevron\" size={12} /> : <ChevronDown className=\"step-chevron\" size={12} />\n )}\n {extra && <span className=\"step-extra\">{extra}</span>}\n </button>\n\n {expanded && detail && (\n <div className=\"step-detail\">\n {typeof detail === 'string' ? <pre>{detail}</pre> : detail}\n </div>\n )}\n </div>\n )\n}\n\n/** 获取工具调用的显示名称 */\nfunction getToolDisplayName(name: string): string {\n const nameMap: Record<string, string> = {\n read_file: '读取文件',\n write_file: '写入文件',\n execute_command: '执行命令',\n search_files: '搜索文件',\n list_directory: '列出目录',\n create_directory: '创建目录',\n delete_file: '删除文件',\n web_search: '网页搜索',\n generate_image: '生成图片',\n image_to_video: '图片转视频',\n }\n return nameMap[name] || name\n}\n\n/** 获取工具调用的图标 */\nfunction getToolIcon(name: string) {\n switch (name) {\n case 'read_file': return <FileText size={14} />\n case 'write_file': return <FileEdit size={14} />\n case 'execute_command': return <Terminal size={14} />\n case 'search_files': return <Search size={14} />\n case 'list_directory': return <Folder size={14} />\n case 'create_directory': return <FolderPlus size={14} />\n case 'delete_file': return <Trash2 size={14} />\n case 'web_search': return <Globe size={14} />\n case 'generate_image': return <Image size={14} />\n case 'image_to_video': return <Video size={14} />\n default: return <Wrench size={14} />\n }\n}\n\n/** 格式化工具调用参数 */\nfunction formatToolArgs(args?: Record<string, unknown>): string {\n if (!args) return ''\n return Object.entries(args)\n .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)\n .join('\\n')\n}\n\nexport const ExecutionSteps: FC<ExecutionStepsProps> = ({\n loading,\n hasContent,\n thinking,\n thinkingComplete = true,\n thinkingDuration,\n searching,\n searchResults,\n toolCalls,\n}) => {\n // 判断是否有任何执行步骤\n const hasSteps =\n thinking ||\n searching ||\n (searchResults && searchResults.length > 0) ||\n (toolCalls && toolCalls.length > 0) ||\n (loading && !hasContent)\n\n if (!hasSteps) return null\n\n return (\n <div className=\"execution-steps\">\n {/* 正在规划 */}\n {loading && !hasContent && !thinking && !searching && (!toolCalls || toolCalls.length === 0) && (\n <StepItem\n icon={<Sparkles size={14} />}\n title=\"正在规划下一步...\"\n status=\"running\"\n />\n )}\n\n {/* 思考过程 */}\n {thinking && (\n <StepItem\n icon={<Sparkles size={14} />}\n title={thinkingComplete ? '思考完成' : '思考中...'}\n status={thinkingComplete ? 'completed' : 'running'}\n extra={thinkingDuration ? `${thinkingDuration}s` : undefined}\n detail={thinking}\n />\n )}\n\n {/* 搜索 */}\n {(searching || (searchResults && searchResults.length > 0)) && (\n <StepItem\n icon={<Globe size={14} />}\n title={searching ? '搜索中...' : `搜索完成 ${searchResults?.length || 0} 条结果`}\n status={searching ? 'running' : 'completed'}\n detail={\n searchResults && searchResults.length > 0 ? (\n <div>\n {searchResults.map((result, i) => (\n <a\n key={i}\n href={result.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"search-result-item\"\n >\n <div className=\"search-result-title\">\n <span>{result.title}</span>\n <ExternalLink size={12} style={{ opacity: 0.5 }} />\n </div>\n <div className=\"search-result-snippet\">{result.snippet}</div>\n </a>\n ))}\n </div>\n ) : undefined\n }\n />\n )}\n\n {/* 工具调用 */}\n {toolCalls &&\n toolCalls.map((call, index) => (\n <StepItem\n key={`tool-${index}`}\n icon={getToolIcon(call.name)}\n title={`${getToolDisplayName(call.name)}${call.status === 'running' ? '...' : ''}`}\n status={call.status === 'running' ? 'running' : call.status === 'error' ? 'error' : 'completed'}\n detail={\n <div>\n {call.args && (\n <div style={{ marginBottom: call.result ? 8 : 0 }}>\n <div style={{ fontSize: 10, color: 'var(--chat-text-muted)', marginBottom: 4 }}>参数</div>\n <pre style={{ margin: 0 }}>{formatToolArgs(call.args)}</pre>\n </div>\n )}\n {call.result && (\n <div>\n <div style={{ fontSize: 10, color: 'var(--chat-text-muted)', marginBottom: 4 }}>结果</div>\n <pre style={{ margin: 0, maxHeight: 160, overflow: 'auto' }}>{call.result}</pre>\n </div>\n )}\n </div>\n }\n />\n ))}\n </div>\n )\n}\n","/**\n * ChatInput Component\n * 与 Vue 版本 ChatInput.vue 保持一致\n */\n\nimport { useState, useRef, useCallback, useEffect, type FC } from 'react'\nimport {\n X,\n ChevronDown,\n Check,\n Globe,\n Sparkles,\n ImageIcon,\n Square,\n ArrowUp,\n Zap,\n MessageCircle,\n AtSign,\n Mic,\n} from 'lucide-react'\nimport type { ChatMode, ModelConfig } from '../types'\nimport { DEFAULT_MODELS } from '../types'\n\ninterface ChatInputProps {\n /** 变体模式:input-底部输入框,message-历史消息 */\n variant?: 'input' | 'message'\n /** 受控值(用于历史消息编辑) */\n value?: string\n selectedImages?: string[]\n isLoading?: boolean\n mode?: ChatMode\n model?: string\n models?: ModelConfig[]\n webSearchEnabled?: boolean\n thinkingEnabled?: boolean\n onSend?: (text: string) => void\n onRemoveImage?: (index: number) => void\n onCancel?: () => void\n onUploadImage?: () => 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 MODES = [\n { value: 'agent' as const, label: 'Agent', Icon: Zap },\n { value: 'ask' as const, label: 'Ask', Icon: MessageCircle },\n]\n\nexport const ChatInput: FC<ChatInputProps> = ({\n variant = 'input',\n value = '',\n selectedImages = [],\n isLoading = false,\n mode = 'agent',\n model = '',\n models = DEFAULT_MODELS,\n webSearchEnabled = false,\n thinkingEnabled = false,\n onSend,\n onRemoveImage,\n onCancel,\n onUploadImage,\n onAtContext,\n onModeChange,\n onModelChange,\n onWebSearchChange,\n onThinkingChange,\n}) => {\n const isMessageVariant = variant === 'message'\n\n const [inputText, setInputText] = useState(value)\n const [isFocused, setIsFocused] = useState(false)\n const [modeMenuOpen, setModeMenuOpen] = useState(false)\n const [modelMenuOpen, setModelMenuOpen] = useState(false)\n\n const inputRef = useRef<HTMLTextAreaElement>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n // 同步外部 value\n useEffect(() => {\n setInputText(value)\n }, [value])\n\n const currentMode = MODES.find((m) => m.value === mode) || MODES[0]\n const currentModel = models.find((m) => m.model === model)\n\n // 是否显示工具栏\n const showToolbar = !isMessageVariant || isFocused\n\n // 预览\n const selectedPreview = selectedImages.slice(0, 3)\n\n // 占位符\n const placeholder = selectedImages.length > 0\n ? '描述你想要的效果...'\n : mode === 'ask'\n ? '有什么问题想问我?'\n : '描述任务,@ 添加上下文'\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 // 发送或取消\n const handleSendOrCancel = useCallback(() => {\n if (isLoading) {\n onCancel?.()\n return\n }\n\n const text = inputText.trim()\n if (!text) return\n\n onSend?.(text)\n\n if (!isMessageVariant) {\n setInputText('')\n if (inputRef.current) {\n inputRef.current.style.height = 'auto'\n }\n inputRef.current?.focus()\n } else {\n setIsFocused(false)\n }\n }, [isLoading, inputText, onSend, onCancel, isMessageVariant])\n\n // 键盘事件\n const handleKeydown = useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault()\n handleSendOrCancel()\n } else {\n setTimeout(adjustTextareaHeight, 0)\n }\n },\n [handleSendOrCancel, adjustTextareaHeight]\n )\n\n // 选择模式\n const selectMode = useCallback(\n (value: ChatMode) => {\n onModeChange?.(value)\n setModeMenuOpen(false)\n },\n [onModeChange]\n )\n\n // 选择模型\n const selectModel = useCallback(\n (m: ModelConfig) => {\n onModelChange?.(m.model)\n setModelMenuOpen(false)\n },\n [onModelChange]\n )\n\n // 图片 URL 处理\n const getImageUrl = (path: string): string => {\n if (\n path.startsWith('app://') ||\n path.startsWith('file://') ||\n path.startsWith('data:') ||\n path.startsWith('http')\n ) {\n return path\n }\n if (path.match(/^[A-Z]:\\\\/i)) {\n return `app://file${encodeURIComponent(path.replace(/\\\\/g, '/'))}`\n }\n return `app://file${encodeURIComponent(path)}`\n }\n\n // 点击外部关闭菜单\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as HTMLElement\n if (!target.closest('.selector')) {\n setModeMenuOpen(false)\n setModelMenuOpen(false)\n }\n if (\n isMessageVariant &&\n containerRef.current &&\n !containerRef.current.contains(target)\n ) {\n setIsFocused(false)\n }\n }\n\n document.addEventListener('click', handleClickOutside)\n return () => document.removeEventListener('click', handleClickOutside)\n }, [isMessageVariant])\n\n const CurrentModeIcon = currentMode.Icon\n\n return (\n <div className={`chat-input${isMessageVariant ? ' message-variant' : ''}`}>\n <div\n ref={containerRef}\n className={`input-container${isFocused ? ' focused' : ''}`}\n >\n {/* 附件预览 */}\n {selectedImages.length > 0 && (\n <div className=\"attachment-preview\">\n <div className=\"preview-images\">\n {selectedPreview.map((img, index) => (\n <div key={`${img}-${index}`} className=\"preview-item\">\n <img\n src={getImageUrl(img)}\n className=\"preview-thumb\"\n alt={`附件 ${index + 1}`}\n onError={(e) => {\n (e.target as HTMLImageElement).style.display = 'none'\n }}\n />\n {!isMessageVariant && (\n <button\n className=\"remove-btn\"\n title={`移除图片 ${index + 1}`}\n onClick={() => onRemoveImage?.(index)}\n >\n <X size={10} />\n </button>\n )}\n </div>\n ))}\n {selectedImages.length > 3 && (\n <div className=\"preview-more\">+{selectedImages.length - 3}</div>\n )}\n </div>\n </div>\n )}\n\n {/* 输入框 */}\n <div className=\"input-field-wrapper\">\n <textarea\n ref={inputRef}\n value={inputText}\n onChange={(e) => setInputText(e.target.value)}\n onKeyDown={handleKeydown}\n onInput={adjustTextareaHeight}\n onFocus={() => setIsFocused(true)}\n placeholder={placeholder}\n rows={1}\n className=\"input-field\"\n />\n </div>\n\n {/* 底部控制栏 */}\n {showToolbar && (\n <div className=\"input-controls\">\n {/* 左侧:模式和模型选择 */}\n <div className=\"input-left\">\n {/* 模式选择 */}\n <div\n className=\"selector mode-selector\"\n onClick={(e) => {\n e.stopPropagation()\n setModeMenuOpen(!modeMenuOpen)\n setModelMenuOpen(false)\n }}\n >\n <CurrentModeIcon size={12} />\n <span>{currentMode.label}</span>\n <ChevronDown size={10} className=\"chevron\" />\n\n {modeMenuOpen && (\n <div className=\"dropdown-menu\" onClick={(e) => e.stopPropagation()}>\n {MODES.map((m) => (\n <button\n key={m.value}\n className={`dropdown-item${mode === m.value ? ' active' : ''}`}\n onClick={() => selectMode(m.value)}\n >\n <m.Icon size={14} />\n <span>{m.label}</span>\n {mode === m.value && <Check size={14} className=\"check-icon\" />}\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* 模型选择 */}\n <div\n className=\"selector model-selector\"\n onClick={(e) => {\n e.stopPropagation()\n setModelMenuOpen(!modelMenuOpen)\n setModeMenuOpen(false)\n }}\n >\n <span>{currentModel?.displayName || 'Auto'}</span>\n <ChevronDown size={10} className=\"chevron\" />\n\n {modelMenuOpen && (\n <div className=\"dropdown-menu\" onClick={(e) => e.stopPropagation()}>\n {models.map((m) => (\n <button\n key={m.model}\n className={`dropdown-item${model === m.model ? ' active' : ''}`}\n onClick={() => selectModel(m)}\n >\n <span>{m.displayName}</span>\n {model === m.model && <Check size={14} className=\"check-icon\" />}\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* 右侧:功能按钮 */}\n <div className=\"input-right\">\n <button className=\"icon-btn\" title=\"提及上下文 (@)\" onClick={onAtContext}>\n <AtSign size={14} />\n </button>\n\n <button\n className={`toggle-btn${thinkingEnabled ? ' active' : ''}`}\n title=\"深度思考\"\n onClick={() => onThinkingChange?.(!thinkingEnabled)}\n >\n <Sparkles size={14} />\n </button>\n\n <button\n className={`toggle-btn${webSearchEnabled ? ' active' : ''}`}\n title=\"联网搜索\"\n onClick={() => onWebSearchChange?.(!webSearchEnabled)}\n >\n <Globe size={14} />\n </button>\n\n <button className=\"icon-btn\" title=\"上传图片\" onClick={onUploadImage}>\n <ImageIcon size={14} />\n </button>\n\n {inputText.trim() || isLoading ? (\n <button\n className={`send-btn${isLoading ? ' loading' : ''}`}\n title={isLoading ? '停止' : isMessageVariant ? '重新发送' : '发送'}\n onClick={handleSendOrCancel}\n >\n {isLoading ? <Square size={14} /> : <ArrowUp size={14} />}\n </button>\n ) : (\n <button className=\"icon-btn\" title=\"语音输入\">\n <Mic size={14} />\n </button>\n )}\n </div>\n </div>\n )}\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["useEffect","useRef","useCallback","FileType","useState","useRef","useCallback","jsx","jsxs","Check","useState","Terminal","Trash2","Video","jsx","jsxs","useState","useRef","useCallback","useEffect","X","ChevronDown","Globe","Sparkles","ImageIcon","jsx","jsxs","useState","useRef","useEffect","useCallback","value","X","ChevronDown","Sparkles","Globe","ImageIcon","jsx","jsxs","Check","jsx","jsxs","useRef","useEffect","useCallback"]}
|
|
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/parts/CollapsibleCard.tsx","../src/components/message/parts/TextPart.tsx","../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/ToolResultPart.tsx","../src/components/message/parts/ImagePart.tsx","../src/components/message/parts/ErrorPart.tsx","../src/components/message/PartsRenderer.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/components/common/ConfirmDialog.tsx","../src/components/common/Toast.tsx","../src/components/common/SettingsPanel.tsx","../src/components/common/IndexingSettings.tsx","../src/components/message/ContentRenderer.tsx","../src/components/message/blocks/TextBlock.tsx","../src/components/message/blocks/CodeBlock.tsx","../src/components/message/ToolResultRenderer.tsx","../src/components/message/tool-results/DefaultToolResult.tsx","../src/components/message/tool-results/WeatherCard.tsx","../src/components/message/tool-results/SearchResults.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/** 搜索结果 */\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 */\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 */\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' // pending: 等待用户批准, cancelled: 已取消, skipped: 已跳过\n result: unknown | null // 执行结果,null 表示尚未执行或没有结果\n}\n\n/** 工具结果 Part - 用于自定义 UI 渲染(备用,主要使用 ToolCallPart) */\nexport interface ToolResultPart {\n type: 'tool_result'\n id: string\n name: string\n args?: Record<string, unknown>\n result: unknown // 解析后的结构化数据\n status: 'done' | 'error' | 'cancelled' | 'skipped'\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 联合类型 */\nexport type ContentPart =\n | TextPart\n | ThinkingPart\n | SearchPart\n | ToolCallPart\n | ToolResultPart\n | ImagePart\n | ErrorPart\n\n/** 内容 Part 类型字符串 */\nexport type ContentPartType = ContentPart['type']\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?: Date\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\n/** @deprecated 使用 ContentPart 替代 */\nexport type ExecutionStepType = 'thinking' | 'search' | 'tool_call' | 'error'\n\n/** @deprecated 使用 ContentPart 替代 */\nexport type ExecutionStepStatus = 'running' | 'completed' | 'error'\n\n/** @deprecated 使用 ContentPart 替代 */\nexport type ExecutionStep = {\n id: string\n type: ExecutionStepType\n status: ExecutionStepStatus\n startedAt?: number\n completedAt?: number\n duration?: number\n content?: string\n query?: string\n results?: SearchResult[]\n callId?: string\n name?: string\n args?: Record<string, unknown>\n result?: string\n message?: string\n category?: string\n}\n\n/** @deprecated 使用 ContentPart 替代 - 思考步骤类型 */\nexport type ThinkingStep = ExecutionStep & {\n type: 'thinking'\n status: 'running' | 'completed'\n}\n\n/** @deprecated 使用 ContentPart 替代 - 搜索步骤类型 */\nexport type SearchStep = ExecutionStep & {\n type: 'search'\n status: 'running' | 'completed'\n}\n\n/** @deprecated 使用 ContentPart 替代 - 工具调用步骤类型 */\nexport type ToolCallStep = ExecutionStep & {\n type: 'tool_call'\n status: 'running' | 'completed' | 'error'\n}\n\n/** @deprecated 使用 ContentPart 替代 - 错误步骤类型 */\nexport type ErrorStep = ExecutionStep & {\n type: 'error'\n status: 'error'\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,\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 ToolResultPart,\n ErrorPart,\n SearchResult,\n} from '../types'\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 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 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 })\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 model: record.model || undefined,\n mode: record.mode || undefined,\n webSearchEnabled: record.webSearchEnabled ?? undefined,\n thinkingEnabled: record.thinkingEnabled ?? undefined,\n loading: false,\n timestamp: record.timestamp,\n }\n}\n\n/** 会话状态 */\ninterface SessionState {\n messages: ChatMessage[]\n isLoading: boolean\n abortController: AbortController | 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 // 默认配置\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 useEffect(() => {\n loadAutoRunConfig()\n }, [loadAutoRunConfig])\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 })\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 setCurrentSessionId(list[0].id)\n // 加载消息\n const state = getSessionState(list[0].id)\n if (state.messages.length === 0) {\n const savedMessages = await adapter.getMessages(list[0].id)\n state.messages = savedMessages.map(convertToMessage)\n forceUpdate()\n }\n // 同步配置\n setModeState(list[0].mode)\n setModelState(list[0].model)\n setWebSearchState(list[0].webSearchEnabled)\n setThinkingState(list[0].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 })\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 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] = { ...part, text: part.text + data.content }\n } else {\n parts.push({ type: 'thinking', text: data.content, status: 'running' })\n }\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 parts.push({ type: 'search', query: data.query, status: 'running' })\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.findLastIndex(\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', result: null }\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 result: null,\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.findLastIndex(\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', result: null }\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 result: null,\n })\n }\n break\n }\n\n case 'tool_call_result': {\n const data = event.data as { id: string; name: string; result: string; success: boolean }\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,而不是转换为 tool_result\n const toolCall = parts[toolCallIndex] as ToolCallPart\n parts[toolCallIndex] = {\n ...toolCall,\n result: parsedResult,\n status,\n }\n } else {\n // 如果没有对应的 tool_call,创建一个新的 tool_call(而不是 tool_result)\n parts.push({\n type: 'tool_call',\n id: data.id,\n name: data.name,\n args: {},\n result: parsedResult,\n status,\n })\n }\n \n // 移除可能存在的独立 tool_result(如果有的话)\n const existingResultIndex = parts.findIndex(\n p => p.type === 'tool_result' && (p as ToolResultPart).id === data.id\n )\n if (existingResultIndex >= 0) {\n parts.splice(existingResultIndex, 1)\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 '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 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 === 'search' && (lastPart as SearchPart).status === 'done') ||\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 const sendMessage = useCallback(async (text: string, images?: string[]) => {\n if (!text.trim()) 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 })\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: new Date(),\n }\n state.messages = [...state.messages, userMsg]\n forceUpdate()\n\n try {\n await adapter.saveMessage({\n sessionId,\n role: 'user',\n content: text,\n })\n\n if (state.messages.length === 1) {\n const title = text.slice(0, 20) + (text.length > 20 ? '...' : '')\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: new Date(),\n }\n state.messages = [...state.messages, assistantMsg]\n \n // 创建本次请求专用的 abortController(避免多请求竞态条件)\n const requestAbortController = new AbortController()\n state.isLoading = true\n state.abortController = requestAbortController\n forceUpdate()\n \n const sendModel = modelRef.current\n const sendMode = modeRef.current\n const sendWebSearch = webSearchRef.current\n const sendThinking = thinkingRef.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 content: extractTextContent(msg.parts),\n }))\n \n for await (const event of adapter.sendMessage(\n text,\n {\n mode: sendMode,\n model: sendModel,\n enableWebSearch: sendWebSearch,\n thinkingMode: sendThinking ? 'enabled' : 'disabled',\n autoRunConfig,\n history, // 传递历史消息\n },\n images,\n sessionId // 传递 sessionId 用于事件过滤\n )) {\n // 使用本次请求专用的 abortController 检查(避免被新请求覆盖)\n if (requestAbortController.signal.aborted) break\n\n updateSessionMessage(sessionId, assistantMsgIndex, event)\n\n // 【关键】在重要事件后增量保存到数据库\n const shouldSave = \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 if (shouldSave) {\n await saveMessageProgress()\n }\n\n if (event.type === 'done' || event.type === 'error') {\n break\n }\n }\n } catch (error) {\n console.error('发送消息失败:', error)\n updateSessionMessage(sessionId, assistantMsgIndex, {\n type: 'error',\n data: { message: error instanceof Error ? error.message : String(error) },\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 saveMessageProgress()\n\n state.abortController = null\n forceUpdate()\n }\n }, [adapter, getSessionState, updateSessionMessage, forceUpdate])\n\n // ==================== 其他方法 ====================\n const cancelRequest = useCallback(() => {\n if (!currentSessionIdRef.current) return\n const state = sessionStatesRef.current.get(currentSessionIdRef.current)\n if (state) {\n state.abortController?.abort()\n state.isLoading = false\n forceUpdate()\n }\n adapter.cancel()\n }, [adapter, forceUpdate])\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 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 userMsg = state.messages[messageIndex - 1]\n const userText = extractTextContent(userMsg.parts)\n state.messages = state.messages.slice(0, messageIndex - 1)\n forceUpdate()\n sendMessage(userText, userMsg.images)\n }\n }, [sendMessage, forceUpdate])\n\n /** 从指定索引重新发送消息(编辑后重发) */\n const resendFromIndex = useCallback((index: number, text: string) => {\n if (!currentSessionIdRef.current) return\n const state = sessionStatesRef.current.get(currentSessionIdRef.current)\n if (!state) return\n\n state.messages = state.messages.slice(0, index)\n forceUpdate()\n sendMessage(text)\n }, [sendMessage, forceUpdate])\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","/**\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 * 渲染器上下文\n * 用于注入自定义块渲染器和工具结果渲染器\n */\n\nimport { createContext, type ComponentType, type ReactNode, type FC } from 'react'\nimport type { ContentBlock, ToolRendererProps } from '@huyooo/ai-chat-shared'\n\n/** 块渲染器映射 */\nexport type BlockRenderers = Record<string, ComponentType<{ block: ContentBlock }>>\n\n/** 工具结果渲染器映射 */\nexport type ToolRenderers = Record<string, ComponentType<ToolRendererProps>>\n\n/** 块渲染器上下文 */\nexport const BlockRenderersContext = createContext<BlockRenderers>({})\n\n/** 工具结果渲染器上下文 */\nexport const ToolRenderersContext = createContext<ToolRenderers>({})\n\n/** 渲染器 Provider Props */\ninterface RenderersProviderProps {\n blockRenderers?: BlockRenderers\n toolRenderers?: ToolRenderers\n children: ReactNode\n}\n\n/** 渲染器 Provider */\nexport const RenderersProvider: FC<RenderersProviderProps> = ({\n blockRenderers = {},\n toolRenderers = {},\n children,\n}) => {\n return (\n <BlockRenderersContext.Provider value={blockRenderers}>\n <ToolRenderersContext.Provider value={toolRenderers}>\n {children}\n </ToolRenderersContext.Provider>\n </BlockRenderersContext.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 { ChatAdapter, ModelOption, ChatMode } from '@huyooo/ai-chat-bridge-electron/renderer'\nimport type { AutoRunConfig } from '@huyooo/ai-chat-bridge-electron/renderer'\nimport type { ToolRendererProps } from '@huyooo/ai-chat-shared'\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 { RenderersProvider } 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 /** 自定义工具结果渲染器 - 根据工具名称选择渲染组件 */\n toolRenderers?: Record<string, ComponentType<ToolRendererProps>>\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 toolRenderers = {},\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 const SCROLL_THRESHOLD = 100\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 setMode,\n setModel,\n setWebSearch,\n setThinking,\n setWorkingDirectory,\n autoRunConfig,\n saveAutoRunConfig,\n } = useChat({\n adapter,\n defaultModel,\n defaultMode,\n onToolComplete,\n })\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 setShouldAutoScroll(isNearBottom())\n }, [isNearBottom])\n\n // 滚动到底部\n const scrollToBottom = useCallback((force = false) => {\n if (messagesRef.current && (force || shouldAutoScroll)) {\n messagesRef.current.scrollTop = messagesRef.current.scrollHeight\n setShouldAutoScroll(true)\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) => {\n sendMessage(text)\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 // 删除当前消息及后续消息,然后重新发送\n // 这里简化处理,实际需要更完善的逻辑\n sendMessage(text)\n },\n [sendMessage]\n )\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 // 模式变更现在在 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 <RenderersProvider blockRenderers={{}} toolRenderers={toolRenderers}>\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 onChange={handleSaveSettings}\n onClose={() => setSettingsPanelVisible(false)}\n />\n\n {/* 顶部标题栏 */}\n {!hideHeader && (\n <ChatHeader\n sessions={sessions}\n currentSessionId={currentSessionId}\n showClose={!!onClose}\n onNewSession={createNewSession}\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 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 </RenderersProvider>\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 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 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.text) || \n p.type === 'tool_result' ||\n p.type === 'thinking' ||\n p.type === 'search'\n )\n }, [parts])\n\n // loading 状态:决定显示什么类型的指示器\n // cursor: 闪烁光标(文本流式输出时)\n // text: 文字提示(等待状态时)\n // none: 不显示\n const loadingState = useMemo<{ type: 'cursor' | 'text' | 'none'; text?: string }>(() => {\n if (!loading) {\n return { type: 'none' }\n }\n \n if (parts.length === 0) {\n return { type: 'text', text: '正在思考...' }\n }\n \n const lastPart = parts[parts.length - 1]\n \n // 文本流式输出 → 不需要额外指示,用户能看到文字在增加\n if (lastPart.type === 'text') {\n return { type: 'none' }\n }\n \n // 工具调用完成后 → 显示规划提示\n if (lastPart.type === 'tool_call') {\n const status = (lastPart as ToolCallPart).status\n if (status === 'done' || status === 'error' || status === 'skipped') {\n return { type: 'text', text: '正在规划下一步...' }\n }\n // 工具正在执行时,卡片本身有状态,不需要额外指示\n return { type: 'none' }\n }\n \n // 搜索完成后 → 显示规划提示\n if (lastPart.type === 'search') {\n if ((lastPart as SearchPart).status === 'done') {\n return { type: 'text', text: '正在规划下一步...' }\n }\n return { type: 'none' }\n }\n \n // 思考完成后 → 显示规划提示\n if (lastPart.type === 'thinking') {\n if ((lastPart as ThinkingPart).status === 'done') {\n return { type: 'text', text: '正在规划下一步...' }\n }\n return { type: 'none' }\n }\n \n return { type: 'none' }\n }, [loading, parts])\n\n return (\n <div className={`message-bubble ${role}`}>\n {/* 用户消息 */}\n {isUser ? (\n onSend && inputContext ? (\n <ChatInput\n variant=\"message\"\n value={userText}\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 autoRunConfig={autoRunConfig}\n onSaveConfig={onSaveConfig}\n />\n \n {/* 加载指示器:等待状态时显示 */}\n {loadingState.type === 'text' && (\n <div className=\"loading-indicator\">\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 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 className=\"card-header-left\" onClick={() => onExpandedChange(!expanded)}>\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 type { FC } from 'react'\nimport { renderMarkdown } from '@huyooo/ai-chat-shared'\nimport './TextPart.css'\n\ninterface TextPartProps {\n text: string\n}\n\nexport const TextPart: FC<TextPartProps> = ({ text }) => {\n if (!text) return null\n \n const html = renderMarkdown(text)\n \n return (\n <div \n className=\"text-part markdown-content\" \n dangerouslySetInnerHTML={{ __html: html }}\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 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 status: 'pending' | 'running' | 'done' | 'error' | 'cancelled' | 'skipped'\n result: unknown | null\n expandedType?: StepsExpandedType\n // 通过 props 传递,不使用 context\n adapter?: ChatAdapter\n autoRunConfig?: AutoRunConfig\n onSaveConfig?: (config: AutoRunConfig) => Promise<void>\n}\n\n// 模式选项\nconst modeOptions = [\n { value: 'manual', label: '执行前询问我' },\n { value: 'run-everything', label: '自动执行' },\n]\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\n// 状态颜色映射\nconst statusColors: Record<string, string> = {\n error: 'var(--chat-error, #ef4444)',\n done: 'var(--chat-success, #22c55e)',\n cancelled: 'var(--chat-warning, #f59e0b)',\n skipped: 'var(--chat-text-muted, #888)',\n running: 'var(--chat-accent, #3b82f6)',\n pending: 'var(--chat-text-muted, #888)',\n}\n\n// 状态显示图标\nconst statusDisplayIcons: Record<string, string> = {\n done: 'lucide:check-circle-2',\n error: 'lucide:x-circle',\n running: 'lucide:loader-2',\n pending: 'lucide:clock',\n cancelled: 'lucide:ban',\n skipped: 'lucide:skip-forward',\n}\n\n// 状态文本\nconst statusTexts: Record<string, string> = {\n done: '成功',\n error: '错误',\n running: '运行中',\n pending: '等待中',\n cancelled: '已取消',\n skipped: '已跳过',\n}\n\nexport const ToolCallPart: FC<ToolCallPartProps> = ({\n id,\n name,\n args,\n status,\n result,\n expandedType = 'auto',\n adapter,\n autoRunConfig,\n onSaveConfig,\n}) => {\n // 当前模式:直接从配置读取\n const currentMode = autoRunConfig?.mode ?? 'run-everything'\n\n // 命令显示\n const commandDisplay = useMemo(() => {\n if (name === 'execute_command' && args?.command) {\n const cmd = String(args.command)\n const parts = cmd.trim().split(/\\s+/)\n return parts.slice(0, 3).join(' ') + (parts.length > 3 ? '...' : '')\n }\n return name\n }, [name, args])\n\n const commandText = 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 return JSON.stringify(args, null, 2)\n } catch {\n return String(args)\n }\n }\n return name\n }, [name, args])\n\n // 格式化执行结果\n const formattedResult = useMemo(() => {\n if (result === null) return ''\n if (typeof result === 'string') return result\n try {\n return JSON.stringify(result, null, 2)\n } catch {\n return String(result)\n }\n }, [result])\n\n // 折叠状态\n const getInitialExpanded = (): boolean => {\n if (expandedType === 'open') return true\n if (expandedType === 'close') return false\n return status === 'pending' || status === 'running'\n }\n\n const [expanded, setExpanded] = useState(getInitialExpanded)\n\n // auto 模式下:状态变化时自动折叠/展开\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 \n try {\n await onSaveConfig({\n ...autoRunConfig,\n mode: value as AutoRunMode,\n })\n } catch (error) {\n console.error('[ToolCallPart] 保存配置失败:', error)\n }\n }, [onSaveConfig, autoRunConfig])\n\n /** 跳过执行:只拒绝当前工具,AI 继续思考 */\n const handleSkip = useCallback(async () => {\n if (!adapter?.respondToolApproval) return\n \n try {\n // 只拒绝工具执行,不取消整个请求\n // AI 会收到\"用户跳过了此工具\"的反馈,然后可能:\n // 1. 尝试其他工具/方法\n // 2. 直接回复用户\n // 3. 询问用户想要什么\n await adapter.respondToolApproval(id, false)\n } catch (error) {\n console.error('[ToolCallPart] 跳过失败:', error)\n }\n }, [adapter, id])\n\n /** 运行执行 */\n const handleRun = useCallback(async () => {\n if (!adapter?.respondToolApproval) return\n \n try {\n await adapter.respondToolApproval(id, true)\n } catch (error) {\n console.error('[ToolCallPart] 运行失败:', error)\n }\n }, [adapter, id])\n\n /** 取消执行 */\n const handleCancel = useCallback(() => {\n adapter?.cancel?.()\n }, [adapter])\n\n // 监听模式变化:从 manual 切换到 run-everything 时,自动执行 pending 的工具\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\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={\n <CopyButton text={commandText} title=\"复制\" />\n }\n >\n <div className=\"tool-call-content\">\n {/* 命令显示区域 */}\n <div className=\"tool-call-command\">\n <div className=\"command-header\">\n <span className=\"command-label\">执行:</span>\n <span className=\"command-name\">{commandDisplay}</span>\n </div>\n <code className=\"command-code\">{commandText}</code>\n </div>\n\n {/* 执行结果(如果有) */}\n {result !== null && (\n <div className=\"tool-call-result\">\n <div className=\"result-header\">\n <span className=\"result-label\">结果:</span>\n <span className=\"result-name\"></span>\n </div>\n <code className=\"result-content\">{formattedResult}</code>\n </div>\n )}\n\n {/* 底部操作区域 */}\n <div className=\"tool-call-footer\">\n {/* 左侧:模式选择(始终可用,切换后影响后续操作) */}\n <div className=\"footer-left\">\n <DropdownSelector\n value={currentMode}\n options={modeOptions}\n onSelect={handleModeChange}\n />\n </div>\n\n {/* 右侧:执行状态或按钮 */}\n <div className=\"footer-right\">\n {/* pending 状态:显示跳过/运行按钮 */}\n {status === 'pending' ? (\n <div className=\"action-buttons\">\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 </div>\n ) : status === 'running' ? (\n /* running 状态:显示运行中状态 + 取消按钮 */\n <>\n <div className=\"execution-status running\">\n <Icon icon=\"lucide:loader-2\" width={14} className=\"spinning\" />\n <span>运行中</span>\n </div>\n <button className=\"btn btn-cancel\" onClick={handleCancel}>\n <Icon icon=\"lucide:x\" width={14} />\n 取消\n </button>\n </>\n ) : (\n /* done/error 状态:只显示状态 */\n <div className={`execution-status ${status}`}>\n <Icon icon={statusDisplayIcons[status] ?? 'lucide:clock'} width={14} />\n <span>{statusTexts[status] ?? ''}</span>\n </div>\n )}\n </div>\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 } 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}\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 [menuOpen, setMenuOpen] = useState(false);\n const [dropdownDirection, setDropdownDirection] = useState<'up' | 'down'>('up');\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 * 点击外部关闭菜单\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 <button\n key={opt.value}\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 ))}\n </div>\n ))}\n </>\n ) : (\n /* 扁平列表模式:无分组数据时使用 */\n sortedOptions.map((opt) => (\n <button\n key={opt.value}\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 ))\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, useContext, useMemo, type FC, type ComponentType } from 'react'\nimport { Icon } from '@iconify/react'\nimport { ToolRenderersContext } from '../../../context/RenderersContext'\nimport type { ToolRendererProps } from '@huyooo/ai-chat-shared'\nimport type { StepsExpandedType } from '../../../types'\nimport './ToolResultPart.css'\n\ninterface ToolResultPartProps {\n id: string\n name: string\n args?: Record<string, unknown>\n result: unknown\n status: 'done' | 'error' | 'cancelled' | 'skipped'\n expandedType?: StepsExpandedType\n}\n\nexport const ToolResultPart: FC<ToolResultPartProps> = ({ \n name, \n args, \n result, \n status,\n expandedType = 'auto'\n}) => {\n const toolRenderers = useContext(ToolRenderersContext)\n \n // 根据模式计算初始状态(工具结果完成后默认折叠,除非 mode 是 open)\n const getInitialExpanded = () => {\n if (expandedType === 'open') return true\n return false // close 和 auto 模式下默认折叠\n }\n \n const [expanded, setExpanded] = useState(getInitialExpanded)\n\n // 获取自定义渲染器\n const CustomRenderer = useMemo(() => {\n return toolRenderers[name] as ComponentType<ToolRendererProps> | undefined\n }, [toolRenderers, name])\n\n // 格式化结果\n const formattedResult = useMemo(() => {\n if (typeof result === 'string') {\n return result\n }\n return JSON.stringify(result, null, 2)\n }, [result])\n\n // 将 ToolResultPart 的 status 映射到 ToolRendererProps 的 status\n const rendererStatus = useMemo((): 'running' | 'completed' | 'error' => {\n if (status === 'error') return 'error'\n if (status === 'cancelled') return 'error'\n // 'done' 和 'skipped' 都映射为 'completed'\n return 'completed'\n }, [status])\n\n // 如果有自定义渲染器,使用它\n if (CustomRenderer) {\n return (\n <div className=\"tool-result-part\">\n <CustomRenderer \n toolName={name}\n toolArgs={args || {}}\n toolResult={result}\n status={rendererStatus}\n />\n </div>\n )\n }\n\n // 默认渲染:可折叠的 JSON\n return (\n <div className=\"tool-result-part\">\n <div className={`default-result ${expanded ? 'expanded' : ''}`}>\n <div className=\"result-header\" onClick={() => setExpanded(!expanded)}>\n <div className=\"result-icon\">\n {status === 'error' ? (\n <Icon icon=\"lucide:x-circle\" width={14} className=\"error\" />\n ) : (\n <Icon icon=\"lucide:check-circle\" width={14} className=\"success\" />\n )}\n </div>\n <span className=\"result-name\">{name}</span>\n <Icon \n icon={expanded ? 'lucide:chevron-up' : 'lucide:chevron-down'} \n width={14} \n className=\"result-chevron\"\n />\n </div>\n {expanded && (\n <div className=\"result-content\">\n <pre>{formattedResult}</pre>\n </div>\n )}\n </div>\n </div>\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","import type { FC } from 'react'\nimport type { ContentPart, StepsExpandedType } from '../../types'\nimport type { ChatAdapter } from '../../adapter'\nimport type { AutoRunConfig } from '@huyooo/ai-chat-bridge-electron/renderer'\nimport { \n TextPart, \n ThinkingPart, \n SearchPart, \n ToolCallPart, \n ToolResultPart, \n ImagePart,\n ErrorPart \n} from './parts'\nimport './PartsRenderer.css'\n\ninterface PartsRendererProps {\n parts: ContentPart[]\n expandedType?: StepsExpandedType\n // 工具调用相关\n adapter?: ChatAdapter\n autoRunConfig?: AutoRunConfig\n onSaveConfig?: (config: AutoRunConfig) => Promise<void>\n}\n\nexport const PartsRenderer: FC<PartsRendererProps> = ({ \n parts,\n expandedType = 'auto',\n adapter,\n autoRunConfig,\n onSaveConfig,\n}) => {\n return (\n <div className=\"parts-renderer\">\n {parts.map((part, index) => {\n switch (part.type) {\n case 'text':\n return <TextPart key={index} text={part.text} />\n \n case 'thinking':\n return (\n <ThinkingPart \n key={index}\n text={part.text}\n status={part.status}\n duration={part.duration}\n expandedType={expandedType}\n />\n )\n \n case 'search':\n return (\n <SearchPart \n key={index}\n query={part.query}\n results={part.results}\n status={part.status}\n expandedType={expandedType}\n />\n )\n \n case 'tool_call':\n return (\n <ToolCallPart \n key={index}\n id={part.id}\n name={part.name}\n args={part.args}\n status={part.status}\n result={part.result}\n expandedType={expandedType}\n adapter={adapter}\n autoRunConfig={autoRunConfig}\n onSaveConfig={onSaveConfig}\n />\n )\n \n case 'tool_result':\n return (\n <ToolResultPart \n key={index}\n id={part.id}\n name={part.name}\n args={part.args}\n result={part.result}\n status={part.status}\n expandedType={expandedType}\n />\n )\n \n case 'image':\n return (\n <ImagePart \n key={index}\n url={part.url}\n />\n )\n \n case 'error':\n return (\n <ErrorPart \n key={index}\n message={part.message}\n category={part.category}\n retryable={part.retryable}\n />\n )\n \n default:\n return null\n }\n })}\n </div>\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, GroupedOptions } from './DropdownSelector';\nimport { useChatInputContext } from '../../context/ChatInputContext';\nimport { useImageUpload } from '../../hooks/useImageUpload';\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 isLoading?: boolean;\n mode?: ChatMode;\n model?: string;\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 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 // 将模型列表转换为分组格式(完全使用后端返回的 group 字段)\n const groupedModelOptions = useMemo<GroupedOptions>(() => {\n const groups: Record<string, Array<{ value: string; label: string; icon?: string }>> = {};\n \n models.forEach((m) => {\n // 完全使用后端返回的 group 字段\n const groupName = m.group;\n \n if (!groups[groupName]) {\n groups[groupName] = [];\n }\n \n groups[groupName].push({\n value: m.modelId,\n label: m.displayName,\n });\n });\n \n // 对每个分组内的选项进行排序\n Object.keys(groups).forEach(groupName => {\n groups[groupName].sort((a, b) => a.label.localeCompare(b.label));\n });\n \n return groups;\n }, [models]);\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 // 是否显示工具栏\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 // 自动调整高度\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 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 (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSendOrCancel();\n }\n },\n [handleSendOrCancel]\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' : ''}`.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 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 groupedOptions={groupedModelOptions}\n onSelect={(v) => onModelChange?.(v)} \n />\n </div>\n\n {/* 右侧 */}\n <div className=\"input-right\">\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 <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 <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 {hasContent || isLoading ? (\n <button\n className={`send-btn${isLoading ? ' loading' : ''}`}\n title={isLoading ? '停止' : isMessageVariant ? '重新发送' : '发送'}\n onClick={handleSendOrCancel}\n >\n {isLoading ? (\n <Icon icon=\"streamline-flex:button-pause-circle-remix\" width={18} />\n ) : (\n <Icon icon=\"streamline-flex:mail-send-email-message-circle-remix\" width={18} />\n )}\n </button>\n ) : (\n <button className=\"icon-btn\" title=\"语音输入\">\n <Icon icon=\"lucide:mic\" width={18} />\n </button>\n )}\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}\n\n/**\n * 图片上传 hook\n * @param options 配置项\n */\nexport function useImageUpload(options: UseImageUploadOptions = {}) {\n const { maxImages = 5, maxSize = 10 * 1024 * 1024 } = 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 * 读取图片文件为 base64\n */\n const readImageFile = useCallback((file: File): Promise<ImageItem> => {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const dataUrl = reader.result as string;\n // dataUrl 格式: data:image/png;base64,xxxxx\n const base64 = dataUrl.split(',')[1];\n resolve({\n dataUrl,\n base64,\n mimeType: file.type,\n });\n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n }, []);\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 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 };\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 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, 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 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\n {/* 索引与文档设置 */}\n {currentSection === 'indexing' && (\n <IndexingSettings />\n )}\n </div>\n </div>\n </div>\n </div>\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 * 内容渲染器\n * 将原始文本解析为内容块并渲染\n */\n\nimport { FC, useMemo, useContext, type ComponentType } from 'react'\nimport { parseContent } from '@huyooo/ai-chat-shared'\nimport type { ContentBlock } from '@huyooo/ai-chat-shared'\nimport { TextBlock, CodeBlock } from './blocks'\nimport { BlockRenderersContext } from '../../context/RenderersContext'\nimport './ContentRenderer.css'\n\ninterface ContentRendererProps {\n /** 原始文本内容 */\n content: string\n /** 预解析的块列表(可选,用于流式更新) */\n blocks?: ContentBlock[]\n /** 代码复制事件 */\n onCodeCopy?: (code: string) => void\n}\n\nexport const ContentRenderer: FC<ContentRendererProps> = ({\n content,\n blocks: preBlocks,\n onCodeCopy,\n}) => {\n // 从上层获取自定义块渲染器\n const customRenderers = useContext(BlockRenderersContext)\n\n // 解析后的内容块\n const blocks = useMemo(() => {\n // 优先使用预解析的块\n if (preBlocks?.length) {\n return preBlocks\n }\n // 否则解析原始内容\n return parseContent(content)\n }, [content, preBlocks])\n\n if (!blocks.length) return null\n\n return (\n <div className=\"content-renderer\">\n {blocks.map((block) => {\n // 自定义块渲染器\n const CustomRenderer = customRenderers[block.type] as ComponentType<{ block: ContentBlock }>\n if (CustomRenderer) {\n return <CustomRenderer key={block.id} block={block} />\n }\n\n // 内置渲染器\n switch (block.type) {\n case 'text':\n return <TextBlock key={block.id} block={block} />\n case 'code':\n return <CodeBlock key={block.id} block={block} onCopy={onCodeCopy} />\n default:\n return null\n }\n })}\n </div>\n )\n}\n","/**\n * 文本块组件\n */\n\nimport { FC } from 'react'\nimport type { TextBlock as TextBlockType } from '@huyooo/ai-chat-shared'\nimport './blocks.css'\n\ninterface TextBlockProps {\n block: TextBlockType\n}\n\nexport const TextBlock: FC<TextBlockProps> = ({ block }) => {\n return <div className=\"text-block\">{block.content}</div>\n}\n","/**\n * 代码块组件\n */\n\nimport { FC, useState, useCallback, useMemo } from 'react'\nimport { Icon } from '@iconify/react'\nimport { highlightCode, getLanguageDisplayName } from '@huyooo/ai-chat-shared'\nimport type { CodeBlock as CodeBlockType } from '@huyooo/ai-chat-shared'\nimport './blocks.css'\n\ninterface CodeBlockProps {\n block: CodeBlockType\n onCopy?: (code: string) => void\n}\n\nexport const CodeBlock: FC<CodeBlockProps> = ({ block, onCopy }) => {\n const [copied, setCopied] = useState(false)\n\n // 语言显示名称\n const languageDisplay = useMemo(\n () => getLanguageDisplayName(block.language),\n [block.language]\n )\n\n // 高亮后的代码\n const highlightedCode = useMemo(\n () => highlightCode(block.content, block.language),\n [block.content, block.language]\n )\n\n /** 复制代码 */\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(block.content)\n setCopied(true)\n onCopy?.(block.content)\n setTimeout(() => setCopied(false), 2000)\n } catch (err) {\n console.error('复制失败:', err)\n }\n }, [block.content, onCopy])\n\n return (\n <div className=\"code-block\">\n {/* 头部:语言 + 操作按钮 */}\n <div className=\"code-header\">\n <span className=\"code-language\">{languageDisplay}</span>\n <div className=\"code-actions\">\n <button className=\"code-action-btn\" title=\"复制代码\" onClick={handleCopy}>\n <Icon icon={copied ? 'lucide:check' : 'lucide:copy'} width={14} />\n </button>\n </div>\n </div>\n {/* 代码内容 */}\n <pre className=\"code-content\">\n <code dangerouslySetInnerHTML={{ __html: highlightedCode }} />\n </pre>\n </div>\n )\n}\n","/**\n * 工具结果渲染器\n * 根据工具名称选择合适的渲染组件\n */\n\nimport { FC, useContext, useMemo, type ComponentType } from 'react'\nimport type { ToolRendererProps } from '@huyooo/ai-chat-shared'\nimport { ToolRenderersContext } from '../../context/RenderersContext'\nimport { DefaultToolResult } from './tool-results'\n\nexport const ToolResultRenderer: FC<ToolRendererProps> = (props) => {\n // 从上层获取自定义工具渲染器\n const customRenderers = useContext(ToolRenderersContext)\n\n // 解析使用哪个组件\n const Component = useMemo<ComponentType<ToolRendererProps>>(() => {\n return customRenderers[props.toolName] || DefaultToolResult\n }, [customRenderers, props.toolName])\n\n return <Component {...props} />\n}\n","/**\n * 默认工具结果渲染器\n */\n\nimport { FC, useMemo } from 'react'\nimport type { ToolRendererProps } from '@huyooo/ai-chat-shared'\nimport './tool-results.css'\n\nexport const DefaultToolResult: FC<ToolRendererProps> = ({ toolResult }) => {\n const formattedResult = useMemo(() => {\n if (typeof toolResult === 'string') {\n return toolResult\n }\n try {\n return JSON.stringify(toolResult, null, 2)\n } catch {\n return String(toolResult)\n }\n }, [toolResult])\n\n return (\n <div className=\"default-tool-result\">\n <pre className=\"result-content\">{formattedResult}</pre>\n </div>\n )\n}\n","/**\n * 天气卡片渲染器\n */\n\nimport { FC, useMemo } from 'react'\nimport { Icon } from '@iconify/react'\nimport type { ToolRendererProps, WeatherData } from '@huyooo/ai-chat-shared'\nimport './tool-results.css'\n\nexport const WeatherCard: FC<ToolRendererProps> = ({ toolResult }) => {\n const weather = useMemo<WeatherData>(() => {\n if (typeof toolResult === 'object' && toolResult !== null) {\n return toolResult as WeatherData\n }\n return {\n city: '未知',\n temperature: 0,\n condition: '未知',\n }\n }, [toolResult])\n\n return (\n <div className=\"weather-card\">\n <div className=\"weather-header\">\n <Icon icon=\"lucide:cloud-sun\" width={24} className=\"weather-icon\" />\n <div className=\"weather-location\">{weather.city}</div>\n </div>\n <div className=\"weather-main\">\n <div className=\"weather-temp\">{weather.temperature}°</div>\n <div className=\"weather-condition\">{weather.condition}</div>\n </div>\n {(weather.humidity || weather.wind) && (\n <div className=\"weather-details\">\n {weather.humidity && (\n <div className=\"weather-detail\">\n <Icon icon=\"lucide:droplets\" width={14} />\n <span>{weather.humidity}%</span>\n </div>\n )}\n {weather.wind && (\n <div className=\"weather-detail\">\n <Icon icon=\"lucide:wind\" width={14} />\n <span>{weather.wind}</span>\n </div>\n )}\n </div>\n )}\n {weather.forecast?.length ? (\n <div className=\"weather-forecast\">\n {weather.forecast.map((item) => (\n <div key={item.date} className=\"forecast-item\">\n <div className=\"forecast-date\">{item.date}</div>\n <div className=\"forecast-temp\">\n {item.low}° / {item.high}°\n </div>\n <div className=\"forecast-condition\">{item.condition}</div>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n )\n}\n","/**\n * 搜索结果渲染器\n */\n\nimport { FC, useMemo, useCallback } from 'react'\nimport { Icon } from '@iconify/react'\nimport type { ToolRendererProps, SearchResultItem } from '@huyooo/ai-chat-shared'\nimport './tool-results.css'\n\nexport const SearchResults: FC<ToolRendererProps> = ({ toolResult }) => {\n const results = useMemo<SearchResultItem[]>(() => {\n if (Array.isArray(toolResult)) {\n return toolResult as SearchResultItem[]\n }\n if (typeof toolResult === 'object' && toolResult !== null && 'results' in toolResult) {\n return (toolResult as { results: SearchResultItem[] }).results\n }\n return []\n }, [toolResult])\n\n /** 获取域名 */\n const getDomain = useCallback((url: string): string => {\n try {\n return new URL(url).hostname\n } catch {\n return url\n }\n }, [])\n\n /** 打开外部链接 */\n const openExternal = useCallback((url: string) => {\n const bridge = (window as { aiChatBridge?: { openExternal: (url: string) => Promise<void> } })\n .aiChatBridge\n if (bridge?.openExternal) {\n bridge.openExternal(url)\n } else {\n window.open(url, '_blank')\n }\n }, [])\n\n return (\n <div className=\"search-results-card\">\n <div className=\"search-header\">\n <Icon icon=\"lucide:search\" width={16} />\n <span>搜索结果</span>\n <span className=\"search-count\">{results.length} 条</span>\n </div>\n <div className=\"search-list\">\n {results.map((item, index) => (\n <a\n key={index}\n href={item.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"search-item\"\n onClick={(e) => {\n e.preventDefault()\n openExternal(item.url)\n }}\n >\n <div className=\"item-title\">{item.title}</div>\n {item.snippet && <div className=\"item-snippet\">{item.snippet}</div>}\n <div className=\"item-url\">{getDomain(item.url)}</div>\n </a>\n ))}\n </div>\n </div>\n )\n}\n","/**\n * @huyooo/ai-chat-frontend-react\n *\n * AI Chat 前端组件库 - React 版本\n *\n * 新架构:使用 ContentPart 数组渲染消息内容\n * - 支持流式渲染\n * - 支持自定义工具结果 UI\n * - 支持思考、搜索、工具调用等多种内容类型\n */\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 ToolResultPart,\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// 渲染器上下文\nexport { RenderersProvider, BlockRenderersContext, ToolRenderersContext } from './context/RenderersContext'\nexport type { BlockRenderers, ToolRenderers } 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'\n\n// 内容渲染组件(保留,兼容旧代码)\nexport { ContentRenderer } from './components/message/ContentRenderer'\nexport { TextBlock, CodeBlock } from './components/message/blocks'\nexport { ToolResultRenderer } from './components/message/ToolResultRenderer'\nexport { DefaultToolResult, WeatherCard, SearchResults } from './components/message/tool-results'\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 ToolRendererProps,\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. 自定义工具渲染器:\n * import CustomWeatherCard from './CustomWeatherCard'\n * const toolRenderers = { get_weather: CustomWeatherCard }\n * <ChatPanel adapter={adapter} toolRenderers={toolRenderers} />\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":["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","Icon","jsx","jsxs","Icon","jsx","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","Fragment","jsx","jsxs","useMemo","useState","useEffect","useCallback","useRef","Icon","useState","useContext","useMemo","Icon","jsx","jsxs","useContext","useState","useMemo","Icon","useState","Icon","jsx","jsxs","useState","Icon","useState","jsx","useState","jsx","useState","useRef","useCallback","useEffect","forwardRef","useImperativeHandle","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","jsx","jsxs","forwardRef","useState","useRef","useCallback","useMemo","useEffect","useImperativeHandle","Icon","Fragment","jsx","jsxs","formatTime","useMemo","Icon","useEffect","createPortal","Icon","jsx","jsxs","useEffect","createPortal","Icon","useEffect","createPortal","jsx","useEffect","createPortal","useState","useCallback","useMemo","Icon","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","useMemo","useContext","jsx","useState","useCallback","useMemo","Icon","jsx","jsxs","useState","useMemo","useCallback","Icon","jsx","useContext","useMemo","useContext","useMemo","useMemo","jsx","useMemo","useMemo","Icon","jsx","jsxs","useMemo","Icon","useMemo","useCallback","Icon","jsx","jsxs","useMemo","useCallback","Icon","jsx","useContext","useMemo","parseContent","highlightCode","getLanguageDisplayName","renderMarkdown"]}
|