Skip to main content
A search-powered daily digest has a duplicate problem. The same story appears on dozens of sites under different headlines, related topic queries return overlapping results, and yesterday’s news resurfaces today under a fresh timestamp. If every copy lands in the digest, readers stop trusting it. The usual fix is embedding similarity over the article body, but similarity is the wrong test. Two articles can read alike and cover different events: “Microsoft beats expectations on Azure growth” looks the same for Q1 as for Q2, so quarterly earnings stories score as duplicates. Two articles can read differently and cover the same event: “Amazon to build $3 billion data center campus in Mississippi” and “Vicksburg lands the largest tech investment in state history” are one story told two ways. Whether two articles report the same underlying event is a reasoning question, not a distance metric. This cookbook builds the digest with one Agent API request. The model writes code in the sandbox that fetches the day’s news for each topic, groups the results into stories by judgment, and delivers the digest plus a story registry as downloadable files.

Prerequisites

Install one SDK:
  • Python: pip install perplexityai
  • TypeScript: npm install @perplexity-ai/perplexity_ai
If you do not have an API key yet:

Get your Perplexity API Key

Navigate to the API Keys tab in the API Portal and generate a new key.
Export your API key:

How the request divides the work

The request walks through three steps:
  1. Code fetches. The sandbox container ships with a preinstalled Perplexity SDK, so the model writes a script that runs exactly one web search per topic and saves every result to results.json. Search counts and result caps live in code, so coverage is the same on every run.
  2. The model groups. Deciding whether two articles report the same event is judgment, and the instructions say so explicitly: no string matching, no embeddings.
  3. Code assembles. A final script builds digest.md and an updated stories.json from the saved results, referring to results by number so every title and link is copied exactly.
The standing rules live in instructions, which the model re-reads on every step of the agent loop. The input carries only what changes each day: the topics and the stories the digest has already covered.

Run the digest

Sandbox runs belong in background mode: submit with background: true and poll until the status is terminal.

What the response contains

The completed response’s output walks through the run: a skill_loaded item for the sandbox reference skills, one sandbox_results item per execution with the exact code the model ran and its stdout, a share_file item per delivered file, and a closing message. The sandbox_results items are worth keeping in your logs; they show precisely what executed, so a bad digest is debuggable. The two downloaded files are the product. digest.md reads like this:
And stories.json is the registry that makes tomorrow’s run smarter:

Story memory across days

The registry is what separates deduplication from grouping. Each run receives the known stories in its input and labels every story it finds: new if the event has not been covered before, update if it matches a known story and adds material new information, and repeat if it matches a known story and adds nothing. Updates stay in the digest, marked as such; repeats are dropped from the digest but kept in the registry. Because the model reuses each story_id for matched events, the registry stays stable across days. Prune registry entries whose last_seen is older than your dedupe window (30 days is plenty) so the input stays small.

Run it every day

Schedule the script with whatever already runs your jobs. The only state between runs is stories.json, and the run itself keeps it current: today’s job downloads the updated copy and tomorrow’s job feeds it back in. Everything else is stateless.

Scaling up

A three-topic day costs about seven cents on claude-haiku-4-5: roughly two cents of tokens, three cents for the sandbox session, and half a cent per search. The run takes about a minute in background mode. To cover more ground, add topics to the list; the code makes exactly one search per topic, so cost and coverage scale predictably. To dedupe against a large existing archive, give the request a link the sandbox can download, such as a presigned S3 URL, and extend the instructions so the fetch step pulls the archive next to the day’s results; give bigger jobs a larger model and a higher max_steps. If your digest renderer wants data instead of markdown, have the final script write a digest.json with the same fields.

Next steps

Sandbox

How the container works, calling other tools from code, pricing, and limits.

Background Mode

Submit, poll, stream, and cancel long-running agent runs.

Working with Files

List and download files an Agent API response produced in the sandbox.