pi-search-tools
LLM-driven web search and content extraction extension for Pi — Tavily, Exa, Anysearch, Gemini, DeepSeek, Jina, and Firecrawl.
Package details
Install pi-search-tools from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-search-tools- Package
pi-search-tools- Version
1.1.1- Published
- Jul 8, 2026
- Downloads
- 999/mo · 871/wk
- Author
- huanghui-dev
- License
- MIT
- Types
- extension
- Size
- 100.8 KB
- Dependencies
- 0 dependencies · 4 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
Pi Search Tools
LLM-driven web search and content extraction extension for Pi. The extension does not classify queries or auto-select providers. Instead, each provider declares its specialty via metadata (searchHint/fetchHint), and the calling LLM picks the best provider via the provider parameter, guided by dynamically-generated promptGuidelines.
Providers
| Provider | Search | Fetch | Notes |
|---|---|---|---|
| Tavily | ✅ | ✅ | General web search + crawl/map/research (SimpleQA SOTA 93.3%) |
| Exa | ✅ | ✅ | Semantic/academic search, freshness-driven queries |
| Serper | ✅ | — | Fast Google Search API wrapper for organic search |
| iFlow | ✅ | ✅ | Optimized for Chinese queries, news, and localized content extraction |
| Anysearch | ✅ | ✅ | Structured vertical search (finance, academic, security, travel) |
| Gemini | ✅ | — | Google Search Grounding API |
| DeepSeek | ✅ | — | DeepSeek's server-side search tool via its Anthropic-compatible API |
| Jina | — | ✅ | JS rendering, PDF support, frequency-limited, zero-setup (no API key required) |
| Firecrawl | — | ✅ | Full Playwright rendering, strongest JS support, quota-limited |
Project Structure
pi-search-tools/
├── index.ts # Pi extension entry point (re-exports src/index.ts)
├── src/
│ ├── index.ts # Extension registration logic
│ ├── config.ts # Config file parser (~/.pi/pi-search-tools/config.json)
│ ├── commands.ts # Interactive /search-tools API key setup
│ ├── utils.ts # Result dedup, SSRF guard, retry/timeout, memory cache
│ ├── web-search.ts # web_search tool with dynamic provider routing
│ ├── web-fetch.ts # web_fetch tool with SSRF protection + content extraction
│ └── providers/ # REST API clients + provider metadata
│ ├── index.ts # Factory, dynamic helpers, promptGuidelines aggregation
│ ├── types.ts # Provider interface + META types
│ ├── tavily.ts # Tavily API adapter
│ ├── exa.ts # Exa API adapter
│ ├── serper.ts # Serper API adapter (Google Search wrapper)
│ ├── iflow.ts # iFlow API adapter (Chinese optimization)
│ ├── anysearch.ts # Anysearch API adapter (vertical search)
│ ├── gemini.ts # Gemini API adapter (Google Search Grounding)
│ ├── deepseek.ts # DeepSeek API adapter (Server-side search grounding)
│ ├── jina.ts # Jina reader adapter (SSE-aware, zero-setup)
│ └── firecrawl.ts # Firecrawl API adapter
├── test/ # Native TypeScript unit tests (80 tests)
│ ├── providers.test.ts # META consistency + dynamic enum/chain generation
│ ├── prompt-guidelines.test.ts # promptGuidelines aggregation correctness
│ ├── factory.test.ts # Provider factory + apiKeyRequired behavior
│ ├── execute.test.ts # Search/fetch execution flow + this-binding regression
│ ├── gemini.test.ts # Gemini API request, parsing, redirection timeouts
│ ├── deepseek.test.ts # DeepSeek API stream parsing + custom model tests
│ ├── jina-fetch.test.ts # Jina SSE parsing + dedup
│ ├── config.test.ts # API key masking and resolution priority
│ ├── dedup.test.ts # URL deduplication
│ └── utils.test.ts # SSRF, SafeMemoryCache, fetchWithTimeout/Retry
└── package.json
Installation
pi install npm:pi-search-tools
Configuration
Interactive Setup
/search-tools
Select a provider and enter its API key.
Environment Variables
Set provider API keys in your environment (takes precedence over config file):
TAVILY_API_KEYEXA_API_KEYSERPER_API_KEYIFLOW_API_KEYANYSEARCH_API_KEYGEMINI_API_KEYDEEPSEEK_API_KEYDEEPSEEK_SEARCH_MODEL(Optional; customize the model used for search, defaults todeepseek-v4-flash)JINA_API_KEYFIRECRAWL_API_KEY
Routing
LLM-Driven Routing
The extension does not classify queries. The calling LLM chooses a provider via the provider parameter:
# General search → Tavily (fastest)
web_search({ query: "React 19 features", provider: "tavily" })
# Academic search → Exa (semantic, freshness-driven)
web_search({ query: "transformer architecture paper", provider: "exa" })
# Stock/CVE → Anysearch + vertical
web_search({ query: "AAPL", provider: "anysearch", vertical: "finance.us_stock" })
web_search({ query: "CVE-2025-12345", provider: "anysearch", vertical: "security.scan" })
If you omit provider, a cost-priority fallback chain is tried automatically:
- Search:
Tavily → Exa → Serper → iFlow → Anysearch → Gemini → Deepseek - Fetch:
Tavily → Jina → Exa → Anysearch → Firecrawl → iFlow
When you explicitly specify a provider and it fails, the extension does not fall back — it returns the error to the LLM, respecting the LLM's choice.
Architecture
Design decisions are documented in the repository:
- CONTEXT.md — domain glossary and canonical terminology
- docs/adr/ — architecture decision records (LLM routing, single interface, Jina search exclusion, Anysearch retention)
Testing
npm run test
80 tests covering META consistency, chain generation, promptGuidelines aggregation, factory behavior, execution flow, SSE parsing, config resolution, dedup, and SSRF protection.
Development
- Linter & Formatter: Biome, tab indentation (width 3)
- TypeScript: strict mode
- Check:
npm run check - Test:
npm test
License
MIT