From cffbe79077c6c862375c0ad4d5b653bf99114150 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 5 Jan 2026 14:11:33 +0000 Subject: [PATCH] fix: add /model list alias --- CHANGELOG.md | 1 + docs/faq.md | 2 ++ src/auto-reply/reply.directive.test.ts | 26 ++++++++++++++++++++++ src/auto-reply/reply/directive-handling.ts | 3 ++- 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32fbf04fe..52ae530ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - macOS: drop deprecated `afterMs` from agent wait params to match gateway schema. - Auth: add OpenAI Codex OAuth support and migrate legacy oauth.json into auth.json. - Model: `/model` list shows auth source (masked key or OAuth email) per provider. +- Model: `/model list` is an alias for `/model`. - Docs: clarify auth storage, migration, and OpenAI Codex OAuth onboarding. - Sandbox: copy inbound media into sandbox workspaces so agent tools can read attachments. - Status: show runtime (docker/direct) and move shortcuts to `/help`. diff --git a/docs/faq.md b/docs/faq.md index 4918cdb97..cb9726919 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -556,6 +556,8 @@ Use `/model` to switch without restarting: /model gemini-flash ``` +List available models with `/model`, `/model list`, or `/model status`. + Clawdbot ships a few default model shorthands (you can override them in config): `opus`, `sonnet`, `gpt`, `gpt-mini`, `gemini`, `gemini-flash`. diff --git a/src/auto-reply/reply.directive.test.ts b/src/auto-reply/reply.directive.test.ts index 3933f19ed..082c05a71 100644 --- a/src/auto-reply/reply.directive.test.ts +++ b/src/auto-reply/reply.directive.test.ts @@ -610,6 +610,32 @@ describe("directive parsing", () => { }); }); + it("lists allowlisted models on /model list", async () => { + await withTempHome(async (home) => { + vi.mocked(runEmbeddedPiAgent).mockReset(); + const storePath = path.join(home, "sessions.json"); + + const res = await getReplyFromConfig( + { Body: "/model list", From: "+1222", To: "+1222" }, + {}, + { + agent: { + model: "anthropic/claude-opus-4-5", + workspace: path.join(home, "clawd"), + allowedModels: ["anthropic/claude-opus-4-5", "openai/gpt-4.1-mini"], + }, + session: { store: storePath }, + }, + ); + + const text = Array.isArray(res) ? res[0]?.text : res?.text; + expect(text).toContain("anthropic/claude-opus-4-5"); + expect(text).toContain("openai/gpt-4.1-mini"); + expect(text).toContain("auth:"); + expect(runEmbeddedPiAgent).not.toHaveBeenCalled(); + }); + }); + it("sets model override on /model directive", async () => { await withTempHome(async (home) => { vi.mocked(runEmbeddedPiAgent).mockReset(); diff --git a/src/auto-reply/reply/directive-handling.ts b/src/auto-reply/reply/directive-handling.ts index 576f4d144..8cdd5e13f 100644 --- a/src/auto-reply/reply/directive-handling.ts +++ b/src/auto-reply/reply/directive-handling.ts @@ -234,8 +234,9 @@ export async function handleDirectiveOnly(params: { } = params; if (directives.hasModelDirective) { + const modelDirective = directives.rawModelDirective?.trim().toLowerCase(); const isModelListAlias = - directives.rawModelDirective?.trim().toLowerCase() === "status"; + modelDirective === "status" || modelDirective === "list"; if (!directives.rawModelDirective || isModelListAlias) { if (allowedModelCatalog.length === 0) { return { text: "No models available." };