Skip to content

Commit ff5817b

Browse files
docs: update backlog tasks
1 parent fd8593a commit ff5817b

1 file changed

Lines changed: 94 additions & 60 deletions

File tree

β€Žbacklog/tasks/task-277 - Genius-playlist-creator.mdβ€Ž

Lines changed: 94 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@ title: Genius playlist creator
44
status: In Progress
55
assignee: []
66
created_date: '2026-02-18 05:58'
7-
updated_date: '2026-03-31 21:18'
7+
updated_date: '2026-03-31 21:27'
88
labels:
99
- feature
1010
- playlists
1111
- recommendation
12+
- agent
13+
- ollama
14+
- lastfm
1215
dependencies: []
16+
references:
17+
- docs/genius.md
1318
priority: high
1419
ordinal: 750
1520
---
@@ -39,7 +44,7 @@ Design document: `~/.claude/plans/steady-juggling-scroll.md`
3944
## Implementation Plan
4045

4146
<!-- SECTION:PLAN:BEGIN -->
42-
## Phase 1: Dependencies (DONE)
47+
## Phase 1: Dependencies (DONE β€” commit fc5846b)
4348

4449
Added to `crates/mt-tauri/Cargo.toml`:
4550

@@ -49,7 +54,7 @@ Added to `crates/mt-tauri/Cargo.toml`:
4954

5055
Verified: `cargo check --features agent` and `cargo check` (without) both compile.
5156

52-
## Phase 2: Types + Prompt + Module Scaffold (DONE)
57+
## Phase 2: Types + Prompt + Module Scaffold (DONE β€” commit 2f121f7)
5358

5459
Created `crates/mt-tauri/src/agent/` module with 3 files:
5560

@@ -73,7 +78,8 @@ Created `crates/mt-tauri/src/agent/` module with 3 files:
7378
### `mod.rs`
7479
- Module exports (`pub mod types; pub mod prompt;`)
7580
- `parse_agent_response()` β€” robust LLM output parser (handles brackets, preamble, mixed valid/invalid IDs)
76-
- Placeholder `agent_generate_playlist` and `agent_check_status` functions
81+
- `parse_model_names()` β€” extracts model names from Ollama /api/tags JSON
82+
- `has_default_model()` β€” checks if default model is in available list (base name match)
7783
- 8 unit tests for parser edge cases
7884

7985
### `lib.rs` wiring
@@ -82,67 +88,107 @@ Created `crates/mt-tauri/src/agent/` module with 3 files:
8288
- Graceful "not enabled" JSON response when feature is off
8389
- Commands registered unconditionally in `generate_handler!`
8490

85-
Verified: `cargo check --features agent`, `cargo check`, and 17/17 agent tests pass.
91+
## Phase 3: Tools (DONE β€” commit d9a37c9)
8692

87-
## Phase 3: Tools (`tools.rs`)
93+
Implemented 8 tools with Rig's `Tool` trait in `tools.rs`, each receiving `Arc<AgentContext>`:
8894

89-
Implement 8 tools with Rig's `Tool` trait, each receiving `Arc<AgentContext>`:
90-
91-
1. **GetRecentlyPlayed** β€” `db::favorites::get_recently_played`
92-
2. **GetTopArtists** β€” `db::stats::get_top_artists`
93-
3. **SearchLibrary** β€” `db::library::get_all_tracks`
94-
4. **GetSimilarTracks** β€” Last.fm `track.getSimilar` + library cross-ref
95+
1. **GetRecentlyPlayed** β€” `db::favorites::get_recently_played` with configurable limit/date range
96+
2. **GetTopArtists** β€” `db::stats::get_top_artists` with configurable limit
97+
3. **SearchLibrary** β€” `db::library::get_all_tracks` with keyword/artist/genre filters + limit
98+
4. **GetSimilarTracks** β€” Last.fm `track.getSimilar` + library cross-ref via `find_track_by_artist_title`
9599
5. **GetSimilarArtists** β€” Last.fm `artist.getSimilar` + library cross-ref
96100
6. **GetTrackTags** β€” Last.fm `track.getTopTags`
97101
7. **GetTopArtistsByTag** β€” Last.fm `tag.getTopArtists` + library cross-ref
98102
8. **GetTopTracksByCountry** β€” Last.fm `geo.getTopTracks` + library cross-ref
99103

100-
TDD: Unit test each tool's `call()` with test DB; mock Last.fm responses for similarity tools.
104+
Also added 5 Last.fm discovery methods to `lastfm/client.rs` and response types to `lastfm/types.rs`.
105+
12 tool tests + all tools have `name()`, `description()`, `definition()` verified.
106+
107+
## Phase 4: Agent Loop + Tauri Commands (DONE β€” commit d9a37c9)
101108

