@sema-agent/core
Version:
Stateless, task-oriented AI agent core
107 lines (106 loc) • 4.92 kB
JavaScript
import { HOST_ROLES, isWordOf } from "./catalog/schema.js";
export function promptTraitsOf(facts) {
const traits = new Set();
if (facts.promptProfile !== "classic")
traits.add("lean_prompt");
if (facts.fableMitigations === true)
traits.add("fable_5_mitigations");
return traits;
}
export function catalogFactsOf(facts) {
return {
policyEnabled: facts.policyEnabled,
hooksEnabled: facts.hooksEnabled,
isolationEnabled: facts.isolationEnabled,
readFaceOpen: facts.readFaceOpen === true,
writeFaceOpen: facts.writeFaceOpen === true,
withinTaskCompactionEnabled: facts.withinTaskCompactionEnabled,
supervisorEnabled: facts.supervisorEnabled,
orchestrationEnabled: facts.orchestrationEnabled,
orchestrationDeferred: facts.orchestrationDeferred === true,
awarenessEnabled: facts.awarenessEnabled,
goalEnabled: facts.goalEnabled,
worktreeIsolated: facts.worktreeIsolated,
teammateEnabled: facts.teammateEnabled,
isSubagent: facts.isSubagent === true,
executionEnvironmentDeclared: facts.policyEnabled || facts.isolationEnabled,
};
}
export function resolveHost(task) {
const refuse = (key, value, allowed) => {
throw Object.assign(new Error(`TaskSpec.${key} is ${typeof value === "string" ? JSON.stringify(value.slice(0, 64)) : typeof value}; it is one of ${allowed.map((a) => `"${a}"`).join(", ")} (or absent)`), {
code: "config.prompt_selector_invalid",
});
};
const role = task.promptRole === undefined ? undefined : isWordOf(HOST_ROLES, task.promptRole) ? task.promptRole : refuse("promptRole", task.promptRole, HOST_ROLES);
const form = task.promptForm === undefined ? undefined : task.promptForm === "minimal" ? "minimal" : refuse("promptForm", task.promptForm, ["minimal"]);
return Object.freeze({ ...(role !== undefined ? { role } : {}), ...(form !== undefined ? { form } : {}) });
}
export function selectorsOf(facts, host = {}, binding) {
return Object.freeze({
traits: promptTraitsOf(facts),
host: Object.freeze({ role: host.role ?? "general", form: host.form ?? "standard" }),
facts: Object.freeze(catalogFactsOf(facts)),
...(binding !== undefined ? { binding } : {}),
});
}
export function selectorRecordOf(s) {
return {
...(s.binding !== undefined ? { binding: s.binding } : {}),
traits: [...s.traits].sort(),
host: { role: s.host.role, form: s.host.form },
facts: { ...s.facts },
};
}
export function factsHold(conj, facts) {
if (conj === undefined)
return true;
for (const [name, want] of Object.entries(conj))
if (facts[name] !== want)
return false;
return true;
}
function traitsHold(cond, traits) {
if (cond === undefined)
return true;
return (cond.allOf ?? []).every((t) => traits.has(t)) && !(cond.noneOf ?? []).some((t) => traits.has(t));
}
function hostHolds(cond, host) {
if (cond === undefined)
return true;
return (cond.role === undefined || cond.role === host.role) && (cond.form === undefined || cond.form === host.form);
}
function bindingHolds(cond, binding) {
if (cond === undefined)
return true;
if (cond.anyOf !== undefined)
return binding !== undefined && cond.anyOf.includes(binding);
return binding === undefined || !cond.noneOf.includes(binding);
}
export function whenHolds(when, s) {
return when === undefined || (traitsHold(when.traits, s.traits) && hostHolds(when.host, s.host) && factsHold(when.facts, s.facts) && bindingHolds(when.binding, s.binding));
}
const byText = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
const sortedSet = (xs) => Object.freeze([...new Set(xs ?? [])].sort(byText));
export function canonicalWhen(when) {
if (when === undefined)
return undefined;
const allOf = sortedSet(when.traits?.allOf);
const noneOf = sortedSet(when.traits?.noneOf);
const hostKeys = Object.keys(when.host ?? {});
const factNames = Object.keys(when.facts ?? {}).sort(byText);
const binding = when.binding;
const out = {};
if (allOf.length > 0 || noneOf.length > 0)
out.traits = Object.freeze({ ...(allOf.length > 0 ? { allOf } : {}), ...(noneOf.length > 0 ? { noneOf } : {}) });
if (hostKeys.length > 0)
out.host = Object.freeze({ ...when.host });
if (factNames.length > 0)
out.facts = Object.freeze(Object.fromEntries(factNames.map((n) => [n, when.facts[n]])));
if (binding !== undefined)
out.binding = Object.freeze(binding.anyOf !== undefined ? { anyOf: sortedSet(binding.anyOf) } : { noneOf: sortedSet(binding.noneOf) });
return Object.keys(out).length === 0 ? undefined : Object.freeze(out);
}
export function selectVariant(message, s) {
return message.variants.find((v) => whenHolds(v.when, s));
}