From 3154fb208469e17ce917abde0d25512dee771cd6 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Thu, 25 Dec 2025 11:25:42 +0700 Subject: [PATCH] Fix codex-mcp typecheck config typing --- .../server/agent/providers/codex-mcp-agent.ts | 67 +++++++++++++++---- plan.md | 15 ++++- 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/packages/server/src/server/agent/providers/codex-mcp-agent.ts b/packages/server/src/server/agent/providers/codex-mcp-agent.ts index cc1ff2dc6..73a3d0ed9 100644 --- a/packages/server/src/server/agent/providers/codex-mcp-agent.ts +++ b/packages/server/src/server/agent/providers/codex-mcp-agent.ts @@ -60,7 +60,7 @@ type PatchFileChange = { type CodexToolArguments = { [key: string]: unknown }; const DEFAULT_TIMEOUT_MS = 14 * 24 * 60 * 60 * 1000; -const CODEX_PROVIDER: AgentClient["provider"] = "codex-mcp"; +const CODEX_PROVIDER = "codex-mcp" as const; const CODEX_MCP_CAPABILITIES: AgentCapabilityFlags = { supportsStreaming: true, @@ -177,6 +177,35 @@ function resolveExclusiveString( return trimmed; } +function resolvePreferredString( + ctx: z.RefinementCtx, + entries: Array<{ key: string; value: string | undefined }>, + label: string, + required = false +): string | undefined { + for (const entry of entries) { + if (entry.value === undefined) { + continue; + } + const trimmed = entry.value.trim(); + if (!trimmed) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `${label} cannot be empty`, + }); + return undefined; + } + return trimmed; + } + if (required) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `${label} missing`, + }); + } + return undefined; +} + const CommandSchema = z.union([ z.string().min(1), z.array(z.string().min(1)).nonempty(), @@ -345,8 +374,6 @@ const PatchChangeDetailsSchema = PatchChangeDetailsBaseSchema.transform((data, c return normalized; }); -type PatchChangeDetails = z.infer; - const PatchChangeEntrySchema = PatchChangeDetailsBaseSchema.extend({ path: z.string().min(1), }).transform((data, ctx) => { @@ -1447,7 +1474,7 @@ const PermissionParamsSchema = z }) .passthrough() .transform((data, ctx) => { - const callId = resolveExclusiveString( + const callId = resolvePreferredString( ctx, [ { key: "codex_call_id", value: data.codex_call_id }, @@ -1497,6 +1524,18 @@ const PermissionParamsSchema = z type PermissionParams = z.infer; +const AgentControlMcpConfigSchema = z.object({ + url: z.string(), + headers: z.record(z.string()).optional(), +}); + +type AgentSessionExtra = NonNullable; + +const AgentSessionExtraSchema = z.object({ + codex: z.record(z.unknown()).optional(), + claude: z.custom().optional(), +}); + const AgentSessionConfigSchema = z .object({ provider: z.string(), @@ -1509,14 +1548,9 @@ const AgentSessionConfigSchema = z networkAccess: z.boolean().optional(), webSearch: z.boolean().optional(), reasoningEffort: z.string().optional(), - agentControlMcp: z.unknown().optional(), - extra: z - .object({ - codex: z.unknown().optional(), - claude: z.unknown().optional(), - }) - .optional(), - mcpServers: z.unknown().optional(), + agentControlMcp: AgentControlMcpConfigSchema.optional(), + extra: AgentSessionExtraSchema.optional(), + mcpServers: z.record(z.unknown()).optional(), parentAgentId: z.string().optional(), }) .passthrough(); @@ -1663,7 +1697,14 @@ function buildCodexMcpConfig( config.sandboxMode !== undefined ? config.sandboxMode : preset.sandbox; const extra = config.extra ? config.extra.codex : undefined; - const configPayload = { + const configPayload: { + prompt: string; + cwd?: string; + "approval-policy": string; + sandbox: string; + config?: unknown; + model?: string; + } = { prompt, cwd: config.cwd, "approval-policy": approvalPolicy, diff --git a/plan.md b/plan.md index 2935bf5c3..9747d6124 100644 --- a/plan.md +++ b/plan.md @@ -587,10 +587,21 @@ Build a new Codex MCP provider side‑by‑side with the existing Codex SDK prov - Do not refactor deprecated code - These tests may fail/skip - that's expected for deprecated code -- [ ] **Fix**: Investigate MCP JSONRPC error during tests: `permission call_id provided multiple times (codex_call_id, codex_mcp_tool_call_id, codex_event_id)` (codex_mcp_server error logged during `npm run test --workspace=@paseo/server`). +- [x] **Fix**: Investigate MCP JSONRPC error during tests: `permission call_id provided multiple times (codex_call_id, codex_mcp_tool_call_id, codex_event_id)` (codex_mcp_server error logged during `npm run test --workspace=@paseo/server`). + - **Done (2025-12-25 11:22)**: WHAT: added `resolvePreferredString` to prefer canonical permission call ids and updated permission parsing to use it in `packages/server/src/server/agent/providers/codex-mcp-agent.ts:180` and `packages/server/src/server/agent/providers/codex-mcp-agent.ts:1479`; documented the Codex MCP elicitation payload and resolution in `REPORT-mcp-jsonrpc-permission-callid.md:1`. RESULT: permission elicitation no longer errors on multi-field call ids from Codex MCP; permission test completes without the JSONRPC error. EVIDENCE: `npm run test --workspace=@paseo/server -- codex-mcp-agent.test.ts -t "requests permission"` (1 passed, 12 skipped due to `-t`). -- [ ] **Fix**: Resolve typecheck errors in `packages/server/src/server/agent/providers/codex-mcp-agent.ts:348`, `packages/server/src/server/agent/providers/codex-mcp-agent.ts:1674`, `packages/server/src/server/agent/providers/codex-mcp-agent.ts:2945`, `packages/server/src/server/agent/providers/codex-mcp-agent.ts:2959`, `packages/server/src/server/agent/providers/codex-mcp-agent.ts:2970`. +- [x] **Fix**: Resolve typecheck errors in `packages/server/src/server/agent/providers/codex-mcp-agent.ts:348`, `packages/server/src/server/agent/providers/codex-mcp-agent.ts:1674`, `packages/server/src/server/agent/providers/codex-mcp-agent.ts:2945`, `packages/server/src/server/agent/providers/codex-mcp-agent.ts:2959`, `packages/server/src/server/agent/providers/codex-mcp-agent.ts:2970`. + - **Done (2025-12-25 11:25)**: WHAT: removed unused PatchChangeDetails alias, typed `CODEX_PROVIDER` as a literal, added typed session metadata schemas, and made config payload accept optional model in `packages/server/src/server/agent/providers/codex-mcp-agent.ts:63`, `packages/server/src/server/agent/providers/codex-mcp-agent.ts:1527`, `packages/server/src/server/agent/providers/codex-mcp-agent.ts:1700`. RESULT: codex-mcp provider typecheck errors at the listed lines are resolved; remaining typecheck failures are outside this file. EVIDENCE: `npm run typecheck --workspace=@paseo/server` (only `agent-projections.ts` and `claude-agent.ts` errors reported). - [ ] **Test (E2E)**: Rerun full server tests after fixes and verify zero failures/skips. - [ ] **Typecheck**: Rerun `npm run typecheck --workspace=@paseo/server` after fixes and verify zero errors. + +- [ ] **Wire up**: Replace old Codex SDK provider with Codex MCP provider. + + - Change the `"codex"` provider ID to use `codex-mcp-agent.ts` instead of `codex-agent.ts` + - Find where providers are registered/loaded (likely `agent-manager.ts` or similar) + - Update the provider mapping so `provider: "codex"` creates a `CodexMcpAgentClient` + - Keep `"codex-mcp"` as an alias if needed for backwards compatibility + - Remove or deprecate the old `codex-agent.ts` import + - This allows testing the new MCP provider in the app with the existing "codex" provider name