102-
## Phase 4: Agent Loop + Tauri Commands
109+
Implemented in `mod.rs`:
110+
- `check_ollama()` β€” GET to `{OLLAMA_BASE_URL}/api/tags`, returns raw JSON string
111+
- `build_agent(ctx)` β€” constructs Rig agent with Ollama client, all 8 tools, system prompt, multi_turn(5)
112+
- `agent_generate_playlist(db, prompt)` β€” full flow: health check -> build agent -> run prompt -> parse response -> create playlist via `db::playlists::create_playlist` + `add_tracks_to_playlist` -> return AgentResponse
113+
- `agent_check_status(db)` β€” checks Ollama availability + model presence -> returns AgentStatusResponse
103114

104-
- `build_agent(ctx)` β€” construct Rig agent with all 8 tools + system prompt
105-
- Wire real implementation into `agent_generate_playlist`: health check -> build agent -> run (max 5 turns) -> parse track IDs -> create playlist
106-
- Wire real implementation into `agent_check_status`: check Ollama + model availability
115+
Key patterns: `LastFmClient::new()` constructed fresh (not Tauri state), `Arc<AgentContext>` shared across tools, graceful NoOllama/NoModel status returns.
107116

108-
## Phase 5: Onboarding + Setup (`setup.rs`)
117+
## Phase 5: Onboarding + Setup (DONE β€” commit f1cf52c)
109118

110-
Tauri commands:
119+
Created `setup.rs` with 4 public functions:
120+
- `check_ollama_status()` β€” wraps `check_ollama()` + `parse_model_names()`, returns `OllamaStatus { available, models }`
121+
- `pull_model(app, model)` β€” POST streaming to `{OLLAMA_BASE_URL}/api/pull`, emits `agent://pull-progress` Tauri events with `PullProgress { status, completed, total }`, returns `PullModelResult { success, error }`
122+
- `get_onboarding_state(app)` β€” reads `OnboardingState` from `agent.json` store (key: `agent_onboarding`), defaults to `{ complete: false, model: None }`
123+
- `set_onboarding_complete(app, model)` β€” writes `OnboardingState { complete: true, model: Some(model) }` to store
111124

112-
- `agent_check_ollama()` β€” health check Ollama, list models
113-
- `agent_pull_model(model)` β€” stream model download with progress events
114-
- `agent_get_onboarding_state()` / `agent_set_onboarding_complete()` β€” persist via tauri-plugin-store
125+
New types in `types.rs`: `OllamaStatus`, `PullProgress`, `OnboardingState`, `PullModelResult`
126+
4 new Tauri command pairs (cfg/not-cfg) in `lib.rs`: `agent_check_ollama`, `agent_pull_model`, `agent_get_onboarding_state`, `agent_set_onboarding_complete`
127+
7 unit tests in setup.rs + 6 type tests in types.rs (13 total for Phase 5).
115128

116-
## Phase 6: Evals (`evals.rs`)
129+
## Phase 6: Evals (DONE β€” commit 27f9c2e, cfg-gate fix fd8593a)
117130

118-
Heuristic evals (no LLM judge):
131+
13 heuristic eval tests in `evals.rs` using wiremock mock Ollama server:
119132

120-
- Tool selection evals (correct tools per prompt class)
121-
- Output format evals (parseable response, no hallucinated IDs)
122-
- Degradation evals (graceful fallback when Last.fm tools fail)
133+
- **Tool execution evals (3)**: `eval_tool_execution_search_library`, `eval_tool_execution_get_recently_played`, `eval_tool_execution_get_top_artists` β€” verify mock Ollama tool-call requests trigger correct tool execution and return valid data
134+
- **Output format evals (6)**: `eval_output_format_valid_response`, `eval_output_format_with_preamble`, `eval_output_format_bracketed_ids`, `eval_output_format_no_valid_ids`, `eval_output_format_missing_playlist_line`, `eval_output_format_hallucinated_ids_filtered` β€” verify `parse_agent_response()` handles all LLM output variations
135+
- **Degradation evals (5)**: `eval_degradation_ollama_unreachable`, `eval_degradation_ollama_healthy`, `eval_degradation_empty_tool_result`, `eval_degradation_invalid_tags_response`, `eval_degradation_no_models_available` β€” verify graceful fallback behavior
123136

