@sema-agent/core
Version:
Stateless, task-oriented AI agent core
44 lines (43 loc) • 1.89 kB
JavaScript
import { createHash } from "node:crypto";
export const TOOL_NAME_MAX_CHARS = 64;
export const MINTED_TOOL_SEGMENT_MIN_CHARS = 16;
const SEGMENT_DIGEST_CHARS = 8;
const NAME_SEP = "__";
export function normalizeNameSegment(name) {
return clampNameSegment(name.replace(/[^a-zA-Z0-9_-]/g, "_"));
}
const SEGMENT_DIGEST_JOIN = "-";
export function clampNameSegment(seg, max = TOOL_NAME_MAX_CHARS) {
if (seg === "")
return "_";
if (seg.length <= max)
return seg;
const digest = createHash("sha256").update(seg).digest("hex").slice(0, SEGMENT_DIGEST_CHARS);
const keep = max - digest.length - SEGMENT_DIGEST_JOIN.length;
return keep > 0 ? `${seg.slice(0, keep)}${SEGMENT_DIGEST_JOIN}${digest}` : digest.slice(0, max);
}
function settlePeerSegment(clamped) {
const folded = clamped.replace(/_{2,}/g, "_").replace(/_+$/, "");
if (folded !== "")
return folded;
return createHash("sha256").update(clamped).digest("hex").slice(0, SEGMENT_DIGEST_CHARS);
}
export function mintNamespacePrefix(ns, peer) {
const peerBudget = Math.max(1, TOOL_NAME_MAX_CHARS - ns.prefix.length - NAME_SEP.length - MINTED_TOOL_SEGMENT_MIN_CHARS);
return `${ns.prefix}${settlePeerSegment(clampNameSegment(normalizeNameSegment(peer), peerBudget))}${NAME_SEP}`;
}
export function findNamespacePrefixCollision(ns, peers) {
const seen = new Map();
for (const peer of peers) {
const prefix = mintNamespacePrefix(ns, peer);
const first = seen.get(prefix);
if (first !== undefined)
return { prefix, peers: [first, peer] };
seen.set(prefix, peer);
}
return undefined;
}
export function mintNamespacedToolName(ns, peer, tool) {
const prefix = mintNamespacePrefix(ns, peer);
return `${prefix}${clampNameSegment(normalizeNameSegment(tool), Math.max(1, TOOL_NAME_MAX_CHARS - prefix.length))}`;
}