Skip to main content

Embedding Config Setup

Vector search runs on embedding_config rows you create via the API. V1 deliberately accepts a near-raw JSON object per provider - similar to how AWS IAM policies are raw JSON - rather than a form-driven UI. This doc lists the credentials/config shape each supported provider expects. Field meanings (what a model name means, what a base URL should point at) are documented by each provider's own API docs, linked below - this page only covers the shape Yew Search expects, not provider semantics.

See plans/advanced-search-vector-embeddings.md for the full design history and reasoning behind this feature.

Creating a config​

POST /v1/embedding-config
{
"provider": "openai",
"credentials": { "apiKey": "sk-..." },
"config": { "model": "text-embedding-3-small" }
}

On save, the config is validated by actually calling the provider (embedQuery("ok")). If that fails, the raw provider/SDK error is returned - there's no separate schema validation layer for V1. If it succeeds, dimension is auto-discovered from the returned vector (never supply it yourself), and an OpenSearch index is provisioned for this config automatically.

Provider shapes​

openai​

  • credentials.apiKey - required
  • config.model - optional, defaults to OpenAI's own default embedding model
  • config.baseUrl - optional, only needed for Azure OpenAI or an OpenAI-compatible self-hosted server (LM Studio, vLLM, text-embeddings-inference, LocalAI)

Docs: https://platform.openai.com/docs/guides/embeddings

ollama​

  • credentials - not needed, Ollama has no API key
  • config.baseUrl - required, e.g. http://localhost:11434 or http://ollama:11434 in a docker-compose network - there's no universal default since it always points at a specific instance
  • config.model - required, no default - depends entirely on what's pulled on that Ollama instance (e.g. nomic-embed-text, mxbai-embed-large)

Docs: https://ollama.com/blog/embedding-models

voyage​

What most people mean by "Anthropic embeddings" - Anthropic has no native embeddings API, and recommends Voyage AI as a third-party partner (Voyage is now owned by MongoDB, acquired Feb 2025 - unrelated to whether you use MongoDB anywhere else).

  • credentials.apiKey - required
  • config.model - required, no universal default (e.g. voyage-3, voyage-3-lite)
  • config.baseUrl - optional, defaults to Voyage's own API

Docs: https://docs.voyageai.com/docs/embeddings

google-genai​

  • credentials.apiKey - required
  • config.model - optional, has a default (e.g. text-embedding-004)

Docs: https://ai.google.dev/gemini-api/docs/embeddings

mistralai​

  • credentials.apiKey - required
  • config.model - required, no universal default (e.g. mistral-embed)

Docs: https://docs.mistral.ai/capabilities/embeddings/

An unknown provider is rejected with 400 before the validation call. There's no anthropic embeddings provider - Anthropic has no embeddings API and recommends Voyage, which is voyage here.

Deleting a config​

DELETE /v1/embedding-config/:id

Returns 204. Deleting a config also removes everything that only exists because of it:

  • its attachments to integrations (user_integration_embedding_config rows, including ones already detached), so those integrations stop being embedded with it
  • its OpenSearch index (embedding_chunks_<id>) and every vector in it

A search request that still passes its id in embeddingConfigIds fails (the search page reloads the config list each time it opens, so it won't). If dropping the index fails, the config is still deleted and the failure is logged, leaving an orphaned index to remove by hand.

Chunking​

Chunk size/overlap are measured in characters, not tokens - deliberately, so chunking never depends on a provider-specific tokenizer. config.chunkSize/config.chunkOverlap on the embedding_config itself set the default (falls back to 2000/200 if omitted); a user_integration_embedding_config attachment can override either per integration - see below. One generic chunker is used for every provider and content type - there's no per-content-type strategy; pick sizes appropriate to what you're attaching this config to (e.g. a larger chunk size for long-form FTP text vs. a smaller one for short emails).

Attaching a config to an integration​

Vector search selection happens at the integration level, not per content row. Attaching is its own full resource, user_integration_embedding_config, not a nested action on embedding_config - creating an attachment is a real record with its own id, not just a boolean flag:

POST /v1/user-integration-embedding-config
{
"userIntegrationId": "...",
"embeddingConfigId": "...",
"chunkSize": 1500,
"chunkOverlap": 150
}

chunkSize/chunkOverlap are optional overrides for this attachment only - omit them to use the embedding_config's own values. This is what lets one embedding_config (one provider, one API key) be reused across integrations with different chunking needs without duplicating credentials just to vary chunk size. Attach more than one config to the same integration (different providers, or the same provider with different chunk overrides) to compare them side by side.

Standard resource shape, same as everywhere else in this API:

  • GET /v1/user-integration-embedding-config - list, filterable by inUserIntegrationIds/ninUserIntegrationIds/inEmbeddingConfigIds/ninEmbeddingConfigIds
  • GET /v1/user-integration-embedding-config/:id - get one
  • PATCH /v1/user-integration-embedding-config/:id - update chunkSize/chunkOverlap only; userIntegrationId/embeddingConfigId aren't mutable, detach and re-attach instead
  • DELETE /v1/user-integration-embedding-config/:id - detach (soft delete). Existing embeddings for a detached config are left in place as inert leftovers, not cleaned up. Re-attaching the same (userIntegrationId, embeddingConfigId) pair after detaching is fine, the uniqueness constraint only applies to active attachments.

embedding_config rows themselves still cannot be deleted in V1 - only detached from an integration.

Re-indexing​

POST /v1/user-integration-embedding-config/reindex/:userIntegrationId reprocesses all of that integration's already-stored content against its currently attached configs - without re-crawling or re-fetching from the external source. Use this after attaching a new config to an integration that already has content, so existing content gets backfilled against it. This is synchronous for V1 and will block for the duration of a large integration's full re-embed.

Searching​

GET /v1/search accepts embeddingConfigIds (a list) alongside the existing inEngines/ninEngines. Any combination is valid: omit it for unchanged full-text/Postgres behavior, pass it with engines excluded for pure vector search, or combine both to merge BM25 and one or more vector searches together, ranked via magnitude-aware score fusion.