Files
ThothII/harness/.pi/extensions/gate/memory/repair.js
T
Codex d8a29bfbdd Add full shell, replaceable Omics adapter and bilingual interaction
Implement approved specification #32 and tickets #33-#37. Keep host authentication server-verified and pin session interaction language. Compile scoped base selectors for browser compatibility and retain full gutters during CSS pruning.
2026-09-13 14:26:39 +02:00

78 lines
4.8 KiB
JavaScript

import { Type } from "typebox";
export function installRepairGate(pi, { workflow, memory, waitForReviewer, toTextResult, languageFor, gateText }) {
pi.registerTool({
name: "reviewer_archive_repair",
label: "Resolve Memory / Evidence conflict",
description: "Present closed archive correction choices with current and resulting content. " +
"Pass a reason and options (id, label, archive memory|evidence, target_id, revision, " +
"complete content). Only the human selects the persistent correction. " +
"Resume with repair_id from tht memory repairs --session. Never run repair-apply yourself. " +
"This gate does not approve or advance the current workflow phase.",
parameters: Type.Object({
session: Type.String(),
repair_id: Type.Optional(Type.String()),
proposal: Type.Optional(Type.Object({
reason: Type.String(), options: Type.Array(Type.Object({
id: Type.String(), label: Type.String(),
archive: Type.Union([Type.Literal("memory"), Type.Literal("evidence")]),
target_id: Type.String(), revision: Type.String(),
content: Type.Record(Type.String(), Type.Unknown()),
}), { minItems: 1, maxItems: 5 }),
})),
}),
async execute(_id, params, _signal, _update, ctx) {
workflow.activate();
try {
if (!!params.repair_id === !!params.proposal)
return toTextResult("Supply either a new proposal or an existing repair_id.");
const locale = languageFor(ctx, params.session);
const run = args => JSON.parse(memory.execute(ctx,
[...args, "--session", params.session, "--json"]));
let repair = params.repair_id
? run(["repair-show", "--repair-id", params.repair_id])
: run(["repair-prepare", "--proposal-json", JSON.stringify(params.proposal)]);
let error;
while (true) {
const response = await waitForReviewer(ctx, {
id: `u${Date.now()}`, schema_version: 1,
phase: workflow.phase(ctx, params.session).id,
widget: "archive-repair", title: gateText(locale, "archiveRepair"),
title_i18n: gateText("en", "archiveRepair"),
...(error ? { error_i18n: gateText("en", "repairError") } : {}),
repair, error, reserved: ["other", "back", "exit"],
});
if (response.control) return toTextResult(response.control === "freetext"
? `Reviewer feedback: ${response.text}. Reformulate the repair choices. ` +
`Existing receipt ${repair.repair_id}: ${repair.status}.`
: `Reviewer requested ${response.control}. Repair ${repair.repair_id}: ${repair.status}.`);
const selected = response.choices;
if (!Array.isArray(selected) || selected.length !== 1)
return toTextResult("Invalid archive repair selection. Present the gate again.");
const choice = selected[0];
if (choice === "continue" && (repair.choice || !repair.can_apply))
return toTextResult(JSON.stringify({ repair_id: repair.repair_id,
status: repair.status, saved: repair.saved, indexed: repair.indexed,
choice: repair.choice,
correction: repair.options.find(o => o.id === repair.choice)?.content,
next: "Continue the normal question review gates. Archive status above is authoritative." }));
if (choice !== "reject" && !repair.options.some(o => o.id === choice))
return toTextResult("Select only a displayed repair choice.");
try {
repair = run(["repair-apply", "--repair-id", repair.repair_id, "--choice", choice]);
error = undefined;
if (repair.status === "rejected")
return toTextResult("All repair proposals were rejected as inadequate. " +
"No archive was changed. Reformulate the options for the reviewer.");
} catch (failure) {
error = gateText(locale, "repairError");
repair = run(["repair-show", "--repair-id", repair.repair_id]);
}
}
} catch (error) {
return toTextResult(`[reviewer_archive_repair] ${String(error.stderr || error.message || error).trim()}`);
}
},
});
}