yoi/.yoi/tickets/00001KY1ZKCPC/thread.md

24 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::Method payloads 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(...) in worker-runtime.
    • Method::ListCompletions returns direct Event::Completions for same-command-connection semantics.
    • Other methods are delivered unchanged to the execution backend.
  • Added WorkerExecutionBackend::dispatch_method(...) and concrete support in WorkerRuntimeExecutionBackend.
    • This accepts existing protocol::Method values instead of translating through operation-specific HTTP request DTOs.
  • Added runtime command WebSocket:
    • /v1/workers/{worker_id}/protocol/ws
    • accepts raw protocol::Method JSON frames
    • returns raw direct protocol::Event JSON 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 BackendRuntimeClient so send(&Method) no longer maps to HTTP /input, lifecycle, or unsupported diagnostics.
  • It now opens a command WS to /protocol/ws and sends cloned raw protocol::Method values.
  • 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/ws while keeping /events/ws as observation stream.
  • Removed normal operation use of HTTP POST /input and POST /completions from the Console page.
  • Composer send now maps to protocol methods:
    • user input -> Method::Run with protocol Segment[]
    • system input -> Method::Notify { auto_run: true }
    • :compact -> Method::Compact
    • :rewind -> Method::ListRewindTargets
    • :peer -> Method::RegisterPeer
  • Completion lookup now sends Method::ListCompletions over command WS and waits for direct Event::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 -- --check
  • cargo check -p worker-runtime -p yoi-workspace-server -p client -p tui
  • cargo test -p client backend_runtime --lib
  • cargo test -p yoi-workspace-server registry_worker_list_can_be_scoped_by_runtime_id --lib
  • cargo test -p worker-runtime --features ws-server --lib worker_backend
  • git diff --check

Frontend check note:

  • web/workspace/package.json currently 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::Method JSON frames
  • runtime/backend -> client: raw protocol::Event JSON frames

Runtime changes:

  • Removed /v1/workers/{worker_id}/events/ws route.
  • Removed runtime-specific event WS envelope/diagnostic frame types.
  • Extended /v1/workers/{worker_id}/protocol/ws to stream snapshot/backlog/live observation events as raw protocol::Event while also accepting method frames on the same socket.

Workspace Backend changes:

  • Removed public /api/.../events/ws and /api/w/.../events/ws routes.
  • Removed Backend client event WS envelope types.
  • Workspace /protocol/ws now proxies/streams raw protocol events and forwards raw protocol methods on the same socket.
  • Runtime observation source endpoint generation now targets runtime /protocol/ws instead of /events/ws.

Client/frontend changes:

  • TUI BackendRuntimeClient no longer opens a separate observation socket. It uses only /protocol/ws for 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 -- --check
  • nix develop -c cargo check -p worker-runtime -p yoi-workspace-server -p client -p tui
  • nix develop -c cargo test -p client backend_runtime --lib
  • nix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_ws
  • nix develop -c cargo test -p yoi-workspace-server protocol_ws --lib
  • nix develop -c cargo test -p yoi-workspace-server proxy_maps_runtime_worker_not_found_http_404_to_protocol_error_event --lib
  • deno test --allow-read web/workspace/src/lib/workspace/console/worker-console.ui.test.ts from web/workspace
  • git 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 transport style error.

Root cause:

  • /events/ws had been removed and /protocol/ws unified, but workspace-server still handled inbound client protocol::Method by calling RuntimeRegistry::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/ws and 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::ListCompletions through the workspace-server protocol proxy returns Event::Completions from the runtime, proving method frames reach the runtime instead of the Backend unsupported fallback.

Verification:

  • nix develop -c cargo fmt -- --check
  • nix develop -c cargo check -p yoi-workspace-server -p client -p worker-runtime
  • nix develop -c cargo test -p yoi-workspace-server proxies_worker_protocol_ws_as_raw_events --lib
  • nix develop -c cargo test -p client backend_runtime --lib
  • nix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_ws
  • nix develop -c cargo test -p yoi-workspace-server protocol_ws --lib
  • deno test --allow-read web/workspace/src/lib/workspace/console/worker-console.ui.test.ts
  • git diff --check

Implementation report

Bug fix for missing local echo in TUI/Web:

