import type { Command } from "commander"; import { agentCliCommand } from "../../commands/agent-via-gateway.js"; import { agentsAddCommand, agentsBindingsCommand, agentsBindCommand, agentsDeleteCommand, agentsListCommand, agentsSetIdentityCommand, agentsUnbindCommand, } from "../../commands/agents.js"; import { setVerbose } from "../../globals.js"; import { defaultRuntime } from "../../runtime.js"; import { formatDocsLink } from "../../terminal/links.js"; import { theme } from "../../terminal/theme.js"; import { runCommandWithRuntime } from "../cli-utils.js"; import { hasExplicitOptions } from "../command-options.js"; import { createDefaultDeps } from "../deps.js"; import { formatHelpExamples } from "../help-format.js"; import { collectOption } from "./helpers.js"; export function registerAgentCommands(program: Command, args: { agentChannelOptions: string }) { program .command("agent") .description("Run an agent turn via the Gateway (use --local for embedded)") .requiredOption("-m, --message ", "Message body for the agent") .option("-t, --to ", "Recipient number in E.164 used to derive the session key") .option("--session-id ", "Use an explicit session id") .option("--agent ", "Agent id (overrides routing bindings)") .option("--thinking ", "Thinking level: off | minimal | low | medium | high") .option("--verbose ", "Persist agent verbose level for the session") .option( "--channel ", `Delivery channel: ${args.agentChannelOptions} (omit to use the main session channel)`, ) .option("--reply-to ", "Delivery target override (separate from session routing)") .option("--reply-channel ", "Delivery channel override (separate from routing)") .option("--reply-account ", "Delivery account id override") .option( "--local", "Run the embedded agent locally (requires model provider API keys in your shell)", false, ) .option("--deliver", "Send the agent's reply back to the selected channel", false) .option("--json", "Output result as JSON", false) .option( "--timeout ", "Override agent command timeout (seconds, default 600 or config value)", ) .addHelpText( "after", () => ` ${theme.heading("Examples:")} ${formatHelpExamples([ ['openclaw agent --to +15555550123 --message "status update"', "Start a new session."], ['openclaw agent --agent ops --message "Summarize logs"', "Use a specific agent."], [ 'openclaw agent --session-id 1234 --message "Summarize inbox" --thinking medium', "Target a session with explicit thinking level.", ], [ 'openclaw agent --to +15555550123 --message "Trace logs" --verbose on --json', "Enable verbose logging and JSON output.", ], ['openclaw agent --to +15555550123 --message "Summon reply" --deliver', "Deliver reply."], [ 'openclaw agent --agent ops --message "Generate report" --deliver --reply-channel slack --reply-to "#reports"', "Send reply to a different channel/target.", ], ])} ${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.openclaw.ai/cli/agent")}`, ) .action(async (opts) => { const verboseLevel = typeof opts.verbose === "string" ? opts.verbose.toLowerCase() : ""; setVerbose(verboseLevel === "on"); // Build default deps (keeps parity with other commands; future-proofing). const deps = createDefaultDeps(); await runCommandWithRuntime(defaultRuntime, async () => { await agentCliCommand(opts, defaultRuntime, deps); }); }); const agents = program .command("agents") .description("Manage isolated agents (workspaces + auth + routing)") .addHelpText( "after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/agents", "docs.openclaw.ai/cli/agents")}\n`, ); agents .command("list") .description("List configured agents") .option("--json", "Output JSON instead of text", false) .option("--bindings", "Include routing bindings", false) .action(async (opts) => { await runCommandWithRuntime(defaultRuntime, async () => { await agentsListCommand( { json: Boolean(opts.json), bindings: Boolean(opts.bindings) }, defaultRuntime, ); }); }); agents .command("bindings") .description("List routing bindings") .option("--agent ", "Filter by agent id") .option("--json", "Output JSON instead of text", false) .action(async (opts) => { await runCommandWithRuntime(defaultRuntime, async () => { await agentsBindingsCommand( { agent: opts.agent as string | undefined, json: Boolean(opts.json), }, defaultRuntime, ); }); }); agents .command("bind") .description("Add routing bindings for an agent") .option("--agent ", "Agent id (defaults to current default agent)") .option( "--bind ", "Binding to add (repeatable). If omitted, accountId is resolved by channel defaults/hooks.", collectOption, [], ) .option("--json", "Output JSON summary", false) .action(async (opts) => { await runCommandWithRuntime(defaultRuntime, async () => { await agentsBindCommand( { agent: opts.agent as string | undefined, bind: Array.isArray(opts.bind) ? (opts.bind as string[]) : undefined, json: Boolean(opts.json), }, defaultRuntime, ); }); }); agents .command("unbind") .description("Remove routing bindings for an agent") .option("--agent ", "Agent id (defaults to current default agent)") .option("--bind ", "Binding to remove (repeatable)", collectOption, []) .option("--all", "Remove all bindings for this agent", false) .option("--json", "Output JSON summary", false) .action(async (opts) => { await runCommandWithRuntime(defaultRuntime, async () => { await agentsUnbindCommand( { agent: opts.agent as string | undefined, bind: Array.isArray(opts.bind) ? (opts.bind as string[]) : undefined, all: Boolean(opts.all), json: Boolean(opts.json), }, defaultRuntime, ); }); }); agents .command("add [name]") .description("Add a new isolated agent") .option("--workspace ", "Workspace directory for the new agent") .option("--model ", "Model id for this agent") .option("--agent-dir ", "Agent state directory for this agent") .option("--bind ", "Route channel binding (repeatable)", collectOption, []) .option("--non-interactive", "Disable prompts; requires --workspace", false) .option("--json", "Output JSON summary", false) .action(async (name, opts, command) => { await runCommandWithRuntime(defaultRuntime, async () => { const hasFlags = hasExplicitOptions(command, [ "workspace", "model", "agentDir", "bind", "nonInteractive", ]); await agentsAddCommand( { name: typeof name === "string" ? name : undefined, workspace: opts.workspace as string | undefined, model: opts.model as string | undefined, agentDir: opts.agentDir as string | undefined, bind: Array.isArray(opts.bind) ? (opts.bind as string[]) : undefined, nonInteractive: Boolean(opts.nonInteractive), json: Boolean(opts.json), }, defaultRuntime, { hasFlags }, ); }); }); agents .command("set-identity") .description("Update an agent identity (name/theme/emoji/avatar)") .option("--agent ", "Agent id to update") .option("--workspace ", "Workspace directory used to locate the agent + IDENTITY.md") .option("--identity-file ", "Explicit IDENTITY.md path to read") .option("--from-identity", "Read values from IDENTITY.md", false) .option("--name ", "Identity name") .option("--theme ", "Identity theme") .option("--emoji ", "Identity emoji") .option("--avatar ", "Identity avatar (workspace path, http(s) URL, or data URI)") .option("--json", "Output JSON summary", false) .addHelpText( "after", () => ` ${theme.heading("Examples:")} ${formatHelpExamples([ ['openclaw agents set-identity --agent main --name "OpenClaw" --emoji "🦞"', "Set name + emoji."], ["openclaw agents set-identity --agent main --avatar avatars/openclaw.png", "Set avatar path."], [ "openclaw agents set-identity --workspace ~/.openclaw/workspace --from-identity", "Load from IDENTITY.md.", ], [ "openclaw agents set-identity --identity-file ~/.openclaw/workspace/IDENTITY.md --agent main", "Use a specific IDENTITY.md.", ], ])} `, ) .action(async (opts) => { await runCommandWithRuntime(defaultRuntime, async () => { await agentsSetIdentityCommand( { agent: opts.agent as string | undefined, workspace: opts.workspace as string | undefined, identityFile: opts.identityFile as string | undefined, fromIdentity: Boolean(opts.fromIdentity), name: opts.name as string | undefined, theme: opts.theme as string | undefined, emoji: opts.emoji as string | undefined, avatar: opts.avatar as string | undefined, json: Boolean(opts.json), }, defaultRuntime, ); }); }); agents .command("delete ") .description("Delete an agent and prune workspace/state") .option("--force", "Skip confirmation", false) .option("--json", "Output JSON summary", false) .action(async (id, opts) => { await runCommandWithRuntime(defaultRuntime, async () => { await agentsDeleteCommand( { id: String(id), force: Boolean(opts.force), json: Boolean(opts.json), }, defaultRuntime, ); }); }); agents.action(async () => { await runCommandWithRuntime(defaultRuntime, async () => { await agentsListCommand({}, defaultRuntime); }); }); }