> Public product help. This page has no customer entries, projects, chat transcripts, API keys, or horizon contents.
> Reading that data requires `Authorization: Bearer` (a signed-in app session JWT, or a Headless access token).
> Do not call Supabase `/rest/v1` with a Headless JWT. Data reads go through `/casc/v1/headless/v1/rest`.

# Vector Tools and Embeddings

Tools are how chat agents and processing prompts access your data and the outside world. Manage them under **Settings → Tools**. Project chats use the **project global allowlist**: all horizon tools plus your active web search provider.

## Tool kinds

| Kind | Purpose | Needs ingestion groups? | Embeddings? |
| --- | --- | --- | --- |
| **Search** | Semantic similarity over approved entries in linked groups | Yes (1–5 groups) | **Yes — required after every ingest** |
| **Analytics** | SQL-style aggregates (sum, count, group by) on allowlisted raw/output keys | Yes | No for aggregates; still embed any linked *search* tools after ingest |
| **Filter** | Exact field predicates returning matching rows (paginated) | Yes | No for filter itself; still embed any linked *search* tools after ingest |
| **Web search** | Internet search via Brave, Serper, or Tavily | No | No |
| **HTTP request** | Configured outbound HTTP (method, URL, headers, auth, body template); runtime supplies `url` | No | No |
| **Scheduler** | UTC cron (15-minute min); run a tool chain or a generic prompt with attached tools. Manage under Settings → Scheduler | No | No |

See also [scheduler](scheduler.md) for toolchain scheduler status, pause/activate, and chat controls.

## How to build a search tool

1. **Settings → Tools → Add Tool**.
2. Select **Horizon** (suffix).
3. Tool kind: **Search**.
4. Enter unique **slug** and **name**.
5. Pick **ingestion group(s)** that contain the data to search.
6. Set **search field** — primary text embedded and matched (e.g. `raw.body`, `raw.description`, `file.file`). Must exist on the group's column mapping or entries.
7. Set **return fields** — columns returned to the agent (titles, ids, filenames). Use `raw.*` prefix for raw columns.
8. Save, then **Initiate Embedding**.

See [search-fields](search-fields.md) for raw vs output key rules.

## How to build an analytics tool

1. Ensure entries store JSON metrics on a raw field (e.g. `raw.metrics`).
2. Add tool kind **Analytics**; select groups and **return fields** (allowlisted keys the agent may aggregate).
3. Set search field to the JSON field or first return field.
4. Attach to prompts or rely on project global allowlist.

Agents send structured query JSON (measures, group_by, filters). See [analytics](analytics.md).

## How to build a filter tool

1. Add tool kind **Filter**; select groups and **return fields** (allowlisted keys the agent may filter on and receive).
2. Search field is optional (defaults to first return field).
3. Attach to prompts or rely on project global allowlist.

Agents send field predicates and paginate until `has_more` is false. See [filter](filter.md).

## How to build a web search tool

1. Add tool kind **Web search**.
2. Choose **search provider** (Brave, Serper, Tavily).
3. Add provider API key under **Settings → User → Web Search API Keys** and set **Active Web Search Provider**.
4. No ingestion groups required. Tool is included in project allowlist when provider is active for your account.

## How to build an HTTP request tool

Use **HTTP request** for fixed outbound APIs (readers, extractors, webhooks). The tool config owns
method, request URL, headers, auth, and body template. Chat or a tool chain supplies the target
`url` (alias `search`), which is substituted for `{{url}}` in the
request URL, headers, and body. The egress host must match the configured request URL host (SSRF lock).

