fix(embedding): normalize gateway base_url to the /v1 base path
EMBEDDING_GATEWAY_URL is configured as a bare origin (scheme://host:port) —
the deployment's Service URL. GatewayProvider now appends the gateway's /v1
base path before handing the URL to the OpenAI SDK, so both embed posts
({base}/embeddings) and dimension discovery ({base}/models) land under /v1.
Idempotent: a URL already ending in /v1 is left unchanged.
This lets EMBEDDING_GATEWAY_URL stay a bare domain (matching the gitops
Service URLs) instead of requiring a hand-appended /v1.
Also align the `embedding_gateway_model` field default with _DEFAULTS
("mistral/mistral-embed"). The gateway catalog is provider-namespaced, and
_detect_dimension matches `entry.id == embedding_model`; the stale
un-namespaced default would silently miss the catalog entry and leave the
dimension unresolved (re-triggering the external-mode startup crash).
Tests: bare / trailing-slash / idempotent normalization + a bare-origin
discovery test asserting /v1/models. 16 gateway-provider tests pass;
providers + vector suites green (129 total); ruff clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
2d191b4055
commit
4f170d32cb
@@ -289,3 +289,59 @@ async def test_detect_dimension_skips_when_already_known(monkeypatch):
|
||||
await provider._detect_dimension()
|
||||
assert called["n"] == 0
|
||||
assert provider.get_dimension() == 1024
|
||||
|
||||
|
||||
# --- /v1 base-path normalization --------------------------------------------
|
||||
# EMBEDDING_GATEWAY_URL is configured as a bare origin (scheme://host:port);
|
||||
# the provider appends the gateway's /v1 base path so both the OpenAI SDK's
|
||||
# embed posts ({base}/embeddings) and discovery ({base}/models) land under /v1.
|
||||
|
||||
|
||||
def _client_base(provider: GatewayProvider) -> str:
|
||||
return str(provider.client.base_url).rstrip("/")
|
||||
|
||||
|
||||
def test_bare_base_url_gets_v1_base_path():
|
||||
provider = GatewayProvider(
|
||||
base_url="http://gw:8083", embedding_model="mistral/mistral-embed"
|
||||
)
|
||||
assert _client_base(provider).endswith("/v1")
|
||||
|
||||
|
||||
def test_v1_base_url_is_idempotent():
|
||||
# A URL that already carries /v1 (e.g. legacy config) is not doubled.
|
||||
provider = GatewayProvider(
|
||||
base_url="http://gw:8083/v1", embedding_model="mistral/mistral-embed"
|
||||
)
|
||||
base = _client_base(provider)
|
||||
assert base.endswith("/v1")
|
||||
assert not base.endswith("/v1/v1")
|
||||
|
||||
|
||||
def test_trailing_slash_base_url_normalized():
|
||||
provider = GatewayProvider(
|
||||
base_url="http://gw:8083/", embedding_model="mistral/mistral-embed"
|
||||
)
|
||||
base = _client_base(provider)
|
||||
assert base.endswith("/v1")
|
||||
assert not base.endswith("/v1/v1")
|
||||
|
||||
|
||||
async def test_detect_dimension_with_bare_base_url_hits_v1_models(monkeypatch):
|
||||
"""End-to-end of the fix: a bare-origin base_url still resolves the
|
||||
dimension because discovery lands on /v1/models."""
|
||||
seen = {}
|
||||
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
seen["url"] = str(request.url)
|
||||
return httpx.Response(
|
||||
200, json={"data": [{"id": "mistral/mistral-embed", "dimension": 1024}]}
|
||||
)
|
||||
|
||||
_mock_async_client(monkeypatch, handler)
|
||||
provider = GatewayProvider(
|
||||
base_url="http://gw:8083", embedding_model="mistral/mistral-embed"
|
||||
)
|
||||
await provider._detect_dimension()
|
||||
assert provider.get_dimension() == 1024
|
||||
assert seen["url"].endswith("/v1/models")
|
||||
|
||||
Reference in New Issue
Block a user