Skip to content

Commit ea4251e

Browse files
committed
fix: finish OpenAI cleanup follow-through
1 parent 8645653 commit ea4251e

8 files changed

Lines changed: 67 additions & 49 deletions

File tree

src/agents/tools/pdf-tool.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,11 @@ describe("createPdfTool", () => {
557557

558558
it("uses extraction fallback for non-native models", async () => {
559559
await withTempPdfAgentDir(async (agentDir) => {
560-
await stubPdfToolInfra(agentDir, { provider: "openai", input: ["text"] });
560+
await stubPdfToolInfra(agentDir, {
561+
provider: "openai",
562+
api: "openai-responses",
563+
input: ["text"],
564+
});
561565
const extractSpy = vi.spyOn(pdfExtractModule, "extractPdfContent").mockResolvedValue({
562566
text: "Extracted content",
563567
images: [],

src/commands/auth-choice.model-check.test.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ describe("warnIfModelConfigLooksOff", () => {
4646

4747
expect(loadModelCatalog).not.toHaveBeenCalled();
4848
expect(ensureAuthProfileStore).toHaveBeenCalledOnce();
49-
expect(listProfilesForProvider).toHaveBeenCalledTimes(2);
50-
expect(listProfilesForProvider).toHaveBeenCalledWith({ version: 1, profiles: {} }, "openai");
49+
expect(listProfilesForProvider).toHaveBeenCalledOnce();
5150
expect(listProfilesForProvider).toHaveBeenCalledWith({ version: 1, profiles: {} }, "openai");
5251
expect(note).toHaveBeenCalledWith(
5352
'No auth configured for provider "openai". The agent may fail until credentials are added. Run `openclaw models auth login --provider openai`, `openclaw configure`, or set an API key env var.',
@@ -88,14 +87,26 @@ describe("warnIfModelConfigLooksOff", () => {
8887

8988
expect(note).not.toHaveBeenCalled();
9089
expect(listProfilesForProvider).toHaveBeenCalledWith(store, "openai");
91-
expect(listProfilesForProvider).toHaveBeenCalledWith(store, "openai");
9290
expect(resolveEnvApiKey).not.toHaveBeenCalled();
9391
expect(hasUsableCustomProviderApiKey).not.toHaveBeenCalled();
9492
});
9593

9694
it("keeps custom OpenAI-compatible provider auth separate from Codex OAuth profiles", async () => {
9795
const note = vi.fn(async () => {});
9896
const prompter = makePrompter({ note });
97+
const store = {
98+
version: 1,
99+
profiles: {
100+
"openai:default": {
101+
type: "oauth",
102+
provider: "openai",
103+
access: "access-token",
104+
refresh: "refresh-token",
105+
expires: Date.now() + 60_000,
106+
},
107+
},
108+
} satisfies AuthProfileStore;
109+
ensureAuthProfileStore.mockReturnValue(store);
99110
listProfilesForProvider.mockImplementation((_store, provider) =>
100111
provider === "openai" ? ["openai:default"] : [],
101112
);
@@ -119,7 +130,7 @@ describe("warnIfModelConfigLooksOff", () => {
119130

120131
await warnIfModelConfigLooksOff(config, prompter, { validateCatalog: false });
121132

122-
expect(listProfilesForProvider.mock.calls.map(([, provider]) => provider)).toEqual(["openai"]);
133+
expect(listProfilesForProvider).toHaveBeenCalledWith(store, "openai");
123134
expect(note).toHaveBeenCalledWith(
124135
'No auth configured for provider "openai". The agent may fail until credentials are added. Run `openclaw models auth login --provider openai`, `openclaw configure`, or set an API key env var.',
125136
"Model check",

src/commands/auth-choice.model-check.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import { ensureAuthProfileStore, listProfilesForProvider } from "../agents/auth-profiles.js";
2+
import type { AuthProfileCredential } from "../agents/auth-profiles/types.js";
23
import { resolveAgentHarnessPolicy } from "../agents/harness/policy.js";
34
import { hasUsableCustomProviderApiKey, resolveEnvApiKey } from "../agents/model-auth.js";
45
import { loadModelCatalog } from "../agents/model-catalog.js";
56
import { resolveDefaultModelForAgent } from "../agents/model-selection.js";
6-
import { listOpenAIAuthProfileProvidersForAgentRuntime } from "../agents/openai-routing.js";
7+
import {
8+
listOpenAIAuthProfileProvidersForAgentRuntime,
9+
openAIProviderUsesCodexRuntimeByDefault,
10+
} from "../agents/openai-routing.js";
711
import type { OpenClawConfig } from "../config/types.openclaw.js";
812
import type { WizardPrompter } from "../wizard/prompts.js";
913
import { buildProviderAuthRecoveryHint } from "./provider-auth-guidance.js";
@@ -32,6 +36,37 @@ function resolveAuthProviderCandidates(params: {
3236
];
3337
}
3438

39+
function resolveAcceptedAuthProfileTypes(params: {
40+
config: OpenClawConfig;
41+
provider: string;
42+
}): readonly AuthProfileCredential["type"][] | undefined {
43+
if (
44+
openAIProviderUsesCodexRuntimeByDefault({
45+
provider: params.provider,
46+
config: params.config,
47+
})
48+
) {
49+
return undefined;
50+
}
51+
return params.provider === "openai" ? ["api_key"] : undefined;
52+
}
53+
54+
function hasProfileForProvider(params: {
55+
store: ReturnType<typeof ensureAuthProfileStore>;
56+
provider: string;
57+
acceptedTypes?: readonly AuthProfileCredential["type"][];
58+
}): boolean {
59+
const profileIds = listProfilesForProvider(params.store, params.provider);
60+
if (!params.acceptedTypes) {
61+
return profileIds.length > 0;
62+
}
63+
const acceptedTypes = new Set(params.acceptedTypes);
64+
return profileIds.some((profileId) => {
65+
const profile = params.store.profiles[profileId];
66+
return profile ? acceptedTypes.has(profile.type) : false;
67+
});
68+
}
69+
3570
export async function warnIfModelConfigLooksOff(
3671
config: OpenClawConfig,
3772
prompter: WizardPrompter,
@@ -66,8 +101,12 @@ export async function warnIfModelConfigLooksOff(
66101
modelId: ref.model,
67102
agentId: options?.agentId,
68103
});
104+
const acceptedTypes = resolveAcceptedAuthProfileTypes({
105+
config,
106+
provider: ref.provider,
107+
});
69108
const hasAuth =
70-
authProviders.some((provider) => listProfilesForProvider(store, provider).length > 0) ||
109+
authProviders.some((provider) => hasProfileForProvider({ store, provider, acceptedTypes })) ||
71110
authProviders.some((provider) => resolveEnvApiKey(provider)) ||
72111
authProviders.some((provider) => hasUsableCustomProviderApiKey(config, provider));
73112
if (!hasAuth) {

src/commands/doctor-memory-search.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,9 @@ async function hasApiKeyForProvider(
667667
}
668668

669669
function resolvePrimaryMemoryProviderEnvVar(provider: string): string {
670+
if (provider === "openai") {
671+
return "OPENAI_API_KEY";
672+
}
670673
const metadata = resolveMemoryEmbeddingProviderDoctorMetadata(provider);
671674
return metadata?.envVars[0] ?? `${provider.toUpperCase()}_API_KEY`;
672675
}

src/commands/doctor/shared/codex-route-warnings.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3474,7 +3474,7 @@ describe("collectCodexRouteWarnings", () => {
34743474
agentId: "worker",
34753475
config: cfg,
34763476
}).runtime,
3477-
).toBe("codex");
3477+
).toBe("auto");
34783478

34793479
const result = maybeRepairCodexRoutes({
34803480
cfg,

src/commands/model-picker.test.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -349,18 +349,13 @@ afterEach(() => {
349349
});
350350

351351
describe("promptDefaultModel", () => {
352-
it("adds runtime-route hints for canonical and legacy OpenAI Codex models", async () => {
352+
it("adds runtime-route hints for canonical OpenAI models", async () => {
353353
loadModelCatalog.mockResolvedValue([
354354
{
355355
provider: "openai",
356356
id: "gpt-5.5",
357357
name: "GPT-5.5",
358358
},
359-
{
360-
provider: "openai",
361-
id: "gpt-5.5",
362-
name: "GPT-5.5",
363-
},
364359
]);
365360

366361
const select = vi.fn(async (params) => params.initialValue as never);
@@ -377,8 +372,6 @@ describe("promptDefaultModel", () => {
377372
const options = pickerOptions(select as MockCallSource);
378373
const canonical = requireOption(options, "openai/gpt-5.5");
379374
expect(canonical.hint).toContain("Codex runtime route");
380-
const legacy = requireOption(options, "openai/gpt-5.5");
381-
expect(legacy.hint).toContain("legacy Codex OAuth route");
382375
});
383376

384377
it("hides unauthenticated catalog entries from default model choices", async () => {
@@ -453,7 +446,6 @@ describe("promptDefaultModel", () => {
453446
"openai/gpt-5.5",
454447
"anthropic/claude-sonnet-4-6",
455448
"google/gemini-3.1-pro-preview",
456-
"openai/gpt-5.5",
457449
]);
458450
});
459451

src/commands/models/list.table.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ describe("printModelTable", () => {
2323

2424
expect(runtime.log.mock.calls).toEqual([
2525
["Model Input Ctx Local Auth Tags"],
26-
["openai/gpt-5.5 text+image 266k/391k no yes "],
26+
["openai/gpt-5.5 text+image 266k/391k no yes "],
2727
]);
2828
});
2929
});

src/commands/onboard-non-interactive/local/auth-choice.test.ts

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -81,37 +81,6 @@ describe("applyNonInteractiveAuthChoice", () => {
8181
expect(applyNonInteractivePluginProviderChoice).toHaveBeenCalledOnce();
8282
});
8383

84-
it("normalizes legacy OpenAI Codex setup choice before provider auth", async () => {
85-
const runtime = createRuntime();
86-
const nextConfig = { agents: { defaults: {} } } as OpenClawConfig;
87-
const resolvedConfig = { auth: { profiles: { "openai:default": { mode: "oauth" } } } };
88-
resolveManifestDeprecatedProviderAuthChoice.mockImplementation(((choiceId: string) =>
89-
choiceId === "openai"
90-
? {
91-
choiceId: "openai",
92-
choiceLabel: "ChatGPT Login",
93-
}
94-
: undefined) as never);
95-
applyNonInteractivePluginProviderChoice.mockResolvedValueOnce(resolvedConfig as never);
96-
97-
const result = await applyNonInteractiveAuthChoice({
98-
nextConfig,
99-
authChoice: "openai",
100-
opts: {} as never,
101-
runtime: runtime as never,
102-
baseConfig: nextConfig,
103-
});
104-
105-
expect(result).toBe(resolvedConfig);
106-
expect(runtime.log).toHaveBeenCalledWith(
107-
'Auth choice "openai" is deprecated; using ChatGPT Login setup instead.',
108-
);
109-
expect(runtime.error).not.toHaveBeenCalled();
110-
expect(applyNonInteractivePluginProviderChoice).toHaveBeenCalledWith(
111-
expect.objectContaining({ authChoice: "openai" }),
112-
);
113-
});
114-
11584
it("escapes deprecated auth choice guidance for terminal output", async () => {
11685
const runtime = createRuntime();
11786
const nextConfig = { agents: { defaults: {} } } as OpenClawConfig;

0 commit comments

Comments
 (0)