Skip to content

web.search

web.search is called out by name in PLAN.md §4 as the single most important skill in Novaterra: it is how a small, cheap model performs far above its weight. Every agent gets it by default (DEFAULT_AGENT_SKILLS), and Muse leans on it for anything current, factual, numeric, or niche.

Schema

Input = {
query: string, // min 1 char
maxResults?: number, // 1-20, default 8
recency?: 'day' | 'week' | 'month' | 'year',
}
Output = {
results: Array<{ title: string, url: string, snippet: string, publishedAt?: string }>,
provider: string, // 'tavily' | 'brave' | 'openrouter-online' | 'duckduckgo' | 'none'
query: string,
notes: string[], // backends tried and why they failed
}

The fallback chain

Backends are tried in this exact order, each one skipped if unavailable rather than erroring:

  1. Tavily — if TAVILY_API_KEY is set.
  2. Brave Search — if BRAVE_API_KEY is set.
  3. OpenRouter :online — if an OpenRouter key is configured; asks a cheap-tier model with online: true to search and return results, merging its own JSON array with the model’s URL citation annotations (annotations are authoritative for URLs; JSON items usually carry better snippets).
  4. DuckDuckGo HTML — no key required at all; scrapes html.duckduckgo.com, falling back to lite.duckduckgo.com if the HTML endpoint returns nothing (or a bot-challenge page).

A failing backend never throws out of the skill — its failure reason is appended to notes and the next backend is tried. provider: 'none' with populated notes only happens if every single backend failed. Results are deduplicated by normalised URL (query string and trailing slash stripped) before being capped at maxResults.

Example

Terminal window
curl -s -X POST http://localhost:4000/api/studio/skills/invoke \
-H 'content-type: application/json' -b cookies.txt \
-d '{"name":"web.search","input":{"query":"OpenRouter pricing gemini 2.5 flash","maxResults":3}}'
{
"ok": true,
"output": {
"query": "OpenRouter pricing gemini 2.5 flash",
"provider": "duckduckgo",
"notes": [],
"results": [
{ "title": "Gemini 2.5 Flash - OpenRouter", "url": "https://openrouter.ai/google/gemini-2.5-flash", "snippet": "Google's Gemini 2.5 Flash is a workhorse model..." }
]
},
"durationMs": 612
}

See Environment variables for the TAVILY_API_KEY / BRAVE_API_KEY settings, and web.fetch for reading a result page in full, or web.research for a synthesised, cited answer in one call.