@huyooo/ai-chat-frontend-react 0.1.2 → 0.1.3

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/dist/index.d.ts CHANGED
@@ -1,9 +1,75 @@
1
+ import { ChatMode as ChatMode$1, ThinkingMode, ChatAdapter, ModelConfig as ModelConfig$1, SessionRecord as SessionRecord$1 } from '@huyooo/ai-chat-bridge-electron/renderer';
2
+ export { ChatAdapter, ChatMode, ChatOptions, ChatProgress, ChatProgressType, MessageRecord, ModelConfig, ModelProvider, SessionRecord, ThinkingMode, createElectronAdapter } from '@huyooo/ai-chat-bridge-electron/renderer';
1
3
  import { FC, ReactNode } from 'react';
2
4
 
5
+ /**
6
+ * Chat Adapter 辅助类型和工具
7
+ * 核心 ChatAdapter 接口从 bridge-electron 导入
8
+ */
9
+
10
+ /** 思考数据 */
11
+ interface ThinkingData {
12
+ content: string;
13
+ isComplete: boolean;
14
+ }
15
+ /** 工具调用数据 */
16
+ interface ToolCallData {
17
+ name: string;
18
+ args: Record<string, unknown>;
19
+ }
20
+ /** 工具结果数据 */
21
+ interface ToolResultData {
22
+ name: string;
23
+ result: string;
24
+ }
25
+ /** 图片数据 */
26
+ interface ImageData {
27
+ base64: string;
28
+ mimeType: string;
29
+ }
30
+ /** 发送消息选项 */
31
+ interface SendMessageOptions {
32
+ mode: ChatMode$1;
33
+ model: string;
34
+ enableWebSearch: boolean;
35
+ thinkingMode: ThinkingMode;
36
+ }
37
+ /** 创建会话选项 */
38
+ interface CreateSessionOptions {
39
+ title: string;
40
+ model: string;
41
+ mode: ChatMode$1;
42
+ }
43
+ /** 更新会话选项 */
44
+ interface UpdateSessionOptions {
45
+ title?: string;
46
+ model?: string;
47
+ mode?: ChatMode$1;
48
+ }
49
+ /** 保存消息选项 */
50
+ interface SaveMessageOptions {
51
+ sessionId: string;
52
+ role: 'user' | 'assistant';
53
+ content: string;
54
+ thinking?: string;
55
+ toolCalls?: string;
56
+ searchResults?: string;
57
+ }
58
+ /**
59
+ * 创建空 Adapter(用于测试或无后端场景)
60
+ * 返回一个最小实现的 ChatAdapter
61
+ */
62
+ declare function createNullAdapter(): ChatAdapter;
63
+
3
64
  /**
4
65
  * AI Chat 前端类型定义
5
- * Vue 版本保持一致
66
+ * 核心类型(ChatAdapter, SessionRecord, MessageRecord 等)从 bridge-electron 导出
67
+ * 这里只定义前端特有的类型
6
68
  */
69
+
70
+ type ChatMode = ChatMode$1;
71
+ type ModelConfig = ModelConfig$1;
72
+ type SessionRecord = SessionRecord$1;
7
73
  /** 搜索结果 */
