Repository navigation
feat: more dials for web search providers - #5
Merged
Merged
Conversation
Several dials offered a short or stale list. Each list now matches the vendor's current reference. - Firecrawl categories are developer, research, pdf and gov. github is gone from the docs (GitHub search moved into the developer index), so it leaves both Firecrawl tiers; a stored "github" is dropped by validate_dials and the request goes out with no category. - Past hour (qdr:h) for Firecrawl and Serper. Brave, Tavily and DuckDuckGo document nothing shorter than a day, so they keep their lists; Perplexity already had it. - Exa freshness gains Past hour too. startPublishedDate is now computed in hours rather than days, which is the same instant for the old values. - Exa mode lists all six types: auto, fast, instant, deep-lite, deep, deep-reasoning. Exa quotes deep-reasoning at 12-40 seconds, so the help text says it can outlast a host's request timeout. - Brave country offers ALL, Brave's documented "no country" value; left at its default Brave searches as US. - DuckDuckGo region lists all 68 regions on its URL-parameters page, in the page's order. us-en stays the default row. A service may now declare up to kMaxWebSearchDials (7) dials, the number Tavily will need; the catalogue test checks against the constant instead of the old three.
…plexity Each is a documented request field that changes which results come back, not what they cost or how much text they carry. Tavily, both tiers (the key-less mode documents "all parameters"): - Exact phrases: exact_match, so quoted phrases match as written. - Language match: filter_by_language drops other languages instead of ranking them lower. It needs a language or Tavily answers 400, so it is sent only when the host gave one. - Country: Tavily takes a lower-case English name, not an ISO code, so the shared country codes are mapped; it is sent only with the General topic, the one Tavily accepts it with. - Safe search: safe_search, which the fast and ultra-fast depths do not support, so it is left out with them. - tavily-free also gets Depth, which only tavily-api had. Brave API: Spell correction off sends spellcheck=false. With it on, Brave searches its corrected query, which rewrites identifiers and error strings. Firecrawl, both tiers: - Safe search: safe=true. - Sort: Newest first adds sbd:1 to tbs, joined to the freshness window as "sbd:1,qdr:w", the combined form the reference documents. Exa: Safe search (moderation) and Country (userLocation, the bare ISO alpha-2 string form). Perplexity: Mode, web or fast (search_type). people is left out: it searches for people, not pages.
Every dial was a fixed list of values, so a field whose value is a URL or a place name could not be offered. A dial can now be free text: WebSearchDial::text says which kind (Line or HttpsUrl), max_bytes bounds it, and values stays empty. A list dial is unchanged. web_search_dial_value_ok is the one rule for both kinds, and is public so a host can check what a user typed against the same rule the request uses. A text value must be valid UTF-8 within max_bytes with no control characters (no newline can start a second Goggles rule); an HttpsUrl must also start with https:// and carry no spaces. validate_dials now calls it, so a hand-edited value that fails is still dropped, never sent. Two text dials: - Brave API, Goggle: one hosted Goggle URL, sent as goggles=. Goggles re-rank Brave's results by the file's rules. Brave advises hosted files over inline rules, which are capped by URL length, so inline rules are not accepted. Limit 2048 bytes. - Firecrawl, both tiers, Location: free text such as "San Francisco,California,United States", sent as location=. Firecrawl advises setting Country with it. Limit 200 bytes.
From 2026-11-16 Firecrawl's research category searches its Research Index and answers in data.research with paper records (paperId, primaryId, ids, title, abstract, score) instead of web pages in data.web. The parser read data.web only and required it, so a research search would have been reported unreadable and the next slot tried. Both containers are read now, web results first, the count covering both. A reply with either is readable; one with neither still is not. Until the switch data.research is absent and nothing changes. A paper record has no url, and a hit without one is dropped, so one is made from primaryId. Firecrawl documents four forms, each mapped to the paper's own page: arxiv:<id> https://arxiv.org/abs/<id> pmid:<id> https://pubmed.ncbi.nlm.nih.gov/<id>/ pmcid:<id> https://pmc.ncbi.nlm.nih.gov/articles/PMC<n>/ doi:<doi> https://doi.org/<doi> Whether a pmcid keeps PMC's own "PMC" prefix is not documented, so both spellings give the same link. Any other form, or no primaryId, falls back to Firecrawl's paper endpoint by paperId, the canonical id every record has, so a namespace Firecrawl adds later still gets a link. Ids are percent-encoded, keeping the slash a DOI or an old arXiv id holds. The abstract is the snippet.
Perplexity was the one keyed service that still got excluded sites as -site: words in the query. The catalogue note said its domain filter had no documented way to exclude. It has: the Search API's domain-filter guide and the /search reference list a "-" in front of a host as the deny form of search_domain_filter, at most 20 entries, and a list that is all allow or all deny. Whether /search honours -site: in the query text is documented nowhere. Perplexity now has a native exclude, like Tavily, Firecrawl and Exa: the -site: tokens are lifted out of the query and sent as search_domain_filter ["-reddit.com", ...]. split_site_exclusions already lifts at most 20, so the list never exceeds Perplexity's limit; a 21st and later stay in the query as before. Only the deny form is ever sent, so allow and deny are never mixed. The catalogue note no longer says excluding is undocumented.
3 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
web_search: more ways to tune each service, typed settings, Firecrawl research papers, Perplexity exclusions
Follow-up to #4, which added the catalogue of search services. Branch
feat/search-dials, 5 commits onedc3186. agentty has a matching PR that moves its submodule to this branch, so this one needs to be merged first.Why
When the catalogue went in, each service got at most three settings, chosen because they change the quality of the results. Settings that mainly change cost or how much text comes back were left out on purpose. This PR goes back through every vendor's current documentation and adds the remaining settings that change which results come back, with the same rule: nothing whose main effect is cost, tokens or extra page text.
The same review turned up lists that had drifted from the docs, an API change Firecrawl has announced for 2026-11-16 that would break its Research category, and a way to exclude sites on Perplexity that was thought not to exist. All three are fixed here.
1. Lists that were missing values or out of date
2. New settings
A service can now have up to seven settings (
kMaxWebSearchDials). Tavily uses all seven.When one setting only works together with another, as with Tavily's Country, Safe search and Language match, the library applies the rule itself when it builds the request. A host can show every setting as a plain choice and never sends a combination the vendor would reject. Tavily also wants a country name ("new zealand") rather than a code ("NZ"), so the shared country codes are translated for it.
3. Typed settings
Until now every setting was a choice from a list. Two useful ones aren't lists, so a setting can now be free text:
https://raw.githubusercontent.com/brave/goggles-quickstart/main/goggles/tech_blogs.goggle. Brave also accepts rules typed straight into the request, but it recommends hosted files and limits typed rules by URL length, so only an address is accepted.San Francisco,California,United States. Firecrawl recommends setting Country as well.Accepted text is one line of valid UTF-8 with no control characters, within a size limit: 2048 bytes for a Goggle address, 200 for a Location. A Goggle address must also start with
https://and contain no spaces. The library runs this check before every request and drops a value that fails. The check is also public (web_search_dial_value_ok), so a host can refuse a bad value as soon as it is typed. Otherwise the host would store a value that every later search ignores.For host authors:
valuesis empty and the newtextfield says which kind it is. A host that draws every setting as a dropdown needs to handle this, or it will show an empty dropdown.WebSearchDialas{id, label, help, values}still compiles unchanged. The new fields come after those and have defaults.4. Firecrawl research papers
On 2026-11-16 Firecrawl changes what its Research category returns:
Until now the library only looked for web results and treated a reply without them as broken. From that date every Research search would have failed and fallen through to the next service.
Both parts of the reply are read now: web results first, then papers, together counting toward the number of results asked for. Until the date nothing changes, because the papers part is simply absent.
A paper record has no web address, and the library drops any result without one: the model needs it to cite the result and to open it. So an address is built from the paper's id. Firecrawl documents four kinds of id:
arxiv:2105.05233https://arxiv.org/abs/2105.05233pmid:31452104https://pubmed.ncbi.nlm.nih.gov/31452104/pmcid:PMC6824467https://pmc.ncbi.nlm.nih.gov/articles/PMC6824467/doi:10.1038/s41586-021-03819-2https://doi.org/10.1038/s41586-021-03819-2A paper with any other kind of id, or none, links to Firecrawl's own page for it. That page uses the Firecrawl id that every record carries. So if Firecrawl adds a new kind of id later, those papers still appear with a working link instead of disappearing. That link is Firecrawl's data page for the paper, not the publisher's. The paper's abstract is used as the result's text.
Firecrawl's docs don't say whether PubMed Central ids keep their usual
PMCprefix, so both spellings give the same link.5. Perplexity uses its own filter for excluded sites
A host can ask for sites to be left out of every search (agentty calls this Never return). For Tavily, Firecrawl and Exa the library sends them through each service's own exclusion filter. For Perplexity it couldn't: when the catalogue went in, we believed Perplexity's domain filter could only limit a search to certain sites, not exclude them. So excluded sites were written into the search text as
-site:reddit.com. Perplexity doesn't document that it understands this form at all.Its documentation does describe excluding: put a
-in front of a site in its domain filter. The filter takes at most 20 sites, and must either all include or all exclude. Perplexity now gets excluded sites the same way the other three services do, through that filter.The library already lifted at most 20 excluded sites out of the search text, so the filter never goes over Perplexity's limit. A 21st and later site stays in the search text as before. Only the exclude form is ever sent, so the two forms are never mixed.
Checked against
Every request field and value comes from the vendor's own documentation, read during this work:
Left out, and why
Testing
tests/web_search_services_test.cppcovers:the values each setting offers, and how many settings each service has;
each new setting reaching the request, and staying out of it when left at its default or when a rule says it can't be sent;
what typed settings accept and refuse;
links for each kind of paper id and the fallback, web results and papers in one reply, and which replies count as readable.
excluded sites reaching Perplexity's filter (and leaving the search text), the 20-site limit, and no filter being sent when nothing is excluded.
The changed files compile with g++ 16.2 (
-std=c++23 -Wall -Wextra) and give no warnings.Full build and
cteston Linux.Commits
2ec79dfweb_search: dials offer every value their vendor documents3e6d8e6web_search: more quality dials for Tavily, Brave, Firecrawl, Exa, Perplexityf0eba67web_search: free-text dials, for Brave Goggles and Firecrawl location1e69b25web_search: Firecrawl paper records, each with a link791957dweb_search: Perplexity takes excluded sites as its domain filter