fix(maestro-p): finalize interactive plan-mode turns on ExitPlanMode#1118
Conversation
Interactive Token Source routes the agent turn through maestro-p, which drives the Claude TUI. In read-only/plan mode (`--permission-mode plan`) the model ends its turn by calling ExitPlanMode, which parks the TUI on a blocking "Ready to code?" approval dialog that maestro-p has no human to answer. The model never emits `stop_reason: end_turn`, so the runner's only completion signal never arrives and the idle watchdog kills the turn at --max-wait with exitCode 3 / `response: undefined`, discarding the plan it had already captured. Treat an ExitPlanMode tool call as a terminal completion: fold the plan body (carried in the tool_use input, not a text block) into the result and finalize successfully, mirroring `claude --print --permission-mode plan`. Closes #1117
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds a new ChangesPlan-mode ExitPlanMode detection and early finalization
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryFixes a hang-then-timeout on every interactive plan-mode turn:
Confidence Score: 4/5Safe to merge; the change is well-scoped and only affects the interactive plan-mode path. The fix is narrow, well-scoped to the interactive plan-mode path, and backed by comprehensive tests. The single concern is a substring deduplication check that could silently drop the plan body in a contrived edge case. The deduplication guard on line 467 of src/maestro-p/index.ts is the only place that warrants a second look. Important Files Changed
Reviews (1): Last reviewed commit: "fix(maestro-p): finalize interactive pla..." | Re-trigger Greptile |
| if (planText && !aggregatedText.includes(planText)) { | ||
| aggregatedText += (aggregatedText ? '\n\n' : '') + planText; | ||
| } |
There was a problem hiding this comment.
Substring deduplication can silently drop the plan body
aggregatedText.includes(planText) is a substring match against all text accumulated earlier in the turn. If the model previously wrote any text that happens to contain planText as a literal substring (e.g. the same phrasing appears in a prior reasoning block), the guard evaluates to true and the plan is never appended - the user receives only the pre-ExitPlanMode text. Because collectAssistantText only collects text-type blocks and the plan lives in tool_use.input.plan, this overlap is unlikely today, but it's a silent correctness trap. A boolean flag (planTextAppended) would be more reliable.
Closes #1117
Problem
With Token Source = Interactive, Maestro routes the agent turn through
maestro-p, which drives the Claude TUI (instead ofclaude --print). When the agent is in read-only / plan mode, Maestro forwards--permission-mode planto the TUI.In plan mode, the model ends its turn by calling the
ExitPlanModetool, which parks the TUI on a blocking "Ready to code? 1. Yes / 2. No, keep planning" approval dialog.maestro-pis a headless driver with no human to answer it, so the model never emits astop_reason: end_turnassistant message.maestro-p's run loop only finalizes a turn onend_turn, so that completion signal never arrives. The idle watchdog then kills the turn after--max-wait(~302s) witherror: timeout/ exitCode 3, and because that is an error path it drops the assistant text it had already captured, surfacing to the user asresponse: undefined. This matches the report in #1117 exactly (the plan/answer was generated, e.g. the tab-namer captured "Texas", but the main agent path returned nothing).The headless
claude --print --permission-mode planpath is unaffected because print mode emits the plan and exits with no interactive dialog.Fix
Treat an
ExitPlanModetool call as a terminal completion for the turn:extractExitPlanText(message)(src/maestro-p/plan-mode.ts) detects anExitPlanModetool_use block and returns its plan body (carried in the tool_useinput.plan, not in atextblock).src/maestro-p/index.ts), when an assistant message callsExitPlanMode, fold the plan body into the aggregated result andfinalize()with exitCode 0, mirroring the semantics ofclaude --print --permission-mode plan(the plan is the deliverable for a read-only turn).Tests
Added
src/__tests__/maestro-p/plan-mode.test.ts(7 cases: plan extracted, missing/non-string plan body, normalend_turn, non-ExitPlanMode tool_use, block-position independence, malformed input). Fullmaestro-psuite passes (224 tests).Notes
--print/ API path or to normalend_turnturns.Summary by CodeRabbit
New Features
Tests