import type { NodeId } from "../../types"; export class ConnectionNodeIdFactory { static readonly connectionSegment = "__conn__" as const; static languageModelConnectionNodeId(parentNodeId: NodeId): NodeId { return `${parentNodeId}${this.connectionSegment}llm`; } static toolConnectionNodeId(parentNodeId: NodeId, toolName: string): NodeId { const normalized = this.normalizeToolName(toolName); return `${parentNodeId}${this.connectionSegment}tool${this.connectionSegment}${normalized}`; } static mcpConnectionNodeId(parentNodeId: NodeId, serverId: string): NodeId { return `${parentNodeId}${this.connectionSegment}mcp${this.connectionSegment}${serverId}`; } static isMcpConnectionNodeId(nodeId: NodeId): boolean { return nodeId.includes(`${this.connectionSegment}mcp${this.connectionSegment}`); } static parseMcpConnectionNodeId(nodeId: NodeId): Readonly<{ parentNodeId: NodeId; serverId: string }> | undefined { if (!this.isMcpConnectionNodeId(nodeId)) { return undefined; } const marker = `${this.connectionSegment}mcp${this.connectionSegment}`; const idx = nodeId.lastIndexOf(marker); if (idx < 0) { return undefined; } const parentNodeId = nodeId.slice(0, idx); const serverId = nodeId.slice(idx + marker.length); if (!parentNodeId || !serverId) { return undefined; } return { parentNodeId, serverId }; } static isLanguageModelConnectionNodeId(nodeId: NodeId): boolean { return nodeId.endsWith(`${this.connectionSegment}llm`); } static isToolConnectionNodeId(nodeId: NodeId): boolean { return nodeId.includes(`${this.connectionSegment}tool${this.connectionSegment}`); } static parseLanguageModelConnectionNodeId(nodeId: NodeId): Readonly<{ parentNodeId: NodeId }> | undefined { if (!this.isLanguageModelConnectionNodeId(nodeId)) { return undefined; } const suffix = `${this.connectionSegment}llm`; const parentNodeId = nodeId.slice(0, -suffix.length); return parentNodeId ? { parentNodeId } : undefined; } static parseToolConnectionNodeId( nodeId: NodeId, ): Readonly<{ parentNodeId: NodeId; normalizedToolName: string }> | undefined { if (!this.isToolConnectionNodeId(nodeId)) { return undefined; } const marker = `${this.connectionSegment}tool${this.connectionSegment}`; const idx = nodeId.lastIndexOf(marker); if (idx < 0) { return undefined; } const parentNodeId = nodeId.slice(0, idx); const normalizedToolName = nodeId.slice(idx + marker.length); if (!parentNodeId || !normalizedToolName) { return undefined; } return { parentNodeId, normalizedToolName }; } static isConnectionOwnedDescendantOf(parentNodeId: NodeId, nodeId: NodeId): boolean { return nodeId.startsWith(`${parentNodeId}${this.connectionSegment}`); } static normalizeToolName(toolName: string): string { return ( toolName .trim() .toLowerCase() .replace(/[^a-z0-9]+/g, "_") .replace(/^_+|_+$/g, "") || "tool" ); } }