# Sprint 003 — Agent Worker + Daily Telegram Digest **Depends on:** Sprint 002 (FTS, duration, view count, pagination) **Duration:** ~8h total **Goal:** Make the agent queue functional (LLM processing), and deliver a daily Telegram digest of new YouTube summaries. --- ## T3.1 — Implement agent_worker LLM processing - **Files:** `backend/agent_worker.py`, `backend/main.py` - **Done means:** `agent_worker.py` processes items from `agent_queue` with status=`pending`: - Calls local LLM (via `QWEN_BASE_URL` env) or DeepSeek API to process the queued note/prompt. - Stores result in `agent_queue.result` column. - Updates status: `pending` → `processing` → `done` (or `error`). - Runs as background loop every 30s. - **Verify by:** 1. Add item to agent queue via frontend "Save to Agent". 2. Watch status change to `processing` then `done` in queue tab. 3. `result` field populated with LLM response. - **Risk:** LLM endpoint may be unreachable from NAS. Use `AGENT_BASE_URL` env var with fallback to DeepSeek API. - [ ] T3.1 — Agent worker LLM processing ## T3.2 — Daily Telegram digest via cron - **Files:** New cron job in Hermes (not in repo — Hermes-managed) - **Done means:** Every morning at 8:00 AM CST (00:00 UTC), Hermes: 1. Calls `GET /api/videos?status=pending&limit=20` on t-youtube backend. 2. Groups by channel. 3. Formats and sends a Telegram digest message: channel name, video title, summary snippet. 4. Marks videos as `read` after sending (optional, or just inform). - **Verify by:** 1. Trigger cron manually → Telegram message received. 2. Message shows channel groupings, titles, and summaries. - **Risk:** t-youtube API behind Authelia — cron needs API token, not SSO. Use `API_TOKEN` env var. - [ ] T3.2 — Daily Telegram digest cron ## T3.3 — Duration + view count display in frontend - **Files:** `frontend/src/routes/YoutubeDashboard.svelte` - **Done means:** Video list items show duration (formatted as `MM:SS` or `H:MM:SS`) and view count (formatted as `1.2M`, `45K`) in the sidebar list item. - **Verify by:** 1. Open dashboard → sidebar shows duration + view count for videos where populated. 2. Videos with `duration=null` show nothing (no broken display). - **Risk:** Most existing videos don't have duration yet (only newly synced ones do). Display only if non-null. - [ ] T3.3 — Duration + views display in video list ## T3.4 — Search UX polish: debounce + loading state - **Files:** `frontend/src/routes/YoutubeDashboard.svelte` - **Done means:** - Search input debounced 300ms (no API call on every keystroke). - Loading spinner shows while fetching search results. - "No results" state when FTS returns empty. - **Verify by:** 1. Type quickly → only one API call fires (after 300ms pause). 2. Loading state visible while waiting. 3. Type nonsense → "No results" shows cleanly. - [ ] T3.4 — Search debounce + loading state ## T3.5 — Update active.md symlink to Sprint 003 - **File:** `docs/specs/active.md` - **Done means:** Symlink points to `sprint-003-agent-digest.md`. - **Verify by:** `ls -la docs/specs/active.md` → points to sprint-003. - [ ] T3.5 — Update active.md symlink --- ## Exit criteria - [ ] Agent queue processes items via LLM — status changes pending → done, result populated - [ ] Daily Telegram digest cron fires at 8 AM CST with grouped summaries - [ ] Duration + view count shown in video list (non-null only) - [ ] Search debounced, has loading state and empty state - [ ] All 23+ backend tests pass - [ ] Frontend builds cleanly