/** * AgentService —— 基于 @earendil-works/pi-agent-core 封装的流式 agent 服务。 * * 设计要点: * - pi agent(pi-agent-core.Agent)是"会调用工具(read/bash/edit/write)的 coding agent", * 其流式输出通过 session.subscribe(listener) 以回调形式推送, * session.prompt(text) 返回 Promise。streamChat 要把它桥接成一个 * AsyncIterable。 * - 每次 streamChat 调用都新建一个 in-memory session(无文件持久化副作用,贴合本仓库 * "runtime 不持有业务状态/不写业务库"的边界),调用结束即 dispose。 * - API key 由调用方经 auth 参数传入,通过 Agent.getApiKey 回调在每次 LLM 调用前注入, * 经 pi-ai Models 的 applyAuth → resolveProviderAuth 合成 credential 透传, * **绝不落盘**(无 CredentialStore,认证无状态化)。 * * 桥接模式说明: * pi 的事件是"被推送"的(stream),而 async iterator 是"被拉取"的。StreamBridge 在中间放一个 * 事件队列 + pending resolver: * - subscribe 的 listener 把结构化事件 push 进队列;若消费方正在 await,直接 resolve。 * - 迭代器的 next() 若队列空则挂起等待下一个事件;收到 done/error 后关闭迭代器。 * 这样既保留 pi 的事件顺序与背压语义,又让消费方可以用 for-await-of 自然消费。 */ import type { AgentEvent } from './types.js'; import type { IAgentAuth, AgentStreamEvent, IAgentStreamOptions } from '../../../core/types.js'; import { type CreateAgentSession } from './createAgentSession.js'; /** * 建 session 的工厂类型。抽出这个类型既是为了让 {@link AgentService} 在单测里能 * 注入一个 spy/session stub(验证 streamChat 给 pi 的入参,如默认 `tools: []`), * 也是为了把对 pi 的调用收口到一处。生产代码用本包的 {@link createAgentSession} * (基于 pi-agent-core.Agent + pi-ai Models 装配)。 */ /** * AgentService —— 流式 agent 服务。 * * 无状态地持有 streamChat 方法:为每次调用新建独立的 pi session, * 多次并发调用互不干扰(各自走自己的 session 与 StreamBridge)。 */ export declare class AgentService { /** * 建 session 的工厂。默认用 pi 的 `createAgentSession`;单测可注入 spy/stub * 以断言 streamChat 传给 pi 的入参(如默认 `tools: []`)而不发起真实 LLM 调用。 */ private readonly createSession; constructor(createSession?: CreateAgentSession); /** * 用给定 prompt 发起一次 agent 对话,返回结构化事件的 async iterator。 * * @param prompt 用户输入 * @param auth provider + apiKey,运行时注入,不落盘 * @param options 可选:cwd / model / thinkingLevel / systemPrompt / tools * @returns AgentStreamEvent 的 async iterable;迭代在产出 done 或 error 后自然结束 * * @example * const service = new AgentService(); * const iter = service.streamChat('整理当前目录', { provider: 'anthropic', apiKey: sk }); * for await (const ev of iter) { * if (ev.type === 'delta') process.stdout.write(ev.content); * if (ev.type === 'tool_start') console.log('tool:', ev.toolName); * } */ streamChat(prompt: string, auth: IAgentAuth, options?: IAgentStreamOptions): AsyncIterable; } /** * 把 pi-agent-core 的 {@link AgentEvent} 收敛成结构化 AgentStreamEvent。 * 返回 undefined 表示该 pi 事件不对外暴露(被过滤)。 * * 导出以便单测验证事件映射语义(不依赖真实 LLM 调用)。 * * 与旧实现(消费 pi-coding-agent 的 AgentSessionEvent)的差异: * - AgentEvent 与 AgentSessionEvent 同源(message_update.assistantMessageEvent.text_delta、 * tool_execution_start/end 字段一致),message_update / tool_execution_* 分支不变。 * - pi-agent-core 的 agent_end 无 willRetry 字段,且无 agent_settled 事件。本 runtime * tools:[] 不触发自动重试,agent_end 即终态,直接 → done。 */ export declare function translateEvent(event: AgentEvent): AgentStreamEvent | undefined; /** 单个 Pi 事件可同时产出 Tool End 与其携带的 A2UI Card UI 事件。 */ export declare function translateEvents(event: AgentEvent): AgentStreamEvent[]; /** 把任意错误归一化成 IAgentStreamError。导出以便单测。 */ export declare function toErrorEvent(err: unknown): AgentStreamEvent;