UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

53 lines (52 loc) • 1.88 kB
function escapedAt(s, i) { let backslashes = 0; for (let j = i - 1; j >= 0 && s[j] === "\\"; j--) backslashes++; return backslashes % 2 === 1; } export function indexOfUnescaped(s, ch) { for (let i = 0; i < s.length; i++) if (s[i] === ch && !escapedAt(s, i)) return i; return -1; } export function lastIndexOfUnescaped(s, ch) { for (let i = s.length - 1; i >= 0; i--) if (s[i] === ch && !escapedAt(s, i)) return i; return -1; } function unescapeRuleContent(s) { return s.replaceAll("\\(", "(").replaceAll("\\)", ")").replaceAll("\\\\", "\\"); } export function parsePermissionRule(rule) { const open = indexOfUnescaped(rule, "("); if (open === -1) return { toolName: rule.trim() }; const close = lastIndexOfUnescaped(rule, ")"); if (close === -1 || close <= open) return { toolName: rule.trim() }; if (close !== rule.length - 1) return { toolName: rule.trim() }; const name = rule.substring(0, open); const content = rule.substring(open + 1, close); if (!name) return { toolName: rule.trim() }; if (content === "" || content === "*") return { toolName: name.trim() }; return { toolName: name.trim(), ruleContent: unescapeRuleContent(content) }; } const RULE_TOOL_NAME = /^(?:\*|[A-Za-z0-9_](?:[A-Za-z0-9_.:*-]*[A-Za-z0-9_*-])?)$/; export function isNameableToolName(name) { return typeof name === "string" && name !== "*" && RULE_TOOL_NAME.test(name); } export function ruleSpellingOf(rule) { if (rule !== rule.trim()) return undefined; const open = indexOfUnescaped(rule, "("); const name = open < 0 ? rule : rule.slice(0, open); if (!RULE_TOOL_NAME.test(name)) return undefined; const parsed = parsePermissionRule(rule); return parsed.toolName === name ? parsed : undefined; }