UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

44 lines (43 loc) • 1.89 kB
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))}`; }