Add query-type-aware source tiering and scoring

Detect query type (product/concept/opinion/how_to/comparison/breaking_news/
prediction) via lightweight regex patterns and use it for:

1. Source selection: each query type has tier-1 (always run) and tier-2
   (run if available) sources. Unlisted sources are opt-in only.
   Truth Social is always opt-in regardless of query type.

2. WebSearch penalty: varies by query type instead of flat -15pt.
   Concept queries get 0 penalty (web docs are authoritative),
   how_to gets 5pt, breaking_news gets 10pt, product/opinion get 15pt.

3. Tiebreaker ordering: source priority varies by query type.
   YouTube ranks first for how_to, Polymarket for prediction,
   HN for concept queries, X for breaking news.

All changes are backward-compatible: callers that don't pass query_type
get the original behavior (15pt penalty, Reddit > X > YouTube tiebreaker).
This commit is contained in:
Jeffrey Sperling
2026-03-11 17:24:52 -07:00
parent e568ef8af9
commit ef7c0f05dd
4 changed files with 308 additions and 47 deletions
+25 -19
View File
@@ -160,6 +160,7 @@ from lib import (
websearch,
xai_x,
youtube_yt,
query_type as qt,
)
@@ -1692,14 +1693,19 @@ def main():
else:
mode = sources
# Detect query type for source tiering and scoring adjustments
query_type = qt.detect_query_type(args.topic)
# Apply --search flag: restrict sources to the specified subset
search_do_hackernews = True
search_do_bluesky = has_bluesky
search_do_truthsocial = has_truthsocial
search_do_polymarket = True
search_run_youtube = has_ytdlp
search_run_tiktok = has_tiktok
search_run_instagram = has_instagram
# Source defaults are query-type-aware (Truth Social always opt-in,
# Bluesky only for query types where it adds signal)
search_do_hackernews = qt.is_source_enabled("hn", query_type) if not args.search else True
search_do_bluesky = has_bluesky and qt.is_source_enabled("bluesky", query_type)
search_do_truthsocial = False # Always opt-in (requires --search truthsocial)
search_do_polymarket = qt.is_source_enabled("polymarket", query_type)
search_run_youtube = has_ytdlp and qt.is_source_enabled("youtube", query_type)
search_run_tiktok = has_tiktok and qt.is_source_enabled("tiktok", query_type)
search_run_instagram = has_instagram and qt.is_source_enabled("instagram", query_type)
search_run_xiaohongshu = has_xiaohongshu
if args.search:
search_sources = parse_search_flag(args.search)
@@ -1795,19 +1801,19 @@ def main():
scored_bsky = score.score_bluesky_items(filtered_bsky) if filtered_bsky else []
scored_ts = score.score_truthsocial_items(filtered_ts) if filtered_ts else []
scored_pm = score.score_polymarket_items(filtered_pm) if filtered_pm else []
scored_web = score.score_websearch_items(filtered_web) if filtered_web else []
scored_web = score.score_websearch_items(filtered_web, query_type=query_type) if filtered_web else []
# Sort items
sorted_reddit = score.sort_items(scored_reddit)
sorted_x = score.sort_items(scored_x)
sorted_youtube = score.sort_items(scored_youtube) if scored_youtube else []
sorted_tiktok = score.sort_items(scored_tiktok) if scored_tiktok else []
sorted_ig = score.sort_items(scored_ig) if scored_ig else []
sorted_hn = score.sort_items(scored_hn) if scored_hn else []
sorted_bsky = score.sort_items(scored_bsky) if scored_bsky else []
sorted_ts = score.sort_items(scored_ts) if scored_ts else []
sorted_pm = score.sort_items(scored_pm) if scored_pm else []
sorted_web = score.sort_items(scored_web) if scored_web else []
# Sort items (query-type-aware tiebreaker ordering)
sorted_reddit = score.sort_items(scored_reddit, query_type=query_type)
sorted_x = score.sort_items(scored_x, query_type=query_type)
sorted_youtube = score.sort_items(scored_youtube, query_type=query_type) if scored_youtube else []
sorted_tiktok = score.sort_items(scored_tiktok, query_type=query_type) if scored_tiktok else []
sorted_ig = score.sort_items(scored_ig, query_type=query_type) if scored_ig else []
sorted_hn = score.sort_items(scored_hn, query_type=query_type) if scored_hn else []
sorted_bsky = score.sort_items(scored_bsky, query_type=query_type) if scored_bsky else []
sorted_ts = score.sort_items(scored_ts, query_type=query_type) if scored_ts else []
sorted_pm = score.sort_items(scored_pm, query_type=query_type) if scored_pm else []
sorted_web = score.sort_items(scored_web, query_type=query_type) if scored_web else []
# Dedupe items
deduped_reddit = dedupe.dedupe_reddit(sorted_reddit)