Skip to content

fix(orchestration): surface async sub-agent failures/awaiting-user in chat (#4896)#4908

Merged
senamakel merged 4 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/4896-subagent-failure-propagation
Jul 16, 2026
Merged

fix(orchestration): surface async sub-agent failures/awaiting-user in chat (#4896)#4908
senamakel merged 4 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/4896-subagent-failure-propagation

Conversation

@M3gA-Mind

@M3gA-Mind M3gA-Mind commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Closes #4896

Root cause

Async sub-agent delegation re-injected only successful outcomes. Completed/Incomplete called background_completions::record_completion (→ re-injected via background_delivery::try_deliver), but the AwaitingUser and Err(...) branches in spawn_async_subagent.rs only published events — never record_completion. Since try_deliver drains only pending completions, failures/awaiting could never reach chat: the parent turn finalized on "Accepted async sub-agent…" and the failure was silently lost.

Fix

Route failure and awaiting-user outcomes through the delivery path with a user-readable summary (task id + reason), and render outcome-specific items in background_delivery (mixed-batch tagging, outcome-specific fallbacks, outcome preserved through a drain/requeue). Success tag/wording preserved; existing tests unaffected.

Verification

Unit tests: an erroring child and an awaiting-user child each produce a delivered chat follow-up. i18n: none — these are agent-context/system-turn strings (same class as the existing untranslated [SUBAGENT_INCOMPLETE] framing), not localized UI. No AI attribution.

Summary by CodeRabbit

  • New Features

    • Background sub-agent results now clearly distinguish successful completions, failures, and requests for user input.
    • Failed tasks and tasks awaiting input are surfaced in the parent conversation with dedicated notices.
    • Delivery and retry handling now preserve each task’s terminal status.
  • Bug Fixes

    • Resolved an issue where sub-agent failures or input requests could be omitted from parent chat delivery.
    • Improved batched notices with outcome-specific labels and fallback messages.

…r in chat

Async sub-agent delegation re-injected only successful outcomes; the AwaitingUser
and Err(...) branches published events but never called record_completion, so
background_delivery (which drains only completions) could never surface them and
the turn finalized on "Accepted" with the failure silently lost.

Route failure and awaiting-user outcomes through the delivery path with a
user-readable summary (task id + reason), and render outcome-specific items in
background_delivery so the user learns a delegated task failed or needs input.
Success tag/wording preserved; existing tests unaffected.

Closes tinyhumansai#4896
@M3gA-Mind M3gA-Mind requested a review from a team July 15, 2026 13:53
@coderabbitai

coderabbitai Bot commented Jul 15, 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: 11 minutes

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: 36e1a615-45b4-4cd0-81c8-13b92c0199d3

📥 Commits

Reviewing files that changed from the base of the PR and between 45bd523 and 834c823.

📒 Files selected for processing (1)
  • src/openhuman/agent_orchestration/background_delivery.rs
📝 Walkthrough

Walkthrough

Async sub-agent failures and awaiting-user states are now recorded alongside successful completions, preserved through background delivery and requeueing, and rendered with distinct notice tags and fallback messages.

Changes

Async sub-agent outcome propagation

Layer / File(s) Summary
Outcome-aware completion recording and rendering
src/openhuman/agent_orchestration/background_completions.rs
Completion records now carry explicit terminal outcomes. Failure and awaiting-input helpers enqueue framed summaries, while batched notices render outcome-specific tags and empty-summary fallbacks. Tests cover recording, draining, rendering, and outcome preservation.
Terminal-state recording
src/openhuman/agent_orchestration/tools/spawn_async_subagent.rs
Detached sub-agent awaiting-user and error paths now enqueue parent-chat results through the background completion pipeline.
Terminal-event delivery and requeue
src/openhuman/agent_orchestration/background_delivery.rs
Failed and awaiting-user events now schedule debounced delivery, and requeued batches preserve each completion’s original outcome. Tests cover all terminal event types.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SpawnAsyncSubagent
  participant BackgroundCompletions
  participant BackgroundDelivery
  participant ParentChat
  SpawnAsyncSubagent->>BackgroundCompletions: record failure or awaiting-input outcome
  SpawnAsyncSubagent->>BackgroundDelivery: publish terminal event
  BackgroundDelivery->>BackgroundCompletions: schedule and drain delivery
  BackgroundCompletions-->>BackgroundDelivery: outcome-specific completion
  BackgroundDelivery-->>ParentChat: inject batched notice
Loading

Possibly related PRs

Suggested labels: bug, agent

Poem

I’m a bunny with outcomes tucked tight,
Failure and questions now hop into sight.
Success wears one tag, needs-input another,
Messages return to their waiting burrow.
Requeued with care, each state stays true—
A tidy little trail from child to you.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: surfacing async sub-agent failures and awaiting-user states in chat.
Linked Issues check ✅ Passed The diff implements the issue's required failure and awaiting-user chat reinjection plus regression coverage through background_delivery.
Out of Scope Changes check ✅ Passed Changes stay focused on background delivery, outcome preservation, and sub-agent failure/awaiting-input surfacing; no unrelated scope is introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4838b94b33

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/openhuman/agent_orchestration/tools/spawn_async_subagent.rs
Comment on lines +671 to +677
crate::openhuman::agent_orchestration::background_completions::record_awaiting_input(
background_parent_session.clone(),
outcome.task_id.clone(),
outcome.agent_id.clone(),
question,
background_parent_thread_id.clone(),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Suppress queued terminal notices after wait_subagent

Now that awaiting-user and failed async outcomes are enqueued for background delivery, a parent that calls wait_subagent and receives that terminal status inline can still get a second injected follow-up after AgentTurnCompleted, because wait_subagent only calls mark_collected for the Completed arm. In the scenario where the child pauses or fails while the parent is waiting, this new queued notice survives and is delivered as a duplicate for the same task.

Useful? React with 👍 / 👎.

senamakel and others added 2 commits July 16, 2026 00:06
…inyhumansai#4896)

The background delivery handler only scheduled a drain on SubagentCompleted, so
a subagent that FAILED (or paused awaiting user) after the parent turn was
already idle never triggered a delivery attempt — the pending failure sat
undelivered until some unrelated later turn, leaving the chat stuck on the
original "Accepted" response (Codex P1). Match all three subagent terminal
events (completed | failed | awaiting-user), each of which carries
`parent_session`, in the same debounced-drain arm. Add a handler test that
accepts every terminal event.
@coderabbitai coderabbitai Bot added agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. bug labels Jul 15, 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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/openhuman/agent_orchestration/background_delivery.rs (1)

254-261: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Test requeue with an actual failed outcome.

This calls record_completion, so it passes even if requeue downgrades failures to success. Enqueue with record_failure, requeue, drain, and assert BackgroundAgentOutcome::Failed.

🤖 Prompt for 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.

In `@src/openhuman/agent_orchestration/background_delivery.rs` around lines 254 -
261, Update requeue_restores_a_failed_batch to enqueue the batch using
record_failure instead of record_completion, then requeue and drain it with
take_pending; assert that the resulting outcome is
BackgroundAgentOutcome::Failed, while retaining the pending-state and cleanup
checks.

Source: Coding guidelines

🧹 Nitpick comments (1)
src/openhuman/agent_orchestration/background_completions.rs (1)

149-195: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add grep-friendly terminal-outcome lifecycle diagnostics. The new outcome pipeline has no trace for terminal-state detection, queue acceptance/deduplication, or drain scheduling, making silent delivery loss difficult to diagnose. Do not log summaries, questions, or error text.

  • src/openhuman/agent_orchestration/background_completions.rs#L149-L195: log accepted and duplicate-suppressed records with task_id and outcome.
  • src/openhuman/agent_orchestration/tools/spawn_async_subagent.rs#L666-L725: log the awaiting-input/failed branch before enqueueing, using task ID, agent ID, and disposition only.
  • src/openhuman/agent_orchestration/background_delivery.rs#L73-L85: log terminal-event drain scheduling with the task ID.

As per coding guidelines, “New or changed flows must include verbose, grep-friendly diagnostics for entry/exit, branches, external calls, retries/timeouts, state transitions, and errors; use log/tracing at debug/trace in Rust and namespaced debug logging in the app. Never log secrets or full PII.”

🤖 Prompt for 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.

In `@src/openhuman/agent_orchestration/background_completions.rs` around lines 149
- 195, Since the terminal-outcome lifecycle lacks diagnostics, add namespaced
debug logs at all three sites: in background_completions.rs lines 149-195,
update record_outcome to log accepted records and duplicate-suppressed records
with task_id and outcome only; in tools/spawn_async_subagent.rs lines 666-725,
log the awaiting-input/failed terminal branch immediately before enqueueing
using task ID, agent ID, and disposition only; and in background_delivery.rs
lines 73-85, log terminal-event drain scheduling with the task ID. Do not log
summaries, questions, error text, secrets, or full PII.

Source: Coding guidelines

🤖 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/background_delivery.rs`:
- Around line 317-359: Strengthen handler_accepts_every_subagent_terminal_event
so each terminal event demonstrably schedules and executes a drain: enqueue a
matching headless result before handling each event, await the debounce period,
and assert that the pending item was consumed. Retain the existing assertion
that terminal events do not mark the parent session busy.

---

Outside diff comments:
In `@src/openhuman/agent_orchestration/background_delivery.rs`:
- Around line 254-261: Update requeue_restores_a_failed_batch to enqueue the
batch using record_failure instead of record_completion, then requeue and drain
it with take_pending; assert that the resulting outcome is
BackgroundAgentOutcome::Failed, while retaining the pending-state and cleanup
checks.

---

Nitpick comments:
In `@src/openhuman/agent_orchestration/background_completions.rs`:
- Around line 149-195: Since the terminal-outcome lifecycle lacks diagnostics,
add namespaced debug logs at all three sites: in background_completions.rs lines
149-195, update record_outcome to log accepted records and duplicate-suppressed
records with task_id and outcome only; in tools/spawn_async_subagent.rs lines
666-725, log the awaiting-input/failed terminal branch immediately before
enqueueing using task ID, agent ID, and disposition only; and in
background_delivery.rs lines 73-85, log terminal-event drain scheduling with the
task ID. Do not log summaries, questions, error text, secrets, or full PII.
🪄 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: a844096d-0e98-4f81-9abe-42bf720ab877

📥 Commits

Reviewing files that changed from the base of the PR and between d320c43 and 45bd523.

📒 Files selected for processing (3)
  • src/openhuman/agent_orchestration/background_completions.rs
  • src/openhuman/agent_orchestration/background_delivery.rs
  • src/openhuman/agent_orchestration/tools/spawn_async_subagent.rs

Comment thread src/openhuman/agent_orchestration/background_delivery.rs Outdated
@M3gA-Mind

Copy link
Copy Markdown
Collaborator Author

W5 code review (comment-only — maintainer decides merge)

Reviewed the full diff (3 files, +326/-7). Verdict: sound. This correctly closes the gap where a detached sub-agent that failed or paused awaiting input never surfaced in chat — the parent turn finalized on "Accepted" and the outcome was lost.

Transparency: the background_delivery.rs change that drains on SubagentFailed/SubagentAwaitingUser (not just Completed) is my own earlier fix on this head — without it the newly-recorded failures/awaiting-input would sit undelivered when the parent turn is idle, so it's load-bearing for this PR. My review below is of the recording + notice logic (the author's work).

What's good

  • Clean model: BackgroundAgentOutcome { Completed, Failed, AwaitingInput } threaded through record_outcometake_pendingbuild_batched_notice, with distinct XML-ish tags (background_agent_result / _failure / _needs_input) and outcome-specific empty fallbacks so a failure is never rendered as a normal completion.
  • Careful idempotency: record_outcome drops entries for cancelled_threads and collected_tasks (closing the wait_subagent wait-before-record race) and dedups per task_id. Outcome is preserved across a drain+requeue (record_outcome_preserves_the_outcome_through_a_drain).
  • Recording sites are right: spawn_async_subagent records record_failure on error and record_awaiting_input on pause, with the parent session/thread/task ids.
  • Test coverage is thorough: framed-failure, framed-awaiting, distinct-tag rendering, outcome-specific empty fallback, and drain-preservation are all covered.

One minor note (non-blocking)

record_outcome's per-task dedup (pending.iter().any(|c| c.task_id == entry.task_id)) silently drops a later outcome for a task that already has a pending, undelivered entry. In the awaiting-input → continue → complete flow, if the AwaitingInput notice hasn't drained yet when the task later Completed/Failed, the terminal outcome is dropped and the stale "needs input" notice is what the user sees. In practice this is a very narrow race — delivery is idle-gated + ~3s-debounced and continue_subagent is user-paced, so the awaiting notice all but always drains first — but a defensive improvement would be to let a terminal Completed/Failed replace a still-pending non-terminal AwaitingInput for the same task (or at least a code comment documenting the "one live pending entry per task" assumption).

No i18n surface (Rust-only). No blockers. Not approving/merging — that's the maintainer's call.

…tinyhumansai#4896)

CodeRabbit: the previous handler test only asserted `!is_busy`, which also holds
if the events fall through to `_ => {}`, so it couldn't catch a regression to the
completed-only behaviour. Replace it with a behavioural test on the paused clock:
queue a headless result per session, fire each terminal event, advance past the
debounce, and assert the pending result was consumed — proving the arm scheduled
a drain for SubagentFailed / SubagentAwaitingUser (not just SubagentCompleted).
@M3gA-Mind

Copy link
Copy Markdown
Collaborator Author

W5 — pushed 834c823 (CodeRabbit)

Rewrote the terminal-events handler test as a behavioural check (paused clock): queues a headless result per session, fires each of the 3 terminal events, advances past the debounce, and asserts the pending result was consumed — so it now fails if any terminal event is dropped or falls through to _ => {} (the old test only asserted !is_busy, which CodeRabbit correctly noted also passed for the fall-through). No wall-clock wait. Comment-only.

@senamakel senamakel merged commit 9707fa3 into tinyhumansai:main Jul 16, 2026
18 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Team Openhuman Jul 16, 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

Status: Done

Development

Successfully merging this pull request may close these issues.

Async sub-agent failures never propagate to chat and are silently dropped

2 participants