feat(runtime): bridge user-input events and API to external GUI clients#2133
Open
gaord wants to merge 5 commits into
Open
feat(runtime): bridge user-input events and API to external GUI clients#2133gaord wants to merge 5 commits into
gaord wants to merge 5 commits into
Conversation
Add SSE event forwarding for UserInputRequired, REST endpoint for submitting user input responses, timeout protection for await_user_input, and fix interrupt_turn to clear active_turn immediately.
Contributor
There was a problem hiding this comment.
Code Review
This pull request introduces a 300-second timeout for user input requests and adds a new API endpoint for submitting user input. It also updates the runtime thread manager to handle user input events and modifies turn interruption logic. Feedback suggests improving error handling consistency by using standard error mapping for missing threads and removing redundant turn finalization code that could cause duplicate events and data loss.
The monitor_turn loop already handles full turn finalization when the engine shuts down after cancellation, including saving turn status, usage, error, emitting turn.completed, and clearing active_turn. Having interrupt_turn also save turn status and emit turn.completed causes duplicate SSE events and loses usage/error data that monitor_turn would have captured from TurnComplete. Keep only the active_turn cleanup so the 409 error is resolved while monitor_turn remains the single source of truth for turn completion.
- Change 'not loaded' to 'not found' in submit_user_input and cancel_user_input so map_thread_err correctly maps to 404 - Use map_thread_err in submit_user_input API endpoint for consistent error response (404 for missing thread, 409 for conflict, etc.) instead of always returning 500
Clearing active_turn immediately breaks is_interrupt_requested detection in monitor_turn, causing turn status to be Completed instead of Interrupted. Let monitor_turn handle the cleanup after it detects the interrupt flag and performs full finalization with correct status, usage, and error.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The TUI engine already emits
EngineEvent::UserInputRequiredand theEnginehandle exposessubmit_user_input/cancel_user_input, but the runtime API layer (used by external GUI clients like VSCode extensions) was missing the plumbing to propagate these events or accept responses. This meantrequest_user_inputtool calls would hang indefinitely in GUI mode with no dialog appearing.Changes
1.
approval.rs— Timeout protection forawait_user_inputUSER_INPUT_TIMEOUT) around therx_user_input.recv()callStatusevent and returns aToolError2.
runtime_threads.rs— Event forwarding + manager methods + interrupt fixEngineEvent::UserInputRequiredin the event loop, emitting a"user_input.required"SSE event with the input ID and full request payload (questions, options)submit_user_input()andcancel_user_input()onRuntimeThreadManagerthat delegate to theEnginehandleinterrupt_turn()now immediately clearsactive_turnand emits"turn.completed"so the thread accepts new messages after/interrupt— this prevents persistent 409 "Thread already has an active turn" errors3.
runtime_api.rs— REST endpoint for user input submissionPOST /v1/user-input/{thread_id}/{input_id}endpoint{ "answers": [{ "id": "...", "label": "...", "value": "..." }] }RuntimeThreadManager::submit_user_input()Flow
Testing
cargo check -p codewhale-tuipassescargo clippy -p codewhale-tui --all-targetspasses (no new warnings)Related
approval.requiredSSE +POST /v1/approvals/{id}) that already works for tool authorization dialogs