diff --git a/electron/main/ai/conversations.ts b/electron/main/ai/conversations.ts index 40640bb..49073bd 100644 --- a/electron/main/ai/conversations.ts +++ b/electron/main/ai/conversations.ts @@ -7,6 +7,8 @@ import Database from 'better-sqlite3' import * as path from 'path' import { getAiDataDir, ensureDir } from '../paths' +const DEFAULT_GENERAL_ID = 'general_cn' + // AI 数据库实例 let AI_DB: Database.Database | null = null diff --git a/electron/main/ipc/ai.ts b/electron/main/ipc/ai.ts index b7749a8..75ee098 100644 --- a/electron/main/ipc/ai.ts +++ b/electron/main/ipc/ai.ts @@ -1,5 +1,5 @@ // electron/main/ipc/ai.ts -import { ipcMain, BrowserWindow, shell } from 'electron' +import { ipcMain, shell } from 'electron' import * as fs from 'fs' import * as path from 'path' import * as aiConversations from '../ai/conversations' @@ -13,12 +13,26 @@ import { getActiveConfig, buildPiModel } from '../ai/llm' import * as assistantManager from '../ai/assistant' import type { AssistantConfig } from '../ai/assistant/types' import * as skillManager from '../ai/skills' -import { completeSimple, streamSimple, type TextContent as PiTextContent } from '@mariozechner/pi-ai' +import { + completeSimple, + streamSimple, + type Message as PiMessage, + type TextContent as PiTextContent, +} from '@mariozechner/pi-ai' import { t } from '../i18n' import type { ToolContext } from '../ai/tools/types' import { getDefaultRulesForLocale, mergeRulesForLocale } from '../ai/preprocessor/builtin-rules' import type { IpcContext } from './types' +function toPiSimpleMessages(messages: Array<{ role: string; content: string }>, timestamp: number): PiMessage[] { + // pi-ai 的 simple API 在类型上要求完整 Message 联合,这里沿用现有轻量消息格式并集中做兼容转换。 + return messages.map((message) => ({ + role: message.role as 'user' | 'assistant', + content: message.content, + timestamp, + })) as unknown as PiMessage[] +} + // ==================== AI Agent 请求追踪 ==================== // 用于跟踪活跃的 Agent 请求,支持中止操作 const activeAgentRequests = new Map() @@ -147,22 +161,22 @@ export function registerAIHandlers({ win }: IpcContext): void { * 创建新的 AI 对话 * 参数契约与 preload / 数据层保持一致:(sessionId, title?) */ - ipcMain.handle('ai:createConversation', async (_, sessionId: string, title?: string, assistantId?: string) => { - try { - if (!assistantId) { - throw new Error('assistantId is required when creating a conversation') + ipcMain.handle( + 'ai:createConversation', + async (_, sessionId: string, title: string | undefined, assistantId: string) => { + try { + return aiConversations.createConversation(sessionId, title, assistantId) + } catch (error) { + console.error('Failed to create AI conversation:', error) + throw error } - return aiConversations.createConversation(sessionId, title, assistantId) - } catch (error) { - console.error('Failed to create AI conversation:', error) - throw error } - }) + ) /** * 获取所有 AI 对话列表 */ - ipcMain.handle('ai:getConversations', async (_, sessionId?: string) => { + ipcMain.handle('ai:getConversations', async (_, sessionId: string) => { try { return aiConversations.getConversations(sessionId) } catch (error) { @@ -485,11 +499,7 @@ export function registerAIHandlers({ win }: IpcContext): void { piModel, { systemPrompt: systemMsg?.content, - messages: nonSystemMsgs.map((m) => ({ - role: m.role as 'user' | 'assistant', - content: m.content, - timestamp: now, - })), + messages: toPiSimpleMessages(nonSystemMsgs, now), }, { apiKey: activeConfig.apiKey, @@ -536,11 +546,7 @@ export function registerAIHandlers({ win }: IpcContext): void { piModel, { systemPrompt: systemMsg?.content, - messages: nonSystemMsgs.map((m) => ({ - role: m.role as 'user' | 'assistant', - content: m.content, - timestamp: now, - })), + messages: toPiSimpleMessages(nonSystemMsgs, now), }, { apiKey: activeConfig.apiKey, diff --git a/electron/preload/apis/ai.ts b/electron/preload/apis/ai.ts index dbbabf4..54991ee 100644 --- a/electron/preload/apis/ai.ts +++ b/electron/preload/apis/ai.ts @@ -419,7 +419,7 @@ export const aiApi = { /** * 创建 AI 对话 */ - createConversation: (sessionId: string, title?: string, assistantId: string): Promise => { + createConversation: (sessionId: string, title: string | undefined, assistantId: string): Promise => { return ipcRenderer.invoke('ai:createConversation', sessionId, title, assistantId) }, diff --git a/electron/preload/index.d.ts b/electron/preload/index.d.ts index 44d10f6..d061d66 100644 --- a/electron/preload/index.d.ts +++ b/electron/preload/index.d.ts @@ -358,7 +358,7 @@ interface AiApi { senderId?: number, keywords?: string[] ) => Promise<{ messages: SearchMessageResult[]; hasMore: boolean }> - createConversation: (sessionId: string, title?: string, assistantId: string) => Promise + createConversation: (sessionId: string, title: string | undefined, assistantId: string) => Promise getConversations: (sessionId: string) => Promise getConversation: (conversationId: string) => Promise updateConversationTitle: (conversationId: string, title: string) => Promise diff --git a/electron/preload/index.ts b/electron/preload/index.ts index 26abf4e..11f020a 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -11,6 +11,9 @@ import { chatApi, mergeApi } from './apis/chat' import { aiApi, llmApi, agentApi, embeddingApi, assistantApi, skillApi } from './apis/ai' import { nlpApi, networkApi, cacheApi, sessionApi } from './apis/utils' +// 为渲染进程提供统一的类型入口,避免 type-only import 指向无导出的运行时代码。 +export type { PreprocessConfig, EmbeddingServiceConfig, EmbeddingServiceConfigDisplay } from './apis/ai' + // Use `contextBridge` APIs to expose Electron APIs to // renderer only if context isolation is enabled, otherwise // just add to the DOM global. diff --git a/packages/chart-cluster/ClusterView.vue b/packages/chart-cluster/ClusterView.vue index e55b8c1..37a0a45 100644 --- a/packages/chart-cluster/ClusterView.vue +++ b/packages/chart-cluster/ClusterView.vue @@ -12,7 +12,7 @@ import { TooltipComponent, GridComponent, VisualMapComponent } from 'echarts/com import { CanvasRenderer } from 'echarts/renderers' import type { EChartsOption } from 'echarts' import { loadClusterGraph } from './queries' -import type { ClusterGraphData, ClusterGraphOptions, ClusterGraphNode } from './types' +import type { ClusterGraphData, ClusterGraphOptions } from './types' echarts.use([HeatmapChart, TooltipComponent, GridComponent, VisualMapComponent, CanvasRenderer]) diff --git a/src/components/AIChat/GlobalTaskBar.vue b/src/components/AIChat/GlobalTaskBar.vue index 490630b..1e5bcd7 100644 --- a/src/components/AIChat/GlobalTaskBar.vue +++ b/src/components/AIChat/GlobalTaskBar.vue @@ -51,7 +51,7 @@ async function handleOpenTask() {