Observed symptom:

  • Sending from TUI/Web over unified /protocol/ws reached the runtime and was accepted as protocol_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::UserMessage for user input / Event::SystemItem for system input).
  • The new raw Method::Run / Method::Notify protocol 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-runtime after accepted Runtime::send_protocol_method(...) dispatch.
  • Method::Run now records Event::UserMessage { segments }.
  • Method::Notify now records a system input Event::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::Run over /protocol/ws and assert the same socket receives Event::UserMessage with the sent text.

Verification:

  • nix develop -c cargo fmt -- --check
  • nix develop -c cargo check -p worker-runtime -p yoi-workspace-server -p client -p tui
  • nix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_ws_echoes_accepted_run_as_user_message
  • nix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_ws
  • nix develop -c cargo test -p yoi-workspace-server protocol_ws --lib
  • nix develop -c cargo test -p client backend_runtime --lib
  • git 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 SegmentLogSink live entries; LogEntry::UserInput is mapped to Event::UserMessage there.
  • Runtime observation/protocol streaming missed that SegmentLogSink live-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()
  • Added runtime bridge mapping matching local IPC behavior:
    • LogEntry::SegmentStart -> Event::SegmentRotated
    • LogEntry::UserInput -> Event::UserMessage
    • LogEntry::SystemItem -> Event::SystemItem
    • LogEntry::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::UserInput maps to Event::UserMessage.

Verification:

  • nix develop -c cargo fmt -- --check
  • nix develop -c cargo check -p worker-runtime -p yoi-workspace-server -p client -p tui
  • nix develop -c cargo test -p worker-runtime --features ws-server --lib runtime_bridge_maps_live_user_input_log_entry_to_user_message
  • nix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_ws
  • nix develop -c cargo test -p yoi-workspace-server protocol_ws --lib
  • nix develop -c cargo test -p client backend_runtime --lib
  • git 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.rs already knows how to combine:
    • WorkerHandle::event_tx protocol events
    • SegmentLogSink live log entries (LogEntry::UserInput -> Event::UserMessage, etc.)
    • Method frame 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 SegmentLogSink live 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_session as 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::SegmentRotated
      • UserInput -> Event::UserMessage
      • SystemItem -> Event::SystemItem
      • Invoke -> Event::InvokeStart
    • dispatch_worker_protocol_method(...) centralizes same-connection direct response handling for ListCompletions, forwarding other methods to WorkerHandle::send.
  • Updated local IPC server to use the shared helper instead of owning its own mapping/subscription logic.
  • Updated worker-runtime embedded backend bridge to use the same shared helper for live Worker/log event bridging.
  • Removed the duplicated live_log_entry_event mapping 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 -- --check
  • nix develop -c cargo check -p worker-runtime -p worker -p yoi-workspace-server -p client -p tui
  • nix develop -c cargo test -p worker --lib ipc::protocol_session
  • nix develop -c cargo test -p worker --lib ipc::server
  • nix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_ws
  • nix develop -c cargo test -p yoi-workspace-server protocol_ws --lib
  • nix develop -c cargo test -p client backend_runtime --lib
  • git 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_method
    • encode_event / decode_event
    • JsonLineReader::next_method()
    • JsonLineWriter::write_event()
  • Updated local IPC to use the shared codec helpers and the shared worker::ipc::protocol_session semantics.
  • Updated runtime WS and workspace-server embedded protocol handling to use the same decode_method / encode_event helpers instead of direct serde_json calls.
  • Updated Backend runtime client and remote observation client to use encode_method / decode_event for protocol frames.

Resulting split:

  • Shared:
    • JSON shape for protocol::Method / protocol::Event
    • Method/Event encode/decode
    • WorkerHandle subscription semantics
    • live LogEntry -> Event mapping
    • direct-response method semantics such as ListCompletions
  • 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 -- --check
  • nix develop -c cargo check -p protocol -p worker -p worker-runtime -p yoi-workspace-server -p client -p tui
  • nix develop -c cargo test -p worker --lib ipc::protocol_session
  • nix develop -c cargo test -p worker --lib ipc::server
  • nix develop -c cargo test -p worker-runtime --features ws-server --lib protocol_ws
  • nix develop -c cargo test -p yoi-workspace-server protocol_ws --lib
  • nix develop -c cargo test -p client backend_runtime --lib
  • git 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_start by projecting a Compacting… 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.ts so segment_rotated reprojects event.data.entry through the same log-entry projection path used by snapshot.
  • Added a Web projection regression test asserting segment_rotated replaces stale visible rows with the new segment seed.
  • While running Web check, fixed a narrow list_completions TypeScript 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.ts
  • cd web/workspace && deno task check passes with 0 errors; it still reports 2 existing a11y warnings in +page.svelte.
  • git diff --check

