Files
Jiangzhou 9700655aa6 refactor(embedder-params): drop dimensions knob; pass indexing kwargs into LiteLLM ctor (#151)
- Remove `dimensions` from the litellm whitelist in `_ACCEPTED_KWARGS`.
  Output dimension must be identical for indexing and query for vectors to
  be comparable, so it's a model-wide setting, not a per-side knob —
  exposing it under `indexing_params` / `query_params` invited
  misconfiguration. Updated comment template, README, design doc, and
  testing plan accordingly.
- Plumb `indexing_params` into `create_embedder` and pass them as
  constructor kwargs to `PacedLiteLLMEmbedder`. The values land in
  `self._kwargs` and become defaults forwarded into every
  `litellm.aembedding` call — including paths that don't go through the
  `INDEXING_EMBED_PARAMS` context var (e.g. the dim probe in `_get_dim`).
  Per-call overrides (`query_params` spread at query time) still win
  because `_embed` overlays kwargs on top of `self._kwargs`. Sentence-
  transformers ignores `indexing_params` (its constructor doesn't accept
  arbitrary kwargs; `prompt_name` is per-call only).
2026-04-25 09:33:24 -07:00

127 lines
4.3 KiB
Python

"""Tests for validate_params and resolve_embedder_params."""
from __future__ import annotations
import pytest
from cocoindex_code.embedder_params import (
EmbedderParams,
resolve_embedder_params,
validate_params,
)
from cocoindex_code.settings import EmbeddingSettings
def test_validate_params_accepts_known_keys() -> None:
validate_params("sentence-transformers", {}, {"prompt_name": "query"})
validate_params("litellm", {"input_type": "passage"}, {"input_type": "query"})
def test_validate_params_rejects_dimensions() -> None:
"""`dimensions` is a model-wide setting, not a per-side knob — must be rejected."""
with pytest.raises(ValueError, match="dimensions"):
validate_params("litellm", {"dimensions": 512}, {})
def test_validate_params_rejects_unknown_key() -> None:
with pytest.raises(ValueError, match="input_type"):
validate_params("sentence-transformers", {"input_type": "passage"}, {})
def test_validate_params_rejects_excluded_normalize_embeddings() -> None:
with pytest.raises(ValueError, match="normalize_embeddings"):
validate_params("sentence-transformers", {"normalize_embeddings": False}, {})
def test_validate_params_rejects_excluded_encoding_format() -> None:
with pytest.raises(ValueError, match="encoding_format"):
validate_params("litellm", {"encoding_format": "base64"}, {})
def test_validate_params_rejects_unknown_provider() -> None:
with pytest.raises(ValueError, match="Unknown provider"):
validate_params("nonsense", {}, {})
def test_resolve_embedder_params_user_set_verbatim() -> None:
settings = EmbeddingSettings(
provider="litellm",
model="cohere/embed-english-v3.0",
indexing_params={"input_type": "search_document"},
query_params={"input_type": "search_query"},
)
assert resolve_embedder_params(settings) == EmbedderParams(
indexing={"input_type": "search_document"},
query={"input_type": "search_query"},
used_backward_compat=False,
)
def test_resolve_embedder_params_empty_query_suppresses_legacy_bridge() -> None:
settings = EmbeddingSettings(
provider="sentence-transformers",
model="nomic-ai/CodeRankEmbed",
indexing_params=None,
query_params={},
)
assert resolve_embedder_params(settings) == EmbedderParams(
indexing={}, query={}, used_backward_compat=False
)
def test_resolve_embedder_params_empty_indexing_suppresses_legacy_bridge() -> None:
settings = EmbeddingSettings(
provider="sentence-transformers",
model="nomic-ai/CodeRankEmbed",
indexing_params={},
query_params=None,
)
# indexing_params set but query_params None — should still NOT fire the
# legacy bridge because the user has expressed intent.
assert resolve_embedder_params(settings) == EmbedderParams(
indexing={}, query={}, used_backward_compat=False
)
def test_resolve_embedder_params_legacy_bridge_fires() -> None:
settings = EmbeddingSettings(
provider="sentence-transformers",
model="nomic-ai/CodeRankEmbed",
)
assert resolve_embedder_params(settings) == EmbedderParams(
indexing={},
query={"prompt_name": "query"},
used_backward_compat=True,
)
def test_resolve_embedder_params_legacy_bridge_only_for_legacy_models() -> None:
settings = EmbeddingSettings(
provider="sentence-transformers",
model="nomic-ai/nomic-embed-text-v1.5", # not in LEGACY_QUERY_PROMPT_MODELS
)
assert resolve_embedder_params(settings) == EmbedderParams(
indexing={}, query={}, used_backward_compat=False
)
def test_resolve_embedder_params_no_match_returns_empty() -> None:
settings = EmbeddingSettings(
provider="litellm",
model="openai/text-embedding-3-small",
)
assert resolve_embedder_params(settings) == EmbedderParams(
indexing={}, query={}, used_backward_compat=False
)
def test_resolve_embedder_params_rejects_invalid_user_config() -> None:
settings = EmbeddingSettings(
provider="sentence-transformers",
model="anything",
indexing_params={"prompt_name": "x"},
query_params={"input_type": "y"}, # invalid for sentence-transformers
)
with pytest.raises(ValueError):
resolve_embedder_params(settings)