From 34f50b4860c8ea1773cdfb607d15a90b346f8b6e Mon Sep 17 00:00:00 2001 From: Dallin Romney Date: Thu, 20 Aug 2026 22:35:44 -0700 Subject: [PATCH] fix(codex): preserve omitted resume effort --- .../src/app-server/thread-lifecycle-io.ts | 4 ++- .../thread-lifecycle.binding.test.ts | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/extensions/codex/src/app-server/thread-lifecycle-io.ts b/extensions/codex/src/app-server/thread-lifecycle-io.ts index 6540aee8724e..1f96c9331b9b 100644 --- a/extensions/codex/src/app-server/thread-lifecycle-io.ts +++ b/extensions/codex/src/app-server/thread-lifecycle-io.ts @@ -285,7 +285,9 @@ export async function resumeExistingCodexThread( boundAuthProfileId, response.modelProvider ?? requestModelProvider ?? startModelProvider, ), - reasoningEffort: response.reasoningEffort, + ...(response.reasoningEffort !== undefined + ? { reasoningEffort: response.reasoningEffort } + : {}), dynamicToolsFingerprint, dynamicToolsContainDeferred, webSearchThreadConfigFingerprint, diff --git a/extensions/codex/src/app-server/thread-lifecycle.binding.test.ts b/extensions/codex/src/app-server/thread-lifecycle.binding.test.ts index abe6838dcbb2..0faf83beeae2 100644 --- a/extensions/codex/src/app-server/thread-lifecycle.binding.test.ts +++ b/extensions/codex/src/app-server/thread-lifecycle.binding.test.ts @@ -291,6 +291,40 @@ function createTwoCalendarAppPolicyContext() { setupRunAttemptTestHooks(); describe("Codex app-server thread lifecycle bindings", () => { + it("preserves the stored reasoning effort when resume omits it", async () => { + const sessionFile = path.join(tempDir, "session-effort.jsonl"); + const workspaceDir = path.join(tempDir, "workspace-effort"); + const threadId = "thread-effort"; + const request = vi.fn(async (method: string) => { + const response = threadStartResult(threadId); + if (method === "thread/start") { + return { ...response, reasoningEffort: "high" }; + } + if (method === "thread/resume") { + const { reasoningEffort: _reasoningEffort, ...withoutReasoningEffort } = response; + return withoutReasoningEffort; + } + throw new Error(`unexpected method: ${method}`); + }); + const common = { + client: { getInstanceId: () => "effort-client", request } as never, + params: createParams(sessionFile, workspaceDir), + cwd: workspaceDir, + dynamicTools: [], + appServer: createThreadLifecycleAppServerOptions(), + userMcpServersEnabled: false, + }; + + await startOrResumeThread(common); + await startOrResumeThread(common); + + expect(request.mock.calls.map(([method]) => method)).toEqual(["thread/start", "thread/resume"]); + await expect(readCodexAppServerBinding(sessionFile)).resolves.toMatchObject({ + threadId, + reasoningEffort: "high", + }); + }); + it("persists the native rollout path across thread start and resume", async () => { const sessionFile = path.join(tempDir, "session.jsonl"); const workspaceDir = path.join(tempDir, "workspace");