feat: sync latest continuity hard-gate integration
This commit is contained in:
@@ -8,6 +8,7 @@ const execFileAsync = promisify(execFile);
|
||||
const LONG_TASK_WRAPPER_TIMEOUT_MS = 8000;
|
||||
const LONG_TASK_GATE_LOCK_TIMEOUT_MS = 8000;
|
||||
const LONG_TASK_AUTO_CHAIN_PLANNER_TIMEOUT_MS = 8000;
|
||||
const APPROVED_PLAN_CONTINUITY_TIMEOUT_MS = 8000;
|
||||
|
||||
type AutoChainPlanResult = {
|
||||
plannerStatus: string;
|
||||
@@ -30,6 +31,14 @@ type GateLockResult = {
|
||||
allowedResponseModes?: string[];
|
||||
};
|
||||
|
||||
type ApprovedPlanContinuityResult = {
|
||||
ok: boolean;
|
||||
status: string;
|
||||
verdict: string;
|
||||
reason?: string;
|
||||
gate?: string;
|
||||
};
|
||||
|
||||
function clamp(s: string, max = 1200): string {
|
||||
if (!s) return s;
|
||||
if (s.length <= max) return s;
|
||||
@@ -328,6 +337,63 @@ async function runAutoChainPlanner(workspaceDir: string, gateLockResult: GateLoc
|
||||
return runJsonScript(plannerPath, workspaceDir, input, LONG_TASK_AUTO_CHAIN_PLANNER_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
function buildApprovedPlanContinuityInput(wrapperResult: any, autoChainPlanResult: AutoChainPlanResult | null): Record<string, unknown> | null {
|
||||
if (!wrapperResult || wrapperResult.classification !== "long_task") return null;
|
||||
|
||||
const wrapperNextAction = wrapperResult?.nextDerivedAction ?? wrapperResult?.derivedAction ?? null;
|
||||
const plannerDerivedAction = autoChainPlanResult?.derivedAction && autoChainPlanResult.derivedAction !== "none"
|
||||
? {
|
||||
type: autoChainPlanResult.dispatchMode ?? "no_dispatch",
|
||||
action: autoChainPlanResult.derivedAction,
|
||||
}
|
||||
: null;
|
||||
const nextDerivedAction = wrapperNextAction ?? plannerDerivedAction;
|
||||
|
||||
if (nextDerivedAction == null) return null;
|
||||
|
||||
const replyClosureState = typeof wrapperResult?.replyClosureState === "string"
|
||||
? wrapperResult.replyClosureState
|
||||
: (wrapperResult?.handoff?.mode === "button_path" ? "waiting_user" : "completed");
|
||||
|
||||
const dispatchReceipt = wrapperResult?.dispatchReceipt ?? null;
|
||||
|
||||
return {
|
||||
planId: wrapperResult?.planId ?? "hook-preflight-approved-plan",
|
||||
currentTask: wrapperResult?.currentTask ?? wrapperResult?.requiredNextAction ?? "hook-preflight-task",
|
||||
taskState: wrapperResult?.taskState ?? (plannerDerivedAction ? "complete" : null),
|
||||
nextDerivedAction,
|
||||
replyClosureState,
|
||||
dispatchReceipt,
|
||||
};
|
||||
}
|
||||
|
||||
async function runApprovedPlanContinuityGate(workspaceDir: string, wrapperResult: any, autoChainPlanResult: AutoChainPlanResult | null): Promise<ApprovedPlanContinuityResult | null> {
|
||||
const continuityPath = path.join(workspaceDir, "scripts", "approved_plan_continuity_gate.mjs");
|
||||
const input = buildApprovedPlanContinuityInput(wrapperResult, autoChainPlanResult);
|
||||
if (!input) return null;
|
||||
return runJsonScript(continuityPath, workspaceDir, input, APPROVED_PLAN_CONTINUITY_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
function buildApprovedPlanContinuityBlock(result: ApprovedPlanContinuityResult | null): string {
|
||||
if (!result) return "";
|
||||
|
||||
const lines = [
|
||||
"[APPROVED_PLAN_CONTINUITY_GATE]",
|
||||
`status=${result.status}`,
|
||||
`verdict=${result.verdict}`,
|
||||
];
|
||||
|
||||
if (result.reason) lines.push(`reason=${result.reason}`);
|
||||
|
||||
if (result.ok === false) {
|
||||
lines.push("- HARD_GATE: Do not close out this reply as normal completion.");
|
||||
lines.push("- HARD_GATE: Route back to continuity failure until a real next dispatch receipt exists, unless closure state is waiting_user, blocked, or pending_verification.");
|
||||
}
|
||||
|
||||
lines.push("[/APPROVED_PLAN_CONTINUITY_GATE]", "");
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function buildAutoChainPlanBlock(planResult: AutoChainPlanResult | null): string {
|
||||
if (!planResult) {
|
||||
return [
|
||||
@@ -473,8 +539,11 @@ const forceRecall = async (event: any) => {
|
||||
]);
|
||||
const gateLockResult = wrapperResult ? await runLongTaskGateLock(workspaceDir, wrapperResult) : null;
|
||||
const autoChainPlanResult = wrapperResult ? await runAutoChainPlanner(workspaceDir, gateLockResult, wrapperResult) : null;
|
||||
const approvedPlanContinuityResult = wrapperResult
|
||||
? await runApprovedPlanContinuityGate(workspaceDir, wrapperResult, autoChainPlanResult)
|
||||
: null;
|
||||
|
||||
if (!rulebook && !soul && !wrapperResult && !gateLockResult && !autoChainPlanResult) return;
|
||||
if (!rulebook && !soul && !wrapperResult && !gateLockResult && !autoChainPlanResult && !approvedPlanContinuityResult) return;
|
||||
|
||||
const wrapperBlock = wrapperResult
|
||||
? [
|
||||
@@ -500,6 +569,7 @@ const forceRecall = async (event: any) => {
|
||||
|
||||
const gateLockBlock = buildGateLockBlock(gateLockResult);
|
||||
const autoChainPlanBlock = buildAutoChainPlanBlock(autoChainPlanResult);
|
||||
const approvedPlanContinuityBlock = buildApprovedPlanContinuityBlock(approvedPlanContinuityResult);
|
||||
|
||||
const recallBlock = [
|
||||
"[RECALL_GATE] Mandatory recall before ANY technical action/tool use.",
|
||||
@@ -509,6 +579,7 @@ const forceRecall = async (event: any) => {
|
||||
wrapperBlock || null,
|
||||
gateLockBlock,
|
||||
autoChainPlanBlock,
|
||||
approvedPlanContinuityBlock || null,
|
||||
rulebook ? `RULEBOOK (source: ${rulebookPath}):\n${clamp(rulebook, 1200)}` : null,
|
||||
soul ? `SOUL (source: ${soulPath}):\n${clamp(soul, 1200)}` : null,
|
||||
"[/RECALL_GATE]",
|
||||
|
||||
Reference in New Issue
Block a user