# pi-xsearch-gateway

X search for any Pi model, without installing a Grok provider.

`pi-xsearch-gateway` adds one `x_search` tool to [Pi](https://pi.dev). The tool sends a separate request to xAI's Responses API or to a gateway that passes through the server-side `x_search` tool. Your active Pi model can be Claude, GPT, Gemini, Grok, or a local model.

The extension has no runtime dependencies, background processes, persistent clients, or per-session cache.

## Install

```bash
pi install npm:pi-xsearch-gateway
```

Then reload Pi:

```text
/reload
```

## Direct xAI setup

Set an xAI API key before starting Pi:

```bash
export XAI_API_KEY="..."
pi
```

The direct setup uses:

```text
https://api.x.ai/v1/responses
```

The default search model is `grok-4-1-fast-non-reasoning`. Override it when needed:

```bash
export PI_XSEARCH_MODEL="grok-4.5"
```

## Gateway setup

Point the tool at any gateway that supports the OpenAI Responses request shape and passes through xAI's server-side `x_search` tool:

```bash
export PI_XSEARCH_URL="https://llm.example.com/v1/responses"
export PI_XSEARCH_API_KEY="..."
pi
```

An auth-free local gateway is also supported:

```bash
export PI_XSEARCH_URL="http://127.0.0.1:8317/v1/responses"
pi
```

Remote endpoints must use HTTPS. Plain HTTP is accepted only for loopback addresses.

## Usage

Ask naturally:

```text
Search X for recent posts about the Responses API.
```

Or use filters:

```text
Find posts from @xai and @SpaceXAI about Grok between 2026-07-01 and 2026-07-31.
```

The tool accepts:

| Parameter                    | Purpose                                           |
| ---------------------------- | ------------------------------------------------- |
| `query`                      | Keywords, hashtags, or a natural-language request |
| `allowed_x_handles`          | Search only these handles, maximum 10             |
| `excluded_x_handles`         | Exclude these handles, maximum 10                 |
| `from_date`                  | Inclusive start date in `YYYY-MM-DD` format       |
| `to_date`                    | Inclusive end date in `YYYY-MM-DD` format         |
| `enable_image_understanding` | Inspect images attached to matching posts         |
| `enable_video_understanding` | Inspect videos attached to matching posts         |

The allowed and excluded handle lists cannot be used together. A leading `@` is optional, and duplicate handles are removed.

## Configuration

| Variable                       | Default                         | Description                                                       |
| ------------------------------ | ------------------------------- | ----------------------------------------------------------------- |
| `PI_XSEARCH_URL`               | `https://api.x.ai/v1/responses` | Direct xAI endpoint or compatible gateway                         |
| `PI_XSEARCH_API_KEY`           | unset                           | Gateway-specific bearer token                                     |
| `XAI_API_KEY`                  | unset                           | Fallback token for direct xAI access                              |
| `PI_XSEARCH_MODEL`             | `grok-4-1-fast-non-reasoning`   | Model used for the separate search request                        |
| `PI_XSEARCH_REASONING_EFFORT`  | unset                           | Optional reasoning effort for models and gateways that support it |
| `PI_XSEARCH_MAX_OUTPUT_TOKENS` | `4096`                          | Positive integer output-token limit                               |

`PI_XSEARCH_API_KEY` takes precedence over `XAI_API_KEY`.

## Why a separate tool?

Search should not dictate which model handles the rest of your Pi session. A separate tool lets a coding or reasoning model call Grok only for the part Grok is uniquely positioned to answer: current content from X.

It also keeps gateway routing explicit. Teams can send search traffic through their existing proxy, rate limiter, audit layer, or account router without adding a second model provider to Pi.

## Resource use

The extension imports `ExtensionAPI` as a TypeScript type only. The emitted JavaScript has no Pi or TypeBox runtime imports.

A local benchmark with Pi 0.82.1 found no measurable idle-memory increase beyond normal process variance. The benchmark compared nine alternating starts of Pi without the extension and Pi with the extension. See [docs/benchmarks.md](docs/benchmarks.md) for the measurements and limitations.

## Response handling

The extension:

- extracts source URLs from output annotations and citation arrays
- removes duplicate citations
- rejects responses that explicitly report zero `x_search` calls
- refuses redirects so a bearer token cannot follow a redirect to another host
- limits model-facing output to 50 KB or 2,000 complete lines
- truncates on UTF-8 boundaries

X posts are untrusted third-party content. Pi receives a prompt guideline telling the active model not to treat post text as instructions.

## Gateway compatibility

A gateway must accept this shape at its configured Responses endpoint:

```json
{
  "model": "grok-4-1-fast-non-reasoning",
  "input": [{ "role": "user", "content": "..." }],
  "tools": [{ "type": "x_search" }],
  "store": false,
  "stream": false
}
```

"OpenAI-compatible" by itself is not enough. The gateway must preserve the xAI `x_search` tool and return a Responses-style result.

## Development

```bash
npm install
npm run check
```

Test the package in Pi without installing it:

```bash
pi -e .
```

## License

MIT
