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..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`, 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 |
-| 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_get_started.md b/cookbook/markdown/00_get_started.md
new file mode 100644
index 0000000..5558387
--- /dev/null
+++ b/cookbook/markdown/00_get_started.md
@@ -0,0 +1,158 @@
+# Get started: setup and core concepts
+
+**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
+
+```bash
+pip install asknews
+```
+
+Create an API key at https://my.asknews.app and export it:
+
+```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`).
+
+```python
+import os
+
+from asknews_sdk import AskNewsSDK
+
+
+ask = AskNewsSDK(
+ api_key=os.environ["ASKNEWS_API_KEY"],
+)
+```
+
+An async client with the same methods is available as `AsyncAskNewsSDK`.
+Every method below is awaitable on it:
+
+```python
+from asknews_sdk import AsyncAskNewsSDK
+
+async with AsyncAskNewsSDK(api_key=...) as ask:
+ response = await ask.news.search_news(query="...")
+```
+
+## Which endpoint do I want?
+
+| 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
+
+A `search_news` call is a **filter** followed by a **ranking**:
+
+1. **Hard filters** decide which articles are eligible. Time window,
+ `entity_guarantee`, `string_guarantee`, `domain_url`, `categories`,
+ `languages`, `countries`, `page_rank`, `sentiment`, and so on.
+2. **`query`** ranks the eligible articles by relevance. It does not
+ exclude anything by itself (beyond `similarity_score_threshold`).
+
+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`, timestamps, and `strategy`
+
+- `hours_back` (default `24`) is the simplest window, relative to now.
+- `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 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
+ `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
+ monitoring and reports. `crawl_date` is best for "anything new since I
+ last polled".
+
+## `method`: `kw` vs `nl`
+
+- `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. 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
+
+- `"string"` (default): `response.as_string`, a prompt-optimized block of
+ `...` entries you can paste straight into an LLM prompt.
+- `"dicts"`: `response.as_dicts`, a list of typed article objects
+ (`title`, `article_url`, `pub_date`, `summary`, `key_points`,
+ `entities`, `source_id`, `page_rank`, `sentiment`, ...).
+- `"both"`: both of the above.
+
+## Plan limits
+
+- `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
+
+`try_cache="1h" | "6h" | "12h" | "24h" | "3d" | "7d"` reuses a cached
+response for an identical query, which is much cheaper. Useful for
+backtests and parameter sweeps. `response.hit_cache` tells you whether it
+hit.
+
+```python
+response = ask.news.search_news(
+ query="NVIDIA earnings guidance data center revenue",
+ entity_guarantee=["Organization:NVIDIA"],
+ hours_back=24,
+ n_articles=5,
+ return_type="both",
+ try_cache="1h",
+)
+
+print(response.as_string)
+for article in response.as_dicts:
+ print(article.pub_date, article.source_id, article.title, article.article_url)
+print("cache hit:", response.hit_cache)
+```
diff --git a/cookbook/markdown/00_setup_and_core_concepts.md b/cookbook/markdown/00_setup_and_core_concepts.md
deleted file mode 100644
index d041eba..0000000
--- a/cookbook/markdown/00_setup_and_core_concepts.md
+++ /dev/null
@@ -1,127 +0,0 @@
-# Setup and core concepts
-
-Read this first. Every other recipe assumes the concepts here.
-
-## Install
-
-```bash
-pip install asknews
-```
-
-Create an API key at https://my.asknews.app and export it:
-
-```bash
-export ASKNEWS_API_KEY="..."
-```
-
-```python
-import os
-
-from asknews_sdk import AskNewsSDK
-
-
-ask = AskNewsSDK(
- api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news", "chat", "stories", "analytics"],
-)
-```
-
-An async client with the same methods is available as `AsyncAskNewsSDK`.
-Every method below is awaitable on it:
-
-```python
-from asknews_sdk import AsyncAskNewsSDK
-
-async with AsyncAskNewsSDK(api_key=..., scopes=[...]) as ask:
- response = await ask.news.search_news(query="...")
-```
-
-## 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.
-
-## The `search_news` mental model
-
-A `search_news` call is a **filter** followed by a **ranking**:
-
-1. **Hard filters** decide which articles are eligible. Time window,
- `entity_guarantee`, `string_guarantee`, `domain_url`, `categories`,
- `languages`, `countries`, `page_rank`, `sentiment`, and so on.
-2. **`query`** ranks the eligible articles by relevance. It does not
- exclude anything by itself (beyond `similarity_score_threshold`).
-
-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
-
-- `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
- [02 Searching archive news](02_searching_archive_news.md).
-- `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
- monitoring and reports. `crawl_date` is best for "anything new since I
- last polled".
-
-## `method`: `kw` vs `nl`
-
-- `method="kw"` (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.
-
-## `return_type`: feeding an LLM vs feeding code
-
-- `"string"` (default): `response.as_string`, a prompt-optimized block of
- `...` entries you can paste straight into an LLM prompt.
-- `"dicts"`: `response.as_dicts`, a list of typed article objects
- (`title`, `article_url`, `pub_date`, `summary`, `key_points`,
- `entities`, `source_id`, `page_rank`, `sentiment`, ...).
-- `"both"`: both of the above.
-
-## `premium=True`
-
-Includes premium publisher content in the results. The examples in this
-cookbook set it wherever source quality matters.
-
-## Caching repeated queries
-
-`try_cache="1h" | "6h" | "12h" | "24h" | "3d" | "7d"` reuses a cached
-response for an identical query, which is much cheaper. Useful for
-backtests and parameter sweeps. `response.hit_cache` tells you whether it
-hit.
-
-```python
-response = ask.news.search_news(
- query="NVIDIA earnings guidance data center revenue",
- entity_guarantee=["Organization:NVIDIA"],
- hours_back=24,
- n_articles=5,
- return_type="both",
- premium=True,
- try_cache="1h",
-)
-
-print(response.as_string)
-for article in response.as_dicts:
- print(article.pub_date, article.source_id, article.title, article.article_url)
-print("cache hit:", response.hit_cache)
-```
diff --git a/cookbook/markdown/01_getting_real_time_news.md b/cookbook/markdown/01_search_live_news.md
similarity index 59%
rename from cookbook/markdown/01_getting_real_time_news.md
rename to cookbook/markdown/01_search_live_news.md
index aea10b7..884ba6f 100644
--- a/cookbook/markdown/01_getting_real_time_news.md
+++ b/cookbook/markdown/01_search_live_news.md
@@ -1,18 +1,23 @@
-# Getting real-time news
+# Search live 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".
+**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".
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 +28,6 @@ from asknews_sdk import AskNewsSDK
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news"],
)
```
@@ -36,16 +40,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 +61,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 +88,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 Paginate news search results](03_paginate_news_search.md)).
```python
seen: set = set()
@@ -100,9 +103,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:
@@ -113,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 66%
rename from cookbook/markdown/02_searching_archive_news.md
rename to cookbook/markdown/02_search_historical_news.md
index 8dc1d62..0da70c3 100644
--- a/cookbook/markdown/02_searching_archive_news.md
+++ b/cookbook/markdown/02_search_historical_news.md
@@ -1,13 +1,23 @@
-# Searching archive news
+# Search historical news
-The live index holds the last ~48 hours. To search further back, set
-`historical=True` and give an explicit window.
+**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:
-- **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 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
anything you want to reproduce later.
- Use `time_filter="pub_date"` for historical research: you almost always
@@ -24,7 +34,6 @@ from asknews_sdk import AskNewsSDK
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news"],
)
```
@@ -36,14 +45,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,35 +68,31 @@ 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)
```
-## Archive + entity guarantee
+## Historical news + entity guarantee
-Hard filters work the same way on the archive. This pulls every article
+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 Paginating](03_paginating.md).
+results, see [03 Paginate news search results](03_paginate_news_search.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_paginate_news_search.md
similarity index 76%
rename from cookbook/markdown/03_paginating.md
rename to cookbook/markdown/03_paginate_news_search.md
index 5173de8..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`
@@ -7,12 +10,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 +32,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 +81,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_build_llm_context.md
similarity index 92%
rename from cookbook/markdown/04_building_llm_context.md
rename to cookbook/markdown/04_build_llm_context.md
index 061af6b..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.
@@ -23,7 +26,6 @@ from asknews_sdk import AskNewsSDK
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news"],
)
```
@@ -40,7 +42,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 +54,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 +66,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_search_wikipedia.md
similarity index 90%
rename from cookbook/markdown/05_using_wikipedia.md
rename to cookbook/markdown/05_search_wikipedia.md
index 2bf2c93..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:
@@ -27,7 +30,6 @@ from asknews_sdk import AskNewsSDK
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news"],
)
```
@@ -76,10 +78,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_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 8c2047f..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
@@ -37,7 +40,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_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 ee52e5f..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
@@ -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_search_podcasts.md
similarity index 85%
rename from cookbook/markdown/08_searching_podcasts.md
rename to cookbook/markdown/08_search_podcasts.md
index cff40d1..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:
@@ -8,11 +11,9 @@ 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
-than "what happened".
```python
import os
@@ -22,7 +23,6 @@ from asknews_sdk import AskNewsSDK
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news", "chat"],
)
```
@@ -33,7 +33,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 +51,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,14 +68,13 @@ response = ask.news.search_news(
podcasts="none",
hours_back=24,
n_articles=10,
- premium=True,
)
```
## 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 94%
rename from cookbook/markdown/09_tracking_a_company.md
rename to cookbook/markdown/09_monitor_a_company.md
index 802e664..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**:
@@ -35,7 +38,6 @@ from asknews_sdk import AskNewsSDK
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news", "chat"],
)
```
@@ -59,7 +61,6 @@ response = ask.news.search_news(
page_rank=100000,
languages=["en"],
return_type="both",
- premium=True,
)
print(response.as_string)
```
@@ -76,7 +77,6 @@ response = ask.news.search_news(
time_filter="pub_date",
n_articles=10,
return_type="dicts",
- premium=True,
)
```
@@ -92,11 +92,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,14 +111,13 @@ response = ask.news.search_news(
query="Apple Inc. iPhone, App Store, antitrust, Tim Cook, earnings",
hours_back=24,
n_articles=10,
- premium=True,
)
```
## 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 6a00752..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
@@ -25,7 +28,6 @@ from asknews_sdk import AskNewsSDK
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news", "chat"],
)
```
@@ -46,7 +48,6 @@ response = ask.news.search_news(
time_filter="pub_date",
n_articles=10,
return_type="both",
- premium=True,
)
print(response.as_string)
```
@@ -62,10 +63,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 +74,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 +101,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"],
@@ -115,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 93%
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 69fc026..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:
@@ -9,7 +12,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 +36,6 @@ from asknews_sdk import AskNewsSDK
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news"],
)
```
@@ -46,10 +48,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 +65,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 +90,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 +114,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 +126,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 +146,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_run_deep_research.md
similarity index 89%
rename from cookbook/markdown/12_deep_research_basics.md
rename to cookbook/markdown/12_run_deep_research.md
index da7440f..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:
@@ -13,8 +28,8 @@ 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). |
-| `search_depth`, `max_depth` | How much research to do. See [13 Deep research depth](13_deep_research_depth.md). |
+| `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 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. |
@@ -28,10 +43,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 |
@@ -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.
@@ -55,7 +70,6 @@ from asknews_sdk import AskNewsSDK
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["chat", "news"],
)
```
@@ -300,7 +314,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 +369,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_set_deep_research_depth.md
similarity index 91%
rename from cookbook/markdown/13_deep_research_depth.md
rename to cookbook/markdown/13_set_deep_research_depth.md
index de75481..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
@@ -80,7 +84,6 @@ from asknews_sdk import AskNewsSDK
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["chat", "news"],
)
```
@@ -148,10 +151,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 +167,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_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 b877503..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.
@@ -142,7 +146,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_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 0f83e64..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`,
@@ -60,7 +63,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_connect_to_the_mcp_server.md
similarity index 92%
rename from cookbook/markdown/16_using_the_mcp_server.md
rename to cookbook/markdown/16_connect_to_the_mcp_server.md
index 0442768..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,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. |
+| 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"` |
| SDK method | MCP tool | Argument difference |
@@ -155,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",
@@ -164,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_get_started.py b/cookbook/recipes/00_get_started.py
new file mode 100644
index 0000000..228901e
--- /dev/null
+++ b/cookbook/recipes/00_get_started.py
@@ -0,0 +1,158 @@
+# %% [markdown]
+# # Get started: setup and core concepts
+#
+# **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
+#
+# ```bash
+# pip install asknews
+# ```
+#
+# Create an API key at https://my.asknews.app and export it:
+#
+# ```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
+
+from asknews_sdk import AskNewsSDK
+
+
+ask = AskNewsSDK(
+ api_key=os.environ["ASKNEWS_API_KEY"],
+)
+
+# %% [markdown]
+# An async client with the same methods is available as `AsyncAskNewsSDK`.
+# Every method below is awaitable on it:
+#
+# ```python
+# from asknews_sdk import AsyncAskNewsSDK
+#
+# async with AsyncAskNewsSDK(api_key=...) as ask:
+# response = await ask.news.search_news(query="...")
+# ```
+#
+# ## Which endpoint do I want?
+#
+# | 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
+#
+# A `search_news` call is a **filter** followed by a **ranking**:
+#
+# 1. **Hard filters** decide which articles are eligible. Time window,
+# `entity_guarantee`, `string_guarantee`, `domain_url`, `categories`,
+# `languages`, `countries`, `page_rank`, `sentiment`, and so on.
+# 2. **`query`** ranks the eligible articles by relevance. It does not
+# exclude anything by itself (beyond `similarity_score_threshold`).
+#
+# 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`, timestamps, and `strategy`
+#
+# - `hours_back` (default `24`) is the simplest window, relative to now.
+# - `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 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
+# `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
+# monitoring and reports. `crawl_date` is best for "anything new since I
+# last polled".
+#
+# ## `method`: `kw` vs `nl`
+#
+# - `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. 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
+#
+# - `"string"` (default): `response.as_string`, a prompt-optimized block of
+# `...` entries you can paste straight into an LLM prompt.
+# - `"dicts"`: `response.as_dicts`, a list of typed article objects
+# (`title`, `article_url`, `pub_date`, `summary`, `key_points`,
+# `entities`, `source_id`, `page_rank`, `sentiment`, ...).
+# - `"both"`: both of the above.
+#
+# ## Plan limits
+#
+# - `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
+#
+# `try_cache="1h" | "6h" | "12h" | "24h" | "3d" | "7d"` reuses a cached
+# response for an identical query, which is much cheaper. Useful for
+# backtests and parameter sweeps. `response.hit_cache` tells you whether it
+# hit.
+
+# %%
+response = ask.news.search_news(
+ query="NVIDIA earnings guidance data center revenue",
+ entity_guarantee=["Organization:NVIDIA"],
+ hours_back=24,
+ n_articles=5,
+ return_type="both",
+ try_cache="1h",
+)
+
+print(response.as_string)
+for article in response.as_dicts:
+ print(article.pub_date, article.source_id, article.title, article.article_url)
+print("cache hit:", response.hit_cache)
diff --git a/cookbook/recipes/00_setup_and_core_concepts.py b/cookbook/recipes/00_setup_and_core_concepts.py
deleted file mode 100644
index d6b310a..0000000
--- a/cookbook/recipes/00_setup_and_core_concepts.py
+++ /dev/null
@@ -1,127 +0,0 @@
-# %% [markdown]
-# # Setup and core concepts
-#
-# Read this first. Every other recipe assumes the concepts here.
-#
-# ## Install
-#
-# ```bash
-# pip install asknews
-# ```
-#
-# Create an API key at https://my.asknews.app and export it:
-#
-# ```bash
-# export ASKNEWS_API_KEY="..."
-# ```
-
-# %%
-import os
-
-from asknews_sdk import AskNewsSDK
-
-
-ask = AskNewsSDK(
- api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news", "chat", "stories", "analytics"],
-)
-
-# %% [markdown]
-# An async client with the same methods is available as `AsyncAskNewsSDK`.
-# Every method below is awaitable on it:
-#
-# ```python
-# from asknews_sdk import AsyncAskNewsSDK
-#
-# async with AsyncAskNewsSDK(api_key=..., scopes=[...]) as ask:
-# response = await ask.news.search_news(query="...")
-# ```
-#
-# ## 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.
-#
-# ## The `search_news` mental model
-#
-# A `search_news` call is a **filter** followed by a **ranking**:
-#
-# 1. **Hard filters** decide which articles are eligible. Time window,
-# `entity_guarantee`, `string_guarantee`, `domain_url`, `categories`,
-# `languages`, `countries`, `page_rank`, `sentiment`, and so on.
-# 2. **`query`** ranks the eligible articles by relevance. It does not
-# exclude anything by itself (beyond `similarity_score_threshold`).
-#
-# 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
-#
-# - `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
-# [02 Searching archive news](02_searching_archive_news.md).
-# - `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
-# monitoring and reports. `crawl_date` is best for "anything new since I
-# last polled".
-#
-# ## `method`: `kw` vs `nl`
-#
-# - `method="kw"` (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.
-#
-# ## `return_type`: feeding an LLM vs feeding code
-#
-# - `"string"` (default): `response.as_string`, a prompt-optimized block of
-# `...` entries you can paste straight into an LLM prompt.
-# - `"dicts"`: `response.as_dicts`, a list of typed article objects
-# (`title`, `article_url`, `pub_date`, `summary`, `key_points`,
-# `entities`, `source_id`, `page_rank`, `sentiment`, ...).
-# - `"both"`: both of the above.
-#
-# ## `premium=True`
-#
-# Includes premium publisher content in the results. The examples in this
-# cookbook set it wherever source quality matters.
-#
-# ## Caching repeated queries
-#
-# `try_cache="1h" | "6h" | "12h" | "24h" | "3d" | "7d"` reuses a cached
-# response for an identical query, which is much cheaper. Useful for
-# backtests and parameter sweeps. `response.hit_cache` tells you whether it
-# hit.
-
-# %%
-response = ask.news.search_news(
- query="NVIDIA earnings guidance data center revenue",
- entity_guarantee=["Organization:NVIDIA"],
- hours_back=24,
- n_articles=5,
- return_type="both",
- premium=True,
- try_cache="1h",
-)
-
-print(response.as_string)
-for article in response.as_dicts:
- print(article.pub_date, article.source_id, article.title, article.article_url)
-print("cache hit:", response.hit_cache)
diff --git a/cookbook/recipes/01_getting_real_time_news.py b/cookbook/recipes/01_search_live_news.py
similarity index 59%
rename from cookbook/recipes/01_getting_real_time_news.py
rename to cookbook/recipes/01_search_live_news.py
index 25a8f72..25b890f 100644
--- a/cookbook/recipes/01_getting_real_time_news.py
+++ b/cookbook/recipes/01_search_live_news.py
@@ -1,19 +1,24 @@
# %% [markdown]
-# # Getting real-time news
+# # Search live 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".
+# **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".
#
# 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 +29,6 @@
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news"],
)
# %% [markdown]
@@ -37,16 +41,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 +62,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 +89,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 Paginate news search results](03_paginate_news_search.md)).
# %%
seen: set = set()
@@ -101,9 +104,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:
@@ -114,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 66%
rename from cookbook/recipes/02_searching_archive_news.py
rename to cookbook/recipes/02_search_historical_news.py
index ffd2577..70dd99a 100644
--- a/cookbook/recipes/02_searching_archive_news.py
+++ b/cookbook/recipes/02_search_historical_news.py
@@ -1,14 +1,24 @@
# %% [markdown]
-# # Searching archive news
+# # Search historical news
#
-# The live index holds the last ~48 hours. To search further back, set
-# `historical=True` and give an explicit window.
+# **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:
#
-# - **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 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
# anything you want to reproduce later.
# - Use `time_filter="pub_date"` for historical research: you almost always
@@ -25,7 +35,6 @@
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news"],
)
# %% [markdown]
@@ -37,14 +46,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,34 +69,30 @@
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)
# %% [markdown]
-# ## Archive + entity guarantee
+# ## Historical news + entity guarantee
#
-# Hard filters work the same way on the archive. This pulls every article
+# 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 Paginating](03_paginating.md).
+# results, see [03 Paginate news search results](03_paginate_news_search.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_paginate_news_search.py
similarity index 76%
rename from cookbook/recipes/03_paginating.py
rename to cookbook/recipes/03_paginate_news_search.py
index 072d427..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`
@@ -8,12 +11,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 +33,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 +82,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_build_llm_context.py
similarity index 92%
rename from cookbook/recipes/04_building_llm_context.py
rename to cookbook/recipes/04_build_llm_context.py
index a47ab2a..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.
@@ -24,7 +27,6 @@
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news"],
)
# %% [markdown]
@@ -41,7 +43,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 +55,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 +67,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_search_wikipedia.py
similarity index 89%
rename from cookbook/recipes/05_using_wikipedia.py
rename to cookbook/recipes/05_search_wikipedia.py
index 36c07c9..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:
#
@@ -28,7 +31,6 @@
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news"],
)
# %% [markdown]
@@ -77,10 +79,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_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 cccb68e..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
@@ -38,7 +41,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_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 a8ffe1a..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
@@ -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_search_podcasts.py
similarity index 85%
rename from cookbook/recipes/08_searching_podcasts.py
rename to cookbook/recipes/08_search_podcasts.py
index 1d4ebe7..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:
@@ -9,11 +12,9 @@
# - `"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
-# than "what happened".
# %%
import os
@@ -23,7 +24,6 @@
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news", "chat"],
)
# %% [markdown]
@@ -34,7 +34,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 +52,6 @@
entity_guarantee=["Person:Dario Amodei"],
podcasts="only",
hours_back=720,
- historical=True,
n_articles=10,
return_type="string",
)
@@ -71,14 +69,13 @@
podcasts="none",
hours_back=24,
n_articles=10,
- premium=True,
)
# %% [markdown]
# ## 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 94%
rename from cookbook/recipes/09_tracking_a_company.py
rename to cookbook/recipes/09_monitor_a_company.py
index 9ea69e0..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**:
#
@@ -36,7 +39,6 @@
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news", "chat"],
)
# %% [markdown]
@@ -60,7 +62,6 @@
page_rank=100000,
languages=["en"],
return_type="both",
- premium=True,
)
print(response.as_string)
@@ -77,7 +78,6 @@
time_filter="pub_date",
n_articles=10,
return_type="dicts",
- premium=True,
)
# %% [markdown]
@@ -93,11 +93,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,14 +112,13 @@
query="Apple Inc. iPhone, App Store, antitrust, Tim Cook, earnings",
hours_back=24,
n_articles=10,
- premium=True,
)
# %% [markdown]
# ## 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 de13e42..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
@@ -26,7 +29,6 @@
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news", "chat"],
)
# %% [markdown]
@@ -47,7 +49,6 @@
time_filter="pub_date",
n_articles=10,
return_type="both",
- premium=True,
)
print(response.as_string)
@@ -63,10 +64,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 +75,6 @@
response = ask.news.search_news(
authors=["Kaitlan Collins"],
hours_back=168,
- historical=True,
n_articles=10,
return_type="dicts",
)
@@ -104,7 +102,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"],
@@ -116,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 93%
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 1861487..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:
@@ -10,7 +13,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 +37,6 @@
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["news"],
)
# %% [markdown]
@@ -47,10 +49,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 +66,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 +91,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 +115,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 +127,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 +147,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_run_deep_research.py
similarity index 89%
rename from cookbook/recipes/12_deep_research_basics.py
rename to cookbook/recipes/12_run_deep_research.py
index a1f02b4..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:
#
@@ -14,8 +29,8 @@
# | `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). |
-# | `search_depth`, `max_depth` | How much research to do. See [13 Deep research depth](13_deep_research_depth.md). |
+# | `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 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. |
@@ -29,10 +44,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 |
@@ -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.
@@ -56,7 +71,6 @@
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["chat", "news"],
)
# %% [markdown]
@@ -301,7 +315,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 +371,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_set_deep_research_depth.py
similarity index 91%
rename from cookbook/recipes/13_deep_research_depth.py
rename to cookbook/recipes/13_set_deep_research_depth.py
index f26af26..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
#
@@ -81,7 +85,6 @@
ask = AskNewsSDK(
api_key=os.environ["ASKNEWS_API_KEY"],
- scopes=["chat", "news"],
)
# %% [markdown]
@@ -149,10 +152,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 +168,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_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 9e13ef8..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.
#
@@ -143,7 +147,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_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 9e9cdb1..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`,
@@ -61,7 +64,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_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 8c0e596..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,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. |
+# | 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"` |
#
# | SDK method | MCP tool | Argument difference |
@@ -158,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",
@@ -167,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