@aid-framework/runtime 0.0.0 → 0.1.39

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.
Files changed (188) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +53 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/agents/deep_agents.d.ts +78 -0
  5. package/dist/agents/deep_agents.d.ts.map +1 -0
  6. package/dist/agents/deep_agents.js +477 -0
  7. package/dist/agents/deep_agents.js.map +1 -0
  8. package/dist/agents/engine.d.ts +85 -0
  9. package/dist/agents/engine.d.ts.map +1 -0
  10. package/dist/agents/engine.js +129 -0
  11. package/dist/agents/engine.js.map +1 -0
  12. package/dist/agents/gateway_chat_model.d.ts +151 -0
  13. package/dist/agents/gateway_chat_model.d.ts.map +1 -0
  14. package/dist/agents/gateway_chat_model.js +350 -0
  15. package/dist/agents/gateway_chat_model.js.map +1 -0
  16. package/dist/agents/guardrail_middleware.d.ts +57 -0
  17. package/dist/agents/guardrail_middleware.d.ts.map +1 -0
  18. package/dist/agents/guardrail_middleware.js +85 -0
  19. package/dist/agents/guardrail_middleware.js.map +1 -0
  20. package/dist/agents/guardrails.d.ts +124 -0
  21. package/dist/agents/guardrails.d.ts.map +1 -0
  22. package/dist/agents/guardrails.js +336 -0
  23. package/dist/agents/guardrails.js.map +1 -0
  24. package/dist/agents/index.d.ts +15 -0
  25. package/dist/agents/index.d.ts.map +1 -0
  26. package/dist/agents/index.js +15 -0
  27. package/dist/agents/index.js.map +1 -0
  28. package/dist/agents/ir.d.ts +144 -0
  29. package/dist/agents/ir.d.ts.map +1 -0
  30. package/dist/agents/ir.js +513 -0
  31. package/dist/agents/ir.js.map +1 -0
  32. package/dist/agents/loop.d.ts +145 -0
  33. package/dist/agents/loop.d.ts.map +1 -0
  34. package/dist/agents/loop.js +1025 -0
  35. package/dist/agents/loop.js.map +1 -0
  36. package/dist/agents/memory.d.ts +115 -0
  37. package/dist/agents/memory.d.ts.map +1 -0
  38. package/dist/agents/memory.js +258 -0
  39. package/dist/agents/memory.js.map +1 -0
  40. package/dist/agents/state.d.ts +137 -0
  41. package/dist/agents/state.d.ts.map +1 -0
  42. package/dist/agents/state.js +255 -0
  43. package/dist/agents/state.js.map +1 -0
  44. package/dist/concurrency.d.ts +36 -0
  45. package/dist/concurrency.d.ts.map +1 -0
  46. package/dist/concurrency.js +86 -0
  47. package/dist/concurrency.js.map +1 -0
  48. package/dist/control.d.ts +116 -0
  49. package/dist/control.d.ts.map +1 -0
  50. package/dist/control.js +281 -0
  51. package/dist/control.js.map +1 -0
  52. package/dist/cost.d.ts +95 -0
  53. package/dist/cost.d.ts.map +1 -0
  54. package/dist/cost.js +161 -0
  55. package/dist/cost.js.map +1 -0
  56. package/dist/errors.d.ts +213 -0
  57. package/dist/errors.d.ts.map +1 -0
  58. package/dist/errors.js +316 -0
  59. package/dist/errors.js.map +1 -0
  60. package/dist/evals/dataset.d.ts +45 -0
  61. package/dist/evals/dataset.d.ts.map +1 -0
  62. package/dist/evals/dataset.js +147 -0
  63. package/dist/evals/dataset.js.map +1 -0
  64. package/dist/evals/gate.d.ts +236 -0
  65. package/dist/evals/gate.d.ts.map +1 -0
  66. package/dist/evals/gate.js +572 -0
  67. package/dist/evals/gate.js.map +1 -0
  68. package/dist/evals/metrics.d.ts +141 -0
  69. package/dist/evals/metrics.d.ts.map +1 -0
  70. package/dist/evals/metrics.js +364 -0
  71. package/dist/evals/metrics.js.map +1 -0
  72. package/dist/evals/predicate.d.ts +79 -0
  73. package/dist/evals/predicate.d.ts.map +1 -0
  74. package/dist/evals/predicate.js +178 -0
  75. package/dist/evals/predicate.js.map +1 -0
  76. package/dist/evals/runner.d.ts +94 -0
  77. package/dist/evals/runner.d.ts.map +1 -0
  78. package/dist/evals/runner.js +202 -0
  79. package/dist/evals/runner.js.map +1 -0
  80. package/dist/gateway.d.ts +118 -0
  81. package/dist/gateway.d.ts.map +1 -0
  82. package/dist/gateway.js +250 -0
  83. package/dist/gateway.js.map +1 -0
  84. package/dist/index.d.ts +83 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +59 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/internal/json.d.ts +44 -0
  89. package/dist/internal/json.d.ts.map +1 -0
  90. package/dist/internal/json.js +90 -0
  91. package/dist/internal/json.js.map +1 -0
  92. package/dist/internal/text.d.ts +17 -0
  93. package/dist/internal/text.d.ts.map +1 -0
  94. package/dist/internal/text.js +22 -0
  95. package/dist/internal/text.js.map +1 -0
  96. package/dist/pipeline.d.ts +80 -0
  97. package/dist/pipeline.d.ts.map +1 -0
  98. package/dist/pipeline.js +159 -0
  99. package/dist/pipeline.js.map +1 -0
  100. package/dist/policy.d.ts +52 -0
  101. package/dist/policy.d.ts.map +1 -0
  102. package/dist/policy.js +199 -0
  103. package/dist/policy.js.map +1 -0
  104. package/dist/prompts.d.ts +86 -0
  105. package/dist/prompts.d.ts.map +1 -0
  106. package/dist/prompts.js +337 -0
  107. package/dist/prompts.js.map +1 -0
  108. package/dist/providers/base.d.ts +19 -0
  109. package/dist/providers/base.d.ts.map +1 -0
  110. package/dist/providers/base.js +13 -0
  111. package/dist/providers/base.js.map +1 -0
  112. package/dist/providers/fake.d.ts +98 -0
  113. package/dist/providers/fake.d.ts.map +1 -0
  114. package/dist/providers/fake.js +181 -0
  115. package/dist/providers/fake.js.map +1 -0
  116. package/dist/providers/http.d.ts +62 -0
  117. package/dist/providers/http.d.ts.map +1 -0
  118. package/dist/providers/http.js +245 -0
  119. package/dist/providers/http.js.map +1 -0
  120. package/dist/retrieval/chunking.d.ts +88 -0
  121. package/dist/retrieval/chunking.d.ts.map +1 -0
  122. package/dist/retrieval/chunking.js +188 -0
  123. package/dist/retrieval/chunking.js.map +1 -0
  124. package/dist/retrieval/citations.d.ts +98 -0
  125. package/dist/retrieval/citations.d.ts.map +1 -0
  126. package/dist/retrieval/citations.js +134 -0
  127. package/dist/retrieval/citations.js.map +1 -0
  128. package/dist/retrieval/connectors.d.ts +74 -0
  129. package/dist/retrieval/connectors.d.ts.map +1 -0
  130. package/dist/retrieval/connectors.js +218 -0
  131. package/dist/retrieval/connectors.js.map +1 -0
  132. package/dist/retrieval/embedding.d.ts +116 -0
  133. package/dist/retrieval/embedding.d.ts.map +1 -0
  134. package/dist/retrieval/embedding.js +282 -0
  135. package/dist/retrieval/embedding.js.map +1 -0
  136. package/dist/retrieval/gate.d.ts +52 -0
  137. package/dist/retrieval/gate.d.ts.map +1 -0
  138. package/dist/retrieval/gate.js +91 -0
  139. package/dist/retrieval/gate.js.map +1 -0
  140. package/dist/retrieval/hybrid.d.ts +76 -0
  141. package/dist/retrieval/hybrid.d.ts.map +1 -0
  142. package/dist/retrieval/hybrid.js +150 -0
  143. package/dist/retrieval/hybrid.js.map +1 -0
  144. package/dist/retrieval/metrics.d.ts +126 -0
  145. package/dist/retrieval/metrics.d.ts.map +1 -0
  146. package/dist/retrieval/metrics.js +200 -0
  147. package/dist/retrieval/metrics.js.map +1 -0
  148. package/dist/retrieval/pgvector.d.ts +62 -0
  149. package/dist/retrieval/pgvector.d.ts.map +1 -0
  150. package/dist/retrieval/pgvector.js +262 -0
  151. package/dist/retrieval/pgvector.js.map +1 -0
  152. package/dist/retrieval/rerank.d.ts +61 -0
  153. package/dist/retrieval/rerank.d.ts.map +1 -0
  154. package/dist/retrieval/rerank.js +105 -0
  155. package/dist/retrieval/rerank.js.map +1 -0
  156. package/dist/retrieval/retriever.d.ts +125 -0
  157. package/dist/retrieval/retriever.d.ts.map +1 -0
  158. package/dist/retrieval/retriever.js +281 -0
  159. package/dist/retrieval/retriever.js.map +1 -0
  160. package/dist/retrieval/stores.d.ts +106 -0
  161. package/dist/retrieval/stores.d.ts.map +1 -0
  162. package/dist/retrieval/stores.js +142 -0
  163. package/dist/retrieval/stores.js.map +1 -0
  164. package/dist/retrieval/types.d.ts +314 -0
  165. package/dist/retrieval/types.d.ts.map +1 -0
  166. package/dist/retrieval/types.js +388 -0
  167. package/dist/retrieval/types.js.map +1 -0
  168. package/dist/steps.d.ts +156 -0
  169. package/dist/steps.d.ts.map +1 -0
  170. package/dist/steps.js +199 -0
  171. package/dist/steps.js.map +1 -0
  172. package/dist/structured.d.ts +91 -0
  173. package/dist/structured.d.ts.map +1 -0
  174. package/dist/structured.js +155 -0
  175. package/dist/structured.js.map +1 -0
  176. package/dist/tools.d.ts +100 -0
  177. package/dist/tools.d.ts.map +1 -0
  178. package/dist/tools.js +201 -0
  179. package/dist/tools.js.map +1 -0
  180. package/dist/tracing.d.ts +104 -0
  181. package/dist/tracing.d.ts.map +1 -0
  182. package/dist/tracing.js +155 -0
  183. package/dist/tracing.js.map +1 -0
  184. package/dist/types.d.ts +240 -0
  185. package/dist/types.d.ts.map +1 -0
  186. package/dist/types.js +357 -0
  187. package/dist/types.js.map +1 -0
  188. package/package.json +80 -14
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Reordering a retrieved set before it is returned.
3
+ *
4
+ * Exactly one reranker exists in Phase 1, and it is lexical. That is a deliberate
5
+ * limitation rather than an unfinished one: the seam is what this layer owes, and the
6
+ * deterministic implementation is what lets a gate assert on ranking behaviour
7
+ * without an API key or a floating cross-encoder.
8
+ *
9
+ * Why rerank at all when hybrid search already blends two rankings? Because fusion
10
+ * answers "which candidates are worth considering" and reranking answers "which of
11
+ * these best answers the question", and the second question can look at the query and
12
+ * one passage together instead of at ranks alone. The lexical reranker does that with
13
+ * query-term coverage, which is cheap, explainable, and stable.
14
+ *
15
+ * The reranker **replaces** each item's score instead of adding a second number. After
16
+ * reranking, the number that ranks the list is the reranker's, and keeping a fused RRF
17
+ * value in the same field would put two incomparable scales in one place. Ranks are
18
+ * renumbered from 1 so {@link RetrievalResult.context} stays resolvable.
19
+ */
20
+ import { ConfigurationError, FeatureDeferredError } from '../errors.js';
21
+ import { repr } from '../internal/json.js';
22
+ import { cite, RetrievedItem } from './citations.js';
23
+ import { tokenize } from './hybrid.js';
24
+ const LEXICAL_MARKER = 'lexical';
25
+ /**
26
+ * How much of `query` the passage actually covers, in `[0, 1]`.
27
+ *
28
+ * Query-term coverage, not term frequency: for "which passages answer this", a
29
+ * passage containing each distinct query term once is as good a candidate as one
30
+ * repeating a term, and rewarding repetition is how a keyword-stuffed chunk wins. An
31
+ * exact phrase match breaks ties toward the passage quoting the query.
32
+ */
33
+ export function lexicalScore(query, text) {
34
+ const terms = new Set(tokenize(query));
35
+ if (terms.size === 0)
36
+ return 0.0;
37
+ const present = new Set(tokenize(text));
38
+ let coverage = 0;
39
+ for (const term of terms) {
40
+ if (present.has(term))
41
+ coverage += 1;
42
+ }
43
+ coverage /= terms.size;
44
+ const trimmed = query.trim();
45
+ if (trimmed.length > 0 && text.toLowerCase().includes(trimmed.toLowerCase())) {
46
+ // Small and bounded, so it can only order passages that already cover the query
47
+ // equally well; it can never promote an unrelated passage.
48
+ return Math.min(1.0, coverage + 0.1);
49
+ }
50
+ return coverage;
51
+ }
52
+ /** Coverage-based reranking, with ties broken on chunk id. */
53
+ export class LexicalReranker {
54
+ _name;
55
+ constructor(init = {}) {
56
+ this._name = init.name ?? 'lexical';
57
+ }
58
+ get name() {
59
+ return this._name;
60
+ }
61
+ async rerank(query, items, init) {
62
+ if (init.topN < 1) {
63
+ throw new ConfigurationError('rerank top_n must be at least 1');
64
+ }
65
+ const scored = items.map((item) => ({
66
+ score: lexicalScore(query, item.chunk.text),
67
+ chunkId: item.chunk.chunkId,
68
+ item,
69
+ }));
70
+ // A reranker that cannot read the query leaves the incoming order alone rather
71
+ // than shuffling it: every score is 0.0, so the tie-break would be chunk-id
72
+ // order, which is an arbitrary order dressed up as a decision.
73
+ if (scored.every((entry) => entry.score === 0.0)) {
74
+ return items.slice(0, init.topN);
75
+ }
76
+ scored.sort((left, right) => left.score !== right.score ? right.score - left.score : left.chunkId < right.chunkId ? -1 : 1);
77
+ return scored.slice(0, init.topN).map((entry, offset) => new RetrievedItem({
78
+ chunk: entry.item.chunk,
79
+ score: entry.score,
80
+ rank: offset + 1,
81
+ citation: cite(entry.item.chunk),
82
+ }));
83
+ }
84
+ }
85
+ /**
86
+ * The reranker a retriever's `rerank` block asks for, if any.
87
+ *
88
+ * `rerank.model` is free-form in the IR, and Phase 1 ships exactly one
89
+ * implementation. A declared model outside the lexical family is refused rather than
90
+ * quietly served by {@link LexicalReranker}, for the same reason an unimplemented
91
+ * source kind or store kind is refused: a retriever that appears to rerank with a
92
+ * cross-encoder it never called is worse than one that says it cannot. The guard
93
+ * matches on the name because the name is the only signal the IR gives; the lexical
94
+ * family is what this runtime can honestly claim.
95
+ */
96
+ export function rerankerFor(spec) {
97
+ if (spec === null)
98
+ return null;
99
+ if (!spec.model.toLowerCase().includes(LEXICAL_MARKER)) {
100
+ throw new FeatureDeferredError(`rerank model ${repr(spec.model)} is declared but not implemented: Phase 1 ships one ` +
101
+ 'deterministic lexical reranker, and a hosted cross-encoder is a later layer');
102
+ }
103
+ return new LexicalReranker();
104
+ }
105
+ //# sourceMappingURL=rerank.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rerank.js","sourceRoot":"","sources":["../../src/retrieval/rerank.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Ingesting a corpus and retrieving from it.
3
+ *
4
+ * This is the module a later layer's generated code calls: `ingest` once per
5
+ * refresh, `retrieve` per query. It is deliberately not a command-line entry point --
6
+ * the generated module is the intended surface, and a runtime that also shipped a
7
+ * `main` would grow a second, competing one.
8
+ *
9
+ * Both halves are orchestration over injected seams. Nothing here chooses a model by
10
+ * name, because the binding already carries the resolved model id, the vector width
11
+ * and the store kind; resolving any of those at run time is exactly what the pinning
12
+ * rule forbids.
13
+ *
14
+ * Cost is charged to the existing ledger using the existing profile. The IR quotes
15
+ * embedding prices per MTok and `CostProfile` quotes per 1k tokens; that conversion
16
+ * happens once, in `pinnedEmbedding`, so no call site repeats it.
17
+ *
18
+ * Candidates: the retriever fetches more than `topK` candidates from each ranking
19
+ * before fusing, because fusion and reranking both reorder, and a fused list built
20
+ * from only `topK` inputs has nothing to reorder. `topK` is applied to the *result*,
21
+ * which is what the IR field means.
22
+ */
23
+ import { type Budget, type CostLedger } from '../cost.js';
24
+ import { RetrievalResult } from './citations.js';
25
+ import { type Connector, type SourceDocument } from './connectors.js';
26
+ import { type Embedder } from './embedding.js';
27
+ import { type Reranker } from './rerank.js';
28
+ import { type VectorStore } from './stores.js';
29
+ import { type RetrieverBinding } from './types.js';
30
+ /**
31
+ * How many candidates per ranking are fetched before fusion. Four is a round number
32
+ * with a defensible property: it lets a passage ranked 4th lexically and 1st by
33
+ * vector similarity reach the top of the fused list, which is the case fusion exists
34
+ * to fix.
35
+ */
36
+ export declare const DEFAULT_CANDIDATE_FACTOR = 4;
37
+ /**
38
+ * What one ingest wrote.
39
+ *
40
+ * `chunkIds` is the load-bearing field for idempotence: it is sorted, so two ingests
41
+ * of identical input compare equal without depending on the order the filesystem
42
+ * happened to yield. `costUsd` is what *this* ingest charged, not the ledger's
43
+ * running total, so ingesting twice reads as two separate spends.
44
+ */
45
+ export declare class IngestReport {
46
+ readonly retriever: string;
47
+ readonly documents: number;
48
+ readonly chunks: number;
49
+ readonly written: number;
50
+ readonly tokens: number;
51
+ readonly costUsd: number;
52
+ readonly chunkIds: readonly string[];
53
+ constructor(init: {
54
+ readonly retriever: string;
55
+ readonly documents: number;
56
+ readonly chunks: number;
57
+ readonly written: number;
58
+ readonly tokens: number;
59
+ readonly costUsd: number;
60
+ readonly chunkIds: readonly string[];
61
+ });
62
+ get isEmpty(): boolean;
63
+ }
64
+ export interface RetrieverOptions {
65
+ readonly embedder?: Embedder;
66
+ readonly store?: VectorStore;
67
+ readonly reranker?: Reranker | null;
68
+ readonly connector?: Connector | null;
69
+ readonly ledger?: CostLedger;
70
+ readonly budget?: Budget;
71
+ readonly baseDir?: string | null;
72
+ readonly candidateFactor?: number;
73
+ }
74
+ /**
75
+ * A bound retriever: its source, its chunker, its embedder, its store.
76
+ *
77
+ * Seams are injectable and default from the binding. Tests inject the fake embedder
78
+ * and an in-memory store; generated code passes the real ones.
79
+ */
80
+ export declare class Retriever {
81
+ private readonly _binding;
82
+ private readonly _embedder;
83
+ private readonly _store;
84
+ private readonly _reranker;
85
+ private _connector;
86
+ private readonly _baseDir;
87
+ private readonly _ledger;
88
+ private readonly _budget;
89
+ private readonly _candidateFactor;
90
+ private _closed;
91
+ constructor(binding: RetrieverBinding, options?: RetrieverOptions);
92
+ get binding(): RetrieverBinding;
93
+ get store(): VectorStore;
94
+ /**
95
+ * Chunk a source, embed it, and write it.
96
+ *
97
+ * Idempotent by construction: chunk ids are content hashes and the store upserts on
98
+ * them, so ingesting the same input twice replaces rather than duplicates.
99
+ * Re-ingesting is therefore a legitimate way to refresh a corpus.
100
+ */
101
+ ingest(documents?: readonly SourceDocument[] | null): Promise<IngestReport>;
102
+ /** Search the store for `query` and return ranked, cited passages. */
103
+ retrieve(query: string, options?: {
104
+ readonly topK?: number | null;
105
+ }): Promise<RetrievalResult>;
106
+ close(): Promise<void>;
107
+ private _readSource;
108
+ /**
109
+ * Embed a batch, charge it to the ledger, and report what it cost.
110
+ *
111
+ * The cost is returned as well as charged so a caller can report what one operation
112
+ * spent: the ledger's total is cumulative across every call the process made, and
113
+ * reporting that as this ingest's cost would double-count.
114
+ */
115
+ private _embed;
116
+ /**
117
+ * The candidate ranking: vector only, or fused with a lexical ranking.
118
+ *
119
+ * Fusion is skipped when `index.hybrid` is false, and that is the whole meaning of
120
+ * the flag -- not "use a different metric", but "do not consult the lexical ranking
121
+ * at all".
122
+ */
123
+ private _rank;
124
+ }
125
+ //# sourceMappingURL=retriever.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retriever.d.ts","sourceRoot":"","sources":["../../src/retrieval/retriever.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Ingesting a corpus and retrieving from it.
3
+ *
4
+ * This is the module a later layer's generated code calls: `ingest` once per
5
+ * refresh, `retrieve` per query. It is deliberately not a command-line entry point --
6
+ * the generated module is the intended surface, and a runtime that also shipped a
7
+ * `main` would grow a second, competing one.
8
+ *
9
+ * Both halves are orchestration over injected seams. Nothing here chooses a model by
10
+ * name, because the binding already carries the resolved model id, the vector width
11
+ * and the store kind; resolving any of those at run time is exactly what the pinning
12
+ * rule forbids.
13
+ *
14
+ * Cost is charged to the existing ledger using the existing profile. The IR quotes
15
+ * embedding prices per MTok and `CostProfile` quotes per 1k tokens; that conversion
16
+ * happens once, in `pinnedEmbedding`, so no call site repeats it.
17
+ *
18
+ * Candidates: the retriever fetches more than `topK` candidates from each ranking
19
+ * before fusing, because fusion and reranking both reorder, and a fused list built
20
+ * from only `topK` inputs has nothing to reorder. `topK` is applied to the *result*,
21
+ * which is what the IR field means.
22
+ */
23
+ import { LedgerEntry } from '../cost.js';
24
+ import { ConfigurationError, FeatureDeferredError } from '../errors.js';
25
+ import { repr } from '../internal/json.js';
26
+ import { TokenUsage } from '../types.js';
27
+ import { chunkerFor } from './chunking.js';
28
+ import { cite, RetrievalResult, RetrievedItem } from './citations.js';
29
+ import { openConnector } from './connectors.js';
30
+ import { embedderFor } from './embedding.js';
31
+ import { fuse, lexicalRanking } from './hybrid.js';
32
+ import { rerankerFor } from './rerank.js';
33
+ import { createStore, StoreRecord } from './stores.js';
34
+ import { ScoredChunk } from './types.js';
35
+ /**
36
+ * How many candidates per ranking are fetched before fusion. Four is a round number
37
+ * with a defensible property: it lets a passage ranked 4th lexically and 1st by
38
+ * vector similarity reach the top of the fused list, which is the case fusion exists
39
+ * to fix.
40
+ */
41
+ export const DEFAULT_CANDIDATE_FACTOR = 4;
42
+ /** Texts per embedding request. */
43
+ const BATCH_SIZE = 64;
44
+ /**
45
+ * What one ingest wrote.
46
+ *
47
+ * `chunkIds` is the load-bearing field for idempotence: it is sorted, so two ingests
48
+ * of identical input compare equal without depending on the order the filesystem
49
+ * happened to yield. `costUsd` is what *this* ingest charged, not the ledger's
50
+ * running total, so ingesting twice reads as two separate spends.
51
+ */
52
+ export class IngestReport {
53
+ retriever;
54
+ documents;
55
+ chunks;
56
+ written;
57
+ tokens;
58
+ costUsd;
59
+ chunkIds;
60
+ constructor(init) {
61
+ this.retriever = init.retriever;
62
+ this.documents = init.documents;
63
+ this.chunks = init.chunks;
64
+ this.written = init.written;
65
+ this.tokens = init.tokens;
66
+ this.costUsd = init.costUsd;
67
+ this.chunkIds = [...init.chunkIds];
68
+ }
69
+ get isEmpty() {
70
+ return this.chunks === 0;
71
+ }
72
+ }
73
+ /**
74
+ * A bound retriever: its source, its chunker, its embedder, its store.
75
+ *
76
+ * Seams are injectable and default from the binding. Tests inject the fake embedder
77
+ * and an in-memory store; generated code passes the real ones.
78
+ */
79
+ export class Retriever {
80
+ _binding;
81
+ _embedder;
82
+ _store;
83
+ _reranker;
84
+ _connector;
85
+ _baseDir;
86
+ _ledger;
87
+ _budget;
88
+ _candidateFactor;
89
+ _closed = false;
90
+ constructor(binding, options = {}) {
91
+ if (binding.refreshMode !== 'full') {
92
+ throw new FeatureDeferredError(`refresh mode ${repr(binding.refreshMode)} is declared but not implemented: ` +
93
+ 'spec v0.1 reindexes the whole source, and incremental refresh needs change ' +
94
+ 'detection the runtime does not have');
95
+ }
96
+ const candidateFactor = options.candidateFactor ?? DEFAULT_CANDIDATE_FACTOR;
97
+ if (candidateFactor < 1) {
98
+ throw new ConfigurationError('candidate_factor must be at least 1');
99
+ }
100
+ this._binding = binding;
101
+ this._embedder = options.embedder ?? embedderFor(binding.embedding);
102
+ this._store =
103
+ options.store ??
104
+ createStore(binding.storeKind, {
105
+ uri: binding.storeUri,
106
+ dimensions: binding.embedding.dimensions,
107
+ });
108
+ this._reranker = options.reranker ?? rerankerFor(binding.rerank);
109
+ this._connector = options.connector ?? null;
110
+ this._baseDir = options.baseDir ?? null;
111
+ this._ledger = options.ledger;
112
+ this._budget = options.budget;
113
+ this._candidateFactor = candidateFactor;
114
+ }
115
+ get binding() {
116
+ return this._binding;
117
+ }
118
+ get store() {
119
+ return this._store;
120
+ }
121
+ /**
122
+ * Chunk a source, embed it, and write it.
123
+ *
124
+ * Idempotent by construction: chunk ids are content hashes and the store upserts on
125
+ * them, so ingesting the same input twice replaces rather than duplicates.
126
+ * Re-ingesting is therefore a legitimate way to refresh a corpus.
127
+ */
128
+ async ingest(documents) {
129
+ const sourceDocuments = documents != null ? [...documents] : await this._readSource();
130
+ const chunker = chunkerFor(this._binding.chunking);
131
+ const chunks = [];
132
+ for (const document of sourceDocuments) {
133
+ for (const chunk of chunker.chunk(document)) {
134
+ chunks.push(chunk);
135
+ }
136
+ }
137
+ const records = [];
138
+ let tokens = 0;
139
+ let cost = 0.0;
140
+ for (let start = 0; start < chunks.length; start += BATCH_SIZE) {
141
+ const batch = chunks.slice(start, start + BATCH_SIZE);
142
+ const embedded = await this._embed(batch.map((chunk) => chunk.text));
143
+ tokens += embedded.batch.usage.inputTokens;
144
+ cost += embedded.costUsd;
145
+ const batchVectors = embedded.batch.vectors;
146
+ if (batchVectors.length !== batch.length) {
147
+ throw new ConfigurationError(`the embedder returned ${batchVectors.length} vectors for ${batch.length} texts`);
148
+ }
149
+ batch.forEach((chunk, offset) => {
150
+ records.push(new StoreRecord({ chunk, vector: batchVectors[offset] }));
151
+ });
152
+ }
153
+ const written = await this._store.upsert(records);
154
+ return new IngestReport({
155
+ retriever: this._binding.retrieverId,
156
+ documents: sourceDocuments.length,
157
+ chunks: chunks.length,
158
+ written,
159
+ tokens,
160
+ costUsd: cost,
161
+ chunkIds: chunks.map((chunk) => chunk.chunkId).sort((left, right) => (left < right ? -1 : 1)),
162
+ });
163
+ }
164
+ /** Search the store for `query` and return ranked, cited passages. */
165
+ async retrieve(query, options = {}) {
166
+ const wanted = options.topK ?? this._binding.topK;
167
+ if (wanted < 1) {
168
+ throw new ConfigurationError('top_k must be at least 1');
169
+ }
170
+ const queryBatch = await this._embed([query]);
171
+ const vector = queryBatch.batch.vectors[0];
172
+ if (vector === undefined) {
173
+ throw new ConfigurationError('the embedder returned no vector for the query');
174
+ }
175
+ const candidates = wanted * this._candidateFactor;
176
+ const hits = await this._store.search(vector, {
177
+ topK: candidates,
178
+ metric: this._binding.index.metric,
179
+ });
180
+ const ranked = await this._rank(query, hits, candidates);
181
+ let items = toItems(ranked);
182
+ if (this._reranker !== null) {
183
+ const topN = this._binding.rerank?.topN ?? wanted;
184
+ items = await this._reranker.rerank(query, items, { topN });
185
+ }
186
+ return new RetrievalResult({
187
+ retriever: this._binding.retrieverId,
188
+ query,
189
+ items: items.slice(0, wanted),
190
+ });
191
+ }
192
+ async close() {
193
+ if (this._closed)
194
+ return;
195
+ this._closed = true;
196
+ await this._store.close();
197
+ await this._embedder.close();
198
+ if (this._connector !== null) {
199
+ await this._connector.close();
200
+ }
201
+ }
202
+ async _readSource() {
203
+ if (this._connector === null) {
204
+ this._connector = openConnector(this._binding.source, { baseDir: this._baseDir });
205
+ }
206
+ return this._connector.documents();
207
+ }
208
+ /**
209
+ * Embed a batch, charge it to the ledger, and report what it cost.
210
+ *
211
+ * The cost is returned as well as charged so a caller can report what one operation
212
+ * spent: the ledger's total is cumulative across every call the process made, and
213
+ * reporting that as this ingest's cost would double-count.
214
+ */
215
+ async _embed(texts) {
216
+ const batch = await this._embedder.embed(texts, { model: this._binding.embedding });
217
+ const usage = new TokenUsage({
218
+ inputTokens: batch.usage.inputTokens,
219
+ outputTokens: batch.usage.outputTokens,
220
+ });
221
+ // Priced through CostProfile rather than a ModelSpec: a ModelSpec requires a
222
+ // context window and an output ceiling, and fabricating those to reuse a pricing
223
+ // helper would put invented numbers in a generated artifact.
224
+ const costUsd = this._binding.embedding.cost.costUsd(usage);
225
+ if (this._ledger !== undefined) {
226
+ this._ledger.charge(this._budget, new LedgerEntry({
227
+ alias: this._binding.embedModel,
228
+ model: this._binding.embedding.modelId,
229
+ provider: this._binding.embedding.provider,
230
+ usage,
231
+ costUsd,
232
+ }));
233
+ }
234
+ return { batch, costUsd };
235
+ }
236
+ /**
237
+ * The candidate ranking: vector only, or fused with a lexical ranking.
238
+ *
239
+ * Fusion is skipped when `index.hybrid` is false, and that is the whole meaning of
240
+ * the flag -- not "use a different metric", but "do not consult the lexical ranking
241
+ * at all".
242
+ */
243
+ async _rank(query, hits, candidates) {
244
+ if (!this._binding.index.hybrid) {
245
+ return hits.map((hit) => new ScoredChunk({ chunk: hit.record.chunk, score: hit.score }));
246
+ }
247
+ const corpus = await this._store.corpus();
248
+ const byId = new Map();
249
+ for (const record of corpus) {
250
+ byId.set(record.chunk.chunkId, record);
251
+ }
252
+ for (const hit of hits) {
253
+ if (!byId.has(hit.record.chunk.chunkId)) {
254
+ byId.set(hit.record.chunk.chunkId, hit.record);
255
+ }
256
+ }
257
+ const lexical = lexicalRanking(corpus.map((record) => record.chunk.text), corpus.map((record) => record.chunk.chunkId), query, { topK: candidates });
258
+ const fused = fuse([
259
+ hits.map((hit) => hit.record.chunk.chunkId),
260
+ lexical.map((entry) => entry.chunkId),
261
+ ]);
262
+ const ranked = [];
263
+ for (const entry of fused) {
264
+ const record = byId.get(entry.chunkId);
265
+ if (record !== undefined) {
266
+ ranked.push(new ScoredChunk({ chunk: record.chunk, score: entry.score }));
267
+ }
268
+ }
269
+ return ranked;
270
+ }
271
+ }
272
+ /** Attach provenance and assign contiguous 1-based ranks. */
273
+ function toItems(ranked) {
274
+ return ranked.map((scored, offset) => new RetrievedItem({
275
+ chunk: scored.chunk,
276
+ score: scored.score,
277
+ rank: offset + 1,
278
+ citation: cite(scored.chunk),
279
+ }));
280
+ }
281
+ //# sourceMappingURL=retriever.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retriever.js","sourceRoot":"","sources":["../../src/retrieval/retriever.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Where vectors live and how they are searched.
3
+ *
4
+ * Two adapters behind one protocol: in-memory and pgvector. The in-memory store is
5
+ * not a stand-in for a "real" one -- it is the adapter every gate runs against, so it
6
+ * is the one whose behaviour is the contract. The pgvector adapter is covered by the
7
+ * same expectations and by nothing else: it is locally provisioned, and no required
8
+ * gate touches a database.
9
+ *
10
+ * Similarity is always reported as *higher is better*, including for L2, where the
11
+ * raw quantity is a distance. A store that inverted its sign for one metric would
12
+ * make every caller responsible for remembering which metric it asked for, and fusion
13
+ * and reranking downstream would silently rank backwards.
14
+ *
15
+ * Lexical search is deliberately absent from the store. The store owns the vector
16
+ * index; BM25 lives in `hybrid.ts` and reads the corpus through
17
+ * {@link VectorStore.corpus}. That keeps one lexical implementation instead of one
18
+ * per backend, at the cost of fetching the corpus per query -- a Phase 1
19
+ * simplification, correct at test scale and worth revisiting when a corpus outgrows
20
+ * memory.
21
+ */
22
+ import type { Chunk, DistanceMetric, StoreKind } from './types.js';
23
+ /** One chunk and its vector, exactly as it is written to a store. */
24
+ export declare class StoreRecord {
25
+ readonly chunk: Chunk;
26
+ readonly vector: readonly number[];
27
+ constructor(init: {
28
+ readonly chunk: Chunk;
29
+ readonly vector: readonly number[];
30
+ });
31
+ }
32
+ /** A record and its similarity to the query, higher being better. */
33
+ export declare class SearchHit {
34
+ readonly record: StoreRecord;
35
+ readonly score: number;
36
+ constructor(init: {
37
+ readonly record: StoreRecord;
38
+ readonly score: number;
39
+ });
40
+ }
41
+ /**
42
+ * Similarity of two equal-length vectors under `metric`.
43
+ *
44
+ * Always oriented so that a larger number means a better match.
45
+ */
46
+ export declare function similarity(left: readonly number[], right: readonly number[], init: {
47
+ readonly metric: DistanceMetric;
48
+ }): number;
49
+ /**
50
+ * A vector index the retriever can ingest into and search.
51
+ *
52
+ * `close` must be idempotent, matching the other seams in this runtime.
53
+ */
54
+ export interface VectorStore {
55
+ readonly kind: StoreKind;
56
+ /** Write records, keyed by `chunkId`. Returns the number written. */
57
+ upsert(records: readonly StoreRecord[]): Promise<number>;
58
+ search(vector: readonly number[], init: {
59
+ readonly topK: number;
60
+ readonly metric: DistanceMetric;
61
+ }): Promise<readonly SearchHit[]>;
62
+ /**
63
+ * Every stored record.
64
+ *
65
+ * Exists for the lexical half of hybrid search, and for assertions about a store's
66
+ * contents after re-ingest.
67
+ */
68
+ corpus(): Promise<readonly StoreRecord[]>;
69
+ close(): Promise<void>;
70
+ }
71
+ /**
72
+ * A map keyed by `chunkId`.
73
+ *
74
+ * The key choice is what makes ingest idempotent: re-ingesting identical input
75
+ * recomputes identical ids and overwrites in place, so the store's contents are a
76
+ * function of the input rather than of how many times it was ingested.
77
+ */
78
+ export declare class InMemoryVectorStore implements VectorStore {
79
+ private readonly _kind;
80
+ private readonly _records;
81
+ constructor(init?: {
82
+ readonly kind?: StoreKind;
83
+ });
84
+ get kind(): StoreKind;
85
+ upsert(records: readonly StoreRecord[]): Promise<number>;
86
+ search(vector: readonly number[], init: {
87
+ readonly topK: number;
88
+ readonly metric: DistanceMetric;
89
+ }): Promise<readonly SearchHit[]>;
90
+ corpus(): Promise<readonly StoreRecord[]>;
91
+ close(): Promise<void>;
92
+ }
93
+ /**
94
+ * Select a store adapter.
95
+ *
96
+ * `pgvector.ts` is imported statically but loads its database driver lazily on first
97
+ * connect, so importing this module still pulls in no driver: the optional-extra
98
+ * property the Python adapter preserves at import time is preserved here at connect
99
+ * time instead. It keeps `createStore` synchronous, which is what the retriever's
100
+ * constructor needs.
101
+ */
102
+ export declare function createStore(kind: StoreKind, init?: {
103
+ readonly uri?: string | null;
104
+ readonly dimensions?: number | null;
105
+ }): VectorStore;
106
+ //# sourceMappingURL=stores.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stores.d.ts","sourceRoot":"","sources":["../../src/retrieval/stores.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH,OAAO,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEnE,qEAAqE;AACrE,qBAAa,WAAW;IACtB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAEnC,YAAY,IAAI,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,EAG9E;CACF;AAED,qEAAqE;AACrE,qBAAa,SAAS;IACpB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,YAAY,IAAI,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAGzE;CACF;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,IAAI,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GACxC,MAAM,CA8BR;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,qEAAqE;IACrE,MAAM,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzD,MAAM,CACJ,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;KAAE,GAC/D,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;IACjC;;;;;OAKG;IACH,MAAM,IAAI,OAAO,CAAC,SAAS,WAAW,EAAE,CAAC,CAAC;IAC1C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;;GAMG;AACH,qBAAa,mBAAoB,YAAW,WAAW;IACrD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAE3D,YAAY,IAAI,GAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAA;KAAO,EAEnD;IAED,IAAI,IAAI,IAAI,SAAS,CAEpB;IAEK,MAAM,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAK7D;IAEK,MAAM,CACV,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;KAAE,GAC/D,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAiB/B;IAEK,MAAM,IAAI,OAAO,CAAC,SAAS,WAAW,EAAE,CAAC,CAI9C;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3B;CACF;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,SAAS,EACf,IAAI,GAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,GAC/E,WAAW,CAWb"}