124-
Gated behind `--features agent`; CI uses mock HTTP server.
137+
Refactored `build_agent()` and `check_ollama()` to accept `base_url: &str` parameter for test injection.
138+
Added `wiremock = "0.6"` to dev-dependencies.
139+
753/753 tests pass.
125140

126-
## Phase 7: Frontend β€” Genius Sidebar Category + Prompt UI
141+
Cfg-gate fix (fd8593a): After merging main (which had reverted the lastfm discovery methods), restored the methods and gated all discovery types, methods, and tests behind `#[cfg(feature = "agent")]` so default builds have zero dead_code warnings.
127142

128-
- Genius sidebar category with wayfarer glasses icon
143+
## Phase 7: Frontend β€” Genius Sidebar Category + Prompt UI β€” NOT STARTED
144+
145+
- Genius sidebar category with wayfarer glasses icon (in sidebar nav alongside Library, Playlists, etc.)
129146
- Natural language prompt input + Generate button
130-
- Loading state while agent runs
147+
- Loading state while agent runs (listen for `agent://pull-progress` events during model download)
131148
- Onboarding wizard (3 steps): Ollama check -> model download -> ready
149+
- Wire to Tauri commands: `agent_check_ollama`, `agent_pull_model`, `agent_get_onboarding_state`, `agent_set_onboarding_complete`, `agent_generate_playlist`, `agent_check_status`
150+
- Alpine.js store for agent state, basecoat/Tailwind for UI components
151+
152+
Must satisfy AC #1 (prompt input), AC #2 (LLM interpretation), AC #3 (8 tools visible), AC #4 (local tracks only), AC #5 (graceful degradation UX).
132153
<!-- SECTION:PLAN:END -->
133154

134155
## Implementation Notes
135156

136157
<!-- SECTION:NOTES:BEGIN -->
137158
## Current State (2026-03-31)
138159

139-
- Phase 1 (deps) complete
140-
- Phase 2 (types + prompt + module scaffold) complete β€” 3 files, 17 tests
141-
- Phase 3 (tools) complete β€” 8 Tool trait implementations, 12 tests
142-
- Phase 4 (agent loop + Tauri commands) complete β€” real implementations, 20 tests in mod.rs
160+
- Phase 1 (deps) complete β€” commit fc5846b
161+
- Phase 2 (types + prompt + module scaffold) complete β€” commit 2f121f7
162+
- Phase 3 (tools) complete β€” commit d9a37c9
163+
- Phase 4 (agent loop + Tauri commands) complete β€” commit d9a37c9
164+
- Phase 5 (onboarding + setup) complete β€” commit f1cf52c
165+
- Phase 6 (evals) complete β€” commit 27f9c2e, cfg-gate fix fd8593a
166+
- Merged into main and pushed (fast-forward merge fd8593a)
167+
168+
753/753 tests pass with `cargo nextest run --workspace --features agent`.
169+
Both `cargo check --features agent` and `cargo check` compile cleanly (zero warnings).
170+
171+
## Phase 5 Summary
172+
173+
Added `setup.rs` with 4 public functions + 13 new tests:
174+
- `check_ollama_status()` β€” health check returning OllamaStatus (available/unavailable + model list)
175+
- `pull_model(app, model)` β€” POST streaming to Ollama, emits `agent://pull-progress` Tauri events
176+
- `get_onboarding_state(app)` β€” reads from `agent.json` store
177+
- `set_onboarding_complete(app, model)` β€” writes to `agent.json` store
178+
179+
New types in `types.rs`: OllamaStatus, PullProgress, OnboardingState, PullModelResult
143180

144-
Both `cargo check --features agent` and `cargo check` pass.
145-
726/726 tests pass with `cargo nextest run --workspace --features agent`.
181+
4 new Tauri command pairs (cfg/not-cfg) wired in lib.rs:
182+
- `agent_check_ollama`, `agent_pull_model`, `agent_get_onboarding_state`, `agent_set_onboarding_complete`
183+
184+
## Phase 6 Summary
185+
186+
13 eval tests in `evals.rs` using wiremock mock Ollama server.
187+
Categories: tool execution (3), output format (6), degradation (5).
188+
Refactored `build_agent()` and `check_ollama()` to accept `base_url: &str` for test injection.
189+
Added `wiremock = "0.6"` to dev-dependencies.
190+
191+
Cfg-gate fix: After merging main (which had reverted lastfm discovery methods), restored them and gated all discovery types, methods, and tests behind `#[cfg(feature = "agent")]`.
146192

147193
## Key Design Decisions
148194

