aid-runtime-python 0.1.39__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aid_runtime/__init__.py +500 -0
- aid_runtime/agents/__init__.py +94 -0
- aid_runtime/agents/chat_model.py +351 -0
- aid_runtime/agents/deep_agents.py +600 -0
- aid_runtime/agents/engine.py +102 -0
- aid_runtime/agents/guardrails.py +519 -0
- aid_runtime/agents/ir.py +622 -0
- aid_runtime/agents/loop.py +1308 -0
- aid_runtime/agents/memory.py +241 -0
- aid_runtime/agents/policy.py +163 -0
- aid_runtime/agents/state.py +182 -0
- aid_runtime/cache.py +185 -0
- aid_runtime/concurrency.py +70 -0
- aid_runtime/control.py +329 -0
- aid_runtime/cost.py +168 -0
- aid_runtime/errors.py +337 -0
- aid_runtime/evals/__init__.py +72 -0
- aid_runtime/evals/dataset.py +77 -0
- aid_runtime/evals/gate.py +430 -0
- aid_runtime/evals/metrics.py +335 -0
- aid_runtime/evals/predicate.py +211 -0
- aid_runtime/evals/runner.py +224 -0
- aid_runtime/gateway.py +473 -0
- aid_runtime/pipeline.py +168 -0
- aid_runtime/prompts.py +185 -0
- aid_runtime/providers/__init__.py +20 -0
- aid_runtime/providers/base.py +57 -0
- aid_runtime/providers/fake.py +256 -0
- aid_runtime/providers/http.py +344 -0
- aid_runtime/py.typed +0 -0
- aid_runtime/retrieval/__init__.py +178 -0
- aid_runtime/retrieval/chunking.py +222 -0
- aid_runtime/retrieval/citations.py +131 -0
- aid_runtime/retrieval/connectors.py +131 -0
- aid_runtime/retrieval/embedding.py +293 -0
- aid_runtime/retrieval/gate.py +120 -0
- aid_runtime/retrieval/hybrid.py +164 -0
- aid_runtime/retrieval/metrics.py +213 -0
- aid_runtime/retrieval/pgvector.py +258 -0
- aid_runtime/retrieval/rerank.py +133 -0
- aid_runtime/retrieval/retriever.py +335 -0
- aid_runtime/retrieval/stores.py +161 -0
- aid_runtime/retrieval/types.py +433 -0
- aid_runtime/steps.py +284 -0
- aid_runtime/structured.py +150 -0
- aid_runtime/tools.py +271 -0
- aid_runtime/tracing.py +241 -0
- aid_runtime/types.py +332 -0
- aid_runtime_python-0.1.39.dist-info/METADATA +268 -0
- aid_runtime_python-0.1.39.dist-info/RECORD +52 -0
- aid_runtime_python-0.1.39.dist-info/WHEEL +5 -0
- aid_runtime_python-0.1.39.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
"""Shapes the retrieval runtime shares across its modules.
|
|
2
|
+
|
|
3
|
+
Two families live here and the split is deliberate.
|
|
4
|
+
|
|
5
|
+
* The **IR mirror** models (``SourceSpec``, ``ChunkingSpec``, ``IndexSpec``,
|
|
6
|
+
``RerankSpec``, ``RefreshSpec``, ``RetrieverSpec``, ``EmbeddingSpec``,
|
|
7
|
+
``VectorStoreSpec``) reproduce the L1 IR's ``retrievers`` / ``embeddings`` /
|
|
8
|
+
``stores`` entries field for field. Field names are Pythonic; the IR's
|
|
9
|
+
camelCase spelling is carried as a pydantic *alias*, so an IR fragment
|
|
10
|
+
validates against these models unchanged and the two vocabularies cannot drift
|
|
11
|
+
without a test going red. Enum *values* are the IR's own strings
|
|
12
|
+
(``recursive``, ``pgvector``, ``cosine``) and are never re-spelled.
|
|
13
|
+
* The **resolved** models (``PinnedEmbedding``, ``RetrieverBinding``) are what
|
|
14
|
+
generated code binds with literals. They carry the exact embedding model id
|
|
15
|
+
rather than an alias, so a run is reproducible from the generated source alone
|
|
16
|
+
and nothing is resolved at run time.
|
|
17
|
+
* The **store records** (``StoreRecord``, ``SearchHit``) are the payloads the store
|
|
18
|
+
adapters read and write. They live here rather than in ``stores`` so the pgvector
|
|
19
|
+
adapter can build them without importing ``stores``, which imports ``pgvector``
|
|
20
|
+
back lazily; the module graph then has no cycle.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import hashlib
|
|
26
|
+
from enum import StrEnum
|
|
27
|
+
from typing import Any, Literal
|
|
28
|
+
|
|
29
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
30
|
+
|
|
31
|
+
from aid_runtime.errors import ConfigurationError, FeatureDeferredError
|
|
32
|
+
from aid_runtime.types import CostProfile
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"Chunk",
|
|
36
|
+
"ChunkingSpec",
|
|
37
|
+
"ChunkingStrategy",
|
|
38
|
+
"DistanceMetric",
|
|
39
|
+
"EmbeddingCostProfile",
|
|
40
|
+
"EmbeddingSpec",
|
|
41
|
+
"IndexSpec",
|
|
42
|
+
"PinnedEmbedding",
|
|
43
|
+
"RefreshMode",
|
|
44
|
+
"RefreshSpec",
|
|
45
|
+
"RerankSpec",
|
|
46
|
+
"RetrievalMetricSpec",
|
|
47
|
+
"RetrieverBinding",
|
|
48
|
+
"RetrieverSpec",
|
|
49
|
+
"ScoredChunk",
|
|
50
|
+
"SearchHit",
|
|
51
|
+
"SourceKind",
|
|
52
|
+
"SourceSpec",
|
|
53
|
+
"StoreKind",
|
|
54
|
+
"StoreRecord",
|
|
55
|
+
"VectorStoreSpec",
|
|
56
|
+
"binding_from_spec",
|
|
57
|
+
"chunk_id_for",
|
|
58
|
+
"pinned_embedding",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
#: The IR spells several fields in camelCase. Accepting both spellings is what
|
|
62
|
+
#: lets one model validate an IR fragment *and* be built from generated Python.
|
|
63
|
+
_IR_RECORD = ConfigDict(frozen=True, extra="forbid", populate_by_name=True)
|
|
64
|
+
|
|
65
|
+
#: The runtime's own records are constructed by us, never parsed from IR JSON,
|
|
66
|
+
#: so they need no aliases and refuse anything unexpected.
|
|
67
|
+
_RUNTIME_RECORD = ConfigDict(frozen=True, extra="forbid")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class DistanceMetric(StrEnum):
|
|
71
|
+
"""``retriever.index.metric``."""
|
|
72
|
+
|
|
73
|
+
COSINE = "cosine"
|
|
74
|
+
DOT = "dot"
|
|
75
|
+
L2 = "l2"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class SourceKind(StrEnum):
|
|
79
|
+
"""``retriever.source.kind``.
|
|
80
|
+
|
|
81
|
+
``FILE`` is the only kind the Phase 1 connector implements; the rest are part
|
|
82
|
+
of the IR contract and fail loudly rather than silently indexing nothing.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
FILE = "file"
|
|
86
|
+
S3 = "s3"
|
|
87
|
+
HTTP = "http"
|
|
88
|
+
DB = "db"
|
|
89
|
+
MCP = "mcp"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class ChunkingStrategy(StrEnum):
|
|
93
|
+
"""``retriever.chunking.strategy``."""
|
|
94
|
+
|
|
95
|
+
FIXED = "fixed"
|
|
96
|
+
RECURSIVE = "recursive"
|
|
97
|
+
SEMANTIC = "semantic"
|
|
98
|
+
CODE = "code"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class StoreKind(StrEnum):
|
|
102
|
+
"""``vectorStore.kind``."""
|
|
103
|
+
|
|
104
|
+
MEMORY = "memory"
|
|
105
|
+
PGVECTOR = "pgvector"
|
|
106
|
+
QDRANT = "qdrant"
|
|
107
|
+
PINECONE = "pinecone"
|
|
108
|
+
WEAVIATE = "weaviate"
|
|
109
|
+
CUSTOM = "custom"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class RefreshMode(StrEnum):
|
|
113
|
+
"""``retriever.refresh.mode``. Only ``FULL`` is implemented."""
|
|
114
|
+
|
|
115
|
+
FULL = "full"
|
|
116
|
+
INCREMENTAL = "incremental"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class SourceSpec(BaseModel):
|
|
120
|
+
"""``retriever.source``."""
|
|
121
|
+
|
|
122
|
+
model_config = _IR_RECORD
|
|
123
|
+
|
|
124
|
+
kind: SourceKind
|
|
125
|
+
uri: str
|
|
126
|
+
glob: str | None = None
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class ChunkingSpec(BaseModel):
|
|
130
|
+
"""``retriever.chunking``."""
|
|
131
|
+
|
|
132
|
+
model_config = _IR_RECORD
|
|
133
|
+
|
|
134
|
+
strategy: ChunkingStrategy
|
|
135
|
+
size: int = Field(gt=0)
|
|
136
|
+
overlap: int = Field(ge=0)
|
|
137
|
+
keep_metadata: tuple[str, ...] = Field(alias="keepMetadata")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class IndexSpec(BaseModel):
|
|
141
|
+
"""``retriever.index``."""
|
|
142
|
+
|
|
143
|
+
model_config = _IR_RECORD
|
|
144
|
+
|
|
145
|
+
metric: DistanceMetric
|
|
146
|
+
hybrid: bool
|
|
147
|
+
params: dict[str, Any] | None = None
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class RerankSpec(BaseModel):
|
|
151
|
+
"""``retriever.rerank``."""
|
|
152
|
+
|
|
153
|
+
model_config = _IR_RECORD
|
|
154
|
+
|
|
155
|
+
model: str
|
|
156
|
+
top_n: int = Field(gt=0, alias="topN")
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class RefreshSpec(BaseModel):
|
|
160
|
+
"""``retriever.refresh``."""
|
|
161
|
+
|
|
162
|
+
model_config = _IR_RECORD
|
|
163
|
+
|
|
164
|
+
mode: RefreshMode
|
|
165
|
+
schedule: str | None = None
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class RetrieverSpec(BaseModel):
|
|
169
|
+
"""One entry of the IR's ``retrievers`` map."""
|
|
170
|
+
|
|
171
|
+
model_config = _IR_RECORD
|
|
172
|
+
|
|
173
|
+
id: str = Field(min_length=1)
|
|
174
|
+
source: SourceSpec
|
|
175
|
+
chunking: ChunkingSpec
|
|
176
|
+
embed_model: str = Field(alias="embedModel")
|
|
177
|
+
store: str
|
|
178
|
+
index: IndexSpec
|
|
179
|
+
top_k: int = Field(gt=0, alias="topK")
|
|
180
|
+
rerank: RerankSpec | None = None
|
|
181
|
+
filters: tuple[str, ...] | None = None
|
|
182
|
+
refresh: RefreshSpec
|
|
183
|
+
traits: tuple[str, ...]
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class EmbeddingCostProfile(BaseModel):
|
|
187
|
+
"""``embedding.costProfile`` -- USD per **million** tokens.
|
|
188
|
+
|
|
189
|
+
Not interchangeable with :class:`~aid_runtime.types.CostProfile`, which prices
|
|
190
|
+
per *thousand* tokens because it predates the IR. :func:`pinned_embedding` is
|
|
191
|
+
the single place the two are converted, so the factor of 1000 is stated once
|
|
192
|
+
rather than assumed at every call site.
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
model_config = _IR_RECORD
|
|
196
|
+
|
|
197
|
+
input_per_mtok: float = Field(ge=0.0, alias="inputPerMTok")
|
|
198
|
+
output_per_mtok: float = Field(ge=0.0, alias="outputPerMTok")
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class EmbeddingSpec(BaseModel):
|
|
202
|
+
"""One entry of the IR's ``embeddings`` map.
|
|
203
|
+
|
|
204
|
+
``id`` is the *alias* a retriever's ``embedModel`` names -- the resolution the
|
|
205
|
+
runtime must never repeat at run time.
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
model_config = _IR_RECORD
|
|
209
|
+
|
|
210
|
+
id: str = Field(min_length=1)
|
|
211
|
+
provider: str
|
|
212
|
+
model_id: str = Field(alias="modelId")
|
|
213
|
+
dimensions: int | None = Field(default=None, gt=0)
|
|
214
|
+
cost_profile: EmbeddingCostProfile | None = Field(default=None, alias="costProfile")
|
|
215
|
+
traits: tuple[str, ...]
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class VectorStoreSpec(BaseModel):
|
|
219
|
+
"""One entry of the IR's ``stores`` map."""
|
|
220
|
+
|
|
221
|
+
model_config = _IR_RECORD
|
|
222
|
+
|
|
223
|
+
id: str = Field(min_length=1)
|
|
224
|
+
kind: StoreKind
|
|
225
|
+
uri: str | None = None
|
|
226
|
+
dimensions: int | None = Field(default=None, gt=0)
|
|
227
|
+
traits: tuple[str, ...]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class RetrievalMetricSpec(BaseModel):
|
|
231
|
+
"""The IR's ``retrieval`` metric variant: ``{kind, expectDocs, k}``."""
|
|
232
|
+
|
|
233
|
+
model_config = _IR_RECORD
|
|
234
|
+
|
|
235
|
+
kind: Literal["retrieval"] = "retrieval"
|
|
236
|
+
expect_docs: tuple[str, ...] = Field(alias="expectDocs")
|
|
237
|
+
k: int = Field(gt=0)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class PinnedEmbedding(BaseModel):
|
|
241
|
+
"""An ``embedModel`` alias already resolved to an exact embedding model.
|
|
242
|
+
|
|
243
|
+
The same contract as :class:`~aid_runtime.types.PinnedModel`: a baseline
|
|
244
|
+
recorded against ``text-embedding-3-small`` means nothing if the alias floats
|
|
245
|
+
to another revision, so the resolved id, the dimensions and the price are all
|
|
246
|
+
*recorded inputs* rather than lookups a run performs.
|
|
247
|
+
"""
|
|
248
|
+
|
|
249
|
+
model_config = _RUNTIME_RECORD
|
|
250
|
+
|
|
251
|
+
alias: str = Field(min_length=1)
|
|
252
|
+
provider: str = Field(min_length=1)
|
|
253
|
+
model_id: str = Field(min_length=1)
|
|
254
|
+
dimensions: int = Field(gt=0)
|
|
255
|
+
cost: CostProfile
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class RetrieverBinding(BaseModel):
|
|
259
|
+
"""A retriever as generated code binds it, with every alias resolved.
|
|
260
|
+
|
|
261
|
+
``embed_model`` keeps the declared alias purely so cost can be attributed to
|
|
262
|
+
the name the spec used; ``embedding`` is the resolved model actually called.
|
|
263
|
+
``store_kind`` is resolved from the store entry, because a run must not
|
|
264
|
+
discover at search time which backend it wrote to.
|
|
265
|
+
|
|
266
|
+
``store_uri`` is deliberately kept *unresolved*: a hosted store's location is a
|
|
267
|
+
deployment secret, which is why the IR writes ``env:PGVECTOR_URL`` rather than a
|
|
268
|
+
DSN. The name is pinned in code; the value is read from the environment at run
|
|
269
|
+
time, and an environment variable is not an alias.
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
model_config = _RUNTIME_RECORD
|
|
273
|
+
|
|
274
|
+
retriever_id: str = Field(min_length=1)
|
|
275
|
+
source: SourceSpec
|
|
276
|
+
chunking: ChunkingSpec
|
|
277
|
+
embed_model: str = Field(min_length=1)
|
|
278
|
+
embedding: PinnedEmbedding
|
|
279
|
+
store: str = Field(min_length=1)
|
|
280
|
+
store_kind: StoreKind
|
|
281
|
+
store_uri: str | None = None
|
|
282
|
+
index: IndexSpec
|
|
283
|
+
top_k: int = Field(gt=0)
|
|
284
|
+
rerank: RerankSpec | None = None
|
|
285
|
+
refresh_mode: RefreshMode = RefreshMode.FULL
|
|
286
|
+
traits: tuple[str, ...] = ()
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class Chunk(BaseModel):
|
|
290
|
+
"""One indexed passage.
|
|
291
|
+
|
|
292
|
+
``chunk_id`` hashes the document id, the chunk's position *and* its text.
|
|
293
|
+
That is what makes ingest idempotent: identical input re-chunks to identical
|
|
294
|
+
ids, so a second ingest replaces rather than duplicates. Position is part of
|
|
295
|
+
the hash on purpose -- two byte-identical paragraphs in one document must stay
|
|
296
|
+
two chunks instead of colliding into one.
|
|
297
|
+
"""
|
|
298
|
+
|
|
299
|
+
model_config = _RUNTIME_RECORD
|
|
300
|
+
|
|
301
|
+
chunk_id: str = Field(min_length=1)
|
|
302
|
+
doc_id: str = Field(min_length=1)
|
|
303
|
+
uri: str = ""
|
|
304
|
+
index: int = Field(ge=0)
|
|
305
|
+
start: int = Field(ge=0)
|
|
306
|
+
end: int = Field(ge=0)
|
|
307
|
+
text: str
|
|
308
|
+
metadata: dict[str, str] = Field(default_factory=dict)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
class StoreRecord(BaseModel):
|
|
312
|
+
"""One chunk and its vector, exactly as it is written to a store."""
|
|
313
|
+
|
|
314
|
+
model_config = _RUNTIME_RECORD
|
|
315
|
+
|
|
316
|
+
chunk: Chunk
|
|
317
|
+
vector: tuple[float, ...]
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
class SearchHit(BaseModel):
|
|
321
|
+
"""A record and its similarity to the query, higher being better."""
|
|
322
|
+
|
|
323
|
+
model_config = _RUNTIME_RECORD
|
|
324
|
+
|
|
325
|
+
record: StoreRecord
|
|
326
|
+
score: float
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class ScoredChunk(BaseModel):
|
|
330
|
+
"""A chunk with the score that ranked it."""
|
|
331
|
+
|
|
332
|
+
model_config = _RUNTIME_RECORD
|
|
333
|
+
|
|
334
|
+
chunk: Chunk
|
|
335
|
+
score: float
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def chunk_id_for(doc_id: str, index: int, text: str) -> str:
|
|
339
|
+
"""The content hash that identifies a chunk.
|
|
340
|
+
|
|
341
|
+
Shared by every chunker so the id scheme cannot differ between strategies; a
|
|
342
|
+
strategy that changed the id scheme would silently duplicate a corpus on
|
|
343
|
+
re-ingest instead of replacing it.
|
|
344
|
+
"""
|
|
345
|
+
digest = hashlib.sha256()
|
|
346
|
+
for part in (doc_id, str(index), text):
|
|
347
|
+
digest.update(part.encode("utf-8"))
|
|
348
|
+
digest.update(b"\x00")
|
|
349
|
+
return f"sha256:{digest.hexdigest()}"
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def pinned_embedding(
|
|
353
|
+
spec: EmbeddingSpec, *, alias: str, dimensions: int | None = None
|
|
354
|
+
) -> PinnedEmbedding:
|
|
355
|
+
"""Resolve an IR embedding entry into the pinned form generated code carries.
|
|
356
|
+
|
|
357
|
+
``dimensions`` may be supplied when the IR entry omits it (the schema makes it
|
|
358
|
+
optional); it is an error to have neither, because an unpinned width would let
|
|
359
|
+
a store accept vectors a later run cannot compare against.
|
|
360
|
+
"""
|
|
361
|
+
width = dimensions if dimensions is not None else spec.dimensions
|
|
362
|
+
if width is None:
|
|
363
|
+
raise ConfigurationError(
|
|
364
|
+
f"embedding {spec.id!r} pins no dimensions and none were supplied; the vector "
|
|
365
|
+
"width must be recorded with the pinned model so stores stay comparable"
|
|
366
|
+
)
|
|
367
|
+
profile = spec.cost_profile
|
|
368
|
+
# costProfile quotes USD per MTok; CostProfile quotes USD per 1k tokens.
|
|
369
|
+
scale = 1_000.0
|
|
370
|
+
return PinnedEmbedding(
|
|
371
|
+
alias=alias,
|
|
372
|
+
provider=spec.provider,
|
|
373
|
+
model_id=spec.model_id,
|
|
374
|
+
dimensions=width,
|
|
375
|
+
cost=CostProfile(
|
|
376
|
+
input_per_1k_usd=(profile.input_per_mtok / scale) if profile else 0.0,
|
|
377
|
+
output_per_1k_usd=(profile.output_per_mtok / scale) if profile else 0.0,
|
|
378
|
+
),
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def binding_from_spec(
|
|
383
|
+
spec: RetrieverSpec,
|
|
384
|
+
*,
|
|
385
|
+
embedding: EmbeddingSpec,
|
|
386
|
+
store: VectorStoreSpec,
|
|
387
|
+
dimensions: int | None = None,
|
|
388
|
+
) -> RetrieverBinding:
|
|
389
|
+
"""Bind one IR retriever entry to the embedding and store it names.
|
|
390
|
+
|
|
391
|
+
``embedModel`` names an *embeddings entry id*, not a provider model, and
|
|
392
|
+
``store`` names a *stores entry id*. Both are checked here rather than
|
|
393
|
+
trusted, because a mistyped reference in generated code would otherwise
|
|
394
|
+
surface as an empty or mis-scored corpus far from its cause.
|
|
395
|
+
"""
|
|
396
|
+
if spec.embed_model != embedding.id:
|
|
397
|
+
raise ConfigurationError(
|
|
398
|
+
f"retriever {spec.id!r} names embedModel {spec.embed_model!r} but embedding "
|
|
399
|
+
f"{embedding.id!r} was supplied"
|
|
400
|
+
)
|
|
401
|
+
if spec.store != store.id:
|
|
402
|
+
raise ConfigurationError(
|
|
403
|
+
f"retriever {spec.id!r} names store {spec.store!r} but store {store.id!r} was supplied"
|
|
404
|
+
)
|
|
405
|
+
if spec.filters:
|
|
406
|
+
# The spec validator already refuses filters; the runtime checks too,
|
|
407
|
+
# because generated code is reachable without the validator having run.
|
|
408
|
+
raise FeatureDeferredError(
|
|
409
|
+
f"retriever {spec.id!r} declares filters, which spec v0.1 does not implement: a "
|
|
410
|
+
"filter would have to be pushed into every store adapter's query"
|
|
411
|
+
)
|
|
412
|
+
pinned = pinned_embedding(embedding, alias=spec.embed_model, dimensions=dimensions)
|
|
413
|
+
if store.dimensions is not None and store.dimensions != pinned.dimensions:
|
|
414
|
+
raise ConfigurationError(
|
|
415
|
+
f"store {store.id!r} is declared {store.dimensions}-dimensional but retriever "
|
|
416
|
+
f"{spec.id!r} pins {pinned.dimensions} dimensions via embedModel "
|
|
417
|
+
f"{spec.embed_model!r}; the two must agree before anything is indexed"
|
|
418
|
+
)
|
|
419
|
+
return RetrieverBinding(
|
|
420
|
+
retriever_id=spec.id,
|
|
421
|
+
source=spec.source,
|
|
422
|
+
chunking=spec.chunking,
|
|
423
|
+
embed_model=spec.embed_model,
|
|
424
|
+
embedding=pinned,
|
|
425
|
+
store=spec.store,
|
|
426
|
+
store_kind=store.kind,
|
|
427
|
+
store_uri=store.uri,
|
|
428
|
+
index=spec.index,
|
|
429
|
+
top_k=spec.top_k,
|
|
430
|
+
rerank=spec.rerank,
|
|
431
|
+
refresh_mode=spec.refresh.mode,
|
|
432
|
+
traits=spec.traits,
|
|
433
|
+
)
|