feat(kiloclaw): deliver morning briefing to configured channels#2813
feat(kiloclaw): deliver morning briefing to configured channels#2813
Conversation
Send generated briefings to configured Telegram, Discord, and Slack routes with channel-friendly formatting and delivery status reporting so users can receive briefings where they work. Add robust routing, timeout/retry hardening, and run-path warmup handling so generation success is decoupled from delivery flakiness.
Split command and channel-delivery concerns into dedicated modules, tighten timeout retry semantics, and reuse shared UI typing to reduce schema drift. Add cron JSON compatibility fallback to avoid controller/runtime option skew.
Render morning briefing delivery failures with reason-only text in Settings so stored command errors remain available for diagnostics without leaking message content in the dashboard.
Treat gateway and briefing readiness as boot-session fresh data to avoid stale Disabled flaps, and clear cached gateway/morning-briefing queries on start, provision, and restarts so controls remain in warmup state until current boot data arrives.
Stop emitting synthetic enabled=false during morning-briefing warmup and treat gateway_warming_up as authoritative in the dashboard card. Keep warmup badge styling and delivery visibility gated until status fields are resolved to prevent transient Disabled and Last delivery flaps.
Move Last delivery beneath Last generated, render channel/status labels with user-friendly capitalization, and top-align action buttons so the card layout stays consistent as metadata lines appear.
Add a topical Morning Briefing icon, keep delivery labels user-friendly and capitalized, and place the source summary in the same content column so metadata lines share a consistent leading edge.
Render Morning Briefing Last delivery entries as provider-first labels with status in parentheses while keeping the bullet delimiter for readability.
Rename the report heading to Failures and keep the section omitted when no failures exist so the daily briefing body stays concise and focused.
| } | ||
|
|
||
| function convertInlineMarkdownToText(line: string): string { | ||
| const withLinksExpanded = line.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1 - $2'); |
There was a problem hiding this comment.
WARNING: Markdown link conversion breaks valid URLs containing )
formatBriefingMarkdownForMessage() expands links with \[([^\]]+)\]\(([^)]+)\), which stops at the first closing parenthesis. Any briefing item whose URL includes ) (common in docs and wiki links) will be truncated before delivery, so the channel message contains a broken target even though the saved markdown is correct.
There was a problem hiding this comment.
Fixed in 4e845d2e7. Replaced regex-only link expansion with a balanced-parentheses parser in briefing-utils.ts and added regression coverage in briefing-utils.test.ts for URLs containing nested ) so channel messages preserve full links.
Code Review SummaryStatus: 1 Issue Found | Recommendation: Address before merge Overview
Issue Details (click to expand)No new issues in the incremental diff. Other Observations (not in diff)Issues found in unchanged code that cannot receive inline comments:
Files Reviewed (3 files)
Reviewed by gpt-5.4-20260305 · 814,836 tokens |
Replace regex-only markdown link expansion with a balanced-parentheses parser so channel messages keep full URLs when links contain nested parentheses.
Use endpoint-specific warmup retry policy so morning-briefing run no longer retries timeout errors that can overlap in-flight runs and duplicate sends. Return a dedicated run-timeout response code for clients.
Extract morning briefing card state derivation and add regression coverage for stale enabled values plus gateway_warming_up payloads so the card stays in warmup state instead of flashing Disabled.
Store concise delivery failure details instead of full command text to reduce sensitive payload exposure while preserving operator diagnostics. Update lifecycle assertions to match sanitized error persistence.
Rename timeout test semantics, add focused delivery-utils unit coverage, and emit structured delivery outcome events for sent/skipped/failed paths. Include latest Morning Briefing warmup/source-summary alignment tweak in the same push-ready set.
| const DELIVERY_CHANNELS = ['telegram', 'discord', 'slack'] as const; | ||
| const DELIVERY_STATUSES = ['sent', 'skipped', 'failed'] as const; | ||
| const DELIVERY_REASONS = [ | ||
| 'missing_target', | ||
| 'ambiguous_target', | ||
| 'send_failed', | ||
| 'config_unavailable', | ||
| ] as const; |
There was a problem hiding this comment.
Would be good if we didn't have to duplicate these here and in services/kiloclaw/plugins/kiloclaw-morning-briefing/src/delivery-utils.ts
Extract delivery channel/status/reason enums into a shared module and reuse them in gateway response schemas and plugin delivery utilities to prevent drift.
4c0a8ce to
384cc0d
Compare
This reverts commit 384cc0d.
Summary
Verification
Visual Changes
Reviewer Notes
style(web): apply formatting for morning briefing UI) was added to satisfy pre-push hooks..plans/morning-briefing-channel-delivery.mdis intentionally not included in this PR.