@sema-agent/core
Version:
Stateless, task-oriented AI agent core
201 lines (200 loc) • 12.1 kB
JavaScript
import { persistedRuleMandateOf, ruleClearanceOf } from "../ask-origin.js";
import {} from "../hooks.js";
import { adjudicatePersistedPathRules, adjudicatePersistedRules, callPathFaceOf, faceAskSpeaksFor, laneToolNamesOf, ruleToolGrammarOf, segmentCoverageOf, suggestRulesForCommand } from "../permission-rule-model.js";
import { isAbsolutePathForm } from "../../tools/fs/safety.js";
import { effectivePathTargetOf } from "../effective-path-target.js";
import { declaredPathTargetOf, protectivePathTargetOf } from "../tool-registry.js";
import { heldBy, seatOf, wireOf } from "../tool-name-readings.js";
import { orgRuleVerdictFor, settleOrgVerdictWithin } from "../permission-rule-org.js";
import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
import { ownerStoreOf } from "../permission-rule-provider.js";
import { thrownText } from "../thrown-value.js";
import { strongestAnswer } from "../persisted-rule-arms.js";
import { gateWaitFailureOf, withGateTimeout } from "../gate-bounded-await.js";
import { ORG_ADJUDICATION_TIMEOUT_MS } from "../permission-rule-org.js";
export const PERSISTED_RULE_TOOL = "Bash";
const HANDOFF_BOUND = 256;
export function inheritedAskRuleEvidence(provider) {
const org = provider?.partitions.org === true ? "not_adjudicated" : "not_wired";
const personal = provider?.partitions.durable === true ? "not_adjudicated" : "not_wired";
return Object.freeze({ orgRevisionAbsent: org, orgRuleAbsent: org, personalRuleDotsAbsent: personal });
}
export function orgRevisionEvidenceOf(resolution, onDefect) {
const reported = resolution.revision;
if (reported === undefined)
return {};
if (typeof reported === "number" && Number.isFinite(reported))
return { revision: reported };
onDefect(`the org rule partition reported revision ${JSON.stringify(reported)} — a snapshot revision is a finite number; ` +
`the adjudication stands, but the ask carries no revision evidence for this call`);
return {};
}
export function persistedRuleHitOf(verdict) {
return verdict === undefined
? undefined
: { behavior: verdict.behavior, rules: verdict.rules.map((r) => ({ rule: r.rule, dots: r.adds.map((a) => ({ actor: a.dot.actor, counter: a.dot.counter })) })) };
}
export function persistedRuleAnswerOf(verdict) {
if (verdict?.unreadable !== undefined)
return { unreadable: true, reason: verdict.unreadable };
return persistedRuleHitOf(verdict);
}
export function pathRuleLaneAnswer(table, req, ctx) {
const bases = { ...(ctx.root !== undefined ? { root: ctx.root } : {}), ...(ctx.liveCwd !== undefined ? { cwd: ctx.liveCwd } : {}), ...(ctx.home !== undefined ? { home: ctx.home } : {}) };
const tighten = effectivePathTargetOf(req, protectivePathTargetOf(req), bases);
const allow = effectivePathTargetOf(req, declaredPathTargetOf(req), bases);
if (tighten === undefined && allow === undefined)
return undefined;
return persistedRuleAnswerOf(adjudicatePersistedPathRules(table, { tool: req.toolName, cwd: ctx.root, sessionId: ctx.sessionId, face: callPathFaceOf(req) }, { ...(tighten !== undefined ? { tighten } : {}), ...(allow !== undefined ? { allow } : {}) }, bases));
}
export function orgRuleLane(cfg) {
return {
adjudicate: async (req) => {
if (wireOf("offer.orgQuestionExemption", req) === cfg.questionToolName && cfg.questionToolMounted)
return { status: "available" };
let resolution;
try {
resolution = (await cfg.read(req.toolCallId)).org;
}
catch (err) {
return { status: "unavailable", disclosures: [`the permission-rule store threw while resolving the org partition: ${thrownText(err)}`] };
}
if (resolution.status === "unavailable" || resolution.status === "ungoverned") {
return { status: "unavailable", disclosures: resolution.status === "ungoverned" ? ["the store reports no org partition while the provider declares one — unreadable governance, never an empty one"] : resolution.disclosures };
}
const revisionCell = orgRevisionEvidenceOf(resolution, cfg.onRevisionDefect);
const command = req.args?.command;
if (!laneToolNamesOf(req).includes(PERSISTED_RULE_TOOL) || typeof command !== "string")
return { status: "available", ...revisionCell };
const verdict = orgRuleVerdictFor(resolution.rules, { tool: PERSISTED_RULE_TOOL, command });
return verdict === undefined ? { status: "available", ...revisionCell } : { status: "available", verdict, ...revisionCell };
},
};
}
export function orgVerdictBeforeClaim(cfg, req) {
const unreadable = { status: "unavailable", disclosures: [] };
const read = () => {
const store = ownerStoreOf(cfg.provider, cfg.principal, cfg.localOwnerDeclared);
return orgRuleLane({ read: () => store.effective({ sessionId: cfg.sessionId }), questionToolMounted: true, questionToolName: ASK_USER_QUESTION_TOOL_NAME, onRevisionDefect: () => undefined }).adjudicate(req);
};
return settleOrgVerdictWithin(Promise.resolve().then(read).catch(() => unreadable), unreadable, { timeoutMs: ORG_ADJUDICATION_TIMEOUT_MS, ...(cfg.signal !== undefined ? { signal: cfg.signal } : {}) });
}
export function createPermissionRuleLanes(cfg) {
const provider = cfg.provider;
if (cfg.home !== undefined && !isAbsolutePathForm(cfg.home)) {
const e = new Error(`the execution environment declares homeDir ${JSON.stringify(cfg.home)}, which is not an absolute path — a \`~/\` permission rule could not be resolved against it; declare an absolute home directory or none`);
e.code = "config.execution_env_home_dir_invalid";
throw e;
}
if (cfg.localOwnerDeclared) {
if (provider === undefined || !provider.partitions.durable) {
throw new Error("RunnerDeps.localOwnerRules is declared but no durable permission-rule partition is wired — there is no bucket for the local owner to hold rules in; refusing rather than running as if the declaration were absent");
}
if (provider.forLocalOwner === undefined) {
throw new Error("RunnerDeps.localOwnerRules is declared but the wired permission-rule provider implements no forLocalOwner() face — a provider without a local-owner bucket cannot honor the declaration; refusing rather than silently resolving zero rules");
}
}
if (provider === undefined)
return { personal: undefined, org: undefined };
const anonymous = cfg.principal === undefined || cfg.principal === "";
const store = ownerStoreOf(provider, cfg.principal, cfg.localOwnerDeclared);
const handed = new Map();
const read = () => store.effective({ sessionId: cfg.sessionId }).then((view) => {
for (const line of view.disclosures)
cfg.onDisclosure(line);
return view;
});
const hand = (toolCallId) => {
const p = read();
handed.delete(toolCallId);
handed.set(toolCallId, p);
if (handed.size > HANDOFF_BOUND) {
const oldest = handed.keys().next().value;
if (oldest !== undefined)
handed.delete(oldest);
}
p.catch(() => undefined);
return p;
};
const claim = (toolCallId) => {
const p = handed.get(toolCallId);
if (p === undefined)
return read();
handed.delete(toolCallId);
return p;
};
const org = provider.partitions.org ? orgRuleLane({ read: hand, questionToolMounted: cfg.questionToolMounted, questionToolName: cfg.questionToolName, onRevisionDefect: cfg.onRevisionDefect }) : undefined;
const personalAdjudicate = async (req) => {
if (anonymous && !cfg.localOwnerDeclared)
return undefined;
const judged = laneToolNamesOf(req).map((n) => [n, ruleToolGrammarOf(n)]);
if (!judged.some(([, g]) => g === "path") && faceAskSpeaksFor(callPathFaceOf(req)))
judged.push([req.toolName, "path"]);
if (judged.length === 0)
return undefined;
let view;
try {
view = await withGateTimeout(claim(req.toolCallId), ORG_ADJUDICATION_TIMEOUT_MS, cfg.signal, "persistedRules");
}
catch (err) {
return gateWaitFailureOf(err) === "aborted" ? { unreadable: true } : skipped(thrownText(err));
}
if (view.unreadable !== undefined)
skipped(view.unreadable, view.unreadableSources);
try {
const answer = strongestAnswer(judged.map(([n, grammar]) => judgeAgainst(view.rules.filter((r) => r.behavior !== "allow" || cfg.stripsAllow?.(r, req) !== true), { ...req, toolName: n }, grammar)));
return view.unreadable !== undefined && (answer === undefined || "segmentCoverage" in answer) ? { unreadable: true } : answer;
}
catch (err) {
const why = `judging this call against the rows threw: ${thrownText(err)}`;
cfg.onDisclosure(`the persisted rule lane could not judge a ${req.toolName} call against the rows it read — ${why}`);
return { unreadable: true, reason: why };
}
};
const judgeAgainst = (table, req, grammar) => {
const liveCwd = cfg.liveCwd();
if (grammar === "path")
return pathRuleLaneAnswer(table, req, { root: cfg.root, sessionId: cfg.sessionId, liveCwd, home: cfg.home });
const command = req.args?.command;
if (typeof command !== "string")
return undefined;
const execCwd = liveCwd !== undefined ? { execCwd: liveCwd } : {};
const verdict = adjudicatePersistedRules(table, { tool: req.toolName, command, cwd: cfg.root, sessionId: cfg.sessionId, ...execCwd });
if (verdict !== undefined)
return persistedRuleAnswerOf(verdict);
const coverage = segmentCoverageOf(command, { persisted: table }, { tool: req.toolName, cwd: cfg.root, sessionId: cfg.sessionId, ...execCwd });
return coverage !== undefined ? { segmentCoverage: coverage } : undefined;
};
const skipped = (why, sources) => (cfg.onDisclosure(why), cfg.onStoreUnreadable("call", sources), { unreadable: true });
const personal = provider.partitions.durable ? { adjudicate: personalAdjudicate } : undefined;
return { personal, org };
}
export function createRuleOffersOf(cfg) {
return (call, args, ask) => {
const toolName = wireOf("offer.laneTool", call);
if (!cfg.laneArmed || toolName !== PERSISTED_RULE_TOOL)
return {};
if ((cfg.principal === undefined || cfg.principal === "") && !cfg.localOwnerDeclared)
return {};
const tierSeat = seatOf("offer.marks", cfg.irreversibilityTier, call);
const closedDoor = ruleClearanceOf(ask, {
egress: heldBy("offer.marks.egress", cfg.egressTools, call),
irreversibility: tierSeat?.value,
shellGated: tierSeat?.shellGated(cfg.shellGatedTools, cfg.toolMarkSources) === true,
}).word;
if (closedDoor !== undefined)
return { ruleOffersAbsence: closedDoor };
const command = args?.command;
if (typeof command !== "string")
return { ruleOffersAbsence: "lane_cannot_speak" };
const offers = suggestRulesForCommand(command, {
...(ask?.segmentCoverage !== undefined ? { coverage: ask.segmentCoverage } : {}),
...(cfg.taskRoot !== undefined ? { scope: { kind: "project", root: cfg.taskRoot }, cwd: cfg.taskRoot } : {}),
...(cfg.cwdRef?.current !== undefined ? { execCwd: cfg.cwdRef.current } : {}),
...(cfg.deniesDirectoryRead !== undefined ? { deniesDirectoryRead: cfg.deniesDirectoryRead } : {}),
});
return offers.length > 0
? { ruleOffers: offers, ...(cfg.cwdRef?.current !== undefined ? { execCwd: cfg.cwdRef.current } : {}) }
: { ruleOffersAbsence: "lane_cannot_speak" };
};
}