Comment

Requested Web Console timeline-bar display change before implementation:

  • Keep user-message markers/items as they are today.
  • For assistant display in the timeline bar, show only the last assistant item within each turn.

Implementation plan:

  • Locate the Web timeline-bar projection/rendering path.
  • Change only the timeline-bar item derivation/filtering, not the underlying transcript/event model.
  • Add/update focused Web tests if there is a projection helper; otherwise verify through existing Web check and keep the diff scoped.

Implementation report

Implementation report for Web Console timeline-bar assistant filtering:

  • Added selectConsoleTimelineLines() in web/workspace/src/lib/workspace/console/model.ts.
  • The selector keeps every user line in the timeline selection.
  • Assistant lines are grouped by user-delimited turns, and only the last assistant line in each turn is selected.
  • Non-user/non-assistant lines remain excluded from the timeline bar selection.
  • Updated +page.svelte timeline layout construction to use the selector before converting selected lines to timeline marks. Positioning still uses the full transcript line count, so marks remain aligned to scroll position.
  • Added a focused model test for user, assistant, tool, assistant, user, assistant, assistant to assert the selected timeline items are u1, a2, u2, and a4.

Verification:

  • cd web/workspace && deno test --allow-read=src --allow-env=VSCODE_TEXTMATE_DEBUG src/lib/workspace/console/model.test.ts
  • cd web/workspace && deno task check passed with 0 errors; it still reports the existing 2 a11y warnings in +page.svelte.
  • git diff --check

Note: deno fmt --check on the touched files still reports existing formatting changes outside this patch scope, so it was not used as the gating check for this small change.


Comment

Requested Web Console tool-path display change before implementation:

  • Use the Worker's protocol snapshot.greeting.cwd as the display base.
  • For known display portions of edit-related tools plus Read, Grep, and Glob, show absolute paths relative to cwd.
  • Do not globally replace arbitrary tool output text; only rewrite known path-bearing parts of known tool display formats.

Implementation plan:

  • Carry greeting.cwd through the Web Console projection state.
  • Add a focused display normalizer for known tool output formats:
    • Read ... from <path> / read error path forms if present.
    • grep result path prefixes such as <path>:line:... and summary lines like matching lines in files.
    • glob found-path listing entries.
    • edit/write-style success/error lines that explicitly include a file path.
  • Add focused model tests for the supported formats and keep transcript/protocol payloads unchanged.

Implementation report

Implementation report for Web Console known tool-path display relativization:

  • Web Console projection now carries snapshot.greeting.cwd in ConsoleProjection.
  • Each ToolCallView captures the current cwd so later rendering can use the correct display base without changing protocol payloads or stored tool output.
  • Added path-display normalization scoped to known tool display formats only:
    • Read: file_path display and Read ... from <path> summary/detail path.
    • Write: file_path display and known Created / Overwrote / Wrote / related result-line path prefixes.
    • Edit: file_path display and known Edited <path> (...) result-line path prefix.
    • Glob: line-start cwd paths in result preview.
    • Grep: line-start cwd paths in result preview, including path:line:... output.
  • Paths outside cwd are left absolute.
  • Arbitrary default tool output, Bash output, and argument JSON/details are not globally rewritten.

Tests:

  • Added a focused Web model regression test with snapshot.greeting.cwd = /repo covering Read/Write/Edit/Glob/Grep display output.
  • The test asserts cwd-contained paths become relative while /outside/... paths remain absolute.

Verification:

  • cd web/workspace && deno test --allow-read=src --allow-env=VSCODE_TEXTMATE_DEBUG src/lib/workspace/console/model.test.ts
  • cd web/workspace && deno task check passed with 0 errors; it still reports the existing 2 a11y warnings in +page.svelte.
  • git diff --check