Skip to content

feat: add OrcaRouter embedding provider - #683

Open
XiaoHuo888-hue wants to merge 1 commit into
zilliztech:mainfrom
XiaoHuo888-hue:feat/orcarouter-provider
Open

XiaoHuo888-hue wants to merge 1 commit into
zilliztech:mainfrom
XiaoHuo888-hue:feat/orcarouter-provider

Conversation

@XiaoHuo888-hue

Copy link
Copy Markdown

Add OrcaRouter embedding provider

This registers OrcaRouter as a named embedding provider in the provider registry, mirroring the existing openai provider. Instead of pointing the generic OpenAI provider at a custom base_url, users can set embedding.provider = "orcarouter" directly.

OrcaRouter is an OpenAI-compatible model routing gateway that brings 150+ models from OpenAI, Anthropic, Google, DeepSeek, Qwen, MiniMax and xAI behind a single endpoint and API key. Beyond routing, it runs gateway-level, zero-trust security for AI agents on the same endpoint — screening every prompt/response and governing every tool call on a default-deny basis, with no application code changes. This PR registers it as a named provider so users can opt in directly.

I'm an engineer on the OrcaRouter team.

Files changed

  • src/memsearch/embeddings/orcarouter.py (new) — OrcaRouterEmbedding, OpenAI-compatible, default base URL https://api.orcarouter.ai/v1, default model openai/text-embedding-3-small, key read from ORCAROUTER_API_KEY (override base URL via ORCAROUTER_BASE_URL).
  • src/memsearch/embeddings/__init__.py — registered orcarouter in _PROVIDERS, DEFAULT_MODELS, _INSTALL_HINTS, and in the base_url/api_key pass-through of get_provider().
  • src/memsearch/cli.py — config init now lists orcarouter with its default model.
  • tests/test_embeddings_orcarouter.py (new) — mirrors test_embeddings_openai.py (skipped without ORCAROUTER_API_KEY).
  • Docs: provider table in docs/home/configuration.md, config-init prompt output in docs/cli.md and docs/getting-started.md, README config example, and the provider list in CLAUDE.md.

Notes

  • OrcaRouter model IDs are namespaced (e.g. openai/text-embedding-3-small); bare IDs like text-embedding-3-small return 503 model_not_found, so the provider defaults to the namespaced form.
  • The openai SDK is already a base dependency, so no new extras are required.

Verification

  • ruff check and ruff format --check pass on all touched files.
  • tests/test_embeddings_orcarouter.py passes (5/5) against the live endpoint.
  • The config/CLI/embedding test subset shows no regressions; the only failures are pre-existing Windows/Milvus-Lite environment issues present on main as well.

Add a named `orcarouter` embedding provider registered in the provider
registry, mirroring the existing `openai` provider. OrcaRouter is an
OpenAI-compatible model routing gateway; model IDs are namespaced (e.g.
`openai/text-embedding-3-small`), and bare IDs return 503, so the provider
defaults to the namespaced model and the `https://api.orcarouter.ai/v1`
base URL. Config via `ORCAROUTER_API_KEY` / `ORCAROUTER_BASE_URL`.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: XiaoHuo888 <sjh00112233@outlook.com>
# Provider registry: name -> (module_path, class_name)
_PROVIDERS: dict[str, tuple[str, str]] = {
"openai": ("memsearch.embeddings.openai", "OpenAIEmbedding"),
"orcarouter": ("memsearch.embeddings.orcarouter", "OrcaRouterEmbedding"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/memsearch/embeddings/init.py line:27
Medium ---- Registering orcarouter here makes it a valid embedding.provider value, but the plugin session-start hooks that map a provider to its required API key were not updated: _required_env_var in plugins/claude-code/hooks/session-start.sh:58-66 and plugins/codex/hooks/session-start.sh:41-49 only maps openai/google/voyage/jina/mistral to their env vars and returns "" for everything else. With provider=orcarouter and ORCAROUTER_API_KEY unset, the hook reports a healthy status line instead of the "ERROR: ... not set - memory search disabled" warning it shows for the other key-based providers, so plugin users get a silent broken config. The previous provider addition (PR #346) updated these hooks; please add orcarouter) echo "ORCAROUTER_API_KEY" ;; to both here.

|----------|---------|---------|-------|
| **onnx** (default) | `pip install memsearch[onnx]` | No | Local, free, ~100MB model download |
| openai | `pip install memsearch[openai]` | `OPENAI_API_KEY` | Best quality |
| orcarouter | `pip install memsearch` | `ORCAROUTER_API_KEY` | OpenAI-compatible routing gateway |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs/home/configuration.md line:77
Medium ---- This row keeps the provider table current, but two other surfaces that enumerate every embedding provider were not updated: docs/home/comparison.md:37 still claims "(8: openai / google / voyage / jina / mistral / ollama / local / onnx)" (now 9 providers; the count and list are stale after this PR), and docs/python-api.md:45 omits orcarouter from the embedding_provider parameter description. PR #346 updated both of these files when jina/mistral were added; please extend them here as well so the docs stay consistent for users discovering the new provider.

orcarouter providers).
api_key:
Override the API key (currently only used by the openai provider).
Override the API key (currently only used by the openai and

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/memsearch/embeddings/init.py line:87
Low ---- This edited docstring claims the api_key override is "currently only used by the openai and orcarouter providers", but the same function also forwards api_key to the jina and mistral providers (elif name in ("jina", "mistral") and api_key: right below). Since these docstring lines are being touched anyway, consider correcting the claim (e.g. "used by the openai, orcarouter, jina and mistral providers") so the public docstring is accurate.

_DEFAULT_BASE_URL = "https://api.orcarouter.ai/v1"

# Known output dimensions for OrcaRouter-routable embedding models.
_KNOWN_DIMENSIONS: dict[str, int] = {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/memsearch/embeddings/orcarouter.py line:21
Low ---- This dimension table is a namespaced duplicate of the openai provider's _KNOWN_DIMENSIONS for the same underlying models, and it is already missing an entry the openai table has: openai/text-embedding-ada-002 (1536). Any model not in this 2-row table makes _detect_dimension fall through to a synchronous, blocking trial embed inside __init__, so every MemSearch() construction (index/search/watch) for such a model pays a live network round-trip just to resolve the dimension - and since OrcaRouter advertises 150+ models, this fallback is the common case rather than the exception. Consider completing the table (add openai/text-embedding-ada-002 and any other routable embedding models) or documenting the construction-time network dependency for custom models.


import pytest

pytestmark = pytest.mark.skipif(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests/test_embeddings_orcarouter.py line:11
Low ---- All five new tests are skipped whenever ORCAROUTER_API_KEY is unset, so in CI the new module executes zero tests. Two new code paths can be covered without any key or network: the missing-key RuntimeError raised in OrcaRouterEmbedding.__init__ (orcarouter-specific - openai relies on the SDK to raise instead) and the no-network dimension lookup for models already in _KNOWN_DIMENSIONS. Adding those offline unit tests would give the new provider guaranteed coverage independent of a live endpoint.

@github-actions

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Feel free to reopen if this is still relevant.

@github-actions github-actions Bot added the stale label Oct 21, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants