Skip to content

refactor(fb15c): split SubagentRunner into modules - #171

Merged
dirac-run merged 6 commits into
dirac-run:masterfrom
alexdim:fix/fb15c-subagent-split
Aug 13, 2026
Merged

refactor(fb15c): split SubagentRunner into modules#171
dirac-run merged 6 commits into
dirac-run:masterfrom
alexdim:fix/fb15c-subagent-split

Conversation

@alexdim

@alexdim alexdim commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Split the 1033-line SubagentRunner.ts into focused modules under src/core/task/tools/subagent/:

  • SubagentRunTypes.ts — run status/result/progress/tool-call types
  • SubagentRunHelpers.ts — pure functions (tool-call parsing, result blocks, best-effort result)
  • SubagentRunState.ts — phase/liveness/heartbeat tracking
  • SubagentRunProgress.ts — progress queue/drain + recorder flush
    SubagentRunner.ts becomes the orchestration adapter.

Why

FIX-BACKLOG FB-15c — single responsibility: runner keeps orchestration; state, progress, types, and pure helpers are separate units.

Review follow-ups

1. Flush blocking terminal completion

Reviewer flagged await this.runProgress.flush() in the finally block: it changed recorder flushing from fire-and-forget to part of the awaited run lifecycle, so a slow or stuck filesystem append could delay terminal completion.

Fix: restored the pre-split fire-and-forget behavior — void this.runProgress.flush() instead of await. Errors are still handled internally by SubagentRunProgress.flush() (try/catch → reportRecorderFailure).

Regression test: does not block terminal completion on a slow recorder flush — stubs recorder.flush() to hang forever; asserts run() still resolves with COMPLETED and that flush() was called.

2. Terminal phase stuck on "cancelling"

Reviewer flagged that recordTerminal was missing the enterPhase call after extraction. On timeout/parent-cancel, the terminal progress reported status: cancelled while phase remained cancelling.

Fix: restored this.enterPhase(this.phaseForStatus(result.status), "subagent run settled", { status: result.status }) before runProgress.recordTerminal() in SubagentRunner.recordTerminal().

Regression test: reports cancelled phase on parent cancel, not cancelling — triggers parent abort, collects progress updates, asserts every cancelled-status update has phase: "cancelled".

Notes / Caveats

  • Rebased onto current master.
  • Pre-existing subagent drain-timeout test failure is unrelated and untouched.
  • Pre-existing AgentConfigLoader EPERM on TCC-protected ~/Documents/Dirac is environment-specific (machine has no Full Disk Access); not from this PR.

Verification

  • tsc -p tsconfig.unit-test.json --noEmit — only pre-existing src/shared/storage/types.ts baseline error.
  • biome check on touched files — 1 pre-existing warning (not from these changes).
  • SubagentRunner.test.ts — new regression tests passing (2/2 targeted).
  • SubagentRunRecorder.test.ts — 4/4 passing.
  • SubagentBuilder.test.ts — 5/5 passing.

Closes FB-15c (FIX-BACKLOG).

@dirac-run dirac-run left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requested follow-up: await this.runProgress.flush() changes recorder flushing from fire-and-forget to part of the awaited run lifecycle. A slow or stuck filesystem append can now delay terminal completion, despite the PR being described as behavior-preserving. Please either preserve the previous non-blocking behavior or explicitly document and test the new completion contract, ideally with a bounded wait.

@alexdim
alexdim force-pushed the fix/fb15c-subagent-split branch from a7c4c7e to 52a0cba Compare August 12, 2026 16:33
@dirac-run

Copy link
Copy Markdown
Owner

Follow-up needed:

The recorder flush issue is fixed, but the extraction dropped the terminal phase transition from SubagentRunner.recordTerminal().

When timeout or parent cancellation wins Promise.race, the result is built directly without passing through instrumentedOnProgress. Terminal progress therefore reports status: cancelled while phase remains cancelling.

Please restore enterPhase(phaseForStatus(result.status), ...) before recording terminal state and add a regression test for the timeout/parent-cancellation path asserting a final cancelled phase.

devin-ai-integration Bot and others added 6 commits August 13, 2026 00:32
- Introduce SubagentRunTypes for shared run/result/progress/stats/tool types.
- Extract pure helpers into SubagentRunHelpers (usage state, stats, tool
  serialization, tool-call preview/normalization, best-effort result).
- Update SubagentToolExecutor and SubagentAbortHandler to import from the new
  modules and tighten any[]/any types.

Co-Authored-By: Alexandros Salapatas <alexsal.alex@gmail.com>
Move phase tracking, liveness, heartbeat, activity markers, runtime progress
snapshot and diagnostic details out of SubagentRunner into SubagentRunState.

Co-Authored-By: Alexandros Salapatas <alexsal.alex@gmail.com>
- Extract progress enqueueing, draining, terminal/flush/summary behavior into
  SubagentRunProgress.
- Convert SubagentRunner into a run-orchestration adapter that delegates status
  to SubagentRunState and progress to SubagentRunProgress.
- Re-export public types from ./SubagentRunTypes for backward compatibility.

Co-Authored-By: Alexandros Salapatas <alexsal.alex@gmail.com>
- shouldCompactBeforeNextRequest never read modelId

- remove stray blank line in import block
await flush() blocked terminal completion on slow
fs append. back to void flush() (pre-split behavior).
regression test: run() resolves with hung flush.
enterPhase(phaseForStatus(...)) was dropped when
recordTerminal moved to SubagentRunProgress.
on timeout/parent-cancel, phase stayed "cancelling"
instead of transitioning to "cancelled".
regression test asserts cancelled phase on cancel.
@alexdim
alexdim force-pushed the fix/fb15c-subagent-split branch from 52a0cba to 2937b59 Compare August 12, 2026 21:35
@dirac-run

Copy link
Copy Markdown
Owner

LGTM.

@dirac-run
dirac-run merged commit d602e3c into dirac-run:master Aug 13, 2026
@alexdim
alexdim deleted the fix/fb15c-subagent-split branch August 13, 2026 20:08
alexdim pushed a commit to alexdim/dirac that referenced this pull request Aug 23, 2026
refactor(fb15c): split SubagentRunner into modules
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants