omp packages

pi-camoufox-gateway0.1.1

Let pi search the web and read pages through a camoufox gateway

odynvolk Published 9 days ago MIT ~376 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

pi-camoufox-gateway

Give pi web search and page reading through a self-hosted Camoufox browser gateway. No API keys, no per-query cost, and JavaScript-rendered pages come back readable.

This repo is the pi extension. The gateway (camofox-browser) runs separately; this code just talks to it over HTTP.

Tools

camoufox_search(query, n?, engine?, resolve?)

Searches through the browser and returns ranked titles, urls and snippets.

  • Google goes through the gateway's @google_search macro, which is what survives Google's consent interstitial. If Google walls us, DuckDuckGo answers and the output says which engines were tried.
  • Bing is not offered: through this gateway it returns a Network Protocol Error before results render, so it would only ever waste a page load.
  • n is clamped to 10. The macro takes only a query, so a longer list is not reachable.
  • resolve: true turns Google's google.com/goto?url=… wrappers into final urls. It costs one extra page load per result and runs at most three tabs at a time, so it is off by default.

camoufox_read(url, maxChars?, offset?, schema?)

Loads a page in the browser and returns its text.

  • Reports the final url after redirects.
  • Defaults to 12,000 characters (~3K tokens) and tells you the offset to continue from. A full page from the gateway runs 20K+ tokens, which is the difference between reading a page and losing your context window.
  • schema accepts a JSON Schema whose properties carry x-ref hints; the tool snapshots the page first (refs only exist after a snapshot), then calls the gateway's extractor.

Install

Install it as a pi package and pi wires it into your settings:

pi install npm:pi-camoufox-gateway        # every session (~/.pi/agent/settings.json)
pi install -l npm:pi-camoufox-gateway     # this project only (.pi/settings.json)

The camoufox_search and camoufox_read tools are then available the next time pi starts. Try it for a single run without writing to settings:

pi -e npm:pi-camoufox-gateway

Manage it with pi list, pi remove npm:pi-camoufox-gateway (pi uninstall is an alias) and pi update.

Without npm, or straight from this checkout:

pi install git:github.com/odynvolk/pi-camoufox-gateway@v0.1.1   # pinned to a tag
pi install ./pi-camoufox-gateway                                 # a local checkout
pi -e ./src/camoufox-gateway.ts                                  # from this repo, nothing installed

You do not need to declare pi.extensions anywhere yourself — package.json points pi at src/camoufox-gateway.ts. Pointing the extension at your gateway is described below.

Requires Node 23+ and a running camofox-browser; the extension is shipped as TypeScript and pi loads it directly.

Configuration

Config resolves defaults → JSON file → environment variables.

File location: $CAMOUFOX_CONFIG_PATH, or $PI_CODING_AGENT_DIR/camoufox.json (default ~/.pi/agent/camoufox.json). See config.example.json.

Environment: CAMOUFOX_GATEWAY_URL, CAMOUFOX_API_KEY, CAMOUFOX_CONFIG_PATH.

Setting Default Notes
gatewayUrl http://localhost:9377 must be absolute http(s)
apiKey unset sent as Bearer only if set
engines google, duckduckgo ordered fallback chain
cache.serpMs / cache.pageMs 30 min / 10 min failures are never cached
read.defaultMaxChars 12000 per-read text budget
search.maxResults 10 hard ceiling, engine page size
blockedHosts [] client-side guard; the gateway enforces none
timeoutMs 30000 per gateway request

Unknown keys are a hard error on purpose — a silently typo'd setting is worse than a loud one. A config file that exists but fails to load is not replaced with defaults either: every tool call returns config_error naming the file and the key, so a typo cannot quietly point the extension at the wrong gateway.

Error codes

The tool output starts with the code so the model can react instead of guessing.

Code Meaning
config_error the config file is unreadable or invalid, so nothing was attempted
gateway_unreachable cannot reach gatewayUrl (one cheap liveness probe per 60s window, not one timeout per call)
gateway_unauthorized gateway rejected apiKey
gateway_error the gateway answered with a failure, or something threw without a code
consent_wall Google served consent/CAPTCHA, not results
empty_results clean page, zero organic results
empty_page / navigation_failed nothing rendered / browser error page
parse_error the accessibility tree changed shape
extraction_empty schema refs matched nothing on this page
host_blocked url matched blockedHosts
blocked_url not an http(s) url
tab_not_found the tab was closed under us (session teardown or a stray sweep)
unsupported bad input or an engine we have no adapter for — nothing was fetched
timeout / aborted deadline hit / tool call cancelled

What this does not do

  • No browser or gateway code — that lives in camofox-browser.
  • No clicking, typing or scrolling. Refs ([e12]) are only valid until the next navigation, which makes an interaction API hard to promise.
  • No LLM in the tool path. The tools return raw data; your model does the reading.
  • Sessions: tabs live in a gateway session named after your pi session id and are torn down on session_shutdown. A lost POST /tabs/open response also triggers a sweep: the gateway may hold a tab we were never given an id for, so it is listed and closed rather than left behind.

Development

npm install
npm test          # unit + fixture tests, no network access
npm run typecheck
npm run test:live # live smoke test against the configured gateway
python3 scripts/record-fixtures.py  # re-record snapshots after a gateway or Google change

Requires Node ≥ 23: the tests import src/*.ts directly, which depends on Node's native type stripping. On 20 or 21 you get ERR_UNKNOWN_FILE_EXTENSION instead of a test failure.

The snapshot fixtures under tests/fixtures/ are real captures. If a parser test fails, re-record them before concluding the parser broke.