ID@agntn/webv0.9.0

One query. Every engine.

One TypeScript interface over Brave, Exa, Tavily, Firecrawl, Jina, SearXNG and the rest of the catalog. Search, reverse image search and page reading come back in the same shape, from a library, a CLI, an AI SDK tool or an MCP server, your pick.

Providers
13
one class shape
Capabilities
3
13 search · 1 image
Read
6 readers
fallback from Jina
Install$ pnpm add @agntn/web

Query in, results out

create("brave") reads the key from env and gives you a provider with one search(). Change the string, the rest of your code stays. This panel walks through 4 queries and replaces each recorded sample with the live answer from the docs worker.

  • Every provider answers { url, title, snippet }. Score, dates, highlights and full text come along when the engine has them
  • A filter the provider cannot do lands in ignoredFilters. Nothing gets dropped quietly
  • Brave, Marginalia, Mojeek, SearXNG, SerpAPI, SerpBase and TinyFish page through an opaque continuation token
Read Searching
Callsearch("TypeScript 7 native compiler")recorded
Provider / create("brave")

Brave

5 results, next page through a continuation token.

  1. 01Microsoft Releases TypeScript 7.0 with a Native Go Compiler, Delivering 10x Faster Builds - InfoQinfoq.com
  2. 02TypeScript 7.0 Native Compiler: What Breaks, What Gets 10x Faster, and How to Migrate - Developers Digestdevelopersdigest.tech
  3. 03TypeScript 7 Native Compiler: 3x Faster Type Checks in a Real Monorepoprisma.io
  4. 04TypeScript 7: The Native Compiler 10x Fasterbelievemy.com
{ url, title, snippet } from api.search.brave.com
Query

Ask them all, keep the evidence

One query, every key you have. UTM junk is stripped before URLs are compared, the first provider in order gives the representative record, and one engine hitting a paywall, a rate limit or a timeout does not empty the list. That was the whole point.

  • searchAll asks every configured provider at once and deduplicates by normalized URL
  • Each result remembers which providers returned it and keeps every record as evidence
  • A provider that fails goes to errors. The rest still answer
Read Fan-out, fallback and pagination

URL in, page out

You have a URL, you want the page. readUrl gives it back as Markdown, text or HTML. The bound is measured after the provider answers, so a page is never bigger than the agent asked for. A truncated page carries a token for the next slice.

  • readUrl starts with Jina Reader and moves to Context.dev, Firecrawl, TinyFish, Tavily or Exa when Jina fails in a way that makes sense to retry
  • maxChars is an exact bound in code points, same on every reader, with a continuation for the rest
  • readUrlDetailed tells you which reader answered and which ones it tried first
Read Reading pages
CallreadUrl("infoq.com…")recorded
Page / Jina

Microsoft Releases TypeScript 7.0 with a Native Go Compiler, Delivering 10x Faster Builds

infoq.com/news/2026/08/typescript-7-released

