Files
InfoRSI/src/agents/types.ts
T
iomgaa 3600b5c409 feat: 任务书 07,agents 模块与真实模型测试
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>
2026-10-03 01:03:19 -04:00

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 };