# Pi Search Tools

A unified web search and content extraction extension for Pi. The extension does not classify queries itself — routing decisions are made by the calling LLM, guided by each provider's self-declared specialty. This glossary defines the canonical terms for the extension's domain.

## Language

### Capability axes

**Search**:
The act of taking a query string and returning a list of web results (title, url, snippet, optional metadata). One of the two capability axes the extension routes across.
_Avoid_: lookup, retrieval (reserved for RAG-style grounding)

**Fetch**:
The act of taking a URL and returning its extracted content as clean text/markdown. The other capability axis. Independent of Search — a provider may offer one without the other.
_Avoid_: scrape, crawl (crawl is a distinct multi-page operation, not fetch)

**Provider**:
A service that implements one or both capability axes, declared via capability flags. There is a single `Provider` interface with optional `search()` and `fetch()` methods; a provider implements whichever it supports and flags them in `capabilities`. Tavily/AnySearch implement both; Jina implements fetch; Exa implements both; Gemini, Serper, and DeepSeek implement search; Firecrawl implements fetch; iFlow implements both. Tavily/AnySearch/Jina are built-in providers; the others are loaded from the local `pi-search-kit/` directory when present.
_Avoid_: engine, backend, source, SearchProvider/FetchProvider (no longer split into two interfaces)

### Providers

**Tavily**:
Built-in general-purpose web search plus extract, crawl, map, and research. Search and extract support keyless access; crawl/map/research require a key. The initial fallback provider when the LLM does not specify one.
_Avoid_: Tavily AI

**AnySearch**:
Built-in general and structured vertical search plus extraction. Supports anonymous search with lower rate limits; strongest for finance, academic, security, and travel verticals.
_Avoid_: AnySearch AI

**Exa**:
Local-only semantic/time-sensitive web search, strong on academic and freshness-driven queries. Backed by Cursor/Notion usage. Implements both search and fetch.
_Avoid_: Exa.ai

**Serper**:
Local-only fast Google Search API wrapper. Implements only search.
_Avoid_: Serper AI

**Jina**:
Content extraction via `r.jina.ai`. Implements only fetch. The Reader endpoint supports anonymous fetches at a lower rate limit; Jina's `s.jina.ai` search endpoint requires a key and is not exposed. Native PDF support and low latency; JS rendering is basic.
_Avoid_: Jina Reader, Reader API (those refer to the endpoint, not the provider as a whole)

**Firecrawl**:
Local-only content extraction via full headless Chromium (Playwright). Implements only fetch. Strongest JS rendering and main-content cleaning (`onlyMainContent`). Slower and quota-limited (monthly credits).
_Avoid_: Firecrawl.dev

### Security

**SSRF guard**:
The security boundary that prevents the extension from fetching internal, loopback, or private network addresses, protecting the local host from unauthorized private network request redirection.
_Avoid_: IP blacklist, firewall

### Routing

**LLM routing**:
The routing philosophy: the extension does not classify queries or pick providers. The calling LLM selects a provider via the `provider` parameter, guided by `promptGuidelines`. There is no in-extension rule-based classifier (the previous `router.ts` is removed).
_Avoid_: intent classification, automatic routing, rule routing

**Fallback chain**:
The ordered list of providers tried when the LLM does not pass `provider`. Generated at runtime by sorting providers by the `searchFallbackPriority` / `fetchFallbackPriority` numbers in their META (ascending; providers that don't declare the relevant priority are excluded). When the LLM explicitly specifies a provider via the `provider` parameter and that provider fails, the extension does NOT fall back — it returns the error to the LLM, respecting the LLM's choice. Current built-in ordering: search `Tavily → AnySearch`; fetch `Tavily → Jina → AnySearch` (free/low-latency first). Local providers are inserted according to their declared priorities when loaded and configured. Does not trigger on low-quality non-empty results — there is no quality classifier (rule-based routing was removed). A user who wants a specific provider passes it via the `provider` parameter or tells the LLM in natural language.
_Avoid_: retry list, default provider, fallback provider (superseded — there is no longer a single user-configured default, only chains)

**Vertical**:
A structured sub-domain search mode offered by a search provider, e.g. `finance.us_stock`, `academic.search`, `security.scan`. Passed by the LLM via the `vertical` parameter when it selects a vertical-capable provider for a domain query. The set of valid vertical values is not hardcoded — it is aggregated at runtime from each provider's META `verticals` field. The extension does not auto-detect when to send a vertical — that judgment belongs to the LLM.
_Avoid_: sub-intent, facet, auto-vertical

**promptGuidelines**:
The runtime-generated array of strings returned by `web_search` and `web_fetch` as tool guidance for the calling LLM. Each tool's `promptGuidelines` is formed by aggregating: (1) a fixed intro describing the tool's purpose, (2) one line per provider that declares a `searchHint` (search) or `fetchHint` (fetch) in its META, each formatted as `- Label (provider='name'): hint`, (3) a vertical enumeration listing all available `verticals` if any provider is vertical-capable, and (4) fixed closing rules about omitting provider, citing sources, and multi-query usage. Providers that only implement one capability axis (Serper/DeepSeek/Jina/Firecrawl) appear only in the guidelines for that axis. Adding a new provider automatically extends the relevant tool's guidelines — the aggregation is driven entirely by META fields, not hardcoded lists.
_Avoid_: guideline, routing rule, promptHint (superseded by the split pair)

**searchHint / fetchHint**:
Two specialty descriptions carried in each provider's META, one per capability axis. A provider that only implements fetch (Jina, Firecrawl) declares only `fetchHint`; its `searchHint` is undefined and it never appears in search guidelines. This keeps search and fetch routing advice independent, so the LLM does not infer a fetch specialty from a search specialty.

**apiKeyRequired**:
A boolean field in a provider's META (default `true`). When `false`, the provider factory creates an instance even without a configured API key, enabling zero-setup usage with reduced rate limits (currently Tavily and AnySearch for search/extract, and Jina for fetch). When `true` (or omitted), the factory skips the provider if no key is configured. The factory reads this field generically — no provider is special-cased by name.
_Avoid_: free tier flag, optional key (these describe the user-facing effect, not the META mechanism)