[BT](https://www.infoq.com/int/bt/ "bt")## InfoQ Software Architects' NewsletterA monthly overview of things you need to know as an architect or aspiring architect.[View an example](https://www.infoq.com/software-architects-newsletter#placeholderPastIssues)Enter your e-mail address
900 of 900 code points, continuation issuedjina

Thirteen adapters, one shape

Exa wants a POST with x-api-key, Brave a GET with X-Subscription-Token, Tavily puts the key in the body. Different APIs, different ideas about a request. Each adapter maps one of them onto the shared types and says what it can do, and the rest of the library just reads that. A custom provider is one class and one register() call.

Import@agntn/web/providers/<name>

listProviders()13 providers · catalog order
KeyWhat it talks to
BraveBRAVE_API_KEYThe Brave Search API, one GET per page, with extra snippets joined into text and a continuation that carries the offset.search
Context.devCONTEXT_DEV_API_KEYThe Context.dev API for search with Markdown ranked by relevance and for scraping pages into Markdown or HTML.search · read
ExaEXA_API_KEYThe Exa neural search API, the richest result shape of the built-ins, with highlights by default and summaries and full text on request, and Exa Contents for reading pages.search · read
FirecrawlFIRECRAWL_API_KEYThe Firecrawl v2 API for search with scraped passages and for scraping a page into Markdown or HTML.search · read
JinaJINA_API_KEYJina's s.jina.ai for search and r.jina.ai for reading, the default reader, with an optional key.search · read
MarginaliaMARGINALIA_API_KEYMarginalia Search, an independent index of small personal sites and plain text pages, usable without a key when you name it.search
MojeekMOJEEK_API_KEYThe Mojeek Search API, an independent index with classic SERP metadata, domain and date filters and paging.search
OpenAI CodexOPENAI_CODEX_ACCESS_TOKENHosted web search through the ChatGPT Codex backend using an existing Pi, OMP, Codex or OpenCode login. Native sources, not snippets invented by the model.search
SearXNGnone, self-hostedA self-hosted SearXNG metasearch instance, no key, with a reachability probe and the engines behind each result in metadata.search
SerpAPISERPAPI_API_KEYSerpAPI's Google endpoints for classic SERP results and Google Lens for reverse image search.search · image
SerpBaseSERPBASE_API_KEYSerpBase's Google SERP endpoints, with a category that picks the web, images, news or videos endpoint.search
TavilyTAVILY_API_KEYThe Tavily search API, with an optional generated answer in response metadata, and Tavily Extract for reading pages.search · read
TinyFishTINYFISH_API_KEYTinyFish Search for news and research results with publisher metadata, and TinyFish Fetch for reading pages.search · read
read from the catalog / no networkcreate("<key>") loads one

Every tool, every host

searchTool from the /ai subpath is a Vercel AI SDK tool, web mcp serves the same set over stdio. The model reads a short header and numbered results, your code gets the data underneath.

  • web_search, web_image_search, web_read, web_reveal and web_providers, same schema on every surface
  • Provider names are checked against the live registry, so a custom provider works in a tool call too
  • The host abort signal cancels the provider request. Reads default to 20 000 characters
Read AI SDK, MCP, Pi and OMP
Callweb_search("TypeScript 7 native compiler")
Tool / read-only

Brave

The model reads a header and numbered results. Your code gets the same answer as data, diagnostics and all.

provider
"brave"
results.length
5
pagination
{ status: "next" }
AI SDK · MCP · Pi · OMPweb mcp · stdio

Same calls, every adapter

Type guards like isReadProvider tell you what a provider can do, the registry tells you which ones exist. Upstream quirks, Brave's extra snippets, Exa's highlights, all of that stays inside the adapter. The public types never see it.

  • search(), searchByImage() and read() on the providers that have them
  • AuthError, RateLimitError with retryAfter, HTTPError with the key already redacted from the URL
  • Every network call takes a signal, a deadline and a concurrency bound
Read Custom providers
Filebrave.tssame calls · 13 providers

Search

import { create } from "@agntn/web";// reads BRAVE_API_KEY from process.env, imports one adapterconst provider = await create("brave");const results = await provider.search("TypeScript 7 native compiler", { maxResults: 5 });results[0].url;   // "infoq.com…"results[0].title; // same shape from Brave as from every other oneresults[0].publishedDate; // "2026-08-03"results.length;   // 5
Startpnpm add @agntn/webNode.js 26 or newer

Start with one command

One install gives you the library, the web CLI and the MCP server. Name a provider, ask it something and read the same shape whoever answered.

  • PinPre-1.0, so pin exact versions.
  • KeysEach provider reads its key from its own env var. A self-hosted SearXNG needs none.
  • DataResults and pages come from sites you did not write. Treat them as data.

First search

$ pnpm add @agntn/webimport { create } from "@agntn/web";const brave = await create("brave");const results = await brave.search("TypeScript 7 native compiler");results[0].url; // "https://www.infoq.com/news/2026/08/typescript-7-released/"