UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

107 lines (106 loc) • 4.92 kB
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)); }