From 51f610f3a5e424a43afe41d4e21576070b6fac51 Mon Sep 17 00:00:00 2001 From: Joseph Magly <1159087+jmagly@users.noreply.github.com> Date: Wed, 15 Jul 2026 19:09:34 -0400 Subject: [PATCH] fix(local-agents): support current Codex exec CLI (#95) --- src/agent/local-agents.ts | 14 ++++++++++++-- src/server.ts | 10 ++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/agent/local-agents.ts b/src/agent/local-agents.ts index f6de5ec..fed5c4c 100644 --- a/src/agent/local-agents.ts +++ b/src/agent/local-agents.ts @@ -126,7 +126,17 @@ const SPECS: AgentSpec[] = [ versionArgs: ['--version'], parseVersion: (o) => (o.match(/[\d]+\.[\d]+(\.[\d]+)?/) || ['?'])[0], authArtifacts: ['~/.codex/auth.json', '~/.config/codex/auth.json'], - oneShot: (p, m) => ['exec', ...(m ? ['-m', m] : []), p], + oneShot: (p, m) => [ + 'exec', + '--ephemeral', + '--skip-git-repo-check', + '--sandbox', + 'read-only', + '--color', + 'never', + ...(m ? ['-m', m] : []), + p, + ], }, { id: 'hermes', @@ -322,7 +332,7 @@ export function localAgentChat(id: string, prompt: string, opts: { model?: strin } else if (id === 'codex') { workDir = mkdtempSync(join(tmpdir(), 't3mp3st-codexllm-')); outFile = join(workDir, 'reply.txt'); - args = ['exec', '--skip-git-repo-check', '--color', 'never', '--sandbox', 'read-only', '--output-last-message', outFile, ...(model ? ['-m', model] : [])]; + args = ['exec', '--ephemeral', '--skip-git-repo-check', '--color', 'never', '--sandbox', 'read-only', '--output-last-message', outFile, ...(model ? ['-m', model] : [])]; } else { // hermes — takes the prompt as an arg args = ['-z', prompt, ...(hermesYoloEnabled() ? ['--yolo'] : []), ...(model ? ['-m', model] : [])]; viaStdin = false; diff --git a/src/server.ts b/src/server.ts index 3343e44..362377d 100755 --- a/src/server.ts +++ b/src/server.ts @@ -6654,8 +6654,6 @@ function bringUpMissionFromPlan( async function runCodexExecReadinessProbe(command: string): Promise<{ stdout: string; stderr: string }> { const marker = 'T3MP3ST_CODEX_READY'; const args = [ - '--ask-for-approval', - 'never', 'exec', '-c', 'model_reasoning_effort="low"', @@ -6681,7 +6679,7 @@ async function runCodexExecReadinessProbe(command: string): Promise<{ stdout: st const timer = setTimeout(() => { child.kill('SIGTERM'); reject(new Error('Codex exec readiness probe timed out')); - }, 30000); + }, 60000); // Bounded accumulation so a runaway/verbose child can't grow these strings without limit // before the 30s timer fires (matches the local-agent caps). A normal probe emits a tiny @@ -6733,7 +6731,7 @@ app.get('/api/codex/status', async (_req: Request, res: Response): Promise tokenHandling: 'no token is accepted by or returned from T3MP3ST', command, version: stdout.trim(), - executionMode: 'codex exec --ephemeral --sandbox read-only --ask-for-approval never', + executionMode: 'codex exec --ephemeral --sandbox read-only', execProbe: 'POST /api/codex/probe', // exec self-test moved off GET (B-04) }); } catch (error: any) { @@ -6753,7 +6751,7 @@ app.post('/api/codex/probe', async (_req: Request, res: Response): Promise provider: 'codex', command, version: stdout.trim(), - executionMode: 'codex exec --ephemeral --sandbox read-only --ask-for-approval never', + executionMode: 'codex exec --ephemeral --sandbox read-only', }; try { const probe = await runCodexExecReadinessProbe(command); @@ -7472,7 +7470,7 @@ type ConnectedLocalAgent = { }; const connectedLocalAgents = new Map(); const LOCAL_AGENT_HEALTH_TTL_MS = 30_000; -const LOCAL_AGENT_HEALTH_TIMEOUT_MS = 15_000; +const LOCAL_AGENT_HEALTH_TIMEOUT_MS = 45_000; async function refreshConnectedLocalAgentHealth(force = false): Promise { const now = Date.now();