8
74
  interface SearchResult {
9
75
  title: string;
@@ -17,22 +83,7 @@ interface ToolCall {
17
83
  result?: string;
18
84
  status: 'running' | 'success' | 'error';
19
85
  }
20
- /** 模型提供商 */
21
- type ModelProvider = 'openrouter' | 'doubao' | 'deepseek' | 'qwen' | 'gemini' | 'ark';
22
- /** 模型配置 */
23
- interface ModelConfig {
24
- provider: ModelProvider;
25
- model: string;
26
- displayName: string;
27
- supportsTools: boolean;
28
- supportsWebSearch: boolean;
29
- supportedThinkingModes: ThinkingMode[];
30
- }
31
- /** 思考模式 */
32
- type ThinkingMode = 'enabled' | 'disabled';
33
- /** 聊天模式 */
34
- type ChatMode = 'agent' | 'ask';
35
- /** 聊天消息 */
86
+ /** 聊天消息(前端显示用) */
36
87
  interface ChatMessage {
37
88
  id: string;
38
89
  role: 'user' | 'assistant';
@@ -47,28 +98,8 @@ interface ChatMessage {
47
98
  loading?: boolean;
48
99
  timestamp?: Date;
49
100
  }
50
- /** 会话记录 */
51
- interface SessionRecord {
52
- id: string;
53
- title: string;
54
- model: string;
55
- mode: ChatMode;
56
- createdAt: Date;
57
- updatedAt: Date;
58
- }
59
- /** 消息记录 */
60
- interface MessageRecord {
61
- id: string;
62
- sessionId: string;
63
- role: 'user' | 'assistant';
64
- content: string;
65
- thinking?: string;
66
- toolCalls?: string;
67
- searchResults?: string;
68
- timestamp: Date;
69
- }
70
101
  /** 默认模型列表 */
71
- declare const DEFAULT_MODELS: ModelConfig[];
102
+ declare const DEFAULT_MODELS: ModelConfig$1[];
72
103
  /** @deprecated 使用 SessionRecord */
73
104
  interface ChatSession {
74
105
  id: string;
@@ -108,99 +139,6 @@ interface DiffStat {
108
139
  type: 'modified' | 'added' | 'deleted';
109
140
  }
110
141
 
111
- /**
112
- * Chat Adapter 接口定义
113
- * 解耦前端组件与后端通信方式
114
- *
115
- * 与 Vue 版本保持一致
116
- */
117
-
118
- /** 聊天进度类型 */
119
- type ChatProgressType = 'thinking' | 'search_start' | 'search_result' | 'tool_call' | 'tool_result' | 'text_delta' | 'text' | 'done' | 'error';
120
- /** 思考数据 */
121
- interface ThinkingData {
122
- content: string;
123
- isComplete: boolean;
124
- }
125
- /** 工具调用数据 */
126
- interface ToolCallData {
127
- name: string;
128
- args: Record<string, unknown>;
129
- }
130
- /** 工具结果数据 */
131
- interface ToolResultData {
132
- name: string;
133
- result: string;
134
- }
135
- /** 图片数据 */
136
- interface ImageData {
137
- base64: string;
138
- mimeType: string;
139
- }
140
- /** 聊天进度事件 */
141
- interface ChatProgress {
142
- type: ChatProgressType;
143
- data: string | ThinkingData | ToolCallData | ToolResultData | {
144
- results: SearchResult[];
145
- };
146
- }
147
- /** 发送消息选项 */
148
- interface SendMessageOptions {
149
- mode: ChatMode;
150
- model: string;
151
- enableWebSearch: boolean;
152
- thinkingMode: ThinkingMode;
153
- }
154
- /** 创建会话选项 */
155
- interface CreateSessionOptions {
156
- title: string;
157
- model: string;
158
- mode: ChatMode;
159
- }
160
- /** 更新会话选项 */
161
- interface UpdateSessionOptions {
162
- title?: string;
163
- model?: string;
164
- mode?: ChatMode;
165
- }
166
- /** 保存消息选项 */
167
- interface SaveMessageOptions {
168
- sessionId: string;
169
- role: 'user' | 'assistant';
170
- content: string;
171
- thinking?: string;
172
- toolCalls?: string;
173
- searchResults?: string;
174
- }
175
- /**
176
- * Chat Adapter 接口
177
- * 所有后端通信实现都需要实现此接口
178
- */
179
- interface ChatAdapter {
180
- /** 获取所有会话 */
181
- getSessions(): Promise<SessionRecord[]>;
182
- /** 创建新会话 */
183
- createSession(options: CreateSessionOptions): Promise<SessionRecord>;
184
- /** 更新会话 */
185
- updateSession(sessionId: string, options: UpdateSessionOptions): Promise<void>;
186
- /** 删除会话 */
187
- deleteSession(sessionId: string): Promise<void>;
188
- /** 获取会话消息 */
189
- getMessages(sessionId: string): Promise<MessageRecord[]>;
190
- /** 保存消息 */
191
- saveMessage(options: SaveMessageOptions): Promise<MessageRecord>;
192
- /** 发送消息并获取流式响应 */
193
- sendMessage(content: string, options: SendMessageOptions, images?: string[]): AsyncGenerator<ChatProgress, void, unknown>;
194
- /** 取消当前请求 */
195
- cancel(): void;
196
- /** 设置工作目录 */
197
- setWorkingDir?(dir: string): void;
198
- }
199
- /**
200
- * 创建空 Adapter(用于测试或无后端场景)
201
- */
202
- declare function createNullAdapter(): ChatAdapter;
203
-
204
142
  /**
205
143
  * useChat Hook
206
144
  * 管理聊天状态和与后端的通信
@@ -215,17 +153,17 @@ interface UseChatOptions {
215
153
  /** 默认模型 */
216
154
  defaultModel?: string;
217
155
  /** 默认模式 */
218
- defaultMode?: ChatMode;
156
+ defaultMode?: ChatMode$1;
219
157
  }
220
158
  /**
221
159
  * 聊天状态管理 Hook
222
160
  */
223
161
  declare function useChat(options?: UseChatOptions): {
224
- sessions: SessionRecord[];
162
+ sessions: SessionRecord$1[];
225
163
  currentSessionId: string | null;
226
164
  messages: ChatMessage[];
227
165
  isLoading: boolean;
228
- mode: ChatMode;
166
+ mode: ChatMode$1;
229
167
  model: string;
230
168
  webSearch: boolean;
231
169
  thinking: boolean;
@@ -238,7 +176,7 @@ declare function useChat(options?: UseChatOptions): {
238
176
  cancelRequest: () => void;
239
177
  copyMessage: (messageId: string) => Promise<void>;
240
178
  regenerateMessage: (messageIndex: number) => void;
241
- setMode: (value: ChatMode) => void;
179
+ setMode: (value: ChatMode$1) => void;
242
180
  setModel: (value: string) => void;
243
181
  setWebSearch: (value: boolean) => void;
244
182
  setThinking: (value: boolean) => void;
@@ -258,9 +196,9 @@ interface ChatPanelProps {
258
196
  /** 默认模型 */
259
197
  defaultModel?: string;
260
198
  /** 默认模式 */
261
- defaultMode?: ChatMode;
199
+ defaultMode?: ChatMode$1;
262
200
  /** 可用模型列表 */
263
- models?: ModelConfig[];
201
+ models?: ModelConfig$1[];
264
202
  /** 隐藏标题栏 */
265
203
  hideHeader?: boolean;
266
204
  /** 关闭回调(有此属性时显示关闭按钮) */
@@ -398,4 +336,4 @@ interface ExecutionStepsProps {
398
336
  }
399
337
  declare const ExecutionSteps: FC<ExecutionStepsProps>;
400
338
 
401
- export { type AiModel, type ChatAdapter, ChatHeader, ChatInput, type ChatMessage, type ChatMode, ChatPanel, type ChatProgress, type ChatProgressType, type ChatSession, type CreateSessionOptions, DEFAULT_MODELS, type DiffStat, ExecutionSteps, FileType, type ImageData, type MediaOperation, MessageBubble, type MessageRecord, type ModelConfig, type ModelProvider, type SaveMessageOptions, type SearchResult, type SendMessageOptions, type SessionRecord, type ThinkingData, type ThinkingMode, type ToolCall, type ToolCallData, type ToolResultData, type UpdateSessionOptions, type UseChatOptions, WelcomeMessage, createNullAdapter, useChat };
339
+ export { type AiModel, ChatHeader, ChatInput, type ChatMessage, ChatPanel, type ChatSession, type CreateSessionOptions, DEFAULT_MODELS, type DiffStat, ExecutionSteps, FileType, type ImageData, type MediaOperation, MessageBubble, type SaveMessageOptions, type SearchResult, type SendMessageOptions, type ThinkingData, type ToolCall, type ToolCallData, type ToolResultData, type UpdateSessionOptions, type UseChatOptions, WelcomeMessage, createNullAdapter, useChat };
package/dist/index.js CHANGED
@@ -1,38 +1,62 @@
1
+ // src/index.ts
2
+ import { createElectronAdapter } from "@huyooo/ai-chat-bridge-electron/renderer";
3
+
1
4
  // src/adapter.ts
2
5
  function createNullAdapter() {
3
6
  return {
7
+ async getModels() {
8
+ return [];
9
+ },
4
10
  async getSessions() {
5
11
  return [];
6
12
  },
7
- async createSession(options) {
13
+ async getSession() {
14
+ return null;
15
+ },
16
+ async createSession(params) {
8
17
  return {
9
18
  id: Date.now().toString(),
10
- title: options.title,
11
- model: options.model,
12
- mode: options.mode,
19
+ appId: null,
20
+ userId: null,
21
+ title: params?.title || "\u65B0\u5BF9\u8BDD",
22
+ model: params?.model || "",
23
+ mode: params?.mode || "agent",
13
24
  createdAt: /* @__PURE__ */ new Date(),
14
25
  updatedAt: /* @__PURE__ */ new Date()
15
26
  };
16
27
  },
17
28
  async updateSession() {
29
+ return null;
18
30
  },
19
31
  async deleteSession() {
20
32
  },
21
33
  async getMessages() {
22
34
  return [];
23
35
  },
24
- async saveMessage(options) {
36
+ async saveMessage(params) {
25
37
  return {
26
38
  id: Date.now().toString(),
27
- sessionId: options.sessionId,
28
- role: options.role,
29
- content: options.content,
30
- thinking: options.thinking,
31
- toolCalls: options.toolCalls,
32
- searchResults: options.searchResults,
39
+ sessionId: params.sessionId,
40
+ role: params.role,
41
+ content: params.content,
42
+ thinking: params.thinking || null,
43
+ toolCalls: params.toolCalls || null,
44
+ searchResults: params.searchResults || null,
45
+ operationIds: null,
33
46
  timestamp: /* @__PURE__ */ new Date()
34
47
  };
35
48
  },
49
+ async deleteMessagesAfter() {
50
+ },
51
+ async getOperations() {
52
+ return [];
53
+ },
54
+ async getTrashItems() {
55
+ return [];
56
+ },
57
+ async restoreFromTrash() {
58
+ return void 0;
59
+ },
36
60
  async *sendMessage() {
37
61
  yield { type: "text", data: "\u65E0\u53EF\u7528\u7684 Adapter" };
38
62
  yield { type: "done", data: "" };
@@ -1415,6 +1439,7 @@ export {
1415
1439
  FileType,
1416
1440
  MessageBubble,
1417
1441
  WelcomeMessage,
1442
+ createElectronAdapter,
1418
1443
  createNullAdapter,
1419
1444
  useChat
1420
1445
  };
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 * 解耦前端组件与后端通信方式\n * \n * 与 Vue 版本保持一致\n */\n\nimport type { SessionRecord, MessageRecord, ChatMode, ThinkingMode, SearchResult } from './types'\n\n/** 聊天进度类型 */\nexport type ChatProgressType =\n | 'thinking'\n | 'search_start'\n | 'search_result'\n | 'tool_call'\n | 'tool_result'\n | 'text_delta'\n | 'text'\n | 'done'\n | 'error'\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 ChatProgress {\n type: ChatProgressType\n data: string | ThinkingData | ToolCallData | ToolResultData | { results: SearchResult[] }\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 * Chat Adapter 接口\n * 所有后端通信实现都需要实现此接口\n */\nexport interface ChatAdapter {\n /** 获取所有会话 */\n getSessions(): Promise<SessionRecord[]>\n \n /** 创建新会话 */\n createSession(options: CreateSessionOptions): Promise<SessionRecord>\n \n /** 更新会话 */\n updateSession(sessionId: string, options: UpdateSessionOptions): Promise<void>\n \n /** 删除会话 */\n deleteSession(sessionId: string): Promise<void>\n \n /** 获取会话消息 */\n getMessages(sessionId: string): Promise<MessageRecord[]>\n \n /** 保存消息 */\n saveMessage(options: SaveMessageOptions): Promise<MessageRecord>\n \n /** 发送消息并获取流式响应 */\n sendMessage(\n content: string,\n options: SendMessageOptions,\n images?: string[]\n ): AsyncGenerator<ChatProgress, void, unknown>\n \n /** 取消当前请求 */\n cancel(): void\n \n /** 设置工作目录 */\n setWorkingDir?(dir: string): void\n}\n\n/**\n * 创建空 Adapter(用于测试或无后端场景)\n */\nexport function createNullAdapter(): ChatAdapter {\n return {\n async getSessions() {\n return []\n },\n async createSession(options) {\n return {\n id: Date.now().toString(),\n title: options.title,\n model: options.model,\n mode: options.mode,\n createdAt: new Date(),\n updatedAt: new Date(),\n }\n },\n async updateSession() {},\n async deleteSession() {},\n async getMessages() {\n return []\n },\n async saveMessage(options) {\n return {\n id: Date.now().toString(),\n sessionId: options.sessionId,\n role: options.role,\n content: options.content,\n thinking: options.thinking,\n toolCalls: options.toolCalls,\n searchResults: options.searchResults,\n timestamp: new Date(),\n }\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 { ChatAdapter, ChatProgress } from '../adapter'\nimport { createNullAdapter } from '../adapter'\nimport type {\n ChatMessage,\n ChatMode,\n SessionRecord,\n MessageRecord,\n SearchResult,\n ToolCall,\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 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 } from '../adapter'\nimport type { ModelConfig, ChatMode } from '../types'\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 * 与 Vue 版本保持一致\n */\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 type ModelProvider = 'openrouter' | 'doubao' | 'deepseek' | 'qwen' | 'gemini' | 'ark'\n\n/** 模型配置 */\nexport interface ModelConfig {\n provider: ModelProvider\n model: string\n displayName: string\n supportsTools: boolean\n supportsWebSearch: boolean\n supportedThinkingModes: ThinkingMode[]\n}\n\n/** 思考模式 */\nexport type ThinkingMode = 'enabled' | 'disabled'\n\n/** 聊天模式 */\nexport type ChatMode = 'agent' | 'ask'\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 interface SessionRecord {\n id: string\n title: string\n model: string\n mode: ChatMode\n createdAt: Date\n updatedAt: Date\n}\n\n/** 消息记录 */\nexport interface MessageRecord {\n id: string\n sessionId: string\n role: 'user' | 'assistant'\n content: string\n thinking?: string\n toolCalls?: string\n searchResults?: string\n timestamp: Date\n}\n\n/** 默认模型列表 */\nexport const DEFAULT_MODELS: ModelConfig[] = [\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/index.ts","../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 * @huyooo/ai-chat-frontend-react\n *\n * AI Chat 前端组件库 - React 版本\n *\n * 使用 adapter 模式,与后端通信方式解耦\n * 与 Vue 版本 (@huyooo/ai-chat-frontend-vue) 保持一致的 API\n */\n\n// 从 bridge-electron 重新导出核心类型,确保类型一致性\nexport type {\n ChatAdapter,\n ChatProgress,\n ChatProgressType,\n ChatOptions,\n ChatMode,\n ModelConfig,\n ModelProvider,\n ThinkingMode,\n SessionRecord,\n MessageRecord,\n} from '@huyooo/ai-chat-bridge-electron/renderer'\n\n// 导出 createElectronAdapter 便于使用\nexport { createElectronAdapter } from '@huyooo/ai-chat-bridge-electron/renderer'\n\n// 导出本地定义的辅助类型\nexport type {\n ThinkingData,\n ToolCallData,\n ToolResultData,\n ImageData,\n SendMessageOptions,\n CreateSessionOptions,\n UpdateSessionOptions,\n SaveMessageOptions,\n} from './adapter'\nexport { createNullAdapter } from './adapter'\n\n// 导出 hooks\nexport { useChat } from './hooks/useChat'\nexport type { UseChatOptions } from './hooks/useChat'\n\n// 导出主组件\nexport { ChatPanel } from './components/ChatPanel'\n\n// 导出输入组件\nexport { ChatInput } from './components/ChatInput'\n\n// 导出 Header 组件\nexport { ChatHeader } from './components/chat/ui/ChatHeader'\n\n// 导出欢迎消息组件\nexport { WelcomeMessage } from './components/chat/ui/WelcomeMessage'\n\n// 导出消息组件\nexport { MessageBubble } from './components/chat/messages/MessageBubble'\nexport { ExecutionSteps } from './components/chat/messages/ExecutionSteps'\n\n// 导出前端特有类型(不与 bridge-electron 重复)\nexport type {\n ChatMessage,\n SearchResult,\n ToolCall,\n // 向后兼容\n ChatSession,\n MediaOperation,\n AiModel,\n DiffStat,\n} from './types'\nexport { DEFAULT_MODELS, FileType } from './types'\n\n/**\n * 使用说明:\n *\n * 1. 导入样式:\n * import '@huyooo/ai-chat-frontend-react/style.css'\n *\n * 2. 创建 adapter 和使用组件(一行导入):\n * import { ChatPanel, createElectronAdapter } from '@huyooo/ai-chat-frontend-react'\n * const adapter = createElectronAdapter()\n * <ChatPanel adapter={adapter} />\n *\n * 3. 或使用 useChat hook 自定义 UI:\n * import { useChat, createElectronAdapter } from '@huyooo/ai-chat-frontend-react'\n * const adapter = createElectronAdapter()\n * const chat = useChat({ adapter })\n */\n","/**\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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huyooo/ai-chat-frontend-react",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "AI Chat Frontend - React components with adapter pattern",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,6 +30,7 @@
30
30
  "react-dom": ">=18.0.0"
31
31
  },
32
32
  "dependencies": {
33
+ "@huyooo/ai-chat-bridge-electron": "^0.1.3",
33
34
  "lucide-react": "^0.460.0"
34
35
  },
35
36
  "devDependencies": {
package/src/adapter.ts CHANGED
@@ -1,23 +1,10 @@
1
1
  /**
2
- * Chat Adapter 接口定义
3
- * 解耦前端组件与后端通信方式
4
- *
5
- * 与 Vue 版本保持一致
2
+ * Chat Adapter 辅助类型和工具
3
+ * 核心 ChatAdapter 接口从 bridge-electron 导入
6
4
  */
7
5
 
8
- import type { SessionRecord, MessageRecord, ChatMode, ThinkingMode, SearchResult } from './types'
9
-
10
- /** 聊天进度类型 */
11
- export type ChatProgressType =
12
- | 'thinking'
13
- | 'search_start'
14
- | 'search_result'
15
- | 'tool_call'
16
- | 'tool_result'
17
- | 'text_delta'
18
- | 'text'
19
- | 'done'
20
- | 'error'
6
+ import type { ChatAdapter, ChatMode, ThinkingMode } from '@huyooo/ai-chat-bridge-electron/renderer'
7
+ import type { SearchResult } from './types'
21
8
 
22
9
  /** 思考数据 */
23
10
  export interface ThinkingData {
@@ -43,12 +30,6 @@ export interface ImageData {
43
30
  mimeType: string
44
31
  }
45
32
 
46
- /** 聊天进度事件 */
47
- export interface ChatProgress {
48
- type: ChatProgressType
49
- data: string | ThinkingData | ToolCallData | ToolResultData | { results: SearchResult[] }
50
- }
51
-
52
33
  /** 发送消息选项 */
53
34
  export interface SendMessageOptions {
54
35
  mode: ChatMode
@@ -81,78 +62,63 @@ export interface SaveMessageOptions {
81
62
  searchResults?: string
82
63
  }
83
64
 
84
- /**
85
- * Chat Adapter 接口
86
- * 所有后端通信实现都需要实现此接口
87
- */
88
- export interface ChatAdapter {
89
- /** 获取所有会话 */
90
- getSessions(): Promise<SessionRecord[]>
91
-
92
- /** 创建新会话 */
93
- createSession(options: CreateSessionOptions): Promise<SessionRecord>
94
-
95
- /** 更新会话 */
96
- updateSession(sessionId: string, options: UpdateSessionOptions): Promise<void>
97
-
98
- /** 删除会话 */
99
- deleteSession(sessionId: string): Promise<void>
100
-
101
- /** 获取会话消息 */
102
- getMessages(sessionId: string): Promise<MessageRecord[]>
103
-
104
- /** 保存消息 */
105
- saveMessage(options: SaveMessageOptions): Promise<MessageRecord>
106
-
107
- /** 发送消息并获取流式响应 */
108
- sendMessage(
109
- content: string,
110
- options: SendMessageOptions,
111
- images?: string[]
112
- ): AsyncGenerator<ChatProgress, void, unknown>
113
-
114
- /** 取消当前请求 */
115
- cancel(): void
116
-
117
- /** 设置工作目录 */
118
- setWorkingDir?(dir: string): void
119
- }
120
-
121
65
  /**
122
66
  * 创建空 Adapter(用于测试或无后端场景)
67
+ * 返回一个最小实现的 ChatAdapter
123
68
  */
124
69
  export function createNullAdapter(): ChatAdapter {
125
70
  return {
71
+ async getModels() {
72
+ return []
73
+ },
126
74
  async getSessions() {
127
75
  return []
128
76
  },
129
- async createSession(options) {
77
+ async getSession() {
78
+ return null
79
+ },
80
+ async createSession(params) {
130
81
  return {
131
82
  id: Date.now().toString(),
132
- title: options.title,
133
- model: options.model,
134
- mode: options.mode,
83
+ appId: null,
84
+ userId: null,
85
+ title: params?.title || '新对话',
86
+ model: params?.model || '',
87
+ mode: (params?.mode || 'agent') as ChatMode,
135
88
  createdAt: new Date(),
136
89
  updatedAt: new Date(),
137
90
  }
138
91
  },
139
- async updateSession() {},
92
+ async updateSession() {
93
+ return null
94
+ },
140
95
  async deleteSession() {},
141
96
  async getMessages() {
142
97
  return []
143
98
  },
144
- async saveMessage(options) {
99
+ async saveMessage(params) {
145
100
  return {
146
101
  id: Date.now().toString(),
147
- sessionId: options.sessionId,
148
- role: options.role,
149
- content: options.content,
150
- thinking: options.thinking,
151
- toolCalls: options.toolCalls,
152
- searchResults: options.searchResults,
102
+ sessionId: params.sessionId,
103
+ role: params.role,
104
+ content: params.content,
105
+ thinking: params.thinking || null,
106
+ toolCalls: params.toolCalls || null,
107
+ searchResults: params.searchResults || null,
108
+ operationIds: null,
153
109
  timestamp: new Date(),
154
110
  }
155
111
  },
112
+ async deleteMessagesAfter() {},
113
+ async getOperations() {
114
+ return []
115
+ },
116
+ async getTrashItems() {
117
+ return []
118
+ },
119
+ async restoreFromTrash() {
120
+ return undefined
121
+ },
156
122
  async *sendMessage() {
157
123
  yield { type: 'text', data: '无可用的 Adapter' }
158
124
  yield { type: 'done', data: '' }
@@ -5,8 +5,7 @@
5
5
 
6
6
  import { useEffect, useRef, useCallback, type FC, type ReactNode } from 'react'
7
7
  import { useChat } from '../hooks/useChat'
8
- import type { ChatAdapter } from '../adapter'
9
- import type { ModelConfig, ChatMode } from '../types'
8
+ import type { ChatAdapter, ModelConfig, ChatMode } from '@huyooo/ai-chat-bridge-electron/renderer'
10
9
  import { DEFAULT_MODELS } from '../types'
11
10
  import { ChatHeader } from './chat/ui/ChatHeader'
12
11
  import { WelcomeMessage } from './chat/ui/WelcomeMessage'
@@ -7,16 +7,15 @@
7
7
  */
8
8
 
9
9
  import { useState, useCallback, useRef } from 'react'
10
- import type { ChatAdapter, ChatProgress } from '../adapter'
11
- import { createNullAdapter } from '../adapter'
12
10
  import type {
13
- ChatMessage,
11
+ ChatAdapter,
12
+ ChatProgress,
14
13
  ChatMode,
15
14
  SessionRecord,
16
15
  MessageRecord,
17
- SearchResult,
18
- ToolCall,
19
- } from '../types'
16
+ } from '@huyooo/ai-chat-bridge-electron/renderer'
17
+ import { createNullAdapter } from '../adapter'
18
+ import type { ChatMessage, SearchResult, ToolCall } from '../types'
20
19
 
21
20
  /** 生成唯一 ID */
22
21
  function generateId(): string {
package/src/index.ts CHANGED
@@ -7,11 +7,25 @@
7
7
  * 与 Vue 版本 (@huyooo/ai-chat-frontend-vue) 保持一致的 API
8
8
  */
9
9
 
10
- // 导出 Adapter 接口和类型
10
+ // bridge-electron 重新导出核心类型,确保类型一致性
11
11
  export type {
12
12
  ChatAdapter,
13
13
  ChatProgress,
14
14
  ChatProgressType,
15
+ ChatOptions,
16
+ ChatMode,
17
+ ModelConfig,
18
+ ModelProvider,
19
+ ThinkingMode,
20
+ SessionRecord,
21
+ MessageRecord,
22
+ } from '@huyooo/ai-chat-bridge-electron/renderer'
23
+
24
+ // 导出 createElectronAdapter 便于使用
25
+ export { createElectronAdapter } from '@huyooo/ai-chat-bridge-electron/renderer'
26
+
27
+ // 导出本地定义的辅助类型
28
+ export type {
15
29
  ThinkingData,
16
30
  ToolCallData,
17
31
  ToolResultData,
@@ -43,15 +57,9 @@ export { WelcomeMessage } from './components/chat/ui/WelcomeMessage'
43
57
  export { MessageBubble } from './components/chat/messages/MessageBubble'
44
58
  export { ExecutionSteps } from './components/chat/messages/ExecutionSteps'
45
59
 
46
- // 导出类型
60
+ // 导出前端特有类型(不与 bridge-electron 重复)
47
61
  export type {
48
62
  ChatMessage,
49
- ChatMode,
50
- ModelConfig,
51
- ModelProvider,
52
- ThinkingMode,
53
- SessionRecord,
54
- MessageRecord,
55
63
  SearchResult,
56
64
  ToolCall,
57
65
  // 向后兼容
@@ -68,14 +76,13 @@ export { DEFAULT_MODELS, FileType } from './types'
68
76
  * 1. 导入样式:
69
77
  * import '@huyooo/ai-chat-frontend-react/style.css'
70
78
  *
71
- * 2. 创建 adapter(使用桥接包):
72
- * import { createElectronAdapter } from '@huyooo/ai-chat-bridge-electron/renderer'
79
+ * 2. 创建 adapter 和使用组件(一行导入):
80
+ * import { ChatPanel, createElectronAdapter } from '@huyooo/ai-chat-frontend-react'
73
81
  * const adapter = createElectronAdapter()
74
- *
75
- * 3. 在 React 组件中使用:
76
82
  * <ChatPanel adapter={adapter} />
77
83
  *
78
- * 4. 或使用 useChat hook:
84
+ * 3. 或使用 useChat hook 自定义 UI
85
+ * import { useChat, createElectronAdapter } from '@huyooo/ai-chat-frontend-react'
86
+ * const adapter = createElectronAdapter()
79
87
  * const chat = useChat({ adapter })
80
- * // 然后自定义 UI
81
88
  */
@@ -1,8 +1,27 @@
1
1
  /**
2
2
  * AI Chat 前端类型定义
3
- * Vue 版本保持一致
3
+ * 核心类型(ChatAdapter, SessionRecord, MessageRecord 等)从 bridge-electron 导出
4
+ * 这里只定义前端特有的类型
4
5
  */
5
6
 
7
+ // 从 bridge-electron 导入类型(用于本文件)
8
+ import type {
9
+ ChatMode as ChatModeType,
10
+ ModelConfig as ModelConfigType,
11
+ ModelProvider as ModelProviderType,
12
+ ThinkingMode as ThinkingModeType,
13
+ SessionRecord as SessionRecordType,
14
+ MessageRecord as MessageRecordType,
15
+ } from '@huyooo/ai-chat-bridge-electron/renderer'
16
+
17
+ // 重新导出核心类型
18
+ export type ChatMode = ChatModeType
19
+ export type ModelConfig = ModelConfigType
20
+ export type ModelProvider = ModelProviderType
21
+ export type ThinkingMode = ThinkingModeType
22
+ export type SessionRecord = SessionRecordType
23
+ export type MessageRecord = MessageRecordType
24
+
6
25
  /** 搜索结果 */
7
26
  export interface SearchResult {
8
27
  title: string
@@ -18,26 +37,7 @@ export interface ToolCall {
18
37
  status: 'running' | 'success' | 'error'
19
38
  }
20
39
 
21
- /** 模型提供商 */
22
- export type ModelProvider = 'openrouter' | 'doubao' | 'deepseek' | 'qwen' | 'gemini' | 'ark'
23
-
24
- /** 模型配置 */
25
- export interface ModelConfig {
26
- provider: ModelProvider
27
- model: string
28
- displayName: string
29
- supportsTools: boolean
30
- supportsWebSearch: boolean
31
- supportedThinkingModes: ThinkingMode[]
32
- }
33
-
34
- /** 思考模式 */
35
- export type ThinkingMode = 'enabled' | 'disabled'
36
-
37
- /** 聊天模式 */
38
- export type ChatMode = 'agent' | 'ask'
39
-
40
- /** 聊天消息 */
40
+ /** 聊天消息(前端显示用) */
41
41
  export interface ChatMessage {
42
42
  id: string
43
43
  role: 'user' | 'assistant'
@@ -53,30 +53,8 @@ export interface ChatMessage {
53
53
  timestamp?: Date
54
54
  }
55
55
 
56
- /** 会话记录 */
57
- export interface SessionRecord {
58
- id: string
59
- title: string
60
- model: string
61
- mode: ChatMode
62
- createdAt: Date
63
- updatedAt: Date
64
- }
65
-
66
- /** 消息记录 */
67
- export interface MessageRecord {
68
- id: string
69
- sessionId: string
70
- role: 'user' | 'assistant'
71
- content: string
72
- thinking?: string
73
- toolCalls?: string
74
- searchResults?: string
75
- timestamp: Date
76
- }
77
-
78
56
  /** 默认模型列表 */
79
- export const DEFAULT_MODELS: ModelConfig[] = [
57
+ export const DEFAULT_MODELS: ModelConfigType[] = [
80
58
  {
81
59
  provider: 'openrouter',
82
60
  model: 'anthropic/claude-opus-4.5',