github nicobailon/pi-web-access v0.45.0

6 hours ago

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_content can 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" to fetch.allowedModes, and it uses Cloudflare's Clairic model with the Cloudflare key you set up in Pi (CLOUDFLARE_API_KEY and CLOUDFLARE_ACCOUNT_ID); with a CLOUDFLARE_GATEWAY_ID in Pi, the requests go through that Cloudflare AI Gateway. Call it with mode: "extract" and fields such 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_content with mode: "extract" get each page's typed values as data, under extraction for 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" and ninerouterBaseUrl, 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" to searchRouting.fallbackOn and pick a classifier model in searchRouting.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" to searchRouting.fallbackOn. If every provider answers that way, you get the first answer. A routed search can also be given a total time limit with searchRouting.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.
  • queryRewriteModel chooses the model the curator uses to rewrite a search query: "current" for the model your Pi session is running, or a provider/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.
  • summaryModel accepts "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. Pi enabledModels still applies.
  • web_search takes an optional model to pick the search model for one call, for example provider: "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 as provider. 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 (or PI_WEB_ACCESS_ALLOW_HTTP_BASE_URLS=true) lets provider gateway base URLs such as braveBaseUrl use plain http:// 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 openaiResponsesUrl at your Azure resource's /openai/v1/responses endpoint and set openaiSearchModel to your deployment name; an Azure API key is sent in the api-key header and a Microsoft Entra token as Bearer auth. A Pi Azure provider can be reused with openaiUseProviderBaseUrl, and an active Pi model on an Azure endpoint works with searchRouting.useCurrentModel. Azure doesn't support openaiUseAlphaSearch, 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 publication category (its research paper index) also show the citation count and DOI. publication replaces research paper as the documented category; research paper still works. Thanks to @kestermcullough for PR #596.

Changed

  • source_check shows the passages it found under each source, up to 4,000 characters, so the agent can weigh the claim without a second get_search_content call. 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, and get_search_content shrank from about 11,000 to about 4,400 characters. Every parameter is still there; the longer explanations moved to the README (#595).
  • The provider argument of web_search and source_check is 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. The provider setting in web-search.json, including lists, works as before (#595).
  • When summaryModel is 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 invalid summaryModel, including an empty string, stops the summary with an error naming the config file instead of being ignored. If summaryModel is 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 queries list, 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 a quota error, 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_check passages from fetched pages keep the whole sentence when it contains a period inside a word, such as example.com. Before, the passage started after the last such period and lost its subject. Thanks to @appe233 for reporting #600.
  • source_check picks 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 as API, TLS and 429 now count as matching words.

Don't miss a new pi-web-access release

NewReleases is sending notifications on new releases.