openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
69 lines (68 loc) • 3.37 kB
JavaScript
import { c as normalizeOptionalLowercaseString, o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js";
//#region src/agents/agent-bundle-mcp-names.ts
/** Sanitizes MCP server/tool names into stable model-facing tool ids. */
const TOOL_NAME_SAFE_RE = /[^A-Za-z0-9_-]/g;
const TOOL_NAME_MAX_PREFIX = 30;
const TOOL_NAME_MAX_TOTAL = 64;
/** Builds stable node-ID prefixes capped at 32 characters. */
function sanitizeNodeIdFragment(value) {
const fragment = value.trim().toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 32);
if (!fragment) return "node";
return /^[a-z]/.test(fragment) ? fragment : `node_${fragment}`.slice(0, 32);
}
function sanitizeToolFragment(raw, fallback, maxChars) {
const normalized = raw.trim().replace(TOOL_NAME_SAFE_RE, "-") || fallback;
const providerSafe = /^[A-Za-z]/.test(normalized) ? normalized : `${fallback}-${normalized}`;
if (!maxChars) return providerSafe;
return providerSafe.length > maxChars ? providerSafe.slice(0, maxChars) : providerSafe;
}
/** Sanitize one MCP server name and reserve it in the provided set. */
function sanitizeServerName(raw, usedNames) {
const base = sanitizeToolFragment(raw, "mcp", TOOL_NAME_MAX_PREFIX);
let candidate = base;
let n = 2;
while (usedNames.has(normalizeLowercaseStringOrEmpty(candidate))) {
const suffix = `-${n}`;
candidate = `${base.slice(0, Math.max(1, TOOL_NAME_MAX_PREFIX - suffix.length))}${suffix}`;
n += 1;
}
usedNames.add(normalizeLowercaseStringOrEmpty(candidate));
return candidate;
}
/**
* Assign safe server names from the full declared set in declaration order,
* independent of which servers resolve for a requester. Declaration order
* preserves legacy collision-suffix ownership for existing static configs;
* sorting here would silently swap safe names between colliding servers.
*/
function assignSafeServerNames(serverNames) {
const usedNames = /* @__PURE__ */ new Set();
const assignments = /* @__PURE__ */ new Map();
for (const serverName of serverNames) assignments.set(serverName, sanitizeServerName(serverName, usedNames));
return assignments;
}
function sanitizeToolName(raw) {
return sanitizeToolFragment(raw, "tool");
}
/** Normalizes reserved tool names for collision checks. */
function normalizeReservedToolNames(names) {
return new Set(Array.from(names ?? [], (name) => normalizeOptionalLowercaseString(name)).filter((name) => Boolean(name)));
}
/** Build a safe model-facing tool name from server and tool fragments. */
function buildSafeToolName(params) {
const cleanedToolName = sanitizeToolName(params.toolName);
const maxToolChars = Math.max(1, TOOL_NAME_MAX_TOTAL - params.serverName.length - 2);
const truncatedToolName = cleanedToolName.slice(0, maxToolChars);
let candidateToolName = truncatedToolName || "tool";
let candidate = `${params.serverName}__${candidateToolName}`;
let n = 2;
while (params.reservedNames.has(normalizeLowercaseStringOrEmpty(candidate))) {
const suffix = `-${n}`;
candidateToolName = `${(truncatedToolName || "tool").slice(0, Math.max(1, maxToolChars - suffix.length))}${suffix}`;
candidate = `${params.serverName}__${candidateToolName}`;
n += 1;
}
return candidate;
}
//#endregion
export { sanitizeServerName as a, sanitizeNodeIdFragment as i, buildSafeToolName as n, normalizeReservedToolNames as r, assignSafeServerNames as t };