Skip to content

fix(orchestration): hide raw sub-agent dumps, dedup device tools, scope delegation, pin master-chat scroll#4831

Merged
senamakel merged 5 commits into
tinyhumansai:mainfrom
YellowSnnowmann:fix/orchestration-device-side-quality
Jul 14, 2026
Merged

fix(orchestration): hide raw sub-agent dumps, dedup device tools, scope delegation, pin master-chat scroll#4831
senamakel merged 5 commits into
tinyhumansai:mainfrom
YellowSnnowmann:fix/orchestration-device-side-quality

Conversation

@YellowSnnowmann

@YellowSnnowmann YellowSnnowmann commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Hide the raw [local sub-agent … completed] dumps from the /orchestration master chat and dedup device tool calls, so a hosted brain that spawns many on-device sub-agents no longer floods the transcript, and a redelivered run_local_agent no longer re-spawns.
  • Release a failed device-tool dedup claim so an A2A (non-Master) run_local_agent — which the gate denies — is consistently re-denied on redelivery instead of returning a fabricated accepted.
  • Stop background delivery from re-answering a sub-agent result the parent already collected inline via wait_subagent (duplicate reply).
  • Scope the orchestrator's delegation: don't reach into a connected service (e.g. Gmail) for general-knowledge / web / date / math asks just because it is connected.
  • Pin the master chat to the newest message — it was resetting to the top on every send/receive.

Problem

Surfaced testing the hosted master chat (/orchestration):

  • The hosted brain runs sub-agents on-device via run_local_agent; its raw completion output was persisted as a visible master-chat row, so a brain that spawned N sub-agents produced N raw dumps. orch:tool_call is at-least-once, so a redelivery re-spawned the sub-agent and forwarded a duplicate tool_completion.
  • The dedup guard claimed the call_id before dispatch but never released it on failure, so a redelivery of an A2A-denied run_local_agent fabricated an accepted/running ack for a call that never ran — masking the denial and stranding the brain.
  • A spawn_async_subagent result collected inline was still queued for background delivery, so the idle turn re-answered it.
  • A connected integration was treated as a standing reason to delegate to integrations_agent, so a plain date/headline ask could fetch the inbox.
  • The /orchestration transcript has no scroll management: a send/receive flips it to a full-height loading spinner and back, clamping scrollTop to 0 (the top).

Solution

  • effect_executor: tag the completion row with an excluded event_kind (hidden from transcript/preview/unread by the existing store filters) while still forwarding it to the brain via push_event; add an is_local_execution_tool dedup guard to handle_tool_call, and release_call on a failed dispatch so a redelivery re-runs (the success path stays latched so it never re-spawns).
  • background_completions / wait_subagent: a bounded collected-task tombstone set at the wait_subagent collection seam and checked in record_completion, closing both orderings of the wait/record race under the queue mutex; never-waited fire-and-forget results are untouched.
  • orchestrator prompt: additive scope gate — delegate to a connected service only when the request operates on that service's own data/actions; the force-delegate contract for real service asks is preserved.
  • AgentChatPanel: adopt the app's existing useStickToBottom hook (same as /chat) — re-snaps to the bottom after the spinner swap and respects a user who scrolled up.

Tradeoff: hiding the raw dumps means the user reads the orchestrator's synthesized reply rather than intermediate sub-agent output (matches the distill-not-forward intent). The prompt scope-gate is model guidance (probabilistic).

Submission Checklist

  • Tests added or updated (happy path + failure/edge): effect_executor dedup + A2A-release, background-delivery tombstone, orchestrator scope-gate, master-chat stick-to-bottom (+ scrolled-up)
  • Diff coverage ≥ 80% — every new branch is exercised by an added test; the CI diff-cover gate confirms on the merged lcov
  • Coverage matrix updated — N/A: behaviour-only bug fixes, no feature rows added/removed/renamed
  • All affected feature IDs listed under ## RelatedN/A: no matrix feature affected
  • No new external network dependencies introduced
  • Manual smoke checklist updated — N/A: fixes to existing surfaces, no new release-cut surface
  • Linked issue closed via Closes #NNNN/A: surfaced during hosted master-chat testing; no filed issue

Impact

  • Desktop /orchestration master chat: cleaner transcript (raw sub-agent dumps hidden), correct autoscroll, fewer duplicate replies. A2A safety preserved — run_local_agent stays Master-gated and is now consistently denied for A2A even under redelivery. No schema/RPC/wire changes.

