From 9a92124c63c1bf42bf6db58d91a154488435a460 Mon Sep 17 00:00:00 2001 From: Dotta <34892728+cryppadotta@users.noreply.github.com> Date: Thu, 16 Jul 2026 11:41:29 -0500 Subject: [PATCH] fix(codex-local): raise default output-inactivity timeout to 30m (#9699) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Thinking Path > - Paperclip is the open source control plane for managing AI-agent companies. > - Agent adapters are responsible for launching, observing, and terminating provider processes safely. > - The local Codex adapter uses an output-inactivity monitor to stop genuinely hung child processes. > - The existing seven-minute default also stopped legitimate long-running tasks that emitted no output while tests or remote checks were still running. > - Explicit per-agent timeout overrides already provide configuration flexibility, so the smallest safe correction is to increase only the default window. > - This pull request raises the default to 30 minutes, retains the existing termination behavior, and adds a regression assertion for the new value. > - The benefit is fewer unnecessary Codex restarts while still bounding genuinely silent processes well below the platform safety limit. ## Linked Issues or Issue Description **Pre-submission checklist** - Searched open and closed GitHub issues and pull requests; no duplicate fix exists. The original inactivity monitor was introduced in #5017. - Reproduces on the current `master` implementation. - The termination originates in Paperclip's Codex adapter inactivity monitor rather than the model provider or local configuration. **What happened?** Long-running `codex_local` tasks were terminated after seven minutes without stdout or stderr, even when the child process was still performing legitimate work such as a quiet test suite or waiting for remote checks. **Expected behavior** The default inactivity window should tolerate common long-running quiet tasks while continuing to terminate processes that remain silent for an extended period. **Steps to reproduce** 1. Start a `codex_local` run with the default `outputInactivityTimeoutMs` configuration. 2. Have the child process perform legitimate work without emitting stdout or stderr for more than seven minutes. 3. Observe the adapter terminate the process at the old default threshold. **Version / deployment** Current `master`, built from source in local/self-hosted deployments, using the Codex adapter. This behavior is not database- or access-context-specific. ## What Changed - Raise `DEFAULT_CODEX_OUTPUT_INACTIVITY_TIMEOUT_MS` from seven minutes to 30 minutes. - Update the adapter configuration documentation to state the new default. - Add a focused regression assertion that pins the default to 30 minutes. ## Verification - `pnpm vitest run packages/adapters/codex-local/src/server/output-inactivity-monitor.test.ts` — 15 tests passed. - `pnpm --filter @paperclipai/adapter-codex-local typecheck` — passed. ## Risks - Low risk: only the fallback default changes; explicit positive timeout values and `null` disablement retain their existing behavior. - A genuinely silent Codex process now remains alive up to 23 minutes longer before the same SIGTERM/SIGKILL cleanup path runs. - No schema, API, migration, UI, or workflow changes are included. > This is a focused bug fix and does not overlap with planned core feature work in `ROADMAP.md`. ## Model Used - Anthropic Claude Fable 5 via the `claude_local` adapter produced the initial investigation and implementation with repository/tool access. - OpenAI Codex via the Codex CLI prepared the PR, added the focused regression assertion, and ran verification; the runtime did not expose a more specific model ID or context-window value. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [ ] I have used a public-friendly branch name without internal tracker identifiers (execution-workspace exception: this branch is runtime-managed and cannot be renamed) - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge The source branch is execution-workspace managed and cannot be renamed during this run; the PR title and body intentionally contain no internal tracker references. Co-authored-by: Paperclip --- packages/adapters/codex-local/src/index.ts | 2 +- .../src/server/output-inactivity-monitor.test.ts | 4 ++++ .../codex-local/src/server/output-inactivity-monitor.ts | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/adapters/codex-local/src/index.ts b/packages/adapters/codex-local/src/index.ts index 8b25aa5343..77db7a8af2 100644 --- a/packages/adapters/codex-local/src/index.ts +++ b/packages/adapters/codex-local/src/index.ts @@ -95,7 +95,7 @@ Core fields: Operational fields: - timeoutSec (number, optional): run timeout in seconds - graceSec (number, optional): SIGTERM grace period in seconds -- outputInactivityTimeoutMs (number | null, optional): inactivity monitor around the codex child. Resets whenever the child emits stdout or stderr bytes, including non-JSON progress from long-running verification commands. Defaults to 7 * 60_000 ms when unset or non-positive. Set to \`null\` to disable the monitor entirely (only do this for known-slow tasks; the platform-level 1h silent-run safety net still applies). On fire, the adapter sends SIGTERM to the process group, waits 5s, then SIGKILL, and surfaces the run as failed with errorMessage "monitor: no codex output for {N}m {S}s". +- outputInactivityTimeoutMs (number | null, optional): inactivity monitor around the codex child. Resets whenever the child emits stdout or stderr bytes, including non-JSON progress from long-running verification commands. Defaults to 30 * 60_000 ms when unset or non-positive. Set to \`null\` to disable the monitor entirely (only do this for known-slow tasks; the platform-level 1h silent-run safety net still applies). On fire, the adapter sends SIGTERM to the process group, waits 5s, then SIGKILL, and surfaces the run as failed with errorMessage "monitor: no codex output for {N}m {S}s". - agentCommand (string, optional): ACP server command override used only when engine="acp"; defaults to the package-local codex-acp binary - mode (string, optional): ACP session mode when engine="acp"; persistent or oneshot - nonInteractivePermissions (string, optional): ACP non-interactive permission fallback when engine="acp"; deny or fail diff --git a/packages/adapters/codex-local/src/server/output-inactivity-monitor.test.ts b/packages/adapters/codex-local/src/server/output-inactivity-monitor.test.ts index 71c25df94e..5bf64ad901 100644 --- a/packages/adapters/codex-local/src/server/output-inactivity-monitor.test.ts +++ b/packages/adapters/codex-local/src/server/output-inactivity-monitor.test.ts @@ -51,6 +51,10 @@ class FakeClock { } describe("resolveCodexInactivityTimeout", () => { + it("defaults to 30 minutes", () => { + expect(DEFAULT_CODEX_OUTPUT_INACTIVITY_TIMEOUT_MS).toBe(30 * 60 * 1000); + }); + it("uses default when value is unset", () => { expect(resolveCodexInactivityTimeout(undefined)).toEqual({ mode: "default", diff --git a/packages/adapters/codex-local/src/server/output-inactivity-monitor.ts b/packages/adapters/codex-local/src/server/output-inactivity-monitor.ts index 814e06d94d..e1e0ca2f2f 100644 --- a/packages/adapters/codex-local/src/server/output-inactivity-monitor.ts +++ b/packages/adapters/codex-local/src/server/output-inactivity-monitor.ts @@ -1,6 +1,6 @@ import { parseJson } from "@paperclipai/adapter-utils/server-utils"; -export const DEFAULT_CODEX_OUTPUT_INACTIVITY_TIMEOUT_MS = 7 * 60 * 1000; +export const DEFAULT_CODEX_OUTPUT_INACTIVITY_TIMEOUT_MS = 30 * 60 * 1000; export const CODEX_OUTPUT_INACTIVITY_MONITOR_SIGTERM_GRACE_MS = 5_000; export type CodexOutputInactivityMonitorResolution = @@ -13,9 +13,9 @@ export type CodexOutputInactivityMonitorResolution = * Resolve the inactivity monitor timeout from raw adapter config. * * - `null` → disabled (explicit escape hatch). - * - missing/`undefined` → default 7m. + * - missing/`undefined` → default 30m. * - number > 0 → configured value. - * - number ≤ 0 → default 7m (and a `non_positive` note for logging). + * - number ≤ 0 → default 30m (and a `non_positive` note for logging). */ export function resolveCodexInactivityTimeout(rawValue: unknown): CodexOutputInactivityMonitorResolution { if (rawValue === null) return { mode: "disabled", reason: "explicit_null" };