mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-29 19:12:18 +00:00
fix(status): prefer active OAuth for runtime aliases
Prefer the active Claude CLI OAuth auth label when the configured Anthropic model resolves through an equivalent Claude CLI runtime alias, so `/status` no longer reports an unused env API-key label. Also adds regression coverage for both text and message status renderers, plus the maintainer changelog entry. Closes #80184. Co-authored-by: brokemac79 <martin_cleary@yahoo.co.uk>
This commit is contained in:
@@ -23,6 +23,7 @@ Docs: https://docs.openclaw.ai
|
||||
- OpenShell/SSH: reject malformed generated exec commands before sandbox/session setup so unresolved workflow placeholders fail fast instead of reaching the remote shell. Fixes #72373. Thanks @brokemac79.
|
||||
- Google: stop normalizing `gemini-3.1-flash-lite` to the retired preview endpoint and update Flash Lite alias guidance to the GA model id. Fixes #86151. (#86240) Thanks @SebTardif.
|
||||
- Installer: make Alpine apk installs cover Git, verify the Node runtime floor, try `nodejs-current`, and report Alpine version guidance when repositories only provide older Node packages.
|
||||
- Agents/status: prefer the active Claude CLI OAuth auth label over an unused Anthropic env API-key label for equivalent runtime aliases. Fixes #80184. (#86570) Thanks @brokemac79.
|
||||
- Agents/media: send direct fallback for generated media still missing after an active requester wake fails. (#85489) Thanks @fuller-stack-dev.
|
||||
- Agents: derive overflow compaction budgets from provider-reported and synthetic over-budget token counts so confirmed context overflows compact before retrying. (#70473) Thanks @fuller-stack-dev.
|
||||
- Agents/Codex: recover Codex context-window prompt errors through overflow compaction and surface reset guidance when recovery is exhausted. (#85542) Thanks @fuller-stack-dev.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
|
||||
import { normalizeStaticProviderModelId } from "./model-ref-shared.js";
|
||||
import { resolveModelRuntimePolicy } from "./model-runtime-policy.js";
|
||||
import { resolveProviderIdForAuth } from "./provider-auth-aliases.js";
|
||||
@@ -182,6 +183,26 @@ export function areRuntimeModelRefsEquivalent(left: string, right: string): bool
|
||||
);
|
||||
}
|
||||
|
||||
export function shouldPreferActiveRuntimeAliasAuthLabel(params: {
|
||||
runtimeAliasModelEquivalent: boolean;
|
||||
selectedAuthLabel?: string;
|
||||
activeAuthLabel?: string;
|
||||
}): boolean {
|
||||
if (!params.runtimeAliasModelEquivalent) {
|
||||
return false;
|
||||
}
|
||||
const selectedAuth = normalizeOptionalLowercaseString(params.selectedAuthLabel);
|
||||
const activeAuth = normalizeOptionalLowercaseString(params.activeAuthLabel);
|
||||
if (!activeAuth || activeAuth === "unknown") {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
selectedAuth === "unknown" ||
|
||||
(Boolean(selectedAuth?.startsWith("api-key")) &&
|
||||
(activeAuth.startsWith("oauth") || activeAuth.startsWith("token")))
|
||||
);
|
||||
}
|
||||
|
||||
function resolveConfiguredRuntime(params: {
|
||||
cfg?: OpenClawConfig;
|
||||
provider: string;
|
||||
|
||||
@@ -856,6 +856,52 @@ describe("buildStatusReply subagent summary", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("prefers active Claude CLI OAuth over selected env API-key labels for runtime aliases", async () => {
|
||||
const text = await buildStatusText({
|
||||
cfg: {
|
||||
...baseCfg,
|
||||
agents: {
|
||||
defaults: {
|
||||
agentRuntime: { id: "claude-cli" },
|
||||
},
|
||||
},
|
||||
},
|
||||
sessionEntry: {
|
||||
sessionId: "sess-status-claude-cli-env-key-shadow",
|
||||
updatedAt: 0,
|
||||
providerOverride: "anthropic",
|
||||
modelOverride: "claude-opus-4-7",
|
||||
modelProvider: "claude-cli",
|
||||
model: "claude-opus-4-7",
|
||||
fallbackNoticeSelectedModel: "anthropic/claude-opus-4-7",
|
||||
fallbackNoticeActiveModel: "claude-cli/claude-opus-4-7",
|
||||
fallbackNoticeReason: "selected model unavailable",
|
||||
},
|
||||
sessionKey: "agent:main:main",
|
||||
parentSessionKey: "agent:main:main",
|
||||
sessionScope: "per-sender",
|
||||
statusChannel: "mobilechat",
|
||||
provider: "anthropic",
|
||||
model: "claude-opus-4-7",
|
||||
contextTokens: 32_000,
|
||||
resolvedHarness: "claude-cli",
|
||||
resolvedFastMode: false,
|
||||
resolvedVerboseLevel: "off",
|
||||
resolvedReasoningLevel: "off",
|
||||
resolveDefaultThinkingLevel: async () => undefined,
|
||||
isGroup: false,
|
||||
defaultGroupActivation: () => "mention",
|
||||
modelAuthOverride: "api-key (env: ANTHROPIC_API_KEY)",
|
||||
activeModelAuthOverride: "oauth (claude-cli)",
|
||||
});
|
||||
|
||||
const normalized = normalizeTestText(text);
|
||||
expect(normalized).toContain("Session selected: anthropic/claude-opus-4-7");
|
||||
expect(normalized).toContain("oauth (claude-cli)");
|
||||
expect(normalized).not.toContain("api-key (env: ANTHROPIC_API_KEY)");
|
||||
expect(normalized).not.toContain("Usage:");
|
||||
});
|
||||
|
||||
it("uses Codex OAuth context overrides for openai models running on the Codex harness", async () => {
|
||||
registerStatusCodexHarness();
|
||||
|
||||
|
||||
@@ -995,6 +995,53 @@ describe("buildStatusMessage", () => {
|
||||
expect(normalized).toContain("Context: 36k/1.0m (4%)");
|
||||
});
|
||||
|
||||
it("prefers active CLI OAuth over selected env API-key labels for runtime aliases", () => {
|
||||
const text = buildStatusMessage({
|
||||
config: {
|
||||
models: {
|
||||
providers: {
|
||||
anthropic: {
|
||||
models: [
|
||||
{
|
||||
id: "claude-opus-4-7",
|
||||
cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
} as unknown as OpenClawConfig,
|
||||
agent: {
|
||||
model: "anthropic/claude-opus-4-7",
|
||||
},
|
||||
sessionEntry: {
|
||||
sessionId: "claude-cli-runtime-alias-env-key",
|
||||
updatedAt: 0,
|
||||
providerOverride: "anthropic",
|
||||
modelOverride: "claude-opus-4-7",
|
||||
modelProvider: "claude-cli",
|
||||
model: "claude-opus-4-7",
|
||||
fallbackNoticeSelectedModel: "anthropic/claude-opus-4-7",
|
||||
fallbackNoticeActiveModel: "claude-cli/claude-opus-4-7",
|
||||
fallbackNoticeReason: "selected model unavailable",
|
||||
inputTokens: 29,
|
||||
outputTokens: 19_000,
|
||||
},
|
||||
sessionKey: "agent:main:main",
|
||||
sessionScope: "per-sender",
|
||||
queue: { mode: "collect", depth: 0 },
|
||||
modelAuth: "api-key (env: ANTHROPIC_API_KEY)",
|
||||
activeModelAuth: "oauth (anthropic:claude-cli)",
|
||||
});
|
||||
|
||||
const normalized = normalizeTestText(text);
|
||||
expect(normalized).toContain("Model: anthropic/claude-opus-4-7");
|
||||
expect(normalized).toContain("oauth (anthropic:claude-cli)");
|
||||
expect(normalized).not.toContain("api-key (env: ANTHROPIC_API_KEY)");
|
||||
expect(normalized).not.toContain("Fallback: claude-cli/claude-opus-4-7");
|
||||
expect(normalized).not.toContain("Cost:");
|
||||
});
|
||||
|
||||
it("keeps an explicit runtime context limit when fallback status already computed one", () => {
|
||||
const text = buildStatusMessage({
|
||||
config: {
|
||||
|
||||
@@ -2,7 +2,10 @@ import fs from "node:fs";
|
||||
import { resolveContextTokensForModel } from "../agents/context.js";
|
||||
import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
|
||||
import { resolveModelAuthMode } from "../agents/model-auth.js";
|
||||
import { areRuntimeModelRefsEquivalent } from "../agents/model-runtime-aliases.js";
|
||||
import {
|
||||
areRuntimeModelRefsEquivalent,
|
||||
shouldPreferActiveRuntimeAliasAuthLabel,
|
||||
} from "../agents/model-runtime-aliases.js";
|
||||
import {
|
||||
buildModelAliasIndex,
|
||||
resolveConfiguredModelRef,
|
||||
@@ -925,8 +928,15 @@ export function buildStatusMessage(args: StatusArgs): string {
|
||||
activeAuthMode && activeAuthMode !== "unknown"
|
||||
? (args.activeModelAuth ?? activeAuthMode)
|
||||
: undefined;
|
||||
const selectedAuthLabelValue =
|
||||
rawSelectedAuthLabelValue ?? (runtimeAliasModelEquivalent ? activeAuthLabelValue : undefined);
|
||||
const preferActiveAuthLabel = shouldPreferActiveRuntimeAliasAuthLabel({
|
||||
runtimeAliasModelEquivalent,
|
||||
selectedAuthLabel: rawSelectedAuthLabelValue,
|
||||
activeAuthLabel: activeAuthLabelValue,
|
||||
});
|
||||
const selectedAuthLabelValue = preferActiveAuthLabel
|
||||
? activeAuthLabelValue
|
||||
: (rawSelectedAuthLabelValue ??
|
||||
(runtimeAliasModelEquivalent ? activeAuthLabelValue : undefined));
|
||||
const fallbackState = resolveActiveFallbackState({
|
||||
selectedModelRef: selectedModelLabel,
|
||||
activeModelRef: activeModelLabel,
|
||||
|
||||
@@ -10,7 +10,10 @@ import {
|
||||
import { resolveContextTokensForModel } from "../agents/context.js";
|
||||
import { resolveFastModeState } from "../agents/fast-mode.js";
|
||||
import { resolveModelAuthLabel } from "../agents/model-auth-label.js";
|
||||
import { areRuntimeModelRefsEquivalent } from "../agents/model-runtime-aliases.js";
|
||||
import {
|
||||
areRuntimeModelRefsEquivalent,
|
||||
shouldPreferActiveRuntimeAliasAuthLabel,
|
||||
} from "../agents/model-runtime-aliases.js";
|
||||
import { resolveDefaultModelForAgent } from "../agents/model-selection.js";
|
||||
import { listOpenAIAuthProfileProvidersForAgentRuntime } from "../agents/openai-codex-routing.js";
|
||||
import {
|
||||
@@ -280,10 +283,11 @@ export async function buildStatusText(params: BuildStatusTextParams): Promise<st
|
||||
modelRefs.active.label,
|
||||
);
|
||||
if (
|
||||
runtimeAliasModelEquivalent &&
|
||||
normalizeOptionalLowercaseString(selectedModelAuth) === "unknown" &&
|
||||
activeModelAuth &&
|
||||
normalizeOptionalLowercaseString(activeModelAuth) !== "unknown"
|
||||
shouldPreferActiveRuntimeAliasAuthLabel({
|
||||
runtimeAliasModelEquivalent,
|
||||
selectedAuthLabel: selectedModelAuth,
|
||||
activeAuthLabel: activeModelAuth,
|
||||
})
|
||||
) {
|
||||
selectedModelAuth = activeModelAuth;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user