@sema-agent/core
Version:
Stateless, task-oriented AI agent core
63 lines (62 loc) • 4.09 kB
JavaScript
export function parentSpecSeatOf(spec, frozenOnQuestion) {
return Object.freeze({
...(spec.principal !== undefined ? { principal: spec.principal } : {}),
...(spec.oneShot === true ? { oneShot: true } : {}),
...(spec.clientContext !== undefined ? { clientContext: spec.clientContext } : {}),
...(frozenOnQuestion !== undefined ? { onQuestion: frozenOnQuestion } : {}),
...(spec.hooks !== undefined ? { hooks: spec.hooks } : {}),
...(spec.additionalDirectories !== undefined ? { additionalDirectories: Object.freeze([...spec.additionalDirectories]) } : {}),
...(spec.additionalReadDirectories !== undefined ? { additionalReadDirectories: Object.freeze([...spec.additionalReadDirectories]) } : {}),
...(spec.envFacts !== undefined ? { envFacts: Object.freeze({ ...spec.envFacts }) } : {}),
...(spec.memoryPersistenceCapable !== undefined ? { memoryPersistenceCapable: spec.memoryPersistenceCapable } : {}),
...(spec.compaction !== undefined ? { compaction: Object.freeze({ ...spec.compaction }) } : {}),
...(spec.skillListingBudgetFraction !== undefined ? { skillListingBudgetFraction: spec.skillListingBudgetFraction } : {}),
...(spec.skillListingMaxDescChars !== undefined ? { skillListingMaxDescChars: spec.skillListingMaxDescChars } : {}),
...(spec.fileHistory !== undefined ? { fileHistory: spec.fileHistory } : {}),
...(spec.memory?.enabled === false ? { memoryOff: true } : {}),
});
}
export function applyParentSpecSeat(child, seat) {
if (seat === undefined)
return child;
const fill = (key, value) => child[key] === undefined && value !== undefined ? { [key]: value } : {};
return {
...child,
...fill("principal", seat.principal),
...fill("clientContext", seat.clientContext),
...fill("onQuestion", seat.onQuestion),
...fill("hooks", seat.hooks),
...fill("additionalDirectories", (seat.additionalDirectories !== undefined ? [...seat.additionalDirectories] : undefined)),
...fill("additionalReadDirectories", (seat.additionalReadDirectories !== undefined ? [...seat.additionalReadDirectories] : undefined)),
...fill("envFacts", (seat.envFacts !== undefined ? { ...seat.envFacts } : undefined)),
...fill("compaction", (seat.compaction !== undefined ? { ...seat.compaction } : undefined)),
...fill("skillListingBudgetFraction", seat.skillListingBudgetFraction),
...fill("skillListingMaxDescChars", seat.skillListingMaxDescChars),
...fill("fileHistory", seat.fileHistory),
...(seat.oneShot === true ? { oneShot: true } : {}),
...(seat.memoryPersistenceCapable === false ? { memoryPersistenceCapable: false } : fill("memoryPersistenceCapable", seat.memoryPersistenceCapable)),
...(seat.memoryOff === true ? { memory: memoryTurnedOff(child.memory) } : {}),
};
}
export function memoryTurnedOff(memory) {
return { ...(memory ?? {}), enabled: false };
}
const SEAT_FACTS_ON_CTX = ["principal", "oneShot", "onQuestion", "memoryPersistenceCapable"];
export function parentSpecSeatOfCtx(ctx) {
const seat = ctx.parentSpecSeat;
const facts = SEAT_FACTS_ON_CTX.filter((k) => ctx[k] !== undefined);
if (seat === undefined) {
if (facts.length === 0)
return undefined;
throw seatRefusal(`the tool context carries ${facts.join(" / ")} but no \`parentSpecSeat\` — a delegating caller hands its children the seat it was minted (a Runner-filled ctx always carries it); spawning without it would silently drop the identity`);
}
const disagree = facts.filter((k) => (k === "oneShot" ? (ctx.oneShot === true) !== (seat.oneShot === true) : ctx[k] !== seat[k]));
if (disagree.length > 0)
throw seatRefusal(`the tool context's ${disagree.join(" / ")} disagree with its \`parentSpecSeat\` — one mint, one value`);
return seat;
}
function seatRefusal(message) {
const e = new Error(`parentSpecSeat: ${message}`);
e.code = "config.parent_spec_seat_missing";
return e;
}