Scheduled pushes deliver silently (no streaming) #30

Closed
opened 2026-07-05 12:54:22 +08:00 by weiwen · 1 comment
Owner

What to build

Scheduled/proactive pushes (the scheduler_taskdelivery_consumer path) should deliver a single, clean message instead of streaming. Today they run the same pipeline as interactive messages: an immediate placeholder (which fires a Telegram notification with no content), a typing indicator, and live throttled edits as pi streams.

Scheduled pushes should instead be fully silent until pi finishes — no placeholder, no typing indicator, no live edits — then send one fresh message with the final answer (or the error). Interactive messages are unchanged: they keep streaming exactly as they do now.

Structure the shared delivery pipeline as two entry points plus a shared tail:

  • deliver_streaming — interactive path, current behavior unchanged.
  • deliver_silent — scheduled path. Awaits pi inline with a throwaway snapshot channel (drop the receiver up front; pi's snapshot sends already fail harmlessly), so no tokio::spawn / select! / edit loop. Renders into an empty MessageView so pages send fresh; errors send fresh too.
  • render_final — shared tail taking the already-awaited result: paginate → send pages → source buttons on the last page on success, or the plain error notice on failure (respecting expose_errors).

delivery_consumer calls deliver_silent; the interactive handler calls deliver_streaming.

No trait or enum DeliveryMode — the mode is a structural fact of the call site, not a per-message runtime choice. An enum can be introduced later if a runtime mode decision (e.g. a per-schedule stream flag) ever appears.

Acceptance criteria

  • Scheduled pushes send no placeholder and no typing indicator; nothing appears in the chat until pi completes.
  • On success, a scheduled push lands as a single fresh message (multi-page split preserved for long answers, source-note buttons preserved on the last page).
  • On error, a scheduled push sends a fresh error message honoring expose_errors (verbatim vs. "Something went wrong. Your session has been reset.").
  • Interactive Telegram messages stream exactly as before (placeholder, typing, live edits, final authoritative render) — no regression.
  • Shared final-render logic (pagination, source buttons, error rendering) is not duplicated between the two paths.
  • CONTEXT.md is updated: the delivery_consumer description and the pi.rs/telegram architecture notes reflect that scheduled pushes deliver silently rather than via the streaming pipeline.

Blocked by

None - can start immediately

## What to build Scheduled/proactive pushes (the `scheduler_task` → `delivery_consumer` path) should deliver a single, clean message instead of streaming. Today they run the same pipeline as interactive messages: an immediate `…` placeholder (which fires a Telegram notification with no content), a typing indicator, and live throttled edits as `pi` streams. Scheduled pushes should instead be **fully silent until `pi` finishes** — no placeholder, no typing indicator, no live edits — then send **one fresh message** with the final answer (or the error). Interactive messages are unchanged: they keep streaming exactly as they do now. Structure the shared delivery pipeline as two entry points plus a shared tail: - `deliver_streaming` — interactive path, current behavior unchanged. - `deliver_silent` — scheduled path. Awaits `pi` inline with a throwaway snapshot channel (drop the receiver up front; `pi`'s snapshot sends already fail harmlessly), so no `tokio::spawn` / `select!` / edit loop. Renders into an empty `MessageView` so pages send fresh; errors send fresh too. - `render_final` — shared tail taking the already-awaited result: paginate → send pages → source buttons on the last page on success, or the plain error notice on failure (respecting `expose_errors`). `delivery_consumer` calls `deliver_silent`; the interactive handler calls `deliver_streaming`. No trait or `enum DeliveryMode` — the mode is a structural fact of the call site, not a per-message runtime choice. An enum can be introduced later if a runtime mode decision (e.g. a per-schedule `stream` flag) ever appears. ## Acceptance criteria - [ ] Scheduled pushes send no `…` placeholder and no typing indicator; nothing appears in the chat until `pi` completes. - [ ] On success, a scheduled push lands as a single fresh message (multi-page split preserved for long answers, source-note buttons preserved on the last page). - [ ] On error, a scheduled push sends a fresh error message honoring `expose_errors` (verbatim vs. "Something went wrong. Your session has been reset."). - [ ] Interactive Telegram messages stream exactly as before (placeholder, typing, live edits, final authoritative render) — no regression. - [ ] Shared final-render logic (pagination, source buttons, error rendering) is not duplicated between the two paths. - [ ] CONTEXT.md is updated: the `delivery_consumer` description and the pi.rs/telegram architecture notes reflect that scheduled pushes deliver silently rather than via the streaming pipeline. ## Blocked by None - can start immediately
Author
Owner

Implemented on branch sandcastle/issue-30 (commit c069297).

Changes:

  • Split deliver_response into deliver_streaming (interactive, unchanged behavior) and deliver_silent (scheduled path: no placeholder, no typing indicator, no live edits)
  • Added render_final shared tail: paginate → send pages → source buttons on success, plain error notice on failure; works for both paths via MessageView
  • Added MessageView::empty() so the silent path sends all pages as fresh messages
  • delivery_consumer now calls deliver_silent; handle_message calls deliver_streaming
  • CONTEXT.md updated: telegram/mod.rs and pi.rs architecture notes reflect the new split

No enum/trait for delivery mode — the mode is structural at the call site as specified. CI must validate compilation (no Rust toolchain in sandbox).

Implemented on branch sandcastle/issue-30 (commit c069297). Changes: - Split deliver_response into deliver_streaming (interactive, unchanged behavior) and deliver_silent (scheduled path: no placeholder, no typing indicator, no live edits) - Added render_final shared tail: paginate → send pages → source buttons on success, plain error notice on failure; works for both paths via MessageView - Added MessageView::empty() so the silent path sends all pages as fresh messages - delivery_consumer now calls deliver_silent; handle_message calls deliver_streaming - CONTEXT.md updated: telegram/mod.rs and pi.rs architecture notes reflect the new split No enum/trait for delivery mode — the mode is structural at the call site as specified. CI must validate compilation (no Rust toolchain in sandbox).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
weiwen/evie#30
No description provided.