From c4563ee51784bd8717595a5ed64b66b8fe18b8e4 Mon Sep 17 00:00:00 2001 From: Onur Solmaz Date: Tue, 31 Mar 2026 17:07:14 +0200 Subject: [PATCH 1/2] fix(codex): honor configured ACP profile --- images/examples/codex/acp-server.mjs | 6 ++ images/examples/codex/acp-server.test.mjs | 89 +++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/images/examples/codex/acp-server.mjs b/images/examples/codex/acp-server.mjs index 6e20704..06906fc 100644 --- a/images/examples/codex/acp-server.mjs +++ b/images/examples/codex/acp-server.mjs @@ -26,6 +26,7 @@ const DEFAULTS = { workdir: "/workspace", requiredEnv: ["OPENAI_API_KEY"], model: "", + profile: "", shutdownTimeoutMs: 5_000, }; @@ -149,6 +150,7 @@ function extractPromptText(prompt) { function buildConfig(env) { const codexPackageRoot = env.SPRITZ_CODEX_PACKAGE_ROOT || DEFAULTS.codexPackageRoot; const model = String(env.SPRITZ_CODEX_MODEL || DEFAULTS.model || "").trim(); + const profile = String(env.SPRITZ_CODEX_PROFILE || DEFAULTS.profile || "").trim(); const configOptions = []; if (model) { configOptions.push({ @@ -171,6 +173,7 @@ function buildConfig(env) { agentTitle: env.SPRITZ_CODEX_AGENT_TITLE || DEFAULTS.agentTitle, agentVersion: env.SPRITZ_CODEX_AGENT_VERSION || readVersion(codexPackageRoot), model, + profile, configOptions, metadata: { protocolVersion: 1, @@ -308,12 +311,14 @@ class CodexACPRuntime { buildCodexCommand(session, promptText, outputFile) { const modelArgs = this.config.model ? ["--model", this.config.model] : []; + const profileArgs = this.config.profile ? ["-p", this.config.profile] : []; if (session.threadId) { return [ "exec", "resume", "--json", "--skip-git-repo-check", + ...profileArgs, ...modelArgs, ...this.config.codexArgs, "--output-last-message", @@ -326,6 +331,7 @@ class CodexACPRuntime { "exec", "--json", "--skip-git-repo-check", + ...profileArgs, "-C", session.cwd, ...modelArgs, diff --git a/images/examples/codex/acp-server.test.mjs b/images/examples/codex/acp-server.test.mjs index d15ce5d..0bbed06 100644 --- a/images/examples/codex/acp-server.test.mjs +++ b/images/examples/codex/acp-server.test.mjs @@ -138,6 +138,10 @@ function writeMockCodex(tempRoot) { " process.exit(0);", "}", "if (args[0] !== 'exec') { process.exit(1); }", + "const captureFile = String(process.env.CODEX_ARGS_CAPTURE || '');", + "if (captureFile) {", + " fs.appendFileSync(captureFile, JSON.stringify(args) + '\\n');", + "}", "const isResume = args[1] === 'resume';", "const prompt = String(args[args.length - 1] || '');", "const outputFile = findFlagValue('--output-last-message');", @@ -359,3 +363,88 @@ test("session/prompt captures Codex replies and replays them on load", async (t) }); assert.equal(secondPrompt.updates[1].params.update.content.text, "Resumed: second turn"); }); + +test("session/prompt passes the configured Codex profile to fresh and resumed exec calls", async (t) => { + const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "spritz-codex-runtime-")); + const codexPath = writeMockCodex(tempRoot); + const argsCapturePath = path.join(tempRoot, "codex-args.jsonl"); + const runtime = new CodexACPRuntime( + { + codexBin: codexPath, + codexArgs: [], + workdir: tempRoot, + model: "", + profile: "gateway-profile", + configOptions: [], + metadata: { + protocolVersion: 1, + agentCapabilities: { loadSession: true, promptCapabilities: {} }, + agentInfo: { name: "codex", title: "Codex", version: "1.0.0" }, + authMethods: [], + }, + }, + { + ...process.env, + OPENAI_API_KEY: "test-key", + CODEX_ARGS_CAPTURE: argsCapturePath, + }, + console, + ); + t.after(() => { + runtime.stop(); + }); + + const socket = new FakeSocket(); + runtime.attach(socket); + await sendRuntimeRPC(socket, { id: "init-1", jsonrpc: "2.0", method: "initialize", params: {} }); + const created = await sendRuntimeRPC(socket, { + id: "new-1", + jsonrpc: "2.0", + method: "session/new", + params: { cwd: tempRoot, mcpServers: [] }, + }); + const sessionId = String(created.result.sessionId); + + await sendRuntimeRPC(socket, { + id: "prompt-1", + jsonrpc: "2.0", + method: "session/prompt", + params: { + sessionId, + prompt: [{ type: "text", text: "hello world" }], + }, + }); + await sendRuntimeRPC(socket, { + id: "prompt-2", + jsonrpc: "2.0", + method: "session/prompt", + params: { + sessionId, + prompt: [{ type: "text", text: "second turn" }], + }, + }); + + const capturedArgs = fs + .readFileSync(argsCapturePath, "utf8") + .trim() + .split("\n") + .filter(Boolean) + .map((line) => JSON.parse(line)); + + assert.equal(capturedArgs.length, 2); + assert.deepEqual(capturedArgs[0].slice(0, 5), [ + "exec", + "--json", + "--skip-git-repo-check", + "-p", + "gateway-profile", + ]); + assert.deepEqual(capturedArgs[1].slice(0, 6), [ + "exec", + "resume", + "--json", + "--skip-git-repo-check", + "-p", + "gateway-profile", + ]); +}); From 75a2d3bafc3d71b1862b1b1581e7d760e04558c7 Mon Sep 17 00:00:00 2001 From: Onur Solmaz Date: Tue, 31 Mar 2026 17:09:45 +0200 Subject: [PATCH 2/2] fix(codex): order resume profile before subcommand --- images/examples/codex/acp-server.mjs | 4 ++-- images/examples/codex/acp-server.test.mjs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/images/examples/codex/acp-server.mjs b/images/examples/codex/acp-server.mjs index 06906fc..aa1268e 100644 --- a/images/examples/codex/acp-server.mjs +++ b/images/examples/codex/acp-server.mjs @@ -315,10 +315,10 @@ class CodexACPRuntime { if (session.threadId) { return [ "exec", + ...profileArgs, "resume", "--json", "--skip-git-repo-check", - ...profileArgs, ...modelArgs, ...this.config.codexArgs, "--output-last-message", @@ -329,9 +329,9 @@ class CodexACPRuntime { } return [ "exec", + ...profileArgs, "--json", "--skip-git-repo-check", - ...profileArgs, "-C", session.cwd, ...modelArgs, diff --git a/images/examples/codex/acp-server.test.mjs b/images/examples/codex/acp-server.test.mjs index 0bbed06..05980c6 100644 --- a/images/examples/codex/acp-server.test.mjs +++ b/images/examples/codex/acp-server.test.mjs @@ -434,17 +434,17 @@ test("session/prompt passes the configured Codex profile to fresh and resumed ex assert.equal(capturedArgs.length, 2); assert.deepEqual(capturedArgs[0].slice(0, 5), [ "exec", - "--json", - "--skip-git-repo-check", "-p", "gateway-profile", + "--json", + "--skip-git-repo-check", ]); assert.deepEqual(capturedArgs[1].slice(0, 6), [ "exec", + "-p", + "gateway-profile", "resume", "--json", "--skip-git-repo-check", - "-p", - "gateway-profile", ]); });