Skip to content

Publish subagent summaries to parent sessions - #99

Merged
delete-cloud merged 5 commits into
mainfrom
subagent-parent-messages
May 4, 2026
Merged

delete-cloud merged 5 commits into
mainfrom
subagent-parent-messages

Conversation

@delete-cloud

@delete-cloud delete-cloud commented May 4, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Publish completed subagent summaries through the parent session runtime message bus via a product-owned callback.
  • Bind SessionManager-created runtime contexts to publish_subagent_message without adding new agentkit, HTTP, or UI surface.
  • Cover both direct subagent publishing and SessionManager runtime injection.

Verification

  • uv run pytest tests/coding_agent/tools/test_subagent.py tests/ui/test_session_manager_public_api.py -q
  • uv run basedpyright src/coding_agent/tools/subagent.py src/coding_agent/ui/session_manager.py tests/coding_agent/tools/test_subagent.py tests/ui/test_session_manager_public_api.py --level error
  • python3 -m py_compile src/coding_agent/tools/subagent.py src/coding_agent/ui/session_manager.py tests/coding_agent/tools/test_subagent.py tests/ui/test_session_manager_public_api.py
  • GIT_MASTER=1 git diff --check HEAD
  • Manual driver: invoked the subagent tool with a SessionManager publisher and consumed the resulting subagent_message from the parent bus.

Summary by CodeRabbit

  • New Features
    • Subagent completion and error summaries are now automatically published to parent sessions, providing enhanced visibility into subagent execution outcomes.

delete-cloud and others added 2 commits May 4, 2026 17:50
Publish completed child summaries through the product-owned parent-session message publisher so the next parent prompt can see subagent results.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Bind session runtime contexts to the SessionManager publisher so subagent completions enter the existing runtime message bus without new HTTP or agentkit surface.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@coderabbitai

coderabbitai Bot commented May 4, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@delete-cloud has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 22 minutes and 54 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: feb9e6db-5ed5-4426-9aa4-f0738bb39ac4

📥 Commits

Reviewing files that changed from the base of the PR and between 00baeb1 and 8588fa2.

📒 Files selected for processing (3)
  • coding-agent/src/coding_agent/tools/subagent.py
  • coding-agent/src/coding_agent/ui/session_manager.py
  • coding-agent/tests/coding_agent/tools/test_subagent.py
📝 Walkthrough

Walkthrough

This PR adds infrastructure for publishing subagent completion and error summaries to a parent session. The SessionManager binds a configurable subagent_message_publisher callback into the runtime context during agent setup, and the subagent tool invokes this publisher after computing outcome summaries, passing session ID, summary text, and child agent metadata.

Changes

Subagent Summary Publishing Flow

Layer / File(s) Summary
Publisher Binding
coding_agent/src/coding_agent/ui/session_manager.py
Added _bind_subagent_message_publisher(ctx) helper that injects self.publish_subagent_message into ctx.config["subagent_message_publisher"]. Invoked in multiple setup paths: checkpoint restore, HTTP run_agent initialization, and _build_session_runtime.
Subagent Summary Publication
coding_agent/src/coding_agent/tools/subagent.py
Added async helper _publish_subagent_summary(...) that retrieves the publisher from context config and conditionally invokes it with session_id, summary, child_agent_id, and source="subagent" metadata; awaits if the publisher result is awaitable. Updated subagent_dispatch to call this helper after computing outcome summary and before returning.
Tests & Verification
coding_agent/tests/coding_agent/tools/test_subagent.py, coding_agent/tests/ui/test_session_manager_public_api.py
New test test_subagent_tool_publishes_completion_summary_to_parent_session verifies the subagent tool publishes summaries with correct payload and metadata. Updated test_run_agent_does_not_hardcode_api_key mocking approach and added test_run_agent_injects_subagent_message_publisher to verify SessionManager.run_agent binds the publisher into agent context and that invoking it produces SUBAGENT_MESSAGE events on the runtime message bus.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 A publisher hops through the context,
Subagents complete, summaries connect it—
From child to parent, the message takes flight,
Async and awaited, the wiring feels right! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Publish subagent summaries to parent sessions' directly describes the main change: adding functionality to publish subagent completion summaries to parent session runtimes via a callback mechanism.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch subagent-parent-messages

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.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 22 minutes and 54 seconds.

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

@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

🧹 Nitpick comments (2)
coding-agent/tests/coding_agent/tools/test_subagent.py (1)

198-217: 💤 Low value

ImmediateAdapter and StubCoordinator duplicate existing module-level helpers.

The inline ImmediateAdapter (lines 207-215) is identical to what _make_immediate_adapter() (line 385) returns, and the inline StubCoordinator (lines 198-200) duplicates _StubCoordinator (line 399). Using the shared helpers keeps the new test consistent with the rest of the file and reduces future drift.

♻️ Proposed fix
-    class StubCoordinator:
-        def allocate_child_id(self, parent_agent_id: str) -> str:
-            return f"{parent_agent_id}.child-1"
-
     child_ctx = PipelineContext(tape=Tape(), session_id="parent-session")

     def child_pipeline_builder(**_kwargs: Any):
         return cast(Pipeline, object()), child_ctx

