From 53bf8b7b801e279985ba1beb51e11f0a08fb9173 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 5 Jan 2026 23:00:37 +0100 Subject: [PATCH] fix: avoid duplicate missing auth label --- CHANGELOG.md | 1 + src/auto-reply/reply.directive.test.ts | 25 ++++++++++++++++++++++ src/auto-reply/reply/directive-handling.ts | 9 +++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee10954a7..1efdec700 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Model: `/model` list shows auth source (masked key or OAuth email) per provider. - Model: `/model list` is an alias for `/model`. - Model: `/model` output now includes auth source location (env/auth.json/models.json). +- Model: avoid duplicate `missing (missing)` auth labels in `/model` list output. - Docs: clarify auth storage, migration, and OpenAI Codex OAuth onboarding. - Sandbox: copy inbound media into sandbox workspaces so agent tools can read attachments. - Control UI: show a reading indicator bubble while the assistant is responding. diff --git a/src/auto-reply/reply.directive.test.ts b/src/auto-reply/reply.directive.test.ts index 082c05a71..92ffdc410 100644 --- a/src/auto-reply/reply.directive.test.ts +++ b/src/auto-reply/reply.directive.test.ts @@ -636,6 +636,31 @@ describe("directive parsing", () => { }); }); + it("does not repeat missing auth labels 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"], + }, + session: { store: storePath }, + }, + ); + + const text = Array.isArray(res) ? res[0]?.text : res?.text; + expect(text).toContain("auth:"); + expect(text).not.toContain("missing (missing)"); + 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 541345e6b..5ccae73e8 100644 --- a/src/auto-reply/reply/directive-handling.ts +++ b/src/auto-reply/reply/directive-handling.ts @@ -93,6 +93,13 @@ const resolveAuthLabel = async ( return { label: "missing", source: "missing" }; }; +const formatAuthLabel = (auth: { label: string; source: string }) => { + if (!auth.source || auth.source === auth.label || auth.source === "missing") { + return auth.label; + } + return `${auth.label} (${auth.source})`; +}; + export type InlineDirectives = { cleaned: string; hasThinkDirective: boolean; @@ -272,7 +279,7 @@ export async function handleDirectiveOnly(params: { authStorage, authPaths, ); - authByProvider.set(entry.provider, `${auth.label} (${auth.source})`); + authByProvider.set(entry.provider, formatAuthLabel(auth)); } const current = `${params.provider}/${params.model}`; const defaultLabel = `${defaultProvider}/${defaultModel}`;