3600b5c409
src/agents 4 个文件 681 行:runSession 按角色开 Pi 子会话、发工具、核对实际加载内容, 提交参数非法 JSON、必填字段交 null、Pi 形状校验不通过都经提交回调记退回。 Pi 依赖固定 0.85.1;新增 npm run test:pi(glm-5.3 真实会话)。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
89 lines
4.3 KiB
TypeScript
89 lines
4.3 KiB
TypeScript
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<CreateAgentSessionOptions["thinkingLevel"]>;
|
|
|
|
/** 用哪个模型:provider、模型名与 Pi 的模型服务配置里的写法相同;思考档位必须写明。 */
|
|
export interface RoleModel {
|
|
provider: string;
|
|
model: string;
|
|
thinking: ThinkingLevel;
|
|
}
|
|
|
|
/** 某个角色交的提交种类,取自 vocab 的 SUBMISSION_KINDS。 */
|
|
export type KindOf<R extends Role> = {
|
|
[K in SubmissionKind]: (typeof SUBMISSION_KINDS)[K]["role"] extends R ? K : never;
|
|
}[SubmissionKind];
|
|
|
|
/**
|
|
* 模型调一次提交工具,交给提交回调的东西:
|
|
* - 形状合格:内容和"替换哪一份"(只有研究者的提交能替换,其余永远是 null);
|
|
* - 形状不合格:Pi 解析出的参数原样、退回原因。agents 已经把这个原因回给模型,
|
|
* 回调只需记一条退回(方法.md 第三部分:被退回的提交也记),它交回的回执不再回给模型。
|
|
*/
|
|
export type SubmitAttempt<K extends SubmissionKind> =
|
|
| { shape: "valid"; content: Submission<K>; replaces: string | null }
|
|
| { shape: "invalid"; raw: Json; reason: string };
|
|
|
|
/** 提交回调的回答:收下和编号,或退回和原因。agents 原样回给模型。 */
|
|
export type SubmitReceipt = { accepted: true; id: string } | { accepted: false; reason: string };
|
|
|
|
/** 三种角色共有的输入。回调抛出的错误按内部错误处理:会话立即停下,错误原样抛给调用方。 */
|
|
interface Common<K extends SubmissionKind> {
|
|
model: RoleModel;
|
|
/** 角色提示词、第一条消息:materials 拼好的文字。 */
|
|
systemPrompt: string;
|
|
firstMessage: string;
|
|
/** 会话的工作目录、Pi 会话文件存放的目录,都由调用方建好。 */
|
|
workDir: string;
|
|
sessionDir: string;
|
|
/** 这次要交的提交种类,提交工具的参数形状就是 vocab 里它的字段定义。 */
|
|
kind: K;
|
|
/** 查一条材料:交回文字,或 null 表示看不到(不存在和看不到故意不区分)。 */
|
|
query(ref: string): string | null;
|
|
submit(attempt: SubmitAttempt<K>): Promise<SubmitReceipt>;
|
|
/** 每次模型回复(包括出错重试的那几次、压缩上下文时写摘要的那次)交一份用量。 */
|
|
usage(usage: ModelUsage): void;
|
|
/** 用户中途停下研究时触发。 */
|
|
stop: AbortSignal;
|
|
}
|
|
|
|
/**
|
|
* 跑一次会话的输入,按角色区分(任务书 07 第二、三部分)。
|
|
* 研究者交上一份被收下后会话不结束:可能要交几份,或看了回执发现被截断要替换;实验员、核验员交上就结束。
|
|
*/
|
|
export type SessionTask =
|
|
| (Common<KindOf<"researcher">> & {
|
|
role: "researcher";
|
|
/** 读代码工具能读的目录。 */
|
|
readableDirs: readonly string[];
|
|
/** 写私人笔记:整份覆盖,笔记是账本记录,由回调写。 */
|
|
writeNote(body: string): void;
|
|
})
|
|
| (Common<KindOf<"verifier">> & { role: "verifier"; readableDirs: readonly string[] })
|
|
| (Common<KindOf<"experimenter">> & {
|
|
role: "experimenter";
|
|
/** 轻量检查:flow 用 tasks 和 runner 接好,交回给模型看的结果文字。 */
|
|
lightCheck(): Promise<string>;
|
|
});
|
|
|
|
/**
|
|
* 会话怎么结束的:
|
|
* - 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 };
|