# Web Search Backend Example

Minimal sidecar service for `websearch` via `PI_WEBSEARCH_BACKEND_URL`.

The service is intentionally small:

- accepts `/search` requests from the Pi extension
- calls one AI-search provider through an adapter
- normalizes the provider response to Pi's `SearchBackendResponse`
- returns URLs, titles, snippets, and lightweight metadata

It does not crawl the web itself and it does not return a final AI answer instead of search results.

## First Provider

This example starts with one **Tavily-like** search adapter. The adapter expects a provider that accepts a JSON search request and returns a `results[]` array containing `title`, `url`, `content`/`snippet`, and optional `score`.

## Run

```bash
cat > .env.web-search-backend.local <<'EOF'
PI_TAVILY_SEARCH_API_KEY=...
PI_WEB_SEARCH_BACKEND_PORT=8787
EOF

./scripts/start-web-search-backend.sh
```

Optional provider settings:

```bash
export PI_TAVILY_SEARCH_BASE_URL=https://api.tavily.com/search
export PI_TAVILY_SEARCH_DEPTH=basic
export PI_TAVILY_SEARCH_TOPIC=general
export PI_WEB_SEARCH_BACKEND_HOST=127.0.0.1
```

The start script loads `.env.web-search-backend.local` automatically and prints the backend URL you should export for Pi:

```bash
export PI_WEBSEARCH_BACKEND_URL=http://127.0.0.1:8787/search
```

Or start Pi from the same local env file directly:

```bash
./scripts/start-pi-with-websearch.sh
```

That script starts the local repo source, not the published npm package, so project-local extensions can use the current workspace code.

`/reload` is not enough if the running Pi process was started without `PI_WEBSEARCH_BACKEND_URL`.

## API

`GET /health`

`GET /search?query=...&maxResults=5&allowedDomains=docs.example.com&excludedDomains=blog.example.com`

`POST /search`

```json
{
	"query": "how to configure pi websearch",
	"allowedDomains": ["docs.example.com"],
	"excludedDomains": ["blog.example.com"],
	"maxResults": 5,
	"freshnessDays": 30
}
```

Response shape:

```json
{
	"backend": "search-backend:tavily-like",
	"results": [
		{
			"title": "Example result",
			"url": "https://docs.example.com/install",
			"snippet": "Compact summary from the upstream provider.",
			"source": "tavily-like",
			"score": 0.93
		}
	],
	"hasMore": false,
	"blockedDomains": [],
	"rateLimitedDomains": [],
	"latencyMs": 140
}
```

## Extension Interaction

- Pi `websearch` sends a small query to this backend.
- The backend returns compact results.
- Pi decides what to fetch next with `webfetch`.

If you later want more control, keep the HTTP shape and swap the adapter behind it.
