Repository navigation
Send Gradius dialogue banners as rich messages after the answer - #282
Merged
Merged
Conversation
Gradius now returns a `banner` placement from the dialogue endpoint: rich
HTML for sendRichMessage plus URL buttons. The bot sends it as its own
message after the dialog answer instead of appending it to the answer.
- The client decodes `banner` next to `native-text-ad`; a flat button list
becomes one button per row.
- The banner HTML passes the rich-message allowlist unchanged otherwise;
a `<footer>Реклама</footer>` label is added only when it is missing.
Buttons must be HTTPS, and other methods or message types are rejected
as render errors.
- The banner goes to its own outbox batch `gradius-banner:v1:{bot}:{job}`
with the answer's ordering key, so it is delivered after the answer and
a failed banner never fails the dialog job. The batch and the queued
state are written in one transaction.
- Answer-batch reconciliation skips banners, so a delivered answer cannot
mark an unsent banner as shown; banner batches resolve like utility ads.
Owner
Author
|
Danger "Large PR" warning: this is one feature and it is not split. About 560 of the added lines are code (decoder, rendering, outbox batch, reconciliation guards); about 740 are tests, including a captured live API response used as a fixture. Splitting the decoder from delivery would ship a placement type that the bot cannot send. |
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.
Gradius now returns a
bannerplacement from/v1/native/dialogue_model/chat: rich HTML forsendRichMessageand a list of URL buttons. The bot now sends it as a separate rich message right after the dialog answer. Text ads (native-text-ad) still go to the end of the answer as before.Banner rendering
GradiusPlacement::Banneris decoded next tonative-text-ad; the first supported entry wins. A flatinline_keyboardlist becomes one button per row; nested rows are kept.sanitize_rich_html). The bot adds<footer>Реклама</footer>only when the banner has no footer. Banners get no 📢 label and no VIP spoiler, so the advertiser layout stays as sent.sendRichMessage, a message type other thanhtml, empty content after sanitizing, a button that is empty or not HTTPS, or content over the rich-message limit.disable_notification, because the answer already notified the user.Delivery and accounting
gradius-banner:v1:{bot}:{job}(dialog_job_idNULL) with the answer's ordering keydialog:{bot}:{chat}:{thread}. The outbox claims one ordering key in FIFO order, so the banner is delivered after the answer, and a failed banner never fails the dialog job.enqueue_dialogue_bannerinserts the batch and setsdelivery_state = 'queued'in one transaction. The banner is queued only after the answer was accepted; if the answer enqueue fails, the banner is marked failed and is not sent.reconcile_dialogue_delivered,reconcile_dialogue_delivery_failedand the pending-slot fallback skipselected_placement->>'type' = 'banner'. Without this, delivery of the answer would mark a banner shown before it was sent. Banner batches resolve like utility batches (mark_delivered_by_batch/mark_delivery_failed_by_batch, plus the missed-callback scan).insert_indexNULL).unsupported_surface.Verification
tools/rust-fast-gate.sh:cargo fmt --all -- --check,cargo clippy --locked --workspace --all-targets --all-features -- -D warnings,cargo test --locked --workspace: 2677 tests passed.pgvector/pgvector:pg17: the newpostgres_dialogue_banner_resolves_only_through_its_own_batch(answer reconciliation ignores the banner, atomic and idempotent enqueue, chat mismatch rejected, delivery by the banner batch) and the outbox/Gradius tests (outbox_roundtrip_is_idempotent_ordered_and_fenced,postgres_gradius_receipts_confirm_delivery_and_recover_missed_callbacks, thelive_storage tests) pass.postgres_store_holds_one_slot_until_ad_delivery_is_terminalfails locally: its own raw insert of atelegram_outboxrow dated 1970 hits "no partition of relation telegram_outbox" (the table is partitioned by day since migration 206). This PR does not change that insert; CI does not run the test.[]; an assistant turn containing&&&banner&&&returned onebannerentry. That body is theLIVE_TEST_BANNER_RESPONSEfixture: the rendered HTML equals the provider HTML except<br>→<br/>, with three collage images, one footer and two button rows.&&&banner&&&(not HTML-escaped); a failed answer enqueue closes the banner without queueing it.