fix: harden removed Codex auth choice guidance (#70390) (thanks @pashpashpash)

This commit is contained in:
Peter Steinberger
2026-04-23 03:42:57 +01:00
parent 84aa35e9b2
commit e54d0634c5
6 changed files with 52 additions and 4 deletions

View File

@@ -7,6 +7,7 @@ Docs: https://docs.openclaw.ai
### Changes
- Providers/Amazon Bedrock Mantle: add Claude Opus 4.7 through Mantle's Anthropic Messages route with provider-owned bearer-auth streaming, so the model is actually callable without treating AWS bearer tokens like Anthropic API keys. Thanks @wirjo.
- Providers/OpenAI Codex: remove the Codex CLI auth import path from onboarding and provider discovery so OpenClaw no longer copies `~/.codex` OAuth material into agent auth stores; use browser login or device pairing instead. (#70390) Thanks @pashpashpash.
- OpenAI/Responses: use OpenAI's native `web_search` tool automatically for direct OpenAI Responses models when web search is enabled and no managed search provider is pinned; explicit providers such as Brave keep the managed `web_search` tool.
- ACPX: add an explicit `openClawToolsMcpBridge` option that injects a core OpenClaw MCP server for selected built-in tools, starting with `cron`.
- Agents/sessions: add mailbox-style `sessions_list` filters for label, agent, and search plus visibility-scoped derived title and last-message previews. (#69839) Thanks @dangoZhang.

View File

@@ -5,6 +5,7 @@ import type {
ProviderRuntimeModel,
} from "openclaw/plugin-sdk/plugin-entry";
import {
CODEX_CLI_PROFILE_ID,
ensureAuthProfileStoreForLocalUpdate,
listProfilesForProvider,
type OAuthCredential,
@@ -39,7 +40,6 @@ const OPENAI_WIZARD_GROUP = {
groupLabel: "OpenAI",
groupHint: "API key + Codex auth",
} as const;
const CODEX_CLI_PROFILE_ID = `${PROVIDER_ID}:codex-cli`;
const OPENAI_CODEX_LOGIN_ASSISTANT_PRIORITY = -30;
const OPENAI_CODEX_DEVICE_PAIRING_ASSISTANT_PRIORITY = -10;
const OPENAI_CODEX_LOGIN_LABEL = "OpenAI Codex Browser Login";

View File

@@ -58,7 +58,7 @@ async function formatDeprecatedProviderChoiceError(
if (!deprecatedChoice) {
return undefined;
}
return `Auth choice "${authChoice}" is no longer supported. Use "${deprecatedChoice.choiceId}" instead.`;
return `Auth choice ${JSON.stringify(authChoice)} is no longer supported. Use ${JSON.stringify(deprecatedChoice.choiceId)} instead.`;
}
export async function applyAuthChoice(

View File

@@ -5,6 +5,7 @@ import { resolveAgentDir } from "../agents/agent-scope.js";
import type { OpenClawConfig } from "../config/config.js";
import { resolveAgentModelPrimaryValue } from "../config/model-input.js";
import type { ModelProviderConfig } from "../config/types.models.js";
import * as providerAuthChoices from "../plugins/provider-auth-choices.js";
import type { ProviderAuthMethod, ProviderAuthResult, ProviderPlugin } from "../plugins/types.js";
import type { WizardPrompter } from "../wizard/prompts.js";
import { applyAuthChoice } from "./auth-choice.apply.js";
@@ -705,6 +706,29 @@ describe("applyAuthChoice", () => {
);
});
it("escapes removed provider auth choice guidance for terminal output", async () => {
const spy = vi
.spyOn(providerAuthChoices, "resolveManifestDeprecatedProviderAuthChoice")
.mockReturnValueOnce({
choiceId: "modern\nchoice",
} as never);
try {
await expect(
applyAuthChoice({
authChoice: "legacy\u001b[31mchoice",
config: {},
prompter: createPrompter({}),
runtime: createExitThrowingRuntime(),
setDefaultModel: true,
}),
).rejects.toThrow(
'Auth choice "legacy\\u001b[31mchoice" is no longer supported. Use "modern\\nchoice" instead.',
);
} finally {
spy.mockRestore();
}
});
it("prompts and writes provider API key profiles for common providers", async () => {
const scenarios: Array<{
authChoice: "huggingface-api-key";

View File

@@ -68,7 +68,30 @@ describe("applyNonInteractiveAuthChoice", () => {
expect(result).toBeNull();
expect(runtime.error).toHaveBeenCalledWith(
'"demo-provider-legacy" is no longer supported. Use --auth-choice demo-provider-modern-api instead.',
'"demo-provider-legacy" is no longer supported. Use --auth-choice "demo-provider-modern-api" instead.',
);
expect(runtime.exit).toHaveBeenCalledWith(1);
expect(applyNonInteractivePluginProviderChoice).toHaveBeenCalledOnce();
});
it("escapes deprecated auth choice guidance for terminal output", async () => {
const runtime = createRuntime();
const nextConfig = { agents: { defaults: {} } } as OpenClawConfig;
resolveManifestDeprecatedProviderAuthChoice.mockReturnValueOnce({
choiceId: "modern\nchoice",
} as never);
const result = await applyNonInteractiveAuthChoice({
nextConfig,
authChoice: "legacy\u001b[31mchoice",
opts: {} as never,
runtime: runtime as never,
baseConfig: nextConfig,
});
expect(result).toBeNull();
expect(runtime.error).toHaveBeenCalledWith(
'"legacy\\u001b[31mchoice" is no longer supported. Use --auth-choice "modern\\nchoice" instead.',
);
expect(runtime.exit).toHaveBeenCalledWith(1);
expect(applyNonInteractivePluginProviderChoice).toHaveBeenCalledOnce();

View File

@@ -163,7 +163,7 @@ export async function applyNonInteractiveAuthChoice(params: {
});
if (deprecatedChoice) {
runtime.error(
`"${authChoice as string}" is no longer supported. Use --auth-choice ${deprecatedChoice.choiceId} instead.`,
`${JSON.stringify(authChoice as string)} is no longer supported. Use --auth-choice ${JSON.stringify(deprecatedChoice.choiceId)} instead.`,
);
runtime.exit(1);
return null;