SIGN IN SIGN UP

Queue messages to a busy bot and send them when it settles (#220)

A message sent mid-turn used to bounce with a 409 and a 'try again
later'. Now it lands in the transcript immediately — persisted, marked
queued — and auto-sends when the bot settles: every queued message for
the thread drains into ONE follow-up turn (texts joined), so a burst of
steering notes costs one turn. Stop-then-steer is deliberate: an
interrupted turn drains too, because these are the user's own words, not
a bot's fan-out. The queue itself is memory-only on purpose — each
queued message is already an ordinary persisted thread message, so a
restart loses only the auto-send intent, never the words, and the client
shows the queued affordance only while the bot is busy so a stranded
flag is invisible rather than a false promise.

Drained turns are plain attended turns: no automationSource, no
unattended marking, no comms depth — exactly what typing the same words
into an idle bot would run. Drain triggers on turn.completed and on the
two settle paths that never emit it (dispatch failure, provider reload).
1:1 chats only; rooms keep their existing client-side hold-one behavior.

branching.test.ts's 'second send while busy is 409' assertion encoded
the old contract; it now asserts 202 + queued + still exactly one live
turn, and stops the drained turn before the edit-fork half of the test.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
M
Milind Soni committed
0024d14ccdd9f970cebd95e50fcf4646b6897450
Parent: d129960
Committed by GitHub <noreply@github.com> on 8/18/2026, 5:09:40 AM