diff --git a/CLAUDE.md b/CLAUDE.md index 3def3e9..2b73394 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -117,7 +117,7 @@ cd frontend && npx tsc --noEmit - `GET /api/v1/admin/users` — user list - `PUT /api/v1/admin/users/:id/role` — role management -## Database (17 migrations) +## Database (18 migrations) Tables: `users`, `sessions`, `magic_link_tokens`, `user_settings`, `sources`, `syntheses`, `admin_providers`, `admin_rate_limits`, `user_api_keys`, `audit_log` ## Environment Variables diff --git a/backend/migrations/20260325000018_drop_deprecated_settings.sql b/backend/migrations/20260325000018_drop_deprecated_settings.sql new file mode 100644 index 0000000..7478f59 --- /dev/null +++ b/backend/migrations/20260325000018_drop_deprecated_settings.sql @@ -0,0 +1,2 @@ +ALTER TABLE settings DROP COLUMN source_diversity_window; +ALTER TABLE settings DROP COLUMN use_llm_for_article_extraction; diff --git a/backend/src/db/settings.rs b/backend/src/db/settings.rs index 3f72179..00fbfbd 100644 --- a/backend/src/db/settings.rs +++ b/backend/src/db/settings.rs @@ -18,9 +18,7 @@ struct SettingsRow { categories: serde_json::Value, max_items_per_category: i32, max_articles_per_source: i32, - source_diversity_window: i32, use_llm_for_source_links: bool, - use_llm_for_article_extraction: bool, article_history_days: i32, search_agent_behavior: String, ai_provider: String, @@ -46,9 +44,7 @@ impl TryFrom for UserSettings { categories, max_items_per_category: row.max_items_per_category, max_articles_per_source: row.max_articles_per_source, - source_diversity_window: row.source_diversity_window, use_llm_for_source_links: row.use_llm_for_source_links, - use_llm_for_article_extraction: row.use_llm_for_article_extraction, article_history_days: row.article_history_days, search_agent_behavior: row.search_agent_behavior, ai_provider: row.ai_provider, @@ -76,10 +72,10 @@ pub async fn get_or_create_default( let row = sqlx::query_as::<_, SettingsRow>( r#" - INSERT INTO settings (user_id, theme, max_age_days, categories, max_items_per_category, search_agent_behavior, ai_provider, ai_model, ai_model_writing, rate_limit_max_requests, rate_limit_time_window_seconds, max_articles_per_source, source_diversity_window, use_llm_for_source_links, use_llm_for_article_extraction, article_history_days) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) + INSERT INTO settings (user_id, theme, max_age_days, categories, max_items_per_category, search_agent_behavior, ai_provider, ai_model, ai_model_writing, rate_limit_max_requests, rate_limit_time_window_seconds, max_articles_per_source, use_llm_for_source_links, article_history_days) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) ON CONFLICT (user_id) DO UPDATE SET user_id = settings.user_id - RETURNING user_id, theme, max_age_days, categories, max_items_per_category, search_agent_behavior, ai_provider, ai_model, ai_model_writing, rate_limit_max_requests, rate_limit_time_window_seconds, max_articles_per_source, source_diversity_window, use_llm_for_source_links, use_llm_for_article_extraction, article_history_days, updated_at + RETURNING user_id, theme, max_age_days, categories, max_items_per_category, search_agent_behavior, ai_provider, ai_model, ai_model_writing, rate_limit_max_requests, rate_limit_time_window_seconds, max_articles_per_source, use_llm_for_source_links, article_history_days, updated_at "#, ) .bind(user_id) @@ -94,9 +90,7 @@ pub async fn get_or_create_default( .bind(defaults.rate_limit_max_requests) .bind(defaults.rate_limit_time_window_seconds) .bind(defaults.max_articles_per_source) - .bind(defaults.source_diversity_window) .bind(defaults.use_llm_for_source_links) - .bind(defaults.use_llm_for_article_extraction) .bind(defaults.article_history_days) .fetch_one(pool) .await?; @@ -116,8 +110,8 @@ pub async fn upsert( let row = sqlx::query_as::<_, SettingsRow>( r#" - INSERT INTO settings (user_id, theme, max_age_days, categories, max_items_per_category, search_agent_behavior, ai_provider, ai_model, ai_model_writing, rate_limit_max_requests, rate_limit_time_window_seconds, max_articles_per_source, source_diversity_window, use_llm_for_source_links, use_llm_for_article_extraction, article_history_days) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) + INSERT INTO settings (user_id, theme, max_age_days, categories, max_items_per_category, search_agent_behavior, ai_provider, ai_model, ai_model_writing, rate_limit_max_requests, rate_limit_time_window_seconds, max_articles_per_source, use_llm_for_source_links, article_history_days) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) ON CONFLICT (user_id) DO UPDATE SET theme = EXCLUDED.theme, max_age_days = EXCLUDED.max_age_days, @@ -130,12 +124,10 @@ pub async fn upsert( rate_limit_max_requests = EXCLUDED.rate_limit_max_requests, rate_limit_time_window_seconds = EXCLUDED.rate_limit_time_window_seconds, max_articles_per_source = EXCLUDED.max_articles_per_source, - source_diversity_window = EXCLUDED.source_diversity_window, use_llm_for_source_links = EXCLUDED.use_llm_for_source_links, - use_llm_for_article_extraction = EXCLUDED.use_llm_for_article_extraction, article_history_days = EXCLUDED.article_history_days, updated_at = now() - RETURNING user_id, theme, max_age_days, categories, max_items_per_category, search_agent_behavior, ai_provider, ai_model, ai_model_writing, rate_limit_max_requests, rate_limit_time_window_seconds, max_articles_per_source, source_diversity_window, use_llm_for_source_links, use_llm_for_article_extraction, article_history_days, updated_at + RETURNING user_id, theme, max_age_days, categories, max_items_per_category, search_agent_behavior, ai_provider, ai_model, ai_model_writing, rate_limit_max_requests, rate_limit_time_window_seconds, max_articles_per_source, use_llm_for_source_links, article_history_days, updated_at "#, ) .bind(user_id) @@ -150,9 +142,7 @@ pub async fn upsert( .bind(req.rate_limit_max_requests) .bind(req.rate_limit_time_window_seconds) .bind(req.max_articles_per_source) - .bind(req.source_diversity_window) .bind(req.use_llm_for_source_links) - .bind(req.use_llm_for_article_extraction) .bind(req.article_history_days) .fetch_one(pool) .await?; diff --git a/backend/src/models/settings.rs b/backend/src/models/settings.rs index 4073117..37dd27d 100644 --- a/backend/src/models/settings.rs +++ b/backend/src/models/settings.rs @@ -13,9 +13,7 @@ pub struct UserSettings { pub categories: Vec, pub max_items_per_category: i32, pub max_articles_per_source: i32, - pub source_diversity_window: i32, pub use_llm_for_source_links: bool, - pub use_llm_for_article_extraction: bool, pub article_history_days: i32, pub search_agent_behavior: String, pub ai_provider: String, @@ -34,9 +32,7 @@ pub struct SettingsResponse { pub categories: Vec, pub max_items_per_category: i32, pub max_articles_per_source: i32, - pub source_diversity_window: i32, pub use_llm_for_source_links: bool, - pub use_llm_for_article_extraction: bool, pub article_history_days: i32, pub search_agent_behavior: String, pub ai_provider: String, @@ -54,9 +50,7 @@ impl From for SettingsResponse { categories: s.categories, max_items_per_category: s.max_items_per_category, max_articles_per_source: s.max_articles_per_source, - source_diversity_window: s.source_diversity_window, use_llm_for_source_links: s.use_llm_for_source_links, - use_llm_for_article_extraction: s.use_llm_for_article_extraction, article_history_days: s.article_history_days, search_agent_behavior: s.search_agent_behavior, ai_provider: s.ai_provider, @@ -76,9 +70,7 @@ pub struct UpdateSettingsRequest { pub categories: Vec, pub max_items_per_category: i32, pub max_articles_per_source: i32, - pub source_diversity_window: i32, pub use_llm_for_source_links: bool, - pub use_llm_for_article_extraction: bool, pub article_history_days: i32, pub search_agent_behavior: String, pub ai_provider: String, @@ -126,9 +118,6 @@ impl UpdateSettingsRequest { if !(1..=10).contains(&self.max_articles_per_source) { return Err("max_articles_per_source must be between 1 and 10".into()); } - if !(0..=10).contains(&self.source_diversity_window) { - return Err("source_diversity_window must be between 0 and 10".into()); - } if !(0..=365).contains(&self.article_history_days) { return Err("article_history_days must be between 0 and 365".into()); } @@ -174,9 +163,7 @@ impl Default for UserSettings { ], max_items_per_category: 4, max_articles_per_source: 3, - source_diversity_window: 3, use_llm_for_source_links: false, - use_llm_for_article_extraction: false, article_history_days: 90, search_agent_behavior: String::new(), ai_provider: String::new(), @@ -201,9 +188,7 @@ mod tests { categories: vec!["Category 1".into(), "Category 2".into()], max_items_per_category: 4, max_articles_per_source: 3, - source_diversity_window: 3, use_llm_for_source_links: false, - use_llm_for_article_extraction: false, article_history_days: 90, search_agent_behavior: String::new(), ai_provider: String::new(), @@ -410,31 +395,4 @@ mod tests { assert!(err.contains("ai_model_writing")); } - #[test] - fn test_source_diversity_window_zero_is_valid() { - let mut req = valid_request(); - req.source_diversity_window = 0; - assert!(req.validate().is_ok()); - } - - #[test] - fn test_source_diversity_window_ten_is_valid() { - let mut req = valid_request(); - req.source_diversity_window = 10; - assert!(req.validate().is_ok()); - } - - #[test] - fn test_source_diversity_window_below_range() { - let mut req = valid_request(); - req.source_diversity_window = -1; - assert!(req.validate().is_err()); - } - - #[test] - fn test_source_diversity_window_above_range() { - let mut req = valid_request(); - req.source_diversity_window = 11; - assert!(req.validate().is_err()); - } } diff --git a/backend/src/services/prompts.rs b/backend/src/services/prompts.rs index a008347..607c511 100644 --- a/backend/src/services/prompts.rs +++ b/backend/src/services/prompts.rs @@ -280,9 +280,7 @@ mod tests { ], max_items_per_category: 4, max_articles_per_source: 3, - source_diversity_window: 3, use_llm_for_source_links: false, - use_llm_for_article_extraction: false, article_history_days: 90, search_agent_behavior: String::new(), ai_provider: String::new(), diff --git a/backend/src/services/synthesis.rs b/backend/src/services/synthesis.rs index f800039..13582ef 100644 --- a/backend/src/services/synthesis.rs +++ b/backend/src/services/synthesis.rs @@ -306,11 +306,7 @@ async fn run_generation_inner( let user_rate_limiter = get_user_rate_limiter(state, &settings, user_id); - let llm_for_scraping: Option<(std::sync::Arc, String)> = if settings.use_llm_for_article_extraction { - Some((std::sync::Arc::clone(&provider), model_research.clone())) - } else { - None - }; + let llm_for_scraping: Option<(std::sync::Arc, String)> = None; // Build categories list with "Autre" appended for classification let mut classification_categories = settings.categories.clone(); @@ -621,39 +617,8 @@ async fn run_generation_inner( // Rate limit check before search pass check_rate_limit(state, &user_rate_limiter, &provider_name)?; - // Load recently-used domains for diversity (Phase 2 only) - let recent_domains = if settings.source_diversity_window > 0 { - let recent = db::syntheses::list_for_user( - &state.pool, - user_id, - settings.source_diversity_window as i64, - 0, - ) - .await - .unwrap_or_default(); - - let mut domains: Vec = recent - .iter() - .filter_map(|s| { - serde_json::from_value::>( - s.sections.clone(), - ) - .ok() - }) - .flat_map(|sections| { - sections - .into_iter() - .flat_map(|sec| sec.items.into_iter()) - .filter_map(|item| extract_domain(&item.url)) - }) - .collect(); - - domains.sort(); - domains.dedup(); - domains - } else { - Vec::new() - }; + // Source diversity tracking removed (source_diversity_window setting dropped) + let recent_domains: Vec = Vec::new(); // Build search schema for gap categories let search_schema = build_category_schema(&settings.categories, settings.max_items_per_category);