From 52c227969f56b453eaa7ab7d30b3245b3387806e Mon Sep 17 00:00:00 2001 From: Zuri Date: Sat, 7 Nov 2026 21:00:58 +0200 Subject: [PATCH 1/2] fix(server): codex text generation keeps local provider launch args Text generation filtered the instance's launch args down to config and feature flags, so `--oss`, `--local-provider` and `-p/--profile` were dropped and `codex exec` used a different model provider than chat. Split the filter into per-command builders: `codex exec` now keeps those flags (all accepted by `codex exec`), while `codex mcp list`, which rejects them and `--strict-config`, keeps the shared config/feature flags only. --- .../src/provider/codexLaunchArgs.test.ts | 29 +++++++++++- apps/server/src/provider/codexLaunchArgs.ts | 46 +++++++++++++++---- .../CodexTextGeneration.test.ts | 4 +- .../src/textGeneration/CodexTextGeneration.ts | 12 +++-- 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/apps/server/src/provider/codexLaunchArgs.test.ts b/apps/server/src/provider/codexLaunchArgs.test.ts index ce18c8f3f1bd5..39738656d1924 100644 --- a/apps/server/src/provider/codexLaunchArgs.test.ts +++ b/apps/server/src/provider/codexLaunchArgs.test.ts @@ -2,7 +2,11 @@ import * as NodeAssert from "node:assert/strict"; import { describe, it } from "vite-plus/test"; -import { codexAppServerArgs, codexExecLaunchArgs } from "./codexLaunchArgs.ts"; +import { + codexAppServerArgs, + codexExecLaunchArgs, + codexMcpListLaunchArgs, +} from "./codexLaunchArgs.ts"; describe("codexAppServerArgs", () => { it("preserves escaped TOML quotes in config values", () => { @@ -27,3 +31,26 @@ describe("codexExecLaunchArgs", () => { ]); }); }); + +describe("codex exec and mcp list launch args", () => { + const launchArgs = + "--strict-config --oss --local-provider ollama --profile local -p=work --listen off --enable foo"; + + it("keeps the local model provider flags for codex exec", () => { + NodeAssert.deepStrictEqual(codexExecLaunchArgs(launchArgs), [ + "--strict-config", + "--oss", + "--local-provider", + "ollama", + "--profile", + "local", + "-p=work", + "--enable", + "foo", + ]); + }); + + it("drops exec-only flags for codex mcp list", () => { + NodeAssert.deepStrictEqual(codexMcpListLaunchArgs(launchArgs), ["--enable", "foo"]); + }); +}); diff --git a/apps/server/src/provider/codexLaunchArgs.ts b/apps/server/src/provider/codexLaunchArgs.ts index 33def5ce9a61a..dedf7183e300d 100644 --- a/apps/server/src/provider/codexLaunchArgs.ts +++ b/apps/server/src/provider/codexLaunchArgs.ts @@ -14,26 +14,54 @@ export const codexAppServerArgs = (launchArgs?: string) => [ ...codexLaunchArgv(launchArgs), ]; -export const codexExecLaunchArgs = (launchArgs?: string) => { +interface LaunchArgFilter { + readonly switches: ReadonlySet; + readonly valueFlags: ReadonlySet; + readonly inlinePrefixes: ReadonlyArray; +} + +const SHARED_VALUE_FLAGS = ["--config", "-c", "--enable", "--disable"]; +const SHARED_INLINE_PREFIXES = ["--config=", "-c=", "--enable=", "--disable="]; + +const MCP_LIST_FILTER: LaunchArgFilter = { + switches: new Set(), + valueFlags: new Set(SHARED_VALUE_FLAGS), + inlinePrefixes: SHARED_INLINE_PREFIXES, +}; + +// `codex exec` also takes the local model provider flags; `codex mcp list` rejects them. +const EXEC_FILTER: LaunchArgFilter = { + switches: new Set(["--strict-config", "--oss"]), + valueFlags: new Set([...SHARED_VALUE_FLAGS, "--local-provider", "--profile", "-p"]), + inlinePrefixes: [...SHARED_INLINE_PREFIXES, "--local-provider=", "--profile=", "-p="], +}; + +const filterLaunchArgs = (launchArgs: string | undefined, allowed: LaunchArgFilter) => { const args = codexLaunchArgv(launchArgs); - const execArgs: Array = []; + const kept: Array = []; for (let index = 0; index < args.length; index++) { const arg = args[index]; if (arg === undefined) continue; - if (arg === "--strict-config" || arg.startsWith("--config=") || arg.startsWith("-c=")) { - execArgs.push(arg); - } else if (arg === "--config" || arg === "-c" || arg === "--enable" || arg === "--disable") { + if (allowed.switches.has(arg)) { + kept.push(arg); + } else if (allowed.valueFlags.has(arg)) { const value = args[index + 1]; if (value !== undefined && !value.startsWith("-")) { - execArgs.push(arg, value); + kept.push(arg, value); index++; } - } else if (arg.startsWith("--enable=") || arg.startsWith("--disable=")) { - execArgs.push(arg); + } else if (allowed.inlinePrefixes.some((prefix) => arg.startsWith(prefix))) { + kept.push(arg); } } - return execArgs; + return kept; }; + +export const codexExecLaunchArgs = (launchArgs?: string) => + filterLaunchArgs(launchArgs, EXEC_FILTER); + +export const codexMcpListLaunchArgs = (launchArgs?: string) => + filterLaunchArgs(launchArgs, MCP_LIST_FILTER); diff --git a/apps/server/src/textGeneration/CodexTextGeneration.test.ts b/apps/server/src/textGeneration/CodexTextGeneration.test.ts index 34cc76c95912b..3f50b6a6bfbcd 100644 --- a/apps/server/src/textGeneration/CodexTextGeneration.test.ts +++ b/apps/server/src/textGeneration/CodexTextGeneration.test.ts @@ -429,8 +429,8 @@ it.layer(layerCodexTextGenerationTest)("CodexTextGeneration", (it) => { subject: "Add important change", body: "", }), - launchArgs: "--strict-config --listen off", - requireArg: "--strict-config", + launchArgs: "--strict-config --oss --local-provider ollama --listen off", + requireArg: "--strict-config --oss --local-provider ollama", forbidArg: "--listen", }, (textGeneration) => diff --git a/apps/server/src/textGeneration/CodexTextGeneration.ts b/apps/server/src/textGeneration/CodexTextGeneration.ts index cbf095b303abc..4de5392502c8c 100644 --- a/apps/server/src/textGeneration/CodexTextGeneration.ts +++ b/apps/server/src/textGeneration/CodexTextGeneration.ts @@ -18,7 +18,11 @@ import { resolveSpawnCommand } from "@t3tools/shared/shell"; import { resolveAttachmentPath } from "../attachmentStore.ts"; import * as ServerConfig from "../config.ts"; import { expandHomePath } from "@t3tools/provider-core/server/pathExpansion"; -import { codexExecLaunchArgs, resolveCodexLaunchArgs } from "../provider/codexLaunchArgs.ts"; +import { + codexExecLaunchArgs, + codexMcpListLaunchArgs, + resolveCodexLaunchArgs, +} from "../provider/codexLaunchArgs.ts"; import * as TextGenerationOperations from "@t3tools/provider-core/server/textGenerationOperations"; import { normalizeCliError, @@ -287,19 +291,17 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func } : {}), }; - const execLaunchArgs = codexExecLaunchArgs(launchArgs); const mcpServersOff = yield* listEnabledMcpServers({ binary, cwd, env, - // `codex mcp` rejects --strict-config; the overrides still apply. - launchArgs: execLaunchArgs.filter((arg) => arg !== "--strict-config"), + launchArgs: codexMcpListLaunchArgs(launchArgs), }).pipe(Effect.map(codexMcpServersOff)); const spawnCommand = yield* resolveSpawnCommand( binary, [ "exec", - ...execLaunchArgs, + ...codexExecLaunchArgs(launchArgs), // A user's MCP server could act on the text-generation prompt. ...CODEX_NO_PLUGIN_ARGS, ...(mcpServersOff ? ["--config", mcpServersOff] : []), From 98c6c0872f0832926d0d7beb45f091125b51e5cd Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Tue, 10 Nov 2026 06:05:53 +0000 Subject: [PATCH 2/2] fix(server): discover codex MCP servers with the selected profile --- apps/server/src/provider/codexLaunchArgs.test.ts | 10 ++++++++-- apps/server/src/provider/codexLaunchArgs.ts | 5 ++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/server/src/provider/codexLaunchArgs.test.ts b/apps/server/src/provider/codexLaunchArgs.test.ts index 39738656d1924..661e5abc937e4 100644 --- a/apps/server/src/provider/codexLaunchArgs.test.ts +++ b/apps/server/src/provider/codexLaunchArgs.test.ts @@ -50,7 +50,13 @@ describe("codex exec and mcp list launch args", () => { ]); }); - it("drops exec-only flags for codex mcp list", () => { - NodeAssert.deepStrictEqual(codexMcpListLaunchArgs(launchArgs), ["--enable", "foo"]); + it("keeps the selected profile and drops exec-only flags for codex mcp list", () => { + NodeAssert.deepStrictEqual(codexMcpListLaunchArgs(launchArgs), [ + "--profile", + "local", + "-p=work", + "--enable", + "foo", + ]); }); }); diff --git a/apps/server/src/provider/codexLaunchArgs.ts b/apps/server/src/provider/codexLaunchArgs.ts index dedf7183e300d..b1098af70efd9 100644 --- a/apps/server/src/provider/codexLaunchArgs.ts +++ b/apps/server/src/provider/codexLaunchArgs.ts @@ -25,11 +25,10 @@ const SHARED_INLINE_PREFIXES = ["--config=", "-c=", "--enable=", "--disable="]; const MCP_LIST_FILTER: LaunchArgFilter = { switches: new Set(), - valueFlags: new Set(SHARED_VALUE_FLAGS), - inlinePrefixes: SHARED_INLINE_PREFIXES, + valueFlags: new Set([...SHARED_VALUE_FLAGS, "--profile", "-p"]), + inlinePrefixes: [...SHARED_INLINE_PREFIXES, "--profile=", "-p="], }; -// `codex exec` also takes the local model provider flags; `codex mcp list` rejects them. const EXEC_FILTER: LaunchArgFilter = { switches: new Set(["--strict-config", "--oss"]), valueFlags: new Set([...SHARED_VALUE_FLAGS, "--local-provider", "--profile", "-p"]),