Skip to content

Commit 1d19eab

Browse files
h5kkclaude
andcommitted
tui: raise stream stall timeout from 2 to 5 minutes
The client-side stall watchdog in `detect_and_cancel_stall` cancelled any turn whose server stream went silent for 120s. Reasoning-heavy models (GPT-5.5 with high effort, Claude extended thinking, Gemini deep mode) can legitimately stay silent on the wire for several minutes during a single internal step, especially with non-trivial input contexts. Repro from `~/.jcode/logs/jcode-2026-04-28.log`: three "Stream stall detected: no server events for Some(120.x s), cancelling" warnings during a single GPT-5.5 session over persistent WS, all firing exactly at 120s with no upstream error. Bump the threshold to 300s. WS dead-connection detection is independent (`provider::openai::persistent_ws_idle_*`), so this only affects the "model is thinking quietly" case. A future improvement could plumb provider-side reasoning-preview events through to reset the watchdog on signal rather than time, but a wider window covers the common case today. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ad139a9 commit 1d19eab

1 file changed

Lines changed: 6 additions & 1 deletion

File tree

src/tui/app/remote.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,12 @@ pub(super) async fn process_remote_followups(app: &mut App, remote: &mut RemoteC
777777
}
778778

779779
async fn detect_and_cancel_stall(app: &mut App, remote: &mut RemoteConnection) {
780-
const STALL_TIMEOUT: Duration = Duration::from_secs(2 * 60);
780+
// Reasoning models (GPT-5.5 with high effort, Claude with extended thinking,
781+
// Gemini deep mode) can stay silent on the wire for several minutes during
782+
// a single internal step. The previous 120s was too aggressive and caused
783+
// legitimate turns to be cancelled mid-thought. WS-level health (idle
784+
// ping/pong) is handled separately in `provider::openai::persistent_ws_*`.
785+
const STALL_TIMEOUT: Duration = Duration::from_secs(5 * 60);
781786
let is_running_tool = matches!(app.status, ProcessingStatus::RunningTool(_));
782787
if app.is_processing && !is_running_tool {
783788
let stalled = app

0 commit comments

Comments
 (0)