Skip to content

Commit 4721882

Browse files
committed
fix: honor CODEX_CONFIG reasoning summary per turn
sendPrompt() unconditionally set summary to "auto", overriding whatever the session config carried via CODEX_CONFIG. Read the configured value and pass it through; fall back to "auto" only when unset or invalid. disableSummary still forces "none" unconditionally. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
1 parent 616c085 commit 4721882

4 files changed

Lines changed: 53 additions & 8 deletions

File tree

readme-dev.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ Set `CODEX_PATH` to run a different Codex binary; versions other than the one sp
66
- `CODEX_API_KEY` - API key used when the API-key auth method is selected. Takes precedence over `OPENAI_API_KEY`.
77
- `OPENAI_API_KEY` - fallback API key used when the API-key auth method is selected.
88
- `CODEX_PATH` - run a specific Codex executable instead of the bundled package dependency.
9-
- `CODEX_CONFIG` - JSON object merged into the Codex session config.
9+
- `CODEX_CONFIG` - JSON object merged into the Codex session config. Supported keys include:
10+
- `model_reasoning_summary` - controls reasoning summary verbosity per turn. Valid values: `"auto"`, `"concise"`, `"detailed"`, `"none"`. Defaults to `"auto"` when unset. Example: `CODEX_CONFIG='{"model_reasoning_summary":"detailed"}'`.
1011
- `MODEL_PROVIDER` - model provider to pass to Codex for new sessions.
1112
- `DEFAULT_AUTH_REQUEST` - ACP auth request JSON used when Codex requires authentication.
1213
- `INITIAL_AGENT_MODE` - initial mode id: `read-only`, `agent`, or `agent-full-access`.

