@sema-agent/core
Version:
Stateless, task-oriented AI agent core
394 lines (393 loc) • 23.5 kB
JavaScript
export const ASK_ORIGINS = Object.freeze(["content_question", "ancestor_marked", "org_unavailable", "org_rule", "rule_store_unavailable", "hook", "ask_rule", "denial_limit_fallback", "shell_gate_tighten", "safety_tighten", "policy"]);
const ASK_ORIGIN_SET = new Set(ASK_ORIGINS);
export function isAskOrigin(v) {
return ASK_ORIGIN_SET.has(v);
}
export function askOriginOf(decision, facts) {
const origin = originLadder(decision, facts);
if (ORIGIN_IMPLIES_REAL_APPROVAL[origin] === "at_derivation" && decision.requiresRealApproval !== true) {
throw new Error(`ask origin "${origin}" requires the requiresRealApproval bit on the decision it was derived from, and the decision carries none — an engine mint site dropped the bit`);
}
return origin;
}
const TIGHTEN_ONLY_ORIGINS = new Set(["shell_gate_tighten", "safety_tighten"]);
export function stampAskOrigin(decision, facts, classification) {
const origin = askOriginOf(decision, facts);
const classed = askClassMembersOf(classification);
const { mandate: _selfDeclared, ...unstamped } = decision;
const clearance = ruleClearanceOf(unstamped, facts.mandateMarks);
const mandated = { ...unstamped, ...(clearance.mandated ? { mandated: true } : {}), ...(clearance.mandate !== undefined ? { mandate: clearance.mandate } : {}), ...(facts.mandateMarks.requiresUserInteraction === true ? { requiresRealApproval: true } : {}) };
if (mandated.probeReadRootCandidate === undefined || TIGHTEN_ONLY_ORIGINS.has(origin))
return { ...mandated, origin, ...classed };
const { probeReadRootCandidate: _withdrawn, ...kept } = mandated;
return { ...kept, origin, ...classed };
}
export function ruleClearanceOf(ask, marks) {
const marksWord = persistedRuleMandateOf({ ...marks, probeMandated: ask?.probeMandated === true });
const foldedDoor = (ask?.foldedAskClasses ?? []).some((c) => !MODE_ARBITRATION[c].ruleMayClear);
const doorOutsideTable = ask?.requiresRealApproval === true || ask?.decisionReason === "hook" || ask?.decisionReason === "mode" || foldedDoor || ask?.authoredBy === "deployment" || ask?.inheritedUnresolved === true || ask?.ancestorResolved === true;
const mandated = ask?.mandated === true || doorOutsideTable || marksWord !== undefined;
const stampedWord = ask?.mandated === true && isPersistedRuleMandate(ask.mandate) ? ask.mandate : undefined;
const mandate = doorOutsideTable || (ask?.mandated === true && stampedWord === undefined) ? undefined : (stampedWord ?? marksWord);
const word = (() => {
if (ask?.requiresRealApproval === true)
return "mandated";
if (Array.isArray(ask?.allowRuleShadowed) && ask.allowRuleShadowed.length > 0)
return "shadowed";
if (ask?.decisionReason === "hook")
return "mandated";
if (ask?.decisionReason === "mode" || foldedDoor)
return "mandated";
if (ask?.authoredBy === "deployment")
return "mandated";
if (ask?.matchedAskRule !== undefined)
return "shadowed";
if (ask?.inheritedUnresolved === true)
return "mandated";
if (ask?.ancestorResolved === true)
return "mandated";
return mandated ? "mandated" : undefined;
})();
return { ...(word !== undefined ? { word } : {}), mandated, ruleMayClear: !mandated && ask?.matchedAskRule === undefined, ...(mandate !== undefined ? { mandate } : {}) };
}
export function askMandateMember(ask) {
const { mandated, mandate } = ruleClearanceOf(ask, {});
const authored = ask?.authoredBy === "deployment" ? { authoredBy: "deployment" } : {};
return mandated ? { mandated: true, ...(mandate !== undefined ? { mandate } : {}), ...authored } : authored;
}
export function ownedClearanceFacts(d) {
const { mandated, requiresRealApproval, decisionReason, matchedAskRule, probeMandated, authoredBy, foldedAskClasses } = d;
return {
...(mandated === true ? { mandated } : {}),
...(Array.isArray(foldedAskClasses) && foldedAskClasses.length > 0 ? { foldedAskClasses: [...foldedAskClasses] } : {}),
...(authoredBy === "deployment" ? { authoredBy } : {}),
...(requiresRealApproval === true ? { requiresRealApproval } : {}),
...(decisionReason !== undefined ? { decisionReason } : {}),
...(typeof matchedAskRule === "string" ? { matchedAskRule } : {}),
...(probeMandated === true ? { probeMandated } : {}),
};
}
function originLadder(decision, facts) {
if (facts.contentQuestion)
return "content_question";
if (facts.markedUnresolvable)
return "ancestor_marked";
if (facts.org === "unavailable")
return "org_unavailable";
if (facts.org === "rule")
return "org_rule";
if (facts.ruleCallUnreadable === true)
return "rule_store_unavailable";
if (decision.decisionReason === "hook")
return "hook";
if (decision.matchedAskRule !== undefined)
return "ask_rule";
if (decision.denialLimitFallback !== undefined)
return "denial_limit_fallback";
if (facts.tightened === "shell_gate")
return "shell_gate_tighten";
if (facts.tightened === "safety")
return "safety_tighten";
return "policy";
}
export const ORIGIN_IMPLIES_REAL_APPROVAL = {
content_question: false,
ancestor_marked: false,
org_unavailable: "at_derivation",
org_rule: "at_derivation",
rule_store_unavailable: "at_derivation",
hook: false,
ask_rule: false,
denial_limit_fallback: "at_mint",
shell_gate_tighten: false,
safety_tighten: false,
policy: false,
};
export const PERSISTED_RULE_MANDATES = Object.freeze(["operator_always", "tool_marks", "probe_mandate", "probe_unanswered", "write_protection", "write_protection_unresolved"]);
const PERSISTED_RULE_MANDATE_SET = new Set(PERSISTED_RULE_MANDATES);
export function isPersistedRuleMandate(v) {
return PERSISTED_RULE_MANDATE_SET.has(v);
}
const MANDATE_DISCLOSURE = {
probe_mandate: "the reversibility check declared this call structurally gated (the built-in shell check raises this for a read outside the directories allowed for this session) — it is cleared by confirming this call, never by a standing allow rule",
probe_unanswered: "the reversibility check did not answer for this call (it timed out or failed), so whether the call reads outside the directories allowed for this session is unknown — it is cleared by confirming this call, never by a standing allow rule",
operator_always: "this deployment mandates per-call confirmation for shell commands (shellGate: always)",
tool_marks: "this tool carries egress/irreversibility/interaction marks (a mandated confirmation a rule cannot clear)",
write_protection: "this write's target is on the deployment's write-protection table (the agent's own configuration is guarded one look per write) — it is cleared by confirming this call, never by a standing allow rule",
write_protection_unresolved: "the write-protection judge could not resolve this write's target, so whether it lands on the protected table is unknown — it is cleared by confirming this call: no standing rule and no automatic decider answers for it, though a wired approver seat can",
};
export function mandateDisclosureOf(mandate) {
return mandate === undefined ? "an explicit ask rule matched this call (a person's ask-me-each-time outranks a standing allow rule)" : MANDATE_DISCLOSURE[mandate];
}
export function persistedRuleMandateOf(marks) {
const word = irreversibilityMandateOf(marks);
if (word === "probe_mandate" || word === "probe_unanswered")
return word;
if (marks.writeProtectionUnresolved === true)
return "write_protection_unresolved";
if (marks.writeProtected === true)
return "write_protection";
return marks.egress === true || marks.requiresUserInteraction === true ? "tool_marks" : word;
}
function irreversibilityMandateOf(marks) {
return marks.probeMandated === true
? "probe_mandate"
: marks.probeUnanswered === true
? "probe_unanswered"
: marks.shellGated === true
? marks.irreversibility === "always"
? "operator_always"
: undefined
: marks.irreversibility === "always" || marks.irreversibility === "maybe"
? "tool_marks"
: undefined;
}
export function safetyAxisOf(marks) {
const egress = marks.egress === true;
const raised = irreversibilityMandateOf(marks) !== undefined ||
(marks.shellGated === true && marks.irreversibility === "maybe" && marks.tightened === "shell_gate");
const shell = raised && marks.shellGated === true;
return egress || raised ? { egress, irreversible: raised && !shell, ...(shell ? { shell: true } : {}) } : undefined;
}
export const PERMISSION_MODES = Object.freeze(["default", "acceptEdits", "plan", "auto", "bypassPermissions", "dontAsk"]);
const PERMISSION_MODE_SET = new Set(PERMISSION_MODES);
export function isPermissionMode(v) {
return PERMISSION_MODE_SET.has(v);
}
export const PERMISSION_MODE_RANK = { plan: 0, default: 1, dontAsk: 1, acceptEdits: 2, auto: 3, bypassPermissions: 4 };
export function clampPermissionMode(declared, ceiling) {
if (declared === undefined)
return { effective: ceiling, clamped: false };
if (declared === ceiling)
return { effective: declared, clamped: false };
if (declared === "bypassPermissions")
return { effective: ceiling, clamped: true };
if ((declared === "acceptEdits" && ceiling === "auto") || (declared === "auto" && ceiling === "acceptEdits"))
return { effective: ceiling, clamped: true };
return PERMISSION_MODE_RANK[declared] <= PERMISSION_MODE_RANK[ceiling] ? { effective: declared, clamped: false } : { effective: ceiling, clamped: true };
}
export const ASK_CLASSES = Object.freeze([
"content_question",
"hook",
"ancestor",
"unverifiable_delete",
"transcript_write",
"org_rule",
"governance_unavailable",
"rule_unreadable",
"ask_rule",
"denial_limit_fallback",
"requires_user_interaction",
"operator_forced",
"shell_floor",
"write_protection_unresolved",
"probe",
"write_protection",
"tool_marks_mcp",
"tool_marks_a2a",
"policy_rra",
"artifact_shared_read",
"mode",
"unstated",
"ordinary",
]);
const ASK_CLASS_SET = new Set(ASK_CLASSES);
export function isAskClass(v) {
return ASK_CLASS_SET.has(v);
}
export const MODE_ARBITRATION = {
content_question: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: true },
hook: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
ancestor: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
unverifiable_delete: { bypassImmune: true, classifierEligible: true, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: true },
transcript_write: { bypassImmune: false, classifierEligible: true, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: true },
org_rule: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
governance_unavailable: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
rule_unreadable: { bypassImmune: false, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
ask_rule: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: true },
denial_limit_fallback: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
requires_user_interaction: { bypassImmune: true, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: true },
operator_forced: { bypassImmune: true, classifierEligible: true, sandboxAdmission: true, ruleMayClear: false, hookAskFloor: false },
shell_floor: { bypassImmune: true, classifierEligible: true, sandboxAdmission: true, ruleMayClear: false, hookAskFloor: false },
write_protection_unresolved: { bypassImmune: true, classifierEligible: false, sandboxAdmission: true, ruleMayClear: false, hookAskFloor: true },
probe: { bypassImmune: false, classifierEligible: true, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
write_protection: { bypassImmune: false, classifierEligible: true, sandboxAdmission: true, ruleMayClear: false, hookAskFloor: true },
tool_marks_mcp: { bypassImmune: false, classifierEligible: true, sandboxAdmission: true, ruleMayClear: false, hookAskFloor: false },
tool_marks_a2a: { bypassImmune: false, classifierEligible: true, sandboxAdmission: true, ruleMayClear: false, hookAskFloor: false },
policy_rra: { bypassImmune: true, classifierEligible: true, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
artifact_shared_read: { bypassImmune: false, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: true },
mode: { bypassImmune: false, classifierEligible: false, sandboxAdmission: false, ruleMayClear: false, hookAskFloor: false },
unstated: { bypassImmune: false, classifierEligible: true, sandboxAdmission: false, ruleMayClear: true, hookAskFloor: false },
ordinary: { bypassImmune: false, classifierEligible: true, sandboxAdmission: true, ruleMayClear: true, hookAskFloor: false },
};
export const RRA_EXPLAINERS = new Set(["unverifiable_delete", "transcript_write", "org_rule", "governance_unavailable", "rule_unreadable", "denial_limit_fallback", "ancestor", "artifact_shared_read", "requires_user_interaction"]);
export const RELEASABLE_ASK_CLASSES = ASK_CLASSES.filter((c) => !MODE_ARBITRATION[c].bypassImmune);
export const MODE_RELEASE_REASONS = Object.freeze(["rule_unreadable"]);
const MODE_RELEASE_REASON_SET = new Set(MODE_RELEASE_REASONS);
export function isModeReleaseReason(v) {
return MODE_RELEASE_REASON_SET.has(v);
}
export function askClassMembersOf(c) {
return { askClass: c.askClass, classes: Object.freeze(ASK_CLASSES.filter((k) => c.classes.has(k))) };
}
export function screenAskClassMembers(askClass, classes) {
if (!isAskClass(askClass) || !Array.isArray(classes) || classes.length === 0 || !classes.every(isAskClass))
return undefined;
const held = new Set(classes);
const ordered = ASK_CLASSES.filter((k) => held.has(k));
if (ordered.length !== classes.length || ordered[0] !== askClass)
return undefined;
return { askClass, classes: Object.freeze(ordered) };
}
export function decisionAskClassesOf(d) {
const out = new Set();
if (d.guard === "unverifiable_delete")
out.add("unverifiable_delete");
if (d.guard === "transcript_write")
out.add("transcript_write");
if (d.guard === "artifact_shared_read")
out.add("artifact_shared_read");
if (d.ruleUnreadable !== undefined)
out.add("rule_unreadable");
if (d.matchedAskRule !== undefined)
out.add("ask_rule");
if (d.denialLimitFallback !== undefined)
out.add("denial_limit_fallback");
if (d.authoredBy === "deployment")
out.add("operator_forced");
if (d.probeMandated === true)
out.add("probe");
if (d.decisionReason === "hook")
out.add("hook");
if (d.decisionReason === "mode")
out.add("mode");
if (d.requiresRealApproval === true && ![...out].some((c) => RRA_EXPLAINERS.has(c)))
out.add("policy_rra");
if (out.size === 0 && d.mandated === true)
out.add("operator_forced");
for (const c of d.foldedAskClasses ?? [])
out.add(c);
return out;
}
export function foldArbitrationRow(classes) {
if (classes.size === 0)
return MODE_ARBITRATION.ordinary;
let bypassImmune = false, classifierEligible = true, sandboxAdmission = true, ruleMayClear = true, hookAskFloor = false;
for (const c of classes) {
const row = MODE_ARBITRATION[c];
bypassImmune ||= row.bypassImmune;
classifierEligible &&= row.classifierEligible;
sandboxAdmission &&= row.sandboxAdmission;
ruleMayClear &&= row.ruleMayClear;
hookAskFloor ||= row.hookAskFloor;
}
return { bypassImmune, classifierEligible, sandboxAdmission, ruleMayClear, hookAskFloor };
}
export function classifyAsk(d, facts) {
const classes = decisionAskClassesOf({ ...d, foldedAskClasses: undefined });
classes.delete("policy_rra");
if (facts.contentQuestion)
classes.add("content_question");
if (facts.markedUnresolvable)
classes.add("ancestor");
if (facts.org === "rule")
classes.add("org_rule");
if (facts.org === "unavailable")
classes.add("governance_unavailable");
if (facts.ruleCallUnreadable === true)
classes.add("rule_unreadable");
const marks = facts.mandateMarks;
if (marks.requiresUserInteraction === true)
classes.add("requires_user_interaction");
if (marks.shellGated === true && marks.irreversibility === "always")
classes.add("shell_floor");
const toolMarked = marks.shellGated !== true && (marks.egress === true || marks.irreversibility === "always" || marks.irreversibility === "maybe");
if (toolMarked) {
const sources = facts.toolMarkSources;
if (sources === undefined || sources.size === 0 || sources.has("deployment"))
classes.add("operator_forced");
if (sources?.has("mcp_annotation"))
classes.add("tool_marks_mcp");
if (sources?.has("a2a_default"))
classes.add(facts.a2aIsolatePeers === true ? "operator_forced" : "tool_marks_a2a");
}
if (marks.probeUnanswered === true)
classes.add("probe");
if (marks.writeProtectionUnresolved === true)
classes.add("write_protection_unresolved");
if (marks.writeProtected === true)
classes.add("write_protection");
if (facts.tightened === "unstated")
classes.add("unstated");
for (const c of facts.ancestorClasses ?? [])
classes.add(c);
if (d.requiresRealApproval === true && ![...classes].some((c) => RRA_EXPLAINERS.has(c)))
classes.add("policy_rra");
for (const c of d.foldedAskClasses ?? [])
classes.add(c);
if (classes.size === 0 && d.mandated === true)
classes.add("operator_forced");
if (classes.size === 0)
classes.add("ordinary");
const askClass = ASK_CLASSES.find((c) => classes.has(c));
return { classes, askClass, row: foldArbitrationRow(classes) };
}
export function headlessDenialMessage(toolName, askMessage) {
return `Permission for this tool use was denied: it requires interactive approval, and permission prompts are not available in this session (no approver is wired for "${toolName}" — headless auto-deny). The action was NOT performed. Do not claim it succeeded, and do not retry it in this session — report the limitation to the user, or suggest an alternative. What was requested: ${askMessage}`;
}
export function headlessApprovalRemedy(input) {
const approver = input.approverSeat === "unavailable" ? "make a person reachable through the approver that is wired (it answered `unavailable` for this ask)" : "wire an approver (`onAsk`) to put it to a person";
const c = input.classification;
if (input.mode === "acceptEdits" && input.unplacedOptions !== undefined && (c === undefined || (c.classes.size === 1 && c.classes.has("ordinary"))))
return `${fileCommandOptionsSentence(input.unplacedOptions.program)} Spell the ${input.unplacedOptions.program} without option words for the mode to answer it, or ${approver}`;
if (c?.row.bypassImmune === true)
return `no permission mode releases this ask (${c.askClass}): ${approver}, or change the call`;
if (input.mode === "plan" && c?.classes.has("mode") === true)
return `the plan permission mode asks before every write and every call to a tool the engine does not define that is not read-only — leave plan mode (\`setPermissionMode\` to another mode, or approve the plan) to run it, or ${approver}`;
if (c !== undefined && c.classes.size === 1 && c.classes.has("unstated"))
return `no rule, policy or hook granted this tool, and it states no permission of its own — grant it with an allow rule (a permission rule \`allow\` for its name, or an allow-list entry), run with \`permissionMode: "bypassPermissions"\`, or ${approver}`;
const onlyOrdinary = c === undefined || (c.classes.size === 1 && c.classes.has("ordinary"));
if (input.coveredWrite && onlyOrdinary) {
if (input.mode === "acceptEdits")
return `under \`permissionMode: "acceptEdits"\` the mode asks only for a write outside the working directories — if this target is outside them, add its directory to \`additionalDirectories\`; otherwise (or besides) ${approver}`;
if (input.mode === undefined || input.mode === "default" || input.mode === "auto")
return `the mode's write gate asks every write under \`default\`: \`permissionMode: "acceptEdits"\` lets writes inside the working directories (the task root and \`additionalDirectories\`) through without asking (a question another policy raised still stands), or ${approver}`;
}
return `run with \`permissionMode: "bypassPermissions"\` to release this ask (the release is disclosed on the call), or ${approver}`;
}
export function fileCommandOptionsSentence(program) {
return `${program} with flags requires manual approval to ensure path safety: the mode cannot automatically validate ${program} commands that use flags, as some flags like --target-directory=PATH can bypass path validation.`;
}
export function arbitrateByMode(mode, c, disclosure, call) {
const has = (k) => c.classes.has(k);
const classes = ASK_CLASSES.filter((k) => c.classes.has(k));
switch (mode) {
case "dontAsk":
return has("hook") && !c.row.hookAskFloor ? { kind: "ask" } : { kind: "denied_by_mode", mode, askClass: c.askClass, classes };
case "bypassPermissions":
if (has("write_protection_unresolved"))
return { kind: "denied_by_mode", mode, askClass: c.askClass, classes };
if (c.row.bypassImmune)
return { kind: "ask" };
const reason = [...MODE_RELEASE_REASON_SET].find((r) => has(r));
return {
kind: "released",
mode,
askClass: c.askClass,
classes,
...(disclosure?.origin !== undefined ? { origin: disclosure.origin } : {}),
...(disclosure?.mandate !== undefined ? { mandate: disclosure.mandate } : {}),
...(reason !== undefined ? { reason } : {}),
};
case "acceptEdits":
return call?.fileCommand === true && c.classes.size === 1 && c.classes.has("ordinary") ? { kind: "accepted", mode } : { kind: "ask" };
case "plan":
case "default":
case "auto":
return { kind: "ask" };
default: {
const _exhaustive = mode;
return _exhaustive;
}
}
}