1
0
Fork
You've already forked pi-web-search
0
No description
  • TypeScript 100%
2026年06月18日 02:22:24 -03:00
providers search: use providerOrder and add Exa/Z-AI MCP fallbacks 2026年06月17日 22:06:58 -03:00
test fix: make extractText robust and move shared utils to utils.ts 2026年06月18日 02:22:24 -03:00
.gitignore Initial commit: web_search and fetch_content tools for Pi with Exa, Perplexity, Z-AI, xAI, and OpenAI 2026年06月17日 21:23:01 -03:00
AGENTS.md version: adopt CalVer 0Y.0M.0D (26.6.17) 2026年06月17日 23:07:35 -03:00
config.ts search: use providerOrder and add Exa/Z-AI MCP fallbacks 2026年06月17日 22:06:58 -03:00
fetch.ts fetch: add web_fetch and Z-AI reader backends with automated tests 2026年06月17日 22:17:59 -03:00
health.ts search: add cross-provider fallback with runtime cooldown and demotion 2026年06月17日 22:58:50 -03:00
index.ts fix: make extractText robust and move shared utils to utils.ts 2026年06月18日 02:22:24 -03:00
LICENSE Initial commit: web_search and fetch_content tools for Pi with Exa, Perplexity, Z-AI, xAI, and OpenAI 2026年06月17日 21:23:01 -03:00
package.json version: adopt CalVer 0Y.0M.0D (26.6.17) 2026年06月17日 23:07:35 -03:00
README.md search: add cross-provider fallback with runtime cooldown and demotion 2026年06月17日 22:58:50 -03:00
search.ts search: add cross-provider fallback with runtime cooldown and demotion 2026年06月17日 22:58:50 -03:00
tsconfig.json fetch: add web_fetch and Z-AI reader backends with automated tests 2026年06月17日 22:17:59 -03:00
types.ts Initial commit: web_search and fetch_content tools for Pi with Exa, Perplexity, Z-AI, xAI, and OpenAI 2026年06月17日 21:23:01 -03:00
utils.ts fix: make extractText robust and move shared utils to utils.ts 2026年06月18日 02:22:24 -03:00

pi-web-search

A Pi extension that adds web_search and web_fetch tools backed mostly by direct REST APIs. Exa and Z-AI may use their MCP-compatible HTTP endpoints internally as fallbacks, but the extension does not require Pi-level MCP integration or an MCP SDK. No DuckDuckGo scraping.

Providers

Provider Backend Filters Env var
Exa /answer + /search REST, fallback to Exa MCP-over-HTTP recency, domain, content optional (EXA_API_KEY)
Perplexity chat/completions (sonar) recency, domain PERPLEXITY_API_KEY
Z-AI (GLM) /paas/v4/web_search, fallback to Z-AI MCP-over-HTTP on 1113/balance errors recency, domain ZAI_API_KEY
xAI (Grok) /v1/responses + web_search tool XAI_API_KEY
OpenAI /v1/responses + web_search tool OPENAI_API_KEY

Anthropic and Gemini are planned for a future release.

Install

pi install npm:pi-web-search

Then configure at least one API key (see Configuration).

Configuration

API keys are resolved with environment variable > config file precedence.

Primary config file: ~/.pi/agent/web-search.json

Legacy fallback (read-only compatibility): ~/.pi/web-search.json

{
 "providerOrder": ["zai", "exa", "perplexity", "xai", "openai"],
 "exaApiKey": "abb8ecf3-...",
 "perplexityApiKey": "pplx-...",
 "zaiApiKey": "...",
 "xaiApiKey": "xai-...",
 "openaiApiKey": "sk-...",
 "xaiModel": "grok-3",
 "openaiModel": "gpt-4o",
 "enabled": true
}

Equivalent environment variables (EXA_API_KEY, PERPLEXITY_API_KEY, ZAI_API_KEY, XAI_API_KEY, OPENAI_API_KEY) override the config file.

Notes:

  • EXA_API_KEY is optional because Exa can fall back to its MCP-over-HTTP endpoint.
  • ZAI_API_KEY is still required. The extension may fall back from the REST search API to the Z-AI MCP-over-HTTP endpoint when the REST API reports insufficient balance / no resource package.

providerOrder

providerOrder defines the global fallback preference used when the tool call does not force a specific provider.

Example:

{
 "providerOrder": ["zai", "exa", "openai"]
}