src/CodexAcpClient.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type {Disposable} from "vscode-jsonrpc";
1313
import type {
1414
ClientInfo,
1515
ReasoningEffort,
16+
ReasoningSummary,
1617
ServiceTier,
1718
ServerNotification
1819
} from "./app-server";
@@ -672,7 +673,7 @@ export class CodexAcpClient {
672673
input: input,
673674
approvalPolicy: agentMode.approvalPolicy,
674675
sandboxPolicy: addAdditionalDirectoriesToSandboxPolicy(agentMode.sandboxPolicy, additionalDirectories),
675-
summary: disableSummary ? "none" : "auto",
676+
summary: disableSummary ? "none" : resolveConfiguredSummary(this.config) ?? "auto",
676677
effort: effort,
677678
model: modelId.model,
678679
serviceTier: serviceTier,
@@ -841,6 +842,16 @@ export class CodexAcpClient {
841842

842843
export type JsonObject = { [key in string]?: JsonValue }
843844

845+
const validReasoningSummaries: ReadonlySet<string> = new Set<ReasoningSummary>(["auto", "concise", "detailed", "none"]);
846+
847+
function resolveConfiguredSummary(config: JsonObject): ReasoningSummary | undefined {
848+
const value = config["model_reasoning_summary"];
849+
if (typeof value === "string" && validReasoningSummaries.has(value)) {
850+
return value as ReasoningSummary;
851+
}
852+
return undefined;
853+
}
854+
844855
export type SessionMetadata = {
845856
sessionId: string,
846857
currentModelId: string,

src/__tests__/CodexACPAgent/CodexAcpClient.test.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
type TestFixture
1212
} from "../acp-test-utils";
1313
import type {ServerNotification} from "../../app-server";
14+
import type {JsonObject} from "../../CodexAcpClient";
1415
import type {SessionState} from "../../CodexAcpServer";
1516
import {AgentMode} from "../../AgentMode";
1617
import type {Model, ReviewStartResponse, ThreadGoal, TurnCompletedNotification, TurnStartParams} from "../../app-server/v2";
@@ -2968,8 +2969,8 @@ describe('ACP server test', { timeout: 40_000 }, () => {
29682969
* Sets up a mock fixture with turnStart/awaitTurnCompleted spied on,
29692970
* and a given session state. Returns the fixture and turnStart spy.
29702971
*/
2971-
function setupPromptFixture(sessionOverrides?: Partial<SessionState>) {
2972-
const mockFixture = createCodexMockTestFixture();
2972+
function setupPromptFixture(sessionOverrides?: Partial<SessionState>, options?: { codexConfig?: JsonObject }) {
2973+
const mockFixture = createCodexMockTestFixture(options);
29732974
const sessionState = createTestSessionState(sessionOverrides);
29742975
const turnStartSpy = vi.spyOn(mockFixture.getCodexAppServerClient(), "turnStart").mockResolvedValue({
29752976
turn: {
@@ -3092,6 +3093,36 @@ describe('ACP server test', { timeout: 40_000 }, () => {
30923093
expect(turnStartSpy).toHaveBeenCalledWith(expect.objectContaining({ summary: "auto" }));
30933094
});
30943095

3096+
it ('should honor configured model_reasoning_summary from CODEX_CONFIG', async () => {
3097+
const { mockFixture, turnStartSpy } = setupPromptFixture({
3098+
account: { type: "chatgpt", email: "test@example.com", planType: "pro" },
3099+
}, { codexConfig: { model_reasoning_summary: "detailed" } });
3100+
3101+
await mockFixture.getCodexAcpAgent().prompt({ sessionId: "id", prompt: [{ type: "text", text: "test" }] });
3102+
3103+
expect(turnStartSpy).toHaveBeenCalledWith(expect.objectContaining({ summary: "detailed" }));
3104+
});
3105+
3106+
it ('should fall back to auto for invalid model_reasoning_summary value', async () => {
3107+
const { mockFixture, turnStartSpy } = setupPromptFixture({
3108+
account: { type: "chatgpt", email: "test@example.com", planType: "pro" },
3109+
}, { codexConfig: { model_reasoning_summary: "verbose" } });
3110+
3111+
await mockFixture.getCodexAcpAgent().prompt({ sessionId: "id", prompt: [{ type: "text", text: "test" }] });
3112+
3113+
expect(turnStartSpy).toHaveBeenCalledWith(expect.objectContaining({ summary: "auto" }));
3114+
});
3115+
3116+
it ('should force none when disableSummary is true regardless of configured summary', async () => {
3117+
const { mockFixture, turnStartSpy } = setupPromptFixture({
3118+
account: { type: "apiKey" },
3119+
}, { codexConfig: { model_reasoning_summary: "detailed" } });
3120+
3121+
await mockFixture.getCodexAcpAgent().prompt({ sessionId: "id", prompt: [{ type: "text", text: "test" }] });
3122+
3123+
expect(turnStartSpy).toHaveBeenCalledWith(expect.objectContaining({ summary: "none" }));
3124+
});
3125+
30953126
it ('should reject prompt with images when model does not support image input', async () => {
30963127
const { mockFixture } = setupPromptFixture({
30973128
supportedInputModalities: ["text"],

src/__tests__/acp-test-utils.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as acp from "@agentclientprotocol/sdk";
22
import type {CreateElicitationResponse, McpServerStdio, RequestPermissionResponse} from "@agentclientprotocol/sdk";
3-
import {CodexAcpClient} from '../CodexAcpClient';
3+
import {CodexAcpClient, type JsonObject} from '../CodexAcpClient';
44
import {CodexAppServerClient, type CodexConnectionEvent} from '../CodexAppServerClient';
55
import {startCodexConnection} from "../CodexJsonRpcConnection";
66
import {CodexAcpServer, type SessionState} from "../CodexAcpServer";
@@ -84,6 +84,7 @@ export interface ConnectionConfig {
8484
connection: MessageConnection;
8585
getExitCode: () => number | null;
8686
acpConnection?: AcpConnectionConfig;
87+
codexConfig?: JsonObject;
8788
}
8889

8990
export function createBaseTestFixture(config: ConnectionConfig): TestFixture {
@@ -96,7 +97,7 @@ export function createBaseTestFixture(config: ConnectionConfig): TestFixture {
9697
});
9798

9899
const codexAppServerClient = new CodexAppServerClient(config.connection);
99-
const codexAcpClient = new CodexAcpClient(codexAppServerClient);
100+
const codexAcpClient = new CodexAcpClient(codexAppServerClient, config.codexConfig);
100101
const codexAcpAgent = new CodexAcpServer(acpConnection, codexAcpClient, undefined, config.getExitCode);
101102

102103
const transportEvents: CodexConnectionEvent[] = [];
@@ -254,7 +255,7 @@ export interface CodexMockTestFixture extends TestFixture {
254255
* Provides `sendServerRequest()` to simulate server-initiated requests (e.g., approval requests).
255256
* Provides `setPermissionResponse()` to control ACP permission dialog responses.
256257
*/
257-
export function createCodexMockTestFixture(): CodexMockTestFixture {
258+
export function createCodexMockTestFixture(options?: { codexConfig?: JsonObject }): CodexMockTestFixture {
258259
let unhandledNotificationHandler: ((notification: any) => void) | null = null;
259260
const requestHandlers = new Map<string, (params: unknown) => Promise<unknown>>();
260261

@@ -306,7 +307,8 @@ export function createCodexMockTestFixture(): CodexMockTestFixture {
306307
connection: acpConnection,
307308
events: acpConnectionEvents,
308309
eventHandlers: acpEventHandlers,
309-
}
310+
},
311+
...(options?.codexConfig != null ? { codexConfig: options.codexConfig } : {}),
310312
});
311313

312314
return {

0 commit comments

Comments
 (0)