Repository navigation
Conversation
After LAN⇄Tailscale retarget the client armed a 30s settle that called session.interrupt on silence. That aborted live provider waits and the host mislabeled them as user_stop / explicit stop requested. - Post-retarget rejoin uses the full idle watchdog - Idle watchdog fails the local stream only (no server interrupt) - Real Stop still interrupts and is logged in Diagnostics - Unit tests assert watchdog does not interrupt; cancel still does
|
🤖 Hermes-Relay automated PR intake Thanks for addressing the Android idle/retarget watchdog interruption behavior! This targets Please fill in the remaining intake evidence using the PR template:
A maintainer will review the implementation, compatibility, and verification evidence; this is intake only, not a code review. |
|
Ran into this exact failure mode. Sharing what I saw: Two things from that experience worth weighing before this merges: This PR keeps failFromTransport("Gateway turn timed out") on expiry, so the client-side turn still dies after 180s of quiet. The server work continues, but the app shows the turn as failed and the user loses the view of it. For long prefill (a big prompt where the provider thinks for minutes before the first token) or a long quiet background run, the visible symptom survives the fix. Would you consider not failing the local stream either, and letting settleFromAuthoritativeSessionState or a real disconnect handle a genuinely dead gateway? The per-event timeouts (watchdogTimeoutFor and the ASK_* / COMPACTING constants) only move the deadline, so they dont stop the kill. And since this PR removes the kill, they have nothing left to do, so they could go too. +1 on the Server Ownership model. I tend to run overnight runs, and its really discouraging to see them getting interrupted :/ |
|
Thanks for writing this up — and especially for the concrete timings (240s / 241s / 313s) and the host log shape. That matches the failure mode this PR is aimed at: the client idle path was effectively forging a user Stop ( On the two follow-ups: 1. Still failing the local stream on idle The direction we want next is closer to what you suggest: on idle expiry, don’t invent failure — query authoritative session state (
I’d rather land that as a small follow-up than expand this PR’s diff mid-review, so the interrupt vs Stop split stays easy to review. Happy to take a patch or issue link if you already have a sketch. 2. Per-event timeouts ( Wire note (unchanged here): Thanks again for the field report and for +1’ing the ownership model — this kind of overnight dogfood signal is gold. |
|
Closing in favor of maintainer consolidation #694. #694 already adapts the useful parts of this PR (cancellation-only Core policy here:
…is covered more completely by #694 once that lands. Leaving this open would only fight the same Not merging this branch on top of #694. |
Summary
After a LAN⇄Tailscale route retarget mid-turn, the Android client armed a 30s settle watchdog that called
session.interrupton silence. That aborted live provider waits (e.g. waiting on the model with no tokens yet). The host then default-labeled the interrupt as user_stop / "explicit stop requested" even though the user never pressed Stop.Fix
session.interrupt.chat_user_stop).idle_watchdogvsuser_stop.Why this ownership model
Tests
idle watchdog fires when events stop flowing— stream error, nosession.interruptnon compacting status keeps the ordinary watchdog— samecancel sends session interrupt— still interruptsactive route retarget … preserves the live turn— still passesNotes
Wire
session.interruptstill forbids extra keys (extra=forbid), so interrupt reason is log-only on Android until a host contract change acceptsreason/source.