From 7cff91ceba9772b24be165fba15e0466371a1ac5 Mon Sep 17 00:00:00 2001 From: JonathanLab Date: Thu, 30 Apr 2026 14:09:17 +0200 Subject: [PATCH] feat(codex): upgrade to codex-acp 0.12.0 and normalize config options Generated-By: PostHog Code Task-Id: cb22f81b-7734-43fa-9c85-46aa40b66d40 --- apps/code/scripts/download-binaries.mjs | 2 +- .../agent/src/adapters/codex/codex-agent.ts | 16 ++++++ packages/agent/src/adapters/codex/models.ts | 50 +++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/apps/code/scripts/download-binaries.mjs b/apps/code/scripts/download-binaries.mjs index a8e6d964d..42772e08e 100644 --- a/apps/code/scripts/download-binaries.mjs +++ b/apps/code/scripts/download-binaries.mjs @@ -19,7 +19,7 @@ const DEST_DIR = join(__dirname, "..", "resources", "codex-acp"); const BINARIES = [ { name: "codex-acp", - version: "0.11.1", + version: "0.12.0", getUrl: (version, target) => { const ext = target.includes("windows") ? "zip" : "tar.gz"; return `https://github.com/zed-industries/codex-acp/releases/download/v${version}/codex-acp-${version}-${target}.${ext}`; diff --git a/packages/agent/src/adapters/codex/codex-agent.ts b/packages/agent/src/adapters/codex/codex-agent.ts index 9ed83ec57..d2f6e730c 100644 --- a/packages/agent/src/adapters/codex/codex-agent.ts +++ b/packages/agent/src/adapters/codex/codex-agent.ts @@ -60,6 +60,7 @@ import { } from "../../utils/streams"; import { BaseAcpAgent, type BaseSession } from "../base-acp-agent"; import { createCodexClient } from "./codex-client"; +import { normalizeCodexConfigOptions } from "./models"; import { type CodexSessionState, createSessionState, @@ -265,6 +266,9 @@ export class CodexAcpAgent extends BaseAcpAgent { const requestedPermissionMode = toCodexPermissionMode(meta?.permissionMode); const response = await this.codexConnection.newSession(params); + response.configOptions = normalizeCodexConfigOptions( + response.configOptions, + ); // Initialize session state this.sessionState = createSessionState(response.sessionId, params.cwd, { @@ -302,6 +306,9 @@ export class CodexAcpAgent extends BaseAcpAgent { async loadSession(params: LoadSessionRequest): Promise { const response = await this.codexConnection.loadSession(params); + response.configOptions = normalizeCodexConfigOptions( + response.configOptions, + ); const meta = params._meta as NewSessionMeta | undefined; const currentPermissionMode = getCurrentPermissionMode( response.modes?.currentModeId, @@ -341,6 +348,9 @@ export class CodexAcpAgent extends BaseAcpAgent { cwd: params.cwd, mcpServers: params.mcpServers ?? [], }); + loadResponse.configOptions = normalizeCodexConfigOptions( + loadResponse.configOptions, + ); const meta = params._meta as NewSessionMeta | undefined; const currentPermissionMode = getCurrentPermissionMode( @@ -380,6 +390,9 @@ export class CodexAcpAgent extends BaseAcpAgent { mcpServers: params.mcpServers ?? [], _meta: params._meta, }); + newResponse.configOptions = normalizeCodexConfigOptions( + newResponse.configOptions, + ); const meta = params._meta as NewSessionMeta | undefined; const requestedPermissionMode = toCodexPermissionMode(meta?.permissionMode); @@ -665,6 +678,9 @@ export class CodexAcpAgent extends BaseAcpAgent { ): Promise { const response = await this.codexConnection.setSessionConfigOption(params); if (response.configOptions) { + response.configOptions = normalizeCodexConfigOptions( + response.configOptions, + ) as typeof response.configOptions; this.sessionState.configOptions = response.configOptions; } if (params.configId === "mode" && typeof params.value === "string") { diff --git a/packages/agent/src/adapters/codex/models.ts b/packages/agent/src/adapters/codex/models.ts index ee5fab47d..635e631c7 100644 --- a/packages/agent/src/adapters/codex/models.ts +++ b/packages/agent/src/adapters/codex/models.ts @@ -1,3 +1,9 @@ +import type { + SessionConfigOption, + SessionConfigSelectGroup, + SessionConfigSelectOption, +} from "@agentclientprotocol/sdk"; + interface ReasoningEffortOption { value: string; name: string; @@ -14,3 +20,47 @@ export function getReasoningEffortOptions( ): ReasoningEffortOption[] { return CODEX_REASONING_EFFORT_OPTIONS; } + +const CODEX_ACRONYMS: Record = { + gpt: "GPT", +}; + +export function formatCodexModelName(value: string): string { + const normalized = value.replace(/(\d)-(\d)/g, "$1.$2"); + return normalized + .split("-") + .map((part) => { + const lower = part.toLowerCase(); + if (CODEX_ACRONYMS[lower]) return CODEX_ACRONYMS[lower]; + if (/^[0-9.]+$/.test(part)) return part; + return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase(); + }) + .join("-"); +} + +export function normalizeCodexConfigOptions( + configOptions: SessionConfigOption[] | null | undefined, +): SessionConfigOption[] | null | undefined { + if (!configOptions) return configOptions; + const formatOption = ( + opt: SessionConfigSelectOption, + ): SessionConfigSelectOption => ({ + ...opt, + name: formatCodexModelName(opt.value), + }); + return configOptions.map((option) => { + if (option.category !== "model" || option.type !== "select") return option; + const options = option.options; + if (options.length === 0) return option; + const isGroup = "group" in options[0]; + return { + ...option, + options: isGroup + ? (options as SessionConfigSelectGroup[]).map((group) => ({ + ...group, + options: group.options.map(formatOption), + })) + : (options as SessionConfigSelectOption[]).map(formatOption), + } as SessionConfigOption; + }); +}