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,344 @@
|
|
|
1
|
+
"""A single OpenAI-compatible HTTP provider adapter.
|
|
2
|
+
|
|
3
|
+
One adapter, deliberately. Anthropic, Azure, Bedrock and friends all speak
|
|
4
|
+
slightly different dialects, and the framework's value is the IR seam and the
|
|
5
|
+
eval gate, not the breadth of vendor plumbing. Anything OpenAI-compatible --
|
|
6
|
+
vLLM, Ollama's compatibility endpoint, LiteLLM, OpenAI itself -- works through
|
|
7
|
+
this one class via ``base_url``.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import asyncio
|
|
13
|
+
import json
|
|
14
|
+
from collections.abc import AsyncIterator
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
import httpx
|
|
18
|
+
|
|
19
|
+
from aid_runtime.errors import ProviderError, ProviderResponseError
|
|
20
|
+
from aid_runtime.types import (
|
|
21
|
+
Capability,
|
|
22
|
+
CompletionRequest,
|
|
23
|
+
CompletionResponse,
|
|
24
|
+
FinishReason,
|
|
25
|
+
Message,
|
|
26
|
+
ModelSpec,
|
|
27
|
+
StreamChunk,
|
|
28
|
+
TokenUsage,
|
|
29
|
+
ToolCall,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
__all__ = ["OpenAICompatibleProvider"]
|
|
33
|
+
|
|
34
|
+
DEFAULT_BASE_URL = "https://api.openai.com/v1"
|
|
35
|
+
|
|
36
|
+
# 429 and 5xx are the retryable classes: the request was well-formed but the
|
|
37
|
+
# endpoint declined for a reason that may not repeat.
|
|
38
|
+
_RETRYABLE_STATUS = frozenset({408, 409, 425, 429, 500, 502, 503, 504})
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class OpenAICompatibleProvider:
|
|
42
|
+
"""Calls ``POST {base_url}/chat/completions`` and maps the response back."""
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
*,
|
|
47
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
48
|
+
api_key: str | None = None,
|
|
49
|
+
name: str = "openai-compatible",
|
|
50
|
+
timeout_seconds: float = 60.0,
|
|
51
|
+
max_attempts: int = 3,
|
|
52
|
+
backoff_seconds: float = 0.5,
|
|
53
|
+
client: httpx.AsyncClient | None = None,
|
|
54
|
+
extra_headers: dict[str, str] | None = None,
|
|
55
|
+
) -> None:
|
|
56
|
+
if not base_url.startswith(("http://", "https://")):
|
|
57
|
+
raise ValueError(f"base_url must be an absolute http(s) URL, got {base_url!r}")
|
|
58
|
+
if max_attempts < 1:
|
|
59
|
+
raise ValueError("max_attempts must be at least 1")
|
|
60
|
+
self._name = name
|
|
61
|
+
self._base_url = base_url.rstrip("/")
|
|
62
|
+
self._api_key = api_key
|
|
63
|
+
self._timeout = timeout_seconds
|
|
64
|
+
self._max_attempts = max_attempts
|
|
65
|
+
self._backoff = backoff_seconds
|
|
66
|
+
self._extra_headers = dict(extra_headers or {})
|
|
67
|
+
self._owns_client = client is None
|
|
68
|
+
self._client = client or httpx.AsyncClient(timeout=timeout_seconds)
|
|
69
|
+
self._closed = False
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def name(self) -> str:
|
|
73
|
+
return self._name
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def capabilities(self) -> frozenset[Capability]:
|
|
77
|
+
return frozenset(
|
|
78
|
+
{
|
|
79
|
+
Capability.TOOL_CALLING,
|
|
80
|
+
Capability.STRUCTURED_OUTPUT,
|
|
81
|
+
Capability.STREAMING,
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
async def complete(self, request: CompletionRequest, *, model: ModelSpec) -> CompletionResponse:
|
|
86
|
+
payload = self._build_payload(request, model)
|
|
87
|
+
body = await self._post("/chat/completions", payload)
|
|
88
|
+
return self._parse(body, model)
|
|
89
|
+
|
|
90
|
+
async def stream(
|
|
91
|
+
self, request: CompletionRequest, *, model: ModelSpec
|
|
92
|
+
) -> AsyncIterator[StreamChunk]:
|
|
93
|
+
"""Stream one call as OpenAI-style SSE, yielding one chunk per delta.
|
|
94
|
+
|
|
95
|
+
Streaming is a single attempt, not the retry loop ``complete`` uses: a
|
|
96
|
+
stream that has already emitted a token cannot be safely replayed, so a
|
|
97
|
+
transport or status error is raised once rather than retried mid-stream.
|
|
98
|
+
"""
|
|
99
|
+
payload = self._build_payload(request, model)
|
|
100
|
+
payload["stream"] = True
|
|
101
|
+
payload["stream_options"] = {"include_usage": True}
|
|
102
|
+
url = f"{self._base_url}/chat/completions"
|
|
103
|
+
try:
|
|
104
|
+
async with self._client.stream(
|
|
105
|
+
"POST", url, json=payload, headers=self._headers()
|
|
106
|
+
) as response:
|
|
107
|
+
if response.status_code >= 400:
|
|
108
|
+
await response.aread()
|
|
109
|
+
raise ProviderError(
|
|
110
|
+
f"{self._name} returned {response.status_code}: {response.text[:500]}"
|
|
111
|
+
)
|
|
112
|
+
async for line in response.aiter_lines():
|
|
113
|
+
if not line.startswith("data:"):
|
|
114
|
+
continue
|
|
115
|
+
data = line[len("data:") :].strip()
|
|
116
|
+
if data == "[DONE]":
|
|
117
|
+
continue
|
|
118
|
+
try:
|
|
119
|
+
decoded = json.loads(data)
|
|
120
|
+
except json.JSONDecodeError as exc:
|
|
121
|
+
raise ProviderResponseError(
|
|
122
|
+
f"{self._name} streamed non-JSON", data
|
|
123
|
+
) from exc
|
|
124
|
+
if not isinstance(decoded, dict):
|
|
125
|
+
raise ProviderResponseError(
|
|
126
|
+
f"{self._name} streamed a non-object body", data
|
|
127
|
+
)
|
|
128
|
+
yield self._parse_chunk(decoded, model)
|
|
129
|
+
except httpx.TransportError as exc:
|
|
130
|
+
raise ProviderError(f"{self._name} stream failed: {exc}") from exc
|
|
131
|
+
|
|
132
|
+
async def aclose(self) -> None:
|
|
133
|
+
if self._closed:
|
|
134
|
+
return
|
|
135
|
+
self._closed = True
|
|
136
|
+
if self._owns_client:
|
|
137
|
+
await self._client.aclose()
|
|
138
|
+
|
|
139
|
+
def _headers(self) -> dict[str, str]:
|
|
140
|
+
headers = {"content-type": "application/json", **self._extra_headers}
|
|
141
|
+
if self._api_key:
|
|
142
|
+
headers["authorization"] = f"Bearer {self._api_key}"
|
|
143
|
+
return headers
|
|
144
|
+
|
|
145
|
+
def _build_payload(self, request: CompletionRequest, model: ModelSpec) -> dict[str, Any]:
|
|
146
|
+
payload: dict[str, Any] = {
|
|
147
|
+
"model": model.name,
|
|
148
|
+
"messages": [_message_payload(message) for message in request.messages],
|
|
149
|
+
}
|
|
150
|
+
if request.temperature is not None:
|
|
151
|
+
payload["temperature"] = request.temperature
|
|
152
|
+
if request.max_output_tokens is not None:
|
|
153
|
+
payload["max_tokens"] = min(request.max_output_tokens, model.max_output_tokens)
|
|
154
|
+
if request.tools:
|
|
155
|
+
payload["tools"] = [tool.as_openai_tool() for tool in request.tools]
|
|
156
|
+
if request.stop:
|
|
157
|
+
payload["stop"] = list(request.stop)
|
|
158
|
+
return payload
|
|
159
|
+
|
|
160
|
+
async def _post(self, path: str, payload: dict[str, Any]) -> dict[str, Any]:
|
|
161
|
+
url = f"{self._base_url}{path}"
|
|
162
|
+
last_error: Exception | None = None
|
|
163
|
+
for attempt in range(1, self._max_attempts + 1):
|
|
164
|
+
try:
|
|
165
|
+
response = await self._client.post(url, json=payload, headers=self._headers())
|
|
166
|
+
except httpx.TransportError as exc:
|
|
167
|
+
last_error = exc
|
|
168
|
+
if attempt == self._max_attempts:
|
|
169
|
+
break
|
|
170
|
+
await asyncio.sleep(self._backoff * 2 ** (attempt - 1))
|
|
171
|
+
continue
|
|
172
|
+
|
|
173
|
+
if response.status_code in _RETRYABLE_STATUS and attempt < self._max_attempts:
|
|
174
|
+
last_error = ProviderError(f"{self._name} returned {response.status_code}")
|
|
175
|
+
await asyncio.sleep(self._backoff * 2 ** (attempt - 1))
|
|
176
|
+
continue
|
|
177
|
+
|
|
178
|
+
if response.status_code >= 400:
|
|
179
|
+
raise ProviderError(
|
|
180
|
+
f"{self._name} returned {response.status_code}: {response.text[:500]}"
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
decoded = response.json()
|
|
185
|
+
except json.JSONDecodeError as exc:
|
|
186
|
+
raise ProviderResponseError(
|
|
187
|
+
f"{self._name} returned non-JSON", response.text
|
|
188
|
+
) from exc
|
|
189
|
+
if not isinstance(decoded, dict):
|
|
190
|
+
raise ProviderResponseError(
|
|
191
|
+
f"{self._name} returned a non-object body", response.text
|
|
192
|
+
)
|
|
193
|
+
return decoded
|
|
194
|
+
|
|
195
|
+
raise ProviderError(
|
|
196
|
+
f"{self._name} failed after {self._max_attempts} attempt(s): {last_error}"
|
|
197
|
+
) from last_error
|
|
198
|
+
|
|
199
|
+
def _parse(self, body: dict[str, Any], model: ModelSpec) -> CompletionResponse:
|
|
200
|
+
choices = body.get("choices")
|
|
201
|
+
if not isinstance(choices, list) or not choices:
|
|
202
|
+
raise ProviderResponseError(
|
|
203
|
+
f"{self._name} returned no choices", json.dumps(body, sort_keys=True)
|
|
204
|
+
)
|
|
205
|
+
first = choices[0]
|
|
206
|
+
if not isinstance(first, dict):
|
|
207
|
+
raise ProviderResponseError(f"{self._name} returned a malformed choice")
|
|
208
|
+
message = first.get("message")
|
|
209
|
+
if not isinstance(message, dict):
|
|
210
|
+
raise ProviderResponseError(
|
|
211
|
+
f"{self._name} returned a choice without a message",
|
|
212
|
+
json.dumps(first, sort_keys=True),
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
text = message.get("content")
|
|
216
|
+
if text is None:
|
|
217
|
+
text = ""
|
|
218
|
+
if not isinstance(text, str):
|
|
219
|
+
raise ProviderResponseError(f"{self._name} returned non-string content")
|
|
220
|
+
|
|
221
|
+
tool_calls = self._parse_tool_calls(message.get("tool_calls"))
|
|
222
|
+
|
|
223
|
+
raw_usage = body.get("usage")
|
|
224
|
+
usage = TokenUsage(input_tokens=0, output_tokens=0)
|
|
225
|
+
if isinstance(raw_usage, dict):
|
|
226
|
+
usage = TokenUsage(
|
|
227
|
+
input_tokens=int(raw_usage.get("prompt_tokens") or 0),
|
|
228
|
+
output_tokens=int(raw_usage.get("completion_tokens") or 0),
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
return CompletionResponse(
|
|
232
|
+
text=text,
|
|
233
|
+
model=str(body.get("model") or model.name),
|
|
234
|
+
provider=self._name,
|
|
235
|
+
usage=usage,
|
|
236
|
+
tool_calls=tool_calls,
|
|
237
|
+
finish_reason=_finish_reason(first.get("finish_reason")),
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
def _parse_chunk(self, body: dict[str, Any], model: ModelSpec) -> StreamChunk:
|
|
241
|
+
"""Map one streamed SSE ``data`` payload to a :class:`StreamChunk`."""
|
|
242
|
+
choices = body.get("choices")
|
|
243
|
+
delta = ""
|
|
244
|
+
finish_reason: FinishReason | None = None
|
|
245
|
+
if isinstance(choices, list) and choices:
|
|
246
|
+
first = choices[0]
|
|
247
|
+
if isinstance(first, dict):
|
|
248
|
+
delta_obj = first.get("delta")
|
|
249
|
+
if isinstance(delta_obj, dict):
|
|
250
|
+
content = delta_obj.get("content")
|
|
251
|
+
if isinstance(content, str):
|
|
252
|
+
delta = content
|
|
253
|
+
raw_reason = first.get("finish_reason")
|
|
254
|
+
if isinstance(raw_reason, str) and raw_reason:
|
|
255
|
+
finish_reason = _finish_reason(raw_reason)
|
|
256
|
+
|
|
257
|
+
usage: TokenUsage | None = None
|
|
258
|
+
raw_usage = body.get("usage")
|
|
259
|
+
if isinstance(raw_usage, dict):
|
|
260
|
+
usage = TokenUsage(
|
|
261
|
+
input_tokens=int(raw_usage.get("prompt_tokens") or 0),
|
|
262
|
+
output_tokens=int(raw_usage.get("completion_tokens") or 0),
|
|
263
|
+
)
|
|
264
|
+
return StreamChunk(delta=delta, finish_reason=finish_reason, usage=usage)
|
|
265
|
+
|
|
266
|
+
def _parse_tool_calls(self, raw: Any) -> tuple[ToolCall, ...]:
|
|
267
|
+
if not isinstance(raw, list):
|
|
268
|
+
return ()
|
|
269
|
+
calls: list[ToolCall] = []
|
|
270
|
+
for index, item in enumerate(raw):
|
|
271
|
+
if not isinstance(item, dict):
|
|
272
|
+
continue
|
|
273
|
+
function = item.get("function")
|
|
274
|
+
if not isinstance(function, dict):
|
|
275
|
+
continue
|
|
276
|
+
name = function.get("name")
|
|
277
|
+
if not isinstance(name, str) or not name:
|
|
278
|
+
continue
|
|
279
|
+
calls.append(
|
|
280
|
+
ToolCall(
|
|
281
|
+
id=str(item.get("id") or f"call_{index}"),
|
|
282
|
+
name=name,
|
|
283
|
+
arguments=_decode_arguments(function.get("arguments")),
|
|
284
|
+
)
|
|
285
|
+
)
|
|
286
|
+
return tuple(calls)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
_FINISH_REASONS: dict[str, FinishReason] = {
|
|
290
|
+
"stop": "stop",
|
|
291
|
+
"length": "length",
|
|
292
|
+
"tool_calls": "tool-calls",
|
|
293
|
+
"content_filter": "content-filter",
|
|
294
|
+
"error": "error",
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def _finish_reason(raw: Any) -> FinishReason:
|
|
299
|
+
return _FINISH_REASONS.get(raw, "stop") if isinstance(raw, str) else "stop"
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _decode_arguments(raw: Any) -> dict[str, Any]:
|
|
303
|
+
"""Tool arguments arrive as a JSON *string*; a malformed one is an empty dict.
|
|
304
|
+
|
|
305
|
+
Returning ``{}`` rather than raising keeps the failure in the tool executor,
|
|
306
|
+
where it is reported to the model as a retryable tool error instead of
|
|
307
|
+
aborting the whole turn.
|
|
308
|
+
"""
|
|
309
|
+
if isinstance(raw, dict):
|
|
310
|
+
return raw
|
|
311
|
+
if not isinstance(raw, str) or not raw.strip():
|
|
312
|
+
return {}
|
|
313
|
+
try:
|
|
314
|
+
decoded = json.loads(raw)
|
|
315
|
+
except json.JSONDecodeError:
|
|
316
|
+
return {}
|
|
317
|
+
return decoded if isinstance(decoded, dict) else {}
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def _message_payload(message: Message) -> dict[str, Any]:
|
|
321
|
+
"""One OpenAI chat message, omitting fields the transcript did not set.
|
|
322
|
+
|
|
323
|
+
Single-turn requests must keep the exact ``{"role", "content"}`` shape they had
|
|
324
|
+
before tool bookkeeping existed, so absent fields are omitted rather than sent
|
|
325
|
+
as ``null``/``[]``.
|
|
326
|
+
"""
|
|
327
|
+
payload: dict[str, Any] = {"role": message.role, "content": message.content}
|
|
328
|
+
if message.tool_calls:
|
|
329
|
+
payload["tool_calls"] = [
|
|
330
|
+
{
|
|
331
|
+
"id": call.id,
|
|
332
|
+
"type": "function",
|
|
333
|
+
"function": {
|
|
334
|
+
"name": call.name,
|
|
335
|
+
"arguments": json.dumps(call.arguments, sort_keys=True),
|
|
336
|
+
},
|
|
337
|
+
}
|
|
338
|
+
for call in message.tool_calls
|
|
339
|
+
]
|
|
340
|
+
if message.tool_call_id is not None:
|
|
341
|
+
payload["tool_call_id"] = message.tool_call_id
|
|
342
|
+
if message.name is not None:
|
|
343
|
+
payload["name"] = message.name
|
|
344
|
+
return payload
|
aid_runtime/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""The retrieval runtime: connectors, chunkers, embedders, stores, fusion, citations.
|
|
2
|
+
|
|
3
|
+
The package is one pipeline in source order. A connector yields documents, a chunker
|
|
4
|
+
splits them, an embedder vectorizes them, a store holds them, and retrieval goes back
|
|
5
|
+
out through the store, optionally fusing, optionally reranking, and always attaching
|
|
6
|
+
citations.
|
|
7
|
+
|
|
8
|
+
Every seam is a protocol with a deterministic implementation and, where the plan
|
|
9
|
+
allows one, a hosted implementation. Phase 1 ships exactly one hosted adapter --
|
|
10
|
+
:class:`OpenAICompatibleEmbedder` -- alongside :class:`FakeDeterministicEmbedder`,
|
|
11
|
+
which is what lets a gate run offline. There is no hosted reranker: the only
|
|
12
|
+
reranker is the deterministic :class:`LexicalReranker`.
|
|
13
|
+
|
|
14
|
+
Import safety is deliberate. :class:`PgVectorStore` is exported from here, but the
|
|
15
|
+
``psycopg`` driver is imported inside its connect path, never at module scope, so
|
|
16
|
+
``import aid_runtime`` works without the ``pgvector`` extra installed -- which is the
|
|
17
|
+
only state CI is ever in, since CI installs the ``dev`` extra and ``pgvector`` is not
|
|
18
|
+
part of it. Reaching for the driver without the extra raises ``ConfigurationError``
|
|
19
|
+
naming the extra, rather than ``ImportError`` from three frames down.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
from aid_runtime.retrieval.chunking import (
|
|
25
|
+
Chunker,
|
|
26
|
+
CodeChunker,
|
|
27
|
+
FixedChunker,
|
|
28
|
+
RecursiveChunker,
|
|
29
|
+
chunk_document,
|
|
30
|
+
chunker_for,
|
|
31
|
+
)
|
|
32
|
+
from aid_runtime.retrieval.citations import (
|
|
33
|
+
Citation,
|
|
34
|
+
RetrievalResult,
|
|
35
|
+
RetrievedItem,
|
|
36
|
+
assemble_context,
|
|
37
|
+
cite,
|
|
38
|
+
)
|
|
39
|
+
from aid_runtime.retrieval.connectors import (
|
|
40
|
+
Connector,
|
|
41
|
+
FileConnector,
|
|
42
|
+
SourceDocument,
|
|
43
|
+
open_connector,
|
|
44
|
+
)
|
|
45
|
+
from aid_runtime.retrieval.embedding import (
|
|
46
|
+
Embedder,
|
|
47
|
+
EmbeddingBatch,
|
|
48
|
+
FakeDeterministicEmbedder,
|
|
49
|
+
OpenAICompatibleEmbedder,
|
|
50
|
+
embedder_for,
|
|
51
|
+
estimate_tokens,
|
|
52
|
+
)
|
|
53
|
+
from aid_runtime.retrieval.gate import RetrievalGate
|
|
54
|
+
from aid_runtime.retrieval.hybrid import (
|
|
55
|
+
RankedId,
|
|
56
|
+
bm25_scores,
|
|
57
|
+
fuse,
|
|
58
|
+
lexical_ranking,
|
|
59
|
+
rrf_score,
|
|
60
|
+
tokenize,
|
|
61
|
+
)
|
|
62
|
+
from aid_runtime.retrieval.metrics import (
|
|
63
|
+
CitationGrounding,
|
|
64
|
+
MeanReciprocalRank,
|
|
65
|
+
RecallAtK,
|
|
66
|
+
RetrievalCase,
|
|
67
|
+
RetrievalMetric,
|
|
68
|
+
retrieval_metrics,
|
|
69
|
+
)
|
|
70
|
+
from aid_runtime.retrieval.pgvector import PgVectorStore, resolve_uri
|
|
71
|
+
from aid_runtime.retrieval.rerank import LexicalReranker, Reranker, lexical_score, reranker_for
|
|
72
|
+
from aid_runtime.retrieval.retriever import DEFAULT_CANDIDATE_FACTOR, IngestReport, Retriever
|
|
73
|
+
from aid_runtime.retrieval.stores import (
|
|
74
|
+
InMemoryVectorStore,
|
|
75
|
+
SearchHit,
|
|
76
|
+
StoreRecord,
|
|
77
|
+
VectorStore,
|
|
78
|
+
create_store,
|
|
79
|
+
similarity,
|
|
80
|
+
)
|
|
81
|
+
from aid_runtime.retrieval.types import (
|
|
82
|
+
Chunk,
|
|
83
|
+
ChunkingSpec,
|
|
84
|
+
ChunkingStrategy,
|
|
85
|
+
DistanceMetric,
|
|
86
|
+
EmbeddingCostProfile,
|
|
87
|
+
EmbeddingSpec,
|
|
88
|
+
IndexSpec,
|
|
89
|
+
PinnedEmbedding,
|
|
90
|
+
RefreshMode,
|
|
91
|
+
RefreshSpec,
|
|
92
|
+
RerankSpec,
|
|
93
|
+
RetrievalMetricSpec,
|
|
94
|
+
RetrieverBinding,
|
|
95
|
+
RetrieverSpec,
|
|
96
|
+
ScoredChunk,
|
|
97
|
+
SourceKind,
|
|
98
|
+
SourceSpec,
|
|
99
|
+
StoreKind,
|
|
100
|
+
VectorStoreSpec,
|
|
101
|
+
binding_from_spec,
|
|
102
|
+
chunk_id_for,
|
|
103
|
+
pinned_embedding,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
__all__ = [
|
|
107
|
+
"DEFAULT_CANDIDATE_FACTOR",
|
|
108
|
+
"Chunk",
|
|
109
|
+
"Chunker",
|
|
110
|
+
"ChunkingSpec",
|
|
111
|
+
"ChunkingStrategy",
|
|
112
|
+
"Citation",
|
|
113
|
+
"CitationGrounding",
|
|
114
|
+
"CodeChunker",
|
|
115
|
+
"Connector",
|
|
116
|
+
"DistanceMetric",
|
|
117
|
+
"Embedder",
|
|
118
|
+
"EmbeddingBatch",
|
|
119
|
+
"EmbeddingCostProfile",
|
|
120
|
+
"EmbeddingSpec",
|
|
121
|
+
"FakeDeterministicEmbedder",
|
|
122
|
+
"FileConnector",
|
|
123
|
+
"FixedChunker",
|
|
124
|
+
"InMemoryVectorStore",
|
|
125
|
+
"IndexSpec",
|
|
126
|
+
"IngestReport",
|
|
127
|
+
"LexicalReranker",
|
|
128
|
+
"MeanReciprocalRank",
|
|
129
|
+
"OpenAICompatibleEmbedder",
|
|
130
|
+
"PgVectorStore",
|
|
131
|
+
"PinnedEmbedding",
|
|
132
|
+
"RankedId",
|
|
133
|
+
"RecallAtK",
|
|
134
|
+
"RecursiveChunker",
|
|
135
|
+
"RefreshMode",
|
|
136
|
+
"RefreshSpec",
|
|
137
|
+
"RerankSpec",
|
|
138
|
+
"Reranker",
|
|
139
|
+
"RetrievalCase",
|
|
140
|
+
"RetrievalGate",
|
|
141
|
+
"RetrievalMetric",
|
|
142
|
+
"RetrievalMetricSpec",
|
|
143
|
+
"RetrievalResult",
|
|
144
|
+
"RetrievedItem",
|
|
145
|
+
"Retriever",
|
|
146
|
+
"RetrieverBinding",
|
|
147
|
+
"RetrieverSpec",
|
|
148
|
+
"ScoredChunk",
|
|
149
|
+
"SearchHit",
|
|
150
|
+
"SourceDocument",
|
|
151
|
+
"SourceKind",
|
|
152
|
+
"SourceSpec",
|
|
153
|
+
"StoreKind",
|
|
154
|
+
"StoreRecord",
|
|
155
|
+
"VectorStore",
|
|
156
|
+
"VectorStoreSpec",
|
|
157
|
+
"assemble_context",
|
|
158
|
+
"binding_from_spec",
|
|
159
|
+
"bm25_scores",
|
|
160
|
+
"chunk_document",
|
|
161
|
+
"chunk_id_for",
|
|
162
|
+
"chunker_for",
|
|
163
|
+
"cite",
|
|
164
|
+
"create_store",
|
|
165
|
+
"embedder_for",
|
|
166
|
+
"estimate_tokens",
|
|
167
|
+
"fuse",
|
|
168
|
+
"lexical_ranking",
|
|
169
|
+
"lexical_score",
|
|
170
|
+
"open_connector",
|
|
171
|
+
"pinned_embedding",
|
|
172
|
+
"reranker_for",
|
|
173
|
+
"resolve_uri",
|
|
174
|
+
"retrieval_metrics",
|
|
175
|
+
"rrf_score",
|
|
176
|
+
"similarity",
|
|
177
|
+
"tokenize",
|
|
178
|
+
]
|