UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

617 lines (616 loc) • 23.1 kB
import { c as normalizeOptionalLowercaseString, l as normalizeOptionalString, o as normalizeLowercaseStringOrEmpty } from "./string-coerce-1VuiLaaR.mjs"; import { n as BASE_THINKING_LEVELS } from "./thinking.shared-Jy32Vp-O.mjs"; import { o as listThinkingLevels } from "./thinking-DacLfQjp.mjs"; import { t as formatFastModeAutoLabel, u as resolveFastModeModelAutoOnSeconds } from "./fast-mode-smSVCJXN.mjs"; import { n as parseActivationCommand } from "./group-activation-C9UsJ0Nq.mjs"; //#region src/auto-reply/commands-args.ts /** Argument serializers for command definitions that expose structured values. */ function normalizeArgValue(value) { if (value == null) return; if (typeof value === "string") return normalizeOptionalString(value); if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return normalizeOptionalString(String(value)); if (typeof value === "symbol" || typeof value === "function") return normalizeOptionalString(value.toString()); return JSON.stringify(value) || void 0; } function formatActionArgs(values, pathActions = ["show", "get"]) { const action = normalizeOptionalLowercaseString(normalizeArgValue(values.action)); const path = normalizeArgValue(values.path); const value = normalizeArgValue(values.value); if (!action) return; if (action === "set" && path && value) return `${action} ${path}=${value}`; const includesPath = action === "set" || action === "unset" || pathActions.includes(action); return path && includesPath ? `${action} ${path}` : action; } function formatNamedArgs(values, names, separator, positional) { const parts = []; for (const name of names) { const value = normalizeArgValue(values[name]); if (value) parts.push(name === positional ? value : `${name}${separator}${value}`); } return parts.length > 0 ? parts.join(" ") : void 0; } /** Command-specific serializers used when rebuilding slash-command text from parsed args. */ const COMMAND_ARG_FORMATTERS = { config: formatActionArgs, mcp: formatActionArgs, plugins: (values) => formatActionArgs(values, [ "show", "get", "enable", "disable" ]), debug: (values) => formatActionArgs(values, []), queue: (values) => formatNamedArgs(values, [ "mode", "debounce", "cap", "drop" ], ":", "mode"), exec: (values) => formatNamedArgs(values, [ "host", "security", "ask", "node" ], "=") }; //#endregion //#region src/auto-reply/reply/commands-slash-parse.ts /** Shared parser for slash commands with action and argument tails. */ /** Matches a whole, case-insensitive command token and preserves its argument text. */ function matchSlashCommandToken(raw, command) { const trimmed = raw.trim(); const commandEnd = trimmed.search(/\s/); return (commandEnd === -1 ? trimmed : trimmed.slice(0, commandEnd)).toLowerCase() === command ? commandEnd === -1 ? "" : trimmed.slice(commandEnd).trim() : null; } /** Parses a normalized send-policy command without importing command runtime state. */ function parseSendPolicyCommandBody(normalized) { const match = normalized.match(/^\/send(?:\s+([a-zA-Z]+))?\s*$/i); if (!match) return { hasCommand: false }; const token = normalizeLowercaseStringOrEmpty(match[1]); if (!token) return { hasCommand: true }; if (token === "inherit" || token === "default" || token === "reset") return { hasCommand: true, mode: "inherit" }; return { hasCommand: true, mode: token === "allow" || token === "on" ? "allow" : token === "deny" || token === "off" ? "deny" : void 0 }; } /** Parses a slash command or returns null when the prefix does not match. */ function parseSlashCommandOrNull(raw, slash, defaultAction = "show") { const trimmed = raw.trim(); const slashLower = normalizeLowercaseStringOrEmpty(slash); if (!normalizeLowercaseStringOrEmpty(trimmed).startsWith(slashLower)) return null; const charAfter = trimmed.charAt(slash.length); if (charAfter && !/[\s:]/.test(charAfter)) return null; const rest = trimmed.slice(slash.length).trim(); if (!rest) return { action: defaultAction, args: "" }; const actionEnd = rest.search(/\s/); return { action: (actionEnd === -1 ? rest : rest.slice(0, actionEnd)).toLowerCase(), args: actionEnd === -1 ? "" : rest.slice(actionEnd).trim() }; } //#endregion //#region src/auto-reply/commands-registry.shared.ts /** Shared command registry builders used by browser-safe and runtime command lists. */ const BROWSER_SAFE_THINKING_LEVELS = [ ...BASE_THINKING_LEVELS, "xhigh", "adaptive", "max" ]; /** * Keep simple model selections on fast client-side patch paths. Semantic reset * and multi-token forms require the server directive parser to own the full * atomic transaction. */ function shouldForwardModelCommandToServer(rawArgs) { const args = rawArgs.trim(); const normalized = args.toLowerCase(); return [ "default", "list", "status" ].includes(normalized) || /\s/u.test(args); } function defineCommandArgument(name, description, options = {}) { return { name, description, type: "string", ...options }; } /** Defines a built-in command with its aliases and argument parsing defaults. */ function defineBuiltinCommand(key, description, category, tier, options = {}) { const { nativeName = key } = options; return { key, nativeName: nativeName === false ? void 0 : nativeName, nativeAliases: options.nativeAliases, nativeProviders: options.nativeProviders, description, ...options.descriptionLocalizations ? { descriptionLocalizations: options.descriptionLocalizations } : {}, acceptsArgs: options.acceptsArgs ?? Boolean(options.args?.length), args: options.args, argsParsing: options.argsParsing ?? (options.args?.length ? "positional" : "none"), formatArgs: options.formatArgs, argsMenu: options.argsMenu, textAliases: options.textAliases ?? [`/${key}`], scope: nativeName === false ? "text" : "both", category, tier, activeRunSafe: options.activeRunSafe, modelIndependent: options.modelIndependent }; } /** Builds the built-in command list with context-aware thinking choices. */ function buildBuiltinChatCommands(params = {}) { const configuredThinkingLevels = params.listThinkingLevels ?? (() => BROWSER_SAFE_THINKING_LEVELS); const listThinkingLevelChoices = (provider, model, catalog, agentRuntime) => { return ["default", ...configuredThinkingLevels(provider, model, catalog, agentRuntime).filter((level) => level !== "default")]; }; return [ defineBuiltinCommand("help", "Show available commands.", "status", "essential", { activeRunSafe: true, modelIndependent: "always" }), defineBuiltinCommand("commands", "List all slash commands.", "status", "power", { activeRunSafe: true, modelIndependent: "no-args" }), defineBuiltinCommand("tools", "List available runtime tools.", "status", "standard", { activeRunSafe: true, modelIndependent: "always", args: [defineCommandArgument("mode", "compact or verbose", { choices: ["compact", "verbose"] })], argsMenu: "auto" }), defineBuiltinCommand("skill", "Run a skill by name.", "tools", "standard", { modelIndependent: "no-args", args: [defineCommandArgument("name", "Skill name", { required: true }), defineCommandArgument("input", "Skill input", { captureRemaining: true })] }), defineBuiltinCommand("dashboard", "Create or update this session's dashboard.", "tools", "standard", { args: [defineCommandArgument("request", "Dashboard requirements", { captureRemaining: true })] }), defineBuiltinCommand("learn", "Draft a reusable skill from recent work or named sources.", "tools", "standard", { args: [defineCommandArgument("request", "Sources and requirements for the skill draft", { captureRemaining: true })] }), defineBuiltinCommand("loop", "Loop a prompt: /loop [interval] <prompt> | /loop status | /loop stop [name]", "tools", "standard", { modelIndependent: (args) => !args || args.toLowerCase() === "help", args: [defineCommandArgument("spec", "[interval] prompt, or status/stop", { required: false, captureRemaining: true })] }), defineBuiltinCommand("status", "Show current status.", "status", "essential", { acceptsArgs: true, activeRunSafe: true, modelIndependent: "always" }), defineBuiltinCommand("goal", "Show or control the current goal.", "status", "standard", { modelIndependent: (args) => { const parsed = parseSlashCommandOrNull(`/goal ${args}`, "/goal", "status"); return parsed !== null && ([ "status", "edit", "pause", "complete", "done", "block", "blocked", "clear" ].includes(parsed.action) || [ "start", "set", "create" ].includes(parsed.action) && !parsed.args); }, args: [defineCommandArgument("action", "status, start, edit, pause, resume, complete, block, clear", { choices: [ "status", "start", "edit", "pause", "resume", "complete", "block", "clear" ] }), defineCommandArgument("text", "Goal objective or note", { captureRemaining: true })] }), defineBuiltinCommand("diagnostics", "Explain Gateway diagnostics and Codex feedback upload options.", "status", "standard", { modelIndependent: "always", args: [defineCommandArgument("note", "Optional note for Codex feedback upload", { captureRemaining: true })] }), defineBuiltinCommand("login", "Connect a model provider.", "management", "standard", { modelIndependent: "always", nativeProviders: [ "discord", "slack", "telegram" ], args: [defineCommandArgument("provider", "Provider or connection method")] }), defineBuiltinCommand("openclaw", "Run the OpenClaw setup and repair helper.", "management", "essential", { modelIndependent: "always", nativeName: false, acceptsArgs: true }), defineBuiltinCommand("allowlist", "List/add/remove allowlist entries.", "management", "power", { modelIndependent: "always", nativeName: false, acceptsArgs: true }), defineBuiltinCommand("approve", "Approve or deny exec requests.", "management", "power", { acceptsArgs: true, activeRunSafe: true, modelIndependent: "always" }), defineBuiltinCommand("context", "Explain how context is built and used.", "status", "standard", { acceptsArgs: true, activeRunSafe: true, modelIndependent: "always" }), defineBuiltinCommand("btw", "Ask a side question without changing future session context.", "tools", "standard", { activeRunSafe: true, modelIndependent: "no-args", nativeAliases: ["side"], textAliases: ["/btw", "/side"], acceptsArgs: true }), defineBuiltinCommand("export-session", "Export current session to an owner-only HTML file in the workspace.", "status", "essential", { modelIndependent: "always", textAliases: ["/export-session", "/export"], args: [defineCommandArgument("path", "Output path inside workspace (default: workspace)", { required: false })] }), defineBuiltinCommand("export-trajectory", "Export a JSONL trajectory bundle for the active session.", "status", "essential", { modelIndependent: "always", textAliases: ["/export-trajectory", "/trajectory"], args: [defineCommandArgument("path", "Output directory (default: workspace)", { required: false })] }), defineBuiltinCommand("tts", "Control text-to-speech (TTS).", "media", "standard", { modelIndependent: "always", args: [defineCommandArgument("action", "TTS action", { choices: [ { value: "on", label: "On" }, { value: "off", label: "Off" }, { value: "status", label: "Status" }, { value: "provider", label: "Provider" }, { value: "limit", label: "Limit" }, { value: "summary", label: "Summary" }, { value: "audio", label: "Audio" }, { value: "help", label: "Help" } ] }), defineCommandArgument("value", "Provider, limit, or text", { captureRemaining: true })], argsMenu: { arg: "action", title: "TTS Actions:\n• On – Enable TTS for responses\n• Off – Disable TTS\n• Status – Show current settings\n• Provider – Show or set the voice provider\n• Limit – Set max characters for TTS\n• Summary – Toggle AI summary for long texts\n• Audio – Generate TTS from custom text\n• Help – Show usage guide" } }), defineBuiltinCommand("whoami", "Show your sender id.", "status", "power", { textAliases: ["/whoami", "/id"], activeRunSafe: true, modelIndependent: "no-args" }), defineBuiltinCommand("session", "Manage conversation bindings and session lifecycle settings.", "session", "power", { modelIndependent: "always", args: [defineCommandArgument("action", "idle | max-age | unbind", { choices: [ "idle", "max-age", "unbind" ] }), defineCommandArgument("value", "Duration (24h, 90m) or off", { captureRemaining: true })], argsMenu: "auto" }), defineBuiltinCommand("subagents", "Inspect subagent runs for this session.", "management", "standard", { activeRunSafe: true, modelIndependent: "always", args: [ defineCommandArgument("action", "list | log | info", { choices: [ "list", "log", "info" ] }), defineCommandArgument("target", "Run id, index, or session key"), defineCommandArgument("value", "Additional input (limit/message)", { captureRemaining: true }) ], argsMenu: "auto" }), defineBuiltinCommand("acp", "Manage ACP sessions and runtime options.", "management", "power", { modelIndependent: (args) => { const parsed = parseSlashCommandOrNull(`/acp ${args}`, "/acp", "help"); return parsed !== null && (parsed.action !== "steer" || !parsed.args); }, args: [defineCommandArgument("action", "Action to run", { preferAutocomplete: true, choices: [ "spawn", "cancel", "steer", "close", "sessions", "status", "set-mode", "set", "cwd", "permissions", "timeout", "model", "reset-options", "doctor", "install", "help" ] }), defineCommandArgument("value", "Action arguments", { captureRemaining: true })], argsMenu: "auto" }), defineBuiltinCommand("agents", "List thread-bound agents for this session.", "management", "standard", { activeRunSafe: true, modelIndependent: "always" }), defineBuiltinCommand("steer", "Send guidance to the active run in this session.", "management", "standard", { modelIndependent: "no-args", textAliases: ["/steer", "/tell"], args: [defineCommandArgument("message", "Steering message", { captureRemaining: true })] }), defineBuiltinCommand("config", "Show or set config values.", "management", "power", { modelIndependent: "always", args: [ defineCommandArgument("action", "show | get | set | unset", { choices: [ "show", "get", "set", "unset" ] }), defineCommandArgument("path", "Config path"), defineCommandArgument("value", "Value for set", { captureRemaining: true }) ], argsParsing: "none", formatArgs: COMMAND_ARG_FORMATTERS.config }), defineBuiltinCommand("mcp", "Show or set OpenClaw MCP servers.", "management", "power", { modelIndependent: "always", args: [ defineCommandArgument("action", "show | get | set | unset", { choices: [ "show", "get", "set", "unset" ] }), defineCommandArgument("path", "MCP server name"), defineCommandArgument("value", "JSON config for set", { captureRemaining: true }) ], argsParsing: "none", formatArgs: COMMAND_ARG_FORMATTERS.mcp }), defineBuiltinCommand("plugins", "List, show, enable, or disable plugins.", "management", "power", { modelIndependent: "always", textAliases: ["/plugins", "/plugin"], args: [defineCommandArgument("action", "list | show | get | enable | disable", { choices: [ "list", "show", "get", "enable", "disable" ] }), defineCommandArgument("path", "Plugin id or name")], argsParsing: "none", formatArgs: COMMAND_ARG_FORMATTERS.plugins }), defineBuiltinCommand("debug", "Set runtime debug overrides.", "management", "power", { modelIndependent: "always", args: [ defineCommandArgument("action", "show | reset | set | unset", { choices: [ "show", "reset", "set", "unset" ] }), defineCommandArgument("path", "Debug path"), defineCommandArgument("value", "Value for set", { captureRemaining: true }) ], argsParsing: "none", formatArgs: COMMAND_ARG_FORMATTERS.debug }), defineBuiltinCommand("usage", "Usage footer or cost summary.", "options", "standard", { modelIndependent: "always", args: [defineCommandArgument("mode", "off, tokens, full, or cost", { choices: [ "off", "tokens", "full", "cost" ] })], argsMenu: "auto" }), defineBuiltinCommand("stop", "Stop the current run.", "session", "essential", { activeRunSafe: true, modelIndependent: "no-args" }), defineBuiltinCommand("restart", "Restart OpenClaw.", "tools", "power", { modelIndependent: "no-args" }), defineBuiltinCommand("update", "Update OpenClaw and restart.", "tools", "power", { modelIndependent: "no-args" }), defineBuiltinCommand("activation", "Set group activation mode.", "management", "power", { modelIndependent: (args) => parseActivationCommand(`/activation ${args}`).hasCommand, args: [defineCommandArgument("mode", "mention or always", { choices: ["mention", "always"] })], argsMenu: "auto" }), defineBuiltinCommand("send", "Set send policy.", "management", "power", { modelIndependent: (args) => parseSendPolicyCommandBody(`/send ${args}`).hasCommand, args: [defineCommandArgument("mode", "on, off, or inherit", { choices: [ "on", "off", "inherit" ] })], argsMenu: "auto" }), defineBuiltinCommand("reset", "Reset the current session.", "session", "essential", { activeRunSafe: true, acceptsArgs: true }), defineBuiltinCommand("new", "Start a new session.", "session", "essential", { activeRunSafe: true, modelIndependent: "always", acceptsArgs: true }), defineBuiltinCommand("name", "Name or rename the current session.", "session", "standard", { modelIndependent: "always", args: [defineCommandArgument("title", "New session name (omit to see a suggestion)", { captureRemaining: true })] }), defineBuiltinCommand("compact", "Compact the session context.", "session", "essential", { args: [defineCommandArgument("instructions", "Extra compaction instructions", { captureRemaining: true })] }), defineBuiltinCommand("think", "Set thinking level.", "options", "essential", { modelIndependent: "always", textAliases: [ "/think", "/thinking", "/t" ], activeRunSafe: true, args: [defineCommandArgument("level", "Thinking level", { choices: ({ provider, model, catalog, agentRuntime }) => listThinkingLevelChoices(provider, model, catalog, agentRuntime) })], argsMenu: "auto" }), defineBuiltinCommand("verbose", "Toggle verbose mode.", "options", "standard", { modelIndependent: "always", textAliases: ["/verbose", "/v"], args: [defineCommandArgument("mode", "on, off, or full", { choices: [ "on", "off", "full" ] })], argsMenu: "auto" }), defineBuiltinCommand("trace", "Toggle plugin trace lines.", "options", "power", { modelIndependent: "directive", args: [defineCommandArgument("mode", "on, off, or raw", { choices: [ "on", "off", "raw" ] })], argsMenu: "auto" }), defineBuiltinCommand("fast", "Toggle fast mode.", "options", "standard", { modelIndependent: "always", args: [defineCommandArgument("mode", "on, off, ultrafast, auto, default, or status", { choices: ({ cfg, provider, model }) => [ "on", "off", { value: "auto", label: formatFastModeAutoLabel({ fastAutoOnSeconds: resolveFastModeModelAutoOnSeconds({ cfg, provider, model }) }) }, "default", "status" ] })], argsMenu: "auto" }), defineBuiltinCommand("reasoning", "Toggle reasoning visibility.", "options", "standard", { modelIndependent: "directive", textAliases: ["/reasoning", "/reason"], args: [defineCommandArgument("mode", "on, off, or stream", { choices: [ "on", "off", "stream" ] })], argsMenu: "auto" }), defineBuiltinCommand("elevated", "Toggle elevated mode.", "options", "power", { modelIndependent: "directive", textAliases: ["/elevated", "/elev"], args: [defineCommandArgument("mode", "on, off, ask, or full", { choices: [ "on", "off", "ask", "full" ] })], argsMenu: "auto" }), defineBuiltinCommand("exec", "Set exec defaults for this session.", "options", "power", { modelIndependent: "directive", args: [ defineCommandArgument("host", "auto, sandbox, gateway, or node", { choices: [ "auto", "sandbox", "gateway", "node" ] }), defineCommandArgument("security", "deny, allowlist, or full", { choices: [ "deny", "allowlist", "full" ] }), defineCommandArgument("ask", "off, on-miss, or always", { choices: [ "off", "on-miss", "always" ] }), defineCommandArgument("node", "Node id or name") ], argsParsing: "none", formatArgs: COMMAND_ARG_FORMATTERS.exec }), defineBuiltinCommand("model", "Show or set the model; use -s, -a, or -g to choose scope.", "options", "essential", { modelIndependent: "directive", args: [defineCommandArgument("model", "Model id; add -s for session, -a for agent, or -g for global scope")] }), defineBuiltinCommand("models", "List model providers/models.", "options", "standard", { acceptsArgs: true, activeRunSafe: true, modelIndependent: "always" }), defineBuiltinCommand("queue", "Adjust queue settings.", "options", "power", { modelIndependent: "directive", args: [ defineCommandArgument("mode", "queue mode", { choices: [ "steer", "followup", "collect", "interrupt" ] }), defineCommandArgument("debounce", "debounce duration (e.g. 500ms, 2s)"), defineCommandArgument("cap", "queue cap", { type: "number" }), defineCommandArgument("drop", "drop policy", { choices: [ "old", "new", "summarize" ] }) ], argsParsing: "none", formatArgs: COMMAND_ARG_FORMATTERS.queue }), defineBuiltinCommand("bash", "Run host shell commands (host-only).", "tools", "power", { modelIndependent: "always", nativeName: false, args: [defineCommandArgument("command", "Shell command", { captureRemaining: true })] }) ]; } //#endregion //#region src/auto-reply/commands-registry.data.ts /** Built-in command registry data for auto-reply commands. */ let cachedCommands = null; /** Returns the built-in command registry with runtime thinking-level choices. */ function getChatCommands() { return cachedCommands ??= buildBuiltinChatCommands({ listThinkingLevels }); } //#endregion export { parseSlashCommandOrNull as a, parseSendPolicyCommandBody as i, shouldForwardModelCommandToServer as n, matchSlashCommandToken as r, getChatCommands as t };