# search_exa

A RocketRide search node that submits a user question to the Exa web search API and returns the raw results as pipeline output.

## What it does

Takes a question from the `questions` lane, sends it as a single query to the Exa REST endpoint (`https://api.exa.ai/search`), and writes the pretty-printed Exa JSON response to the `answers` and `text` lanes.

Uses the **requests** library directly against the Exa REST API; no Exa SDK is required. Each HTTP request has a 30-second timeout. The node expects exactly one question per invocation: an empty question or a multi-question payload raises an error immediately.

Result URLs are sanitized before leaving the node. Every `url`, `image`, and `favicon` field in the Exa response is validated to be an `http`/`https` URL whose host resolves to a public IP address. Results whose primary `url` resolves to a private, loopback, link-local, reserved, multicast, or unspecified address are dropped entirely; invalid `image` and `favicon` fields are removed from the result without dropping the whole result. This guards downstream nodes against SSRF via attacker-influenced search content. Sanitization is skipped when the `ROCKETRIDE_MOCK` environment variable is set, which is useful for local testing.

---

## Configuration

### Lanes

| Lane in     | Lane out  | Description                                                    |
|-------------|-----------|----------------------------------------------------------------|
| `questions` | `answers` | Search results as answers (pretty-printed Exa JSON)            |
| `questions` | `text`    | Search results as plain text                                   |
| `questions` | `questions` | Original question passed through unchanged (when a downstream listener is connected) |

### Fields

| Field | Type | Description |
|---|---|---|
| `profile` | string | Default "default".  |
| `apikey` | string | Default empty. Exa API key |
| `type` | string | Default "auto".  |
| `numResults` | integer | Default 5.  |
| `includeHighlights` | boolean | Default true.  |
| `highlightChars` | integer | Default 600.  |

The node ships a single `default` profile containing the search settings (`type`, `numResults`, `includeHighlights`, `highlightChars`). The `apikey` field sits outside the profile and is set once per connection config.

---

## Authentication

The API key is resolved in the following order:

1. `apikey` in the node config
2. `apikey` in the connection config
3. The `ROCKETRIDE_EXA_KEY` environment variable

If none of these sources provides a non-empty value, the pipeline fails at startup with `search_exa: apikey is required`. The editor also surfaces a validation warning while you are configuring the node.

---

## Error handling

Exa HTTP errors are mapped to descriptive failures:

- **401**: `Exa authentication failed` -- bad or missing API key
- **429**: `Exa rate limit exceeded`
- Other 4xx/5xx: `Exa request failed (<status>)` with the upstream message body
- Network timeout: `search_exa: Exa request timed out`
- Connection failure: `search_exa: Unable to reach Exa`

---

<!-- ROCKETRIDE:GENERATED:PARAMS START -->
<!-- Generated by nodes:docs-generate. Do not edit by hand. -->

## Schema

| Field | Type | Description | Default |
|---|---|---|---|
| `search_exa.apikey` | `string` | **API Key**<br/>Exa API key | `""` |
| `search_exa.highlightChars` | `integer` | **Highlight Chars** | `600` |
| `search_exa.includeHighlights` | `boolean` | **Include Highlights** | `true` |
| `search_exa.numResults` | `integer` | **Results** | `5` |
| `search_exa.profile` | `string` | **Profile** | `"default"` |
| `search_exa.type` | `string` | **Search Type** | `"auto"` |

## Dependencies

- `requests`

## Source

[<svg viewBox="0 0 16 16" width="15" height="15" fill="currentColor" aria-hidden="true" style="vertical-align:-0.15em;margin-right:0.35em"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg> View source](https://github.com/rocketride-org/rocketride-server/tree/develop/nodes/src/nodes/search_exa)
<!-- ROCKETRIDE:GENERATED:PARAMS END -->
