20 KiB
作成
LocalTicketBackend によって作成されました。
項目更新
Ticket item updated: title, body.
項目更新
Ticket item updated: title, body.
Plan
Implementation started.
Plan for this pass:
- Inspect local Worker protocol transport and current Backend/frontend HTTP operation mappings.
- Add a Backend/runtime protocol command transport that accepts existing
protocol::Methodpayloads rather than per-operation HTTP endpoints. - Route TUI Backend Runtime client through that protocol transport for run/notify/completion/cancel/pause/resume/compact/rewind operations.
- Route browser Console operations through the same protocol transport and stop using HTTP operation endpoints as the normal path.
- Keep existing HTTP endpoints only as compatibility where needed, not as frontend/TUI authority.
Implementation report
Implementation update:
Implemented the first full protocol-transport pass for Backend/runtime Worker controls.
Backend/runtime:
- Added
Runtime::send_protocol_method(...)inworker-runtime.Method::ListCompletionsreturns directEvent::Completionsfor same-command-connection semantics.- Other methods are delivered unchanged to the execution backend.
- Added
WorkerExecutionBackend::dispatch_method(...)and concrete support inWorkerRuntimeExecutionBackend.- This accepts existing
protocol::Methodvalues instead of translating through operation-specific HTTP request DTOs.
- This accepts existing
- Added runtime command WebSocket:
/v1/workers/{worker_id}/protocol/ws- accepts raw
protocol::MethodJSON frames - returns raw direct
protocol::EventJSON frames where needed
- Added workspace-server command WebSocket:
/api/runtimes/{runtime_id}/workers/{worker_id}/protocol/ws/api/w/{workspace_id}/runtimes/{runtime_id}/workers/{worker_id}/protocol/ws
- Added
RuntimeRegistry::send_protocol_method(...)and embedded runtime forwarding.
TUI client:
- Reworked
BackendRuntimeClientsosend(&Method)no longer maps to HTTP/input, lifecycle, or unsupported diagnostics. - It now opens a command WS to
/protocol/wsand sends cloned rawprotocol::Methodvalues. - Direct command response events are merged into the existing event queue alongside observation WS events.
- This removes the previous unsupported handling for pause/resume/compact/completions/rewind at the TUI client transport layer.
Browser Console:
- Added command WS connection to
/protocol/wswhile keeping/events/wsas observation stream. - Removed normal operation use of HTTP
POST /inputandPOST /completionsfrom the Console page. - Composer send now maps to protocol methods:
- user input ->
Method::Runwith protocolSegment[] - system input ->
Method::Notify { auto_run: true } :compact->Method::Compact:rewind->Method::ListRewindTargets:peer->Method::RegisterPeer
- user input ->
- Completion lookup now sends
Method::ListCompletionsover command WS and waits for directEvent::Completions. - Added frontend controls for cancel / pause / resume / compact / rewind target request / rewind to target.
Compatibility note:
- Existing HTTP operation endpoints remain in backend/server as compatibility for now, but the TUI Backend client and browser Console normal path now use protocol transport.
Verification run under nix develop:
cargo fmt -- --checkcargo check -p worker-runtime -p yoi-workspace-server -p client -p tuicargo test -p client backend_runtime --libcargo test -p yoi-workspace-server registry_worker_list_can_be_scoped_by_runtime_id --libcargo test -p worker-runtime --features ws-server --lib worker_backendgit diff --check
Frontend check note:
web/workspace/package.jsoncurrently has no check script and local frontend dependencies are not installed in this worktree.- Attempted temporary
npm exec --package svelte-check --package typescript -- svelte-check, but the tool bootstrap failed before checking project code. - The Svelte page was updated against the generated protocol types in
web/workspace/src/lib/generated/protocol.ts, but a frontend-native check still needs to be run in an environment with the frontend deps installed.
Implementation report
Follow-up implementation after design clarification:
Changed the transport split so /events/ws no longer exists. /protocol/ws is now the single Worker protocol WebSocket for both directions:
- client -> runtime/backend: raw
protocol::MethodJSON frames - runtime/backend -> client: raw
protocol::EventJSON frames
Runtime changes:
- Removed
/v1/workers/{worker_id}/events/wsroute. - Removed runtime-specific event WS envelope/diagnostic frame types.
- Extended
/v1/workers/{worker_id}/protocol/wsto stream snapshot/backlog/live observation events as rawprotocol::Eventwhile also accepting method frames on the same socket.
Workspace Backend changes:
- Removed public
/api/.../events/wsand/api/w/.../events/wsroutes. - Removed Backend client event WS envelope types.
- Workspace
/protocol/wsnow proxies/streams raw protocol events and forwards raw protocol methods on the same socket. - Runtime observation source endpoint generation now targets runtime
/protocol/wsinstead of/events/ws.
Client/frontend changes:
- TUI
BackendRuntimeClientno longer opens a separate observation socket. It uses only/protocol/wsfor send and receive. - Browser Console no longer opens both observation and command sockets. It uses one protocol socket for replay/live events, completions, rewind targets, and controls.
- Removed old frontend
ClientWorkerEventWs*types. - Updated frontend UI tests to assert protocol-only Console behavior and absence of operation HTTP paths.
Verification:
nix develop -c cargo fmt -- --checknix develop -c cargo check -p worker-runtime -p yoi-workspace-server -p client -p tuinix develop -c cargo test -p client backend_runtime --libnix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_wsnix develop -c cargo test -p yoi-workspace-server protocol_ws --libnix develop -c cargo test -p yoi-workspace-server proxy_maps_runtime_worker_not_found_http_404_to_protocol_error_event --libdeno test --allow-read web/workspace/src/lib/workspace/console/worker-console.ui.test.tsfromweb/workspacegit diff --check
Implementation report
Bug fix after manual TUI send failure:
Observed symptom:
- TUI send over Backend protocol reported a
does not support Worker protocol command transportstyle error.
Root cause:
/events/wshad been removed and/protocol/wsunified, but workspace-server still handled inbound clientprotocol::Methodby callingRuntimeRegistry::send_protocol_method(...).- For remote runtime-backed workers, Backend must be only a protocol WS proxy. Calling the registry default method hits the unsupported path instead of tunneling the frame to the runtime's
/protocol/ws.
Fix:
- Workspace-server now branches by observation/protocol source:
RemoteWs: proxy raw WebSocket frames bidirectionally between client/api/.../protocol/wsand runtime/v1/.../protocol/ws. Backend does not deserialize or interpret method frames in this path.Embedded: use in-process runtime adapter for method dispatch while streaming embedded observation events.
- Added/updated test so sending
Method::ListCompletionsthrough the workspace-server protocol proxy returnsEvent::Completionsfrom the runtime, proving method frames reach the runtime instead of the Backend unsupported fallback.
Verification:
nix develop -c cargo fmt -- --checknix develop -c cargo check -p yoi-workspace-server -p client -p worker-runtimenix develop -c cargo test -p yoi-workspace-server proxies_worker_protocol_ws_as_raw_events --libnix develop -c cargo test -p client backend_runtime --libnix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_wsnix develop -c cargo test -p yoi-workspace-server protocol_ws --libdeno test --allow-read web/workspace/src/lib/workspace/console/worker-console.ui.test.tsgit diff --check
Implementation report
Bug fix for missing local echo in TUI/Web:
Observed symptom:
- Sending from TUI/Web over unified
/protocol/wsreached the runtime and was accepted asprotocol_method, but the user's sent content did not appear in the Console.
Root cause:
- The old HTTP input path emitted observation events for accepted input via
input_protocol_event(...)(Event::UserMessagefor user input /Event::SystemItemfor system input). - The new raw
Method::Run/Method::Notifyprotocol path dispatched the method to the execution backend but did not record the corresponding observation echo event. - Therefore the unified protocol stream had assistant/runtime events, but no echo event representing the user-sent content.
Fix:
- Added protocol-method observation echo in
worker-runtimeafter acceptedRuntime::send_protocol_method(...)dispatch. Method::Runnow recordsEvent::UserMessage { segments }.Method::Notifynow records a system inputEvent::SystemItem.- Kept compact/list_rewind_targets/register_peer command echoes aligned with the old command-input observation shape.
- Added a runtime protocol WS regression test: send
Method::Runover/protocol/wsand assert the same socket receivesEvent::UserMessagewith the sent text.
Verification:
nix develop -c cargo fmt -- --checknix develop -c cargo check -p worker-runtime -p yoi-workspace-server -p client -p tuinix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_ws_echoes_accepted_run_as_user_messagenix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_wsnix develop -c cargo test -p yoi-workspace-server protocol_ws --libnix develop -c cargo test -p client backend_runtime --libgit diff --check
Implementation report
Correction after review:
The previous fix synthesized Event::UserMessage in Runtime::send_protocol_method(...). That was the wrong layer. UserMessage is part of the normal Worker protocol/log output path and should not be constructed by the runtime transport layer.
Root cause refined:
- The embedded Worker backend bridge only subscribed to
WorkerHandle::event_tx. - Local socket clients also subscribe to
SegmentLogSinklive entries;LogEntry::UserInputis mapped toEvent::UserMessagethere. - Runtime observation/protocol streaming missed that
SegmentLogSinklive-entry path, so user input echo events were absent when using runtime protocol transport.
Fix:
- Removed the runtime-side synthetic protocol-method echo from
Runtime::send_protocol_method(...). - Updated
WorkerRuntimeExecutionBackend::connect_handle(...)to bridge both:- direct Worker protocol events from
WorkerHandle::subscribe() - live session log entries from
handle.sink.subscribe_with_snapshot()
- direct Worker protocol events from
- Added runtime bridge mapping matching local IPC behavior:
LogEntry::SegmentStart->Event::SegmentRotatedLogEntry::UserInput->Event::UserMessageLogEntry::SystemItem->Event::SystemItemLogEntry::Invoke->Event::InvokeStart
- Removed the fake protocol-WS echo test that depended on synthetic runtime behavior.
- Added a unit test that locks the normal bridge mapping: live
LogEntry::UserInputmaps toEvent::UserMessage.
Verification:
nix develop -c cargo fmt -- --checknix develop -c cargo check -p worker-runtime -p yoi-workspace-server -p client -p tuinix develop -c cargo test -p worker-runtime --features ws-server --lib runtime_bridge_maps_live_user_input_log_entry_to_user_messagenix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_wsnix develop -c cargo test -p yoi-workspace-server protocol_ws --libnix develop -c cargo test -p client backend_runtime --libgit diff --check
Decision
Design correction / implementation target:
Runtime protocol WS should be thin. /v1/workers/{worker_id}/protocol/ws is already worker-id scoped, so after worker lookup it should not reimplement Worker protocol semantics. It should connect the WebSocket framing to the same Worker protocol session behavior used by local IPC.
Current issue:
- Local IPC protocol session in
worker/src/ipc/server.rsalready knows how to combine:WorkerHandle::event_txprotocol eventsSegmentLogSinklive log entries (LogEntry::UserInput->Event::UserMessage, etc.)Methodframe reading and event writing
- Runtime WS has been recreating similar logic in
worker-runtime/src/http_server.rs/worker_backend.rs. - This duplicated logic caused drift: runtime protocol streaming initially missed
SegmentLogSinklive entries, and a bad synthetic echo workaround was added before being corrected.
Decision:
- Do not make runtime/backend interpret normal Worker protocol operations.
- Backend remains a raw protocol WS proxy for remote runtime workers.
- Runtime remains a worker-id lookup + lifecycle boundary; for protocol WS it should delegate to a shared Worker protocol session implementation.
- Local IPC and runtime WS should use the same session logic so user echo, system items, invoke events, completions, rewind, pause/resume, etc. cannot diverge.
Implementation target:
- Extract the local IPC protocol session logic into a reusable Worker protocol session helper that is not Unix-socket-specific.
- Local IPC server uses the helper.
- Runtime protocol WS uses the same helper or a thin adapter around it.
- Remove duplicated live-entry/event bridging from runtime-specific code where possible.
- Keep lifecycle/runtime management outside the protocol session helper.
Implementation report
Implementation update for thin runtime protocol session:
- Added
worker::ipc::protocol_sessionas the shared Worker protocol session helper.subscribe_worker_protocol_session(&WorkerHandle)centralizes snapshot + alert + live log entry + event subscriptions.live_log_entry_event(LogEntry)centralizes the local IPC mapping:SegmentStart->Event::SegmentRotatedUserInput->Event::UserMessageSystemItem->Event::SystemItemInvoke->Event::InvokeStart
dispatch_worker_protocol_method(...)centralizes same-connection direct response handling forListCompletions, forwarding other methods toWorkerHandle::send.
- Updated local IPC server to use the shared helper instead of owning its own mapping/subscription logic.
- Updated
worker-runtimeembedded backend bridge to use the same shared helper for live Worker/log event bridging. - Removed the duplicated
live_log_entry_eventmapping from runtime-specific code.
Scope note:
- This keeps Backend as raw WS proxy for remote runtime workers.
- Runtime still performs worker-id lookup and execution/lifecycle boundary work, but protocol stream composition now uses the same Worker session helper as local IPC instead of maintaining a separate mapping implementation.
- Full WS socket pump and Unix JSONL pump still have transport-specific loops, but the protocol subscription/mapping/direct-response semantics are no longer duplicated.
Verification:
nix develop -c cargo fmt -- --checknix develop -c cargo check -p worker-runtime -p worker -p yoi-workspace-server -p client -p tuinix develop -c cargo test -p worker --lib ipc::protocol_sessionnix develop -c cargo test -p worker --lib ipc::servernix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_wsnix develop -c cargo test -p yoi-workspace-server protocol_ws --libnix develop -c cargo test -p client backend_runtime --libgit diff --check
Implementation report
Implementation update for shared protocol frame/pump semantics:
- Added Method/Event-specific JSON codec helpers in
protocol::stream:encode_method/decode_methodencode_event/decode_eventJsonLineReader::next_method()JsonLineWriter::write_event()
- Updated local IPC to use the shared codec helpers and the shared
worker::ipc::protocol_sessionsemantics. - Updated runtime WS and workspace-server embedded protocol handling to use the same
decode_method/encode_eventhelpers instead of directserde_jsoncalls. - Updated Backend runtime client and remote observation client to use
encode_method/decode_eventfor protocol frames.
Resulting split:
- Shared:
- JSON shape for
protocol::Method/protocol::Event - Method/Event encode/decode
- WorkerHandle subscription semantics
- live
LogEntry -> Eventmapping - direct-response method semantics such as
ListCompletions
- JSON shape for
- Transport-specific:
- Unix IPC uses JSONL line boundary.
- WebSocket uses one text frame per JSON value.
This makes WS effectively a frame-boundary adapter around the same JSON protocol frames rather than a separate protocol implementation.
Verification:
nix develop -c cargo fmt -- --checknix develop -c cargo check -p protocol -p worker -p worker-runtime -p yoi-workspace-server -p client -p tuinix develop -c cargo test -p worker --lib ipc::protocol_sessionnix develop -c cargo test -p worker --lib ipc::servernix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_wsnix develop -c cargo test -p yoi-workspace-server protocol_ws --libnix develop -c cargo test -p client backend_runtime --libgit diff --check
Comment
Reported issue before implementation:
- TUI shows the
Compacting...progress/status indication. - Web Console does not show the same indication.
Investigation plan:
- Compare TUI protocol/event handling with Web Console protocol/event handling.
- Confirm whether the relevant protocol event reaches the browser and is dropped by frontend state/rendering, or whether the event is not forwarded through the Backend/runtime protocol WS path.
- Fix the narrow missing mapping/rendering path without adding a synthetic event outside the normal Worker protocol/session flow.
Implementation report
Implementation report for Web Console compact/rotation display gap:
- Web Console already handled live
compact_startby projecting aCompacting…status row. - The projection was still ignoring
segment_rotated, while TUI reseeds the visible transcript from the new segment start entry. This made Web diverge around compaction/segment-rotation boundaries. - Updated
web/workspace/src/lib/workspace/console/model.tssosegment_rotatedreprojectsevent.data.entrythrough the same log-entry projection path used bysnapshot. - Added a Web projection regression test asserting
segment_rotatedreplaces stale visible rows with the new segment seed. - While running Web check, fixed a narrow
list_completionsTypeScript narrowing issue in+page.svelte: command completions return early, then the file completion kind/prefix are captured before the Promise closure.
Verification:
cd web/workspace && deno test --allow-read=src --allow-env=VSCODE_TEXTMATE_DEBUG src/lib/workspace/console/model.test.tscd web/workspace && deno task checkpasses with 0 errors; it still reports 2 existing a11y warnings in+page.svelte.git diff --check