The shape
Every library has the same skeleton. Learn one, you know the rest.
Registry and adapters
A provider is a class. In most libraries it registers itself under a name when the module loads and create(name) looks it up, so there's no switch statement to extend. A custom provider is one class and one register() call. A few libraries expose a factory instead, createArchive() in archives, createProvider() in forges, same idea.
import { create, register } from "@agntn/web";
import { MyEngine } from "./my-engine";
register(MyEngine);
const provider = create("my-engine");
const answer = await provider.search({ query: "typescript 7 native" });
The registry is also how the tools know what exists. When a tool validates the provider argument it asks the registry, so a provider you registered yourself works in a tool call too.
Normalized types
Every method answers the shared type of its domain. A search result is { url, title, snippet } with score, dates and highlights when the engine has them. A package is { name, version, license, repository } with the license normalized to SPDX. An archived page is { url, timestamp, snapshot } with provider extras under _meta. Upstream quirks get mapped inside the adapter and never show up in the public types.
When a provider can't do what you asked, the library says so instead of dropping it. A filter the engine can't apply lands in ignoredFilters. A provider that fails inside a fan out lands in errors while the others still answer.
Typed errors
Failures are values with a class, never a bare Error with a string you have to parse. The exact set depends on what can go wrong in the domain. These are the ones the network libraries share:
| Error | Meaning | Found in |
|---|---|---|
RateLimitError | Provider throttled the call, carries retryAfter when known | web, registries, forges, explorers, ciphers |
NotFoundError | The thing you asked for doesn't exist upstream | registries, forges, explorers |
HTTPError | Any other upstream failure, key already redacted from the URL | web, registries, explorers |
AuthError | Missing or rejected credential | web, explorers |
Network calls take an abort signal, so an agent host can cancel a tool call and the request actually stops. Libraries that fan out over several providers, web and archives among them, also take a concurrency bound. web adds a deadline on top.
Configuration
Keys come from the environment when a provider is created. A provider without a key is reported as not configured instead of blowing up later. Hosts and timeouts are constructor options. Nothing is read from a config file the library made up.