diff --git a/src/agents/pi-embedded-runner/model.test.ts b/src/agents/pi-embedded-runner/model.test.ts index ca12a76cb36..766765c415e 100644 --- a/src/agents/pi-embedded-runner/model.test.ts +++ b/src/agents/pi-embedded-runner/model.test.ts @@ -638,6 +638,32 @@ describe("resolveModel", () => { }); }); + it("uses codex fallback when inline model omits api (#39682)", () => { + mockOpenAICodexTemplateModel(); + + // When a user lists gpt-5.4 under openai-codex models without specifying + // an api, the inline match must not shadow the forward-compat resolver + // that supplies "openai-codex-responses". + const cfg: OpenClawConfig = { + models: { + providers: { + "openai-codex": { + baseUrl: "https://custom.example.com", + models: [{ id: "gpt-5.4" }], + }, + }, + }, + } as unknown as OpenClawConfig; + + const result = resolveModel("openai-codex", "gpt-5.4", "/tmp/agent", cfg); + expect(result.error).toBeUndefined(); + expect(result.model).toMatchObject({ + api: "openai-codex-responses", + id: "gpt-5.4", + provider: "openai-codex", + }); + }); + it("includes auth hint for unknown ollama models (#17328)", () => { // resetMockDiscoverModels() in beforeEach already sets find → null const result = resolveModel("ollama", "gemma3:4b", "/tmp/agent"); diff --git a/src/agents/pi-embedded-runner/model.ts b/src/agents/pi-embedded-runner/model.ts index f1b31a5e49a..efb3112bd77 100644 --- a/src/agents/pi-embedded-runner/model.ts +++ b/src/agents/pi-embedded-runner/model.ts @@ -161,7 +161,12 @@ export function resolveModelWithRegistry(params: { (entry) => normalizeProviderId(entry.provider) === normalizedProvider && entry.id === modelId, ); if (inlineMatch) { - return normalizeModelCompat(inlineMatch as Model); + // When the inline model already carries a concrete api, use it as-is. + // Otherwise fall through so forward-compat resolvers can supply the + // correct api (e.g. "openai-codex-responses" for gpt-5.4). #39682 + if (inlineMatch.api) { + return normalizeModelCompat(inlineMatch as Model); + } } // Forward-compat fallbacks must be checked BEFORE the generic providerCfg fallback.