From c50f124ad14f2f7c5c60d18660398209f27048c0 Mon Sep 17 00:00:00 2001 From: thorntwig Date: Thu, 5 Nov 2026 12:21:19 +0100 Subject: [PATCH 1/2] docs: Align the cookbook with news search behavior --- asknews_sdk/api/news.py | 5 +- cookbook/README.md | 6 +-- .../markdown/00_setup_and_core_concepts.md | 53 ++++++++++++++----- .../markdown/01_getting_real_time_news.md | 42 +++++++-------- .../markdown/02_searching_archive_news.md | 33 ++++++------ cookbook/markdown/03_paginating.md | 26 +++++---- cookbook/markdown/04_building_llm_context.md | 6 +-- cookbook/markdown/05_using_wikipedia.md | 3 -- cookbook/markdown/06_searching_twitter.md | 1 - cookbook/markdown/07_searching_google.md | 1 - cookbook/markdown/08_searching_podcasts.md | 6 +-- cookbook/markdown/09_tracking_a_company.md | 8 +-- cookbook/markdown/10_tracking_a_person.md | 6 --- ...11_tracking_a_product_brand_or_industry.md | 24 +++------ cookbook/markdown/12_deep_research_basics.md | 11 ++-- cookbook/markdown/13_deep_research_depth.md | 11 ++-- .../markdown/14_prompting_deep_research.md | 1 - cookbook/markdown/15_creating_an_alert.md | 1 - cookbook/markdown/16_using_the_mcp_server.md | 3 +- .../recipes/00_setup_and_core_concepts.py | 53 ++++++++++++++----- cookbook/recipes/01_getting_real_time_news.py | 42 +++++++-------- cookbook/recipes/02_searching_archive_news.py | 33 ++++++------ cookbook/recipes/03_paginating.py | 26 +++++---- cookbook/recipes/04_building_llm_context.py | 6 +-- cookbook/recipes/05_using_wikipedia.py | 3 -- cookbook/recipes/06_searching_twitter.py | 1 - cookbook/recipes/07_searching_google.py | 1 - cookbook/recipes/08_searching_podcasts.py | 6 +-- cookbook/recipes/09_tracking_a_company.py | 8 +-- cookbook/recipes/10_tracking_a_person.py | 6 --- ...11_tracking_a_product_brand_or_industry.py | 24 +++------ cookbook/recipes/12_deep_research_basics.py | 11 ++-- cookbook/recipes/13_deep_research_depth.py | 11 ++-- .../recipes/14_prompting_deep_research.py | 1 - cookbook/recipes/15_creating_an_alert.py | 1 - cookbook/recipes/16_using_the_mcp_server.py | 3 +- 36 files changed, 235 insertions(+), 248 deletions(-) diff --git a/asknews_sdk/api/news.py b/asknews_sdk/api/news.py index dccb1b8..c18c46e 100644 --- a/asknews_sdk/api/news.py +++ b/asknews_sdk/api/news.py @@ -166,9 +166,8 @@ def search_news( (like a classic news api). Can be 'string' or 'dicts', or 'both', defaults to "dicts". :type return_type: Literal["string", "dicts", "both"] - :param historical: Search on archive of historical news. Defaults to False, - meaning that the search will only look through the most recent news - (48 hours) + :param historical: Deprecated, has no effect. The time window alone sets + what is searched. :type historical: bool :param method: Method to use for searching. Both `kw` and `nl` support natural language queries. `kw` tries to match keywords, diff --git a/cookbook/README.md b/cookbook/README.md index c4265a2..1d6455e 100644 --- a/cookbook/README.md +++ b/cookbook/README.md @@ -19,9 +19,9 @@ PyCharm, or convert it to a notebook with `jupytext --to ipynb`. | # | Recipe | Covers | |---|---|---| -| 00 | Setup and core concepts | Client, which endpoint to use, filter-then-rank model, time windows, `kw` vs `nl`, return types, caching | -| 01 | Getting real-time news | Live index, `pub_date` vs `crawl_date`, newest-first, polling | -| 02 | Searching archive news | `historical=True`, exact windows, point-in-time context for backtests | +| 00 | Setup and core concepts | Client, which endpoint to use, filter-then-rank model, time windows, `kw` vs `nl`, result order, return types, caching, plan limits | +| 01 | Getting real-time news | The last 48 hours, `pub_date` vs `crawl_date`, sorting by date, polling | +| 02 | Searching archive news | Searching back to 2023 by window, exact windows, point-in-time context for backtests | | 03 | Paginating | `offset` loops, caps, dedupe, windowed bulk pulls | | 04 | Building LLM context | `as_string` vs custom context from `as_dicts`, citations, graphs, geo | | 05 | Using Wikipedia | `search_wiki` parameters, background + news in one prompt | diff --git a/cookbook/markdown/00_setup_and_core_concepts.md b/cookbook/markdown/00_setup_and_core_concepts.md index d041eba..4a36944 100644 --- a/cookbook/markdown/00_setup_and_core_concepts.md +++ b/cookbook/markdown/00_setup_and_core_concepts.md @@ -14,6 +14,10 @@ Create an API key at https://my.asknews.app and export it: export ASKNEWS_API_KEY="..." ``` +An API key carries the scopes it was created with, so the client needs no +`scopes` argument. `scopes` applies only to OAuth client credentials +(`client_id` and `client_secret`). + ```python import os @@ -22,7 +26,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news", "chat", "stories", "analytics"], ) ``` @@ -32,7 +35,7 @@ Every method below is awaitable on it: ```python from asknews_sdk import AsyncAskNewsSDK -async with AsyncAskNewsSDK(api_key=..., scopes=[...]) as ask: +async with AsyncAskNewsSDK(api_key=...) as ask: response = await ask.news.search_news(query="...") ``` @@ -67,13 +70,24 @@ Most bad results come from putting everything into `query` and no hard filters. When you know the company, person, or keyword that *must* appear, guarantee it, then use `query` to describe what you care about. -## Time: `hours_back`, `historical`, and timestamps +## Time: `hours_back`, timestamps, and `strategy` - `hours_back` (default `24`) is the simplest window, relative to now. -- `start_timestamp` / `end_timestamp` (unix seconds) give an exact window. -- `historical=False` (default) searches the **live index: the most recent - ~48 hours**. Anything older needs `historical=True`. See +- `start_timestamp` / `end_timestamp` (unix seconds) give an exact window + and take precedence over `hours_back`. One request can span at most 160 + days. +- **One search covers every date.** Coverage goes back to 2023 and the + window alone sets what is searched. The `historical` parameter is + deprecated and has no effect, so leave it out. A window that starts within the last 48 hours costs 1 credit. + One that starts further back costs 5: a `start_timestamp` more than 48 + hours ago, `hours_back` above 48, an `end_timestamp` on its own, or + `strategy="news knowledge"`. See [02 Searching archive news](02_searching_archive_news.md). +- For a past window, pass both timestamps. An `end_timestamp` without a + `start_timestamp` looks 160 days back from it. +- `strategy="latest news"` searches the last 48 hours and + `strategy="news knowledge"` the last 150 days; both set `method="kw"` + and replace the window you pass. - `time_filter="crawl_date"` (default) filters on when AskNews ingested the article. `time_filter="pub_date"` filters on the publisher's date. Use `pub_date` when "it happened in the last 24 hours" matters, e.g. for @@ -82,11 +96,21 @@ guarantee it, then use `query` to describe what you care about. ## `method`: `kw` vs `nl` -- `method="kw"` (default) leans on keyword matching. Best when the query is +- `method="kw"` (the default) leans on keyword matching. Best when the query is a list of names, tickers, and terms. - `method="nl"` leans on semantic meaning. Best when the query is a sentence or a paragraph, e.g. a forecasting question. -- `method="both"` blends the two. +- `method="both"` blends the two. It cannot be paginated. + +## Result order + +Results are ranked by relevance. `sort_by="pub_date"` sorts the page a +search returned by date: you still get the best matches, arranged newest +first, not the newest matches. Shorten the window when recency matters. + +A search with no `query` returns a page of articles from the window that +pass your filters, sorted by date within that page. It is not necessarily +the newest articles in the window. ## `return_type`: feeding an LLM vs feeding code @@ -97,10 +121,16 @@ guarantee it, then use `query` to describe what you care about. `entities`, `source_id`, `page_rank`, `sentiment`, ...). - `"both"`: both of the above. -## `premium=True` +## Plan limits -Includes premium publisher content in the results. The examples in this -cookbook set it wherever source quality matters. +- `n_articles`: Pay as you go, Pro and Spelunker accept up to 10 per + request, the default; more returns a 400 error. Analyst and Enterprise + return up to 30, and a larger value is reduced to 30 without an error. +- `domain_url` needs Analyst or Enterprise. +- `return_graphs` and `return_geo` need Spelunker, Analyst, Enterprise, or + wallet access. +- DeepNews: the `"x"` source needs Spelunker or above, and `"reddit"` + Analyst or above. ## Caching repeated queries @@ -116,7 +146,6 @@ response = ask.news.search_news( hours_back=24, n_articles=5, return_type="both", - premium=True, try_cache="1h", ) diff --git a/cookbook/markdown/01_getting_real_time_news.md b/cookbook/markdown/01_getting_real_time_news.md index aea10b7..a44dd41 100644 --- a/cookbook/markdown/01_getting_real_time_news.md +++ b/cookbook/markdown/01_getting_real_time_news.md @@ -1,18 +1,19 @@ # Getting real-time news -The default `search_news` call searches the live index (the last ~48 -hours), which is what you want for "what's happening right now". +The default `search_news` call covers the last 24 hours, which is what you +want for "what's happening right now". Best practices: -- Keep `historical=False` (the default) for anything inside the last 48 - hours. It is faster than an archive search. +- Keep the window inside the last 48 hours (`hours_back=48` or less). + That costs 1 credit instead of 5. - Set `hours_back` explicitly. The default is 24. - Use `time_filter="pub_date"` when the *publication* time matters (e.g. "only stories published in the last 6 hours"). Use the default `crawl_date` when polling for "new since my last call". -- Use `sort_by="pub_date"` when you want the newest first instead of the - most relevant first. +- Use `sort_by="pub_date"` to arrange the results newest first. It sorts + the best matches by date rather than fetching the newest articles, so + pair it with a short `hours_back`. ```python import os @@ -23,7 +24,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news"], ) ``` @@ -36,16 +36,15 @@ response = ask.news.search_news( time_filter="pub_date", n_articles=10, return_type="string", - premium=True, ) print(response.as_string) ``` -## Newest first, restricted to high-authority outlets +## Sorted by date, restricted to high-authority outlets -`page_rank` is an upper bound on a domain's popularity rank: lower is more -prominent. `page_rank=100000` keeps the top ~100k domains and drops the -long tail of low-authority sites. `diversify_sources=True` stops one outlet +`page_rank` is an upper bound on a domain's rank: lower is more +prominent, and `page_rank=100000` or lower targets top sources and drops +the long tail of low-authority sites. `diversify_sources=True` stops one outlet from dominating the results. ```python @@ -58,27 +57,26 @@ response = ask.news.search_news( diversify_sources=True, n_articles=10, return_type="dicts", - premium=True, ) for a in response.as_dicts: print(f"{a.pub_date:%H:%M} | {a.source_id} | {a.title}") ``` -## Everything new in a category, no query +## Browsing a category, no query -`query` is optional. With no query you get the latest articles that pass -your filters. +`query` is optional. With no query you get a page of articles from the +window that pass your filters, sorted by date within the page. It is not +necessarily the newest articles in the window, so keep the window short. ```python response = ask.news.search_news( categories=["Technology"], languages=["en"], hours_back=1, - n_articles=25, + n_articles=10, return_type="dicts", - premium=True, ) -print(len(response.as_dicts), "technology articles in the last hour") +print(len(response.as_dicts), "technology articles from the last hour") ``` ## Polling for new articles @@ -86,7 +84,8 @@ print(len(response.as_dicts), "technology articles in the last hour") For a lightweight poller, track the last time you checked and use `start_timestamp` with the default `time_filter="crawl_date"`, so you pick up anything AskNews ingested since then even if the publisher back-dated -it. Deduplicate on `article_id`. +it. Deduplicate on `article_id`. If more articles than one page can arrive +between polls, paginate with `offset` (see [03 Paginating](03_paginating.md)). ```python seen: set = set() @@ -100,9 +99,8 @@ for _ in range(3): start_timestamp=last_checked, end_timestamp=now, time_filter="crawl_date", - n_articles=50, + n_articles=10, return_type="dicts", - premium=True, ) for a in response.as_dicts: if a.article_id not in seen: diff --git a/cookbook/markdown/02_searching_archive_news.md b/cookbook/markdown/02_searching_archive_news.md index 8dc1d62..257d358 100644 --- a/cookbook/markdown/02_searching_archive_news.md +++ b/cookbook/markdown/02_searching_archive_news.md @@ -1,13 +1,19 @@ # Searching archive news -The live index holds the last ~48 hours. To search further back, set -`historical=True` and give an explicit window. +Coverage goes back to 2023, and the same `search_news` call reaches it: +give a window that starts in the past. There is no separate mode or flag. Best practices: -- **Always pass `historical=True` for windows older than 48 hours.** - Without it, an old `start_timestamp`/`end_timestamp` or a large - `hours_back` quietly returns only recent articles. +- **Pass both `start_timestamp` and `end_timestamp`.** A start more than + 48 hours ago reaches back. An `end_timestamp` on its own looks 160 + days back from it, which is rarely the window you meant. The + `historical` parameter is deprecated and has no effect, so leave it + out. +- One request can span at most 160 days. Split longer periods into + windows, see [03 Paginating](03_paginating.md). +- A request whose window starts more than 48 hours ago costs 5 credits, + and so does every page of it. - Prefer `start_timestamp` / `end_timestamp` over a huge `hours_back` for anything you want to reproduce later. - Use `time_filter="pub_date"` for historical research: you almost always @@ -24,7 +30,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news"], ) ``` @@ -36,14 +41,12 @@ end = datetime(2025, 3, 31, 23, 59, 59, tzinfo=timezone.utc) response = ask.news.search_news( query="inflation rate United States CPI report", - historical=True, start_timestamp=int(start.timestamp()), end_timestamp=int(end.timestamp()), time_filter="pub_date", method="kw", n_articles=10, return_type="dicts", - premium=True, ) for a in response.as_dicts: print(f"{a.pub_date:%Y-%m-%d} | {a.source_id} | {a.title}") @@ -61,13 +64,11 @@ as_of = datetime(2024, 10, 1, tzinfo=timezone.utc) response = ask.news.search_news( query="Will the Federal Reserve cut interest rates at the November 2024 FOMC meeting?", method="nl", - historical=True, end_timestamp=int(as_of.timestamp()), start_timestamp=int(as_of.timestamp()) - 14 * 24 * 3600, time_filter="pub_date", - n_articles=15, + n_articles=10, return_type="string", - premium=True, try_cache="7d", ) print(response.as_string) @@ -75,21 +76,19 @@ print(response.as_string) ## Archive + entity guarantee -Hard filters work the same way on the archive. This pulls every article -about a specific organization in a quarter. For more than one page of -results, see [03 Paginating](03_paginating.md). +Hard filters work the same way on the archive. This pulls articles about +a specific organization in a quarter. For more than one page of results, +see [03 Paginating](03_paginating.md). ```python response = ask.news.search_news( entity_guarantee=["Organization:OpenAI"], query="OpenAI funding round valuation investors", - historical=True, start_timestamp=int(datetime(2025, 1, 1, tzinfo=timezone.utc).timestamp()), end_timestamp=int(datetime(2025, 4, 1, tzinfo=timezone.utc).timestamp()), time_filter="pub_date", - n_articles=25, + n_articles=10, return_type="dicts", - premium=True, ) print(len(response.as_dicts), "articles") ``` diff --git a/cookbook/markdown/03_paginating.md b/cookbook/markdown/03_paginating.md index 5173de8..9b0e2bf 100644 --- a/cookbook/markdown/03_paginating.md +++ b/cookbook/markdown/03_paginating.md @@ -7,12 +7,18 @@ is `None` (or the page comes back empty), you have reached the end. Best practices: - Keep every parameter identical between pages. Only `offset` changes. -- Use `n_articles=100` per page for bulk pulls (fewer round trips). +- Use the largest page your plan allows: 10 on Pay as you go, Pro and + Spelunker (more returns a 400 error), and 30 on Analyst and Enterprise + (a larger value is reduced to 30). The examples use 10. - Always set a cap (articles or pages) so a broad query cannot run away. - Deduplicate on `article_id` when merging pages. - For very large pulls across long time ranges, split the range into windows and paginate each window. Smaller windows are more reliable - and easy to resume. + and easy to resume. A window can span at most 160 days, and numeric + offsets stop at 3000. +- Paginate with `method="kw"` or `"nl"`; `"both"` cannot be paginated. + Pagination also needs at least one of `query`, `domain_url`, + `entity_guarantee`, `authors`, or a geographic filter. ```python import os @@ -23,28 +29,28 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news"], ) ``` ## Basic offset loop ```python +window_end = datetime.now(timezone.utc) + params = dict( query="Thailand Cambodia border conflict ceasefire peace talks", entity_guarantee=["Location:Thailand", "Location:Cambodia"], entity_guarantee_op="AND", - hours_back=168, - historical=True, + start_timestamp=int((window_end - timedelta(days=7)).timestamp()), + end_timestamp=int(window_end.timestamp()), time_filter="pub_date", - n_articles=100, + n_articles=10, return_type="dicts", - premium=True, ) articles = {} offset = None -max_articles = 500 +max_articles = 100 while True: response = ask.news.search_news(**params, offset=offset or 0) @@ -72,13 +78,11 @@ def pull_window(start: datetime, end: datetime, **filters) -> list: while True: response = ask.news.search_news( **filters, - historical=True, start_timestamp=int(start.timestamp()), end_timestamp=int(end.timestamp()), time_filter="pub_date", - n_articles=100, + n_articles=10, return_type="dicts", - premium=True, offset=offset or 0, ) out.extend(response.as_dicts or []) diff --git a/cookbook/markdown/04_building_llm_context.md b/cookbook/markdown/04_building_llm_context.md index 061af6b..32df07d 100644 --- a/cookbook/markdown/04_building_llm_context.md +++ b/cookbook/markdown/04_building_llm_context.md @@ -23,7 +23,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news"], ) ``` @@ -40,7 +39,6 @@ response = ask.news.search_news( return_type="string", doc_start_delimiter="
", doc_end_delimiter="
", - premium=True, ) prompt = f"""Answer using only the articles below. Cite articles by their citation key. @@ -53,7 +51,8 @@ Question: Where do EU-US trade negotiations stand right now?""" ## Option 2: build your own context from dicts `return_graphs=True` adds an entity relationship graph per article and -`return_geo=True` adds coordinates for extracted locations. Only request +`return_geo=True` adds coordinates for extracted locations. Both need +Spelunker, Analyst, Enterprise, or wallet access. Only request them when your prompt uses them; they add tokens. ```python @@ -64,7 +63,6 @@ response = ask.news.search_news( return_type="dicts", return_graphs=True, return_geo=True, - premium=True, ) diff --git a/cookbook/markdown/05_using_wikipedia.md b/cookbook/markdown/05_using_wikipedia.md index 2bf2c93..daa2a60 100644 --- a/cookbook/markdown/05_using_wikipedia.md +++ b/cookbook/markdown/05_using_wikipedia.md @@ -27,7 +27,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news"], ) ``` @@ -76,10 +75,8 @@ news = ask.news.search_news( query=f"{subject} contract funding drones defense AI", entity_guarantee=[f"Organization:{subject}"], hours_back=168, - historical=True, n_articles=10, return_type="string", - premium=True, ) background_text = "\n\n".join( diff --git a/cookbook/markdown/06_searching_twitter.md b/cookbook/markdown/06_searching_twitter.md index 8c2047f..17c0508 100644 --- a/cookbook/markdown/06_searching_twitter.md +++ b/cookbook/markdown/06_searching_twitter.md @@ -37,7 +37,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["chat"], ) ``` diff --git a/cookbook/markdown/07_searching_google.md b/cookbook/markdown/07_searching_google.md index ee52e5f..69e5fbf 100644 --- a/cookbook/markdown/07_searching_google.md +++ b/cookbook/markdown/07_searching_google.md @@ -31,7 +31,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["chat"], ) ``` diff --git a/cookbook/markdown/08_searching_podcasts.md b/cookbook/markdown/08_searching_podcasts.md index cff40d1..54f422f 100644 --- a/cookbook/markdown/08_searching_podcasts.md +++ b/cookbook/markdown/08_searching_podcasts.md @@ -8,7 +8,7 @@ Podcast episodes are indexed alongside news and are searchable with - `"none"`: exclude podcasts (articles only). All the usual filters (`entity_guarantee`, `string_guarantee`, -time windows, `historical`) apply to podcasts too. +and time windows) apply to podcasts too. Podcasts are where opinions, interviews, and long-form commentary live. Reach for them when the question is "what are people saying about X" more @@ -22,7 +22,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news", "chat"], ) ``` @@ -33,7 +32,6 @@ response = ask.news.search_news( query="opinions on the war with Iran, commentary, debate", podcasts="only", hours_back=168, - historical=True, n_articles=10, return_type="dicts", ) @@ -52,7 +50,6 @@ response = ask.news.search_news( entity_guarantee=["Person:Dario Amodei"], podcasts="only", hours_back=720, - historical=True, n_articles=10, return_type="string", ) @@ -70,7 +67,6 @@ response = ask.news.search_news( podcasts="none", hours_back=24, n_articles=10, - premium=True, ) ``` diff --git a/cookbook/markdown/09_tracking_a_company.md b/cookbook/markdown/09_tracking_a_company.md index 802e664..d9c65bc 100644 --- a/cookbook/markdown/09_tracking_a_company.md +++ b/cookbook/markdown/09_tracking_a_company.md @@ -35,7 +35,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news", "chat"], ) ``` @@ -59,7 +58,6 @@ response = ask.news.search_news( page_rank=100000, languages=["en"], return_type="both", - premium=True, ) print(response.as_string) ``` @@ -76,7 +74,6 @@ response = ask.news.search_news( time_filter="pub_date", n_articles=10, return_type="dicts", - premium=True, ) ``` @@ -92,11 +89,9 @@ response = ask.news.search_news( string_guarantee_op="OR", query="Databricks acquisition, acquires startup, deal terms, purchase price", hours_back=720, - historical=True, time_filter="pub_date", - n_articles=20, + n_articles=10, return_type="dicts", - premium=True, ) ``` @@ -113,7 +108,6 @@ response = ask.news.search_news( query="Apple Inc. iPhone, App Store, antitrust, Tim Cook, earnings", hours_back=24, n_articles=10, - premium=True, ) ``` diff --git a/cookbook/markdown/10_tracking_a_person.md b/cookbook/markdown/10_tracking_a_person.md index 6a00752..150f9ad 100644 --- a/cookbook/markdown/10_tracking_a_person.md +++ b/cookbook/markdown/10_tracking_a_person.md @@ -25,7 +25,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news", "chat"], ) ``` @@ -46,7 +45,6 @@ response = ask.news.search_news( time_filter="pub_date", n_articles=10, return_type="both", - premium=True, ) print(response.as_string) ``` @@ -62,10 +60,8 @@ response = ask.news.search_news( entity_guarantee_op="AND", query="Daniel Ek Helsing chairman defense AI investment", hours_back=720, - historical=True, n_articles=10, return_type="dicts", - premium=True, ) ``` @@ -75,7 +71,6 @@ response = ask.news.search_news( response = ask.news.search_news( authors=["Kaitlan Collins"], hours_back=168, - historical=True, n_articles=10, return_type="dicts", ) @@ -103,7 +98,6 @@ for name, description, handle in watchlist: time_filter="pub_date", n_articles=5, return_type="string", - premium=True, ) posts = ask.chat.live_web_search( queries=[f"(from:{handle} OR @{handle}) min_faves:20"], diff --git a/cookbook/markdown/11_tracking_a_product_brand_or_industry.md b/cookbook/markdown/11_tracking_a_product_brand_or_industry.md index 69fc026..a3ef374 100644 --- a/cookbook/markdown/11_tracking_a_product_brand_or_industry.md +++ b/cookbook/markdown/11_tracking_a_product_brand_or_industry.md @@ -9,7 +9,7 @@ combine filters. The building blocks: | `entity_guarantee` with `Product:` / `Organization:` / `Location:` / `Event:` | Extracted entities that must appear | | `reverse_string_guarantee` / `reverse_entity_guarantee` | Removing known noise | | `categories` | Coarse topic restriction (`Business`, `Technology`, `Finance`, ...) | -| `domain_url` / `bad_domain_url` | Trade press only, or excluding sites | +| `domain_url` / `bad_domain_url` | Trade press only, or excluding sites. `domain_url` needs Analyst or Enterprise | | `languages`, `countries`, `continents` | Market / geography | | `sentiment` | Only negative (or positive) coverage | | `page_rank` | Drop low-authority sites | @@ -33,7 +33,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news"], ) ``` @@ -46,10 +45,8 @@ response = ask.news.search_news( entity_guarantee=["Organization:Apple"], query="Apple Vision Pro sales, reviews, price, shipments, developer adoption", hours_back=168, - historical=True, - n_articles=20, + n_articles=10, return_type="dicts", - premium=True, ) ``` @@ -65,11 +62,9 @@ response = ask.news.search_news( sentiment="negative", reporting_voice=["Objective", "Analytical"], hours_back=72, - historical=True, time_filter="pub_date", - n_articles=20, + n_articles=10, return_type="dicts", - premium=True, ) ``` @@ -92,11 +87,9 @@ response = ask.news.search_news( query="meal kit, recipe box, meal delivery kit, cook-at-home kit, food subscription", languages=["en", "es", "pt"], hours_back=720, - historical=True, time_filter="pub_date", - n_articles=50, + n_articles=10, return_type="dicts", - premium=True, ) ``` @@ -118,9 +111,8 @@ response = ask.news.search_news( languages=["en", "fr", "es", "de"], hours_back=24, time_filter="pub_date", - n_articles=25, + n_articles=10, return_type="both", - premium=True, ) ``` @@ -131,8 +123,7 @@ response = ask.news.search_news( query="semiconductor fab capacity, wafer starts, foundry pricing, advanced packaging", domain_url=["eetimes.com", "semiengineering.com", "digitimes.com", "anandtech.com"], hours_back=168, - historical=True, - n_articles=20, + n_articles=10, return_type="dicts", ) ``` @@ -152,9 +143,8 @@ response = ask.news.search_news( hours_back=48, time_filter="pub_date", method="kw", - n_articles=50, + n_articles=10, return_type="dicts", - premium=True, ) ``` diff --git a/cookbook/markdown/12_deep_research_basics.md b/cookbook/markdown/12_deep_research_basics.md index da7440f..e4ac43d 100644 --- a/cookbook/markdown/12_deep_research_basics.md +++ b/cookbook/markdown/12_deep_research_basics.md @@ -13,7 +13,7 @@ The pieces you control: | `messages` | The task. Chat format; the last user message is the request. | | `sources` | Which tools the agent may use (see below). Default `["asknews"]`. | | `model` | The LLM driving the agent. | -| `engine` | `"v2.0"` is the current engine; `"v1.5"` is the previous one (and the one alerts use). | +| `engine` | `"v2.0"` is the current engine; `"v1.5"` is the previous one (and the one alerts use). The SDK defaults to `"v1"`, so set it explicitly. | | `search_depth`, `max_depth` | How much research to do. See [13 Deep research depth](13_deep_research_depth.md). | | `filter_params` | Defaults applied to the agent's AskNews searches (e.g. `hours_back`, `languages`). | | `stream` | Stream the agent's thinking, tool calls, text, and sources as they happen. | @@ -28,10 +28,10 @@ Sources: |---|---| | `"asknews"` | News search (the `search_news` filters, incl. entity/string guarantees) | | `"google"` | Live web search | -| `"x"` | X (Twitter) advanced search | +| `"x"` | X (Twitter) advanced search. Needs Spelunker or above | | `"wiki"` | Wikipedia | | `"podcasts"` | Podcast search | -| `"reddit"` | Reddit threads | +| `"reddit"` | Reddit threads. Needs Analyst or above | | `"graph"` | News knowledge graph | | `"charts"` | Chart generation from news data | | `"full_text_discovery"` | Full article text | @@ -55,7 +55,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["chat", "news"], ) ``` @@ -300,7 +299,7 @@ from asknews_sdk import AsyncAskNewsSDK from asknews_sdk.dto.deepnews import CreateDeepNewsResponseStreamSourceBatch async def main(): - async with AsyncAskNewsSDK(api_key=..., scopes=["chat"]) as ask: + async with AsyncAskNewsSDK(api_key=...) as ask: stream = await ask.chat.get_deep_news( messages=[{"role": "user", "content": question}], sources=["asknews", "google"], @@ -355,7 +354,7 @@ import asyncio from asknews_sdk import AsyncAskNewsSDK async def main(): - async with AsyncAskNewsSDK(api_key=..., scopes=["chat"]) as ask: + async with AsyncAskNewsSDK(api_key=...) as ask: questions = ["...", "...", "..."] results = await asyncio.gather(*[ ask.chat.get_deep_news( diff --git a/cookbook/markdown/13_deep_research_depth.md b/cookbook/markdown/13_deep_research_depth.md index de75481..dd4882d 100644 --- a/cookbook/markdown/13_deep_research_depth.md +++ b/cookbook/markdown/13_deep_research_depth.md @@ -80,7 +80,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["chat", "news"], ) ``` @@ -148,10 +147,10 @@ response = ask.chat.get_deep_news( ## Backtesting with a knowledge cutoff -`cutoff_datetime` tells every tool to ignore information after a point in -time. Also cap the news searches with `filter_params["end_timestamp"]` -so the two agree. This lets you evaluate research or forecasts as of a -past date without leakage. +`cutoff_datetime` tells every tool to ignore information after a point +in time. Also cap the news searches with +`filter_params["end_timestamp"]` so the two agree. This lets you +evaluate research or forecasts as of a past date without leakage. ```python cutoff = datetime(2026, 4, 15, 14, 0, tzinfo=timezone.utc) @@ -164,6 +163,6 @@ response = ask.chat.get_deep_news( search_depth=3, max_depth=6, cutoff_datetime=cutoff, - filter_params={"end_timestamp": int(cutoff.timestamp()), "historical": True}, + filter_params={"end_timestamp": int(cutoff.timestamp())}, ) ``` diff --git a/cookbook/markdown/14_prompting_deep_research.md b/cookbook/markdown/14_prompting_deep_research.md index b877503..45cb711 100644 --- a/cookbook/markdown/14_prompting_deep_research.md +++ b/cookbook/markdown/14_prompting_deep_research.md @@ -142,7 +142,6 @@ from asknews_sdk import AskNewsSDK ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["chat", "news"], ) companies = """ diff --git a/cookbook/markdown/15_creating_an_alert.md b/cookbook/markdown/15_creating_an_alert.md index 0f83e64..f136d03 100644 --- a/cookbook/markdown/15_creating_an_alert.md +++ b/cookbook/markdown/15_creating_an_alert.md @@ -60,7 +60,6 @@ from asknews_sdk.dto.alert import ( ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["chat", "news"], ) ``` diff --git a/cookbook/markdown/16_using_the_mcp_server.md b/cookbook/markdown/16_using_the_mcp_server.md index 0442768..0bf8ff7 100644 --- a/cookbook/markdown/16_using_the_mcp_server.md +++ b/cookbook/markdown/16_using_the_mcp_server.md @@ -59,7 +59,8 @@ code generators mix these up, so be explicit: | `time_filter` default | `"crawl_date"` | `"pub_date"` | | `string_guarantee_op` default | `"OR"` | `"AND"` | | Exact time window | `start_timestamp` / `end_timestamp` (unix seconds) | `start_datetime` / `end_datetime` (ISO 8601) | -| Archive access | `historical=True` | No flag. Archive is searched automatically. Windows over 160 days must be split into several calls. | +| Archive access | Chosen from the window: a start more than 48 hours ago, or an end with no start | Same | +| Longest window | 160 days per call | 160 days per call | | `return_type` | `"string"`, `"dicts"`, `"both"` | `"string"`, `"dicts"` | | SDK method | MCP tool | Argument difference | diff --git a/cookbook/recipes/00_setup_and_core_concepts.py b/cookbook/recipes/00_setup_and_core_concepts.py index d6b310a..e466f71 100644 --- a/cookbook/recipes/00_setup_and_core_concepts.py +++ b/cookbook/recipes/00_setup_and_core_concepts.py @@ -14,6 +14,10 @@ # ```bash # export ASKNEWS_API_KEY="..." # ``` +# +# An API key carries the scopes it was created with, so the client needs no +# `scopes` argument. `scopes` applies only to OAuth client credentials +# (`client_id` and `client_secret`). # %% import os @@ -23,7 +27,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news", "chat", "stories", "analytics"], ) # %% [markdown] @@ -33,7 +36,7 @@ # ```python # from asknews_sdk import AsyncAskNewsSDK # -# async with AsyncAskNewsSDK(api_key=..., scopes=[...]) as ask: +# async with AsyncAskNewsSDK(api_key=...) as ask: # response = await ask.news.search_news(query="...") # ``` # @@ -68,13 +71,24 @@ # filters. When you know the company, person, or keyword that *must* appear, # guarantee it, then use `query` to describe what you care about. # -# ## Time: `hours_back`, `historical`, and timestamps +# ## Time: `hours_back`, timestamps, and `strategy` # # - `hours_back` (default `24`) is the simplest window, relative to now. -# - `start_timestamp` / `end_timestamp` (unix seconds) give an exact window. -# - `historical=False` (default) searches the **live index: the most recent -# ~48 hours**. Anything older needs `historical=True`. See +# - `start_timestamp` / `end_timestamp` (unix seconds) give an exact window +# and take precedence over `hours_back`. One request can span at most 160 +# days. +# - **One search covers every date.** Coverage goes back to 2023 and the +# window alone sets what is searched. The `historical` parameter is +# deprecated and has no effect, so leave it out. A window that starts within the last 48 hours costs 1 credit. +# One that starts further back costs 5: a `start_timestamp` more than 48 +# hours ago, `hours_back` above 48, an `end_timestamp` on its own, or +# `strategy="news knowledge"`. See # [02 Searching archive news](02_searching_archive_news.md). +# - For a past window, pass both timestamps. An `end_timestamp` without a +# `start_timestamp` looks 160 days back from it. +# - `strategy="latest news"` searches the last 48 hours and +# `strategy="news knowledge"` the last 150 days; both set `method="kw"` +# and replace the window you pass. # - `time_filter="crawl_date"` (default) filters on when AskNews ingested # the article. `time_filter="pub_date"` filters on the publisher's date. # Use `pub_date` when "it happened in the last 24 hours" matters, e.g. for @@ -83,11 +97,21 @@ # # ## `method`: `kw` vs `nl` # -# - `method="kw"` (default) leans on keyword matching. Best when the query is +# - `method="kw"` (the default) leans on keyword matching. Best when the query is # a list of names, tickers, and terms. # - `method="nl"` leans on semantic meaning. Best when the query is a # sentence or a paragraph, e.g. a forecasting question. -# - `method="both"` blends the two. +# - `method="both"` blends the two. It cannot be paginated. +# +# ## Result order +# +# Results are ranked by relevance. `sort_by="pub_date"` sorts the page a +# search returned by date: you still get the best matches, arranged newest +# first, not the newest matches. Shorten the window when recency matters. +# +# A search with no `query` returns a page of articles from the window that +# pass your filters, sorted by date within that page. It is not necessarily +# the newest articles in the window. # # ## `return_type`: feeding an LLM vs feeding code # @@ -98,10 +122,16 @@ # `entities`, `source_id`, `page_rank`, `sentiment`, ...). # - `"both"`: both of the above. # -# ## `premium=True` +# ## Plan limits # -# Includes premium publisher content in the results. The examples in this -# cookbook set it wherever source quality matters. +# - `n_articles`: Pay as you go, Pro and Spelunker accept up to 10 per +# request, the default; more returns a 400 error. Analyst and Enterprise +# return up to 30, and a larger value is reduced to 30 without an error. +# - `domain_url` needs Analyst or Enterprise. +# - `return_graphs` and `return_geo` need Spelunker, Analyst, Enterprise, or +# wallet access. +# - DeepNews: the `"x"` source needs Spelunker or above, and `"reddit"` +# Analyst or above. # # ## Caching repeated queries # @@ -117,7 +147,6 @@ hours_back=24, n_articles=5, return_type="both", - premium=True, try_cache="1h", ) diff --git a/cookbook/recipes/01_getting_real_time_news.py b/cookbook/recipes/01_getting_real_time_news.py index 25a8f72..8a03e23 100644 --- a/cookbook/recipes/01_getting_real_time_news.py +++ b/cookbook/recipes/01_getting_real_time_news.py @@ -1,19 +1,20 @@ # %% [markdown] # # Getting real-time news # -# The default `search_news` call searches the live index (the last ~48 -# hours), which is what you want for "what's happening right now". +# The default `search_news` call covers the last 24 hours, which is what you +# want for "what's happening right now". # # Best practices: # -# - Keep `historical=False` (the default) for anything inside the last 48 -# hours. It is faster than an archive search. +# - Keep the window inside the last 48 hours (`hours_back=48` or less). +# That costs 1 credit instead of 5. # - Set `hours_back` explicitly. The default is 24. # - Use `time_filter="pub_date"` when the *publication* time matters (e.g. # "only stories published in the last 6 hours"). Use the default # `crawl_date` when polling for "new since my last call". -# - Use `sort_by="pub_date"` when you want the newest first instead of the -# most relevant first. +# - Use `sort_by="pub_date"` to arrange the results newest first. It sorts +# the best matches by date rather than fetching the newest articles, so +# pair it with a short `hours_back`. # %% import os @@ -24,7 +25,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news"], ) # %% [markdown] @@ -37,16 +37,15 @@ time_filter="pub_date", n_articles=10, return_type="string", - premium=True, ) print(response.as_string) # %% [markdown] -# ## Newest first, restricted to high-authority outlets +# ## Sorted by date, restricted to high-authority outlets # -# `page_rank` is an upper bound on a domain's popularity rank: lower is more -# prominent. `page_rank=100000` keeps the top ~100k domains and drops the -# long tail of low-authority sites. `diversify_sources=True` stops one outlet +# `page_rank` is an upper bound on a domain's rank: lower is more +# prominent, and `page_rank=100000` or lower targets top sources and drops +# the long tail of low-authority sites. `diversify_sources=True` stops one outlet # from dominating the results. # %% @@ -59,27 +58,26 @@ diversify_sources=True, n_articles=10, return_type="dicts", - premium=True, ) for a in response.as_dicts: print(f"{a.pub_date:%H:%M} | {a.source_id} | {a.title}") # %% [markdown] -# ## Everything new in a category, no query +# ## Browsing a category, no query # -# `query` is optional. With no query you get the latest articles that pass -# your filters. +# `query` is optional. With no query you get a page of articles from the +# window that pass your filters, sorted by date within the page. It is not +# necessarily the newest articles in the window, so keep the window short. # %% response = ask.news.search_news( categories=["Technology"], languages=["en"], hours_back=1, - n_articles=25, + n_articles=10, return_type="dicts", - premium=True, ) -print(len(response.as_dicts), "technology articles in the last hour") +print(len(response.as_dicts), "technology articles from the last hour") # %% [markdown] # ## Polling for new articles @@ -87,7 +85,8 @@ # For a lightweight poller, track the last time you checked and use # `start_timestamp` with the default `time_filter="crawl_date"`, so you pick # up anything AskNews ingested since then even if the publisher back-dated -# it. Deduplicate on `article_id`. +# it. Deduplicate on `article_id`. If more articles than one page can arrive +# between polls, paginate with `offset` (see [03 Paginating](03_paginating.md)). # %% seen: set = set() @@ -101,9 +100,8 @@ start_timestamp=last_checked, end_timestamp=now, time_filter="crawl_date", - n_articles=50, + n_articles=10, return_type="dicts", - premium=True, ) for a in response.as_dicts: if a.article_id not in seen: diff --git a/cookbook/recipes/02_searching_archive_news.py b/cookbook/recipes/02_searching_archive_news.py index ffd2577..dc890b7 100644 --- a/cookbook/recipes/02_searching_archive_news.py +++ b/cookbook/recipes/02_searching_archive_news.py @@ -1,14 +1,20 @@ # %% [markdown] # # Searching archive news # -# The live index holds the last ~48 hours. To search further back, set -# `historical=True` and give an explicit window. +# Coverage goes back to 2023, and the same `search_news` call reaches it: +# give a window that starts in the past. There is no separate mode or flag. # # Best practices: # -# - **Always pass `historical=True` for windows older than 48 hours.** -# Without it, an old `start_timestamp`/`end_timestamp` or a large -# `hours_back` quietly returns only recent articles. +# - **Pass both `start_timestamp` and `end_timestamp`.** A start more than +# 48 hours ago reaches back. An `end_timestamp` on its own looks 160 +# days back from it, which is rarely the window you meant. The +# `historical` parameter is deprecated and has no effect, so leave it +# out. +# - One request can span at most 160 days. Split longer periods into +# windows, see [03 Paginating](03_paginating.md). +# - A request whose window starts more than 48 hours ago costs 5 credits, +# and so does every page of it. # - Prefer `start_timestamp` / `end_timestamp` over a huge `hours_back` for # anything you want to reproduce later. # - Use `time_filter="pub_date"` for historical research: you almost always @@ -25,7 +31,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news"], ) # %% [markdown] @@ -37,14 +42,12 @@ response = ask.news.search_news( query="inflation rate United States CPI report", - historical=True, start_timestamp=int(start.timestamp()), end_timestamp=int(end.timestamp()), time_filter="pub_date", method="kw", n_articles=10, return_type="dicts", - premium=True, ) for a in response.as_dicts: print(f"{a.pub_date:%Y-%m-%d} | {a.source_id} | {a.title}") @@ -62,13 +65,11 @@ response = ask.news.search_news( query="Will the Federal Reserve cut interest rates at the November 2024 FOMC meeting?", method="nl", - historical=True, end_timestamp=int(as_of.timestamp()), start_timestamp=int(as_of.timestamp()) - 14 * 24 * 3600, time_filter="pub_date", - n_articles=15, + n_articles=10, return_type="string", - premium=True, try_cache="7d", ) print(response.as_string) @@ -76,20 +77,18 @@ # %% [markdown] # ## Archive + entity guarantee # -# Hard filters work the same way on the archive. This pulls every article -# about a specific organization in a quarter. For more than one page of -# results, see [03 Paginating](03_paginating.md). +# Hard filters work the same way on the archive. This pulls articles about +# a specific organization in a quarter. For more than one page of results, +# see [03 Paginating](03_paginating.md). # %% response = ask.news.search_news( entity_guarantee=["Organization:OpenAI"], query="OpenAI funding round valuation investors", - historical=True, start_timestamp=int(datetime(2025, 1, 1, tzinfo=timezone.utc).timestamp()), end_timestamp=int(datetime(2025, 4, 1, tzinfo=timezone.utc).timestamp()), time_filter="pub_date", - n_articles=25, + n_articles=10, return_type="dicts", - premium=True, ) print(len(response.as_dicts), "articles") diff --git a/cookbook/recipes/03_paginating.py b/cookbook/recipes/03_paginating.py index 072d427..5d6cb6a 100644 --- a/cookbook/recipes/03_paginating.py +++ b/cookbook/recipes/03_paginating.py @@ -8,12 +8,18 @@ # Best practices: # # - Keep every parameter identical between pages. Only `offset` changes. -# - Use `n_articles=100` per page for bulk pulls (fewer round trips). +# - Use the largest page your plan allows: 10 on Pay as you go, Pro and +# Spelunker (more returns a 400 error), and 30 on Analyst and Enterprise +# (a larger value is reduced to 30). The examples use 10. # - Always set a cap (articles or pages) so a broad query cannot run away. # - Deduplicate on `article_id` when merging pages. # - For very large pulls across long time ranges, split the range into # windows and paginate each window. Smaller windows are more reliable -# and easy to resume. +# and easy to resume. A window can span at most 160 days, and numeric +# offsets stop at 3000. +# - Paginate with `method="kw"` or `"nl"`; `"both"` cannot be paginated. +# Pagination also needs at least one of `query`, `domain_url`, +# `entity_guarantee`, `authors`, or a geographic filter. # %% import os @@ -24,28 +30,28 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news"], ) # %% [markdown] # ## Basic offset loop # %% +window_end = datetime.now(timezone.utc) + params = dict( query="Thailand Cambodia border conflict ceasefire peace talks", entity_guarantee=["Location:Thailand", "Location:Cambodia"], entity_guarantee_op="AND", - hours_back=168, - historical=True, + start_timestamp=int((window_end - timedelta(days=7)).timestamp()), + end_timestamp=int(window_end.timestamp()), time_filter="pub_date", - n_articles=100, + n_articles=10, return_type="dicts", - premium=True, ) articles = {} offset = None -max_articles = 500 +max_articles = 100 while True: response = ask.news.search_news(**params, offset=offset or 0) @@ -73,13 +79,11 @@ def pull_window(start: datetime, end: datetime, **filters) -> list: while True: response = ask.news.search_news( **filters, - historical=True, start_timestamp=int(start.timestamp()), end_timestamp=int(end.timestamp()), time_filter="pub_date", - n_articles=100, + n_articles=10, return_type="dicts", - premium=True, offset=offset or 0, ) out.extend(response.as_dicts or []) diff --git a/cookbook/recipes/04_building_llm_context.py b/cookbook/recipes/04_building_llm_context.py index a47ab2a..0d940c5 100644 --- a/cookbook/recipes/04_building_llm_context.py +++ b/cookbook/recipes/04_building_llm_context.py @@ -24,7 +24,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news"], ) # %% [markdown] @@ -41,7 +40,6 @@ return_type="string", doc_start_delimiter="
", doc_end_delimiter="
", - premium=True, ) prompt = f"""Answer using only the articles below. Cite articles by their citation key. @@ -54,7 +52,8 @@ # ## Option 2: build your own context from dicts # # `return_graphs=True` adds an entity relationship graph per article and -# `return_geo=True` adds coordinates for extracted locations. Only request +# `return_geo=True` adds coordinates for extracted locations. Both need +# Spelunker, Analyst, Enterprise, or wallet access. Only request # them when your prompt uses them; they add tokens. # %% @@ -65,7 +64,6 @@ return_type="dicts", return_graphs=True, return_geo=True, - premium=True, ) diff --git a/cookbook/recipes/05_using_wikipedia.py b/cookbook/recipes/05_using_wikipedia.py index 36c07c9..075ac01 100644 --- a/cookbook/recipes/05_using_wikipedia.py +++ b/cookbook/recipes/05_using_wikipedia.py @@ -28,7 +28,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news"], ) # %% [markdown] @@ -77,10 +76,8 @@ query=f"{subject} contract funding drones defense AI", entity_guarantee=[f"Organization:{subject}"], hours_back=168, - historical=True, n_articles=10, return_type="string", - premium=True, ) background_text = "\n\n".join( diff --git a/cookbook/recipes/06_searching_twitter.py b/cookbook/recipes/06_searching_twitter.py index cccb68e..993616c 100644 --- a/cookbook/recipes/06_searching_twitter.py +++ b/cookbook/recipes/06_searching_twitter.py @@ -38,7 +38,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["chat"], ) # %% [markdown] diff --git a/cookbook/recipes/07_searching_google.py b/cookbook/recipes/07_searching_google.py index a8ffe1a..c8215b8 100644 --- a/cookbook/recipes/07_searching_google.py +++ b/cookbook/recipes/07_searching_google.py @@ -32,7 +32,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["chat"], ) # %% [markdown] diff --git a/cookbook/recipes/08_searching_podcasts.py b/cookbook/recipes/08_searching_podcasts.py index 1d4ebe7..f6a2941 100644 --- a/cookbook/recipes/08_searching_podcasts.py +++ b/cookbook/recipes/08_searching_podcasts.py @@ -9,7 +9,7 @@ # - `"none"`: exclude podcasts (articles only). # # All the usual filters (`entity_guarantee`, `string_guarantee`, -# time windows, `historical`) apply to podcasts too. +# and time windows) apply to podcasts too. # # Podcasts are where opinions, interviews, and long-form commentary live. # Reach for them when the question is "what are people saying about X" more @@ -23,7 +23,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news", "chat"], ) # %% [markdown] @@ -34,7 +33,6 @@ query="opinions on the war with Iran, commentary, debate", podcasts="only", hours_back=168, - historical=True, n_articles=10, return_type="dicts", ) @@ -53,7 +51,6 @@ entity_guarantee=["Person:Dario Amodei"], podcasts="only", hours_back=720, - historical=True, n_articles=10, return_type="string", ) @@ -71,7 +68,6 @@ podcasts="none", hours_back=24, n_articles=10, - premium=True, ) # %% [markdown] diff --git a/cookbook/recipes/09_tracking_a_company.py b/cookbook/recipes/09_tracking_a_company.py index 9ea69e0..1ef5646 100644 --- a/cookbook/recipes/09_tracking_a_company.py +++ b/cookbook/recipes/09_tracking_a_company.py @@ -36,7 +36,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news", "chat"], ) # %% [markdown] @@ -60,7 +59,6 @@ page_rank=100000, languages=["en"], return_type="both", - premium=True, ) print(response.as_string) @@ -77,7 +75,6 @@ time_filter="pub_date", n_articles=10, return_type="dicts", - premium=True, ) # %% [markdown] @@ -93,11 +90,9 @@ string_guarantee_op="OR", query="Databricks acquisition, acquires startup, deal terms, purchase price", hours_back=720, - historical=True, time_filter="pub_date", - n_articles=20, + n_articles=10, return_type="dicts", - premium=True, ) # %% [markdown] @@ -114,7 +109,6 @@ query="Apple Inc. iPhone, App Store, antitrust, Tim Cook, earnings", hours_back=24, n_articles=10, - premium=True, ) # %% [markdown] diff --git a/cookbook/recipes/10_tracking_a_person.py b/cookbook/recipes/10_tracking_a_person.py index de13e42..eb83269 100644 --- a/cookbook/recipes/10_tracking_a_person.py +++ b/cookbook/recipes/10_tracking_a_person.py @@ -26,7 +26,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news", "chat"], ) # %% [markdown] @@ -47,7 +46,6 @@ time_filter="pub_date", n_articles=10, return_type="both", - premium=True, ) print(response.as_string) @@ -63,10 +61,8 @@ entity_guarantee_op="AND", query="Daniel Ek Helsing chairman defense AI investment", hours_back=720, - historical=True, n_articles=10, return_type="dicts", - premium=True, ) # %% [markdown] @@ -76,7 +72,6 @@ response = ask.news.search_news( authors=["Kaitlan Collins"], hours_back=168, - historical=True, n_articles=10, return_type="dicts", ) @@ -104,7 +99,6 @@ time_filter="pub_date", n_articles=5, return_type="string", - premium=True, ) posts = ask.chat.live_web_search( queries=[f"(from:{handle} OR @{handle}) min_faves:20"], diff --git a/cookbook/recipes/11_tracking_a_product_brand_or_industry.py b/cookbook/recipes/11_tracking_a_product_brand_or_industry.py index 1861487..bde91e3 100644 --- a/cookbook/recipes/11_tracking_a_product_brand_or_industry.py +++ b/cookbook/recipes/11_tracking_a_product_brand_or_industry.py @@ -10,7 +10,7 @@ # | `entity_guarantee` with `Product:` / `Organization:` / `Location:` / `Event:` | Extracted entities that must appear | # | `reverse_string_guarantee` / `reverse_entity_guarantee` | Removing known noise | # | `categories` | Coarse topic restriction (`Business`, `Technology`, `Finance`, ...) | -# | `domain_url` / `bad_domain_url` | Trade press only, or excluding sites | +# | `domain_url` / `bad_domain_url` | Trade press only, or excluding sites. `domain_url` needs Analyst or Enterprise | # | `languages`, `countries`, `continents` | Market / geography | # | `sentiment` | Only negative (or positive) coverage | # | `page_rank` | Drop low-authority sites | @@ -34,7 +34,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["news"], ) # %% [markdown] @@ -47,10 +46,8 @@ entity_guarantee=["Organization:Apple"], query="Apple Vision Pro sales, reviews, price, shipments, developer adoption", hours_back=168, - historical=True, - n_articles=20, + n_articles=10, return_type="dicts", - premium=True, ) # %% [markdown] @@ -66,11 +63,9 @@ sentiment="negative", reporting_voice=["Objective", "Analytical"], hours_back=72, - historical=True, time_filter="pub_date", - n_articles=20, + n_articles=10, return_type="dicts", - premium=True, ) # %% [markdown] @@ -93,11 +88,9 @@ query="meal kit, recipe box, meal delivery kit, cook-at-home kit, food subscription", languages=["en", "es", "pt"], hours_back=720, - historical=True, time_filter="pub_date", - n_articles=50, + n_articles=10, return_type="dicts", - premium=True, ) # %% [markdown] @@ -119,9 +112,8 @@ languages=["en", "fr", "es", "de"], hours_back=24, time_filter="pub_date", - n_articles=25, + n_articles=10, return_type="both", - premium=True, ) # %% [markdown] @@ -132,8 +124,7 @@ query="semiconductor fab capacity, wafer starts, foundry pricing, advanced packaging", domain_url=["eetimes.com", "semiengineering.com", "digitimes.com", "anandtech.com"], hours_back=168, - historical=True, - n_articles=20, + n_articles=10, return_type="dicts", ) @@ -153,9 +144,8 @@ hours_back=48, time_filter="pub_date", method="kw", - n_articles=50, + n_articles=10, return_type="dicts", - premium=True, ) # %% [markdown] diff --git a/cookbook/recipes/12_deep_research_basics.py b/cookbook/recipes/12_deep_research_basics.py index a1f02b4..83986dd 100644 --- a/cookbook/recipes/12_deep_research_basics.py +++ b/cookbook/recipes/12_deep_research_basics.py @@ -14,7 +14,7 @@ # | `messages` | The task. Chat format; the last user message is the request. | # | `sources` | Which tools the agent may use (see below). Default `["asknews"]`. | # | `model` | The LLM driving the agent. | -# | `engine` | `"v2.0"` is the current engine; `"v1.5"` is the previous one (and the one alerts use). | +# | `engine` | `"v2.0"` is the current engine; `"v1.5"` is the previous one (and the one alerts use). The SDK defaults to `"v1"`, so set it explicitly. | # | `search_depth`, `max_depth` | How much research to do. See [13 Deep research depth](13_deep_research_depth.md). | # | `filter_params` | Defaults applied to the agent's AskNews searches (e.g. `hours_back`, `languages`). | # | `stream` | Stream the agent's thinking, tool calls, text, and sources as they happen. | @@ -29,10 +29,10 @@ # |---|---| # | `"asknews"` | News search (the `search_news` filters, incl. entity/string guarantees) | # | `"google"` | Live web search | -# | `"x"` | X (Twitter) advanced search | +# | `"x"` | X (Twitter) advanced search. Needs Spelunker or above | # | `"wiki"` | Wikipedia | # | `"podcasts"` | Podcast search | -# | `"reddit"` | Reddit threads | +# | `"reddit"` | Reddit threads. Needs Analyst or above | # | `"graph"` | News knowledge graph | # | `"charts"` | Chart generation from news data | # | `"full_text_discovery"` | Full article text | @@ -56,7 +56,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["chat", "news"], ) # %% [markdown] @@ -301,7 +300,7 @@ # from asknews_sdk.dto.deepnews import CreateDeepNewsResponseStreamSourceBatch # # async def main(): -# async with AsyncAskNewsSDK(api_key=..., scopes=["chat"]) as ask: +# async with AsyncAskNewsSDK(api_key=...) as ask: # stream = await ask.chat.get_deep_news( # messages=[{"role": "user", "content": question}], # sources=["asknews", "google"], @@ -357,7 +356,7 @@ # from asknews_sdk import AsyncAskNewsSDK # # async def main(): -# async with AsyncAskNewsSDK(api_key=..., scopes=["chat"]) as ask: +# async with AsyncAskNewsSDK(api_key=...) as ask: # questions = ["...", "...", "..."] # results = await asyncio.gather(*[ # ask.chat.get_deep_news( diff --git a/cookbook/recipes/13_deep_research_depth.py b/cookbook/recipes/13_deep_research_depth.py index f26af26..33f3edd 100644 --- a/cookbook/recipes/13_deep_research_depth.py +++ b/cookbook/recipes/13_deep_research_depth.py @@ -81,7 +81,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["chat", "news"], ) # %% [markdown] @@ -149,10 +148,10 @@ # %% [markdown] # ## Backtesting with a knowledge cutoff # -# `cutoff_datetime` tells every tool to ignore information after a point in -# time. Also cap the news searches with `filter_params["end_timestamp"]` -# so the two agree. This lets you evaluate research or forecasts as of a -# past date without leakage. +# `cutoff_datetime` tells every tool to ignore information after a point +# in time. Also cap the news searches with +# `filter_params["end_timestamp"]` so the two agree. This lets you +# evaluate research or forecasts as of a past date without leakage. # %% cutoff = datetime(2026, 4, 15, 14, 0, tzinfo=timezone.utc) @@ -165,5 +164,5 @@ search_depth=3, max_depth=6, cutoff_datetime=cutoff, - filter_params={"end_timestamp": int(cutoff.timestamp()), "historical": True}, + filter_params={"end_timestamp": int(cutoff.timestamp())}, ) diff --git a/cookbook/recipes/14_prompting_deep_research.py b/cookbook/recipes/14_prompting_deep_research.py index 9e13ef8..d78acbb 100644 --- a/cookbook/recipes/14_prompting_deep_research.py +++ b/cookbook/recipes/14_prompting_deep_research.py @@ -143,7 +143,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["chat", "news"], ) companies = """ diff --git a/cookbook/recipes/15_creating_an_alert.py b/cookbook/recipes/15_creating_an_alert.py index 9e9cdb1..00f971a 100644 --- a/cookbook/recipes/15_creating_an_alert.py +++ b/cookbook/recipes/15_creating_an_alert.py @@ -61,7 +61,6 @@ ask = AskNewsSDK( api_key=os.environ["ASKNEWS_API_KEY"], - scopes=["chat", "news"], ) # %% [markdown] diff --git a/cookbook/recipes/16_using_the_mcp_server.py b/cookbook/recipes/16_using_the_mcp_server.py index 8c0e596..e123c8a 100644 --- a/cookbook/recipes/16_using_the_mcp_server.py +++ b/cookbook/recipes/16_using_the_mcp_server.py @@ -60,7 +60,8 @@ # | `time_filter` default | `"crawl_date"` | `"pub_date"` | # | `string_guarantee_op` default | `"OR"` | `"AND"` | # | Exact time window | `start_timestamp` / `end_timestamp` (unix seconds) | `start_datetime` / `end_datetime` (ISO 8601) | -# | Archive access | `historical=True` | No flag. Archive is searched automatically. Windows over 160 days must be split into several calls. | +# | Archive access | Chosen from the window: a start more than 48 hours ago, or an end with no start | Same | +# | Longest window | 160 days per call | 160 days per call | # | `return_type` | `"string"`, `"dicts"`, `"both"` | `"string"`, `"dicts"` | # # | SDK method | MCP tool | Argument difference | From dca1e6ef0c8766593fee865a7d077cf6b0eca995 Mon Sep 17 00:00:00 2001 From: thorntwig Date: Thu, 5 Nov 2026 12:46:28 +0100 Subject: [PATCH 2/2] docs: Name cookbook recipes after the task they solve --- cookbook/README.md | 54 ++++++++++--------- cookbook/build.py | 11 +++- ...and_core_concepts.md => 00_get_started.md} | 36 +++++++------ ...al_time_news.md => 01_search_live_news.md} | 10 ++-- ...e_news.md => 02_search_historical_news.md} | 20 ++++--- ...ginating.md => 03_paginate_news_search.md} | 5 +- ...llm_context.md => 04_build_llm_context.md} | 5 +- ...ng_wikipedia.md => 05_search_wikipedia.md} | 9 ++-- ...hing_twitter.md => 06_search_x_twitter.md} | 5 +- ...ng_google.md => 07_search_the_live_web.md} | 10 ++-- ...hing_podcasts.md => 08_search_podcasts.md} | 9 ++-- ...g_a_company.md => 09_monitor_a_company.md} | 7 ++- ...ing_a_person.md => 10_monitor_a_person.md} | 7 ++- ...11_monitor_a_product_brand_or_industry.md} | 5 +- ...arch_basics.md => 12_run_deep_research.md} | 31 ++++++++--- ...depth.md => 13_set_deep_research_depth.md} | 8 ++- ...research.md => 14_prompt_deep_research.md} | 24 +++++---- ...ting_an_alert.md => 15_create_an_alert.md} | 9 ++-- ...ver.md => 16_connect_to_the_mcp_server.md} | 16 +++--- ..._on_mcp.md => 17_build_an_agent_on_mcp.md} | 5 +- cookbook/markdown/index.md | 36 ++++++------- ...and_core_concepts.py => 00_get_started.py} | 36 +++++++------ ...al_time_news.py => 01_search_live_news.py} | 10 ++-- ...e_news.py => 02_search_historical_news.py} | 20 ++++--- ...ginating.py => 03_paginate_news_search.py} | 5 +- ...llm_context.py => 04_build_llm_context.py} | 5 +- ...ng_wikipedia.py => 05_search_wikipedia.py} | 9 ++-- ...hing_twitter.py => 06_search_x_twitter.py} | 5 +- ...ng_google.py => 07_search_the_live_web.py} | 10 ++-- ...hing_podcasts.py => 08_search_podcasts.py} | 9 ++-- ...g_a_company.py => 09_monitor_a_company.py} | 7 ++- ...ing_a_person.py => 10_monitor_a_person.py} | 7 ++- ...11_monitor_a_product_brand_or_industry.py} | 5 +- ...arch_basics.py => 12_run_deep_research.py} | 31 ++++++++--- ...depth.py => 13_set_deep_research_depth.py} | 8 ++- ...research.py => 14_prompt_deep_research.py} | 24 +++++---- ...ting_an_alert.py => 15_create_an_alert.py} | 9 ++-- ...ver.py => 16_connect_to_the_mcp_server.py} | 16 +++--- ..._on_mcp.py => 17_build_an_agent_on_mcp.py} | 5 +- 39 files changed, 344 insertions(+), 199 deletions(-) rename cookbook/markdown/{00_setup_and_core_concepts.md => 00_get_started.md} (72%) rename cookbook/markdown/{01_getting_real_time_news.md => 01_search_live_news.md} (90%) rename cookbook/markdown/{02_searching_archive_news.md => 02_search_historical_news.md} (79%) rename cookbook/markdown/{03_paginating.md => 03_paginate_news_search.md} (95%) rename cookbook/markdown/{04_building_llm_context.md => 04_build_llm_context.md} (96%) rename cookbook/markdown/{05_using_wikipedia.md => 05_search_wikipedia.md} (90%) rename cookbook/markdown/{06_searching_twitter.md => 06_search_x_twitter.md} (94%) rename cookbook/markdown/{07_searching_google.md => 07_search_the_live_web.md} (89%) rename cookbook/markdown/{08_searching_podcasts.md => 08_search_podcasts.md} (89%) rename cookbook/markdown/{09_tracking_a_company.md => 09_monitor_a_company.md} (95%) rename cookbook/markdown/{10_tracking_a_person.md => 10_monitor_a_person.md} (93%) rename cookbook/markdown/{11_tracking_a_product_brand_or_industry.md => 11_monitor_a_product_brand_or_industry.md} (96%) rename cookbook/markdown/{12_deep_research_basics.md => 12_run_deep_research.md} (91%) rename cookbook/markdown/{13_deep_research_depth.md => 13_set_deep_research_depth.md} (95%) rename cookbook/markdown/{14_prompting_deep_research.md => 14_prompt_deep_research.md} (92%) rename cookbook/markdown/{15_creating_an_alert.md => 15_create_an_alert.md} (96%) rename cookbook/markdown/{16_using_the_mcp_server.md => 16_connect_to_the_mcp_server.md} (93%) rename cookbook/markdown/{17_building_agents_on_mcp.md => 17_build_an_agent_on_mcp.md} (98%) rename cookbook/recipes/{00_setup_and_core_concepts.py => 00_get_started.py} (73%) rename cookbook/recipes/{01_getting_real_time_news.py => 01_search_live_news.py} (90%) rename cookbook/recipes/{02_searching_archive_news.py => 02_search_historical_news.py} (78%) rename cookbook/recipes/{03_paginating.py => 03_paginate_news_search.py} (95%) rename cookbook/recipes/{04_building_llm_context.py => 04_build_llm_context.py} (96%) rename cookbook/recipes/{05_using_wikipedia.py => 05_search_wikipedia.py} (89%) rename cookbook/recipes/{06_searching_twitter.py => 06_search_x_twitter.py} (94%) rename cookbook/recipes/{07_searching_google.py => 07_search_the_live_web.py} (89%) rename cookbook/recipes/{08_searching_podcasts.py => 08_search_podcasts.py} (89%) rename cookbook/recipes/{09_tracking_a_company.py => 09_monitor_a_company.py} (95%) rename cookbook/recipes/{10_tracking_a_person.py => 10_monitor_a_person.py} (93%) rename cookbook/recipes/{11_tracking_a_product_brand_or_industry.py => 11_monitor_a_product_brand_or_industry.py} (96%) rename cookbook/recipes/{12_deep_research_basics.py => 12_run_deep_research.py} (91%) rename cookbook/recipes/{13_deep_research_depth.py => 13_set_deep_research_depth.py} (95%) rename cookbook/recipes/{14_prompting_deep_research.py => 14_prompt_deep_research.py} (92%) rename cookbook/recipes/{15_creating_an_alert.py => 15_create_an_alert.py} (96%) rename cookbook/recipes/{16_using_the_mcp_server.py => 16_connect_to_the_mcp_server.py} (93%) rename cookbook/recipes/{17_building_agents_on_mcp.py => 17_build_an_agent_on_mcp.py} (98%) diff --git a/cookbook/README.md b/cookbook/README.md index 1d6455e..391092b 100644 --- a/cookbook/README.md +++ b/cookbook/README.md @@ -17,33 +17,33 @@ PyCharm, or convert it to a notebook with `jupytext --to ipynb`. ## Recipes -| # | Recipe | Covers | -|---|---|---| -| 00 | Setup and core concepts | Client, which endpoint to use, filter-then-rank model, time windows, `kw` vs `nl`, result order, return types, caching, plan limits | -| 01 | Getting real-time news | The last 48 hours, `pub_date` vs `crawl_date`, sorting by date, polling | -| 02 | Searching archive news | Searching back to 2023 by window, exact windows, point-in-time context for backtests | -| 03 | Paginating | `offset` loops, caps, dedupe, windowed bulk pulls | -| 04 | Building LLM context | `as_string` vs custom context from `as_dicts`, citations, graphs, geo | -| 05 | Using Wikipedia | `search_wiki` parameters, background + news in one prompt | -| 06 | Searching X (Twitter) | Advanced search syntax, engagement floors, accounts | -| 07 | Searching Google | Live web search, `strict`, `lookback`, domains, single URL | -| 08 | Searching podcasts | `podcasts="only" / "include" / "none"`, podcasts in DeepNews | -| 09 | Tracking a company | Entity guarantee + descriptive query, variants, exclusions, volume | -| 10 | Tracking a person | Person guarantee, role in query, AND with a company, watchlists | -| 11 | Tracking a product, brand, or industry | Combining string/entity guarantees, region scoping, sentiment, trade press, share of voice | -| 12 | Deep research basics | `get_deep_news`, sources, streaming v2.0 events, `stream_sources_inline` per-call source batches, `filter_params`, async | -| 13 | Deep research depth | `search_depth` / `max_depth`: how and why, sizing guide, cutoff backtests | -| 14 | Prompting deep research | Surgical tool instructions, per-item procedures, fixed vs flexible params, report rules | -| 15 | Creating an alert | `ReportAbout` / `AlwaysAlertWhen` / `AlertOnceIf`, DeepNews reports, triggers, testing and managing | -| 16 | Using the MCP server | MCP vs SDK, auth and transport, tool catalog, MCP-vs-SDK parameter differences, connecting assistants, calling tools directly, `do_news_research` | -| 17 | Building agents on the MCP server | Tool selection, enforcing constraints with interceptors, rate-limit retries, date grounding, research system prompt, search budget, fail-fast, local tools | +| # | Recipe | Use this when | Calls | Covers | +|---|---|---|---|---| +| 00 | [Get started: setup and core concepts](markdown/00_get_started.md) | You are starting with the SDK, or choosing which AskNews endpoint fits your task. Every other recipe builds on the concepts here. | `AskNewsSDK`, `AsyncAskNewsSDK` | Client, which endpoint to use, filter-then-rank model, time windows, `kw` vs `nl`, result order, return types, caching, plan limits | +| 01 | [Search live news](markdown/01_search_live_news.md) | Your application or agent needs what is being reported now: current context for an LLM, the latest on a topic, or new coverage as it arrives. | `news.search_news` | The last 48 hours, `pub_date` vs `crawl_date`, sorting by date, polling | +| 02 | [Search historical news](markdown/02_search_historical_news.md) | The question is about a defined period in the past: how an event developed, what was reported at a given moment, or dated context for forecasting research and backtests. Coverage goes back to 2023. | `news.search_news` | Searching back to 2023 by window, exact windows, point-in-time context for backtests | +| 03 | [Paginate news search results](markdown/03_paginate_news_search.md) | One page of results is not enough: you need every match for a query, or a bulk pull over a long period. | `news.search_news` with `offset` | `offset` loops, caps, dedupe, windowed bulk pulls | +| 04 | [Build LLM context from news](markdown/04_build_llm_context.md) | You retrieve news for your own LLM and want context it can reason over and cite. | `news.search_news` | `as_string` vs custom context from `as_dicts`, citations, graphs, geo | +| 05 | [Search Wikipedia for background](markdown/05_search_wikipedia.md) | Your model needs the background behind the news: who a person is, what a company or institution does, or the history behind an event. | `wiki.search_wiki` | `search_wiki` parameters, background + news in one prompt | +| 06 | [Search X (Twitter)](markdown/06_search_x_twitter.md) | You need what was said on X: an account's own statements, or how people are reacting to an event. | `chat.live_web_search` with `domains=["x.com"]` | Advanced search syntax, engagement floors, accounts | +| 07 | [Search the live web (Google)](markdown/07_search_the_live_web.md) | The answer lives on the wider web rather than in news coverage: company blogs, press releases, regulator and court sites, documentation, or pages published minutes ago. | `chat.live_web_search` | Live web search, `strict`, `lookback`, domains, single URL | +| 08 | [Search podcasts](markdown/08_search_podcasts.md) | You want what people said rather than what was reported: interviews, opinion, and long-form commentary from podcast episodes. | `news.search_news` with `podcasts` | `podcasts="only" / "include" / "none"`, podcasts in DeepNews | +| 09 | [Monitor a company](markdown/09_monitor_a_company.md) | You follow one organization's coverage over time: launches, deals, earnings, leadership changes, and legal issues. | `news.search_news`, `news.get_index_counts` | Entity guarantee + descriptive query, variants, exclusions, volume | +| 10 | [Monitor a person](markdown/10_monitor_a_person.md) | You follow coverage of one person, such as an executive or a politician: what they said, and what was reported about them. | `news.search_news` | Person guarantee, role in query, AND with a company, watchlists | +| 11 | [Monitor a product, brand, or industry](markdown/11_monitor_a_product_brand_or_industry.md) | What you follow is a product, a brand, or an industry or market rather than one company, so no single entity filter covers it. | `news.search_news`, `news.get_index_counts` | Combining string/entity guarantees, region scoping, sentiment, trade press, share of voice | +| 12 | [Run deep research (DeepNews)](markdown/12_run_deep_research.md) | You want a researched, cited answer rather than a list of articles: a question that takes more than one search, such as an investigation, a fact-check, a forecast, or a report across many companies. DeepNews plans the searches, follows what it finds across your chosen sources, and writes the answer. | `chat.get_deep_news` | `get_deep_news`, sources, streaming v2.0 events, `stream_sources_inline` per-call source batches, `filter_params`, async | +| 13 | [Set deep research depth](markdown/13_set_deep_research_depth.md) | A DeepNews answer or report misses things, or does more research than the question needs. Depth sets how much the agent searches before it answers. | `chat.get_deep_news` | `search_depth` / `max_depth`: how and why, sizing guide, cutoff backtests | +| 14 | [Prompt deep research](markdown/14_prompt_deep_research.md) | You want to guide how DeepNews does its research: which tools it uses and how, what it focuses on, and how it formats the output. | `chat.get_deep_news` | Role and tools, exact tool parameters, per-item procedures, fixed vs flexible params, fallbacks, defining what matters, dates and citations, output format | +| 15 | [Create an alert](markdown/15_create_an_alert.md) | A question needs revisiting on a schedule: a recurring research report, or a notification when a described event happens. | `chat.create_alert`, `run_alert`, `update_alert`, `delete_alert` | `ReportAbout` / `AlwaysAlertWhen` / `AlertOnceIf`, DeepNews reports, triggers, testing and managing | +| 16 | [Connect to the AskNews MCP server](markdown/16_connect_to_the_mcp_server.md) | An LLM should decide which AskNews searches to run: inside an assistant such as Claude, ChatGPT, or Cursor, or in an agent you build. | MCP tools at `https://mcp.asknews.app` | MCP vs SDK, auth and transport, tool catalog, MCP-vs-SDK parameter differences, connecting assistants, calling tools directly, `do_news_research` | +| 17 | [Build an agent on the MCP server](markdown/17_build_an_agent_on_mcp.md) | You want your own model, loop, and prompt to do the research on AskNews tools, instead of calling DeepNews. | MCP tools with LangChain | Tool selection, enforcing constraints with interceptors, rate-limit retries, date grounding, research system prompt, search budget, fail-fast, local tools | ## Running ```bash pip install asknews export ASKNEWS_API_KEY="..." -python cookbook/recipes/01_getting_real_time_news.py +python cookbook/recipes/01_search_live_news.py ``` Recipe 15 creates, runs, and deletes a real alert. Change the trigger email @@ -61,9 +61,15 @@ python cookbook/build.py ## Adding a recipe -1. Copy an existing recipe to `recipes/NN_short_name.py`. -2. Start with a `# %% [markdown]` cell whose first line is `# # Title`. +1. Copy an existing recipe to `recipes/NN_short_name.py`. Name it after the + task, in the imperative and with the terms the API docs use + (`08_search_podcasts.py`), so readers and agents can match it to what + they want to do. +2. Start with a `# %% [markdown]` cell whose first line is `# # Title`, the + file name in words (`# # Search podcasts`), followed by a + `**Use this when** ...` line. 3. Open with the "best practices" for the topic, then alternate short prose cells with code cells that each show one idea. 4. Keep every recipe standalone: its own imports and client setup. -5. Run `python cookbook/build.py` and add the recipe to the table above. +5. Run `python cookbook/build.py` and add the recipe to the table above, + with the same "Use this when" text and the SDK methods it calls. diff --git a/cookbook/build.py b/cookbook/build.py index 08ef6aa..d6315b3 100644 --- a/cookbook/build.py +++ b/cookbook/build.py @@ -81,6 +81,13 @@ def title_of(markdown: str) -> str: return "" +def use_when_of(markdown: str) -> str: + for paragraph in markdown.split("\n\n"): + if paragraph.startswith("**Use this when**"): + return " ".join(paragraph.split()) + return "" + + def main() -> None: OUT.mkdir(exist_ok=True) index = [ @@ -94,7 +101,9 @@ def main() -> None: markdown = render(recipe.read_text()) target = OUT / f"{recipe.stem}.md" target.write_text(markdown) - index.append(f"- [{title_of(markdown)}]({target.name})") + entry = f"- [{title_of(markdown)}]({target.name})" + use_when = use_when_of(markdown) + index.append(f"{entry}: {use_when}" if use_when else entry) print(f"wrote {target.relative_to(ROOT)}") (OUT / "index.md").write_text("\n".join(index) + "\n") print(f"wrote {(OUT / 'index.md').relative_to(ROOT)}") diff --git a/cookbook/markdown/00_setup_and_core_concepts.md b/cookbook/markdown/00_get_started.md similarity index 72% rename from cookbook/markdown/00_setup_and_core_concepts.md rename to cookbook/markdown/00_get_started.md index 4a36944..5558387 100644 --- a/cookbook/markdown/00_setup_and_core_concepts.md +++ b/cookbook/markdown/00_get_started.md @@ -1,6 +1,7 @@ -# Setup and core concepts +# Get started: setup and core concepts -Read this first. Every other recipe assumes the concepts here. +**Use this when** you are starting with the SDK, or choosing which AskNews +endpoint fits your task. Every other recipe builds on the concepts here. ## Install @@ -41,20 +42,21 @@ async with AsyncAskNewsSDK(api_key=...) as ask: ## Which endpoint do I want? -| Need | Method | -|---|---| -| Fast, precise lookup when you already know the keywords or entities | `ask.news.search_news()` | -| Background / encyclopedic facts | `ask.wiki.search_wiki()` | -| Live X (Twitter) posts | `ask.chat.live_web_search(..., domains=["x.com"])` | -| Live Google / web results, LLM-distilled | `ask.chat.live_web_search()` | -| Podcast transcripts | `ask.news.search_news(..., podcasts="only")` | -| Iterative, multi-step research across all of the above | `ask.chat.get_deep_news()` | -| Scheduled monitoring that emails / webhooks a report | `ask.chat.create_alert()` | -| Give an LLM agent or assistant (Claude, ChatGPT, Cursor, LangChain) AskNews tools | The MCP server at `https://mcp.asknews.app`, see [16](16_using_the_mcp_server.md) | - -Rule of thumb: if you can write the search parameters yourself, use -`search_news`. If you need an agent to *discover* what to search for next -(follow leads, identify unknown entities, reconcile sources), use DeepNews. +| Need | Method | Recipes | +|---|---|---| +| Articles on a topic, current or historical, for your code or LLM to read | `ask.news.search_news()` | [01 Search live news](01_search_live_news.md), [02 Search historical news](02_search_historical_news.md), [03 Paginate news search results](03_paginate_news_search.md), [04 Build LLM context from news](04_build_llm_context.md), [09 Monitor a company](09_monitor_a_company.md), [10 Monitor a person](10_monitor_a_person.md), [11 Monitor a product, brand, or industry](11_monitor_a_product_brand_or_industry.md) | +| Background / encyclopedic facts | `ask.wiki.search_wiki()` | [05 Search Wikipedia for background](05_search_wikipedia.md) | +| Live X (Twitter) posts | `ask.chat.live_web_search(..., domains=["x.com"])` | [06 Search X (Twitter)](06_search_x_twitter.md) | +| Live Google / web results, LLM-distilled | `ask.chat.live_web_search()` | [07 Search the live web (Google)](07_search_the_live_web.md) | +| Podcast transcripts | `ask.news.search_news(..., podcasts="only")` | [08 Search podcasts](08_search_podcasts.md) | +| A researched, cited answer to a question that takes more than one search | `ask.chat.get_deep_news()` | [12 Run deep research (DeepNews)](12_run_deep_research.md), [13 Set deep research depth](13_set_deep_research_depth.md), [14 Prompt deep research](14_prompt_deep_research.md) | +| Research or a condition check on a schedule, delivered by email, webhook, or Google Docs | `ask.chat.create_alert()` | [15 Create an alert](15_create_an_alert.md) | +| Give an LLM agent or assistant (Claude, ChatGPT, Cursor, LangChain) AskNews tools | The MCP server at `https://mcp.asknews.app` | [16 Connect to the AskNews MCP server](16_connect_to_the_mcp_server.md), [17 Build an agent on the MCP server](17_build_an_agent_on_mcp.md) | + +Rule of thumb: use `search_news` when you want the articles, and your code +or model does the reading. Use DeepNews when you want the answer: it runs +the searches, follows what it finds into context you did not know to ask +for, and returns a synthesized response with citations. ## The `search_news` mental model @@ -82,7 +84,7 @@ guarantee it, then use `query` to describe what you care about. One that starts further back costs 5: a `start_timestamp` more than 48 hours ago, `hours_back` above 48, an `end_timestamp` on its own, or `strategy="news knowledge"`. See - [02 Searching archive news](02_searching_archive_news.md). + [02 Search historical news](02_search_historical_news.md). - For a past window, pass both timestamps. An `end_timestamp` without a `start_timestamp` looks 160 days back from it. - `strategy="latest news"` searches the last 48 hours and diff --git a/cookbook/markdown/01_getting_real_time_news.md b/cookbook/markdown/01_search_live_news.md similarity index 90% rename from cookbook/markdown/01_getting_real_time_news.md rename to cookbook/markdown/01_search_live_news.md index a44dd41..884ba6f 100644 --- a/cookbook/markdown/01_getting_real_time_news.md +++ b/cookbook/markdown/01_search_live_news.md @@ -1,4 +1,8 @@ -# Getting real-time news +# Search live news + +**Use this when** your application or agent needs what is being reported +now: current context for an LLM, the latest on a topic, or new coverage as +it arrives. The default `search_news` call covers the last 24 hours, which is what you want for "what's happening right now". @@ -85,7 +89,7 @@ For a lightweight poller, track the last time you checked and use `start_timestamp` with the default `time_filter="crawl_date"`, so you pick up anything AskNews ingested since then even if the publisher back-dated it. Deduplicate on `article_id`. If more articles than one page can arrive -between polls, paginate with `offset` (see [03 Paginating](03_paginating.md)). +between polls, paginate with `offset` (see [03 Paginate news search results](03_paginate_news_search.md)). ```python seen: set = set() @@ -111,4 +115,4 @@ for _ in range(3): ``` For anything more than a script, use an alert instead of a polling loop. -See [15 Creating an alert](15_creating_an_alert.md). +See [15 Create an alert](15_create_an_alert.md). diff --git a/cookbook/markdown/02_searching_archive_news.md b/cookbook/markdown/02_search_historical_news.md similarity index 79% rename from cookbook/markdown/02_searching_archive_news.md rename to cookbook/markdown/02_search_historical_news.md index 257d358..0da70c3 100644 --- a/cookbook/markdown/02_searching_archive_news.md +++ b/cookbook/markdown/02_search_historical_news.md @@ -1,7 +1,11 @@ -# Searching archive news +# Search historical news -Coverage goes back to 2023, and the same `search_news` call reaches it: -give a window that starts in the past. There is no separate mode or flag. +**Use this when** the question is about a defined period in the past: how +an event developed, what was reported at a given moment, or dated context +for forecasting research and backtests. Coverage goes back to 2023. + +The same `search_news` call reaches every date: give a window that starts +in the past. There is no separate mode or flag. Best practices: @@ -11,7 +15,7 @@ Best practices: `historical` parameter is deprecated and has no effect, so leave it out. - One request can span at most 160 days. Split longer periods into - windows, see [03 Paginating](03_paginating.md). + windows, see [03 Paginate news search results](03_paginate_news_search.md). - A request whose window starts more than 48 hours ago costs 5 credits, and so does every page of it. - Prefer `start_timestamp` / `end_timestamp` over a huge `hours_back` for @@ -74,11 +78,11 @@ response = ask.news.search_news( print(response.as_string) ``` -## Archive + entity guarantee +## Historical news + entity guarantee -Hard filters work the same way on the archive. This pulls articles about -a specific organization in a quarter. For more than one page of results, -see [03 Paginating](03_paginating.md). +Hard filters work the same way on historical news. This pulls articles +about a specific organization in a quarter. For more than one page of +results, see [03 Paginate news search results](03_paginate_news_search.md). ```python response = ask.news.search_news( diff --git a/cookbook/markdown/03_paginating.md b/cookbook/markdown/03_paginate_news_search.md similarity index 95% rename from cookbook/markdown/03_paginating.md rename to cookbook/markdown/03_paginate_news_search.md index 9b0e2bf..3bfccb0 100644 --- a/cookbook/markdown/03_paginating.md +++ b/cookbook/markdown/03_paginate_news_search.md @@ -1,4 +1,7 @@ -# Paginating +# Paginate news search results + +**Use this when** one page of results is not enough: you need every match +for a query, or a bulk pull over a long period. `search_news` returns at most `n_articles` per call. To go deeper, pass `response.offset` back into the **same** query. When `response.offset` diff --git a/cookbook/markdown/04_building_llm_context.md b/cookbook/markdown/04_build_llm_context.md similarity index 96% rename from cookbook/markdown/04_building_llm_context.md rename to cookbook/markdown/04_build_llm_context.md index 32df07d..662fd57 100644 --- a/cookbook/markdown/04_building_llm_context.md +++ b/cookbook/markdown/04_build_llm_context.md @@ -1,4 +1,7 @@ -# Building LLM context from news +# Build LLM context from news + +**Use this when** you retrieve news for your own LLM and want context it +can reason over and cite. The most common use of `search_news` is retrieval for your own LLM. There are two good ways to do it. diff --git a/cookbook/markdown/05_using_wikipedia.md b/cookbook/markdown/05_search_wikipedia.md similarity index 90% rename from cookbook/markdown/05_using_wikipedia.md rename to cookbook/markdown/05_search_wikipedia.md index daa2a60..e2d3f23 100644 --- a/cookbook/markdown/05_using_wikipedia.md +++ b/cookbook/markdown/05_search_wikipedia.md @@ -1,8 +1,11 @@ -# Using Wikipedia +# Search Wikipedia for background + +**Use this when** your model needs the background behind the news: who a +person is, what a company or institution does, or the history behind an +event. `ask.wiki.search_wiki()` searches a chunked Wikipedia index. Pair it with -news: Wikipedia gives the stable background (who someone is, what a -company does, the history of a conflict), news gives what changed. +news search: Wikipedia gives the background, news gives what changed. Parameters that matter: diff --git a/cookbook/markdown/06_searching_twitter.md b/cookbook/markdown/06_search_x_twitter.md similarity index 94% rename from cookbook/markdown/06_searching_twitter.md rename to cookbook/markdown/06_search_x_twitter.md index 17c0508..b09c9fd 100644 --- a/cookbook/markdown/06_searching_twitter.md +++ b/cookbook/markdown/06_search_x_twitter.md @@ -1,4 +1,7 @@ -# Searching X (Twitter) +# Search X (Twitter) + +**Use this when** you need what was said on X: an account's own +statements, or how people are reacting to an event. X search goes through `ask.chat.live_web_search()` with `domains=["x.com"]`. Each entry in `queries` is an **X advanced search diff --git a/cookbook/markdown/07_searching_google.md b/cookbook/markdown/07_search_the_live_web.md similarity index 89% rename from cookbook/markdown/07_searching_google.md rename to cookbook/markdown/07_search_the_live_web.md index 69e5fbf..fc5cc24 100644 --- a/cookbook/markdown/07_searching_google.md +++ b/cookbook/markdown/07_search_the_live_web.md @@ -1,13 +1,13 @@ -# Searching Google (live web search) +# Search the live web (Google) + +**Use this when** the answer lives on the wider web rather than in news +coverage: company blogs, press releases, regulator and court sites, +documentation, or pages published minutes ago. `ask.chat.live_web_search()` runs a live web search, fetches the pages, and returns an LLM-distilled summary of each one (`key_points`), plus a prompt-ready `as_string`. -Use it to fill gaps in the news index: company blogs, press release pages, -regulator and court sites, niche trade publications, or anything published -in the last few minutes. - Parameters that matter: - `queries`: a list of Google-style keyword queries. Short keyword strings diff --git a/cookbook/markdown/08_searching_podcasts.md b/cookbook/markdown/08_search_podcasts.md similarity index 89% rename from cookbook/markdown/08_searching_podcasts.md rename to cookbook/markdown/08_search_podcasts.md index 54f422f..ace90cb 100644 --- a/cookbook/markdown/08_searching_podcasts.md +++ b/cookbook/markdown/08_search_podcasts.md @@ -1,4 +1,7 @@ -# Searching podcasts +# Search podcasts + +**Use this when** you want what people said rather than what was reported: +interviews, opinion, and long-form commentary from podcast episodes. Podcast episodes are indexed alongside news and are searchable with `search_news`. The `podcasts` parameter controls them: @@ -11,8 +14,6 @@ All the usual filters (`entity_guarantee`, `string_guarantee`, and time windows) apply to podcasts too. Podcasts are where opinions, interviews, and long-form commentary live. -Reach for them when the question is "what are people saying about X" more -than "what happened". ```python import os @@ -73,7 +74,7 @@ response = ask.news.search_news( ## Podcasts as a DeepNews source DeepNews can research podcasts as their own source. See -[12 Deep research basics](12_deep_research_basics.md) for streaming +[12 Run deep research (DeepNews)](12_run_deep_research.md) for streaming details. ```python diff --git a/cookbook/markdown/09_tracking_a_company.md b/cookbook/markdown/09_monitor_a_company.md similarity index 95% rename from cookbook/markdown/09_tracking_a_company.md rename to cookbook/markdown/09_monitor_a_company.md index d9c65bc..778f353 100644 --- a/cookbook/markdown/09_tracking_a_company.md +++ b/cookbook/markdown/09_monitor_a_company.md @@ -1,4 +1,7 @@ -# Tracking a company +# Monitor a company + +**Use this when** you follow one organization's coverage over time: +launches, deals, earnings, leadership changes, and legal issues. The reliable pattern is **entity guarantee + descriptive query**: @@ -114,7 +117,7 @@ response = ask.news.search_news( ## Company news + the company's own posts News misses what a company announces on social media. Pair the search -with an X search. See [06 Searching X](06_searching_twitter.md). +with an X search. See [06 Search X (Twitter)](06_search_x_twitter.md). ```python posts = ask.chat.live_web_search( diff --git a/cookbook/markdown/10_tracking_a_person.md b/cookbook/markdown/10_monitor_a_person.md similarity index 93% rename from cookbook/markdown/10_tracking_a_person.md rename to cookbook/markdown/10_monitor_a_person.md index 150f9ad..73e15df 100644 --- a/cookbook/markdown/10_tracking_a_person.md +++ b/cookbook/markdown/10_monitor_a_person.md @@ -1,4 +1,7 @@ -# Tracking a person +# Monitor a person + +**Use this when** you follow coverage of one person, such as an executive +or a politician: what they said, and what was reported about them. Same pattern as companies: `entity_guarantee=["Person:"]` to guarantee the person is in the article, and a `query` that describes @@ -109,4 +112,4 @@ for name, description, handle in watchlist: For a watchlist that should run every morning and land in an inbox, let DeepNews do these searches inside an alert. See -[15 Creating an alert](15_creating_an_alert.md). +[15 Create an alert](15_create_an_alert.md). diff --git a/cookbook/markdown/11_tracking_a_product_brand_or_industry.md b/cookbook/markdown/11_monitor_a_product_brand_or_industry.md similarity index 96% rename from cookbook/markdown/11_tracking_a_product_brand_or_industry.md rename to cookbook/markdown/11_monitor_a_product_brand_or_industry.md index a3ef374..5c08ee6 100644 --- a/cookbook/markdown/11_tracking_a_product_brand_or_industry.md +++ b/cookbook/markdown/11_monitor_a_product_brand_or_industry.md @@ -1,4 +1,7 @@ -# Tracking a product, brand, or industry +# Monitor a product, brand, or industry + +**Use this when** what you follow is a product, a brand, or an industry or +market rather than one company, so no single entity filter covers it. Products, brands, and industries rarely map to one clean entity, so you combine filters. The building blocks: diff --git a/cookbook/markdown/12_deep_research_basics.md b/cookbook/markdown/12_run_deep_research.md similarity index 91% rename from cookbook/markdown/12_deep_research_basics.md rename to cookbook/markdown/12_run_deep_research.md index e4ac43d..b23f1a1 100644 --- a/cookbook/markdown/12_deep_research_basics.md +++ b/cookbook/markdown/12_run_deep_research.md @@ -1,10 +1,25 @@ -# Deep research (DeepNews) basics +# Run deep research (DeepNews) -`ask.chat.get_deep_news()` runs a research agent. It decides what to -search, reads the results, follows leads, searches again, and writes a -cited answer. Use it when you cannot write the right search parameters -up front: unknown entities, multi-hop questions, reconciling conflicting -sources, or reports that cover many things. +**Use this when** you want a researched, cited answer rather than a list +of articles: a question that takes more than one search, such as an +investigation, a fact-check, a forecast, or a report across many +companies. DeepNews plans the searches, follows what it finds across your +chosen sources, and writes the answer. + +`ask.chat.get_deep_news()` calls DeepNews, the AskNews research agent. It +searches the news knowledge graph and the other sources you allow, reflects +on what came back, follows the leads that matter, and returns a synthesized +answer with citations you can check. + +Because it moves from what it finds to what is connected to it, DeepNews +also brings in context you did not know to ask for: the related events, +the other people and organizations involved, and the earlier developments +that explain the current ones. The answer covers the whole picture, not +only the question as you phrased it. + +When you want the articles themselves, for your code or model to read, +`search_news` is faster and cheaper. To run the same research on a +schedule, see [15 Create an alert](15_create_an_alert.md). The pieces you control: @@ -14,7 +29,7 @@ The pieces you control: | `sources` | Which tools the agent may use (see below). Default `["asknews"]`. | | `model` | The LLM driving the agent. | | `engine` | `"v2.0"` is the current engine; `"v1.5"` is the previous one (and the one alerts use). The SDK defaults to `"v1"`, so set it explicitly. | -| `search_depth`, `max_depth` | How much research to do. See [13 Deep research depth](13_deep_research_depth.md). | +| `search_depth`, `max_depth` | How much research to do. See [13 Set deep research depth](13_set_deep_research_depth.md). | | `filter_params` | Defaults applied to the agent's AskNews searches (e.g. `hours_back`, `languages`). | | `stream` | Stream the agent's thinking, tool calls, text, and sources as they happen. | | `stream_sources_inline` | Engine `v2.0` streams only: also emit each tool call's sources as a batch right after the call, not just at the end. See below. | @@ -43,7 +58,7 @@ Best practices: - Stream while you develop. Watching the tool calls is the fastest way to see whether the agent is searching the way you intended, and to learn the tool names and parameters it uses (useful for prompting, see - [14 Prompting deep research](14_prompting_deep_research.md)). + [14 Prompt deep research](14_prompt_deep_research.md)). - Start with small depth and raise it only when the answer is missing things. diff --git a/cookbook/markdown/13_deep_research_depth.md b/cookbook/markdown/13_set_deep_research_depth.md similarity index 95% rename from cookbook/markdown/13_deep_research_depth.md rename to cookbook/markdown/13_set_deep_research_depth.md index dd4882d..6173836 100644 --- a/cookbook/markdown/13_deep_research_depth.md +++ b/cookbook/markdown/13_set_deep_research_depth.md @@ -1,4 +1,8 @@ -# Deep research depth: how and why +# Set deep research depth + +**Use this when** a DeepNews answer or report misses things, or does more +research than the question needs. Depth sets how much the agent searches +before it answers. Depth is the most important DeepNews setting. It decides how much research the agent does before writing, which decides coverage, cost, @@ -57,7 +61,7 @@ Depth gives the agent budget. The prompt tells it how to spend that budget. For list-shaped tasks, spell out the per-item procedure ("for each company do Step 1 then Step 2, then move on") so the agent spends its rounds evenly instead of going deep on the first few items. See -[14 Prompting deep research](14_prompting_deep_research.md). +[14 Prompt deep research](14_prompt_deep_research.md). ## Other knobs for deep runs diff --git a/cookbook/markdown/14_prompting_deep_research.md b/cookbook/markdown/14_prompt_deep_research.md similarity index 92% rename from cookbook/markdown/14_prompting_deep_research.md rename to cookbook/markdown/14_prompt_deep_research.md index 45cb711..3ab3151 100644 --- a/cookbook/markdown/14_prompting_deep_research.md +++ b/cookbook/markdown/14_prompt_deep_research.md @@ -1,10 +1,14 @@ -# Prompting deep research with surgical precision +# Prompt deep research -DeepNews is an agent with tools. The single biggest quality lever is -telling it **exactly how to use those tools**: which tool, in what order, -with which parameters, and what to do when a search comes back empty. -Leaving it to guess works for simple questions and fails for monitoring -and reporting. +**Use this when** you want to guide how DeepNews does its research: which +tools it uses and how, what it focuses on, and how it formats the output. + +DeepNews is an agent with tools, and the prompt is where you direct it. +The single biggest quality lever is telling it **exactly how to use those +tools**: which tool, in what order, with which parameters, and what to do +when a search comes back empty. Then tell it what matters, so it spends +its searches there, and what the answer should look like. Leaving it to +guess works for simple questions and fails for monitoring and reporting. The patterns below come from production daily monitoring reports. @@ -19,7 +23,7 @@ to conduct your research. ``` Refer to tools by name, the same way every time. Stream a run once -([12 Deep research basics](12_deep_research_basics.md)) to see the exact +([12 Run deep research (DeepNews)](12_run_deep_research.md)) to see the exact tool names and argument names the agent uses. ## 2. Put inputs in delimited, structured blocks @@ -48,7 +52,7 @@ every company before moving on. ``` Size `search_depth` to the loop: items x steps. See -[13 Deep research depth](13_deep_research_depth.md). +[13 Set deep research depth](13_set_deep_research_depth.md). ## 4. Show the exact tool parameters, with placeholders @@ -64,8 +68,8 @@ n_articles=5 ``` -Everything in [09 Tracking a company](09_tracking_a_company.md) and -[11 Tracking a product, brand, or industry](11_tracking_a_product_brand_or_industry.md) +Everything in [09 Monitor a company](09_monitor_a_company.md) and +[11 Monitor a product, brand, or industry](11_monitor_a_product_brand_or_industry.md) applies here: you are teaching the agent your best `search_news` parameters. diff --git a/cookbook/markdown/15_creating_an_alert.md b/cookbook/markdown/15_create_an_alert.md similarity index 96% rename from cookbook/markdown/15_creating_an_alert.md rename to cookbook/markdown/15_create_an_alert.md index f136d03..b8476d0 100644 --- a/cookbook/markdown/15_creating_an_alert.md +++ b/cookbook/markdown/15_create_an_alert.md @@ -1,4 +1,7 @@ -# Creating an alert +# Create an alert + +**Use this when** a question needs revisiting on a schedule: a recurring +research report, or a notification when a described event happens. An alert runs on a cron schedule, gathers information, optionally checks a condition, optionally writes a report, and fires triggers (email, @@ -32,9 +35,9 @@ Best practices: - **Put all the research instructions in the report prompt.** For a report, the prompt *is* the alert. Everything in - [14 Prompting deep research](14_prompting_deep_research.md) applies: + [14 Prompt deep research](14_prompt_deep_research.md) applies: tool parameters, per-item procedures, strict date rules. -- **Size depth to the prompt** ([13 Deep research depth](13_deep_research_depth.md)). +- **Size depth to the prompt** ([13 Set deep research depth](13_set_deep_research_depth.md)). A 50-entity monitor with `search_depth=2` will skip most entities. - **Enforce recency in two places**: in the prompt ("last 24 hours only, never expand hours_back") and in `filter_params` (`hours_back`, diff --git a/cookbook/markdown/16_using_the_mcp_server.md b/cookbook/markdown/16_connect_to_the_mcp_server.md similarity index 93% rename from cookbook/markdown/16_using_the_mcp_server.md rename to cookbook/markdown/16_connect_to_the_mcp_server.md index 0bf8ff7..168203f 100644 --- a/cookbook/markdown/16_using_the_mcp_server.md +++ b/cookbook/markdown/16_connect_to_the_mcp_server.md @@ -1,4 +1,8 @@ -# Using the AskNews MCP server +# Connect to the AskNews MCP server + +**Use this when** an LLM should decide which AskNews searches to run: +inside an assistant such as Claude, ChatGPT, or Cursor, or in an agent you +build. AskNews runs a hosted [Model Context Protocol](https://modelcontextprotocol.io) server at `https://mcp.asknews.app`. It exposes AskNews search as tools that @@ -15,9 +19,9 @@ Code), ChatGPT, Cursor, LangChain/LangGraph agents, or your own client. AskNews's own DeepNews agent (`get_deep_news(engine="v2.0")`) is built on this MCP server. Its tools are the same ones you get here. If you want a -managed research agent, call DeepNews ([12 Deep research basics](12_deep_research_basics.md)). +managed research agent, call DeepNews ([12 Run deep research (DeepNews)](12_run_deep_research.md)). If you want your own model, loop, and prompt, build on the MCP tools -([17 Building agents on the MCP server](17_building_agents_on_mcp.md)). +([17 Build an agent on the MCP server](17_build_an_agent_on_mcp.md)). ## Connection facts @@ -59,7 +63,7 @@ code generators mix these up, so be explicit: | `time_filter` default | `"crawl_date"` | `"pub_date"` | | `string_guarantee_op` default | `"OR"` | `"AND"` | | Exact time window | `start_timestamp` / `end_timestamp` (unix seconds) | `start_datetime` / `end_datetime` (ISO 8601) | -| Archive access | Chosen from the window: a start more than 48 hours ago, or an end with no start | Same | +| Historical news | Chosen from the window: a start more than 48 hours ago, or an end with no start | Same | | Longest window | 160 days per call | 160 days per call | | `return_type` | `"string"`, `"dicts"`, `"both"` | `"string"`, `"dicts"` | @@ -156,7 +160,7 @@ async def call_tools() -> None: print(news.content[0].text) # An exact window uses ISO 8601 datetimes, not unix timestamps. - archive = await client.call_tool( + historical = await client.call_tool( "search_news", { "query": "ECB interest rate decision", @@ -165,7 +169,7 @@ async def call_tools() -> None: "return_type": "dicts", }, ) - for article in archive.structured_content["as_dicts"]: + for article in historical.structured_content["as_dicts"]: print(article["pub_date"], article["title"]) posts = await client.call_tool( diff --git a/cookbook/markdown/17_building_agents_on_mcp.md b/cookbook/markdown/17_build_an_agent_on_mcp.md similarity index 98% rename from cookbook/markdown/17_building_agents_on_mcp.md rename to cookbook/markdown/17_build_an_agent_on_mcp.md index 21404ad..2185630 100644 --- a/cookbook/markdown/17_building_agents_on_mcp.md +++ b/cookbook/markdown/17_build_an_agent_on_mcp.md @@ -1,4 +1,7 @@ -# Building agents on the MCP server +# Build an agent on the MCP server + +**Use this when** you want your own model, loop, and prompt to do the +research on AskNews tools, instead of calling DeepNews. This recipe builds a research agent on the AskNews MCP tools with LangChain. The practices come from AskNews's own DeepNews agent, which runs on these diff --git a/cookbook/markdown/index.md b/cookbook/markdown/index.md index be656f7..847614d 100644 --- a/cookbook/markdown/index.md +++ b/cookbook/markdown/index.md @@ -3,21 +3,21 @@ Runnable recipes for the AskNews Python SDK. Each page is generated from the matching file in `cookbook/recipes/`. -- [Setup and core concepts](00_setup_and_core_concepts.md) -- [Getting real-time news](01_getting_real_time_news.md) -- [Searching archive news](02_searching_archive_news.md) -- [Paginating](03_paginating.md) -- [Building LLM context from news](04_building_llm_context.md) -- [Using Wikipedia](05_using_wikipedia.md) -- [Searching X (Twitter)](06_searching_twitter.md) -- [Searching Google (live web search)](07_searching_google.md) -- [Searching podcasts](08_searching_podcasts.md) -- [Tracking a company](09_tracking_a_company.md) -- [Tracking a person](10_tracking_a_person.md) -- [Tracking a product, brand, or industry](11_tracking_a_product_brand_or_industry.md) -- [Deep research (DeepNews) basics](12_deep_research_basics.md) -- [Deep research depth: how and why](13_deep_research_depth.md) -- [Prompting deep research with surgical precision](14_prompting_deep_research.md) -- [Creating an alert](15_creating_an_alert.md) -- [Using the AskNews MCP server](16_using_the_mcp_server.md) -- [Building agents on the MCP server](17_building_agents_on_mcp.md) +- [Get started: setup and core concepts](00_get_started.md): **Use this when** you are starting with the SDK, or choosing which AskNews endpoint fits your task. Every other recipe builds on the concepts here. +- [Search live news](01_search_live_news.md): **Use this when** your application or agent needs what is being reported now: current context for an LLM, the latest on a topic, or new coverage as it arrives. +- [Search historical news](02_search_historical_news.md): **Use this when** the question is about a defined period in the past: how an event developed, what was reported at a given moment, or dated context for forecasting research and backtests. Coverage goes back to 2023. +- [Paginate news search results](03_paginate_news_search.md): **Use this when** one page of results is not enough: you need every match for a query, or a bulk pull over a long period. +- [Build LLM context from news](04_build_llm_context.md): **Use this when** you retrieve news for your own LLM and want context it can reason over and cite. +- [Search Wikipedia for background](05_search_wikipedia.md): **Use this when** your model needs the background behind the news: who a person is, what a company or institution does, or the history behind an event. +- [Search X (Twitter)](06_search_x_twitter.md): **Use this when** you need what was said on X: an account's own statements, or how people are reacting to an event. +- [Search the live web (Google)](07_search_the_live_web.md): **Use this when** the answer lives on the wider web rather than in news coverage: company blogs, press releases, regulator and court sites, documentation, or pages published minutes ago. +- [Search podcasts](08_search_podcasts.md): **Use this when** you want what people said rather than what was reported: interviews, opinion, and long-form commentary from podcast episodes. +- [Monitor a company](09_monitor_a_company.md): **Use this when** you follow one organization's coverage over time: launches, deals, earnings, leadership changes, and legal issues. +- [Monitor a person](10_monitor_a_person.md): **Use this when** you follow coverage of one person, such as an executive or a politician: what they said, and what was reported about them. +- [Monitor a product, brand, or industry](11_monitor_a_product_brand_or_industry.md): **Use this when** what you follow is a product, a brand, or an industry or market rather than one company, so no single entity filter covers it. +- [Run deep research (DeepNews)](12_run_deep_research.md): **Use this when** you want a researched, cited answer rather than a list of articles: a question that takes more than one search, such as an investigation, a fact-check, a forecast, or a report across many companies. DeepNews plans the searches, follows what it finds across your chosen sources, and writes the answer. +- [Set deep research depth](13_set_deep_research_depth.md): **Use this when** a DeepNews answer or report misses things, or does more research than the question needs. Depth sets how much the agent searches before it answers. +- [Prompt deep research](14_prompt_deep_research.md): **Use this when** you want to guide how DeepNews does its research: which tools it uses and how, what it focuses on, and how it formats the output. +- [Create an alert](15_create_an_alert.md): **Use this when** a question needs revisiting on a schedule: a recurring research report, or a notification when a described event happens. +- [Connect to the AskNews MCP server](16_connect_to_the_mcp_server.md): **Use this when** an LLM should decide which AskNews searches to run: inside an assistant such as Claude, ChatGPT, or Cursor, or in an agent you build. +- [Build an agent on the MCP server](17_build_an_agent_on_mcp.md): **Use this when** you want your own model, loop, and prompt to do the research on AskNews tools, instead of calling DeepNews. diff --git a/cookbook/recipes/00_setup_and_core_concepts.py b/cookbook/recipes/00_get_started.py similarity index 73% rename from cookbook/recipes/00_setup_and_core_concepts.py rename to cookbook/recipes/00_get_started.py index e466f71..228901e 100644 --- a/cookbook/recipes/00_setup_and_core_concepts.py +++ b/cookbook/recipes/00_get_started.py @@ -1,7 +1,8 @@ # %% [markdown] -# # Setup and core concepts +# # Get started: setup and core concepts # -# Read this first. Every other recipe assumes the concepts here. +# **Use this when** you are starting with the SDK, or choosing which AskNews +# endpoint fits your task. Every other recipe builds on the concepts here. # # ## Install # @@ -42,20 +43,21 @@ # # ## Which endpoint do I want? # -# | Need | Method | -# |---|---| -# | Fast, precise lookup when you already know the keywords or entities | `ask.news.search_news()` | -# | Background / encyclopedic facts | `ask.wiki.search_wiki()` | -# | Live X (Twitter) posts | `ask.chat.live_web_search(..., domains=["x.com"])` | -# | Live Google / web results, LLM-distilled | `ask.chat.live_web_search()` | -# | Podcast transcripts | `ask.news.search_news(..., podcasts="only")` | -# | Iterative, multi-step research across all of the above | `ask.chat.get_deep_news()` | -# | Scheduled monitoring that emails / webhooks a report | `ask.chat.create_alert()` | -# | Give an LLM agent or assistant (Claude, ChatGPT, Cursor, LangChain) AskNews tools | The MCP server at `https://mcp.asknews.app`, see [16](16_using_the_mcp_server.md) | -# -# Rule of thumb: if you can write the search parameters yourself, use -# `search_news`. If you need an agent to *discover* what to search for next -# (follow leads, identify unknown entities, reconcile sources), use DeepNews. +# | Need | Method | Recipes | +# |---|---|---| +# | Articles on a topic, current or historical, for your code or LLM to read | `ask.news.search_news()` | [01 Search live news](01_search_live_news.md), [02 Search historical news](02_search_historical_news.md), [03 Paginate news search results](03_paginate_news_search.md), [04 Build LLM context from news](04_build_llm_context.md), [09 Monitor a company](09_monitor_a_company.md), [10 Monitor a person](10_monitor_a_person.md), [11 Monitor a product, brand, or industry](11_monitor_a_product_brand_or_industry.md) | +# | Background / encyclopedic facts | `ask.wiki.search_wiki()` | [05 Search Wikipedia for background](05_search_wikipedia.md) | +# | Live X (Twitter) posts | `ask.chat.live_web_search(..., domains=["x.com"])` | [06 Search X (Twitter)](06_search_x_twitter.md) | +# | Live Google / web results, LLM-distilled | `ask.chat.live_web_search()` | [07 Search the live web (Google)](07_search_the_live_web.md) | +# | Podcast transcripts | `ask.news.search_news(..., podcasts="only")` | [08 Search podcasts](08_search_podcasts.md) | +# | A researched, cited answer to a question that takes more than one search | `ask.chat.get_deep_news()` | [12 Run deep research (DeepNews)](12_run_deep_research.md), [13 Set deep research depth](13_set_deep_research_depth.md), [14 Prompt deep research](14_prompt_deep_research.md) | +# | Research or a condition check on a schedule, delivered by email, webhook, or Google Docs | `ask.chat.create_alert()` | [15 Create an alert](15_create_an_alert.md) | +# | Give an LLM agent or assistant (Claude, ChatGPT, Cursor, LangChain) AskNews tools | The MCP server at `https://mcp.asknews.app` | [16 Connect to the AskNews MCP server](16_connect_to_the_mcp_server.md), [17 Build an agent on the MCP server](17_build_an_agent_on_mcp.md) | +# +# Rule of thumb: use `search_news` when you want the articles, and your code +# or model does the reading. Use DeepNews when you want the answer: it runs +# the searches, follows what it finds into context you did not know to ask +# for, and returns a synthesized response with citations. # # ## The `search_news` mental model # @@ -83,7 +85,7 @@ # One that starts further back costs 5: a `start_timestamp` more than 48 # hours ago, `hours_back` above 48, an `end_timestamp` on its own, or # `strategy="news knowledge"`. See -# [02 Searching archive news](02_searching_archive_news.md). +# [02 Search historical news](02_search_historical_news.md). # - For a past window, pass both timestamps. An `end_timestamp` without a # `start_timestamp` looks 160 days back from it. # - `strategy="latest news"` searches the last 48 hours and diff --git a/cookbook/recipes/01_getting_real_time_news.py b/cookbook/recipes/01_search_live_news.py similarity index 90% rename from cookbook/recipes/01_getting_real_time_news.py rename to cookbook/recipes/01_search_live_news.py index 8a03e23..25b890f 100644 --- a/cookbook/recipes/01_getting_real_time_news.py +++ b/cookbook/recipes/01_search_live_news.py @@ -1,5 +1,9 @@ # %% [markdown] -# # Getting real-time news +# # Search live news +# +# **Use this when** your application or agent needs what is being reported +# now: current context for an LLM, the latest on a topic, or new coverage as +# it arrives. # # The default `search_news` call covers the last 24 hours, which is what you # want for "what's happening right now". @@ -86,7 +90,7 @@ # `start_timestamp` with the default `time_filter="crawl_date"`, so you pick # up anything AskNews ingested since then even if the publisher back-dated # it. Deduplicate on `article_id`. If more articles than one page can arrive -# between polls, paginate with `offset` (see [03 Paginating](03_paginating.md)). +# between polls, paginate with `offset` (see [03 Paginate news search results](03_paginate_news_search.md)). # %% seen: set = set() @@ -112,4 +116,4 @@ # %% [markdown] # For anything more than a script, use an alert instead of a polling loop. -# See [15 Creating an alert](15_creating_an_alert.md). +# See [15 Create an alert](15_create_an_alert.md). diff --git a/cookbook/recipes/02_searching_archive_news.py b/cookbook/recipes/02_search_historical_news.py similarity index 78% rename from cookbook/recipes/02_searching_archive_news.py rename to cookbook/recipes/02_search_historical_news.py index dc890b7..70dd99a 100644 --- a/cookbook/recipes/02_searching_archive_news.py +++ b/cookbook/recipes/02_search_historical_news.py @@ -1,8 +1,12 @@ # %% [markdown] -# # Searching archive news +# # Search historical news # -# Coverage goes back to 2023, and the same `search_news` call reaches it: -# give a window that starts in the past. There is no separate mode or flag. +# **Use this when** the question is about a defined period in the past: how +# an event developed, what was reported at a given moment, or dated context +# for forecasting research and backtests. Coverage goes back to 2023. +# +# The same `search_news` call reaches every date: give a window that starts +# in the past. There is no separate mode or flag. # # Best practices: # @@ -12,7 +16,7 @@ # `historical` parameter is deprecated and has no effect, so leave it # out. # - One request can span at most 160 days. Split longer periods into -# windows, see [03 Paginating](03_paginating.md). +# windows, see [03 Paginate news search results](03_paginate_news_search.md). # - A request whose window starts more than 48 hours ago costs 5 credits, # and so does every page of it. # - Prefer `start_timestamp` / `end_timestamp` over a huge `hours_back` for @@ -75,11 +79,11 @@ print(response.as_string) # %% [markdown] -# ## Archive + entity guarantee +# ## Historical news + entity guarantee # -# Hard filters work the same way on the archive. This pulls articles about -# a specific organization in a quarter. For more than one page of results, -# see [03 Paginating](03_paginating.md). +# Hard filters work the same way on historical news. This pulls articles +# about a specific organization in a quarter. For more than one page of +# results, see [03 Paginate news search results](03_paginate_news_search.md). # %% response = ask.news.search_news( diff --git a/cookbook/recipes/03_paginating.py b/cookbook/recipes/03_paginate_news_search.py similarity index 95% rename from cookbook/recipes/03_paginating.py rename to cookbook/recipes/03_paginate_news_search.py index 5d6cb6a..df102ae 100644 --- a/cookbook/recipes/03_paginating.py +++ b/cookbook/recipes/03_paginate_news_search.py @@ -1,5 +1,8 @@ # %% [markdown] -# # Paginating +# # Paginate news search results +# +# **Use this when** one page of results is not enough: you need every match +# for a query, or a bulk pull over a long period. # # `search_news` returns at most `n_articles` per call. To go deeper, pass # `response.offset` back into the **same** query. When `response.offset` diff --git a/cookbook/recipes/04_building_llm_context.py b/cookbook/recipes/04_build_llm_context.py similarity index 96% rename from cookbook/recipes/04_building_llm_context.py rename to cookbook/recipes/04_build_llm_context.py index 0d940c5..b1fa64b 100644 --- a/cookbook/recipes/04_building_llm_context.py +++ b/cookbook/recipes/04_build_llm_context.py @@ -1,5 +1,8 @@ # %% [markdown] -# # Building LLM context from news +# # Build LLM context from news +# +# **Use this when** you retrieve news for your own LLM and want context it +# can reason over and cite. # # The most common use of `search_news` is retrieval for your own LLM. There # are two good ways to do it. diff --git a/cookbook/recipes/05_using_wikipedia.py b/cookbook/recipes/05_search_wikipedia.py similarity index 89% rename from cookbook/recipes/05_using_wikipedia.py rename to cookbook/recipes/05_search_wikipedia.py index 075ac01..fe9fe36 100644 --- a/cookbook/recipes/05_using_wikipedia.py +++ b/cookbook/recipes/05_search_wikipedia.py @@ -1,9 +1,12 @@ # %% [markdown] -# # Using Wikipedia +# # Search Wikipedia for background +# +# **Use this when** your model needs the background behind the news: who a +# person is, what a company or institution does, or the history behind an +# event. # # `ask.wiki.search_wiki()` searches a chunked Wikipedia index. Pair it with -# news: Wikipedia gives the stable background (who someone is, what a -# company does, the history of a conflict), news gives what changed. +# news search: Wikipedia gives the background, news gives what changed. # # Parameters that matter: # diff --git a/cookbook/recipes/06_searching_twitter.py b/cookbook/recipes/06_search_x_twitter.py similarity index 94% rename from cookbook/recipes/06_searching_twitter.py rename to cookbook/recipes/06_search_x_twitter.py index 993616c..0e4a71e 100644 --- a/cookbook/recipes/06_searching_twitter.py +++ b/cookbook/recipes/06_search_x_twitter.py @@ -1,5 +1,8 @@ # %% [markdown] -# # Searching X (Twitter) +# # Search X (Twitter) +# +# **Use this when** you need what was said on X: an account's own +# statements, or how people are reacting to an event. # # X search goes through `ask.chat.live_web_search()` with # `domains=["x.com"]`. Each entry in `queries` is an **X advanced search diff --git a/cookbook/recipes/07_searching_google.py b/cookbook/recipes/07_search_the_live_web.py similarity index 89% rename from cookbook/recipes/07_searching_google.py rename to cookbook/recipes/07_search_the_live_web.py index c8215b8..4c7d2d6 100644 --- a/cookbook/recipes/07_searching_google.py +++ b/cookbook/recipes/07_search_the_live_web.py @@ -1,14 +1,14 @@ # %% [markdown] -# # Searching Google (live web search) +# # Search the live web (Google) +# +# **Use this when** the answer lives on the wider web rather than in news +# coverage: company blogs, press releases, regulator and court sites, +# documentation, or pages published minutes ago. # # `ask.chat.live_web_search()` runs a live web search, fetches the pages, # and returns an LLM-distilled summary of each one (`key_points`), plus a # prompt-ready `as_string`. # -# Use it to fill gaps in the news index: company blogs, press release pages, -# regulator and court sites, niche trade publications, or anything published -# in the last few minutes. -# # Parameters that matter: # # - `queries`: a list of Google-style keyword queries. Short keyword strings diff --git a/cookbook/recipes/08_searching_podcasts.py b/cookbook/recipes/08_search_podcasts.py similarity index 89% rename from cookbook/recipes/08_searching_podcasts.py rename to cookbook/recipes/08_search_podcasts.py index f6a2941..908cb4e 100644 --- a/cookbook/recipes/08_searching_podcasts.py +++ b/cookbook/recipes/08_search_podcasts.py @@ -1,5 +1,8 @@ # %% [markdown] -# # Searching podcasts +# # Search podcasts +# +# **Use this when** you want what people said rather than what was reported: +# interviews, opinion, and long-form commentary from podcast episodes. # # Podcast episodes are indexed alongside news and are searchable with # `search_news`. The `podcasts` parameter controls them: @@ -12,8 +15,6 @@ # and time windows) apply to podcasts too. # # Podcasts are where opinions, interviews, and long-form commentary live. -# Reach for them when the question is "what are people saying about X" more -# than "what happened". # %% import os @@ -74,7 +75,7 @@ # ## Podcasts as a DeepNews source # # DeepNews can research podcasts as their own source. See -# [12 Deep research basics](12_deep_research_basics.md) for streaming +# [12 Run deep research (DeepNews)](12_run_deep_research.md) for streaming # details. # %% diff --git a/cookbook/recipes/09_tracking_a_company.py b/cookbook/recipes/09_monitor_a_company.py similarity index 95% rename from cookbook/recipes/09_tracking_a_company.py rename to cookbook/recipes/09_monitor_a_company.py index 1ef5646..ad087f6 100644 --- a/cookbook/recipes/09_tracking_a_company.py +++ b/cookbook/recipes/09_monitor_a_company.py @@ -1,5 +1,8 @@ # %% [markdown] -# # Tracking a company +# # Monitor a company +# +# **Use this when** you follow one organization's coverage over time: +# launches, deals, earnings, leadership changes, and legal issues. # # The reliable pattern is **entity guarantee + descriptive query**: # @@ -115,7 +118,7 @@ # ## Company news + the company's own posts # # News misses what a company announces on social media. Pair the search -# with an X search. See [06 Searching X](06_searching_twitter.md). +# with an X search. See [06 Search X (Twitter)](06_search_x_twitter.md). # %% posts = ask.chat.live_web_search( diff --git a/cookbook/recipes/10_tracking_a_person.py b/cookbook/recipes/10_monitor_a_person.py similarity index 93% rename from cookbook/recipes/10_tracking_a_person.py rename to cookbook/recipes/10_monitor_a_person.py index eb83269..3c320f1 100644 --- a/cookbook/recipes/10_tracking_a_person.py +++ b/cookbook/recipes/10_monitor_a_person.py @@ -1,5 +1,8 @@ # %% [markdown] -# # Tracking a person +# # Monitor a person +# +# **Use this when** you follow coverage of one person, such as an executive +# or a politician: what they said, and what was reported about them. # # Same pattern as companies: `entity_guarantee=["Person:"]` to # guarantee the person is in the article, and a `query` that describes @@ -110,4 +113,4 @@ # %% [markdown] # For a watchlist that should run every morning and land in an inbox, let # DeepNews do these searches inside an alert. See -# [15 Creating an alert](15_creating_an_alert.md). +# [15 Create an alert](15_create_an_alert.md). diff --git a/cookbook/recipes/11_tracking_a_product_brand_or_industry.py b/cookbook/recipes/11_monitor_a_product_brand_or_industry.py similarity index 96% rename from cookbook/recipes/11_tracking_a_product_brand_or_industry.py rename to cookbook/recipes/11_monitor_a_product_brand_or_industry.py index bde91e3..2614e11 100644 --- a/cookbook/recipes/11_tracking_a_product_brand_or_industry.py +++ b/cookbook/recipes/11_monitor_a_product_brand_or_industry.py @@ -1,5 +1,8 @@ # %% [markdown] -# # Tracking a product, brand, or industry +# # Monitor a product, brand, or industry +# +# **Use this when** what you follow is a product, a brand, or an industry or +# market rather than one company, so no single entity filter covers it. # # Products, brands, and industries rarely map to one clean entity, so you # combine filters. The building blocks: diff --git a/cookbook/recipes/12_deep_research_basics.py b/cookbook/recipes/12_run_deep_research.py similarity index 91% rename from cookbook/recipes/12_deep_research_basics.py rename to cookbook/recipes/12_run_deep_research.py index 83986dd..22be766 100644 --- a/cookbook/recipes/12_deep_research_basics.py +++ b/cookbook/recipes/12_run_deep_research.py @@ -1,11 +1,26 @@ # %% [markdown] -# # Deep research (DeepNews) basics +# # Run deep research (DeepNews) # -# `ask.chat.get_deep_news()` runs a research agent. It decides what to -# search, reads the results, follows leads, searches again, and writes a -# cited answer. Use it when you cannot write the right search parameters -# up front: unknown entities, multi-hop questions, reconciling conflicting -# sources, or reports that cover many things. +# **Use this when** you want a researched, cited answer rather than a list +# of articles: a question that takes more than one search, such as an +# investigation, a fact-check, a forecast, or a report across many +# companies. DeepNews plans the searches, follows what it finds across your +# chosen sources, and writes the answer. +# +# `ask.chat.get_deep_news()` calls DeepNews, the AskNews research agent. It +# searches the news knowledge graph and the other sources you allow, reflects +# on what came back, follows the leads that matter, and returns a synthesized +# answer with citations you can check. +# +# Because it moves from what it finds to what is connected to it, DeepNews +# also brings in context you did not know to ask for: the related events, +# the other people and organizations involved, and the earlier developments +# that explain the current ones. The answer covers the whole picture, not +# only the question as you phrased it. +# +# When you want the articles themselves, for your code or model to read, +# `search_news` is faster and cheaper. To run the same research on a +# schedule, see [15 Create an alert](15_create_an_alert.md). # # The pieces you control: # @@ -15,7 +30,7 @@ # | `sources` | Which tools the agent may use (see below). Default `["asknews"]`. | # | `model` | The LLM driving the agent. | # | `engine` | `"v2.0"` is the current engine; `"v1.5"` is the previous one (and the one alerts use). The SDK defaults to `"v1"`, so set it explicitly. | -# | `search_depth`, `max_depth` | How much research to do. See [13 Deep research depth](13_deep_research_depth.md). | +# | `search_depth`, `max_depth` | How much research to do. See [13 Set deep research depth](13_set_deep_research_depth.md). | # | `filter_params` | Defaults applied to the agent's AskNews searches (e.g. `hours_back`, `languages`). | # | `stream` | Stream the agent's thinking, tool calls, text, and sources as they happen. | # | `stream_sources_inline` | Engine `v2.0` streams only: also emit each tool call's sources as a batch right after the call, not just at the end. See below. | @@ -44,7 +59,7 @@ # - Stream while you develop. Watching the tool calls is the fastest way to # see whether the agent is searching the way you intended, and to learn # the tool names and parameters it uses (useful for prompting, see -# [14 Prompting deep research](14_prompting_deep_research.md)). +# [14 Prompt deep research](14_prompt_deep_research.md)). # - Start with small depth and raise it only when the answer is missing # things. diff --git a/cookbook/recipes/13_deep_research_depth.py b/cookbook/recipes/13_set_deep_research_depth.py similarity index 95% rename from cookbook/recipes/13_deep_research_depth.py rename to cookbook/recipes/13_set_deep_research_depth.py index 33f3edd..3dbef22 100644 --- a/cookbook/recipes/13_deep_research_depth.py +++ b/cookbook/recipes/13_set_deep_research_depth.py @@ -1,5 +1,9 @@ # %% [markdown] -# # Deep research depth: how and why +# # Set deep research depth +# +# **Use this when** a DeepNews answer or report misses things, or does more +# research than the question needs. Depth sets how much the agent searches +# before it answers. # # Depth is the most important DeepNews setting. It decides how much # research the agent does before writing, which decides coverage, cost, @@ -58,7 +62,7 @@ # budget. For list-shaped tasks, spell out the per-item procedure ("for # each company do Step 1 then Step 2, then move on") so the agent spends # its rounds evenly instead of going deep on the first few items. See -# [14 Prompting deep research](14_prompting_deep_research.md). +# [14 Prompt deep research](14_prompt_deep_research.md). # # ## Other knobs for deep runs # diff --git a/cookbook/recipes/14_prompting_deep_research.py b/cookbook/recipes/14_prompt_deep_research.py similarity index 92% rename from cookbook/recipes/14_prompting_deep_research.py rename to cookbook/recipes/14_prompt_deep_research.py index d78acbb..fa91a19 100644 --- a/cookbook/recipes/14_prompting_deep_research.py +++ b/cookbook/recipes/14_prompt_deep_research.py @@ -1,11 +1,15 @@ # %% [markdown] -# # Prompting deep research with surgical precision +# # Prompt deep research # -# DeepNews is an agent with tools. The single biggest quality lever is -# telling it **exactly how to use those tools**: which tool, in what order, -# with which parameters, and what to do when a search comes back empty. -# Leaving it to guess works for simple questions and fails for monitoring -# and reporting. +# **Use this when** you want to guide how DeepNews does its research: which +# tools it uses and how, what it focuses on, and how it formats the output. +# +# DeepNews is an agent with tools, and the prompt is where you direct it. +# The single biggest quality lever is telling it **exactly how to use those +# tools**: which tool, in what order, with which parameters, and what to do +# when a search comes back empty. Then tell it what matters, so it spends +# its searches there, and what the answer should look like. Leaving it to +# guess works for simple questions and fails for monitoring and reporting. # # The patterns below come from production daily monitoring reports. # @@ -20,7 +24,7 @@ # ``` # # Refer to tools by name, the same way every time. Stream a run once -# ([12 Deep research basics](12_deep_research_basics.md)) to see the exact +# ([12 Run deep research (DeepNews)](12_run_deep_research.md)) to see the exact # tool names and argument names the agent uses. # # ## 2. Put inputs in delimited, structured blocks @@ -49,7 +53,7 @@ # ``` # # Size `search_depth` to the loop: items x steps. See -# [13 Deep research depth](13_deep_research_depth.md). +# [13 Set deep research depth](13_set_deep_research_depth.md). # # ## 4. Show the exact tool parameters, with placeholders # @@ -65,8 +69,8 @@ # # ``` # -# Everything in [09 Tracking a company](09_tracking_a_company.md) and -# [11 Tracking a product, brand, or industry](11_tracking_a_product_brand_or_industry.md) +# Everything in [09 Monitor a company](09_monitor_a_company.md) and +# [11 Monitor a product, brand, or industry](11_monitor_a_product_brand_or_industry.md) # applies here: you are teaching the agent your best `search_news` # parameters. # diff --git a/cookbook/recipes/15_creating_an_alert.py b/cookbook/recipes/15_create_an_alert.py similarity index 96% rename from cookbook/recipes/15_creating_an_alert.py rename to cookbook/recipes/15_create_an_alert.py index 00f971a..88cc161 100644 --- a/cookbook/recipes/15_creating_an_alert.py +++ b/cookbook/recipes/15_create_an_alert.py @@ -1,5 +1,8 @@ # %% [markdown] -# # Creating an alert +# # Create an alert +# +# **Use this when** a question needs revisiting on a schedule: a recurring +# research report, or a notification when a described event happens. # # An alert runs on a cron schedule, gathers information, optionally checks # a condition, optionally writes a report, and fires triggers (email, @@ -33,9 +36,9 @@ # # - **Put all the research instructions in the report prompt.** For a # report, the prompt *is* the alert. Everything in -# [14 Prompting deep research](14_prompting_deep_research.md) applies: +# [14 Prompt deep research](14_prompt_deep_research.md) applies: # tool parameters, per-item procedures, strict date rules. -# - **Size depth to the prompt** ([13 Deep research depth](13_deep_research_depth.md)). +# - **Size depth to the prompt** ([13 Set deep research depth](13_set_deep_research_depth.md)). # A 50-entity monitor with `search_depth=2` will skip most entities. # - **Enforce recency in two places**: in the prompt ("last 24 hours only, # never expand hours_back") and in `filter_params` (`hours_back`, diff --git a/cookbook/recipes/16_using_the_mcp_server.py b/cookbook/recipes/16_connect_to_the_mcp_server.py similarity index 93% rename from cookbook/recipes/16_using_the_mcp_server.py rename to cookbook/recipes/16_connect_to_the_mcp_server.py index e123c8a..ee694c1 100644 --- a/cookbook/recipes/16_using_the_mcp_server.py +++ b/cookbook/recipes/16_connect_to_the_mcp_server.py @@ -1,5 +1,9 @@ # %% [markdown] -# # Using the AskNews MCP server +# # Connect to the AskNews MCP server +# +# **Use this when** an LLM should decide which AskNews searches to run: +# inside an assistant such as Claude, ChatGPT, or Cursor, or in an agent you +# build. # # AskNews runs a hosted [Model Context Protocol](https://modelcontextprotocol.io) # server at `https://mcp.asknews.app`. It exposes AskNews search as tools that @@ -16,9 +20,9 @@ # # AskNews's own DeepNews agent (`get_deep_news(engine="v2.0")`) is built on # this MCP server. Its tools are the same ones you get here. If you want a -# managed research agent, call DeepNews ([12 Deep research basics](12_deep_research_basics.md)). +# managed research agent, call DeepNews ([12 Run deep research (DeepNews)](12_run_deep_research.md)). # If you want your own model, loop, and prompt, build on the MCP tools -# ([17 Building agents on the MCP server](17_building_agents_on_mcp.md)). +# ([17 Build an agent on the MCP server](17_build_an_agent_on_mcp.md)). # # ## Connection facts # @@ -60,7 +64,7 @@ # | `time_filter` default | `"crawl_date"` | `"pub_date"` | # | `string_guarantee_op` default | `"OR"` | `"AND"` | # | Exact time window | `start_timestamp` / `end_timestamp` (unix seconds) | `start_datetime` / `end_datetime` (ISO 8601) | -# | Archive access | Chosen from the window: a start more than 48 hours ago, or an end with no start | Same | +# | Historical news | Chosen from the window: a start more than 48 hours ago, or an end with no start | Same | # | Longest window | 160 days per call | 160 days per call | # | `return_type` | `"string"`, `"dicts"`, `"both"` | `"string"`, `"dicts"` | # @@ -159,7 +163,7 @@ async def call_tools() -> None: print(news.content[0].text) # An exact window uses ISO 8601 datetimes, not unix timestamps. - archive = await client.call_tool( + historical = await client.call_tool( "search_news", { "query": "ECB interest rate decision", @@ -168,7 +172,7 @@ async def call_tools() -> None: "return_type": "dicts", }, ) - for article in archive.structured_content["as_dicts"]: + for article in historical.structured_content["as_dicts"]: print(article["pub_date"], article["title"]) posts = await client.call_tool( diff --git a/cookbook/recipes/17_building_agents_on_mcp.py b/cookbook/recipes/17_build_an_agent_on_mcp.py similarity index 98% rename from cookbook/recipes/17_building_agents_on_mcp.py rename to cookbook/recipes/17_build_an_agent_on_mcp.py index f8d55d6..4631695 100644 --- a/cookbook/recipes/17_building_agents_on_mcp.py +++ b/cookbook/recipes/17_build_an_agent_on_mcp.py @@ -1,5 +1,8 @@ # %% [markdown] -# # Building agents on the MCP server +# # Build an agent on the MCP server +# +# **Use this when** you want your own model, loop, and prompt to do the +# research on AskNews tools, instead of calling DeepNews. # # This recipe builds a research agent on the AskNews MCP tools with LangChain. # The practices come from AskNews's own DeepNews agent, which runs on these