openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
509 lines (508 loc) • 21.1 kB
JavaScript
import { c as normalizeOptionalLowercaseString, l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js";
import { d as normalizeStringEntries } from "./string-normalization-DsCfAx8q.js";
import { t as BASE_THINKING_LEVELS } from "./thinking.shared-bHYuuc1L.js";
import { a as listThinkingLevels } from "./thinking-DterdXhr.js";
import { l as resolveFastModeModelAutoOnSeconds, t as formatFastModeAutoLabel } from "./fast-mode-CCX0YiYh.js";
//#region src/auto-reply/commands-args.ts
/** Argument serializers for command definitions that expose structured values. */
function normalizeArgValue(value) {
if (value == null) return;
let text;
if (typeof value === "string") text = normalizeOptionalString(value) ?? "";
else if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") text = normalizeOptionalString(String(value)) ?? "";
else if (typeof value === "symbol") text = normalizeOptionalString(value.toString()) ?? "";
else if (typeof value === "function") text = normalizeOptionalString(value.toString()) ?? "";
else text = JSON.stringify(value);
return text ? text : 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;
}
const formatQueueArgs = (values) => {
const mode = normalizeArgValue(values.mode);
const debounce = normalizeArgValue(values.debounce);
const cap = normalizeArgValue(values.cap);
const drop = normalizeArgValue(values.drop);
const parts = [];
if (mode) parts.push(mode);
if (debounce) parts.push(`debounce:${debounce}`);
if (cap) parts.push(`cap:${cap}`);
if (drop) parts.push(`drop:${drop}`);
return parts.length > 0 ? parts.join(" ") : void 0;
};
const formatExecArgs = (values) => {
const host = normalizeArgValue(values.host);
const security = normalizeArgValue(values.security);
const ask = normalizeArgValue(values.ask);
const node = normalizeArgValue(values.node);
const parts = [];
if (host) parts.push(`host=${host}`);
if (security) parts.push(`security=${security}`);
if (ask) parts.push(`ask=${ask}`);
if (node) parts.push(`node=${node}`);
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: formatQueueArgs,
exec: formatExecArgs
};
//#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);
}
/** Validates command registry uniqueness and text/native surface invariants. */
function assertCommandRegistry(commands) {
const keys = /* @__PURE__ */ new Set();
const nativeNames = /* @__PURE__ */ new Set();
const textAliases = /* @__PURE__ */ new Set();
for (const command of commands) {
if (keys.has(command.key)) throw new Error(`Duplicate command key: ${command.key}`);
keys.add(command.key);
const nativeName = command.nativeName?.trim();
if (command.scope === "text") {
if (nativeName) throw new Error(`Text-only command has native name: ${command.key}`);
if (command.nativeAliases?.length) throw new Error(`Text-only command has native aliases: ${command.key}`);
if (command.textAliases.length === 0) throw new Error(`Text-only command missing text alias: ${command.key}`);
} else if (!nativeName) throw new Error(`Native command missing native name: ${command.key}`);
else for (const alias of [nativeName, ...command.nativeAliases ?? []]) {
const nativeKey = normalizeOptionalLowercaseString(alias) ?? "";
if (nativeNames.has(nativeKey)) throw new Error(`Duplicate native command: ${alias}`);
nativeNames.add(nativeKey);
}
if (command.scope === "native" && command.textAliases.length > 0) throw new Error(`Native-only command has text aliases: ${command.key}`);
for (const alias of command.textAliases) {
if (!alias.startsWith("/")) throw new Error(`Command alias missing leading '/': ${alias}`);
const aliasKey = normalizeOptionalLowercaseString(alias) ?? "";
if (textAliases.has(aliasKey)) throw new Error(`Duplicate command alias: ${alias}`);
textAliases.add(aliasKey);
}
}
}
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 ? normalizeStringEntries(options.nativeAliases) : void 0,
nativeProviders: options.nativeProviders ? normalizeStringEntries(options.nativeProviders) : void 0,
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}`]).map((alias) => alias.trim()).filter(Boolean),
scope: nativeName === false ? "text" : "both",
category,
tier,
activeRunSafe: options.activeRunSafe
};
}
/** 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")];
};
const commands = [
defineBuiltinCommand("help", "Show available commands.", "status", "essential"),
defineBuiltinCommand("commands", "List all slash commands.", "status", "power"),
defineBuiltinCommand("tools", "List available runtime tools.", "status", "standard", {
args: [defineCommandArgument("mode", "compact or verbose", { choices: ["compact", "verbose"] })],
argsMenu: "auto"
}),
defineBuiltinCommand("skill", "Run a skill by name.", "tools", "standard", { 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", { args: [defineCommandArgument("spec", "[interval] prompt, or status/stop", {
required: false,
captureRemaining: true
})] }),
defineBuiltinCommand("status", "Show current status.", "status", "essential", {
acceptsArgs: true,
activeRunSafe: true
}),
defineBuiltinCommand("goal", "Show or control the current goal.", "status", "standard", { 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", { args: [defineCommandArgument("note", "Optional note for Codex feedback upload", { captureRemaining: true })] }),
defineBuiltinCommand("login", "Pair Codex login.", "management", "standard", {
nativeProviders: [
"discord",
"slack",
"telegram"
],
args: [defineCommandArgument("provider", "Provider to pair", { choices: ["codex", "openai"] })]
}),
defineBuiltinCommand("openclaw", "Run the OpenClaw setup and repair helper.", "management", "essential", {
nativeName: false,
acceptsArgs: true
}),
defineBuiltinCommand("tasks", "List background tasks for this session.", "status", "standard"),
defineBuiltinCommand("allowlist", "List/add/remove allowlist entries.", "management", "power", {
nativeName: false,
acceptsArgs: true
}),
defineBuiltinCommand("approve", "Approve or deny exec requests.", "management", "power", { acceptsArgs: true }),
defineBuiltinCommand("context", "Explain how context is built and used.", "status", "standard", { acceptsArgs: true }),
defineBuiltinCommand("btw", "Ask a side question without changing future session context.", "tools", "standard", {
nativeAliases: ["side"],
textAliases: ["/btw", "/side"],
acceptsArgs: true
}),
defineBuiltinCommand("export-session", "Export current session to an owner-only HTML file in the workspace.", "status", "essential", {
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", {
textAliases: ["/export-trajectory", "/trajectory"],
args: [defineCommandArgument("path", "Output directory (default: workspace)", { required: false })]
}),
defineBuiltinCommand("tts", "Control text-to-speech (TTS).", "media", "standard", {
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"] }),
defineBuiltinCommand("session", "Manage conversation bindings and session lifecycle settings.", "session", "power", {
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", {
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", {
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"),
defineBuiltinCommand("steer", "Send guidance to the active run in this session.", "management", "standard", {
textAliases: ["/steer", "/tell"],
args: [defineCommandArgument("message", "Steering message", { captureRemaining: true })]
}),
defineBuiltinCommand("config", "Show or set config values.", "management", "power", {
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", {
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", {
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", {
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", {
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 }),
defineBuiltinCommand("restart", "Restart OpenClaw.", "tools", "power"),
defineBuiltinCommand("update", "Update OpenClaw and restart.", "tools", "power"),
defineBuiltinCommand("activation", "Set group activation mode.", "management", "power", {
args: [defineCommandArgument("mode", "mention or always", { choices: ["mention", "always"] })],
argsMenu: "auto"
}),
defineBuiltinCommand("send", "Set send policy.", "management", "power", {
args: [defineCommandArgument("mode", "on, off, or inherit", { choices: [
"on",
"off",
"inherit"
] })],
argsMenu: "auto"
}),
defineBuiltinCommand("reset", "Reset the current session.", "session", "essential", { acceptsArgs: true }),
defineBuiltinCommand("new", "Start a new session.", "session", "essential", { acceptsArgs: true }),
defineBuiltinCommand("name", "Name or rename the current session.", "session", "standard", { 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", {
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", {
textAliases: ["/verbose", "/v"],
args: [defineCommandArgument("mode", "on, off, or full", { choices: [
"on",
"off",
"full"
] })],
argsMenu: "auto"
}),
defineBuiltinCommand("trace", "Toggle plugin trace lines.", "options", "power", {
args: [defineCommandArgument("mode", "on, off, or raw", { choices: [
"on",
"off",
"raw"
] })],
argsMenu: "auto"
}),
defineBuiltinCommand("fast", "Toggle fast mode.", "options", "standard", {
args: [defineCommandArgument("mode", "on, off, 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", {
textAliases: ["/reasoning", "/reason"],
args: [defineCommandArgument("mode", "on, off, or stream", { choices: [
"on",
"off",
"stream"
] })],
argsMenu: "auto"
}),
defineBuiltinCommand("elevated", "Toggle elevated mode.", "options", "power", {
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", {
args: [
defineCommandArgument("host", "sandbox, gateway, or node", { choices: [
"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", { 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 }),
defineBuiltinCommand("queue", "Adjust queue settings.", "options", "power", {
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", {
nativeName: false,
args: [defineCommandArgument("command", "Shell command", { captureRemaining: true })]
})
];
assertCommandRegistry(commands);
return commands;
}
//#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 { shouldForwardModelCommandToServer as n, getChatCommands as t };