@sema-agent/core
Version:
Stateless, task-oriented AI agent core
74 lines (73 loc) • 4.56 kB
JavaScript
import { deliverEngineNotice } from "../types.js";
import { READ_ROOT_CANDIDATE_DIR_MAX } from "../read-root-candidate.js";
import { DEFAULT_GATE_AWAIT_TIMEOUT_MS } from "../gate-bounded-await.js";
import { thrownText } from "../thrown-value.js";
import { rootAdmittingArtifactStore } from "../../tools/fs/safety.js";
export function readRootGrantOver(seats) {
const { env, writeRoots, readRoots, artifactStore } = seats;
return async (candidate, signal) => {
const c = await env.canonicalPath(candidate.dir);
if (signal.aborted)
return { ok: false, reason: "unresolvable", cause: "the lookup was cut" };
if (!c.ok)
return { ok: false, reason: "unresolvable", cause: `${c.error.code}: ${c.error.message}` };
if (c.value !== candidate.dir)
return { ok: false, reason: "resolves_elsewhere", cause: `it resolves to ${c.value}` };
const store = artifactStore.current;
if (store !== undefined && rootAdmittingArtifactStore(store, [c.value]) !== undefined)
return { ok: false, reason: "admits_artifact_store", cause: "the Artifact tool's ledger and stored files stay outside every root the file tools reach" };
if (!writeRoots.includes(c.value) && !readRoots.includes(c.value))
readRoots.push(c.value);
return { ok: true, root: c.value };
};
}
export function settleReadRootGrant(screen, grant, at) {
if (screen === undefined)
return undefined;
const ids = { toolName: at.toolName, toolCallId: at.toolCallId, sessionId: at.sessionId, runId: at.runId, ...(at.taskId !== undefined ? { taskId: at.taskId } : {}) };
const reject = (reason, offered, requested, why) => deliverEngineNotice(at.onNotice, {
code: "approval.read_root_grant_rejected",
message: `the approval for "${at.toolName}" asked to add a read directory, and nothing was added: ${why}. The approval's own verdict is unchanged.`,
detail: { reason, ...(offered !== undefined ? { offered } : {}), ...(requested !== undefined ? { requested: requested.slice(0, READ_ROOT_CANDIDATE_DIR_MAX) } : {}), ...ids },
});
if (screen.verdict === "rejected") {
const why = {
on_refusal: "a directory grant rides an approval, and this answer refused the call",
not_a_string: "the grant is not a string",
no_candidate: "this approval card offered no directory",
mismatch: "the grant is not the directory the card offered (it must be sent back exactly as offered)",
}[screen.reason];
reject(screen.reason, screen.offered, screen.requested, why);
return undefined;
}
const { candidate } = screen;
if (grant === undefined) {
reject("no_read_roots", candidate.dir, candidate.dir, "this run has no read directories to widen");
return undefined;
}
const cut = AbortSignal.any([...(at.signal !== undefined ? [at.signal] : []), AbortSignal.timeout(DEFAULT_GATE_AWAIT_TIMEOUT_MS)]);
const cutShort = new Promise((resolve) => {
const onCut = () => resolve({ ok: false, reason: "unresolvable", cause: at.signal?.aborted === true ? "the call ended before it resolved" : `it did not resolve within ${DEFAULT_GATE_AWAIT_TIMEOUT_MS}ms` });
if (cut.aborted)
onCut();
else
cut.addEventListener("abort", onCut, { once: true });
});
const attempt = grant(candidate, cut).catch((err) => ({ ok: false, reason: "unresolvable", cause: thrownText(err) }));
return Promise.race([attempt, cutShort]).then((applied) => {
if (!applied.ok) {
const why = {
unresolvable: `the directory could not be resolved (${applied.cause})`,
resolves_elsewhere: `the offered path no longer resolves to itself (${applied.cause})`,
admits_artifact_store: `the directory would admit the artifact store (${applied.cause})`,
}[applied.reason];
reject(applied.reason, candidate.dir, candidate.dir, why);
return;
}
deliverEngineNotice(at.onNotice, {
code: "approval.read_root_granted",
message: `the approval for "${at.toolName}" added ${candidate.covers === "exact" ? "the path" : "the directory"} ${candidate.dir} to this run's read directories (reads only; for the rest of this run).`,
detail: { dir: candidate.dir, ...(candidate.covers !== undefined ? { covers: candidate.covers } : {}), root: applied.root, ...ids },
});
});
}