-    class ImmediateAdapter:
-        def __init__(self, **_kwargs: Any) -> None:
-            pass
-
-        async def run_turn(self, _goal: str) -> TurnOutcome:
-            return TurnOutcome(
-                stop_reason=StopReason.NO_TOOL_CALLS,
-                final_message="Child finished",
-            )
-
-    monkeypatch.setattr("coding_agent.tools.subagent.PipelineAdapter", ImmediateAdapter)
+    monkeypatch.setattr(
+        "coding_agent.tools.subagent.PipelineAdapter", _make_immediate_adapter()
+    )

     tool_fn = build_subagent_tool(child_pipeline_builder)
     parent_ctx = PipelineContext(
         tape=Tape(),
         session_id="parent-session",
         config={
             "agent_id": "parent-agent",
             "subagent_timeout": 30.0,
-            "child_worker_coordinator": StubCoordinator(),
+            "child_worker_coordinator": _StubCoordinator(),
             "subagent_message_publisher": publish_subagent_message,
         },
     )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@coding-agent/tests/coding_agent/tools/test_subagent.py` around lines 198 -
217, The test defines duplicate helpers StubCoordinator and ImmediateAdapter;
remove the inline StubCoordinator and ImmediateAdapter and reuse the
module-level helpers _StubCoordinator and _make_immediate_adapter instead:
instantiate _StubCoordinator for the coordinator usage (replace StubCoordinator)
and call _make_immediate_adapter() (or use its returned class) for the
PipelineAdapter monkeypatch (replace ImmediateAdapter and keep
monkeypatch.setattr("coding_agent.tools.subagent.PipelineAdapter",
_make_immediate_adapter()) or equivalent). Ensure you keep the same behavior and
returned TurnOutcome by using those helpers so the test remains consistent with
the rest of the file.
coding-agent/src/coding_agent/ui/session_manager.py (1)

1376-1394: 💤 Low value

Redundant _bind_subagent_message_publisher call inside the new-agent block.

Line 1376 (inside the if pipeline is None… block) is always superseded by line 1394 (unconditional). Both set ctx.config["subagent_message_publisher"] to the same value, so the first call is unreachable dead work.

♻️ Proposed fix
                 session.tape_id = ctx.tape.tape_id
                 await self._persist_session_async(session)
                 ctx.runtime_message_bus = session.runtime_message_bus
                 ctx.config["wire_consumer"] = None
                 ctx.config["agent_id"] = ""
-                self._bind_subagent_message_publisher(ctx)

                 llm_plugin = pipeline._registry.get("llm_provider")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@coding-agent/src/coding_agent/ui/session_manager.py` around lines 1376 -
1394, Remove the redundant call to _bind_subagent_message_publisher inside the
new-agent/pipeline initialization branch so it only runs once (the later
unconditional call that sets ctx.config["subagent_message_publisher"]);
specifically, delete the earlier invocation that occurs immediately after
creating the PipelineAdapter and before assigning
session.runtime_pipeline/ctx/adapter, leaving the single call after
ctx.config["wire_consumer"] is set; ensure no other side-effects are lost by
verifying _bind_subagent_message_publisher is still invoked exactly once and
that adapter/set_consumer and llm_plugin assignment remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@coding-agent/src/coding_agent/tools/subagent.py`:
- Around line 144-151: The publisher call in _publish_subagent_summary can raise
and abort subagent_dispatch, so wrap the publisher(...) invocation (and the
subsequent await of publish_result when isawaitable(publish_result) is true) in
a try/except that catches Exception, logs the error (including exception
details) and continues instead of re-raising; keep the early return when
publisher is None unchanged, and ensure any awaiting of publish_result happens
inside the same try block so failures there are also non-fatal and
subagent_dispatch can still return summary.

---

Nitpick comments:
In `@coding-agent/src/coding_agent/ui/session_manager.py`:
- Around line 1376-1394: Remove the redundant call to
_bind_subagent_message_publisher inside the new-agent/pipeline initialization
branch so it only runs once (the later unconditional call that sets
ctx.config["subagent_message_publisher"]); specifically, delete the earlier
invocation that occurs immediately after creating the PipelineAdapter and before
assigning session.runtime_pipeline/ctx/adapter, leaving the single call after
ctx.config["wire_consumer"] is set; ensure no other side-effects are lost by
verifying _bind_subagent_message_publisher is still invoked exactly once and
that adapter/set_consumer and llm_plugin assignment remain unchanged.

In `@coding-agent/tests/coding_agent/tools/test_subagent.py`:
- Around line 198-217: The test defines duplicate helpers StubCoordinator and
ImmediateAdapter; remove the inline StubCoordinator and ImmediateAdapter and
reuse the module-level helpers _StubCoordinator and _make_immediate_adapter
instead: instantiate _StubCoordinator for the coordinator usage (replace
StubCoordinator) and call _make_immediate_adapter() (or use its returned class)
for the PipelineAdapter monkeypatch (replace ImmediateAdapter and keep
monkeypatch.setattr("coding_agent.tools.subagent.PipelineAdapter",
_make_immediate_adapter()) or equivalent). Ensure you keep the same behavior and
returned TurnOutcome by using those helpers so the test remains consistent with
the rest of the file.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cdd3fb70-0368-4843-8b60-17b9931839f5

📥 Commits

Reviewing files that changed from the base of the PR and between 77872af and 00baeb1.

📒 Files selected for processing (4)
  • coding-agent/src/coding_agent/tools/subagent.py
  • coding-agent/src/coding_agent/ui/session_manager.py
  • coding-agent/tests/coding_agent/tools/test_subagent.py
  • coding-agent/tests/ui/test_session_manager_public_api.py

delete-cloud and others added 3 commits May 4, 2026 18:10
Keep completed subagent runs from surfacing as tool errors when the optional parent-session publisher fails, and cover the non-fatal path with a regression test.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Drop the redundant run-agent bootstrap binding now that the later unconditional session runtime binding covers the same context path.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Publish timeout results through the same parent-session summary path as completion and error outcomes so the runtime bus always receives a subagent status message.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@delete-cloud
delete-cloud merged commit af14b36 into main May 4, 2026
1 check passed
@delete-cloud
delete-cloud deleted the subagent-parent-messages branch May 4, 2026 10:45
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.

1 participant