1. **Settings → Tools → Add Tool**; kind **HTTP request**.
2. Set **method** and **request URL**: - POST example: `https://r.jina.ai/` with body `{ "url": "{{url}}" }` - GET example: `https://r.jina.ai/{{url}}` (runtime `url` is path-encoded)
3. Add static **headers** as a JSON object (Content-Type, extraction options, timeouts, etc.).
4. Choose **auth**: none, Bearer, or API-key header. You can lock a secret on the tool (write-only), leave it blank and pass `auth_token` / `token` / `api_key` at runtime, or set the field to `{{auth_token}}` (same aliases) like `{{url}}`.
5. Set a **body template** when needed, e.g. `{ "url": "{{url}}" }`.
6. Optional: timeout (≤ 60s), max response size (`0` = unlimited), **batch size** (1–100 concurrent outbound calls; default 1), parse as text/JSON/auto.
7. In chat or a chain, call the tool with `url` set to the page/article to fetch. The result includes `status`, sanitized `response_headers`, and `body_text` / `body_json` for downstream steps.
8. Ingestion prompts: attach this tool to the prompt, then click the workflow button on Horizon (Ingest only loads `raw` rows). The processor seeds `url` from `raw.url` when the model omits it, then writes output keys such as `MD`.

### Example: Jina Reader

| Config field | Value |
| --- | --- |
| method | `POST` |
| request_url | `https://r.jina.ai/` |
| auth | Bearer — static Jina token *or* `{{auth_token}}` passed at runtime |
| headers | `Content-Type: application/json` plus optional `X-Remove-Selector`, `X-Retain-Images`, `X-Target-Selector`, `X-Timeout`, … |
| body_template | `{ "url": "{{url}}" }` |
| runtime arg | `url` = the article/page to extract |

Response text is available as `items[0].body_text` for chat and tool chains.

## Tool allowlists in chat

- **Project global** — all horizon search/analytics/filter/web tools + active web search.
- **Project agent prompt** — optional `tools` list further restricts the subset.
- **Workflow prompt** — when user clicks a workflow button, that prompt's tool list applies for that message.

## Requesting embeddings

> **Required for search tools.** Ingesting or syncing data does *not* make it searchable by itself.
> After every meaningful ingest (including Google Sheet sync), run **Initiate Embedding** (or enable
> **Auto-embed** on the group) and wait for status **Ready** **before** relying on project chat, workflows, or other LLM features that use search tools.
> New or updated rows stay invisible to semantic search until they are embedded.

Search tools need vector embeddings before semantic search returns results. Analytics and filter tools do not use embeddings for their SQL paths (see [analytics](analytics.md), [filter](filter.md)), but if the same groups also have search tools, those search tools still need embedding after each ingest.

- **Manual** — Settings → Tools → **Initiate Embedding** on the tool row, or Horizon → Data Embeddings.
- **Auto-embed on ingestion** — enable on the ingestion group; new/updated rows queue embedding after each ingest. Recommended for recurring Sheet/API syncs.
- **System embedding model** — superadmin sets `EMBEDDING_MODEL` under Settings → System. Changing model requires re-embedding all tools.

Recommended order for any significant LLM work: **ingest → approve (if needed) → embed → then chat / workflows / agents**.

## How you know embedding worked

| Status | Meaning |
| --- | --- |
| `none` | No embedding requested yet |
| `created` / Pending | Job queued |
| `processing` | Worker running |
| `finished` / Ready | Search tool can retrieve vectors for data embedded at that time |
| **Needs Re-embed** / stale | Data was ingested after the last embed — run Initiate Embedding again |
| `errored` | Check logs, model config, and that entries exist with search field populated |

Projects show a warning banner when ingestion is newer than the last embedding. Horizon → Data Embeddings also badges tools that need embedding. UI badges update on Tools and Data Embeddings pages (polling while the tab is visible). Verify in practice by asking a project chat a question only answerable from embedded content.

## Removing embeddings

Tools page → confirm dialog to remove embeddings for a tool (does not delete entries). Re-run Initiate Embedding to rebuild.

## Field collisions

Tools spanning multiple groups cannot use the same return field name for different semantics. Settings → Tools may warn about collisions when selecting multiple groups — resolve by aligning column slugs across groups or split tools.

## YUML formatted output

Enable **YUML emission** on a tool to render tool results as HTML in chat. See [yuml](yuml.md).
