@huyooo/ai-chat-bridge-electron 0.2.13 → 0.2.15
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/main/index.d.ts +2 -0
- package/dist/main/index.js +1 -823
- package/dist/preload/index.d.ts +25 -7
- package/dist/preload/index.js +1 -136
- package/dist/renderer/index.d.cts +1 -1
- package/dist/renderer/index.d.ts +54 -15
- package/dist/renderer/index.js +1 -253
- package/package.json +4 -4
- package/src/main/index.ts +33 -0
- package/src/preload/index.ts +25 -7
- package/src/renderer/index.ts +39 -7
package/src/main/index.ts
CHANGED
|
@@ -46,6 +46,8 @@ import {
|
|
|
46
46
|
export interface ElectronBridgeOptions extends Omit<AgentConfig, 'tools'> {
|
|
47
47
|
/** IPC channel 前缀 */
|
|
48
48
|
channelPrefix?: string;
|
|
49
|
+
/** Tavily API Key(用于统一 Web Search;可选) */
|
|
50
|
+
tavilyApiKey?: string;
|
|
49
51
|
/**
|
|
50
52
|
* 统一数据目录(必填)
|
|
51
53
|
* 所有数据都存储在此目录下:
|
|
@@ -88,6 +90,8 @@ interface MessageParams {
|
|
|
88
90
|
sessionId: string;
|
|
89
91
|
role: 'user' | 'assistant';
|
|
90
92
|
content: string;
|
|
93
|
+
/** 用户消息附带的图片(data URL 或 base64) */
|
|
94
|
+
images?: string[];
|
|
91
95
|
/** 生成此消息时使用的模型 */
|
|
92
96
|
model?: string;
|
|
93
97
|
/** 生成此消息时使用的模式 (ask/agent) */
|
|
@@ -225,6 +229,28 @@ export async function createElectronBridge(options: ElectronBridgeOptions) {
|
|
|
225
229
|
return MODELS;
|
|
226
230
|
});
|
|
227
231
|
|
|
232
|
+
// 获取所有工具列表(用于设置面板)
|
|
233
|
+
ipcMain.handle(`${channelPrefix}:getAllTools`, async () => {
|
|
234
|
+
// 确保工具已初始化(通过调用 chat 方法触发 asyncInit)
|
|
235
|
+
// 如果工具还未初始化,先触发一次初始化
|
|
236
|
+
console.log('[Main] getAllTools 调用,当前工具数量:', agent['tools'].size);
|
|
237
|
+
console.log('[Main] toolConfig 是否存在:', !!agent['toolConfig']);
|
|
238
|
+
console.log('[Main] toolConfig 内容:', agent['toolConfig'] ? `${agent['toolConfig'].length} 个工具配置` : 'undefined');
|
|
239
|
+
|
|
240
|
+
// 如果工具未初始化,尝试初始化
|
|
241
|
+
if (agent['tools'].size === 0 && agent['toolConfig']) {
|
|
242
|
+
console.log('[Main] 工具未初始化,开始 asyncInit...');
|
|
243
|
+
await agent['asyncInit']();
|
|
244
|
+
console.log('[Main] asyncInit 完成,工具数量:', agent['tools'].size);
|
|
245
|
+
} else if (!agent['toolConfig']) {
|
|
246
|
+
console.warn('[Main] ⚠️ toolConfig 不存在,工具可能未注入!');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const tools = (agent as any).getAllTools();
|
|
250
|
+
console.log('[Main] getAllTools 返回:', tools.length, '个工具', tools.map((t: any) => t.name));
|
|
251
|
+
return tools;
|
|
252
|
+
});
|
|
253
|
+
|
|
228
254
|
// 发送消息
|
|
229
255
|
ipcMain.handle(`${channelPrefix}:send`, async (event, params: SendMessageParams) => {
|
|
230
256
|
const webContents = event.sender;
|
|
@@ -387,6 +413,7 @@ export async function createElectronBridge(options: ElectronBridgeOptions) {
|
|
|
387
413
|
sessionId: params.sessionId,
|
|
388
414
|
role: params.role,
|
|
389
415
|
content: params.content,
|
|
416
|
+
images: params.images || [],
|
|
390
417
|
model: params.model || null,
|
|
391
418
|
mode: params.mode || null,
|
|
392
419
|
webSearchEnabled: params.webSearchEnabled ?? null,
|
|
@@ -412,6 +439,12 @@ export async function createElectronBridge(options: ElectronBridgeOptions) {
|
|
|
412
439
|
return { success: true };
|
|
413
440
|
});
|
|
414
441
|
|
|
442
|
+
// 删除指定消息之后的所有消息(用于分叉)
|
|
443
|
+
ipcMain.handle(`${channelPrefix}:messages:deleteAfterMessageId`, async (_event, sessionId: string, messageId: string) => {
|
|
444
|
+
await storage.deleteMessagesAfterMessageId(sessionId, messageId, getContext());
|
|
445
|
+
return { success: true };
|
|
446
|
+
});
|
|
447
|
+
|
|
415
448
|
// 获取操作日志
|
|
416
449
|
ipcMain.handle(`${channelPrefix}:operations:list`, async (_event, sessionId: string) => {
|
|
417
450
|
return storage.getOperations(sessionId, getContext());
|
package/src/preload/index.ts
CHANGED
|
@@ -25,12 +25,14 @@ interface SendMessageParams {
|
|
|
25
25
|
interface ModelOption {
|
|
26
26
|
modelId: string;
|
|
27
27
|
displayName: string;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
supportsThinking: boolean;
|
|
29
|
+
supportsVision: boolean;
|
|
30
|
+
tooltip?: {
|
|
31
|
+
features?: string[];
|
|
32
|
+
/** 开销信息(数组,分行显示) */
|
|
33
|
+
cost?: string[];
|
|
34
|
+
description?: string;
|
|
35
|
+
};
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
/** 会话记录 */
|
|
@@ -55,6 +57,8 @@ interface MessageRecord {
|
|
|
55
57
|
sessionId: string;
|
|
56
58
|
role: 'user' | 'assistant';
|
|
57
59
|
content: string;
|
|
60
|
+
/** 用户消息附带的图片(data URL 或 base64) */
|
|
61
|
+
images: string[];
|
|
58
62
|
/** 生成此消息时使用的模型 */
|
|
59
63
|
model?: string | null;
|
|
60
64
|
/** 生成此消息时使用的模式 (ask/agent) */
|
|
@@ -66,7 +70,10 @@ interface MessageRecord {
|
|
|
66
70
|
/** 执行步骤列表 JSON */
|
|
67
71
|
steps?: string | null;
|
|
68
72
|
operationIds?: string | null;
|
|
69
|
-
|
|
73
|
+
/** 消息序号(会话内递增,用于分叉删除,必须) */
|
|
74
|
+
sequence: number;
|
|
75
|
+
/** 时间戳(毫秒,Unix 时间戳,不受 JSON 序列化影响) */
|
|
76
|
+
timestamp: number;
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
/** 操作记录 */
|
|
@@ -137,6 +144,8 @@ export interface AiChatBridge {
|
|
|
137
144
|
// ============ Chat API ============
|
|
138
145
|
/** 获取可用模型 */
|
|
139
146
|
getModels(): Promise<ModelOption[]>;
|
|
147
|
+
/** 获取所有工具列表(用于设置面板) */
|
|
148
|
+
getAllTools(): Promise<Array<{ name: string; description: string }>>;
|
|
140
149
|
/** 发送消息 */
|
|
141
150
|
send(params: SendMessageParams): Promise<void>;
|
|
142
151
|
/** 取消当前请求 */
|
|
@@ -171,6 +180,8 @@ export interface AiChatBridge {
|
|
|
171
180
|
sessionId: string;
|
|
172
181
|
role: 'user' | 'assistant';
|
|
173
182
|
content: string;
|
|
183
|
+
/** 用户消息附带的图片(data URL 或 base64) */
|
|
184
|
+
images?: string[];
|
|
174
185
|
/** 生成此消息时使用的模型 */
|
|
175
186
|
model?: string;
|
|
176
187
|
/** 生成此消息时使用的模式 (ask/agent) */
|
|
@@ -191,6 +202,8 @@ export interface AiChatBridge {
|
|
|
191
202
|
}): Promise<{ success: boolean }>;
|
|
192
203
|
/** 删除指定时间之后的消息(用于分叉) */
|
|
193
204
|
deleteMessagesAfter(sessionId: string, timestamp: number): Promise<{ success: boolean }>;
|
|
205
|
+
/** 删除指定消息之后的所有消息(用于分叉) */
|
|
206
|
+
deleteMessagesAfterMessageId(sessionId: string, messageId: string): Promise<{ success: boolean }>;
|
|
194
207
|
|
|
195
208
|
// ============ Operations API ============
|
|
196
209
|
/** 获取操作日志 */
|
|
@@ -323,6 +336,9 @@ export function exposeElectronBridge(options: ExposeOptions = {}) {
|
|
|
323
336
|
getModels: () =>
|
|
324
337
|
ipcRenderer.invoke(`${channelPrefix}:models`),
|
|
325
338
|
|
|
339
|
+
getAllTools: () =>
|
|
340
|
+
ipcRenderer.invoke(`${channelPrefix}:getAllTools`),
|
|
341
|
+
|
|
326
342
|
send: (params: SendMessageParams) =>
|
|
327
343
|
ipcRenderer.invoke(`${channelPrefix}:send`, params),
|
|
328
344
|
|
|
@@ -390,6 +406,8 @@ export function exposeElectronBridge(options: ExposeOptions = {}) {
|
|
|
390
406
|
|
|
391
407
|
deleteMessagesAfter: (sessionId: string, timestamp: number) =>
|
|
392
408
|
ipcRenderer.invoke(`${channelPrefix}:messages:deleteAfter`, sessionId, timestamp),
|
|
409
|
+
deleteMessagesAfterMessageId: (sessionId: string, messageId: string) =>
|
|
410
|
+
ipcRenderer.invoke(`${channelPrefix}:messages:deleteAfterMessageId`, sessionId, messageId),
|
|
393
411
|
|
|
394
412
|
// ============ Operations API ============
|
|
395
413
|
getOperations: (sessionId: string) =>
|
package/src/renderer/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ export type ChatEventType =
|
|
|
16
16
|
| 'search_end'
|
|
17
17
|
| 'tool_approval_request'
|
|
18
18
|
| 'tool_call_start'
|
|
19
|
+
| 'tool_call_output'
|
|
19
20
|
| 'tool_call_result'
|
|
20
21
|
| 'text_delta'
|
|
21
22
|
| 'image'
|
|
@@ -69,6 +70,8 @@ export interface ChatOptions {
|
|
|
69
70
|
enableWebSearch?: boolean;
|
|
70
71
|
/** 深度思考开关(每个 provider 内部使用最优参数) */
|
|
71
72
|
thinkingMode?: ThinkingMode;
|
|
73
|
+
/** 启用的工具名称列表(undefined 表示全部启用) */
|
|
74
|
+
enabledTools?: string[];
|
|
72
75
|
/** 自动运行配置 */
|
|
73
76
|
autoRunConfig?: AutoRunConfig;
|
|
74
77
|
/** 对话历史(无状态架构,历史从前端传入) */
|
|
@@ -83,12 +86,17 @@ export interface ModelOption {
|
|
|
83
86
|
modelId: string;
|
|
84
87
|
/** 显示名称 */
|
|
85
88
|
displayName: string;
|
|
86
|
-
/**
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
|
|
89
|
+
/** 是否支持深度思考 */
|
|
90
|
+
supportsThinking: boolean;
|
|
91
|
+
/** 是否支持图片理解 */
|
|
92
|
+
supportsVision: boolean;
|
|
93
|
+
/** 模型项 hover 提示(由后端定义,前端只渲染) */
|
|
94
|
+
tooltip?: {
|
|
95
|
+
features?: string[];
|
|
96
|
+
/** 开销信息(数组,分行显示) */
|
|
97
|
+
cost?: string[];
|
|
98
|
+
description?: string;
|
|
99
|
+
};
|
|
92
100
|
}
|
|
93
101
|
|
|
94
102
|
// 会话记录
|
|
@@ -113,6 +121,8 @@ export interface MessageRecord {
|
|
|
113
121
|
sessionId: string;
|
|
114
122
|
role: 'user' | 'assistant';
|
|
115
123
|
content: string;
|
|
124
|
+
/** 用户消息附带的图片(data URL 或 base64) */
|
|
125
|
+
images: string[];
|
|
116
126
|
/** 生成此消息时使用的模型 */
|
|
117
127
|
model?: string | null;
|
|
118
128
|
/** 生成此消息时使用的模式 (ask/agent) */
|
|
@@ -124,7 +134,10 @@ export interface MessageRecord {
|
|
|
124
134
|
/** 执行步骤列表 JSON */
|
|
125
135
|
steps?: string | null;
|
|
126
136
|
operationIds?: string | null;
|
|
127
|
-
|
|
137
|
+
/** 消息序号(会话内递增,用于分叉删除,必须) */
|
|
138
|
+
sequence: number;
|
|
139
|
+
/** 时间戳(毫秒,Unix 时间戳,不受 JSON 序列化影响) */
|
|
140
|
+
timestamp: number;
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
// 操作记录
|
|
@@ -196,6 +209,8 @@ export interface ChatAdapter {
|
|
|
196
209
|
// ============ Chat API ============
|
|
197
210
|
/** 获取可用模型 */
|
|
198
211
|
getModels(): Promise<ModelOption[]>;
|
|
212
|
+
/** 获取所有工具列表(用于设置面板) */
|
|
213
|
+
getAllTools?(): Promise<Array<{ name: string; description: string }>>;
|
|
199
214
|
/** 发送消息,返回异步迭代器 */
|
|
200
215
|
sendMessage(message: string, options?: ChatOptions, images?: string[], sessionId?: string): AsyncIterable<ChatEvent>;
|
|
201
216
|
/** 取消当前请求 */
|
|
@@ -226,6 +241,8 @@ export interface ChatAdapter {
|
|
|
226
241
|
sessionId: string;
|
|
227
242
|
role: 'user' | 'assistant';
|
|
228
243
|
content: string;
|
|
244
|
+
/** 用户消息附带的图片(data URL 或 base64) */
|
|
245
|
+
images?: string[];
|
|
229
246
|
/** 生成此消息时使用的模型 */
|
|
230
247
|
model?: string;
|
|
231
248
|
/** 生成此消息时使用的模式 (ask/agent) */
|
|
@@ -246,6 +263,8 @@ export interface ChatAdapter {
|
|
|
246
263
|
}): Promise<void>;
|
|
247
264
|
/** 删除指定时间之后的消息(用于分叉) */
|
|
248
265
|
deleteMessagesAfter(sessionId: string, timestamp: number): Promise<void>;
|
|
266
|
+
/** 删除指定消息之后的所有消息(用于分叉) */
|
|
267
|
+
deleteMessagesAfterMessageId(sessionId: string, messageId: string): Promise<void>;
|
|
249
268
|
|
|
250
269
|
// ============ Operations API ============
|
|
251
270
|
/** 获取操作日志 */
|
|
@@ -353,6 +372,15 @@ export function createElectronAdapter(options: CreateAdapterOptions = {}): ChatA
|
|
|
353
372
|
return bridge.getModels();
|
|
354
373
|
},
|
|
355
374
|
|
|
375
|
+
async getAllTools(): Promise<Array<{ name: string; description: string }>> {
|
|
376
|
+
const bridge = getBridge();
|
|
377
|
+
// preload 已保证存在;这里保留一层容错,避免宿主未升级时直接崩
|
|
378
|
+
if (typeof (bridge as unknown as { getAllTools?: unknown }).getAllTools === 'function') {
|
|
379
|
+
return bridge.getAllTools();
|
|
380
|
+
}
|
|
381
|
+
return [];
|
|
382
|
+
},
|
|
383
|
+
|
|
356
384
|
async *sendMessage(
|
|
357
385
|
message: string,
|
|
358
386
|
options?: ChatOptions,
|
|
@@ -451,6 +479,10 @@ export function createElectronAdapter(options: CreateAdapterOptions = {}): ChatA
|
|
|
451
479
|
await getBridge().deleteMessagesAfter(sessionId, timestamp);
|
|
452
480
|
},
|
|
453
481
|
|
|
482
|
+
async deleteMessagesAfterMessageId(sessionId: string, messageId: string): Promise<void> {
|
|
483
|
+
await getBridge().deleteMessagesAfterMessageId(sessionId, messageId);
|
|
484
|
+
},
|
|
485
|
+
|
|
454
486
|
// ============ Operations API ============
|
|
455
487
|
async getOperations(sessionId: string): Promise<OperationRecord[]> {
|
|
456
488
|
return getBridge().getOperations(sessionId);
|