@sema-agent/core
Version:
Stateless, task-oriented AI agent core
77 lines (76 loc) • 3.64 kB
JavaScript
import { isToolContentOrigin, TOOL_CONTENT_ORIGINS } from "./memory-engine/content-origin.js";
import { inlineUntrusted } from "./untrusted-text.js";
export const LOCKED_KEY_REGISTRY = {
mcp: { specFields: ["mcp"] },
toolPolicy: { specFields: ["toolPolicy", "basePolicyForResumeEdit"] },
compliancePosture: { specFields: [] },
retentionPolicy: { specFields: [] },
};
function codedError(code, message) {
const e = new Error(message);
e.code = code;
return e;
}
export function resolveLockedKeys(config) {
if (config === undefined)
return new Set();
const keys = new Set();
for (const key of config.keys) {
if (!Object.prototype.hasOwnProperty.call(LOCKED_KEY_REGISTRY, key)) {
throw codedError("config.locked_registry", `lockedConfig.keys contains "${String(key)}", which is not a member of the locked-key registry ` +
`(${Object.keys(LOCKED_KEY_REGISTRY).join(", ")}). A lock that does not parse must not half-arm — ` +
`fix the deployment's lock declaration.`);
}
keys.add(key);
}
return keys;
}
export function snapshotMcpEntries(entries) {
return entries.map((entry) => Object.freeze({ ...entry }));
}
function describeDeclared(value) {
try {
return JSON.stringify(value) ?? String(value);
}
catch {
try {
return String(value);
}
catch {
return `[unrepresentable ${typeof value}]`;
}
}
}
function snapshotAndValidateMcpEntries(entries) {
const copies = snapshotMcpEntries(entries);
for (const copy of copies) {
const declared = copy.contentOrigin;
if (declared !== undefined && !isToolContentOrigin(declared)) {
throw codedError("config.mcp_content_class", `MCP server ${inlineUntrusted(typeof copy.name === "string" ? JSON.stringify(copy.name) : describeDeclared(copy.name), 80)} declares contentOrigin ` +
`${inlineUntrusted(describeDeclared(declared), 80)}, which is not one of ` +
`${TOOL_CONTENT_ORIGINS.map((v) => `"${v}"`).join(" | ")}. The declaration decides whether this server's tools ` +
`mark the session's memory externally exposed — a value this engine cannot read is refused at the door rather ` +
`than folded to a class, because folding it would let a deployment believe a declaration is in force while every ` +
`call keeps writing a one-way durable mark.`);
}
}
return copies;
}
export function preflightLockedConfig(spec, deps) {
const lockedKeys = resolveLockedKeys(deps.lockedConfig);
for (const key of lockedKeys) {
for (const field of LOCKED_KEY_REGISTRY[key].specFields) {
if (spec[field] !== undefined) {
throw codedError("config.locked_key", `TaskSpec.${field} is administratively locked by this deployment (locked key "${key}") — ` +
`the task-supplied value is refused wholesale (locks are config-time; there is no request-time ` +
`unlock). Remove the field from the task, or change the deployment's lock configuration.`);
}
}
}
return {
lockedKeys,
mcp: lockedKeys.has("mcp") || spec.mcp === undefined ? undefined : snapshotAndValidateMcpEntries(spec.mcp),
toolPolicy: lockedKeys.has("toolPolicy") ? deps.toolPolicy : (spec.toolPolicy ?? deps.toolPolicy),
basePolicyForResumeEdit: lockedKeys.has("toolPolicy") ? deps.basePolicyForResumeEdit : (spec.basePolicyForResumeEdit ?? deps.basePolicyForResumeEdit),
};
}