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 = {