@@ -153,6 +199,8 @@ Both `cargo check --features agent` and `cargo check` pass.
153199
- Thin wrapper Tauri commands in lib.rs with cfg pairs (agent/not-agent) to keep generate_handler! unconditional
154200
- Agent module functions are plain async fns (not #[tauri::command]) β€” lib.rs wrappers handle Tauri integration
155201
- LastFmClient constructed fresh inside agent_generate_playlist (not managed as Tauri state)
202+
- Onboarding state persisted via tauri-plugin-store (`agent.json` with key `agent_onboarding`)
203+
- Model pull uses streaming POST to Ollama with Tauri event emission for progress
156204

157205
## Rig API Notes (v0.27 + experimental)
158206

@@ -165,33 +213,19 @@ Both `cargo check --features agent` and `cargo check` pass.
165213
## Files Created/Modified
166214

167215
- `crates/mt-tauri/src/agent/mod.rs` β€” module root, parse_agent_response, parse_model_names, has_default_model, check_ollama, build_agent, agent_generate_playlist, agent_check_status
168-
- `crates/mt-tauri/src/agent/types.rs` β€” AgentResponse, TrackSummary, AgentContext, AgentError, ParsedPlaylist, AgentStatusResponse
216+
- `crates/mt-tauri/src/agent/types.rs` β€” AgentResponse, TrackSummary, AgentContext, AgentError, ParsedPlaylist, AgentStatusResponse, OllamaStatus, PullProgress, OnboardingState, PullModelResult
169217
- `crates/mt-tauri/src/agent/prompt.rs` β€” SYSTEM_PROMPT, DEFAULT_MODEL, OLLAMA_BASE_URL, MAX_AGENT_TURNS
170218
- `crates/mt-tauri/src/agent/tools.rs` β€” 8 Tool implementations
171-
- `crates/mt-tauri/src/lastfm/client.rs` β€” 5 discovery methods (get_similar_tracks, get_similar_artists, get_track_top_tags, get_top_artists_by_tag, get_top_tracks_by_country)
172-
- `crates/mt-tauri/src/lastfm/types.rs` β€” response types for discovery methods
173-
- `crates/mt-tauri/Cargo.toml` β€” rig-core + schemars deps
174-
- `crates/mt-tauri/src/lib.rs` β€” agent module declaration + wrapper Tauri commands
175-
176-
## Next: Phase 5 (Onboarding + Setup)
177-
178-
## Phase 6 Complete (2026-03-31)
179-
180-
- Phase 6 (evals) complete β€” 13 heuristic eval tests in `evals.rs` using wiremock mock Ollama server
181-
- Categories: tool execution (3), output format (6), degradation (5)
182-
- Refactored `build_agent()` and `check_ollama()` to accept `base_url: &str` for test injection
183-
- Added `wiremock = "0.6"` to dev-dependencies
184-
- 753/753 tests pass with `cargo nextest run --workspace --features agent`
185-
- All 14 agent eval tests pass (13 new + 1 existing build_agent test)
186-
187-
## Files Created/Modified (Phase 6)
219+
- `crates/mt-tauri/src/agent/setup.rs` β€” check_ollama_status, pull_model, get/set_onboarding_state, parse_pull_progress_line
220+
- `crates/mt-tauri/src/agent/evals.rs` β€” 13 eval tests with wiremock
221+
- `crates/mt-tauri/src/lastfm/client.rs` β€” 5 discovery methods (cfg-gated behind agent feature)
222+
- `crates/mt-tauri/src/lastfm/types.rs` β€” response types for discovery methods (cfg-gated behind agent feature)
223+
- `crates/mt-tauri/Cargo.toml` β€” rig-core + schemars deps, wiremock dev-dependency
224+
- `crates/mt-tauri/src/lib.rs` β€” agent module declaration + 6 wrapper Tauri commands (cfg pairs)
188225

189-
- `crates/mt-tauri/src/agent/evals.rs` β€” NEW: 13 eval tests with wiremock
190-
- `crates/mt-tauri/src/agent/mod.rs` β€” refactored build_agent/check_ollama signatures, added `mod evals`
191-
- `crates/mt-tauri/src/agent/setup.rs` β€” updated check_ollama_status caller
192-
- `crates/mt-tauri/Cargo.toml` β€” added wiremock dev-dependency
226+
## Remaining
193227

194-
## Next: Phase 7 (Frontend β€” Genius Sidebar Category + Prompt UI)
228+
- Phase 7: Frontend β€” Genius sidebar category, prompt UI, onboarding wizard UI
195229
<!-- SECTION:NOTES:END -->
196230

197231
## Definition of Done

0 commit comments

Comments
Β (0)