feat: route force-recall continuity via plugin adapter

This commit is contained in:
Eve
2026-04-24 17:26:50 +08:00
parent b336958fc0
commit acf83824b7
8 changed files with 486 additions and 10 deletions

View File

@@ -1,6 +1,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
@@ -39,6 +40,19 @@ type ApprovedPlanContinuityResult = {
gate?: string;
};
type ForceRecallContinuityAdapterModule = {
defaultConfig?: Record<string, unknown>;
runForceRecallContinuityAdapter?: (args: {
wrapperResult: any;
autoChainPlanResult?: AutoChainPlanResult | null;
config?: Record<string, unknown>;
}) => {
input: Record<string, unknown> | null;
result: ApprovedPlanContinuityResult | null;
block: string;
};
};
function clamp(s: string, max = 1200): string {
if (!s) return s;
if (s.length <= max) return s;
@@ -376,14 +390,45 @@ function buildApprovedPlanContinuityInput(wrapperResult: any, autoChainPlanResul
};
}
const continuityAdapterModuleCache = new Map<string, Promise<ForceRecallContinuityAdapterModule | null>>();
async function loadForceRecallContinuityAdapterModule(workspaceDir: string): Promise<ForceRecallContinuityAdapterModule | null> {
const adapterPath = path.join(workspaceDir, "plugins", "continuity", "src", "index.mjs");
let modulePromise = continuityAdapterModuleCache.get(adapterPath);
if (!modulePromise) {
modulePromise = import(pathToFileURL(adapterPath).href).catch(() => null);
continuityAdapterModuleCache.set(adapterPath, modulePromise);
}
return modulePromise;
}
async function evaluateApprovedPlanContinuityViaPlugin(workspaceDir: string, wrapperResult: any, autoChainPlanResult: AutoChainPlanResult | null): Promise<{ input: Record<string, unknown> | null; result: ApprovedPlanContinuityResult | null; block: string; } | null> {
const adapterModule = await loadForceRecallContinuityAdapterModule(workspaceDir);
const runAdapter = adapterModule?.runForceRecallContinuityAdapter;
if (typeof runAdapter !== "function") return null;
return runAdapter({
wrapperResult,
autoChainPlanResult,
config: adapterModule?.defaultConfig ?? {},
});
}
async function runApprovedPlanContinuityGate(workspaceDir: string, wrapperResult: any, autoChainPlanResult: AutoChainPlanResult | null): Promise<ApprovedPlanContinuityResult | null> {
const evaluated = await evaluateApprovedPlanContinuityViaPlugin(workspaceDir, wrapperResult, autoChainPlanResult);
if (evaluated) return evaluated.result;
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 {
async function buildApprovedPlanContinuityBlock(workspaceDir: string, wrapperResult: any, autoChainPlanResult: AutoChainPlanResult | null, result: ApprovedPlanContinuityResult | null): Promise<string> {
const evaluated = await evaluateApprovedPlanContinuityViaPlugin(workspaceDir, wrapperResult, autoChainPlanResult);
if (evaluated?.block) return evaluated.block;
if (!result) return "";
const lines = [
@@ -583,7 +628,7 @@ const forceRecall = async (event: any) => {
const gateLockBlock = buildGateLockBlock(gateLockResult);
const autoChainPlanBlock = buildAutoChainPlanBlock(autoChainPlanResult);
const approvedPlanContinuityBlock = buildApprovedPlanContinuityBlock(approvedPlanContinuityResult);
const approvedPlanContinuityBlock = await buildApprovedPlanContinuityBlock(workspaceDir, wrapperResult, autoChainPlanResult, approvedPlanContinuityResult);
const recallBlock = [
"[RECALL_GATE] Mandatory recall before ANY technical action/tool use.",