import type { CreateAgentSessionOptions } from "@earendil-works/pi-coding-agent"; import type { Json, ModelUsage, Role, Submission, SUBMISSION_KINDS, SubmissionKind } from "../vocab/index.ts"; // agents 对外的约定:flow 交给它什么、拿回什么(任务书 07 第二部分)。 // agents 不碰账本、不决定给模型看什么、不判断交上来的东西好不好,这些都经下面的回调交给 flow。 /** Pi 0.85.1 的思考档位,与 config 的 THINKING_LEVELS 是同一份名单。 */ export type ThinkingLevel = NonNullable; /** 用哪个模型:provider、模型名与 Pi 的模型服务配置里的写法相同;思考档位必须写明。 */ export interface RoleModel { provider: string; model: string; thinking: ThinkingLevel; } /** 某个角色交的提交种类,取自 vocab 的 SUBMISSION_KINDS。 */ export type KindOf = { [K in SubmissionKind]: (typeof SUBMISSION_KINDS)[K]["role"] extends R ? K : never; }[SubmissionKind]; /** * 模型调一次提交工具,交给提交回调的东西: * - 形状合格:内容和"替换哪一份"(只有研究者的提交能替换,其余永远是 null); * - 形状不合格:Pi 解析出的参数原样、退回原因。agents 已经把这个原因回给模型, * 回调只需记一条退回(方法.md 第三部分:被退回的提交也记),它交回的回执不再回给模型。 */ export type SubmitAttempt = | { shape: "valid"; content: Submission; replaces: string | null } | { shape: "invalid"; raw: Json; reason: string }; /** 提交回调的回答:收下和编号,或退回和原因。agents 原样回给模型。 */ export type SubmitReceipt = { accepted: true; id: string } | { accepted: false; reason: string }; /** 三种角色共有的输入。回调抛出的错误按内部错误处理:会话立即停下,错误原样抛给调用方。 */ interface Common { model: RoleModel; /** 角色提示词、第一条消息:materials 拼好的文字。 */ systemPrompt: string; firstMessage: string; /** 会话的工作目录、Pi 会话文件存放的目录,都由调用方建好。 */ workDir: string; sessionDir: string; /** 这次要交的提交种类,提交工具的参数形状就是 vocab 里它的字段定义。 */ kind: K; /** 查一条材料:交回文字,或 null 表示看不到(不存在和看不到故意不区分)。 */ query(ref: string): string | null; submit(attempt: SubmitAttempt): Promise; /** 每次模型回复(包括出错重试的那几次、压缩上下文时写摘要的那次)交一份用量。 */ usage(usage: ModelUsage): void; /** 用户中途停下研究时触发。 */ stop: AbortSignal; } /** * 跑一次会话的输入,按角色区分(任务书 07 第二、三部分)。 * 研究者交上一份被收下后会话不结束:可能要交几份,或看了回执发现被截断要替换;实验员、核验员交上就结束。 */ export type SessionTask = | (Common> & { role: "researcher"; /** 读代码工具能读的目录。 */ readableDirs: readonly string[]; /** 写私人笔记:整份覆盖,笔记是账本记录,由回调写。 */ writeNote(body: string): void; }) | (Common> & { role: "verifier"; readableDirs: readonly string[] }) | (Common> & { role: "experimenter"; /** 轻量检查:flow 用 tasks 和 runner 接好,交回给模型看的结果文字。 */ lightCheck(): Promise; }); /** * 会话怎么结束的: * - submitted:至少有一份被收下; * - notSubmitted:模型自己停下了,一份都没被收下; * - failed:模型服务报错、子会话核对不通过等; * - stopped:用户停下。 */ export type SessionEnding = | { status: "submitted" } | { status: "notSubmitted"; reason: string } | { status: "failed"; reason: string } | { status: "stopped" }; /** 会话的结局,带墙钟时间(秒)和会话文件路径;Pi 在第一条回复之后才写会话文件,没写出来是 null。 */ export type SessionOutcome = SessionEnding & { wallSeconds: number; sessionFile: string | null };