@sema-agent/core
Version:
Stateless, task-oriented AI agent core
281 lines (280 loc) • 16.7 kB
JavaScript
import { screenGateOutcome, SETTLEMENT_IS_REFUSAL } from "../gate-outcome.js";
import { askFaceOf, classifyAsk, headlessApprovalRemedy } from "../ask-origin.js";
import { wireOf } from "../tool-name-readings.js";
import { isProtectedWrite } from "../tool-registry.js";
import { attestationOf, decisionText } from "../tool-policy.js";
import { pathDenialCardOf } from "../../tools/fs/safety.js";
import { boundInputHashOf } from "../canonical-json.js";
import { argsAsTheToolReads, argsReadFrom } from "../effective-path-target.js";
import { askUnresolvableRemedySeat } from "../ask-unresolvable-notice.js";
import { inlineUntrusted } from "../untrusted-text.js";
import { formatHookFeedback } from "../reminder-mint.js";
export function mintGateOutcome(facts) {
const settlement = facts.settled !== undefined ? Object.freeze({ ...facts.settled.settlement, who: Object.freeze({ ...facts.settled.settlement.who }) }) : undefined;
const attribution = facts.classifier !== undefined ? Object.freeze({ ...facts.classifier, ...(facts.classifier.fallback !== undefined ? { fallback: Object.freeze({ ...facts.classifier.fallback }) } : {}) }) : undefined;
const outcome = Object.freeze({
disposition: Object.freeze(facts.deniedBy !== undefined
? {
kind: "denied",
deniedBy: facts.deniedBy,
...(facts.cause !== undefined ? { cause: facts.cause } : {}),
...(attribution !== undefined ? { classifier: attribution } : {}),
...(facts.modeRefusal !== undefined ? { mode: facts.modeRefusal.mode, askClass: facts.modeRefusal.askClass, classes: Object.freeze([...facts.modeRefusal.classes]) } : {}),
}
: { kind: "allowed", ...(attribution !== undefined ? { classifier: attribution } : {}), ...(facts.released !== undefined ? { released: Object.freeze({ ...facts.released, classes: Object.freeze([...facts.released.classes]) }) } : {}) }),
...(facts.settled !== undefined ? { settlement: settlement, origin: facts.settled.origin } : {}),
});
const defects = screenGateOutcome(outcome, { reading: "producer" });
if (defects.length > 0)
throw new Error(`the tool gate composed an outcome that violates its own record: ${defects.join("; ")}`);
return outcome;
}
function releaseRecordOf(a) {
const { kind: _kind, ...record } = a;
return record;
}
export function directDeny(deniedBy) {
return mintGateOutcome({ deniedBy });
}
const SETTLEMENT_IS_HUMAN = {
human_allowed: true,
human_refused: true,
approval_window_expired: false,
denial_limit_window_expired: false,
park_sla_expired: false,
no_approver: false,
approver_unavailable: false,
approver_error: false,
approver_contract: false,
presentation_failed: false,
blanket_allow_refused: false,
policy_allowed: false,
policy_refused: false,
task_aborted: false,
};
const licensedOf = (r) => (r.inputDigest !== undefined ? { licensed: r.inputDigest } : {});
const sameClasses = (a, b) => a === undefined || b === undefined ? a === b : a.length === b.length && a.every((c, i) => c === b[i]);
export function createSettlementLedger(call) {
let settled;
const contractRefusal = (origin) => ({ settlement: { kind: "approver_contract", who: { party: "none" }, when: Date.now() }, origin });
return {
get settled() {
return settled;
},
set(next) {
settled = next;
},
fromResolved(resolved, asked, req) {
const record = attestationOf(resolved, call);
const retired = typeof resolved === "object" && resolved !== null && Object.hasOwn(resolved, "settlement");
if (asked.action !== "ask" || asked.origin === undefined) {
if (resolved.action === "allow" && record?.settlement === undefined && !retired)
return resolved;
throw new Error(`an ask for "${call.toolName}" was resolved without an origin word — the origin stamp precedes every resolution`);
}
const origin = asked.origin;
const refused = (message, by) => {
settled = by;
return { action: "deny", message, decisionReason: "mode" };
};
if (retired) {
return refused(`the resolution for "${call.toolName}" carries the retired "settlement" member — what ended a wait is an engine-minted record ` +
`(\`attestation\`), never a resolver's member; denied fail-closed rather than recording a settlement nobody can attribute`, contractRefusal(origin));
}
const edited = resolved.action === "allow" && resolved.updatedInput !== undefined;
const licensed = () => {
if (edited)
return record.inputDigest === boundInputHashOf(resolved.updatedInput);
const askedDigest = boundInputHashOf(req.args);
return record.inputDigest === askedDigest && (resolved.presentedInput === undefined || boundInputHashOf(resolved.presentedInput) === askedDigest);
};
const bound = record?.settlement !== undefined && record.origin === origin && sameClasses(record.classes, asked.classes) ? record.settlement : undefined;
const refusal = bound !== undefined && SETTLEMENT_IS_REFUSAL[bound.kind] ? bound : undefined;
if (resolved.action === "allow") {
if (refusal !== undefined)
return refused(`the resolution for "${call.toolName}" answered allow but its engine record names a refusal ("${refusal.kind}") — denied fail-closed`, { settlement: refusal, origin });
const answer = bound !== undefined && licensed() ? bound : undefined;
if (answer !== undefined) {
if (asked.requiresRealApproval === true && !SETTLEMENT_IS_HUMAN[answer.kind]) {
return refused(`approval required for "${call.toolName}" — this ask requires real approval; the resolution's engine record names an answer that is not a person's ("${answer.kind}") — denied fail-closed: ${asked.message ?? ""}`, contractRefusal(origin));
}
settled = { settlement: answer, origin, ...licensedOf(record) };
return resolved;
}
if (asked.requiresRealApproval === true) {
return refused(`approval required for "${call.toolName}" — this ask requires real approval and the resolution's allow carries no engine ` +
`settlement record for it (an answer the engine cannot attribute to anyone); denied fail-closed: ${asked.message ?? ""}`, contractRefusal(origin));
}
return resolved;
}
if (resolved.action !== "deny")
return resolved;
settled = refusal !== undefined ? { settlement: refusal, origin } : contractRefusal(origin);
return resolved;
},
fromDecision(decision) {
if (decision.action === "ask")
return { decision };
const record = attestationOf(decision, call);
const answer = record?.settlement !== undefined && record.origin !== undefined ? { settlement: record.settlement, origin: record.origin, ...licensedOf(record) } : undefined;
if (answer !== undefined)
settled = answer;
const refusal = answer !== undefined && SETTLEMENT_IS_REFUSAL[answer.settlement.kind];
if (decision.action === "allow") {
if (!refusal)
return { decision };
return { decision: { action: "deny", message: `the decision for "${call.toolName}" says allow but its engine record names a refusal ("${answer.settlement.kind}") — denied fail-closed`, decisionReason: "rule" }, deniedBy: "ask_resolution" };
}
return { decision, deniedBy: refusal ? "ask_resolution" : "policy" };
},
keepForBytes(runs) {
if (settled !== undefined && settled.licensed !== boundInputHashOf(runs) && settled.licensed !== boundInputHashOf(argsReadFrom(runs)))
settled = undefined;
},
causeOf(decision) {
return decision.action === "deny" ? attestationOf(decision, call)?.classifierCause : undefined;
},
classifierRoundOf(decision) {
return attestationOf(decision, call)?.classifierRound;
},
supersede() {
settled = undefined;
},
};
}
export function cloneObserverInput(input) {
try {
return structuredClone(input);
}
catch {
if (Array.isArray(input))
return [...input];
if (input !== null && typeof input === "object")
return { ...input };
return input;
}
}
export function frozenInputSnapshot(input) {
try {
return deepFreeze(structuredClone(input));
}
catch {
return Object.freeze(Array.isArray(input) ? [...input] : input !== null && typeof input === "object" ? { ...input } : input);
}
}
function deepFreeze(value) {
if (value === null || typeof value !== "object" || Object.isFrozen(value))
return value;
Object.freeze(value);
for (const key of Reflect.ownKeys(value)) {
const d = Object.getOwnPropertyDescriptor(value, key);
if (d !== undefined && "value" in d)
deepFreeze(d.value);
}
return value;
}
const PARK_FAILURE_CAUSE_MAX = 600;
function withParkFailureCause(reason, parkFailed) {
if (parkFailed === undefined)
return reason;
return (`${reason} — note: a durable approval park was attempted for this call FIRST and could not be minted ` +
`(${inlineUntrusted(parkFailed, PARK_FAILURE_CAUSE_MAX)}), so the refusal above is what the fallback had ` +
`left to say, not the reason the call stopped.`);
}
export function passAskFace(pass) {
return askFaceOf(wireOf("gate.askFace", pass.req));
}
export async function engineFailClosedExit(pass, reason) {
const { input, toolName, toolCallId, notifyPermissionDenied } = pass;
const gate = directDeny("hook");
const finalInput = frozenInputSnapshot(pass.currentInput);
await notifyPermissionDenied({ toolName, input: cloneObserverInput(finalInput), toolCallId, reason, gate, ...(input.identity !== undefined ? { identity: input.identity } : {}) });
return { block: true, reason: formatHookFeedback(reason, input.reminderMark), gate, finalInput, preToolContext: pass.preToolContext };
}
export const unownedArgsMessage = (subject, reason) => `${subject} could not be taken into the gate's own copy (${reason}) — denied fail-closed`;
export async function unownedArgsExit(pass, reason) {
pass.decision = { action: "deny", message: unownedArgsMessage(`the arguments of "${pass.toolName}"`, reason) };
pass.deniedBy = "policy";
return await exitGate(pass);
}
export function hookDenyExit(pass, deniedReason) {
const { input } = pass;
return {
block: true,
reason: formatHookFeedback(deniedReason, input.reminderMark),
gate: directDeny("hook"),
finalInput: frozenInputSnapshot(pass.currentInput),
preToolContext: pass.preToolContext,
};
}
const ANCESTOR_UNRESOLVED_CLASSIFICATION = classifyAsk({ action: "ask", message: "" }, { contentQuestion: false, markedUnresolvable: true, org: undefined, tightened: undefined, mandateMarks: {} });
function unresolvableCauseOfSettlement(gate) {
if (gate.disposition.kind !== "denied" || gate.disposition.deniedBy !== "ask_resolution" || gate.settlement === undefined)
return undefined;
if (gate.settlement.kind === "approver_unavailable")
return "approver_unavailable";
if (gate.settlement.kind === "no_approver")
return "no_approver_wired";
return undefined;
}
export async function exitGate(pass) {
const { input, toolName, toolCallId, ledger, notifyPermissionDenied } = pass;
if (pass.decision.action === "deny") {
if (pass.decision.updatedInput !== undefined) {
pass.currentInput = argsAsTheToolReads(pass.req, pass.decision.updatedInput);
}
if (pass.deniedBy === undefined)
throw new Error(`the tool gate refused "${toolName}" without a refusing layer — every deny site attributes itself`);
const ancestorArbitration = pass.arbitration === undefined && pass.deniedBy === "policy" ? input.ancestorArbitrationOf?.(toolCallId) : undefined;
const modeRefusal = pass.arbitration?.kind === "denied_by_mode" ? pass.arbitration : ancestorArbitration?.kind === "denied_by_mode" ? ancestorArbitration : undefined;
if (modeRefusal !== undefined) {
pass.deniedBy = "mode";
ledger.supersede();
}
const gate = mintGateOutcome({ deniedBy: pass.deniedBy, ...(pass.denyCause !== undefined ? { cause: pass.denyCause } : {}), ...(ledger.settled !== undefined ? { settled: ledger.settled } : {}), ...(pass.classifierRound !== undefined ? { classifier: pass.classifierRound } : {}), ...(modeRefusal !== undefined ? { modeRefusal: { mode: modeRefusal.mode, askClass: modeRefusal.askClass, classes: modeRefusal.classes } } : {}) });
const foldCause = attestationOf(pass.decision, { toolCallId, toolName })?.unresolvableCause;
const unresolvable = foldCause ?? unresolvableCauseOfSettlement(gate);
const tableSeat = unresolvable !== undefined ? askUnresolvableRemedySeat(unresolvable) : undefined;
const remedySeat = tableSeat === "absent" && input.askSeatForm === "declared_none" && pass.askClassification?.classes.has("content_question") !== true ? "declared_none" : tableSeat;
const remedy = remedySeat !== undefined ? headlessApprovalRemedy({ mode: input.permissionMode?.(), classification: foldCause !== undefined ? ANCESTOR_UNRESOLVED_CLASSIFICATION : pass.askClassification, approverSeat: remedySeat, coveredWrite: isProtectedWrite(pass.req), ...(pass.shellUnplacedOptions !== undefined ? { unplacedOptions: pass.shellUnplacedOptions } : {}) }) : undefined;
const denyReason = withParkFailureCause(`${decisionText(pass.decision) ?? `tool "${toolName}" denied by policy`}${remedy !== undefined ? ` — ${remedy}` : ""}`, pass.parkFailed);
if (unresolvable !== undefined) {
const cause = unresolvable;
pass.notifier.notify(() => input.onAskUnresolvable?.({ toolName, toolCallId, cause, parkLaneExisted: pass.suspendAsk !== undefined, ...(remedy !== undefined ? { remedy } : {}) }), "toolGate.onAskUnresolvable");
}
const finalInput = frozenInputSnapshot(pass.currentInput);
await notifyPermissionDenied({
toolName,
input: cloneObserverInput(finalInput),
toolCallId,
reason: denyReason,
gate,
...(input.identity !== undefined ? { identity: input.identity } : {}),
});
return {
block: true,
reason: formatHookFeedback(denyReason, input.reminderMark),
gate,
finalInput,
...(() => {
const details = pathDenialCardOf(attestationOf(pass.decision, { toolCallId, toolName })?.pathDenial) ?? pass.denyDetails ?? (modeRefusal !== undefined ? undefined : pass.shellReadDetails);
return details !== undefined ? { details } : {};
})(),
preToolContext: pass.preToolContext,
};
}
if (pass.decision.action === "allow") {
const rw = pass.decision.updatedInput !== undefined ? pass.decision.updatedInput : pass.policyRewrite;
if (rw !== undefined)
pass.currentInput = argsAsTheToolReads(pass.req, rw);
}
ledger.keepForBytes(pass.currentInput);
const release = pass.arbitration?.kind === "released" ? pass.arbitration : (() => { if (ledger.settled !== undefined)
return undefined; const a = pass.arbitration === undefined ? input.ancestorArbitrationOf?.(toolCallId) : undefined; return a?.kind === "released" ? a : undefined; })();
return {
updatedInput: pass.currentInput,
gate: mintGateOutcome({ ...(ledger.settled !== undefined ? { settled: ledger.settled } : {}), ...(pass.classifierRound !== undefined ? { classifier: pass.classifierRound } : {}), ...(release !== undefined ? { released: releaseRecordOf(release) } : {}) }),
finalInput: frozenInputSnapshot(pass.currentInput),
preToolContext: pass.preToolContext,
};
}