diff --git a/src/gateway/gateway-codex-harness.live-helpers.test.ts b/src/gateway/gateway-codex-harness.live-helpers.test.ts index e1904b13856..bc84891975a 100644 --- a/src/gateway/gateway-codex-harness.live-helpers.test.ts +++ b/src/gateway/gateway-codex-harness.live-helpers.test.ts @@ -42,6 +42,39 @@ describe("gateway codex harness live helpers", () => { expect(isExpectedCodexModelsCommandText(text)).toBe(true); }); + it("accepts the interactive TUI current-model summary", () => { + const text = [ + "`codex models` didn’t return a plain list in this environment; it dropped into the interactive TUI instead.", + "", + "What I could confirm from that session is:", + "- Codex CLI version: `v0.118.0`", + "- Current selected model: `local-default-model`", + "- The UI indicates `/model` is the command to change models", + ].join("\n"); + + expect( + EXPECTED_CODEX_MODELS_COMMAND_TEXT.some((expectedText) => text.includes(expectedText)), + ).toBe(true); + expect(isExpectedCodexModelsCommandText(text)).toBe(true); + }); + + it("accepts the local Codex model-cache summary", () => { + const text = [ + "Available models in this Codex install, from the local cache fetched on `2026-04-18`, are:", + "", + "- `gpt-5.4`", + "- `local-default-model`", + "- `gpt-5.4-mini`", + "", + "This session is currently running `codex/gpt-5.4` with `low` reasoning according to `/codex status`.", + ].join("\n"); + + expect( + EXPECTED_CODEX_MODELS_COMMAND_TEXT.some((expectedText) => text.includes(expectedText)), + ).toBe(true); + expect(isExpectedCodexModelsCommandText(text)).toBe(false); + }); + it("rejects unrelated codex command output", () => { expect(isExpectedCodexModelsCommandText("Codex is healthy.")).toBe(false); }); diff --git a/src/gateway/gateway-codex-harness.live-helpers.ts b/src/gateway/gateway-codex-harness.live-helpers.ts index 7ecf8465039..a642ca0e6c0 100644 --- a/src/gateway/gateway-codex-harness.live-helpers.ts +++ b/src/gateway/gateway-codex-harness.live-helpers.ts @@ -13,6 +13,7 @@ export const EXPECTED_CODEX_MODELS_COMMAND_TEXT = [ "`codex models` failed in this sandbox", "`codex models` could not be run in this sandbox.", "`codex models` is not runnable in this sandboxed session.", + "`codex models` didn’t return a plain list in this environment", "I couldn’t get a direct `codex models` CLI listing because the local sandbox blocked that command.", "I couldn’t list all installed/available Codex models from the local CLI because the sandboxed `codex` command failed to start in this environment.", "I couldn’t get `codex models` from the CLI because the sandbox blocks the namespace setup it needs", @@ -21,6 +22,7 @@ export const EXPECTED_CODEX_MODELS_COMMAND_TEXT = [ "Available models in this session:", "Available models in this environment:", "Available models in this Codex environment:", + "Available models in this Codex install", "Available agent models:", "Visible options in this session:", "Current: `codex/", @@ -83,18 +85,32 @@ export function isExpectedCodexModelsCommandText(text: string): boolean { const mentionsInteractiveSelection = normalized.includes("interactive model-selection prompt") || - normalized.includes("interactive model selection prompt"); + normalized.includes("interactive model selection prompt") || + normalized.includes("interactive tui"); const mentionsVisibleOptions = normalized.includes("visible options in this session:") || normalized.includes("visible options:"); const mentionsCurrentActiveModel = normalized.includes("current active model is `codex/") || normalized.includes("current active model is codex/"); + const mentionsCurrentSelectedModel = + normalized.includes("current selected model:") || + normalized.includes("currently selected model:"); const isInteractiveSelectionSummary = text.includes("`/codex models`") && mentionsInteractiveSelection && mentionsVisibleOptions && mentionsCurrentActiveModel; + const isInteractiveTuiSummary = + mentionsCodexModelsCommand && + mentionsInteractiveSelection && + normalized.includes("plain list") && + mentionsCurrentSelectedModel; - return isSandboxFallback || isSessionConfigFallback || isInteractiveSelectionSummary; + return ( + isSandboxFallback || + isSessionConfigFallback || + isInteractiveSelectionSummary || + isInteractiveTuiSummary + ); }