diff --git a/packages/adapters/codex-local/src/index.ts b/packages/adapters/codex-local/src/index.ts index 8bd1d699..4c4a2de0 100644 --- a/packages/adapters/codex-local/src/index.ts +++ b/packages/adapters/codex-local/src/index.ts @@ -27,6 +27,11 @@ export function isCodexLocalManualModel(model: string | null | undefined): boole export function isCodexLocalFastModeSupported(model: string | null | undefined): boolean { if (isCodexLocalManualModel(model)) return true; const normalizedModel = typeof model === "string" ? model.trim() : ""; + // Empty means we're omitting --model so the Codex CLI picks its own default. + // On subscription auth that's gpt-5.5 (fast-mode capable); manual model IDs + // are also treated as supported. Match that policy: pass the fast-mode + // overrides through and let the CLI reject them if the chosen model can't use them. + if (!normalizedModel) return true; return CODEX_LOCAL_FAST_MODE_SUPPORTED_MODELS.includes( normalizedModel as (typeof CODEX_LOCAL_FAST_MODE_SUPPORTED_MODELS)[number], ); diff --git a/packages/adapters/codex-local/src/server/codex-args.test.ts b/packages/adapters/codex-local/src/server/codex-args.test.ts index feb22574..5ef2608d 100644 --- a/packages/adapters/codex-local/src/server/codex-args.test.ts +++ b/packages/adapters/codex-local/src/server/codex-args.test.ts @@ -70,6 +70,25 @@ describe("buildCodexExecArgs", () => { ]); }); + it("enables Codex fast mode overrides when model is omitted (CLI default)", () => { + const result = buildCodexExecArgs({ + fastMode: true, + }); + + expect(result.fastModeRequested).toBe(true); + expect(result.fastModeApplied).toBe(true); + expect(result.fastModeIgnoredReason).toBeNull(); + expect(result.args).toEqual([ + "exec", + "--json", + "-c", + 'service_tier="fast"', + "-c", + "features.fast_mode=true", + "-", + ]); + }); + it("ignores fast mode for unsupported models", () => { const result = buildCodexExecArgs({ model: "gpt-5.3-codex", diff --git a/packages/adapters/codex-local/src/ui/build-config.test.ts b/packages/adapters/codex-local/src/ui/build-config.test.ts index 734d1687..8126c0fb 100644 --- a/packages/adapters/codex-local/src/ui/build-config.test.ts +++ b/packages/adapters/codex-local/src/ui/build-config.test.ts @@ -51,4 +51,10 @@ describe("buildCodexLocalConfig", () => { dangerouslyBypassApprovalsAndSandbox: true, }); }); + + it("omits model when the operator leaves it blank", () => { + const config = buildCodexLocalConfig(makeValues({ model: "" })); + + expect(config).not.toHaveProperty("model"); + }); }); diff --git a/packages/adapters/codex-local/src/ui/build-config.ts b/packages/adapters/codex-local/src/ui/build-config.ts index 78e5e806..ab67feb6 100644 --- a/packages/adapters/codex-local/src/ui/build-config.ts +++ b/packages/adapters/codex-local/src/ui/build-config.ts @@ -1,8 +1,5 @@ import type { CreateConfigValues } from "@paperclipai/adapter-utils"; -import { - DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX, - DEFAULT_CODEX_LOCAL_MODEL, -} from "../index.js"; +import { DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX } from "../index.js"; function parseCommaArgs(value: string): string[] { return value @@ -70,7 +67,7 @@ export function buildCodexLocalConfig(v: CreateConfigValues): Record = {}; if (v.cwd) ac.cwd = v.cwd; if (v.instructionsFilePath) ac.instructionsFilePath = v.instructionsFilePath; - ac.model = v.model || DEFAULT_CODEX_LOCAL_MODEL; + if (v.model) ac.model = v.model; if (v.thinkingEffort) ac.modelReasoningEffort = v.thinkingEffort; ac.timeoutSec = 0; ac.graceSec = 15; diff --git a/server/src/routes/agents.ts b/server/src/routes/agents.ts index fb706f8e..3182c2bf 100644 --- a/server/src/routes/agents.ts +++ b/server/src/routes/agents.ts @@ -85,10 +85,7 @@ import { DEFAULT_ACPX_LOCAL_NON_INTERACTIVE_PERMISSIONS, DEFAULT_ACPX_LOCAL_PERMISSION_MODE, } from "@paperclipai/adapter-acpx-local"; -import { - DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX, - DEFAULT_CODEX_LOCAL_MODEL, -} from "@paperclipai/adapter-codex-local"; +import { DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX } from "@paperclipai/adapter-codex-local"; import { DEFAULT_CURSOR_LOCAL_MODEL } from "@paperclipai/adapter-cursor-local"; import { DEFAULT_GEMINI_LOCAL_MODEL } from "@paperclipai/adapter-gemini-local"; import { DEFAULT_OPENCODE_LOCAL_MODEL } from "@paperclipai/adapter-opencode-local"; @@ -1112,9 +1109,6 @@ export function agentRoutes( return ensureGatewayDeviceKey(adapterType, next); } if (adapterType === "codex_local") { - if (!asNonEmptyString(next.model)) { - next.model = DEFAULT_CODEX_LOCAL_MODEL; - } const hasBypassFlag = typeof next.dangerouslyBypassApprovalsAndSandbox === "boolean" || typeof next.dangerouslyBypassSandbox === "boolean"; diff --git a/ui/src/components/AgentConfigForm.tsx b/ui/src/components/AgentConfigForm.tsx index 9532ba5d..264e61e9 100644 --- a/ui/src/components/AgentConfigForm.tsx +++ b/ui/src/components/AgentConfigForm.tsx @@ -14,10 +14,7 @@ import { environmentsApi } from "../api/environments"; import { instanceSettingsApi } from "../api/instanceSettings"; import { secretsApi } from "../api/secrets"; import { assetsApi } from "../api/assets"; -import { - DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX, - DEFAULT_CODEX_LOCAL_MODEL, -} from "@paperclipai/adapter-codex-local"; +import { DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX } from "@paperclipai/adapter-codex-local"; import { DEFAULT_CURSOR_LOCAL_MODEL } from "@paperclipai/adapter-cursor-local"; import { DEFAULT_GEMINI_LOCAL_MODEL } from "@paperclipai/adapter-gemini-local"; import { DEFAULT_OPENCODE_LOCAL_MODEL } from "@paperclipai/adapter-opencode-local"; @@ -852,7 +849,6 @@ export function AgentConfigForm(props: AgentConfigFormProps) { const { adapterType: _at, ...defaults } = defaultCreateValues; const nextValues: CreateConfigValues = { ...defaults, adapterType: t }; if (t === "codex_local") { - nextValues.model = DEFAULT_CODEX_LOCAL_MODEL; nextValues.dangerouslyBypassSandbox = DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX; } else if (t === "gemini_local") { @@ -872,10 +868,8 @@ export function AgentConfigForm(props: AgentConfigFormProps) { modelProfiles: { cheap: { cleared: true } }, adapterConfig: { model: - t === "codex_local" - ? DEFAULT_CODEX_LOCAL_MODEL - : t === "gemini_local" - ? DEFAULT_GEMINI_LOCAL_MODEL + t === "gemini_local" + ? DEFAULT_GEMINI_LOCAL_MODEL : t === "opencode_local" ? DEFAULT_OPENCODE_LOCAL_MODEL : t === "cursor" diff --git a/ui/src/components/OnboardingWizard.tsx b/ui/src/components/OnboardingWizard.tsx index 0f9c2378..f30168cd 100644 --- a/ui/src/components/OnboardingWizard.tsx +++ b/ui/src/components/OnboardingWizard.tsx @@ -37,10 +37,7 @@ import { selectDefaultCompanyGoalId } from "../lib/onboarding-launch"; import { buildNewAgentRuntimeConfig } from "../lib/new-agent-runtime-config"; -import { - DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX, - DEFAULT_CODEX_LOCAL_MODEL -} from "@paperclipai/adapter-codex-local"; +import { DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX } from "@paperclipai/adapter-codex-local"; import { DEFAULT_CURSOR_LOCAL_MODEL } from "@paperclipai/adapter-cursor-local"; import { DEFAULT_GEMINI_LOCAL_MODEL } from "@paperclipai/adapter-gemini-local"; import { DEFAULT_OPENCODE_LOCAL_MODEL, isValidOpenCodeModelId } from "@paperclipai/adapter-opencode-local"; @@ -322,10 +319,8 @@ export function OnboardingWizard() { ...defaultCreateValues, adapterType, model: - adapterType === "codex_local" - ? model || DEFAULT_CODEX_LOCAL_MODEL - : adapterType === "gemini_local" - ? model || DEFAULT_GEMINI_LOCAL_MODEL + adapterType === "gemini_local" + ? model || DEFAULT_GEMINI_LOCAL_MODEL : adapterType === "cursor" ? model || DEFAULT_CURSOR_LOCAL_MODEL : adapterType === "opencode_local" @@ -754,9 +749,6 @@ export function OnboardingWizard() { const nextType = opt.type; setAdapterType(nextType); if (nextType === "codex_local") { - if (!model) { - setModel(DEFAULT_CODEX_LOCAL_MODEL); - } return; } if (nextType === "opencode_local") { diff --git a/ui/src/pages/NewAgent.tsx b/ui/src/pages/NewAgent.tsx index efb9411a..a786defc 100644 --- a/ui/src/pages/NewAgent.tsx +++ b/ui/src/pages/NewAgent.tsx @@ -32,10 +32,7 @@ import { ReportsToPicker } from "../components/ReportsToPicker"; import { buildNewAgentHirePayload } from "../lib/new-agent-hire-payload"; import { TrustPresetSection } from "../components/TrustPresetSection"; import { buildPermissionsForTrustPreset, getTrustPreset } from "../lib/trust-policy-ui"; -import { - DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX, - DEFAULT_CODEX_LOCAL_MODEL, -} from "@paperclipai/adapter-codex-local"; +import { DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX } from "@paperclipai/adapter-codex-local"; import { DEFAULT_CURSOR_LOCAL_MODEL } from "@paperclipai/adapter-cursor-local"; import { DEFAULT_GEMINI_LOCAL_MODEL } from "@paperclipai/adapter-gemini-local"; import { DEFAULT_OPENCODE_LOCAL_MODEL, isValidOpenCodeModelId } from "@paperclipai/adapter-opencode-local"; @@ -46,7 +43,6 @@ function createValuesForAdapterType( const { adapterType: _discard, ...defaults } = defaultCreateValues; const nextValues: CreateConfigValues = { ...defaults, adapterType }; if (adapterType === "codex_local") { - nextValues.model = DEFAULT_CODEX_LOCAL_MODEL; nextValues.dangerouslyBypassSandbox = DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX; } else if (adapterType === "gemini_local") {