# pi-search-kit

[简体中文](README.zh-CN.md)

LLM-driven web search and content extraction extension for [Pi](https://pi.dev). Ships with built-in Tavily and AnySearch search, plus Jina content extraction.

## Features

- **Built-in Provider Coverage**: Tavily and AnySearch provide general and vertical search; Tavily, AnySearch, and Jina provide content extraction.
- **LLM-Driven Dynamic Routing**: Providers declare capability metadata (`searchHint`/`fetchHint`). The calling LLM selects optimal providers via `promptGuidelines` without static query classifiers.
- **Zero-Setup & Fallback Chains**: Tavily and AnySearch support keyless search, while Jina provides zero-configuration content extraction. Automatic cost-prioritized fallback chains handle transient provider downtime.
- **SSRF & Security Guard**: Built-in DNS and IP validation blocks SSRF attacks against private networks, loopbacks, and cloud metadata services.
- **Bounded Output & Dedup**: Automatically deduplicates search results and truncates oversized webpage contents into local temporary files.

## Requirements

- Node.js 22.19.0 or later
- `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, `@earendil-works/pi-tui`, and `typebox`
- No API key is required for the built-in Tavily/AnySearch search or Jina fetching providers

## Installation

```sh
pi install npm:pi-search-kit
```

## Configuration

Built-in Tavily, AnySearch, and Jina providers work without API keys. To enable authenticated provider features, configure the relevant environment variables:

| Provider | Environment Variable | Specialty / Notes |
| --- | --- | --- |
| Tavily | `TAVILY_API_KEY` (optional) | Keyless general search and extract; key unlocks crawl/map/research |
| AnySearch | `ANYSEARCH_API_KEY` (optional) | Keyless general and vertical search/extract |
| Jina | `JINA_API_KEY` (optional) | Keyless URL and PDF extraction |

Environment variables take precedence over values in the existing `~/.pi/pi-search-kit/config.json` file. The config file is still read for compatibility with previous versions; its key format is:

```json
{
  "apiKeys": {
    "tavily": "your-tavily-key",
    "anysearch": "your-anysearch-key",
    "jina": "your-jina-key"
  }
}
```

## Usage

Agents invoke the `web_search` or `web_fetch` tools directly:

```ts
// General search via Tavily
web_search({ query: "React 19 features", provider: "tavily" })

// Vertical search via the built-in AnySearch provider
web_search({ query: "AAPL stock price", provider: "anysearch", vertical: "finance.us_stock" })

// Content fetch via Jina
web_fetch({ url: "https://example.com/article", provider: "jina" })
```

If `provider` is omitted, the built-in providers are tried in cost-priority order:
- **Search**: `Tavily → AnySearch`
- **Fetch**: `Tavily → Jina → AnySearch`

When `provider` is specified explicitly, the extension uses only that provider and returns its error instead of silently switching to another provider.

## Security

Extension packages execute with the user's system privileges. Review source code before installing any extension.

This extension makes HTTP/HTTPS requests to external provider APIs and user-requested web URLs. It includes built-in SSRF guards (`assertSafeDns` and IP validation) to prevent access to private IP ranges (`127.0.0.1`, `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, AWS metadata `169.254.169.254`). Provider API keys are read from `~/.pi/pi-search-kit/config.json` or environment variables.

## Development

```sh
git clone https://codeberg.org/huanghui/pi-search-kit.git
cd pi-search-kit
npm ci
npm run check
npm test
npm pack --dry-run --json
```

Refer to [CONTEXT.md](CONTEXT.md) and [docs/adr/](docs/adr/) for architecture decision records and domain glossary.

## Contributing

Issues and pull requests are welcome on [Codeberg](https://codeberg.org/huanghui/pi-search-kit). Before submitting changes, please ensure `npm run check` and `npm test` pass cleanly.

## License

[MIT](LICENSE)
