feat: concat chunked Telegram messages for multi-part pastes (#186) - #187
IliyaBrook wants to merge 2 commits into
Conversation
|
Hey, thank you for the PR Or maybe at least add a note to the docs. |
|
Good catch, thanks! You're right — I had the same thought after reading your example. I've lowered the default |
RichardAtCT
left a comment
There was a problem hiding this comment.
Good work — the buffer is well built and the tests drive real timers. Four things before I merge.
1. The join mashes words together. constants.py:94 justifies the 3000 threshold by saying clients split at paragraph and line boundaries. A client that splits there drops the separator. _pop_result then joins with "" (message_buffer.py:218), so the last word of one chunk runs into the first word of the next.
The threshold rationale and the join cannot both be right. Join with "\n", or keep "" and say why.
2. There is no off switch. chunk_buffer_threshold is clamped ge=2000 and there is no feature flag, so every message over 3000 characters now waits 0.5s and gets a "Receiving message…" send-and-delete. An operator cannot turn that off. Please allow 0 to disable.
Also: the description says the default is 4000, the code says 3000, and neither setting is in .env.example. Your tests all use 4000, so the shipped default is untested.
3. Timer-flushed runs skip the global lock. _on_buffer_flush runs _process_agentic_text in a detached task under a per-user lock only, outside StopAwareUpdateProcessor._sequential_lock. No deadlock, but two users Claude runs can now overlap where they could not before.
That may be fine, or even wanted — but it is a real change to how the bot serialises work and it is not mentioned. Tell me it is deliberate and I am happy.
4. Stop drops a pending buffer silently. orchestrator.py:1773 cancels the buffer, throws the result away, then replies "Already completed." A paste made during a flushed run disappears with no message.
Worth adding one orchestrator-level test too — the buffer itself is covered, the wiring is not.
Item 1 is the one that would bite users.
Summary
When a user pastes text longer than 4096 characters, the Telegram client silently splits it into multiple messages. Previously, each fragment triggered a separate Claude run — wasteful, slow, and producing poor results since Claude would see incomplete text fragments.
This PR adds a per-user debounce buffer that detects Telegram-split chunks (messages near the 4096-char limit), accumulates them, and submits the combined text as a single Claude request.
How it works
"".join()) since Telegram splits at character boundariesNew settings
CHUNK_BUFFER_TIMEOUT(default0.5) — seconds to wait for more chunksCHUNK_BUFFER_THRESHOLD(default4000) — min message length to trigger bufferingChanged files
src/bot/utils/message_buffer.py— newMessageBufferclasssrc/bot/orchestrator.py— extracted_process_agentic_text(), added buffer logic toagentic_text()src/config/settings.py— new settingssrc/utils/constants.py— new defaultstests/unit/test_bot/test_message_buffer.py— 20 unit teststests/unit/test_bot/test_middleware.py— fixture update for new settingsTest plan
Closes #186