Related

  • Closes: N/A
  • Follow-up PR(s)/TODOs: the vendor/tinyagents <|tool_call> content-sentinel recovery (needs a fork of tinyhumansai/tinyagents + a submodule bump); backend counterpart tinyhumansai/backend#1086 (context-bleed window + over-spawn prompt overrides).

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

  • N/A (human-authored)

Linear Issue

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

Commit & Branch

  • Branch: fix/orchestration-device-side-quality
  • Commit SHA: branch head

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests: effect_executor (4), background_completions (12), orchestrator::prompt (21), wait_subagent (4), AgentChatPanel vitest (9)
  • Rust fmt/check (if changed): cargo fmt + core builds (pre-push pnpm rust:check green)
  • Tauri fmt/check (if changed): pre-push rust:check covers app/src-tauri

Behavior Changes

  • Intended behavior change: raw sub-agent completion rows are hidden from the master transcript; redelivered device tool calls no longer re-spawn; orchestrator no longer delegates to a connected service for out-of-scope asks; master chat autoscrolls to newest.
  • User-visible effect: cleaner, correctly-scrolling master chat; fewer duplicate/irrelevant sub-agent runs.

Parity Contract

  • Legacy behavior preserved: run_local_agent Master-gating unchanged; force-delegate for real service asks unchanged; genuinely-later fire-and-forget delivery unchanged; the completion is still forwarded to the brain.
  • Guard/fallback/dispatch parity checks: dedup mirrors handle_send_dm/handle_evict; failed-dispatch release added so A2A denial is not masked.

Duplicate / Superseded PR Handling

  • N/A

Summary by CodeRabbit

  • Improvements
    • Chat conversations now more reliably pin to the latest message while keeping your scroll position when you scroll up.
    • Completed background-agent results are no longer displayed twice.
    • Repeated local-agent actions are deduplicated to prevent unnecessary repeat work.
    • Failed local-agent actions can be retried instead of being treated as successful.
    • Previously hidden bookkeeping messages can reappear in message views when appropriate.
  • Behavior Updates
    • Delegation to connected services is limited to requests that actually use that service’s data or actions (not general questions, web/news, headlines, date/time, or math).

…, release failed claims

run_local_agent's raw '[local sub-agent … completed]' output was persisted as a
visible master-chat row, so a brain that spawns many sub-agents floods the chat
with raw dumps. Tag that row with an excluded event_kind so it is hidden from
the transcript/previews/unread while still forwarding to the brain. Add a dedup
guard to handle_tool_call so an at-least-once redelivery does not re-spawn the
sub-agent, and release the claim when dispatch fails (A2A-gate denial / unknown
cycle / invalid args) so a redelivery re-runs and returns the real error instead
of a fabricated accept.
…ed inline

A spawn_async_subagent result collected inline via wait_subagent was still queued
for background delivery, so the idle-delivery turn re-answered it as a duplicate.
Add a bounded collected-task tombstone set at the wait_subagent collection seam
and checked in record_completion, closing both orderings of the wait/record race
under the queue mutex. Genuinely-later fire-and-forget results are untouched.
…eb/date asks

A connected integration (e.g. Gmail) was treated as a standing reason to delegate
to integrations_agent, so a plain date/headline ask could fetch the inbox. Add a
scope gate: delegate to a connected service only when the request operates on that
service's own data/actions; route general-knowledge, web/news, date/time and math
to a direct tool or the matching non-integration specialist. Additive; regression
test added.
The /orchestration master chat had no scroll management: every send/receive flips
the transcript to a full-height loading spinner and back, resetting scrollTop to 0
(the top) instead of the new message at the bottom. Adopt the app's existing
useStickToBottom hook on the scroll container (same as /chat); it re-snaps to the
bottom after the spinner swap and respects a user who scrolled up. Vitest added.
@YellowSnnowmann YellowSnnowmann requested a review from a team July 13, 2026 16:24
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0b2bf0ed-d696-4776-9b67-91e575baa899

📥 Commits

Reviewing files that changed from the base of the PR and between 1f74b04 and 19b20e9.

