fix(api): bound run-ui-command waits and always disconnect the listener#45
fix(api): bound run-ui-command waits and always disconnect the listener#45herikwebb wants to merge 4 commits into
Conversation
wait_for_run_ui_command_response polled forever with no timeout and, unlike its sibling wait_for_chat_user_input, had no try/finally around the signal disconnect. If the browser tab that must answer a UI command disappears (page reload, closed websocket), the request thread kept spinning at 10 Hz indefinitely with the tool loop wedged, and any exception or task cancellation leaked the callback onto the signal. Add a timeout (default 1800s via NBI_RUN_UI_COMMAND_RESPONSE_TIMEOUT, generous because run-cell legitimately blocks for the duration of a long-running cell; <= 0 disables) that raises TimeoutError, and disconnect the listener in a finally block on every exit path.
Automated PR ReviewModel: Changed files: Review result: Automated PR Review FindingsMedium —
|
Review follow-ups (PR #45): - NBI_RUN_UI_COMMAND_RESPONSE_TIMEOUT is read at import time; a malformed value ('', '30s') raised ValueError and blocked the backend from starting. Parse via _float_env, which warns and falls back to the 1800s default. - Deadline arithmetic moves from time.time() to time.monotonic() so NTP adjustments or a VM suspend/resume can't fire the timeout early or defer it indefinitely.
Automated PR ReviewModel: Changed files: Review result: FindingsMedium —
|
Review follow-up (PR #45): the wait loop used None both as the 'no response yet' sentinel and as a possible payload, so a void UI command that legitimately responds with result=None (JSON null) was ignored and the wait ran into the timeout. Use an identity sentinel object instead and cover the None-result case with a test.
Automated PR ReviewModel: Changed files: Review result: Findings
|
Review follow-up (PR #45): float('nan') fails every 'timeout > 0' comparison and float('inf') never elapses — either silently disables the bound this timeout exists to enforce. Reject non-finite values via math.isfinite and fall back to the default; a finite <= 0 remains the documented disable switch.
Automated PR ReviewModel: Changed files: Review result: No automated findings were found. Residual risks: this change introduces a new timeout behavior for UI command round trips, so very long-running frontend commands may now fail unless |
Problem
wait_for_run_ui_command_responsepolled forever with no timeout and, unlike its siblingwait_for_chat_user_input, had notry/finallyaround the signal disconnect. If the browser tab that must answer a UI command disappears (page reload, closed websocket), the request thread kept spinning at 10 Hz indefinitely with the tool loop wedged, and any exception or task cancellation leaked the callback onto the signal.Change
NBI_RUN_UI_COMMAND_RESPONSE_TIMEOUT;<= 0disables) raisingTimeoutError. Generous default becauserun-celllegitimately blocks for the duration of a long-running cell.finallyon every exit path — return, timeout, and task cancellation.Testing
Full Python suite passes (1298 tests).