refactor(disambiguation): extract F3 rewrite path (#26)

This commit is contained in:
2026-08-24 01:44:40 +02:00
parent eccf6212f1
commit 2ed55ef131
4 changed files with 247 additions and 61 deletions
@@ -0,0 +1,77 @@
import { Type } from "typebox";
function normalizedAssumptions(assumptions) {
let normalized = assumptions;
if (typeof normalized === "string") {
try {
normalized = JSON.parse(normalized);
} catch {
normalized = [normalized];
}
}
return Array.isArray(normalized) ? normalized.map(String) : [];
}
function installDisambiguationGate(
pi,
{ workflow, session, ledger, toTextResult },
) {
// Compatibility: tool schema, labels and messages move verbatim from the
// composition root; this extraction changes ownership, not Pi behavior.
pi.registerTool({
name: "rewrite_question",
label: "Riscrittura domanda e chiusura F3 (deterministica)",
description:
"In Fase 3 scrive deterministicamente question.md, registra question_rewritten e " +
"chiude la fase senza chiedere conferma al reviewer. assumptions puo' essere array " +
"o stringa JSON.",
parameters: Type.Object({
session: Type.String(),
question: Type.String(),
assumptions: Type.Optional(Type.Any()),
}),
async execute(_id, params, _signal, _onUpdate, ctx) {
workflow.activate();
try {
const { session: sessionId, question } = params;
const current = workflow.phase(ctx, sessionId);
if (current.number !== 3) {
return toTextResult("La riscrittura automatica e' disponibile solo in Fase 3.");
}
// `tht session set-question` takes the session id as a positional argument
// (unlike phase/cte/decision, which use --session).
const args = ["set-question", sessionId, "--question", question];
for (const assumption of normalizedAssumptions(params.assumptions)) {
args.push("--assumption", assumption);
}
const mutationError = session.mutate(ctx, args, "");
if (mutationError) return mutationError;
const decisionError = ledger.record(ctx, sessionId, {
type: "question_rewritten",
subject: "domanda",
detail: question,
}, "");
if (decisionError) return decisionError;
const advanced = workflow.advance(ctx, sessionId, current.number);
if (advanced.err) return advanced.err;
return toTextResult(
`Domanda riscritta e Fase 3 completata (sessione ${sessionId}).`,
);
} catch (fatal) {
const message = (fatal.stderr || fatal.message || String(fatal)).toString().trim();
return toTextResult(
`[rewrite_question ERRORE INTERNO] ${message}. Riprova o usa un approccio diverso.`,
);
}
},
});
}
export function createDisambiguationGate(dependencies) {
return {
install: (pi) => installDisambiguationGate(pi, dependencies),
};
}