📒 Files selected for processing (5)
  • app/src/components/orchestration/__tests__/AgentChatPanel.test.tsx
  • src/openhuman/agent_registry/agents/orchestrator/prompt.md
  • src/openhuman/agent_registry/agents/orchestrator/prompt.rs
  • src/openhuman/orchestration/effect_executor.rs
  • src/openhuman/orchestration/store.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/openhuman/agent_registry/agents/orchestrator/prompt.md
  • app/src/components/orchestration/tests/AgentChatPanel.test.tsx
  • src/openhuman/agent_registry/agents/orchestrator/prompt.rs
  • src/openhuman/orchestration/effect_executor.rs

📝 Walkthrough

Walkthrough

Chat scrolling is made deterministic, background completions avoid duplicate delivery, integration delegation receives explicit scope gates, and local-agent tool calls gain duplicate suppression with claim release on failed dispatch.

Changes

Chat scrolling

Layer / File(s) Summary
Shared chat scroll binding
app/src/components/orchestration/AgentChatPanel.tsx
Chat views pass stable, keyed stick-to-bottom refs into the shared scroll container, which now exposes a scroll test marker.
Autoscroll regression coverage
app/src/components/orchestration/__tests__/AgentChatPanel.test.tsx
Tests verify bottom snapping, preservation of a user-positioned scroll offset, and rendering without a selected chat.

Background completion collection

Layer / File(s) Summary
Collected completion tracking
src/openhuman/agent_orchestration/background_completions.rs, src/openhuman/agent_orchestration/tools/wait_subagent.rs, src/openhuman/orchestration/store.rs
Collected task IDs use bounded tombstones, queued matches are removed, completed subagent results mark their task as collected, and hidden messages can be restored to visible state after forwarding failure.
Collection behavior tests
src/openhuman/agent_orchestration/background_completions.rs
Tests cover sweeping, suppression, task scoping, and tombstone bounds.

Integration delegation scope

Layer / File(s) Summary
Delegation scope guidance
src/openhuman/agent_registry/agents/orchestrator/prompt.md, src/openhuman/agent_registry/agents/orchestrator/prompt.rs
Delegation guidance now requires actual connected-service data or action usage and excludes unrelated general requests.
Prompt scope regression test
src/openhuman/agent_registry/agents/orchestrator/prompt.rs
Prompt construction is tested with absent and connected integrations.

Local-agent delivery semantics

Layer / File(s) Summary
Forwarding and dispatch control flow
src/openhuman/orchestration/effect_executor.rs, src/openhuman/orchestration/store.rs
Forwarded completions are stored as lifecycle events and restored on forwarding failure; duplicate local-agent calls are re-acked, and failed dispatch claims are released.
Tool delivery regression tests
src/openhuman/orchestration/effect_executor.rs
Tests cover duplicate calls, read-only status calls, and repeated failed dispatches.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant handle_tool_call
  participant dispatch_device_tool
  participant release_call
  participant run_local_agent_and_forward
  handle_tool_call->>dispatch_device_tool: dispatch run_local_agent
  dispatch_device_tool-->>handle_tool_call: return dispatch status
  handle_tool_call->>release_call: release claim after failure
  run_local_agent_and_forward->>run_local_agent_and_forward: persist lifecycle completion
  run_local_agent_and_forward-->>run_local_agent_and_forward: restore visibility if forwarding fails
Loading

Possibly related PRs

Suggested labels: bug, rust-core, agent

Suggested reviewers: graycyrus

Poem

I’m a rabbit guarding queues tonight,
With chat pinned snug and prompts just right.
Duplicate hops get tucked away,
Failed dispatches try another day.
Squeak—clean completions lead the way!

🚥 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 summarizes the main orchestration changes: hiding sub-agent dumps, deduping tool calls, scoping delegation, and pinning chat scroll.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

Warning

Tools execution failed with the following error:

Failed to run tools: 14 UNAVAILABLE: read ECONNRESET


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: 1f74b040b5

ℹ️ 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 app/src/components/orchestration/AgentChatPanel.tsx
Comment thread src/openhuman/orchestration/effect_executor.rs
@coderabbitai coderabbitai Bot added agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. bug rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Jul 13, 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: 4

🧹 Nitpick comments (1)
app/src/components/orchestration/AgentChatPanel.tsx (1)

197-201: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add grep-friendly diagnostics for the new pin/disengage state transition.

