Skip to content

[mirror] Upstream/pr1 on plan ready#1

Open
yashwant86 wants to merge 1 commit into
mm-base-181from
mm-pr-181
Open

[mirror] Upstream/pr1 on plan ready#1
yashwant86 wants to merge 1 commit into
mm-base-181from
mm-pr-181

Conversation

@yashwant86

@yashwant86 yashwant86 commented Apr 26, 2026

Copy link
Copy Markdown

Mirror of upstream open-multi-agent#181 (open PR live findings) for benchmark. Do not merge.


Summary by MergeMonkey

  • Enhancements:
    • Adds onPlanReady callback to allow approval of task plans before execution begins.

Adds an optional callback that fires after the coordinator decomposes
a goal into tasks but before execution begins.

  const orchestrator = new OpenMultiAgent({
    onPlanReady: async (tasks) => {
      displayPlan(tasks)
      return await confirm('Proceed?')
    },
  })

Returning false aborts the run immediately (returns success: false with
empty agentResults). Only fires for runTeam(); runAgent() and runTasks()
are unaffected.
@bot-mergemonkey

bot-mergemonkey Bot commented Apr 26, 2026

Copy link
Copy Markdown
Risk AssessmentNEEDS-TESTING · ~8 min review

Focus areas: onPlanReady callback invocation and error handling · Task list mutability and defensive copying · Early abort path consistency with metrics and token tracking

Assessment: Adds new callback hook to task execution flow with early abort path.

Walkthrough

When runTeam() decomposes a goal into tasks, the new onPlanReady callback is invoked with the task list. If the callback returns false, execution aborts and returns empty results. If true or undefined, execution proceeds normally.

Changes

Files Summary
Plan Ready Callback Integration
src/orchestrator/orchestrator.ts
src/types.ts
Introduces onPlanReady callback to OrchestratorConfig, enabling plan approval before task execution. Callback receives decomposed task list and can abort execution if approval denied.

Sequence Diagram

sequenceDiagram
  participant Caller
  participant OpenMultiAgent
  participant Coordinator
  participant onPlanReady
  participant TaskQueue
  Caller->>OpenMultiAgent: runTeam(goal)
  OpenMultiAgent->>Coordinator: decompose goal
  Coordinator->>TaskQueue: create tasks
  OpenMultiAgent->>onPlanReady: invoke with task list
  alt Callback returns false
    onPlanReady-->>OpenMultiAgent: false
    OpenMultiAgent-->>Caller: {success: false, empty results}
  else Callback returns true or undefined
    onPlanReady-->>OpenMultiAgent: true
    OpenMultiAgent->>TaskQueue: executeQueue
    TaskQueue-->>OpenMultiAgent: execution complete
    OpenMultiAgent-->>Caller: {success: true, results}
  end
Loading

Dig Deeper With Commands

  • /review <file-path> <function-optional>
  • /chat <file-path> "<question>"
  • /roast <file-path>

Runs only when explicitly triggered.

return {
success: false,
agentResults: new Map(),
totalTokenUsage: { input_tokens: 0, output_tokens: 0 },

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Plan-rejection path silently zeros out coordinator decomposition tokens

When onPlanReady returns false, runTeam returns hardcoded zero token usage and a fresh empty agentResults Map, but by that point the coordinator decomposition has already run and its tokens are sitting in cumulativeUsage (and its result in agentResults under 'coordinator:decompose'). Billing/observability will under-report real spend on every rejected plan.

Return the live cumulativeUsage and the existing agentResults Map (or call buildTeamRunResult with success:false) so the decomposition spend isn't lost.

}

if (this.config.onPlanReady) {
const tasks = queue.list()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

onPlanReady call isn't wrapped in try/catch like its sibling onApproval

The existing onApproval callback in this file is invoked inside a try/catch that defaults to a safe approved=false on throw. onPlanReady is called bare — a thrown error from user code will propagate out of runTeam, leaving the already-spent coordinator tokens unaccounted and skipping any cleanup the caller expected. Worth matching the existing pattern.

Mirror the onApproval pattern: try/catch around the await, default approved=false on throw (or rethrow with context), so a buggy host callback can't tear down the run mid-flight.

@bot-mergemonkey

Copy link
Copy Markdown

Actionable Comments Posted: 2

🧹 Nitpick comments (1)
onPlanReady accepts mutable Task[] while sibling onApproval is readonly - src/types.ts (645, 653)
onApproval is typed `readonly Task[]` with an explicit "Do not mutate" doc note, but the new onPlanReady right next to it is plain `Task[]`. Same shape of callback, different mutability contract — easy for a host to accidentally rely on mutation here and then have it forbidden in the other hook.

Tighten to `readonly Task[]` and add the same "Do not mutate" note for parity with onApproval.
🧾 Coverage Summary
✔️ Covered (2 files)
- src/orchestrator/orchestrator.ts
- src/types.ts

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