This release lets the agent pull exact values off a web page instead of reading the whole thing. Ask for a price, a release date or a rate limit, and you get just that value back, typed, with the line it came from. When the value isn't on the page, it says so rather than making one up. Search is also more resilient: it can move on to the next provider when one comes back empty or off-topic, and DuckDuckGo no longer gets your IP blocked. The web tools now take about 60% fewer tokens on every request.
Highlights
- Exact values from a page. Ask for "price: number" and get 29 back with the line it came from, not 40KB of HTML. Codemode scripts get the values as typed data. Opt-in.
- Summaries on your own model. Summaries can run on the model your Pi session is using, so they stay on your local or self-hosted model.
- Smaller tool definitions. The web tools add about 1,100 tokens to each request instead of about 2,800.
- Steadier search. A search can fall through to the next provider when results are empty, miss your domains or are off-topic, you can put a time limit on the whole search, and DuckDuckGo no longer locks itself out.
- More ways to search. Search through Azure OpenAI with Bing or through a self-hosted 9router, or pick the search model for a single call.
Need to know
| If you… | What changed |
|---|---|
set summaryModel
| Summaries use only that model. If it's missing, signed out or fails, you get the plain summary from the search results with the reason, instead of a quiet switch to a built-in cloud model. |
pass several providers in one web_search or source_check call from Pi
| provider is a plain string now: use "brave,exa" instead of a list. The provider setting in web-search.json works as before.
|
Changelog
Highlights
- Pull exact facts off a page. Ask for "price: number" and get 29 back with the line it came from, not 40KB of HTML. It says when a value isn't there instead of guessing. Opt-in.
- Summaries can run on the model your Pi session is using, so they stay on your local or self-hosted model.
- The web tools take 60% less of every request to the model (2.8k → 1.1k tokens).
- Search moves to the next provider when one comes back empty, you can put a time limit on the whole search, and DuckDuckGo no longer gets your IP blocked.
- Search through Azure with Bing, or pick the model for a single search.
Added
fetch_contentcan read specific values off a page instead of returning all of it: a price, a release date, a rate limit, a list of supported platforms. It is off unless you add"extract"tofetch.allowedModes, and it uses Cloudflare's Clairic model with the Cloudflare key you set up in Pi (CLOUDFLARE_API_KEYandCLOUDFLARE_ACCOUNT_ID); with aCLOUDFLARE_GATEWAY_IDin Pi, the requests go through that Cloudflare AI Gateway. Call it withmode: "extract"andfieldssuch as{ "price": "number: Pro plan monthly price" }; each field comes back as a typed value, as an uncertain guess, or as not on the page, and a value is reported only when the model is confident and it has the right type. Once it is on, the agent's tool list tells it to use extract when it needs a specific value rather than the whole page. The page text is sent to Cloudflare. Pi only; docs/field-extract.md has the details and measurements.- Extract mode shows the page line each text or number value was found on, so you can check and cite it. Text the model is confident about but that isn't on the page comes back as uncertain, not extracted (#616).
- Codemode scripts that call
fetch_contentwithmode: "extract"get each page's typed values as data, underextractionfor each URL, so a script doesn't have to parse text (#618). - After an update, the first Pi session shows the highlights of the releases you skipped, once, with a link to the full changelog. A fresh install or a downgrade shows nothing.
- Search through a self-hosted 9router with
provider: "ninerouter"andninerouterBaseUrl, so every search backend set up in the router works from Pi. Thanks to @giovannirandykusuma for PR #612. - Search routing can skip a provider whose results have nothing to do with your query. Add
"off-topic"tosearchRouting.fallbackOnand pick a classifier model insearchRouting.offTopicModel; it then checks each routed answer and moves on when the results are off-topic (#619). - Search routing can move on to the next provider when one answers with no results, or with no results from the domains you asked for. Turn it on by adding
"empty"or"domain-miss"tosearchRouting.fallbackOn. If every provider answers that way, you get the first answer. A routed search can also be given a total time limit withsearchRouting.timeoutMs(1 to 600000 milliseconds), which includes the time spent checking whether each provider is set up and signed in; when it runs out, you get the first answer passed over, or an error that says the route ran out of time. Thanks to @isjiajia01 for PR #594. queryRewriteModelchooses the model the curator uses to rewrite a search query:"current"for the model your Pi session is running, or aprovider/model-id, each with an optional thinking level such as"current:low". When set, no other model is tried. Unset, the rewrite still uses its built-in list of cloud models.summaryModelaccepts"current"or"current:<level>"to write summaries with the model your Pi session is running, which keeps them on a local or self-hosted model. PienabledModelsstill applies.web_searchtakes an optionalmodelto pick the search model for one call, for exampleprovider: "openai", model: "gpt-6-luna", without changing your config. It works with the OpenAI, xAI, Mistral, and Gemini providers, and only when you name exactly one of them asprovider. If that model fails, you get the error; the search is not retried with a different model or provider. Thanks to @IdrisGit for PR #598."allowHttpBaseUrls": true(orPI_WEB_ACCESS_ALLOW_HTTP_BASE_URLS=true) lets provider gateway base URLs such asbraveBaseUrluse plainhttp://on any host, for example an internal Kubernetes Service. Without it, gateway URLs must still use HTTPS unless they point at your own machine. HTTP sends API keys unencrypted, so use it only on a trusted network. Thanks to @Coder-Sang for PR #592.- Web search through Azure OpenAI, which grounds answers with Bing. Point
openaiResponsesUrlat your Azure resource's/openai/v1/responsesendpoint and setopenaiSearchModelto your deployment name; an Azure API key is sent in theapi-keyheader and a Microsoft Entra token as Bearer auth. A Pi Azure provider can be reused withopenaiUseProviderBaseUrl, and an active Pi model on an Azure endpoint works withsearchRouting.useCurrentModel. Azure doesn't supportopenaiUseAlphaSearch, so that setting is rejected before any request. Bing grounding is billed separately by Microsoft; see the README for cost and privacy notes. Thanks to @abhishek944 for PR #599. - Exa search results show each source's published date and authors, and results from Exa's
publicationcategory (its research paper index) also show the citation count and DOI.publicationreplacesresearch paperas the documented category;research paperstill works. Thanks to @kestermcullough for PR #596.
Changed
source_checkshows the passages it found under each source, up to 4,000 characters, so the agent can weigh the claim without a secondget_search_contentcall. Before, the result listed only titles and links.- The web tools now add about 1,100 tokens to every request to the model instead of about 2,800: the definitions of
web_search,source_check,fetch_content, andget_search_contentshrank from about 11,000 to about 4,400 characters. Every parameter is still there; the longer explanations moved to the README (#595). - The
providerargument ofweb_searchandsource_checkis now a plain string. To search several providers at once, pass comma-separated names such as"brave,exa"instead of a list. An unknown name now returns an error that lists the valid names, instead of quietly using automatic selection. Theprovidersetting inweb-search.json, including lists, works as before (#595). - When
summaryModelis set, summaries use only that model. Before, if it was missing, signed out, or failed, the summary quietly switched to a built-in cloud model such as Claude Haiku, which could bill a provider you did not choose. Now you get the plain summary built from the search results, with the reason it failed, and the curator preselects your model even when it is unavailable. An invalidsummaryModel, including an empty string, stops the summary with an error naming the config file instead of being ignored. IfsummaryModelis not set, nothing changes. Thanks to @Meetsch for issue #597.
Fixed
- DuckDuckGo search no longer locks itself out. Several searches at once, such as a
querieslist, used to trigger DuckDuckGo's bot check for the whole IP address for 10 to 15 minutes, and every retry kept the block in place. DuckDuckGo searches now run one at a time, at least 2 seconds apart. After a bot check the provider stops sending requests for 5 minutes, doubling up to 1 hour, and fails at once with aquotaerror, so search routing can fall back right away. - A DuckDuckGo search that times out now fails as a network error instead of an abort, so search routing falls back to the next provider. Its 30-second limit also counts the time spent waiting behind other DuckDuckGo searches. Thanks to @kestermcullough for PR #593.
source_checkpassages from fetched pages keep the whole sentence when it contains a period inside a word, such asexample.com. Before, the passage started after the last such period and lost its subject. Thanks to @appe233 for reporting #600.source_checkpicks the sentences from fetched pages that match the claim. Before, when the search result had a snippet, it matched the snippet instead and the claim was ignored. Acronyms and numbers such asAPI,TLSand429now count as matching words.