These are new state-transition flows (stick-to-bottom pinning vs. user-scroll disengage), but neither call site logs entry into this behavior, unlike other flows in this file (sendComposer, runSteeringReview use debug(...)). A one-line debug() call at each useStickToBottom call site (or inside the hook itself) noting thread/reset key would make scroll-pin regressions easier to diagnose in the field.

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; never log secrets or full PII."

Also applies to: 362-369

🤖 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 `@app/src/components/orchestration/AgentChatPanel.tsx` around lines 197 - 201,
Add a one-line debug diagnostic at each useStickToBottom call site, including
the relevant thread/session and reset key, to mark entry into the pin/disengage
scroll behavior. Use the existing debug pattern in AgentChatPanel, avoid secrets
or full PII, and keep the hook behavior unchanged.

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_registry/agents/orchestrator/prompt.md`:
- Line 25: Update the “Scope gate (required)” guidance in the orchestrator
prompt so service delegation is blocked only when the request neither names nor
clearly implies a connected service. Preserve the existing exclusions for
general-knowledge, web/news, date/time, math, and other non-service requests,
while allowing implied operations such as sending email or checking an inbox to
reach the integrations path.

In `@src/openhuman/orchestration/effect_executor.rs`:
- Around line 403-412: The failed local-execution dispatch branch in the effect
executor releases the claim without emitting diagnostics. Update the !ok path
around is_local_execution_tool and release_call to add a namespaced debug or
warn log containing the call ID, tool name, failure outcome, and claim-release
state, while excluding raw arguments and sensitive error data.
- Around line 381-397: Update the deduplication logic used by is_duplicate_call
so reaching SEEN_CALL_IDS_CAP never removes claims for calls still in flight,
including run_local_agent executions. Keep active claims in a separate
unbounded/in-flight structure, or evict only completed tombstones, while
preserving bounded storage for completed call IDs and existing duplicate re-ack
behavior in the local execution path.
- Around line 890-904: Strengthen the redelivery assertions in the
handle_tool_call test by comparing the first and second error payloads, not just
their ok flags. Assert both attempts contain the expected non-Master denial
error and that the second response preserves the same real error as the first,
while retaining the duplicate-field check.

---

Nitpick comments:
In `@app/src/components/orchestration/AgentChatPanel.tsx`:
- Around line 197-201: Add a one-line debug diagnostic at each useStickToBottom
call site, including the relevant thread/session and reset key, to mark entry
into the pin/disengage scroll behavior. Use the existing debug pattern in
AgentChatPanel, avoid secrets or full PII, and keep the hook behavior unchanged.
🪄 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: 466172b6-1583-4dcc-ba68-3a195c23cbec

📥 Commits

Reviewing files that changed from the base of the PR and between 108942b and 1f74b04.

📒 Files selected for processing (7)
  • app/src/components/orchestration/AgentChatPanel.tsx
  • app/src/components/orchestration/__tests__/AgentChatPanel.test.tsx
  • src/openhuman/agent_orchestration/background_completions.rs
  • src/openhuman/agent_orchestration/tools/wait_subagent.rs
  • src/openhuman/agent_registry/agents/orchestrator/prompt.md
  • src/openhuman/agent_registry/agents/orchestrator/prompt.rs
  • src/openhuman/orchestration/effect_executor.rs

Comment thread src/openhuman/agent_registry/agents/orchestrator/prompt.md Outdated
Comment thread src/openhuman/orchestration/effect_executor.rs
Comment thread src/openhuman/orchestration/effect_executor.rs
Comment thread src/openhuman/orchestration/effect_executor.rs
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 13, 2026
… scope-gate wording, log denied dispatch, cover fallbacks

- run_local_agent_and_forward un-hides the completion row (clear event_kind) when
  push_event fails, so an undelivered result is not lost from the UI (+ store
  helper clear_message_event_kind + test).
- Orchestrator scope gate now delegates when a request names OR clearly implies a
  service (check my inbox / send an email); only no-service asks stay off it.
- Log the failed device-tool dispatch + claim release (no raw args or error body).
- Assert the A2A redelivery returns the same real Master-only denial.
- Cover the master-chat empty-messages fallback (diff-cover).
@senamakel senamakel merged commit e0a7b66 into tinyhumansai:main Jul 14, 2026
21 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Team Openhuman Jul 14, 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 rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants