Skip to content

web.research

web.research is web.search + web.fetch + a synthesis pass, composed into one skill so an agent gets a real, cited answer instead of needing to orchestrate three tool calls itself. The Studio planner’s mandatory research task (see Briefs) is built on this skill.

Schema

Input = {
question: string,
depth?: 1 | 2 | 3, // default 1 — "1 = quick, 3 = thorough"
recency?: 'day' | 'week' | 'month' | 'year',
}
Output = {
answer: string,
sources: Array<{ title: string, url: string }>,
notes: string,
queries: string[], // every search actually run, including follow-ups
costUsd: number,
}

Depth controls everything

DepthPages readFollow-up queriesChars/pageSearch results fetchedSynthesis tier
1 (quick)305,0006cheap
2626,0008cheap
3 (thorough)1037,00010standard

At depth 2 and 3, before reading anything, one cheap-tier call proposes up to followUps additional search queries based on the first page of results — filling gaps like specifics, opposing views, or primary sources — and those results are merged in (deduplicated by URL) before the top N pages are chosen and fetched in parallel.

Synthesis, and what happens when a page fails

Every chosen page is read via web.fetch; a page that fails to fetch still contributes its search snippet rather than being dropped silently, so it can still be cited. The corpus (title + URL + text per page) goes to one structured-free completion instructed to cite claims inline as [2]-style bracketed numbers, say plainly when sources disagree, and say what’s missing if the sources don’t answer the question — capped at roughly 350 words for depth 1, 700 for deeper research.

Without an OpenRouter key, or if synthesis fails, extractiveAnswer() returns a plain listing of the top 6 sources with their snippets instead of prose — the skill always resolves with something useful, never an error, as long as at least one page was found.

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.research","input":{"question":"What changed in Node.js 22 for TypeScript projects?","depth":1}}'
{
"ok": true,
"output": {
"answer": "Node.js 22 stabilises the built-in TypeScript stripping (`--experimental-strip-types`)... [1][2]",
"sources": [
{ "title": "Node.js 22 release notes", "url": "https://nodejs.org/en/blog/release/v22.0.0" },
{ "title": "TypeScript support in Node.js", "url": "https://nodejs.org/en/learn/typescript/run-natively" }
],
"notes": "search provider: duckduckgo",
"queries": ["What changed in Node.js 22 for TypeScript projects?"],
"costUsd": 0.0009
}
}