Skip to content

fix(agent): stop MCP Setup Agent re-spawn loop on user-clarification pause (#4291) - #4303

Merged
M3gA-Mind merged 6 commits into
tinyhumansai:mainfrom
oxoxDev:fix/4291-mcp-setup-awaiting-user
Jun 30, 2026
Merged

M3gA-Mind merged 6 commits into
tinyhumansai:mainfrom
oxoxDev:fix/4291-mcp-setup-awaiting-user

Conversation

@oxoxDev

@oxoxDev oxoxDev commented Jun 29, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Fix the infinite "MCP Setup Agent" re-spawn loop when installing an MCP server from chat (Agent cannot complete MCP server installation via chat — setup agent loops without finishing #4291): a delegated sub-agent that pauses to ask the user a question is now surfaced as a resumable pause instead of being silently reported as done.
  • dispatch_subagent now honours SubagentRunStatus::AwaitingUser and returns the [SUBAGENT_AWAITING_USER] envelope (matching the spawn_subagent path) so the orchestrator resumes the checkpointed run via continue_subagent rather than re-delegating a fresh, stateless sub-agent.
  • Add continue_subagent to the orchestrator's tool set so that resume instruction is actually actionable.
  • Extract the awaiting-user envelope into one shared, unit-tested helper so the two delegation paths can't drift.

Problem

Asking the chat agent to "install an MCP server and test it" spawned the MCP Setup Agent 3+ times and stalled, never completing or failing.

Root cause: the orchestrator reaches mcp_setup through the synthesized delegate_setup_mcp_server tool → ArchetypeDelegationTool::execute → dispatch_subagent. dispatch_subagent matched only Ok/Err on the run outcome and ignored outcome.status. When mcp_setup called ask_user_clarification, the runner checkpointed the conversation and returned SubagentRunStatus::AwaitingUser — but dispatch_subagent returned the question as a plain ToolResult::success and emitted a SubagentCompleted event. The orchestrator never received the task_id, so its only way to "continue" was to re-delegate a fresh, stateless mcp_setup, which restarted from step 1, paused again, and re-spawned — an unbounded loop. No circuit breaker caught it: every re-spawn returns is_error=false, and MAX_SPAWN_DEPTH only bounds nesting depth, not breadth-wise re-spawns.

Compounding it, the orchestrator's named tool list lacked continue_subagent (nothing injected it), so even the existing async pause envelopes already instructed it to call a tool it could not call.

Solution

  • dispatch.rs — match outcome.status in the Ok arm. On AwaitingUser, publish SubagentAwaitingUser (domain + per-turn progress) events and return the [SUBAGENT_AWAITING_USER] envelope carrying task_id/agent_id/question plus an explicit instruction to resume via continue_subagent and not re-spawn. Completed keeps the prior behaviour; the Err arm (and its Cannot write code on filesystem #3193 hallucinated-success guard) is untouched. The paused-path mapping is factored into a pure awaiting_outcome_to_tool_result fn with a regression test.
  • tools/awaiting_user.rs (new) — pure, side-effect-free awaiting_user_envelope(...) builder, the single source of truth for both delegation paths, with unit tests.
  • spawn_subagent.rs — route its existing AwaitingUser arm through the shared helper (no behaviour change).
  • orchestrator/agent.toml — add continue_subagent to [tools].named, locked in by a loader.rs test, so the resume instruction is reachable.

Design notes: the resume machinery (continue_subagent, the on-disk checkpoint keyed by task_id) already existed and is launch-path-agnostic — this PR only routes the synchronous delegate path into it. The Notion 401 angle (#4282) is intentionally out of scope (a separate ok:false-recorded-as-success concern); this fix bounds the loop regardless of the 401, since the orchestrator now resumes one checkpointed agent instead of re-spawning.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) — awaiting_user envelope tests (handles + worker-thread present/absent), dispatch AwaitingUser→envelope mapping regression test, loader orchestrator-has-continue_subagent lock-in test.
  • Diff coverage ≥ 80% — verified: Rust Core Coverage CI gate (cargo-llvm-cov) passed on this head; the new helpers + AwaitingUser→envelope mapping + dispatch path are unit-covered.
  • Coverage matrix updated — N/A: behaviour-only fix to existing delegation flow; no feature row added/removed/renamed.
  • All affected feature IDs listed under ## Related — N/A: no matrix feature IDs touched.
  • No new external network dependencies introduced.
  • Manual smoke checklist updated — N/A: no release-cut surface changed (internal agent orchestration only).
  • Linked issue closed via Closes #NNN in ## Related.

Impact

  • Desktop (and any harness using the orchestrator). No schema, migration, or API change.
  • Installing a named MCP server from chat now reaches a clear outcome: the agent surfaces its clarifying question once and resumes on the user's answer, instead of looping. A genuine install failure still propagates (the Err path is unchanged).
  • Also closes a latent gap on the async spawn/wait pause path, which previously told the orchestrator to call a continue_subagent tool it didn't have.

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: fix/4291-mcp-setup-awaiting-user
  • Commit SHA: 3462fdd (tip)

Validation Run

  • pnpm --filter openhuman-app format:check — N/A: no frontend change.
  • pnpm typecheck — N/A: no TypeScript change.
  • Focused tests: cargo test --lib awaiting_user (5 ok), cargo test --lib orchestrator_can_resume (1 ok).
  • Rust fmt/check: cargo fmt --check clean; cargo check exit 0.
  • Tauri fmt/check (if changed): N/A: no app/src-tauri change.

Validation Blocked

  • command: pre-push pnpm rust:check (Tauri shell check)
  • error: worktree submodules (tauri-cef, tauri-plugin-notification) uninitialised → src-tauri not buildable here
  • impact: pushed with --no-verify; change is core-only (src/openhuman/...), no app/src-tauri files touched, so the Tauri check is not relevant to this diff.

Behavior Changes

  • Intended behavior change: a delegated sub-agent pausing on ask_user_clarification is surfaced as a resumable pause; the orchestrator resumes via continue_subagent instead of re-delegating.
  • User-visible effect: "install an MCP server" from chat asks its question once and continues on reply; no more silent MCP Setup Agent re-spawn loop.

Parity Contract

  • Legacy behavior preserved: Completed and Err outcome paths unchanged (incl. the Cannot write code on filesystem #3193 hallucinated-success guard); spawn_subagent's envelope is byte-identical, now sourced from the shared helper.
  • Guard/fallback/dispatch parity checks: dispatch now mirrors spawn_subagent's AwaitingUser handling; loader test asserts the orchestrator exposes continue_subagent.

Duplicate / Superseded PR Handling

Summary by CodeRabbit

  • New Features

    • Added support for resuming paused sub-agents directly from an awaiting-user checkpoint.
    • Orchestrator can now continue a sub-agent after a clarification prompt instead of re-delegating the task.
    • Introduced clearer handling and messaging for paused sub-agent states.
  • Bug Fixes

    • Prevents repeated clarification loops when a sub-agent needs user input.
    • Ensures paused sub-agent responses are surfaced consistently with the right resume guidance.

oxoxDev added 4 commits June 29, 2026 19:53
)

Single source of truth for the [SUBAGENT_AWAITING_USER] envelope handed to
the orchestrator when a delegated sub-agent pauses on ask_user_clarification.
Pure + side-effect-free so dispatch and spawn_subagent cannot drift, and the
wording is unit-testable without a registry or a real model.
…inyhumansai#4291)

Replace the inline [SUBAGENT_AWAITING_USER] format! with the shared
awaiting_user_envelope helper. No behaviour change.
…inyhumansai#4291)

dispatch_subagent matched only Ok/Err on the run outcome and ignored
outcome.status. When a delegated sub-agent (e.g. mcp_setup via
delegate_setup_mcp_server) called ask_user_clarification, the runner
checkpointed it and returned SubagentRunStatus::AwaitingUser — but dispatch
reported it as a plain success carrying the question, and emitted a
SubagentCompleted event. The orchestrator never received the task_id, so its
only way to continue was to re-delegate a fresh, stateless sub-agent, which
restarted from step 1, paused again, and re-spawned — an unbounded loop
(MCP Setup Agent spawned 3+ times, never finishing).

Match outcome.status: on AwaitingUser, publish SubagentAwaitingUser (domain +
progress) events and return the [SUBAGENT_AWAITING_USER] envelope so the
orchestrator resumes via continue_subagent. Completed and Err paths unchanged
(the tinyhumansai#3193 hallucinated-success guard stays on Err). The paused-path mapping is
factored into a pure awaiting_outcome_to_tool_result fn with a regression test.
…gates (tinyhumansai#4291)

The orchestrator's named tool list lacked continue_subagent, so even after
dispatch surfaces the [SUBAGENT_AWAITING_USER] envelope the model had no tool
to resume the checkpointed run — its only move was to re-delegate, re-entering
the loop. Add continue_subagent to the orchestrator's tools and lock it in with
a loader test.
@oxoxDev
oxoxDev requested a review from a team June 29, 2026 14:26
@coderabbitai

coderabbitai Bot commented Jun 29, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 1 minute

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3a84c829-54b8-4298-b7f6-7aea671f0151

📥 Commits

Reviewing files that changed from the base of the PR and between 3462fdd and fcc90c3.

📒 Files selected for processing (2)
  • src/openhuman/agent_orchestration/tools/awaiting_user.rs
  • src/openhuman/agent_registry/agents/loader.rs
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main fix: preventing the agent re-spawn loop when a sub-agent pauses for user clarification.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

@coderabbitai coderabbitai Bot added agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. bug labels Jun 29, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/agent_orchestration/tools/awaiting_user.rs`:
- Around line 31-45: The awaiting-user envelope in `awaiting_user.rs` is
embedding `question` directly into the `[SUBAGENT_AWAITING_USER]` block, which
can break the tagged format if the text contains newlines or reserved
delimiters. Update the formatting in the function that builds this message to
escape or serialize `question` before insertion, preserving the envelope
structure and resume instructions. Add a regression test covering a multiline
question and a question containing `[/SUBAGENT_AWAITING_USER]` to verify the
block stays intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8526b987-ded6-43bb-911d-9b6e98fd721e

📥 Commits

Reviewing files that changed from the base of the PR and between d867c1f and 3462fdd.

📒 Files selected for processing (6)
  • src/openhuman/agent_orchestration/tools.rs
  • src/openhuman/agent_orchestration/tools/awaiting_user.rs
  • src/openhuman/agent_orchestration/tools/dispatch.rs
  • src/openhuman/agent_orchestration/tools/spawn_subagent.rs
  • src/openhuman/agent_registry/agents/loader.rs
  • src/openhuman/agent_registry/agents/orchestrator/agent.toml

oxoxDev added 2 commits June 30, 2026 11:50
…humansai#4291)

Sub-agent-authored question text was embedded raw into the line-oriented
[SUBAGENT_AWAITING_USER] block. A newline or a literal closing tag could
terminate the envelope early and inject fake resume fields the orchestrator
now trusts. JSON-encode the question so it stays on one line with delimiters
escaped; add a regression test for a multiline / tag-injection question.

@M3gA-Mind M3gA-Mind left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed and verified: correct, well-tested, CI green/clearing. Approving. Thanks!

@M3gA-Mind
M3gA-Mind merged commit 14fbc08 into tinyhumansai:main Jun 30, 2026
15 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Team Openhuman Jun 30, 2026
senamakel pushed a commit to nocstah/openhuman that referenced this pull request Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. bug

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Agent cannot complete MCP server installation via chat — setup agent loops without finishing

2 participants