mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-25 17:54:34 +08:00
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>
This commit is contained in:
1 parent
0ba9ae04a6
commit
6c3d36e7df
17 files changed
+388
-1211
No files matched your search
@@ -2,6 +2,7 @@
|
||||
"name": "chatlab-cli",
|
||||
"version": "0.0.0",
|
||||
"description": "ChatLab CLI & Service - Chat history analysis tool",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"chatlab": "bin/chatlab.mjs"
|
||||
},
|
||||
@@ -46,8 +47,8 @@
|
||||
"dependencies": {
|
||||
"@fastify/multipart": "^10.0.0",
|
||||
"@fastify/static": "^9.1.3",
|
||||
"@mariozechner/pi-agent-core": "0.54.2",
|
||||
"@mariozechner/pi-ai": "0.54.2",
|
||||
"@earendil-works/pi-agent-core": "0.74.2",
|
||||
"@earendil-works/pi-ai": "0.74.2",
|
||||
"@modelcontextprotocol/sdk": "^1.12.1",
|
||||
"better-sqlite3": "^12.4.6",
|
||||
"commander": "^13.1.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 工具适配层
|
||||
*
|
||||
* 将 @openchatlab/tools 的 ToolDefinition 适配为 @mariozechner/pi-agent-core 的 AgentTool 格式。
|
||||
* 将 @openchatlab/tools 的 ToolDefinition 适配为 @earendil-works/pi-agent-core 的 AgentTool 格式。
|
||||
* 消息类工具返回 rawMessages 时自动执行预处理管道(清洗、去噪、脱敏、截断、格式化)。
|
||||
*/
|
||||
|
||||
@@ -63,7 +63,8 @@ export function adaptToolsForAgent(
|
||||
label: tool.name,
|
||||
description: tool.description,
|
||||
parameters: convertJsonSchemaToParameters(tool.inputSchema) as any,
|
||||
async execute(_toolCallId: string, params: Record<string, unknown>): Promise<AgentToolResult<unknown>> {
|
||||
async execute(_toolCallId: string, params: unknown): Promise<AgentToolResult<unknown>> {
|
||||
const toolParams = (params && typeof params === 'object' ? params : {}) as Record<string, unknown>
|
||||
const ctx = getContext()
|
||||
const execCtx: ToolExecutionContext = {
|
||||
db: ctx.db,
|
||||
@@ -73,7 +74,7 @@ export function adaptToolsForAgent(
|
||||
segmentText: (texts, locale, options) => batchSegmentWithFrequency(texts, locale as any, options as any),
|
||||
}
|
||||
try {
|
||||
const result = await tool.handler(params, execCtx)
|
||||
const result = await tool.handler(toolParams, execCtx)
|
||||
|
||||
if (result.rawMessages && result.rawMessages.length > 0) {
|
||||
const pipelineResult = applyPreprocessingPipeline({
|
||||
|
||||
@@ -110,9 +110,9 @@ export class Agent {
|
||||
const errorCapturingStreamFn: typeof streamSimple = (model, context, options) => {
|
||||
return streamSimple(model, context, {
|
||||
...options,
|
||||
onPayload: (payload) => {
|
||||
onPayload: (payload, model) => {
|
||||
lastRequestPayload = payload
|
||||
options?.onPayload?.(payload)
|
||||
return options?.onPayload?.(payload, model)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -51,10 +51,11 @@ export function adaptSharedTool(tool: ToolDefinition, options: AdaptOptions): To
|
||||
label: tool.name,
|
||||
description: `ai.tools.${tool.name}.desc`,
|
||||
parameters: schema as any,
|
||||
async execute(_toolCallId: string, params: Record<string, unknown>): Promise<AgentToolResult<unknown>> {
|
||||
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(params, execCtx)
|
||||
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<
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"description": "ChatLab Node.js 运行时适配器:better-sqlite3、文件系统、路径管理",
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"dependencies": {
|
||||
"@mariozechner/pi-agent-core": "0.54.2",
|
||||
"@mariozechner/pi-ai": "0.54.2",
|
||||
"@earendil-works/pi-agent-core": "0.74.2",
|
||||
"@earendil-works/pi-ai": "0.74.2",
|
||||
"@openchatlab/core": "workspace:*",
|
||||
"better-sqlite3": "^12.4.6",
|
||||
"gray-matter": "^4.0.3",
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface ActivateSkillTool {
|
||||
parameters: Record<string, unknown>
|
||||
execute: (
|
||||
toolCallId: string,
|
||||
params: { skill_id: string },
|
||||
params: unknown,
|
||||
signal?: AbortSignal,
|
||||
onUpdate?: unknown
|
||||
) => Promise<ActivateSkillToolResult>
|
||||
@@ -53,12 +53,14 @@ export function createActivateSkillTool(options: ActivateSkillToolOptions): Acti
|
||||
},
|
||||
required: ['skill_id'],
|
||||
},
|
||||
execute: async (_toolCallId: string, params: { skill_id: string }) => {
|
||||
const skill: SkillDef | null = getSkillConfig(params.skill_id)
|
||||
execute: async (_toolCallId: string, params: unknown) => {
|
||||
const toolParams = (params && typeof params === 'object' ? params : {}) as { skill_id?: string }
|
||||
const skillId = toolParams.skill_id || ''
|
||||
const skill: SkillDef | null = getSkillConfig(skillId)
|
||||
if (!skill) {
|
||||
return {
|
||||
content: [{ type: 'text' as const, text: isZh ? '技能不存在' : 'Skill not found' }],
|
||||
details: { skillId: params.skill_id, found: false },
|
||||
details: { skillId, found: false },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +70,7 @@ export function createActivateSkillTool(options: ActivateSkillToolOptions): Acti
|
||||
: `This skill is only applicable to ${skill.chatScope === 'group' ? 'group chat' : 'private chat'} scenarios`
|
||||
return {
|
||||
content: [{ type: 'text' as const, text: scopeMsg }],
|
||||
details: { skillId: params.skill_id, found: true, applicable: false },
|
||||
details: { skillId, found: true, applicable: false },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +82,7 @@ export function createActivateSkillTool(options: ActivateSkillToolOptions): Acti
|
||||
: `Current assistant lacks tools required by this skill: ${missing.join(', ')}`
|
||||
return {
|
||||
content: [{ type: 'text' as const, text: msg }],
|
||||
details: { skillId: params.skill_id, found: true, applicable: false, missingTools: missing },
|
||||
details: { skillId, found: true, applicable: false, missingTools: missing },
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,7 +93,7 @@ export function createActivateSkillTool(options: ActivateSkillToolOptions): Acti
|
||||
|
||||
return {
|
||||
content: [{ type: 'text' as const, text: `${skill.prompt}${actionPrompt}` }],
|
||||
details: { skillId: params.skill_id, found: true, applicable: true },
|
||||
details: { skillId, found: true, applicable: true },
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
* Server 和 Electron 通过 AgentCoreOptions DI 注入平台差异。
|
||||
*/
|
||||
|
||||
import { Agent as PiAgentCore } from '@mariozechner/pi-agent-core'
|
||||
import type { AgentEvent as PiAgentEvent } from '@mariozechner/pi-agent-core'
|
||||
import { Agent as PiAgentCore } from '@earendil-works/pi-agent-core'
|
||||
import type { AgentEvent as PiAgentEvent, AgentMessage as PiAgentMessage } from '@earendil-works/pi-agent-core'
|
||||
import {
|
||||
type Message as PiMessage,
|
||||
type Usage as PiUsage,
|
||||
streamSimple as defaultStreamSimple,
|
||||
} from '@mariozechner/pi-ai'
|
||||
} from '@earendil-works/pi-ai'
|
||||
import { StreamingThinkTagParser, needsStreamingThinkParsing } from '@openchatlab/core'
|
||||
|
||||
import type { AgentCoreOptions, AgentCoreResult, AgentTokenUsage, SimpleHistoryMessage } from './types'
|
||||
@@ -49,6 +49,10 @@ function toPiHistoryMessages(messages: SimpleHistoryMessage[]): PiMessage[] {
|
||||
})
|
||||
}
|
||||
|
||||
function isPiMessage(message: PiAgentMessage): message is PiMessage {
|
||||
return message.role === 'user' || message.role === 'assistant' || message.role === 'toolResult'
|
||||
}
|
||||
|
||||
export async function runAgentCore(options: AgentCoreOptions): Promise<AgentCoreResult> {
|
||||
const {
|
||||
piModel,
|
||||
@@ -84,8 +88,11 @@ export async function runAgentCore(options: AgentCoreOptions): Promise<AgentCore
|
||||
|
||||
const coreAgent = new PiAgentCore({
|
||||
initialState: {
|
||||
systemPrompt,
|
||||
model: piModel,
|
||||
thinkingLevel: piModel.reasoning ? 'medium' : 'off',
|
||||
tools: maxToolRounds > 0 ? tools : [],
|
||||
messages: toPiHistoryMessages(history),
|
||||
},
|
||||
getApiKey: () => apiKey,
|
||||
streamFn: resolvedStreamFn,
|
||||
@@ -98,10 +105,6 @@ export async function runAgentCore(options: AgentCoreOptions): Promise<AgentCore
|
||||
},
|
||||
})
|
||||
|
||||
coreAgent.setSystemPrompt(systemPrompt)
|
||||
coreAgent.setTools(maxToolRounds > 0 ? tools : [])
|
||||
coreAgent.replaceMessages(toPiHistoryMessages(history))
|
||||
|
||||
let hasReachedToolRoundLimit = false
|
||||
const thinkingStartTime = new Map<number, number>()
|
||||
|
||||
@@ -167,7 +170,7 @@ export async function runAgentCore(options: AgentCoreOptions): Promise<AgentCore
|
||||
toolRounds += 1
|
||||
if (!hasReachedToolRoundLimit && maxToolRounds > 0 && toolRounds >= maxToolRounds) {
|
||||
hasReachedToolRoundLimit = true
|
||||
coreAgent.setTools([])
|
||||
coreAgent.state.tools = []
|
||||
coreAgent.steer({
|
||||
role: 'user',
|
||||
content: [{ type: 'text', text: steerMessage }],
|
||||
@@ -211,8 +214,8 @@ export async function runAgentCore(options: AgentCoreOptions): Promise<AgentCore
|
||||
|
||||
return {
|
||||
usage: totalUsage,
|
||||
error: coreAgent.state.error || undefined,
|
||||
finalMessages: [...coreAgent.state.messages],
|
||||
error: coreAgent.state.errorMessage || undefined,
|
||||
finalMessages: coreAgent.state.messages.filter(isPiMessage),
|
||||
toolsUsed: [...toolsUsed],
|
||||
toolRounds,
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* estimates context tokens. Platform-agnostic via generic chunk type.
|
||||
*/
|
||||
|
||||
import type { Message as PiMessage } from '@mariozechner/pi-ai'
|
||||
import type { Message as PiMessage } from '@earendil-works/pi-ai'
|
||||
import type { AgentCoreEvent } from './types'
|
||||
|
||||
// ==================== Shared types ====================
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
* 供 Server 和 Electron 两端通过 DI 适配。
|
||||
*/
|
||||
|
||||
import type { AgentTool } from '@mariozechner/pi-agent-core'
|
||||
import type { Model, Api, Message } from '@mariozechner/pi-ai'
|
||||
import type { AgentTool } from '@earendil-works/pi-agent-core'
|
||||
import type { Model, Api, Message } from '@earendil-works/pi-ai'
|
||||
|
||||
export interface AgentTokenUsage {
|
||||
promptTokens: number
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
type Model as PiModel,
|
||||
type Api as PiApi,
|
||||
type TextContent as PiTextContent,
|
||||
} from '@mariozechner/pi-ai'
|
||||
} from '@earendil-works/pi-ai'
|
||||
import type { CompressionLlmAdapter } from './types'
|
||||
|
||||
export interface CreateCompressionLlmAdapterOptions {
|
||||
|
||||
@@ -134,15 +134,15 @@ export type { PiModelConfig, BuildPiModelOptions } from './llm-builder'
|
||||
export { fetchRemoteModels, validateApiKey } from './remote-api'
|
||||
export type { RemoteModel, FetchRemoteModelsResult, RemoteApiOptions } from './remote-api'
|
||||
|
||||
// Re-exports from @mariozechner/pi-agent-core
|
||||
export type { AgentTool, AgentToolResult } from '@mariozechner/pi-agent-core'
|
||||
// Re-exports from @earendil-works/pi-agent-core
|
||||
export type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core'
|
||||
|
||||
// LLM simple streaming
|
||||
export { runSimpleLlmStream } from './llm-stream'
|
||||
export type { LlmStreamChunk, RunSimpleLlmStreamOptions } from './llm-stream'
|
||||
|
||||
// Re-exports from @mariozechner/pi-ai
|
||||
export { Type, completeSimple, streamSimple } from '@mariozechner/pi-ai'
|
||||
// Re-exports from @earendil-works/pi-ai
|
||||
export { Type, completeSimple, streamSimple } from '@earendil-works/pi-ai'
|
||||
export type {
|
||||
Model as PiModel,
|
||||
Api as PiApi,
|
||||
@@ -150,7 +150,7 @@ export type {
|
||||
Usage as PiUsage,
|
||||
TextContent as PiTextContent,
|
||||
AssistantMessage as PiAssistantMessage,
|
||||
} from '@mariozechner/pi-ai'
|
||||
} from '@earendil-works/pi-ai'
|
||||
|
||||
// ==================== RAG ====================
|
||||
export {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/**
|
||||
* Shared PiModel builder — translates an AIServiceConfig-like
|
||||
* object into a PiModel instance for @mariozechner/pi-ai.
|
||||
* object into a PiModel instance for @earendil-works/pi-ai.
|
||||
*
|
||||
* Used by both Electron and Server to eliminate duplicated
|
||||
* URL normalization, apiFormat mapping, and model construction.
|
||||
*/
|
||||
|
||||
import { BUILTIN_PROVIDERS, getBuiltinModelsByProvider, BUILTIN_MODELS, type ModelDefinition } from '@openchatlab/core'
|
||||
import type { Model as PiModel, Api as PiApi } from '@mariozechner/pi-ai'
|
||||
import type { Model as PiModel, Api as PiApi } from '@earendil-works/pi-ai'
|
||||
|
||||
export interface PiModelConfig {
|
||||
provider: string
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
* event mapping, and error handling.
|
||||
*/
|
||||
|
||||
import { streamSimple } from '@mariozechner/pi-ai'
|
||||
import type { Model as PiModel, Api as PiApi, Message as PiMessage } from '@mariozechner/pi-ai'
|
||||
import { streamSimple } from '@earendil-works/pi-ai'
|
||||
import type { Model as PiModel, Api as PiApi, Message as PiMessage } from '@earendil-works/pi-ai'
|
||||
|
||||
export interface LlmStreamChunk {
|
||||
content: string
|
||||
|
||||
@@ -16,7 +16,7 @@ import { getEmbeddingService } from '../embedding'
|
||||
import { getVectorStore } from '../store'
|
||||
import { getSessionChunks } from '../chunking'
|
||||
import { loadRAGConfig } from '../config'
|
||||
import { completeSimple, type TextContent } from '@mariozechner/pi-ai'
|
||||
import { completeSimple, type TextContent } from '@earendil-works/pi-ai'
|
||||
import { buildPiModel, type PiModelConfig } from '../../llm-builder'
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
*/
|
||||
|
||||
import { BUILTIN_PROVIDERS } from '@openchatlab/core'
|
||||
import { completeSimple } from '@mariozechner/pi-ai'
|
||||
import { completeSimple } from '@earendil-works/pi-ai'
|
||||
import { buildPiModel, normalizeOpenAICompatibleBaseUrl, type PiModelConfig } from './llm-builder'
|
||||
import type { Model as PiModel, Api as PiApi } from '@mariozechner/pi-ai'
|
||||
import type { Model as PiModel, Api as PiApi } from '@earendil-works/pi-ai'
|
||||
|
||||
export interface RemoteModel {
|
||||
id: string
|
||||
|
||||
@@ -255,7 +255,7 @@ export {
|
||||
} from './merger/temp-db'
|
||||
export type { TempDbMeta, ExportedSession } from './merger/temp-db'
|
||||
|
||||
// Re-exports: @mariozechner/pi-agent-core & @mariozechner/pi-ai
|
||||
// Re-exports: @earendil-works/pi-agent-core & @earendil-works/pi-ai
|
||||
export type { AgentTool, AgentToolResult } from './ai'
|
||||
export { Type, completeSimple, streamSimple, runSimpleLlmStream } from './ai'
|
||||
export type { LlmStreamChunk, RunSimpleLlmStreamOptions } from './ai'
|
||||
|
||||
Generated
+334
-1166
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user