Files
ChatLab/apps/desktop/main/ai/tools/shared-tool-adapter.ts
T
diguaandCursor 6c3d36e7df feat(ai): upgrade pi-ai from @mariozechner 0.54 to @earendil-works 0.74
- Replace @mariozechner/pi-ai and pi-agent-core with @earendil-works scope
- Adapt to AgentTool.execute() params type change (Record → unknown)
- Migrate Agent constructor to use initialState for systemPrompt/tools/messages
- Update onPayload callback signature to include model parameter
- Filter finalMessages with isPiMessage() for new AgentMessage union type
- Use state.errorMessage instead of deprecated state.error

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 23:19:47 +08:00

84 lines
3.1 KiB
TypeScript

/**
* 共享工具适配器
*
* 将 @openchatlab/tools 的 ToolDefinition 转换为 Electron 的 ToolRegistryEntry。
* Electron 端使用 WorkerDataProvider 替代 Server 端的 CoreDataProvider。
*/
import type { ToolDefinition, ToolExecutionContext } from '@openchatlab/tools'
import type { AgentTool, AgentToolResult } from '@openchatlab/node-runtime'
import { batchSegmentWithFrequency } from '@openchatlab/node-runtime'
import type { ToolContext, ToolRegistryEntry, ToolCategory } from './types'
import { WorkerDataProvider } from './worker-data-provider'
import { t as i18nT } from '../../i18n'
interface AdaptOptions {
category: ToolCategory
truncationStrategy?: 'keep_first' | 'keep_last'
}
function buildExecutionContext(ctx: ToolContext): ToolExecutionContext {
return {
dataProvider: new WorkerDataProvider(ctx.sessionId),
sessionId: ctx.sessionId,
locale: ctx.locale,
timeFilter: ctx.timeFilter,
searchContextBefore: ctx.searchContextBefore,
searchContextAfter: ctx.searchContextAfter,
maxMessagesLimit: ctx.maxMessagesLimit,
segmentText: (texts, locale, options) => batchSegmentWithFrequency(texts, locale as any, options as any),
translateTemplate: (key: string) => {
const translated = i18nT(key)
return translated !== key ? translated : undefined
},
}
}
export function adaptSharedTool(tool: ToolDefinition, options: AdaptOptions): ToolRegistryEntry {
return {
name: tool.name,
category: options.category,
truncationStrategy: options.truncationStrategy ?? tool.truncationStrategy,
factory(context: ToolContext): AgentTool<any> {
const schema = {
type: 'object' as const,
properties: { ...tool.inputSchema.properties },
required: tool.inputSchema.required ?? [],
}
return {
name: tool.name,
label: tool.name,
description: `ai.tools.${tool.name}.desc`,
parameters: schema as any,
async execute(_toolCallId: string, params: unknown): Promise<AgentToolResult<unknown>> {
const toolParams = (params && typeof params === 'object' ? params : {}) as Record<string, unknown>
const execCtx = buildExecutionContext(context)
try {
const result = await tool.handler(toolParams, execCtx)
if (result.rawMessages && result.rawMessages.length > 0) {
const baseData = (typeof result.data === 'object' && result.data !== null ? result.data : {}) as Record<
string,
unknown
>
return {
content: [{ type: 'text', text: result.content }],
details: { ...baseData, rawMessages: result.rawMessages },
}
}
return {
content: [{ type: 'text', text: result.content }],
details: result.data ?? null,
}
} catch (error) {
const msg = error instanceof Error ? error.message : String(error)
return { content: [{ type: 'text', text: `Error: ${msg}` }], details: null }
}
},
}
},
}
}