84 lines
3.4 KiB
JavaScript
84 lines
3.4 KiB
JavaScript
import {
|
|
normalizeContinuityEngineInput,
|
|
createContinuityEngineContract,
|
|
} from '../continuity/engine.mjs';
|
|
import { evaluateContinuity, buildContinuityGateBlock } from '../continuity/evaluator.mjs';
|
|
|
|
function isNonEmptyString(value) {
|
|
return typeof value === 'string' && value.trim().length > 0;
|
|
}
|
|
|
|
export function buildApprovedPlanContinuityInput(wrapperResult, autoChainPlanResult = 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 = isNonEmptyString(wrapperResult?.replyClosureState)
|
|
? wrapperResult.replyClosureState
|
|
: (wrapperResult?.handoff?.mode === 'button_path' ? 'waiting_user' : 'completed');
|
|
|
|
const dispatchReceipt = wrapperResult?.dispatchReceipt ?? null;
|
|
const nextTaskKnown = wrapperResult?.nextTaskKnown === true
|
|
|| (plannerDerivedAction != null && isNonEmptyString(autoChainPlanResult?.derivedAction) && autoChainPlanResult.derivedAction !== 'none');
|
|
const sameApprovedPlan = wrapperResult?.sameApprovedPlan === true || plannerDerivedAction != null;
|
|
const taskBoundaryStop = wrapperResult?.taskBoundaryStop === true || replyClosureState === 'completed';
|
|
const highRiskStop = wrapperResult?.highRiskStop === true;
|
|
|
|
return normalizeContinuityEngineInput({
|
|
planId: wrapperResult?.planId ?? 'hook-preflight-approved-plan',
|
|
currentTask: wrapperResult?.currentTask ?? wrapperResult?.requiredNextAction ?? 'hook-preflight-task',
|
|
taskState: wrapperResult?.taskState ?? (plannerDerivedAction ? 'complete' : null),
|
|
nextDerivedAction,
|
|
replyClosureState,
|
|
dispatchReceipt,
|
|
nextTaskKnown,
|
|
sameApprovedPlan,
|
|
taskBoundaryStop,
|
|
highRiskStop,
|
|
metadata: {
|
|
adapterSource: 'force-recall',
|
|
classification: wrapperResult?.classification ?? null,
|
|
},
|
|
});
|
|
}
|
|
|
|
export function createForceRecallContinuityAdapter(config = {}) {
|
|
const legalTerminalStates = config?.legalTerminalStates;
|
|
const label = config?.adapter?.forceRecall?.injectBlockLabel ?? 'APPROVED_PLAN_CONTINUITY_GATE';
|
|
|
|
return {
|
|
evaluate({ wrapperResult, autoChainPlanResult = null }) {
|
|
const input = buildApprovedPlanContinuityInput(wrapperResult, autoChainPlanResult);
|
|
if (!input) {
|
|
return createContinuityEngineContract({
|
|
input: null,
|
|
evaluation: null,
|
|
block: '',
|
|
options: { adapterName: 'force-recall', label },
|
|
});
|
|
}
|
|
const evaluation = evaluateContinuity(input, { legalTerminalStates });
|
|
const block = buildContinuityGateBlock(evaluation, { legalTerminalStates, label });
|
|
return createContinuityEngineContract({
|
|
input,
|
|
evaluation,
|
|
block,
|
|
options: { adapterName: 'force-recall', label },
|
|
});
|
|
},
|
|
};
|
|
}
|
|
|
|
export function runForceRecallContinuityAdapter({ wrapperResult, autoChainPlanResult = null, config = {} } = {}) {
|
|
return createForceRecallContinuityAdapter(config).evaluate({ wrapperResult, autoChainPlanResult });
|
|
}
|