@wierdbytes/pi-web
Anthropic-powered web_search tool for the pi coding agent
Package details
Install @wierdbytes/pi-web from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@wierdbytes/pi-web- Package
@wierdbytes/pi-web- Version
0.6.0- Published
- Sep 11, 2026
- Downloads
- 114/mo · 21/wk
- Author
- wierdbytes
- License
- MIT
- Types
- extension
- Size
- 154.9 KB
- Dependencies
- 4 dependencies · 0 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@wierdbytes/pi-web
Web tools for the pi coding agent:
web_search— Anthropic-powered server-side search with citations.web_fetch— headless-Chrome fetch + trafilatura extraction, with optional sub-agent distillation. Ported from pi-web-fetch (hooks/extension system intentionally omitted).
Tools
Both tools render with the open-right rounded chrome from
@wierdbytes/pi-common/tool-frame (renderShell: "self") so
output sits in a status-coloured frame that matches
@wierdbytes/pi-facelift's read / bash / ls / find / grep:
╭── web_search "query" ────────────────────────
│ 2 sources · 3 cites
╰── ctrl+o to expand ───────────────────────────
For batch web_fetch calls, the URLs render as a sub-tree under the
top border:
╭── web_fetch 3 pages ─────────────────────────
│ │ a.example.com/one
│ │ b.example.com/two
│ ╰ c.example.com/three
web_search
A one-shot POST /v1/messages call backed by Anthropic's server-side
web_search_20250305 tool. Returns a synthesized answer + citations + raw
source list. Never touches the agent's main turn stream.
Parameters:
query(required) — the search querymax_uses— cap on follow-up searches Claude may issue (default 5)allowed_domains/blocked_domains— domain filteringuser_location—{ type: "approximate", country?, city?, region?, timezone? }max_tokens— output token cap for the synthesized answer (default 4096)temperature— sampling temperature, 0–1
web_fetch
Fetches one or more URLs through headless Chrome, extracts the main content as markdown via trafilatura, and optionally distills the result with a pi sub-agent.
Parameters:
url— single URL to fetch (mutually exclusive withpages)prompt— optional extraction prompt. When set, the page content is processed by a fast LLM and only the relevant parts are returned. Omit for the full extracted markdown.summarize— optional, defaults totrue. Set tofalseto skip the automatic LLM overview for large pages and get the raw markdown instead (truncated to pi's standard 2000 lines / 50KB tool-output limits). Cannot be combined withprompt— the call is rejected.pages— array of{ url, prompt?, summarize? }(max 10) for concurrent batch fetching with live per-URL progress.
Behavior:
- HTTP URLs are auto-upgraded to HTTPS.
- Cross-host redirects are surfaced rather than followed; make a second call to the redirect target.
- Pages are cached in-memory for 15 minutes — repeated questions about the same page are cheap.
- Pages larger than ~50KB are auto-summarized (when a model is available)
to a structured overview when no prompt is provided. Pass
summarize: falseto opt out and receive truncated raw markdown instead; the frame title shows a· rawmarker in that case. - Browser pool keeps Chrome warm: one shared instance, up to 6 concurrent tabs, idle-shutdown after 60s.
- Stealth mode is enabled by default via
puppeteer-extra-plugin-stealth: patchesnavigator.webdriver, plugins, languages, WebGL vendor, thechromeruntime, and the User-Agent so common bot-detection canaries pass. Pages that refuse to hydrate for headless Chrome (e.g. SPAs behind fingerprinting) render normally. Auth-walled content is still gated by login — stealth doesn't sign you in. - Two-phase load: navigation waits for
domcontentloaded(hard cap 20s), then opportunistically waits up to 5s for the network to quiet down. Heavy ad/analytics traffic no longer prevents a snapshot — if the network never settles within budget, we capture whatever has rendered.
Prerequisites for web_fetch:
- A Python tool runner (auto-detected, in priority order):
- Puppeteer's bundled Chromium is downloaded on first install (~300MB).
Set
PUPPETEER_EXECUTABLE_PATHto skip the download and use an existing Chrome/Chromium binary. puppeteer-extraandpuppeteer-extra-plugin-stealthare installed as regular dependencies. They're loaded lazily — if they fail to import the pool falls back to plain puppeteer with a warning.
Auth
Resolved in this order, first hit wins:
PI_WIERD_WEB_API_KEYenvironment variable (explicit override).ctx.modelRegistry.getApiKeyForProvider("anthropic")— covers stored API keys, OAuth refresh-with-locking, andANTHROPIC_API_KEYvia pi'sAuthStorage. Same path the agent uses for normal turns, so it inherits anypi.registerProvider("anthropic", { baseUrl })overrides as long asgetApiKeyForProviderreaches them.ANTHROPIC_API_KEY— direct env read, last resort.
OAuth tokens (prefixed sk-ant-oat) are detected automatically and trigger
the Claude-Code-stealth header set (anthropic-beta: claude-code-...,oauth-...,
User-Agent: claude-cli/..., x-app: cli) plus the
"You are Claude Code, ..." system block. claude-3-5-haiku* models skip
the Claude Code identity block, matching pi-mono's built-in carve-out.
Install
pi install npm:@wierdbytes/pi-web
Restart pi to activate. Verify with /web status.
Configuration
Settings persist at ~/.pi/agent/wierd-web.json. The file is created on
first run, seeded from environment variables. Shape:
{
"searchModel": "claude-haiku-4-5",
"fetchModel": "anthropic/claude-haiku-4-5",
"fetchThinkingLevel": "medium"
}
searchModel— Anthropic model used byweb_search.fetchModel— provider/model id for theweb_fetchsub-agent. If unset, falls back to the current session model.fetchThinkingLevel— thinking level for theweb_fetchsub-agent. If unset, falls back to the current session thinking level.
Commands
/web status— print models, thinking level, auth source, config path/web model <id>(alias:search-model) — setsearchModel/web fetch-model <provider/model-id>— setfetchModel/web fetch-thinking <level>— setfetchThinkingLevel/web reset— wipe config, re-seed from env
CLI flags
--wierd-web-model <id>— boot-timesearchModeloverride
Environment
PI_WIERD_WEB_API_KEY— explicit Anthropic credential (API key or OAuth)PI_WIERD_WEB_MODEL— defaultsearchModel(falls back toclaude-haiku-4-5)PI_WIERD_WEB_FETCH_MODEL— defaultfetchModelforweb_fetchPI_WIERD_WEB_FETCH_THINKING— defaultfetchThinkingLevelPI_WIERD_WEB_BASE_URL— override the Anthropic base URL (proxies / regional endpoints). Defaults tohttps://api.anthropic.com.PUPPETEER_EXECUTABLE_PATH— use an existing Chrome/Chromium binary instead of puppeteer's bundled download.
Tests
bun --filter @wierdbytes/pi-web test
Architecture
| File | Responsibility |
|---|---|
index.ts |
Extension entry: tool registration, /web command, lifecycle hooks |
config.ts |
Load/save ~/.pi/agent/wierd-web.json, env seeding |
anthropic.ts |
Auth resolution, header builder, single POST /v1/messages transport |
search.ts |
web_search tool definition + response parser + LLM-facing formatter |
render.ts |
web_search TUI renderers |
types.ts |
web_search types + minimal raw API content-block shapes |
fetch.ts |
web_fetch tool definition + cache + pipeline + batch executor |
fetch-render.ts |
web_fetch TUI renderers (per-URL status, collapsed/expanded result) |
fetch-types.ts |
web_fetch internal types |
browser-pool.ts |
Shared puppeteer browser, lazy launch, max-tabs queueing, idle shutdown |
extract.ts |
Python-runner detection, trafilatura subprocess, timeout helpers |
subagent.ts |
Spawns pi --mode json sub-agent for distillation/summarization |