@sema-agent/core
Version:
Stateless, task-oriented AI agent core
293 lines (292 loc) • 13.9 kB
JavaScript
import { lstat } from "node:fs/promises";
import { isAbsolute, dirname, resolve as resolvePath } from "node:path";
import { formatPeerNameRef, mintPeerRef, normalizePeerName, parsePeerNameRef, PEER_REF_RE } from "./cross-session-ref.js";
import { inlineUntrusted } from "../core/untrusted-text.js";
export const PEER_SESSION_RECORD_SCHEMA_VERSION = 1;
export const PEER_SESSION_RECORD_MAX_BYTES = 262_144;
export const PEER_PRESENCE_MAX_CHARS = 120;
export function peerPresenceLabelValid(v) {
return v === undefined || (typeof v === "string" && v.length <= PEER_PRESENCE_MAX_CHARS);
}
export function assertPeerPresenceValue(v) {
const bad = v === undefined ? undefined : v === null || typeof v !== "object" || Array.isArray(v) ? "peerPresence" : ["agent", "intent"].find((k) => !peerPresenceLabelValid(v[k]));
if (bad === undefined)
return;
const e = new Error(`TaskSpec.${bad === "peerPresence" ? bad : `peerPresence.${bad}`} must be ${bad === "peerPresence" ? "a plain { agent?, intent? } object" : `a string of at most ${PEER_PRESENCE_MAX_CHARS} characters`} — the peer directory refuses such a row whole, so the run would advertise a presence no listing can show`);
e.code = "config.peer_presence_invalid";
throw e;
}
export const SESSION_BOX_PREFIX = "session.";
const SESSION_ID_RE = /^[A-Za-z0-9_-]{1,80}$/;
export const PEER_SESSION_ID_GRAMMAR = "^[A-Za-z0-9_-]{1,80}$";
export function isPeerSessionId(sessionId) {
return SESSION_ID_RE.test(sessionId);
}
const SESSION_ADDRESS_RE = /^session\.([A-Za-z0-9_-]{1,80})$/i;
export function peerSessionBoxHandle(sessionId) {
if (!SESSION_ID_RE.test(sessionId))
throw new Error(`peerSessionBoxHandle: session id ${JSON.stringify(sessionId)} is outside the address grammar ^[A-Za-z0-9_-]{1,80}$`);
return `${SESSION_BOX_PREFIX}${sessionId.toLowerCase()}`;
}
export function parsePeerSessionAddress(text) {
const m = SESSION_ADDRESS_RE.exec(text.trim());
return m === null ? undefined : m[1].toLowerCase();
}
function optNumber(v) {
return v === undefined || (typeof v === "number" && Number.isFinite(v));
}
function optString(v) {
return v === undefined || typeof v === "string";
}
function optStringArray(v) {
return v === undefined || (Array.isArray(v) && v.every((x) => typeof x === "string"));
}
export function readPeerSessionRecord(raw) {
if (raw === null || typeof raw !== "object" || Array.isArray(raw))
return { ok: false, reason: "not_an_object" };
const r = raw;
if (typeof r["schemaVersion"] !== "number" || !Number.isInteger(r["schemaVersion"]) || r["schemaVersion"] < 1)
return { ok: false, reason: "schema_missing" };
if (r["schemaVersion"] > PEER_SESSION_RECORD_SCHEMA_VERSION)
return { ok: false, reason: "schema_newer" };
if (typeof r["sessionId"] !== "string" || !SESSION_ID_RE.test(r["sessionId"]))
return { ok: false, reason: "session_id_invalid" };
if (typeof r["scope"] !== "string" || r["scope"] === "")
return { ok: false, reason: "scope_invalid" };
if (typeof r["name"] !== "string" || normalizePeerName(r["name"]) === "")
return { ok: false, reason: "name_invalid" };
const liveness = r["liveness"];
if (liveness !== "live" && liveness !== "dead" && liveness !== "deleted")
return { ok: false, reason: "liveness_invalid" };
const bad = (field) => ({ ok: false, reason: "field_invalid", field });
if (!optNumber(r["startedAt"]) || r["startedAt"] === undefined)
return bad("startedAt");
if (!optNumber(r["updatedAt"]) || r["updatedAt"] === undefined)
return bad("updatedAt");
if (!optNumber(r["pid"]))
return bad("pid");
if (!optNumber(r["procStartMs"]))
return bad("procStartMs");
if (!optNumber(r["diedAt"]))
return bad("diedAt");
if (!optNumber(r["peerProtocol"]))
return bad("peerProtocol");
if (!optString(r["cwd"]))
return bad("cwd");
if (!peerPresenceLabelValid(r["agent"]))
return bad("agent");
if (!peerPresenceLabelValid(r["intent"]))
return bad("intent");
const agent = typeof r["agent"] === "string" && r["agent"].trim() !== "" ? r["agent"] : undefined;
const intent = typeof r["intent"] === "string" && r["intent"].trim() !== "" ? r["intent"] : undefined;
if (!optString(r["entrypoint"]))
return bad("entrypoint");
if (!optString(r["sockPath"]))
return bad("sockPath");
if (!optStringArray(r["formerNames"]))
return bad("formerNames");
if (!optStringArray(r["peerFeatures"]))
return bad("peerFeatures");
const nameSource = r["nameSource"];
if (nameSource !== undefined && nameSource !== "auto" && nameSource !== "flag" && nameSource !== "rename")
return bad("nameSource");
const tempo = r["tempo"];
if (tempo !== undefined && tempo !== "active" && tempo !== "idle" && tempo !== "blocked")
return bad("tempo");
const inboundPosture = r["inboundPosture"];
if (inboundPosture !== undefined && inboundPosture !== "available" && inboundPosture !== "unavailable")
return bad("inboundPosture");
const record = {
schemaVersion: r["schemaVersion"],
sessionId: r["sessionId"],
scope: r["scope"],
name: r["name"],
...(nameSource !== undefined ? { nameSource } : {}),
...(r["formerNames"] !== undefined ? { formerNames: [...r["formerNames"]] } : {}),
...(r["pid"] !== undefined ? { pid: r["pid"] } : {}),
...(r["procStartMs"] !== undefined ? { procStartMs: r["procStartMs"] } : {}),
...(r["cwd"] !== undefined ? { cwd: r["cwd"] } : {}),
...(agent !== undefined ? { agent } : {}),
...(intent !== undefined ? { intent } : {}),
startedAt: r["startedAt"],
updatedAt: r["updatedAt"],
liveness,
...(r["diedAt"] !== undefined ? { diedAt: r["diedAt"] } : {}),
...(tempo !== undefined ? { tempo } : {}),
...(r["entrypoint"] !== undefined ? { entrypoint: r["entrypoint"] } : {}),
...(r["peerProtocol"] !== undefined ? { peerProtocol: r["peerProtocol"] } : {}),
...(r["peerFeatures"] !== undefined ? { peerFeatures: [...r["peerFeatures"]] } : {}),
...(r["sockPath"] !== undefined ? { sockPath: r["sockPath"] } : {}),
...(inboundPosture !== undefined ? { inboundPosture } : {}),
};
return { ok: true, record };
}
export const defaultPeerLivenessProbe = {
processExists(pid) {
try {
process.kill(pid, 0);
return true;
}
catch (e) {
return e.code === "EPERM";
}
},
};
export function isPeerSessionProcessAlive(record, probe = defaultPeerLivenessProbe) {
if (record.liveness !== "live")
return false;
if (record.pid === undefined)
return true;
if (!probe.processExists(record.pid))
return false;
if (record.procStartMs !== undefined && probe.processStartMs !== undefined) {
const started = probe.processStartMs(record.pid);
if (started !== undefined && Math.abs(started - record.procStartMs) > 2_000)
return false;
}
return true;
}
export function mintPeerSessionCandidates(records, self) {
const entries = records.map((record) => ({ kind: "session", id: record.sessionId.toLowerCase(), record }));
const selfEntry = self !== undefined && !records.some((r) => r.sessionId.toLowerCase() === self.sessionId.toLowerCase()) ? { kind: "session", id: self.sessionId.toLowerCase() } : undefined;
return mintPeerRef(entries, selfEntry).map((e) => ({ record: e.record, ref: e.ref }));
}
function describeCandidate(c) {
const state = c.record.liveness === "live" ? "" : c.record.liveness === "dead" ? " (offline)" : " (deleted)";
return `${formatPeerNameRef(inlineUntrusted(c.record.name, 64), c.ref)}${state} → ${peerSessionBoxHandle(c.record.sessionId)}`;
}
export function resolvePeerSessions(records, to, self) {
const candidates = mintPeerSessionCandidates(records, self);
const selfId = self?.sessionId.toLowerCase();
const settle = (c, rung) => {
if (selfId !== undefined && c.record.sessionId.toLowerCase() === selfId)
return { status: "self" };
if (c.record.liveness === "deleted")
return { status: "deleted", candidate: c };
return { status: "found", candidate: c, rung };
};
const address = parsePeerSessionAddress(to);
if (address !== undefined) {
if (selfId !== undefined && address === selfId)
return { status: "self" };
const hit = candidates.find((c) => c.record.sessionId.toLowerCase() === address);
return hit === undefined ? { status: "not_found" } : settle(hit, "address");
}
const nameRef = parsePeerNameRef(to);
const rawName = nameRef?.name ?? to;
const key = normalizePeerName(rawName);
if (key === "")
return { status: "not_found" };
const byName = candidates.filter((c) => normalizePeerName(c.record.name) === key);
if (nameRef !== undefined) {
const hit = byName.find((c) => c.ref === nameRef.ref) ?? (PEER_REF_RE.test(nameRef.ref) ? candidates.find((c) => c.ref === nameRef.ref && normalizePeerName(c.record.name) === key) : undefined);
if (hit === undefined)
return { status: "stale_ref", ref: nameRef.ref };
return settle(hit, "ref");
}
if (byName.length === 0)
return { status: "not_found" };
if (byName.length === 1)
return settle(byName[0], "name");
const sorted = [...byName].sort((a, b) => (a.record.liveness === b.record.liveness ? b.record.updatedAt - a.record.updatedAt : a.record.liveness === "live" ? -1 : 1));
return {
status: "ambiguous",
candidates: sorted,
message: `"${inlineUntrusted(rawName, 64)}" matches ${sorted.length} sessions — re-send with the name and ref of the one you mean: ${sorted.map(describeCandidate).join("; ")}`,
};
}
export function createInMemoryPeerDirectory() {
const rows = new Map();
const key = (scope, sessionId) => JSON.stringify([scope, sessionId.toLowerCase()]);
return {
listPeerSessions(access) {
return [...rows.values()].filter((r) => r.scope === access.scope).map((r) => ({ ...r }));
},
upsert(record) {
const read = readPeerSessionRecord(record);
if (!read.ok)
throw new Error(`InMemoryPeerDirectory.upsert: refused row (${read.reason}${read.field !== undefined ? `: ${read.field}` : ""})`);
rows.set(key(record.scope, record.sessionId), read.record);
},
markDead(scope, sessionId, diedAt = Date.now()) {
const r = rows.get(key(scope, sessionId));
if (r === undefined || r.liveness !== "live")
return false;
rows.set(key(scope, sessionId), { ...r, liveness: "dead", diedAt, updatedAt: diedAt });
return true;
},
markDeleted(scope, sessionId, at = Date.now()) {
const r = rows.get(key(scope, sessionId));
if (r === undefined)
return false;
rows.set(key(scope, sessionId), { ...r, liveness: "deleted", diedAt: r.diedAt ?? at, updatedAt: at });
return true;
},
restorePeerSession(record) {
const k = key(record.scope, record.sessionId);
if (rows.has(k))
return false;
const read = readPeerSessionRecord(record);
if (!read.ok)
return false;
rows.set(k, read.record);
return true;
},
async sweep(scope, boxEmpty) {
const swept = [];
for (const [k, r] of [...rows.entries()]) {
if (r.scope !== scope || r.liveness === "live")
continue;
if (await boxEmpty(r.sessionId)) {
if (rows.get(k) !== r)
continue;
rows.delete(k);
swept.push(r.sessionId);
}
}
return swept;
},
};
}
export async function vetPeerRegistryDirectory(dir, opts) {
if (!isAbsolute(dir))
return { ok: false, code: "not_absolute", path: dir };
const uid = opts?.uid ?? (typeof process.getuid === "function" ? process.getuid() : undefined);
const stopAt = opts?.stopAt !== undefined ? resolvePath(opts.stopAt) : undefined;
let cursor = resolvePath(dir);
for (;;) {
let st;
try {
st = await lstat(cursor);
}
catch {
return { ok: false, code: "missing", path: cursor };
}
if (st.isSymbolicLink())
return { ok: false, code: "symlink", path: cursor };
if (!st.isDirectory())
return { ok: false, code: "not_directory", path: cursor };
const parent = dirname(cursor);
const isRoot = parent === cursor || (stopAt !== undefined && cursor === stopAt);
if (!isRoot) {
if (uid !== undefined && st.uid !== uid)
return { ok: false, code: "foreign_owner", path: cursor };
if ((st.mode & 0o022) !== 0)
return { ok: false, code: "group_or_world_writable", path: cursor };
}
if (isRoot)
return { ok: true };
cursor = parent;
}
}
export function judgePeerRecordFile(stat, selfUid) {
if (!stat.isFile)
return { ok: false, code: "not_regular" };
if (selfUid !== undefined && stat.uid !== undefined && stat.uid !== selfUid)
return { ok: false, code: "foreign_owner" };
if ((stat.mode & 0o022) !== 0)
return { ok: false, code: "group_or_world_writable" };
if (stat.size > PEER_SESSION_RECORD_MAX_BYTES)
return { ok: false, code: "too_large" };
return { ok: true };
}