Rules:

  • entries must be one of: exa, perplexity, zai, xai, openai
  • duplicates are ignored
  • partial lists are allowed; missing providers are appended in default order

So the example above becomes the effective order:

zai → exa → openai → perplexity → xai

Provider auto-selection

Provider resolution is internal and stateful per session. Each auto search computes an effective order:

  1. start from providerOrder
  2. keep only providers with credentials
  3. demote providers that have failed (sortByHealth)
  4. drop providers currently in cooldown

The search then tries each eligible provider in turn and falls back to the next one on failure.

Default effective order:

Exa → Perplexity → Z-AI → xAI → OpenAI

If no provider is usable, the tool returns a clear setup message. Exa remains usable without a key via its MCP-over-HTTP fallback.

Failure handling (cooldown + demotion)

Runtime health is kept in memory only and never written to your config file.

When a provider fails, it is recorded with a category-based cooldown:

Failure Cooldown
billing/quota (1113, insufficient balance, no resource package) 30 min
rate-limited (429) 5 min
auth (401/403, bad key) 30 min
other 4xx 5 min
5xx / network / timeout 60 s

Behavior:

  • a provider in cooldown is skipped until its window expires
  • a provider that fails repeatedly is demoted toward the back of the effective order
  • a successful call resets that provider's health
  • aborts/cancellations are never counted as failures
  • session_start clears all runtime health for a clean slate

Tools

web_search({ query: "Odin programming language latest release" })
// batch + filters
web_search({
 queries: ["query one", "query two"],
 numResults: 10,
 recencyFilter: "week", // "day" | "week" | "month" | "year"
 domainFilter: ["github.com"], // prefix with - to exclude
})
Parameter Description
query / queries Single query or batch (run in parallel)
numResults Results per query (default 5; Z-AI max 50)
recencyFilter day, week, month, year (Exa, Perplexity, Z-AI)
domainFilter Whitelist domains; prefix - to exclude (Exa, Perplexity, Z-AI)
includeContent Request inline page content where supported (Exa)

Returns a synthesized answer (where the provider produces one) plus a numbered Sources list. Z-AI is a pure search engine, so it returns a source list with snippets.

web_fetch

web_fetch({ url: "https://example.com/docs" })

Parameters:

Parameter Description
url Absolute URL to fetch

Behavior:

  • backend is resolved internally
  • if zai is the first usable provider in providerOrder, use Z-AI Web Reader (POST /api/paas/v4/reader)
  • if the Z-AI REST reader reports 1113 / insufficient-balance errors, fall back internally to the Z-AI Web Reader MCP-over-HTTP endpoint
  • otherwise use local HTTP + lightweight HTML stripping / JSON pretty-print

Output is truncated to ~50 KB / 2000 lines.

/search command

Command Action
/search Interactive provider-order picker (moves one provider to the front)

Provider configuration is stored in ~/.pi/agent/web-search.json.

Testing

npm test

This runs node:test directly on the TypeScript test files via Node's strip-types mode.

Development

This is a TypeScript-only package — Pi loads index.ts directly via jiti, so there is no build step. To type-check during development, point the compiler at Pi's installed packages:

# from the package directory
mkdir -p node_modules/@earendil-works node_modules/@types
ln -s "$(npm root -g)/@earendil-works/pi-coding-agent" node_modules/@earendil-works/pi-coding-agent
ln -s "$(npm root -g)/@earendil-works/pi-ai" node_modules/@earendil-works/pi-ai
ln -s "$(npm root -g)/@earendil-works/pi-tui" node_modules/@earendil-works/pi-tui
ln -s "$(npm root -g)/typebox" node_modules/typebox
ln -s "$(npm root -g)/@types/node" node_modules/@types/node
npx tsc --noEmit -p tsconfig.json

For local testing, symlink the package into Pi's extensions dir and run /reload:

ln -s "$PWD" ~/.pi/agent/extensions/pi-web-search

Structure

index.ts # tool + command registration, events, status bar
search.ts # provider resolution, execution, response formatting
config.ts # ~/.pi/agent/web-search.json load/save + legacy fallback
fetch.ts # local HTTP fetch + Z-AI Web Reader backend
types.ts # shared types
providers/
 exa.ts # /answer + /search
 perplexity.ts # chat/completions (sonar)
 zai.ts # /paas/v4/web_search (search-prime)
 xai.ts # /v1/responses + web_search tool
 openai.ts # /v1/responses + web_search tool

License

MIT — see LICENSE.