diff --git a/src/commands/models/list.status-command.ts b/src/commands/models/list.status-command.ts index 99f4bf13256..f1b1ae70c30 100644 --- a/src/commands/models/list.status-command.ts +++ b/src/commands/models/list.status-command.ts @@ -18,6 +18,7 @@ import { import { resolveEnvApiKey } from "../../agents/model-auth.js"; import { buildModelAliasIndex, + isCliProvider, parseModelRef, resolveConfiguredModelRef, resolveDefaultModelForAgent, @@ -189,6 +190,7 @@ export async function modelsStatusCommand( const providerAuthMap = new Map(providerAuth.map((entry) => [entry.provider, entry])); const missingProvidersInUse = Array.from(providersInUse) .filter((provider) => !providerAuthMap.has(provider)) + .filter((provider) => !isCliProvider(provider, cfg)) .toSorted((a, b) => a.localeCompare(b)); const probeProfileIds = (() => { diff --git a/src/commands/models/list.status.test.ts b/src/commands/models/list.status.test.ts index 0b9d0600b73..93477e04337 100644 --- a/src/commands/models/list.status.test.ts +++ b/src/commands/models/list.status.test.ts @@ -293,6 +293,42 @@ describe("modelsStatusCommand auth overview", () => { ); }); + it("does not report cli backends as missing auth", async () => { + const localRuntime = createRuntime(); + const originalLoadConfig = mocks.loadConfig.getMockImplementation(); + const originalEnvImpl = mocks.resolveEnvApiKey.getMockImplementation(); + mocks.loadConfig.mockReturnValue({ + agents: { + defaults: { + model: { primary: "claude-cli/claude-sonnet-4-6", fallbacks: [] }, + models: { "claude-cli/claude-sonnet-4-6": {} }, + cliBackends: { "claude-cli": {} }, + }, + }, + models: { providers: {} }, + env: { shellEnv: { enabled: true } }, + }); + mocks.resolveEnvApiKey.mockImplementation(() => null); + + try { + await modelsStatusCommand({ json: true }, localRuntime as never); + const payload = JSON.parse(String((localRuntime.log as Mock).mock.calls[0]?.[0])); + expect(payload.defaultModel).toBe("claude-cli/claude-sonnet-4-6"); + expect(payload.auth.missingProvidersInUse).toEqual([]); + } finally { + if (originalLoadConfig) { + mocks.loadConfig.mockImplementation(originalLoadConfig); + } + if (originalEnvImpl) { + mocks.resolveEnvApiKey.mockImplementation(originalEnvImpl); + } else if (defaultResolveEnvApiKeyImpl) { + mocks.resolveEnvApiKey.mockImplementation(defaultResolveEnvApiKeyImpl); + } else { + mocks.resolveEnvApiKey.mockImplementation(() => null); + } + } + }); + it("labels defaults when --agent has no overrides", async () => { const localRuntime = createRuntime(); await withAgentScopeOverrides( diff --git a/src/gateway/cli-session-history.test.ts b/src/gateway/cli-session-history.test.ts index 886346da398..7f8c5f5d076 100644 --- a/src/gateway/cli-session-history.test.ts +++ b/src/gateway/cli-session-history.test.ts @@ -182,6 +182,7 @@ describe("cli session history", () => { const messages = augmentChatHistoryWithCliSessionImports({ entry: { sessionId: "openclaw-session", + updatedAt: Date.now(), cliSessionBindings: { "claude-cli": { sessionId, @@ -205,6 +206,7 @@ describe("cli session history", () => { const messages = augmentChatHistoryWithCliSessionImports({ entry: { sessionId: "openclaw-session", + updatedAt: Date.now(), cliSessionIds: { "claude-cli": sessionId, }, @@ -226,6 +228,7 @@ describe("cli session history", () => { const messages = augmentChatHistoryWithCliSessionImports({ entry: { sessionId: "openclaw-session", + updatedAt: Date.now(), claudeCliSessionId: sessionId, }, provider: "claude-cli", diff --git a/src/gateway/cli-session-history.ts b/src/gateway/cli-session-history.ts index 97fb9c2a652..3a8113e3e6a 100644 --- a/src/gateway/cli-session-history.ts +++ b/src/gateway/cli-session-history.ts @@ -29,6 +29,9 @@ type ClaudeCliProjectEntry = { }; }; +type ClaudeCliMessage = NonNullable; +type ClaudeCliUsage = ClaudeCliMessage["usage"]; + type TranscriptLikeMessage = Record; function resolveHistoryHomeDir(homeDir?: string): string { @@ -64,7 +67,7 @@ function resolveTimestampMs(value: unknown): number | undefined { return Number.isFinite(parsed) ? parsed : undefined; } -function resolveClaudeCliUsage(raw: ClaudeCliProjectEntry["message"]["usage"]) { +function resolveClaudeCliUsage(raw: ClaudeCliUsage) { if (!raw || typeof raw !== "object") { return undefined; }