diff --git a/CHANGELOG.md b/CHANGELOG.md index 3693fc9828d..e73f6475ba5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/extensions/openai/openai-codex-provider.ts b/extensions/openai/openai-codex-provider.ts index 246593e3a6d..f61fef8856f 100644 --- a/extensions/openai/openai-codex-provider.ts +++ b/extensions/openai/openai-codex-provider.ts @@ -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"; diff --git a/src/commands/auth-choice.apply.ts b/src/commands/auth-choice.apply.ts index 1674b30ba92..f79b9ee3de8 100644 --- a/src/commands/auth-choice.apply.ts +++ b/src/commands/auth-choice.apply.ts @@ -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( diff --git a/src/commands/auth-choice.test.ts b/src/commands/auth-choice.test.ts index f8305b5ffce..77c5093dc2a 100644 --- a/src/commands/auth-choice.test.ts +++ b/src/commands/auth-choice.test.ts @@ -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"; diff --git a/src/commands/onboard-non-interactive/local/auth-choice.test.ts b/src/commands/onboard-non-interactive/local/auth-choice.test.ts index ddf96f2b5fb..b60f6a80a0a 100644 --- a/src/commands/onboard-non-interactive/local/auth-choice.test.ts +++ b/src/commands/onboard-non-interactive/local/auth-choice.test.ts @@ -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(); diff --git a/src/commands/onboard-non-interactive/local/auth-choice.ts b/src/commands/onboard-non-interactive/local/auth-choice.ts index 3bbdbb0809b..ef558fd03d1 100644 --- a/src/commands/onboard-non-interactive/local/auth-choice.ts +++ b/src/commands/onboard-non-interactive/local/auth-choice.ts @@ -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;