2.5 KiB
Web Console renders one Worker notification twice
Date: 2026-08-06
Symptom
A single Workspace Orchestrator attention notification appears in Web Console as two adjacent system lines with identical content:
System · embedded worker notificationSystem · notification
The first label is also misleading for Workers running on a non-embedded Runtime.
Confirmed cause
worker-runtime projects one accepted WorkerInputKind::Notify through two independent protocol-event paths.
Runtime::interact_workercallsinput_protocol_event(&input)after the execution backend acknowledges the input and pushes the result to the Worker observation bus. ForNotify,input_protocol_eventconstructs a syntheticprotocol::Event::SystemItemwith kindembedded_worker_notification.- The real Worker drains
NotifyBuffer, commitsSystemItem::Notificationto Worker history, and the Runtime execution bridge republishes the committed log entry as anotherprotocol::Event::SystemItemwith kindnotification.
The Workspace subscription forwards both events. web/workspace/src/lib/workspace/console/model.ts renders every system_item independently and has no semantic deduplication between these two different kinds/event identities.
The authoritative history item is the second event. The synthetic input-observation item is not the durable Worker-history authority, so the LLM should receive the notification once even though Web Console displays it twice.
Relevant code
crates/worker-runtime/src/runtime.rsinput_protocol_event(WorkerInputKind::Notify)createdembedded_worker_notification.Runtime::interact_workerunconditionally published that synthetic event after accepted input.
crates/worker-runtime/src/worker_backend.rs- the controller bridge republishes committed
SegmentLogSinkentries throughlive_log_entry_event.
- the controller bridge republishes committed
web/workspace/src/lib/workspace/console/model.ts- both system-item variants are rendered as separate lines.
Resolution
worker-runtime no longer converts accepted Notify input into a synthetic protocol event. input_protocol_event returns no event for Notify, while the normal interaction acknowledgement remains unchanged. The committed SystemItem::Notification is therefore the single Console-visible projection.
A caller-boundary regression test drives accepted user and Notify inputs, verifies that Notify adds no synthetic observation, then publishes the committed notification event and asserts that exactly one notification system item is present.