@sema-agent/core
Version:
Stateless, task-oriented AI agent core
165 lines (164 loc) • 6.44 kB
JavaScript
import { TOOL_MOUNT_TAGS, pathTargetSlotOnly } from "./tool-face.js";
import { ENGINE_CARDS, TOOL_CATALOG_ENTRIES } from "./tool-catalog-entries.js";
import { seatOf } from "./tool-name-readings.js";
export function describeToolCatalog() {
return TOOL_CATALOG_ENTRIES;
}
export function catalogEntriesNamed(name) {
return TOOL_CATALOG_ENTRIES.filter((e) => e.name === name);
}
export function catalogToolNames() {
const out = new Set();
for (const e of TOOL_CATALOG_ENTRIES) {
out.add(e.name);
for (const a of e.face.aliases ?? [])
out.add(a);
}
return out;
}
const names = (pred) => {
const out = new Set();
for (const e of TOOL_CATALOG_ENTRIES)
if (pred(e))
out.add(e.name);
return out;
};
export function pathConfinableWriteToolNames() {
return names((e) => e.face.pathTarget !== undefined && e.face.pathTarget.access !== "read");
}
function toolCanPersist(t, facts) {
if (facts.exclude?.includes(t.name) ?? false)
return false;
const effect = t.effect ?? facts.effects?.get(t.name) ?? "write";
if (effect === "read")
return false;
const pathTarget = t.pathTarget ?? pathTargetOf(t.name);
const family = t.family ?? catalogEntriesNamed(t.name)[0]?.face.family;
if (!((pathTarget !== undefined && pathTarget.access !== "read") || family === "shell"))
return false;
return !facts.remoteHands;
}
export function persistenceCapableToolNames(tools, facts) {
const out = new Set();
for (const t of tools)
if (toolCanPersist(t, facts))
out.add(t.name);
return [...out];
}
export function rosterCanPersistMemory(tools, facts, declared) {
return declared ?? tools.some((t) => toolCanPersist(t, facts));
}
export function persistenceCandidateToolNames() {
const rows = TOOL_CATALOG_ENTRIES.map((e) => ({ name: e.name, effect: e.face.effect, pathTarget: e.face.pathTarget, family: e.face.family }));
return persistenceCapableToolNames(rows, { remoteHands: false });
}
export function pathTargetingToolNames() {
return names((e) => e.face.pathTarget !== undefined);
}
const onShellFace = (e) => e.face.ruleFace?.grammar === "command";
export function shellFaceToolNames() {
return names(onShellFace);
}
export function isShellFaceToolName(name) {
for (const e of TOOL_CATALOG_ENTRIES)
if (e.name === name && onShellFace(e))
return true;
return false;
}
export function readTargetToolNames() {
return names((e) => e.face.pathTarget?.access === "read");
}
export function compactableToolNames() {
return names((e) => e.face.compactable === true);
}
export function budgetExemptToolNames() {
return names((e) => e.face.budgetExempt === true);
}
export function pathTargetValue(args, pt) {
if (args === null || typeof args !== "object")
return undefined;
const a = args;
for (const k of [pt.param, ...(pt.aliases ?? [])]) {
const v = a[k];
if (typeof v === "string" && v.length > 0)
return v;
}
return undefined;
}
const FILE_ARG_PATH_TARGET = { param: "file_path", aliases: ["path"] };
export function fileArgPath(args) {
return pathTargetValue(args, FILE_ARG_PATH_TARGET);
}
export function protectivePathTargetOf(call) {
if (call.face?.pathTarget !== undefined)
return call.face.pathTarget;
const floor = seatOf("floor.protectivePathTarget", { get: pathTargetOf }, call)?.value;
return floor === undefined || call.face === undefined ? floor : pathTargetSlotOnly(floor);
}
export const BARE_REQUEST_CODE = "policy.bare_request";
export function declaredPathTargetOf(call) {
if (call.face === undefined) {
const e = new Error(`tool call ${JSON.stringify(call.toolName)} carries no face: a containment fence admits a write only by the tool's OWN declared path target, which a prepared leg's roster stamps on every gated request — a policy invoked outside a Runner must stamp \`face\` itself (toolCallFaceOf) rather than expect the catalog's declaration for the name`);
e.code = BARE_REQUEST_CODE;
throw e;
}
return call.face.pathTarget;
}
export function isProtectedWrite(call) {
const pt = protectivePathTargetOf(call);
return pt !== undefined && pt.access !== "read";
}
export function isDeclaredWrite(call) {
const pt = declaredPathTargetOf(call);
return pt !== undefined && pt.access !== "read";
}
export function fileOpAccessOf(name) {
for (const e of TOOL_CATALOG_ENTRIES) {
if (e.name === name && (e.face.family === "file-read" || e.face.family === "file-write") && e.face.pathTarget !== undefined)
return e.face.pathTarget.access;
}
return undefined;
}
export function pathTargetOf(name) {
for (const e of TOOL_CATALOG_ENTRIES)
if (e.name === name && e.face.pathTarget !== undefined)
return e.face.pathTarget;
return undefined;
}
export function catalogRuleFaceOf(name) {
for (const e of TOOL_CATALOG_ENTRIES) {
if (e.name !== name)
continue;
const pt = e.face.pathTarget;
const primary = e.face.ruleFace?.primaryParams ?? (pt !== undefined ? [pt.param, ...(pt.aliases ?? [])] : []);
const params = e.face.ruleFace?.params ?? (pt !== undefined ? [pt.param, ...(pt.aliases ?? [])] : undefined);
if (params === undefined && primary.length === 0)
continue;
return { primaryParams: [...primary], ...(params !== undefined ? { params: [...new Set([...params, ...primary])] } : {}) };
}
return undefined;
}
export function handBandEffects() {
const out = new Map();
for (const e of TOOL_CATALOG_ENTRIES) {
if (!e.mountedBy.includes("hands"))
continue;
const eff = e.face.effect ?? "write";
const prior = out.get(e.name);
if (prior === undefined || prior === "read")
out.set(e.name, eff);
}
return out;
}
export function engineCardTypes() {
const out = new Set(Object.keys(ENGINE_CARDS));
for (const e of TOOL_CATALOG_ENTRIES)
for (const card of e.cards)
out.add(card);
return out;
}
export function predictMountedToolNames(active) {
return names((e) => e.mountedBy.some((t) => active.has(t)));
}
export const TOOL_MOUNT_TAG_SET = new Set(TOOL_MOUNT_TAGS);
export { HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND } from "./tool-face.js";