Repository navigation
feat(images): every picture is queued and delivered in the background, so a slow render can no longer end an agent turn (Refs #799, #938) - #970
Merged
Conversation
…elivery (Refs #799) Asynchronous AI pictures need a durable record of how far each one got, so the next process can finish, expire or mark it unknown after a crash instead of losing it or sending it twice. Migration 070 adds image_deliveries, and ImageDeliveryRepository sits over it: a deterministic id, a forward-only advance() that is the single claim on a send, a finish() that never ends a claimed upload as expired or superseded, a note flag claimed once, and a query for failed/expired rows whose user was never told. The row also keeps the picture's slot, a hash of its render data and a rebuild counter. A picture is rebuilt when the calendar changes while it renders; rebuilt() records that before the new render starts, so a restart in between resumes the rebuilt job and not the stale one that already finished, and a delivery resumed after a restart is deduplicated or superseded like a live one. The migration was written as 068 on its branch and renumbered to 070 before it was ever released: main took 069 (chat_history.turn_order) meanwhile, and no stage or production database has applied the old name. Docs: docs/reference/migrations/070_image_deliveries.md. Review: single-seat Opus via omp (--pool 1), two rounds, because the Sol seat has no quota until 2026-11-09; the full-roster review is owed in #961. The first round's Medium (a restart during a rebuild sent the stale picture) is fixed here by the rebuilds column and rebuilt(); the second round found only Low documentation inaccuracies (retention wording, the slot comment, the rollback note for rows stuck in sending), corrected in the next commit.
…, so a slow render can no longer end an agent turn (Refs #799, #938) On 2026-11-01 the AI picture tools waited for the render inside the agent turn. On the loaded odroid a real render took 73-80 s, two waits plus the model rounds spent the whole 90 s turn budget, the answer validator timed out and the user got an aborted-run notice instead of the text the model had already written. The picture tools, /today, /tomorrow, /week, /month, the agenda buttons and the schedule comparison of an accepted invitation now only enqueue and return at once. ImageDelivery renders through BullMQ with a 150 s bound, sends the PNG as its own message and logs exactly one outcome per picture; every end the user must hear about gets one short note in their language (failed, timed out, too large, refused for good without an offer to ask again, upload cut off: may not have arrived, never sent again). A restart reads the durable image_deliveries rows (migration 070, repository from the previous commit): it resumes pictures still within their bound, tells the user once that the bot was restarting for the ones past it without a timeout alert, and marks an interrupted upload unknown without resending it. Limits: 2 pictures per chat and 12 on the bot; schedule comparisons have their own 4 per chat and 6 on the bot. A newer picture of the same slot is recorded superseded at the moment of replacement. An end the store refuses is written again three times and once more at shutdown. Permanent Telegram refusals raise no alert. Runbook, migration doc and CLAUDE.md describe the flow, the limits and the known gaps (#964, #967, #969). Version 0.3.6.
This was referenced Nov 5, 2026
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The AI picture tools, /today, /tomorrow, /week, /month, the agenda buttons and the schedule comparison of an accepted invitation now only enqueue a picture and return at once.
ImageDeliveryrenders through BullMQ with a 150 s bound, sends the PNG as its own message and logs one outcome per picture. Durable rows (image_deliveries, migration 070, in the first commit) let a restart resume, expire or mark unknown each picture without resending one.Why: on 2026-11-01 a render of 73-80 s inside the agent turn used the whole 90 s budget and the user got an aborted-run notice instead of the finished text.
Refs #799, #938. Known gaps and deferred review findings: #964, #967, #969. Full-roster review debt: #961.
Evidence