Skip to content

refactor(bus): type outbound runtime events - #4590

Merged
Re-bin merged 4 commits into
HKUDS:mainfrom
chengyongru:codex/typed-outbound-events
Jul 1, 2026
Merged

Re-bin merged 4 commits into
HKUDS:mainfrom
chengyongru:codex/typed-outbound-events

Conversation

@chengyongru

@chengyongru chengyongru commented Jun 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Introduces a typed outbound event layer for runtime/UI messages carried by OutboundMessage.event.

  • Adds nanobot.bus.outbound_events with dataclass event types for progress, retry wait, streaming, turn end, goal/session status, and runtime model updates.
  • Migrates core producers plus ChannelManager, WebSocket send(), and CLI interactive consumption to branch on typed events instead of reserved _... metadata flags.
  • Keeps channel wire behavior stable while reserving OutboundMessage.metadata for routing/context such as message IDs, thread IDs, and rich UI blobs.
  • Strips outbound-only continuation state from internal continuation messages.
  • Updates the channel plugin guide for the new runtime event contract and streaming hook signatures.

Compatibility notes

  • Plugin-authored OutboundMessage instances should use event=... for runtime/UI semantics. Legacy metadata flags such as _progress, _stream_delta, _stream_end, _turn_end, and _goal_status are ordinary metadata now; they are not parsed back into runtime events.
  • Custom channels overriding send_delta() must accept keyword-only stream_id, stream_end, and resuming arguments.
  • Custom channels overriding send_reasoning_delta() or send_reasoning_end() must accept keyword-only stream_id.

Why

The previous runtime/UI protocol was spread across ad hoc metadata flags, which made the bus boundary hard to reason about and forced user-facing entry points to know internal flag combinations. This PR creates a single typed outbound event boundary while preserving the existing channel wire payloads.

Validation

  • PYTHONPATH=. uv run --extra dev ruff check nanobot/bus/outbound_events.py nanobot/bus/events.py nanobot/bus/progress.py nanobot/agent/loop.py nanobot/session/webui_turns.py nanobot/session/turn_continuation.py nanobot/channels/manager.py nanobot/channels/websocket.py nanobot/cli/commands.py tests/bus/test_outbound_events.py tests/channels/test_channel_manager_reasoning.py tests/session/test_turn_continuation.py
  • PYTHONPATH=. uv run --extra dev ruff check nanobot/channels/weixin.py nanobot/bus/outbound_events.py nanobot/channels/manager.py
  • PYTHONPATH=. uv run --extra dev pytest tests/bus/test_outbound_events.py tests/channels/test_channel_manager_reasoning.py tests/cli/test_interactive_retry_wait.py tests/agent/test_loop_progress.py::TestToolEventProgress::test_streaming_channel_streams_provider_deltas_for_codex_style_provider tests/agent/test_loop_progress.py::TestToolEventProgress::test_websocket_dispatch_publishes_final_turn_end_marker tests/agent/test_loop_save_turn.py::test_internal_continuation_preserves_streaming_route_metadata tests/channels/test_websocket_channel.py::test_send_turn_end_emits_turn_end_event tests/channels/test_channel_manager_delta_coalescing.py tests/session/test_turn_continuation.py::test_maybe_continue_turn_queues_internal_message
  • PYTHONPATH=. uv run --extra dev pytest tests/bus/test_outbound_events.py tests/channels/test_channel_manager_delta_coalescing.py -q
  • PYTHONPATH=. uv run --extra dev pytest tests/channels/test_weixin_channel.py::test_buffer_flushed_on_stream_end tests/channels/test_weixin_channel.py::test_stream_end_flushes_buffered_answer tests/channels/test_weixin_channel.py::test_stream_end_send_failure_keeps_buffer_for_retry -q
  • Real gateway smoke with temporary config: /webui/bootstrap returned HTTP 200.
  • Real WebSocket smoke through gateway received goal_status, stream_end, message, and turn_end.
  • WebUI lint/test/build are covered by the GitHub Actions webui job.

@chengyongru
chengyongru force-pushed the codex/typed-outbound-events branch 2 times, most recently from 65b2ad1 to b98d695 Compare June 29, 2026 17:09
@chengyongru
chengyongru marked this pull request as ready for review June 29, 2026 17:16

@chengyongru chengyongru left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Automated PR review by nanobot. This is not a human maintainer review or approval.

I found one backward-compatibility side effect around outbound event dispatch.

Comment thread nanobot/channels/manager.py
@chengyongru
chengyongru force-pushed the codex/typed-outbound-events branch from b98d695 to 4eca1a6 Compare June 30, 2026 11:44
@chengyongru chengyongru added the priority: p2 Normal backlog: minor bug, enhancement, docs, cleanup, edge case, or unvalidated proposal. label Jun 30, 2026
@chengyongru
chengyongru force-pushed the codex/typed-outbound-events branch from 4eca1a6 to 55870de Compare July 1, 2026 08:36
@chengyongru chengyongru changed the title [codex] Type outbound runtime events refactor(bus): type outbound runtime events Jul 1, 2026

@Re-bin Re-bin 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.

LGTM. This is a worthwhile cleanup of the outbound runtime protocol: runtime/UI semantics move onto typed OutboundMessage.event payloads while channel routing metadata stays metadata.

I paid special attention to yongru’s compatibility comments. I pushed two focused follow-ups:

  • legacy channel hook signatures still receive the old metadata shape when they do not accept the new keyword arguments
  • legacy in-process producers that still publish _progress, _stream_delta, _stream_end, _turn_end, _goal_status, _goal_state_sync, _session_updated, _runtime_model_updated, _retry_wait, or _streamed metadata are bridged back into typed events

Validated locally:

  • python -m pytest tests/bus/test_outbound_events.py tests/channels/test_channel_plugins.py tests/channels/test_channel_manager_delta_coalescing.py tests/channels/test_channel_manager_reasoning.py -q
  • python -m pytest tests/bus/test_outbound_events.py tests/channels/test_channel_plugins.py tests/channels/test_channel_manager_delta_coalescing.py tests/channels/test_channel_manager_reasoning.py tests/channels/test_websocket_channel.py tests/channels/test_websocket_http_routes.py tests/channels/test_websocket_integration.py tests/agent/test_loop_progress.py tests/agent/test_loop_runner_integration.py tests/agent/test_runner_reasoning.py -q
  • python -m ruff check nanobot/bus/outbound_events.py nanobot/channels/manager.py tests/bus/test_outbound_events.py tests/channels/test_channel_plugins.py tests/channels/test_channel_manager_delta_coalescing.py

GitHub Actions is green across the full matrix.

@Re-bin
Re-bin merged commit c78421c into HKUDS:main Jul 1, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p2 Normal backlog: minor bug, enhancement, docs, cleanup, edge case, or unvalidated proposal. refactor valid

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants