This repository has no description

Stop an abandoned chat turn from blocking the next one master

Closing a tab mid-reply left chat unusable for up to a minute. The turn holds a global slot, and the only release paths were finishing normally or noticing a failed SSE write. Neither fires promptly: Mist keeps the SSE process alive after a disconnect, and writes to a half-closed socket keep succeeding, so the turn just runs to completion while every new message gets 409 AGENT_BUSY. A new turn now signals the incumbent to stop and takes the slot. Two things had to change for that signal to land: - Cancel flags moved from the process dictionary to ETS keyed by pid. The process dictionary is per-process, so one turn could never cancel another. - The SSE process claims ownership itself via claim_turn/0. try_acquire_turn/0 runs in Mist's per-request handler process, which is not the process that blocks on the model, so the pid it recorded was never the one to cancel. Also shortens the heartbeat from 15s to 5s, which is what gives the incumbent a chance to observe the cancel flag between model chunks. Strict serialization is gone by choice: for a single household, blocking the person is worse than the interleaving it prevented. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>


+77 -12
2 changed files