This release adds three new ways to search the web, each used only when you pick it, and lets you ask questions about a video with any model that can see images, without a Gemini key. Fetched pages come back more complete when the first pass keeps only one section of a page, such as one part of a guide or a product page's cart drawer. Searches are also less fragile: DuckDuckGo no longer gets your IP address blocked after a handful of searches, and a provider that times out now hands off to your next provider instead of stopping the search.
Highlights
- Three new search options: SpecStream (which can also fetch pages), Autom, and cloro, which can return Google or Bing AI Mode answers with sources.
- Ask questions about a video with any model that can see images, without a Gemini key.
- Fetched pages come back more complete when the first pass keeps only one section of the page.
- DuckDuckGo search no longer gets your IP address blocked after a handful of searches.
- A search provider that times out now hands off to your next provider instead of stopping the search.
Changelog
Highlights
- Three new search options, each used only when you pick it: SpecStream (which can also fetch pages), Autom, and cloro, which can return Google or Bing AI Mode answers with sources.
- Ask questions about a video with any model that can see images, without a Gemini key.
- Fetched pages come back more complete when the first pass keeps only one section of the page.
- DuckDuckGo search no longer gets your IP address blocked after a handful of searches.
- A search provider that times out now hands off to your next provider instead of stopping the search.
Added
- Search the web and fetch pages through SpecStream with
provider: "specstream"forweb_searchand"specstream"infetchRouting.providersforfetch_content, configured withspecstreamApiKeyorSPECSTREAM_API_KEY(and an optionalspecstreamBaseUrlgateway). It is explicit-only: never chosen byautoorprovider: "all". Thanks to @Specstreamai for PR #669. fetch_contentanswer mode now sends video frames and fetched images to the answer model as images, so any Pi model that accepts image input (OpenRouter, OpenAI, a local gateway) can describe a video without a Gemini credential, and the agent gets back only the text answer. Before, answer mode rejected frames and images. Thanks to @MaksimZinovev for the request in #663.- Search Google through Autom with
provider: "autom", configured withautomApiKeyorAUTOM_API_KEY(and an optionalautomBaseUrlgateway). It is explicit-only: never chosen byautoorprovider: "all", but it can be the named provider or part ofsearchRouting. Domain filters becomesite:clauses and are reapplied locally, andrecencyFilteris sent as Google'stbs. Each search returns at most one Google results page. Thanks to @josselinlbe for PR #675. - Search Google through cloro with
provider: "cloro", configured withcloroApiKeyorCLORO_API_KEY(and an optionalcloroBaseUrlgateway). It is explicit-only: never chosen byautoorprovider: "all", but it can be the named provider or part ofsearchRouting. Domain filters becomesite:clauses and are reapplied locally; recency is not applied. Each search returns at most one Google results page. SetcloroMode: "aimode"orcloroMode: "bing_aimode"to get a Google AI Mode or Bing AI Mode answer and its sources instead. Thanks to @rbatista191 for PR #662 and PR #668.
Changed
- The search curator's code (its local server and page, about 150 KB of source) now loads the first time the curator opens instead of when Pi loads the extension, so sessions that never open it, such as print and json modes or a host with no browser, don't load it at all. Thanks to @lodgekeeper for issue #670.
Fixed
- With the default
toolActivation: "auto", switching models in a new session before sending the first message now picks eager or on-demand web tools for the model you switched to. Before, the choice stayed with the model the session started on, so a model that can't add tools mid-conversation could start with onlyweb_enableand lose its prompt cache when the tools loaded later. Sessions that have already sent a request keep their tools. Thanks to @IdrisGit for PR #674 and @XEric7 for issue #671. fetch_contentnow recovers more of a page when the main extractor keeps only one part of it, such as one section of a guide, a docs catalogue, or a product page's cart drawer. When the extracted text is under half of the page's visible text, the built-in Defuddle extractor gets a try and its result is used when it has at least 1.5 times the text. Before, Defuddle only ran when extraction returned under 500 characters. Thanks to @inaridiy for the measurements in #673.- A search provider whose request times out no longer stops
searchRoutingor theautochain as if you had cancelled the search. The timeout now counts as anetworkerror, so a route withfallbackOn: ["network"]moves on to the next provider. Cancelling a search still stops it at once (#676). - DuckDuckGo search no longer gets the IP address blocked after a few searches. Spacing searches 2 seconds apart was not enough: in testing, DuckDuckGo showed its bot check after 3 to 34 searches at that pace, and after 22 searches in 10 minutes even at 5 seconds apart. Searches in one Pi process now start at least 10 seconds apart, with at most 10 in any 10 minutes, and a search that would have to wait more than 20 seconds to start fails at once with a
quotaerror so routing moves on. After a bot check the provider pauses for 30 minutes, doubling up to 2 hours, since the block lasts 7 to 30 minutes and comes back after a few searches when it is retried too soon. Parallel subagents and other Pi processes now share that pause through aduckduckgo-cooldown.jsonfile next toweb-search.json, so one bot check stops them all instead of each retrying on its own timer. Thanks to @kestermcullough for PR #661. - AnySearch now applies
domainFilterlocally instead of returning off-domain results, and clampsmax_resultsto the API's maximum of 10. AnumResultsabove 10 used to come back with 10 results and no warning. Results removed by the local filter read as an empty response, sosearchRouting.fallbackOn: ["empty"]can move to the next provider, and an include domain that matches nothing also counts as["domain-miss"]. Thanks to @Arcobalneo for PR #665.