import { checkExperiment, checkHunk, checkProtocol, type CodeHunk } from "../jev/index.ts"; import type { JevJudgment } from "../vocab/index.ts"; import { programProblems } from "./checks.ts"; import { protocolBody } from "./protocol.ts"; import type { Incoming, ProtocolBody, Verdict } from "./types.ts"; // 判一份提交收不收(任务书 10 第二部分第 4、5 步):先程序检查,有一项不过就退回、不问 Jev; // 全过了再问 Jev,几问全问完再决定,有一问判"是"就退回。收不收只在这一处判(结构.md 第二部分"几条边界")。 // Jev 调不通、回答读不懂时 jev 报错,这里不接住:那不是模型交得不对,flow 按内部错误停下。 /** 判一份提交。回应、统一先拼好冻结协议主体,程序检查、问 Jev、交回都用这同一份。 */ export async function receive(inc: Incoming): Promise { const protocol = inc.kind === "response" ? protocolBody({ kind: "response", content: inc.content, original: inc.known.original }) : inc.kind === "unification" ? protocolBody({ kind: "unification", content: inc.content }) : null; const problems = programProblems(inc, protocol); if (problems.length > 0) return { accepted: false, reason: ["这份提交没有收下,要改的地方:", ...problems.map((p) => `- ${p}`)].join("\n"), jev: null }; const asked = await askJev(inc, protocol); if (asked === null) return { accepted: true, jev: null, protocol }; if (asked.flagged.length > 0) { return { accepted: false, reason: ["这份提交没有收下,Jev 判出下面几处有问题:", ...asked.flagged].join("\n\n"), jev: asked.judgments }; } return { accepted: true, jev: asked.judgments, protocol }; } /** * 问 Jev(方法.md 4.3 ⑥⑨、诊 4):回应、统一对拼好的协议问冻结条款三问;实现、修复(含诊断程序)每个差异块问代码改动五问,顺序发。 * 诊断解释与实验(诊 1)对每个实验问冻结条款三问(改动了评测、自相矛盾、太含糊,用诊断的变体问法),顺序发。 * 没有差异块的改动(二进制、只改可执行位、空文件增删)Jev 看不到内容,不问;一块都没有就等于没问,交回 null。 * 消融实现不问:冻结协议里没有登记"关掉以后"的随机性和停止条件,五问没有对照(照参考项目)。 * flagged 是退回原因里每一处的文字:只列判"是"的几问,问题名用 jev 的英文名(用户 2026-10-03 定);判"是"只看 jev 交回的 yes。 */ async function askJev(inc: Incoming, protocol: ProtocolBody | null): Promise<{ judgments: JevJudgment[]; flagged: string[] } | null> { if (inc.kind === "response" || inc.kind === "unification") { const c = await checkProtocol(inc.jevModel, protocol!); return { judgments: c.judgments, flagged: c.flagged ? [`- 冻结协议:${flaggedText(c.judgments)}`] : [] }; } if (inc.kind === "diagnosisProposal") { const judgments: JevJudgment[] = []; const flagged: string[] = []; for (const [i, experiment] of inc.content.experiments.entries()) { const c = await checkExperiment(inc.jevModel, experiment); judgments.push(...c.judgments); if (c.flagged) flagged.push(`- 第 ${i + 1} 个诊断实验(${experiment.name}):${flaggedText(c.judgments)}`); } return { judgments, flagged }; } if (inc.kind !== "implementation" && inc.kind !== "repair" && inc.kind !== "diagnosisImplementation" && inc.kind !== "diagnosisRepair") { return null; } // 走到这里程序检查已过,代码一定存成了版本。 const code = inc.known.code as Extract; if (code.hunks.length === 0) return null; const judgments: JevJudgment[] = []; const flagged: string[] = []; const nth = new Map(); for (const hunk of code.hunks) { nth.set(hunk.path, (nth.get(hunk.path) ?? 0) + 1); const c = await checkHunk(inc.jevModel, hunk, code.protocol); judgments.push(...c.judgments); if (c.flagged) flagged.push(hunkText(hunk, nth.get(hunk.path)!, c.judgments)); } return { judgments, flagged }; } /** 判"是"的那几问:问题名、概率、阈值。 */ function flaggedText(judgments: readonly JevJudgment[]): string { return judgments .filter((j) => j.yes) .map((j) => `${j.question} 概率 ${j.probability}(阈值 ${j.threshold})`) .join(";"); } const CHANGE = { added: "新增的文件", deleted: "删掉的文件", modified: "改动的文件" } as const; /** 一个差异块的退回文字:哪个文件的第几块、判"是"的几问,附差异原文。原文里有 ``` 时围栏加长,免得提前收尾。 */ function hunkText(hunk: CodeHunk, n: number, judgments: readonly JevJudgment[]): string { const longest = Math.max(0, ...(hunk.text.match(/`+/g) ?? []).map((s) => s.length)); const fence = "`".repeat(Math.max(3, longest + 1)); return [`- ${hunk.path}(${CHANGE[hunk.change]})的第 ${n} 块:${flaggedText(judgments)}`, "", `${fence}diff`, hunk.text, fence].join("\n"); }