Add AgentWatch tool handling for Codex long-running jobs#1088

closed2
main
GitHub fork: Code/agentwatch-core
openedMar 14, 2026byAAliAlharmoodi
View on GitHubTwo-way sync enabledPR last imported 18d ago

Summary

  • add a small server-side AgentWatch runtime for monitored long-running shell jobs
  • route Codex item/tool/call requests for agentwatch.start|status|poll|tail through CodexAppServerManager
  • add focused regression tests for the AgentWatch runtime and tool-call routing

Why

This is a small reliability-oriented slice that lets Codex hand off long-running commands to a monitored background job instead of keeping everything tied to a single turn.

Scope

This PR intentionally avoids the later UI and orchestration follow-up work. It only adds the core runtime and Codex server plumbing.

Validation

  • bun fmt
  • bun lint
  • bun typecheck

Note

Add AgentWatch tool handling for Codex long-running jobs

  • Introduces AgentWatch, a job supervisor that starts detached shell commands via bash -lc, tracks liveness and output staleness, and captures exit codes by appending a sentinel marker to the job's log file.
  • Exposes agentwatch.start, agentwatch.status, agentwatch.poll, and agentwatch.tail tools via a handleToolCall interface.
  • Integrates AgentWatch into CodexAppServerManager, routing item/tool/call JSON-RPC requests to agentWatch.handleToolCall and disposing the instance on stopAll().
  • Behavioral Change: handleServerRequest now handles a new item/tool/call method, returning -32602 for missing tool name and -32000 for tool invocation failures.
๐Ÿ“Š Macroscope summarized 664fb01. 4 files reviewed, 4 issues evaluated, 0 issues filtered, 2 comments posted

๐Ÿ—‚๏ธ Filtered Issues

Added 2 commits

  • Fix AgentWatch core typecheck regressions664fb01
  • Add AgentWatch tool handling for Codex long-running jobsa66c99b
Synced from GitHub

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

โš™๏ธ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6cdb4791-bc75-4dc9-ade6-f824196ba71c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ๐Ÿ” Trigger review
โœจ Finishing Touches
๐Ÿงช Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
๐Ÿ“ Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

โค๏ธ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can make CodeRabbit's review stricter and more nitpicky using the `assertive` profile, if that's what you prefer.

Change the reviews.profile setting to assertive to make CodeRabbit's nitpick more issues in your PRs.

apps/server/src/agentWatch.tslines 56โ€“63Open thread
โ€ฆโ€ฆ@@ -0,0 +1,320 @@
60+ } catch {
61+ return false;
62+ }
63+}
MmacroscopeappBoton lines 56โ€“63Mar 14, 2026

๐ŸŸ  High src/agentWatch.ts:56

When job.pid is -1 (set on line 149 when child.pid is undefined after spawn), calling process.kill(-1, 0) does not check if a specific process is alive. On POSIX systems, kill(-1, sig) broadcasts the signal to all processes the caller can signal, so isProcessAlive(-1) returns true even though no actual job process exists. The function should return false when pid <= 0.

diff
1+function isProcessAlive(pid: number): boolean {
2+ if (pid <= 0) {
3+ return false;
4+ }
5+ try {
6+ process.kill(pid, 0);
7+ return true;
8+ } catch {
9+ return false;
10+ }
11+}
๐Ÿš€ Reply "fix it for me" or copy this AI Prompt for your agent:
text
1In file apps/server/src/agentWatch.ts around lines 56-63:
2
3When `job.pid` is `-1` (set on line 149 when `child.pid` is undefined after spawn), calling `process.kill(-1, 0)` does not check if a specific process is alive. On POSIX systems, `kill(-1, sig)` broadcasts the signal to all processes the caller can signal, so `isProcessAlive(-1)` returns `true` even though no actual job process exists. The function should return `false` when `pid <= 0`.
4
5Evidence trail:
61. `apps/server/src/agentWatch.ts` lines 56-62: `isProcessAlive` function uses `process.kill(pid, 0)`
72. `apps/server/src/agentWatch.ts` line 149: `pid: child.pid ?? -1` sets pid to -1 if child.pid is undefined
83. `apps/server/src/agentWatch.ts` line 221: `if (!isProcessAlive(job.pid))` uses the function to detect finished jobs
94. Node.js documentation (https://nodejs.org/docs/latest-v22.x/api/process.html): `process.kill()` follows OS semantics, so `kill(-1, sig)` on POSIX sends to all processes caller can signal
105. POSIX `kill(2)` specification: pid=-1 means 'all processes for which the calling process has permission to send signals'
โ€ฆโ€ฆ@@ -1216,6 +1219,44 @@ export class CodexAppServerManager extends EventEmitter<CodexAppServerManagerEve
12161219 });
12171220 }
12181221
1222+ if (request.method === "item/tool/call") {
MmacroscopeappBoton line 1222Mar 14, 2026

๐Ÿ”ด Critical src/codexAppServerManager.ts:1222

item/tool/call requests with non-agentwatch. tool names are routed to this.agentWatch.handleToolCall(), which throws Unsupported tool: ${toolName} and returns a JSON-RPC error to the client. This breaks all non-agentwatch tool calls instead of letting them fall through to the existing handling logic. Consider checking toolName.startsWith("agentwatch.") before routing to the agentWatch handler.

๐Ÿš€ Reply "fix it for me" or copy this AI Prompt for your agent:
text
1In file apps/server/src/codexAppServerManager.ts around line 1222:
2
3`item/tool/call` requests with non-`agentwatch.` tool names are routed to `this.agentWatch.handleToolCall()`, which throws `Unsupported tool: ${toolName}` and returns a JSON-RPC error to the client. This breaks all non-agentwatch tool calls instead of letting them fall through to the existing handling logic. Consider checking `toolName.startsWith("agentwatch.")` before routing to the agentWatch handler.
4
5Evidence trail:
6apps/server/src/codexAppServerManager.ts lines 1222-1256 at REVIEWED_COMMIT: Shows `item/tool/call` handler routing ALL tool calls to `this.agentWatch.handleToolCall(toolName, rawArgs)` without checking if toolName starts with "agentwatch."
7
8apps/server/src/agentWatch.ts lines 283-321 at REVIEWED_COMMIT: Shows `handleToolCall` only handles `agentwatch.start`, `agentwatch.status`, `agentwatch.poll`, `agentwatch.tail` - all other tool names cause `throw new Error(\`Unsupported tool: ${toolName}\`);`

Closing because this introduces speculative custom AgentWatch runtime infrastructure, all touched paths are gone, and correctness checks failed.

This was closed as part of a large repo-wide maintenance sweep. If you think it's still relevant, please reopen.