refactor: remove redundant electron/main/ai/compression wrapper

Inline createCompressionLlmAdapter and logger into the sole caller
(ipc/ai.ts) and import checkAndCompress/manualCompress directly from
@openchatlab/node-runtime. The "old API compatibility" layer was
unnecessary since there is only one internal consumer.
This commit is contained in:
digua committed 2026-05-15 22:08:31 +08:00
1 parent 787e645a60
commit 596eaa3051
2 files changed
+67 -107

No files matched your search

-100
View File
@@ -1,100 +0,0 @@
/**
* 上下文压缩 — Electron 薄包装
*
* 实际逻辑已提取到 @openchatlab/node-runtime。
* 此处提供与旧 API 兼容的函数签名,注入 Electron 的 LLM adapter 和 logger。
*/
export type { CompressionConfig, CompressionResult } from '@openchatlab/node-runtime'
export {
checkAndCompress as sharedCheckAndCompress,
manualCompress as sharedManualCompress,
} from '@openchatlab/node-runtime'
import type { CompressionConfig, CompressionResult, CompressionLlmAdapter } from '@openchatlab/node-runtime'
import {
checkAndCompress as sharedCheckAndCompress,
manualCompress as sharedManualCompress,
} from '@openchatlab/node-runtime'
import { buildPiModel, findModelDefinition } from '../llm'
import type { AIServiceConfig } from '../llm/types'
import { completeSimple, type PiTextContent } from '@openchatlab/node-runtime'
import { aiLogger } from '../logger'
import { getManager } from '../conversations'
const DEFAULT_CONTEXT_WINDOW = 128000
function createLlmAdapter(activeAIConfig: AIServiceConfig, onCompressing?: () => void): CompressionLlmAdapter {
const modelDef = findModelDefinition(activeAIConfig.provider, activeAIConfig.model || '')
const contextWindow = modelDef?.contextWindow ?? DEFAULT_CONTEXT_WINDOW
const piModel = buildPiModel(activeAIConfig)
return {
contextWindow,
compress: async (prompt: string, maxTokens: number) => {
onCompressing?.()
try {
const result = await completeSimple(
piModel,
{
systemPrompt: undefined,
messages: [{ role: 'user', content: [{ type: 'text', text: prompt }], timestamp: Date.now() }] as any,
},
{ apiKey: activeAIConfig.apiKey, maxTokens }
)
const text = result.content
.filter((item): item is PiTextContent => item.type === 'text')
.map((item) => item.text)
.join('')
return text || null
} catch (error) {
aiLogger.warn('Compression', 'LLM compression attempt failed', { error: String(error) })
return null
}
},
}
}
const electronLogger = {
info: (cat: string, msg: string, extra?: Record<string, unknown>) => aiLogger.info(cat, msg, extra),
warn: (cat: string, msg: string, extra?: Record<string, unknown>) => aiLogger.warn(cat, msg, extra),
error: (cat: string, msg: string, extra?: Record<string, unknown>) => aiLogger.error(cat, msg, extra),
}
/**
* 兼容旧 API:检查并执行上下文压缩
*/
export async function checkAndCompress(
conversationId: string,
config: CompressionConfig,
systemPrompt: string,
activeAIConfig: AIServiceConfig,
onCompressing?: () => void
): Promise<CompressionResult> {
return sharedCheckAndCompress(
conversationId,
config,
systemPrompt,
createLlmAdapter(activeAIConfig, onCompressing),
getManager(),
electronLogger
)
}
/**
* 兼容旧 API:手动压缩
*/
export async function manualCompress(
conversationId: string,
config: CompressionConfig,
systemPrompt: string,
activeAIConfig: AIServiceConfig
): Promise<CompressionResult> {
return sharedManualCompress(
conversationId,
config,
systemPrompt,
createLlmAdapter(activeAIConfig),
getManager(),
electronLogger
)
}
+67 -7
View File
@@ -9,19 +9,71 @@ import { serializeError } from '../ai/serialize-error'
import { getLogsDir } from '../paths'
import { Agent, type AgentStreamChunk, type SkillContext } from '../ai/agent'
import { getDefaultGeneralAssistantId } from '../ai/assistant/defaultGeneral'
import { getDefaultAssistantConfig, buildPiModel } from '../ai/llm'
import { checkAndCompress, manualCompress, type CompressionConfig } from '../ai/compression'
import { getDefaultAssistantConfig, buildPiModel, findModelDefinition } from '../ai/llm'
import type { AIServiceConfig } from '../ai/llm/types'
import { countMessagesTokens } from '../ai/tokenizer'
import * as assistantManager from '../ai/assistant'
import type { AssistantConfig } from '../ai/assistant/types'
import * as skillManager from '../ai/skills'
import { completeSimple, streamSimple, type PiMessage, type PiTextContent } from '@openchatlab/node-runtime'
import {
checkAndCompress,
manualCompress,
type CompressionConfig,
type CompressionLlmAdapter,
completeSimple,
streamSimple,
type PiMessage,
type PiTextContent,
} from '@openchatlab/node-runtime'
import { getManager as getConversationManager } from '../ai/conversations'
import { t } from '../i18n'
import type { ToolContext } from '../ai/tools/types'
import { TOOL_REGISTRY } from '../ai/tools/definitions'
import { getDefaultRulesForLocale, mergeRulesForLocale } from '@openchatlab/node-runtime'
import type { IpcContext } from './types'
const DEFAULT_CONTEXT_WINDOW = 128000
const compressionLogger = {
info: (cat: string, msg: string, extra?: Record<string, unknown>) => aiLogger.info(cat, msg, extra),
warn: (cat: string, msg: string, extra?: Record<string, unknown>) => aiLogger.warn(cat, msg, extra),
error: (cat: string, msg: string, extra?: Record<string, unknown>) => aiLogger.error(cat, msg, extra),
}
function createCompressionLlmAdapter(
activeAIConfig: AIServiceConfig,
onCompressing?: () => void
): CompressionLlmAdapter {
const modelDef = findModelDefinition(activeAIConfig.provider, activeAIConfig.model || '')
const contextWindow = modelDef?.contextWindow ?? DEFAULT_CONTEXT_WINDOW
const piModel = buildPiModel(activeAIConfig)
return {
contextWindow,
compress: async (prompt: string, maxTokens: number) => {
onCompressing?.()
try {
const result = await completeSimple(
piModel,
{
systemPrompt: undefined,
messages: [{ role: 'user', content: [{ type: 'text', text: prompt }], timestamp: Date.now() }] as any,
},
{ apiKey: activeAIConfig.apiKey, maxTokens }
)
const text = result.content
.filter((item): item is PiTextContent => item.type === 'text')
.map((item) => item.text)
.join('')
return text || null
} catch (error) {
aiLogger.warn('Compression', 'LLM compression attempt failed', { error: String(error) })
return null
}
},
}
}
function toPiSimpleMessages(messages: Array<{ role: string; content: string }>, timestamp: number): PiMessage[] {
// pi-ai 的 simple API 在类型上要求完整 Message 联合,这里沿用现有轻量消息格式并集中做兼容转换。
return messages.map((message) => ({
@@ -1120,8 +1172,7 @@ export function registerAIHandlers({ win }: IpcContext): void {
context.conversationId,
compressionConfig,
systemPromptForCompression,
activeAIConfig,
() => {
createCompressionLlmAdapter(activeAIConfig, () => {
win.webContents.send('agent:streamChunk', {
requestId,
chunk: {
@@ -1136,7 +1187,9 @@ export function registerAIHandlers({ win }: IpcContext): void {
} satisfies import('@electron/shared/types').AgentRuntimeStatus,
},
})
}
}),
getConversationManager(),
compressionLogger
)
aiLogger.info('IPC', `Compression result for ${requestId}`, compressionResult)
@@ -1351,7 +1404,14 @@ export function registerAIHandlers({ win }: IpcContext): void {
return { success: false, error: t('llm.notConfigured') }
}
const result = await manualCompress(conversationId, compressionConfig, systemPrompt, activeAIConfig)
const result = await manualCompress(
conversationId,
compressionConfig,
systemPrompt,
createCompressionLlmAdapter(activeAIConfig),
getConversationManager(),
compressionLogger
)
return { success: true, result }
} catch (error) {
aiLogger.error('IPC', 'Manual compression failed', { error: String(error) })