From 8761431eb3f2df7f9d97881b86dc03a3a3b343c7 Mon Sep 17 00:00:00 2001 From: Axel Delafosse Date: Wed, 25 Feb 2026 15:03:45 -0800 Subject: [PATCH] feat: unify agent turn timeout and fix codex render boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract AGENT_TURN_TIMEOUT_MS (≈11.7h) into constants.ts as single source of truth - Replace per-file WAIT_TIMEOUT_MS / DEFAULT_WAIT_TIMEOUT_MS with shared constant - Fix codex renderer skipping message boundary when completed event matches active delta stream --- src/loop/claude-sdk-server.ts | 7 +++---- src/loop/codex-app-server.ts | 6 +++--- src/loop/codex-render.ts | 7 ++++++- src/loop/constants.ts | 1 + 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/loop/claude-sdk-server.ts b/src/loop/claude-sdk-server.ts index 28cfb79..e2242fc 100644 --- a/src/loop/claude-sdk-server.ts +++ b/src/loop/claude-sdk-server.ts @@ -5,7 +5,7 @@ import { spawn, spawnSync, } from "bun"; -import { DEFAULT_CLAUDE_MODEL } from "./constants"; +import { AGENT_TURN_TIMEOUT_MS, DEFAULT_CLAUDE_MODEL } from "./constants"; import { findFreePort } from "./ports"; import { DETACH_CHILD_PROCESS, killChildProcess } from "./process"; import type { Options, RunResult } from "./types"; @@ -65,10 +65,9 @@ const BACKGROUND_TASK_CONTINUATION = "Background tasks are complete. Continue with the task."; const DEFAULT_CHILD_POLL_INTERVAL_MS = 2000; const START_TIMEOUT_MS = 60_000; -const DEFAULT_WAIT_TIMEOUT_MS = 600_000; let childPollIntervalMs = DEFAULT_CHILD_POLL_INTERVAL_MS; -let waitTimeoutMs = DEFAULT_WAIT_TIMEOUT_MS; +let waitTimeoutMs = AGENT_TURN_TIMEOUT_MS; type CountChildProcessesFn = (pid: number) => number; @@ -193,7 +192,7 @@ export const claudeSdkInternals = { childPollIntervalMs = next; }, restoreWaitTimeoutMs(): void { - waitTimeoutMs = DEFAULT_WAIT_TIMEOUT_MS; + waitTimeoutMs = AGENT_TURN_TIMEOUT_MS; }, setWaitTimeoutMs(next: number): void { waitTimeoutMs = next; diff --git a/src/loop/codex-app-server.ts b/src/loop/codex-app-server.ts index 2644805..43f36b9 100644 --- a/src/loop/codex-app-server.ts +++ b/src/loop/codex-app-server.ts @@ -1,4 +1,5 @@ import { spawn } from "bun"; +import { AGENT_TURN_TIMEOUT_MS } from "./constants"; import { findFreePort } from "./ports"; import { DETACH_CHILD_PROCESS, killChildProcess } from "./process"; import type { Options, RunResult } from "./types"; @@ -42,7 +43,6 @@ const APP_SERVER_PORT_RANGE = 100; const WS_CONNECT_ATTEMPTS = 40; const WS_CONNECT_DELAY_MS = 150; const USER_INPUT_TEXT_ELEMENTS = "text_elements"; -const WAIT_TIMEOUT_MS = 600_000; const NOOP_CALLBACK: Callback = () => undefined; export const CODEX_TRANSPORT_APP_SERVER: TransportMode = "app-server"; @@ -460,7 +460,7 @@ class AppServerClient { if (this.turns.delete(turnId)) { state.reject(new Error(`codex app-server turn ${turnId} timed out`)); } - }, WAIT_TIMEOUT_MS); + }, AGENT_TURN_TIMEOUT_MS); const clear = () => clearTimeout(timeout); state.resolve = (result) => { clear(); @@ -824,7 +824,7 @@ class AppServerClient { const timeout = setTimeout(() => { this.pending.delete(requestId); reject(new Error(`codex app-server request "${method}" timed out`)); - }, WAIT_TIMEOUT_MS); + }, AGENT_TURN_TIMEOUT_MS); this.pending.set(requestId, { method, resolve, reject, timeout }); }); } diff --git a/src/loop/codex-render.ts b/src/loop/codex-render.ts index f946b03..0b616f0 100644 --- a/src/loop/codex-render.ts +++ b/src/loop/codex-render.ts @@ -181,7 +181,12 @@ const handleCompletedLine = ( state.lastCompleted = candidate; appendChunk(state, format, write, candidate); } - markMessageBoundary(state); + // Skip boundary when this completed event matches the item already streamed + // via deltas. The delta handler detects item changes and sets boundaries when + // a genuinely new item arrives, preventing spurious line breaks mid-stream. + if (!(sameActive && state.activeItemHasDelta)) { + markMessageBoundary(state); + } }; export const createCodexRenderer = ( diff --git a/src/loop/constants.ts b/src/loop/constants.ts index 2ada431..fed5379 100644 --- a/src/loop/constants.ts +++ b/src/loop/constants.ts @@ -38,6 +38,7 @@ Auto-update: export const REVIEW_PASS = "PASS"; export const REVIEW_FAIL = "FAIL"; +export const AGENT_TURN_TIMEOUT_MS = 42_000_069; export const NEWLINE_RE = /\r?\n/; export const VALUE_FLAGS: Record = {