story-search: one call, two search sources

story-search takes the payload agents already send to news/story search catalogs: {query, type, sort, limit}. One paid call fans that out to hn-search and web-search in parallel, merges the two result lists, and returns them as one ranked set.

Sort by relevance (the default) and you get a round-robin interleave of Hacker News and web results, each source keeping its own internal order. Sort by date and you get the merged list newest-first, with anything that has no timestamp pushed to the end instead of dropped. Duplicate URLs across the two sources get collapsed to one entry.

web-search is optional in the compose. If it fails, you still get Hacker News results back with degraded: true instead of a failed call. Price is $0.025.

web-search: $0.02 -> $0.01

We cut the price on web-search in half. Same Decodo-backed Google search, same ranked title/URL/snippet/domain output, same recency filter. Nothing about the endpoint changed except the number.

news-search: race instead of wait, and a cache

The news endpoints (crypto-news, stocks-news, market-recap, and the news-search alias) called GDELT first and only tried GNews after GDELT failed. GDELT averages around 11 seconds per call, so every request paid that latency even when GNews would've answered faster.

Now, when a GNews API key is configured, GDELT and GNews run at the same time and whichever answers first wins. Both keep their existing per-fetch timeouts. If both fail, the error you get back is unchanged.

We also added a small in-memory cache keyed on query, lookback window, and result limit, with a 60-second TTL. Repeat calls for the same topic inside that window skip both upstream fetches entirely. It's capped at 100 entries per worker instance so it can't grow unbounded.