feat(cron): optional threaded delivery (summary parent + detail in thread) - #44537
feat(cron): optional threaded delivery (summary parent + detail in thread)#44537just-code-in wants to merge 1 commit into
Conversation
…hread Adds cron.threaded_delivery (default false). When enabled, Slack cron reports post a compact summary (agent-written TL;DR: paragraph, or first paragraph as fallback) as the parent message and the full report in its thread. Per-job opt-out via "thread": false. Any failure falls back to the existing flat delivery. Platforms other than Slack are unchanged.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the focused Slack delivery proposal. The summary-parent/detail behavior is not present on current main; #56254's cron_continuable_surface: in_channel is a different flat-continuation feature (website/docs/user-guide/features/cron.md:334-370).
Problems
- The PR targets the old live-adapter path. Current main routes cron text through
DeliveryRouter(cron/scheduler.py:1694-1712) and has confirmation/timeout handling through:1721-1811; the new directadapter.sendsequence (cron/scheduler.py:741, invoked at:907in the PR) needs to be rebuilt on that path. _send_threaded_via_adapterretries flat after any timeout (cron/scheduler.py:736-739in the PR). Current main only falls back when cancellation proves dispatch never started (cron/scheduler.py:1721-1761); otherwise retrying can duplicate an in-flight detail message.cron.threaded_deliveryneeds a default inhermes_cli/config.pyand user documentation; the PR changes only the scheduler and tests.
Suggested changes
- Preserve
DeliveryRouterrouting and current timeout semantics for both sends, then add current-path tests for queued versus in-flight timeouts and media. - Document the Slack/live-adapter scope, including the separate desktop standalone path described in
hermes_cli/web_server.py:136-148and related #46207.
Automated hermes-sweeper review.
| try: | ||
| return future.result(timeout=60) | ||
| except TimeoutError: | ||
| future.cancel() |
There was a problem hiding this comment.
Do not unconditionally fall back after this timeout. cancel() returning false means the send is already in flight, so a flat retry can duplicate the detail; current main explicitly distinguishes those cases in cron/scheduler.py:1721-1761.
| and _threaded_delivery_enabled(job) | ||
| ): | ||
| try: | ||
| sent_threaded = _send_threaded_via_adapter( |
There was a problem hiding this comment.
This needs to be reworked around current main's DeliveryRouter path rather than calling adapter.send directly. The current live cron path preserves target routing and confirmation/fallback semantics in cron/scheduler.py:1694-1811.
What does this PR do?
Cron reports currently post to channels as a flat burst — the whole report is sent in one
send()call and the platform adapter splits it into multiple top-level messages. This adds an opt-in threaded delivery mode for platforms that support it (Slack initially):cron.threaded_delivery: true(config, default false) posts a compact parent message — the report'sTL;DR:/TLDR:/Summary:first paragraph (marker stripped), or the first paragraph as fallback — and the full report as replies in its thread."thread": falseon any job definition.Related Issue
Fixes #
Type of Change
Changes Made
cron/scheduler.py: add_split_summary(),_threaded_delivery_enabled(),_send_threaded_via_adapter(); wire threaded path into_deliver_result()behind platform + config gatetests/cron/test_threaded_delivery.py: 24 new tests covering split semantics, config gate, threaded sequence, fallbacks, media-in-thread, origin-thread passthrough, and non-Slack unaffectedHow to Test
cron: threaded_delivery: trueto~/.hermes/config.yaml"thread": falseto a specific job; confirm that job delivers flat even with the global flag onpytest tests/cron/test_threaded_delivery.py tests/cron/test_scheduler.py -q— 158 tests passChecklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/A (cron.wrap_responseis also undocumented in the example; following that precedent)CONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AScreenshots / Logs
Ran on a 4-profile deployment since 2026-06-11. Representative log line:
🤖 Generated with Claude Code