|
|
@@ -13,7 +13,7 @@ import json
|
|
|
from collections.abc import Mapping
|
|
|
from hashlib import sha256
|
|
|
from pathlib import Path
|
|
|
-from typing import Any
|
|
|
+from typing import Any, Protocol
|
|
|
|
|
|
from script_build_host.adapters.retrieval import SafeHttpClient
|
|
|
from script_build_host.domain.errors import ProtocolViolation
|
|
|
@@ -31,8 +31,15 @@ _ATOM_KEY_TO_COLUMN = {
|
|
|
_COLUMN_TO_ATOM_KEY = {value: key for key, value in _ATOM_KEY_TO_COLUMN.items()}
|
|
|
|
|
|
|
|
|
-class LegacyOpenRouterClient:
|
|
|
- """Small credential-contained client for the two old OpenRouter calls."""
|
|
|
+class QueryEmbeddingClient(Protocol):
|
|
|
+ embedding_model: str
|
|
|
+ embedding_dimension: int
|
|
|
+
|
|
|
+ async def embed_one(self, text: str) -> list[float]: ...
|
|
|
+
|
|
|
+
|
|
|
+class OpenAICompatibleEmbeddingClient:
|
|
|
+ """Credential-contained client for an OpenAI-compatible embedding API."""
|
|
|
|
|
|
def __init__(
|
|
|
self,
|
|
|
@@ -40,7 +47,6 @@ class LegacyOpenRouterClient:
|
|
|
*,
|
|
|
api_key: str,
|
|
|
embedding_endpoint: str,
|
|
|
- chat_endpoint: str,
|
|
|
embedding_model: str,
|
|
|
embedding_dimension: int,
|
|
|
) -> None:
|
|
|
@@ -50,7 +56,6 @@ class LegacyOpenRouterClient:
|
|
|
"Content-Type": "application/json",
|
|
|
}
|
|
|
self.embedding_endpoint = embedding_endpoint
|
|
|
- self.chat_endpoint = chat_endpoint
|
|
|
self.embedding_model = embedding_model
|
|
|
self.embedding_dimension = embedding_dimension
|
|
|
|
|
|
@@ -76,6 +81,24 @@ class LegacyOpenRouterClient:
|
|
|
raise ProtocolViolation("embedding response contains a non-numeric value")
|
|
|
return [float(value) for value in vector]
|
|
|
|
|
|
+
|
|
|
+class LegacyOpenRouterClient:
|
|
|
+ """Credential-contained client for the legacy OpenRouter chat calls."""
|
|
|
+
|
|
|
+ def __init__(
|
|
|
+ self,
|
|
|
+ http: SafeHttpClient,
|
|
|
+ *,
|
|
|
+ api_key: str,
|
|
|
+ chat_endpoint: str,
|
|
|
+ ) -> None:
|
|
|
+ self._http = http
|
|
|
+ self._headers = {
|
|
|
+ "Authorization": f"Bearer {api_key}",
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ }
|
|
|
+ self.chat_endpoint = chat_endpoint
|
|
|
+
|
|
|
async def chat_json(
|
|
|
self,
|
|
|
*,
|
|
|
@@ -100,19 +123,19 @@ class LegacyOpenRouterClient:
|
|
|
|
|
|
|
|
|
class LegacyVectorDecodeRetrievalAdapter:
|
|
|
- """Local legacy vector index plus the legacy OpenRouter query embedding."""
|
|
|
+ """Local vector index plus a matching query-embedding provider."""
|
|
|
|
|
|
def __init__(
|
|
|
self,
|
|
|
*,
|
|
|
index_root: Path,
|
|
|
raw_root: Path,
|
|
|
- openrouter: LegacyOpenRouterClient | None,
|
|
|
+ embedding_client: QueryEmbeddingClient | None,
|
|
|
min_score: float = 0.7,
|
|
|
) -> None:
|
|
|
self.index_root = index_root.resolve()
|
|
|
self.raw_root = raw_root.resolve()
|
|
|
- self.openrouter = openrouter
|
|
|
+ self.embedding_client = embedding_client
|
|
|
self.min_score = min_score
|
|
|
self._loaded: tuple[list[dict[str, Any]], Any, dict[str, Any]] | None = None
|
|
|
self._load_lock = asyncio.Lock()
|
|
|
@@ -144,11 +167,15 @@ class LegacyVectorDecodeRetrievalAdapter:
|
|
|
if len(ranked) >= top_k:
|
|
|
break
|
|
|
else:
|
|
|
- if self.openrouter is None:
|
|
|
+ if self.embedding_client is None:
|
|
|
raise ProtocolViolation(
|
|
|
- "semantic decode search requires SCRIPT_BUILD_OPENROUTER_API_KEY"
|
|
|
+ "semantic decode search requires SCRIPT_BUILD_EMBEDDING_API_KEY"
|
|
|
)
|
|
|
- vector = await self.openrouter.embed_one(keyword)
|
|
|
+ if manifest.get("model") != self.embedding_client.embedding_model:
|
|
|
+ raise ProtocolViolation("query embedding model does not match the decode index")
|
|
|
+ if manifest.get("dimension") != self.embedding_client.embedding_dimension:
|
|
|
+ raise ProtocolViolation("query embedding dimension does not match the decode index")
|
|
|
+ vector = await self.embedding_client.embed_one(keyword)
|
|
|
ranked.extend(
|
|
|
await asyncio.to_thread(
|
|
|
_rank_decode_posts,
|
|
|
@@ -717,4 +744,5 @@ __all__ = [
|
|
|
"LegacyLlmKnowledgeRetrievalAdapter",
|
|
|
"LegacyOpenRouterClient",
|
|
|
"LegacyVectorDecodeRetrievalAdapter",
|
|
|
+ "OpenAICompatibleEmbeddingClient",
|
|
|
]
|