Repository navigation
Coalesce a burst of the user's messages into one turn - #682
Conversation
A burst typed in a row opened one turn per line, so the Bot started on the first line and then took the next ones as separate work (#642). In a Bot's own chat the host now holds the user's lines for 1500 ms and opens one turn with them in arrival order, each on its own line. A line that arrives while a turn runs still lands as its own queued item, a Bot-to-Bot delivery never waits behind the window, and a group room keeps its round rules.
Lint: Identifier 'randomUUID' is imported but never used.
|
Verdict: INC at eff9f5a Reviewed at this tip only. All 9 checks are Blocker: the window can report a delivered turn while the user's line is thrown away
Probe (same stub of This is a user-visible regression in the direction the PR is meant to improve: a Bot whose model is not set up (or whose capability install throws) silently eats what the user typed, and the UI shows the line as accepted. The case where a turn starts inside the window is the same defect with a caller available — Fix
Non-blocking
Risk: T3 ( |
The settle window answered ok(true) and swallowed a prompt error, so a line the host could not deliver disappeared while the chat showed it as sent, and the held lines were dropped before the prompt ran. flushSettled() now keeps them, re-arms the window a few times, and rethrows so the send path answers the caller the error instead of ok; the lines go out with the next line after the retries (#682).
|
Verdict: PASS at a3cbbcd Ran:
Not run:
Reviewed at this tip only. All 9 checks are The INC at
Red without the source change: with Non-blocking
Risk: T3 ( |
Fixes #642
Tip SHA: a3cbbcdc848afa1b21abfce0d9c15061669b205aReproduce
Send three short lines to one Bot in its own chat, a few hundred milliseconds apart. Each
sendreachesPOST /api/boton its own (the composer posts one card per line) and the host opened a turn per line: three prompts, three turns, so the Bot starts on the first line and then takes the second and third as separate work.core/test/settle.test.js, "three lines inside the window open one turn, in arrival order", reproduces it: withcore/src/host/channel.jsfrommainit records three prompts; with this change it records one.What changed
Update at
a3cbbcdc— the #682 INC: a held burst is no longer dropped when the prompt fails.flushSettled()takes the lines, and on an error puts them back at the front (a line that arrived meanwhile stays behind them in order), re-arms the window while the failures are belowSETTLE_RETRIES(3), and rethrows. The send path that was waiting for an answer therefore gets the error (bot/refused, asmaindoes) instead ofok(true), so a line the host could not deliver is never reported as sent; past the retries the kept lines go out with the user's next line instead of retrying forever. Two cases pin it: a failed flush delivers nothing and the line goes out on the retry, and a failed flush on the send path answersok: falsewithbot/refusedwhile the kept line still goes first afterwards.core/src/host/channel.js:SETTLE_MS(1500 ms) and one settle timer per Session. In a Bot's own chat (rt.roomOf(sessionId) === undefined) a user line arriving while no turn runs is held, further user lines join it, and the timer opens one turn whose text is those lines joined by\nin arrival order — no sender labels, no "read N messages as one" notice, no new setting, no i18n. A line arriving while a turn runs is not held: the held lines are flushed first (so the queued items keep arrival order) and that line lands as its own queued item, as onmain. A Bot-to-Botdelivernever goes through the window (its own queue and Bot-to-bot reports duplicate and pile up because cross-line delivery only goes through the parent chain #641 dedupe stay its own). A group room keeps its round rules — its line must reach the Session at once so a running round can drain it (Face rooms: a plain line should be answered by the Bot(s) it is for, not by every Bot (follow-up to #295) #299) — so the window is only reached when the Session has no room. The pending timer is cleared on dispose.core/test/settle.test.js(new, 5 cases) and one line incore/test/install.test.js's registration-order snapshot (effect ds-bot: settle window).docs/subsystems/core-host.md: new section "A burst of the user's lines (A burst of messages opens one turn per message; there is no receive buffer #642)".changelog.d/642-settle-window.changed.md.patches/ds-bot/regenerated for the two upstream files (src/host/channel.jsin0005-social-seams,test/install.test.jsin0001-core-fixes) and the new test asfiles/test/settle.test.js.What I ran
At
a3cbbcdc:TZ=UTC DSH_HARNESS=/opt/flybot node --import ./test/harness-resolve.mjs --test test/settle.test.js→ 7/7 pass (the 5 acceptance cases plus the two INC cases).test/rounds.test.js test/install.test.js→ 49/49 pass (rounds 38, install 4, settle 7).ds-bot/+patches/ds-bot/files/+ all 10 patches and compared it byte for byte withcore/→ core/ equals ds-bot/ + patches/ds-bot/ (thecheckhalf ofds-bot-patches.mjs; this box has nogit, andds-bot/is untouched, so the pin-tree check is CI's).node .github/scripts/changelog.mjs check→ 10 fragments well formed.node --checkon both changed JS files.Red without the source change
Restore
core/src/host/channel.jsto9393d558and keep the new tests:test/settle.test.js→ 3 of 7 fail. The headline case records 3 prompts instead of 1; a single line opens its turn before the window; a burst that contains a Bot-to-Bot line opens its prompt during the burst. The four that still pass cover behaviour this issue keeps unchanged or adds no failure path (a line after the window is its own turn, a line arriving while a turn runs is its own item, and the two INC cases cannot fail where nothing is ever held).Restore only this PR's settle change to the previous tip
eff9f5ab(#682's subject) and keep the new tests:test/settle.test.js→ 2 of 7 fail, exactly the two #682 cases — the failed flush delivered nothing but the line never went out on the retry, and the send path answeredok: truefor a line it had lost.Not run
npm run verifyin full: this box has nocore/node_modules(nonpm ci) and nogit, sooxlint,arch-docs(cannot diff against HEAD),build-client --checkand the plugin suites cannot run here. CI'stests-okandpackagejobs run them.dev/bench.sh): not run — the bench needs a pnpm profile install this box cannot do, and CI does not run it. The issue's acceptance cases are covered by the deterministic-clock unit tests above.client.jsrebuild, sobuild-client --checkis unaffected.Risk
.github/agent/risk-rules.json(core/src/host/channel.jsis on the T3 path list); therisk-tierjob summary is authoritative.bot/refusedrather thanok, which is a visible change only in that failure case.