@aid-framework/runtime 0.0.0 → 0.1.48

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 +183 -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,200 @@
1
+ /**
2
+ * Metrics over a retrieved set.
3
+ *
4
+ * The shipped `Metric` scores `(case, prediction: string)`. That signature cannot
5
+ * express these metrics: recall@k and MRR score a *ranked set of passages with
6
+ * provenance*, and a citation-grounding score has to look at where each passage came
7
+ * from. Encoding a retrieved set into one string would make every metric re-parse it,
8
+ * and the parse would become the thing under test.
9
+ *
10
+ * So the retrieval metrics get their own protocol here rather than widening the
11
+ * shipped one. Widening `Metric` would change the meaning of an interface the eval
12
+ * gate already threshold-checks, and would do so for every existing implementation.
13
+ * The new protocol is additive and reuses {@link MetricResult}.
14
+ *
15
+ * The two protocols share the part the gate actually consumes -- `name` and
16
+ * `deterministic` -- which is what lets retrieval metrics be handed to the shipped
17
+ * gate's `metrics` option. See `retrieval/gate.ts` for why that hand-off needs a cast
18
+ * and why the cast is sound.
19
+ *
20
+ * `deterministic` is `true` for all three, and that is a claim the gate enforces:
21
+ * none of these metrics calls a model, and every tie is broken by chunk id, so the
22
+ * same retrieved set always scores the same.
23
+ */
24
+ import { ConfigurationError } from '../errors.js';
25
+ import { MetricResult } from '../evals/metrics.js';
26
+ import { repr } from '../internal/json.js';
27
+ /**
28
+ * One retrieval question and the documents that should answer it.
29
+ *
30
+ * This mirrors the IR's `retrieval` metric node field for field, and it exists
31
+ * because `EvalCase` carries `metadata: Record<string, string>` -- a string map,
32
+ * which cannot hold `expectDocs` without inventing an encoding. The expected
33
+ * documents, and `k`, are what a retrieval metric needs, so they are typed here
34
+ * instead of smuggled through a string.
35
+ */
36
+ export class RetrievalCase {
37
+ id;
38
+ query;
39
+ expectDocs;
40
+ k;
41
+ constructor(init) {
42
+ if (init.id.length === 0)
43
+ throw new ConfigurationError('case id must not be empty');
44
+ if (init.expectDocs.length === 0) {
45
+ throw new ConfigurationError('a retrieval case needs at least one expected document');
46
+ }
47
+ if (!Number.isInteger(init.k) || init.k <= 0) {
48
+ throw new ConfigurationError('a retrieval case needs a positive k');
49
+ }
50
+ this.id = init.id;
51
+ this.query = init.query;
52
+ this.expectDocs = [...init.expectDocs];
53
+ this.k = init.k;
54
+ }
55
+ /** Build a case from the IR's `{kind, expectDocs, k}` node. */
56
+ static fromSpec(init) {
57
+ return new RetrievalCase({
58
+ id: init.caseId,
59
+ query: init.query,
60
+ expectDocs: init.spec.expectDocs,
61
+ k: init.spec.k,
62
+ });
63
+ }
64
+ }
65
+ /**
66
+ * Fraction of expected documents present in the top `k`.
67
+ *
68
+ * Duplicated passages do not inflate the score: {@link RetrievalResult.docIds} is
69
+ * de-duplicated, so a document that contributed three passages counts once. Recall is
70
+ * about which documents were found.
71
+ */
72
+ export class RecallAtK {
73
+ _name;
74
+ _minScore;
75
+ constructor(options = {}) {
76
+ this._name = options.name ?? 'recall@k';
77
+ this._minScore = options.minScore ?? 1.0;
78
+ }
79
+ get name() {
80
+ return this._name;
81
+ }
82
+ get deterministic() {
83
+ return true;
84
+ }
85
+ async score(entry, retrieved) {
86
+ const expected = new Set(entry.expectDocs);
87
+ const foundInTop = new Set(retrieved.docIds.slice(0, entry.k));
88
+ const found = new Set([...expected].filter((docId) => foundInTop.has(docId)));
89
+ const score = found.size / expected.size;
90
+ const missing = [...expected]
91
+ .filter((docId) => !found.has(docId))
92
+ .sort((left, right) => (left < right ? -1 : 1));
93
+ return new MetricResult({
94
+ metric: this.name,
95
+ score,
96
+ passed: score >= this._minScore,
97
+ detail: missing.length === 0 ? '' : `missing: ${missing.join(', ')}`,
98
+ });
99
+ }
100
+ }
101
+ /**
102
+ * Reciprocal rank of the first expected document, averaged over cases.
103
+ *
104
+ * Scored per case, so the "mean" is taken by the gate across cases and runs. One
105
+ * number per case keeps the metric a drop-in for the gate's per-case arithmetic.
106
+ */
107
+ export class MeanReciprocalRank {
108
+ _name;
109
+ _minScore;
110
+ constructor(options = {}) {
111
+ this._name = options.name ?? 'mrr';
112
+ this._minScore = options.minScore ?? 0.5;
113
+ }
114
+ get name() {
115
+ return this._name;
116
+ }
117
+ get deterministic() {
118
+ return true;
119
+ }
120
+ async score(entry, retrieved) {
121
+ const expected = new Set(entry.expectDocs);
122
+ const ranked = retrieved.docIds.slice(0, entry.k);
123
+ for (const [offset, docId] of ranked.entries()) {
124
+ if (expected.has(docId)) {
125
+ const rank = offset + 1;
126
+ const score = 1.0 / rank;
127
+ return new MetricResult({
128
+ metric: this.name,
129
+ score,
130
+ passed: score >= this._minScore,
131
+ detail: `first expected document ${repr(docId)} at rank ${rank}`,
132
+ });
133
+ }
134
+ }
135
+ const sortedExpected = [...expected].sort((left, right) => (left < right ? -1 : 1));
136
+ return new MetricResult({
137
+ metric: this.name,
138
+ score: 0.0,
139
+ passed: this._minScore <= 0.0,
140
+ detail: `none of ${sortedExpected.join(', ')} were retrieved within k=${entry.k}`,
141
+ });
142
+ }
143
+ }
144
+ /**
145
+ * Fraction of expected documents that a returned item cites *correctly*.
146
+ *
147
+ * Distinct from recall because it scores citations rather than document ids, and
148
+ * because it checks integrity first: a citation whose `chunkId` or `docId` disagrees
149
+ * with the passage it is attached to is worse than a missing citation, since it sends
150
+ * a reader to the wrong place while looking authoritative. Any such mismatch scores 0
151
+ * regardless of what was retrieved.
152
+ *
153
+ * This definition is authored here: the IR has no citation metric kind, so there is
154
+ * no upstream semantics to match. It is stated rather than derived.
155
+ */
156
+ export class CitationGrounding {
157
+ _name;
158
+ _minScore;
159
+ constructor(options = {}) {
160
+ this._name = options.name ?? 'citation-grounding';
161
+ this._minScore = options.minScore ?? 1.0;
162
+ }
163
+ get name() {
164
+ return this._name;
165
+ }
166
+ get deterministic() {
167
+ return true;
168
+ }
169
+ async score(entry, retrieved) {
170
+ const broken = retrieved.items.filter((item) => item.citation.chunkId !== item.chunk.chunkId || item.citation.docId !== item.chunk.docId);
171
+ const first = broken[0];
172
+ if (first !== undefined) {
173
+ return new MetricResult({
174
+ metric: this.name,
175
+ score: 0.0,
176
+ passed: false,
177
+ detail: `${broken.length} citation(s) disagree with the passage they name, ` +
178
+ `first: ${first.citation.toString()} vs chunk ${first.chunk.chunkId}`,
179
+ });
180
+ }
181
+ const expected = new Set(entry.expectDocs);
182
+ const cited = new Set(retrieved.items.map((item) => item.citation.docId));
183
+ const grounded = new Set([...expected].filter((docId) => cited.has(docId)));
184
+ const score = grounded.size / expected.size;
185
+ const missing = [...expected]
186
+ .filter((docId) => !grounded.has(docId))
187
+ .sort((left, right) => (left < right ? -1 : 1));
188
+ return new MetricResult({
189
+ metric: this.name,
190
+ score,
191
+ passed: score >= this._minScore,
192
+ detail: missing.length === 0 ? '' : `uncited: ${missing.join(', ')}`,
193
+ });
194
+ }
195
+ }
196
+ /** The retrieval metrics this runtime ships, in a stable order. */
197
+ export function retrievalMetrics() {
198
+ return [new RecallAtK(), new MeanReciprocalRank(), new CitationGrounding()];
199
+ }
200
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/retrieval/metrics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * A pgvector-backed store, provisioned locally and never touched by CI.
3
+ *
4
+ * The driver is optional, so this module must be importable without it. Nothing at
5
+ * module scope imports it; the load happens inside {@link loadDriver} on first use,
6
+ * and a missing driver becomes a {@link ConfigurationError} that names the package to
7
+ * install. Importing the retrieval package therefore cannot fail because a database
8
+ * dependency is absent, which is what lets the default dependency set stay unchanged
9
+ * and what keeps every required gate on the in-memory store.
10
+ *
11
+ * Two consequences of that choice are deliberate and visible:
12
+ *
13
+ * - The driver arrives as an untyped value, so `unknown` reaches this file. It is
14
+ * confined to this one adapter rather than spreading a suppressed import across the
15
+ * retrieval package.
16
+ * - Every statement is a fixed string with positional placeholders. The embedding
17
+ * column is declared dimension-less rather than `vector(1536)`, so no computed
18
+ * identifier is ever interpolated into SQL, and the pinned width is enforced where
19
+ * the pin actually lives: the caller's `PinnedEmbedding`.
20
+ *
21
+ * Correctness here is expected to match the in-memory adapter, but nothing checks
22
+ * that: this adapter is not gate-covered, and its SQL path runs only on a machine
23
+ * where someone brought the database up themselves.
24
+ */
25
+ import { SearchHit, StoreRecord } from './stores.js';
26
+ import type { StoreKind } from './types.js';
27
+ /**
28
+ * Resolve an `env:NAME` reference to the variable's value.
29
+ *
30
+ * An `env:` reference names a variable, not an alias: nothing here reaches the model
31
+ * catalog, so resolving it at run time cannot silently change which store a run wrote
32
+ * to.
33
+ */
34
+ export declare function resolveUri(uri: string | null | undefined): string;
35
+ /** pgvector's text input format, so its own package is not a dependency. */
36
+ export declare function vectorLiteral(vector: readonly number[]): string;
37
+ /** Accept either a driver-returned sequence or pgvector's text form. */
38
+ export declare function parseVector(value: unknown): readonly number[];
39
+ /** A single-table store: one row per chunk, keyed by content hash. */
40
+ export declare class PgVectorStore {
41
+ private readonly _uri;
42
+ private readonly _dimensions;
43
+ private _connection;
44
+ private _closed;
45
+ constructor(options: {
46
+ readonly uri: string | null;
47
+ readonly dimensions?: number | null;
48
+ });
49
+ get kind(): StoreKind;
50
+ upsert(records: readonly StoreRecord[]): Promise<number>;
51
+ search(vector: readonly number[], options: {
52
+ readonly topK: number;
53
+ readonly metric: 'cosine' | 'dot' | 'l2';
54
+ }): Promise<readonly SearchHit[]>;
55
+ corpus(): Promise<readonly StoreRecord[]>;
56
+ close(): Promise<void>;
57
+ private connect;
58
+ private ensureSchema;
59
+ private params;
60
+ private record;
61
+ }
62
+ //# sourceMappingURL=pgvector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pgvector.d.ts","sourceRoot":"","sources":["../../src/retrieval/pgvector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAuF5C;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAkBjE;AAiBD,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAE/D;AAED,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAU7D;AAWD,sEAAsE;AACtE,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgB;IAC5C,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,OAAO,CAAS;IAExB,YAAY,OAAO,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAGxF;IAED,IAAI,IAAI,IAAI,SAAS,CAEpB;IAEK,MAAM,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB7D;IAEK,MAAM,CACV,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,OAAO,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK,GAAG,IAAI,CAAA;KAAE,GAC3E,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAW/B;IAEK,MAAM,IAAI,OAAO,CAAC,SAAS,WAAW,EAAE,CAAC,CAI9C;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAO3B;YAEa,OAAO;YAgBP,YAAY;IAK1B,OAAO,CAAC,MAAM;IAed,OAAO,CAAC,MAAM;CAef"}
@@ -0,0 +1,262 @@
1
+ /**
2
+ * A pgvector-backed store, provisioned locally and never touched by CI.
3
+ *
4
+ * The driver is optional, so this module must be importable without it. Nothing at
5
+ * module scope imports it; the load happens inside {@link loadDriver} on first use,
6
+ * and a missing driver becomes a {@link ConfigurationError} that names the package to
7
+ * install. Importing the retrieval package therefore cannot fail because a database
8
+ * dependency is absent, which is what lets the default dependency set stay unchanged
9
+ * and what keeps every required gate on the in-memory store.
10
+ *
11
+ * Two consequences of that choice are deliberate and visible:
12
+ *
13
+ * - The driver arrives as an untyped value, so `unknown` reaches this file. It is
14
+ * confined to this one adapter rather than spreading a suppressed import across the
15
+ * retrieval package.
16
+ * - Every statement is a fixed string with positional placeholders. The embedding
17
+ * column is declared dimension-less rather than `vector(1536)`, so no computed
18
+ * identifier is ever interpolated into SQL, and the pinned width is enforced where
19
+ * the pin actually lives: the caller's `PinnedEmbedding`.
20
+ *
21
+ * Correctness here is expected to match the in-memory adapter, but nothing checks
22
+ * that: this adapter is not gate-covered, and its SQL path runs only on a machine
23
+ * where someone brought the database up themselves.
24
+ */
25
+ import { createRequire } from 'node:module';
26
+ import { ConfigurationError, ProviderError } from '../errors.js';
27
+ import { dumpsSorted, repr } from '../internal/json.js';
28
+ import { SearchHit, StoreRecord } from './stores.js';
29
+ import { Chunk } from './types.js';
30
+ const ENV_PREFIX = 'env:';
31
+ const DRIVER = 'pg';
32
+ const CREATE_EXTENSION = 'CREATE EXTENSION IF NOT EXISTS vector';
33
+ const CREATE_TABLE = `
34
+ CREATE TABLE IF NOT EXISTS aid_chunks (
35
+ chunk_id text PRIMARY KEY,
36
+ doc_id text NOT NULL,
37
+ uri text NOT NULL,
38
+ chunk_index integer NOT NULL,
39
+ start_offset integer NOT NULL,
40
+ end_offset integer NOT NULL,
41
+ body text NOT NULL,
42
+ metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
43
+ embedding vector NOT NULL
44
+ )
45
+ `;
46
+ const UPSERT = `
47
+ INSERT INTO aid_chunks (
48
+ chunk_id, doc_id, uri, chunk_index, start_offset, end_offset, body, metadata, embedding
49
+ ) VALUES (
50
+ $1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9::vector
51
+ )
52
+ ON CONFLICT (chunk_id) DO UPDATE SET
53
+ doc_id = EXCLUDED.doc_id,
54
+ uri = EXCLUDED.uri,
55
+ chunk_index = EXCLUDED.chunk_index,
56
+ start_offset = EXCLUDED.start_offset,
57
+ end_offset = EXCLUDED.end_offset,
58
+ body = EXCLUDED.body,
59
+ metadata = EXCLUDED.metadata,
60
+ embedding = EXCLUDED.embedding
61
+ `;
62
+ const COLUMNS = 'chunk_id, doc_id, uri, chunk_index, start_offset, end_offset, body, metadata, embedding';
63
+ const CORPUS = `SELECT ${COLUMNS} FROM aid_chunks ORDER BY chunk_id`;
64
+ // `<=>` is cosine distance, `<#>` is negative inner product and `<->` is L2 distance.
65
+ // Each is rewritten into "higher is better" so callers see one orientation, matching
66
+ // `stores.similarity`. The tie-break on `chunk_id` matches the in-memory adapter too:
67
+ // equal scores must rank identically on both.
68
+ //
69
+ // Every statement is spelled out in full rather than assembled from a column list, so
70
+ // that no statement is ever *constructed*: the only values that reach SQL are bound
71
+ // parameters.
72
+ const SEARCH = {
73
+ cosine: `SELECT ${COLUMNS}, 1 - (embedding <=> $1::vector) AS score FROM aid_chunks ` +
74
+ 'ORDER BY embedding <=> $1::vector, chunk_id LIMIT $2',
75
+ dot: `SELECT ${COLUMNS}, -(embedding <#> $1::vector) AS score FROM aid_chunks ` +
76
+ 'ORDER BY embedding <#> $1::vector, chunk_id LIMIT $2',
77
+ l2: `SELECT ${COLUMNS}, -(embedding <-> $1::vector) AS score FROM aid_chunks ` +
78
+ 'ORDER BY embedding <-> $1::vector, chunk_id LIMIT $2',
79
+ };
80
+ const requireFromHere = createRequire(import.meta.url);
81
+ /** Import the optional driver, or explain how to install it. */
82
+ function loadDriver() {
83
+ try {
84
+ return requireFromHere(DRIVER);
85
+ }
86
+ catch {
87
+ throw new ConfigurationError('the pgvector store needs its driver; install it with `pnpm add pg` in the ' +
88
+ 'generated app (the default runtime install omits it)');
89
+ }
90
+ }
91
+ /**
92
+ * Resolve an `env:NAME` reference to the variable's value.
93
+ *
94
+ * An `env:` reference names a variable, not an alias: nothing here reaches the model
95
+ * catalog, so resolving it at run time cannot silently change which store a run wrote
96
+ * to.
97
+ */
98
+ export function resolveUri(uri) {
99
+ if (uri === null || uri === undefined) {
100
+ throw new ConfigurationError('the pgvector store requires a uri');
101
+ }
102
+ if (!uri.startsWith(ENV_PREFIX)) {
103
+ return uri;
104
+ }
105
+ const name = uri.slice(ENV_PREFIX.length);
106
+ if (name.length === 0) {
107
+ throw new ConfigurationError(`store uri ${repr(uri)} names an empty environment variable`);
108
+ }
109
+ const value = process.env[name];
110
+ if (value === undefined) {
111
+ throw new ConfigurationError(`store uri ${repr(uri)} refers to environment variable ${repr(name)}, which is unset`);
112
+ }
113
+ return value;
114
+ }
115
+ /**
116
+ * A float as Python's `repr` spells it, so the literal form matches the Python adapter.
117
+ *
118
+ * `String(-0)` is `'0'`, but `repr(-0.0)` is `'-0.0'`; the sign is part of the literal
119
+ * Python emits, and a bare `0.0` would be a visible divergence. The very large
120
+ * magnitudes where Python's shortest-repr algorithm switches to exponent notation
121
+ * earlier than `Number#toString` are not reproduced -- no embedding component reaches
122
+ * them, and reproducing the algorithm would be a lie dressed as fidelity.
123
+ */
124
+ function floatRepr(value) {
125
+ if (Object.is(value, -0))
126
+ return '-0.0';
127
+ const text = String(value);
128
+ return /[.eEn]/.test(text) ? text : `${text}.0`;
129
+ }
130
+ /** pgvector's text input format, so its own package is not a dependency. */
131
+ export function vectorLiteral(vector) {
132
+ return `[${vector.map((value) => floatRepr(value)).join(',')}]`;
133
+ }
134
+ /** Accept either a driver-returned sequence or pgvector's text form. */
135
+ export function parseVector(value) {
136
+ if (typeof value === 'string') {
137
+ const stripped = value.trim().replace(/^\[/, '').replace(/\]$/, '');
138
+ if (stripped.length === 0)
139
+ return [];
140
+ return stripped.split(',').map((part) => Number.parseFloat(part));
141
+ }
142
+ if (Array.isArray(value)) {
143
+ return value.map((item) => Number(item));
144
+ }
145
+ throw new ConfigurationError('cannot read a vector: expected a sequence or its text form');
146
+ }
147
+ function metadataFrom(value) {
148
+ if (typeof value === 'string') {
149
+ if (value.length === 0)
150
+ return {};
151
+ const parsed = JSON.parse(value);
152
+ return (parsed ?? {});
153
+ }
154
+ return (value ?? {});
155
+ }
156
+ /** A single-table store: one row per chunk, keyed by content hash. */
157
+ export class PgVectorStore {
158
+ _uri;
159
+ _dimensions;
160
+ _connection = null;
161
+ _closed = false;
162
+ constructor(options) {
163
+ this._uri = resolveUri(options.uri);
164
+ this._dimensions = options.dimensions ?? null;
165
+ }
166
+ get kind() {
167
+ return 'pgvector';
168
+ }
169
+ async upsert(records) {
170
+ if (this._dimensions !== null) {
171
+ for (const record of records) {
172
+ if (record.vector.length !== this._dimensions) {
173
+ throw new ConfigurationError(`store is pinned to ${this._dimensions} dimensions but a record carries ` +
174
+ `${record.vector.length}`);
175
+ }
176
+ }
177
+ }
178
+ if (records.length === 0)
179
+ return 0;
180
+ const connection = await this.connect();
181
+ for (const record of records) {
182
+ await connection.query(UPSERT, this.params(record));
183
+ }
184
+ return records.length;
185
+ }
186
+ async search(vector, options) {
187
+ if (options.topK < 1) {
188
+ throw new ConfigurationError('top_k must be at least 1');
189
+ }
190
+ const statement = SEARCH[options.metric];
191
+ if (statement === undefined) {
192
+ throw new ConfigurationError(`pgvector cannot rank by ${repr(options.metric)}`);
193
+ }
194
+ const connection = await this.connect();
195
+ const { rows } = await connection.query(statement, [vectorLiteral(vector), options.topK]);
196
+ return rows.map((row) => new SearchHit({ record: this.record(row), score: Number(row[9]) }));
197
+ }
198
+ async corpus() {
199
+ const connection = await this.connect();
200
+ const { rows } = await connection.query(CORPUS);
201
+ return rows.map((row) => this.record(row));
202
+ }
203
+ async close() {
204
+ if (this._closed)
205
+ return;
206
+ this._closed = true;
207
+ if (this._connection !== null) {
208
+ await this._connection.end();
209
+ this._connection = null;
210
+ }
211
+ }
212
+ async connect() {
213
+ if (this._closed) {
214
+ throw new ConfigurationError('this store has been closed');
215
+ }
216
+ if (this._connection === null) {
217
+ const driver = loadDriver();
218
+ try {
219
+ this._connection = new driver.Client({ connectionString: this._uri });
220
+ }
221
+ catch (error) {
222
+ throw new ProviderError(`cannot connect to the pgvector store: ${String(error)}`);
223
+ }
224
+ await this.ensureSchema(this._connection);
225
+ }
226
+ return this._connection;
227
+ }
228
+ async ensureSchema(connection) {
229
+ await connection.query(CREATE_EXTENSION);
230
+ await connection.query(CREATE_TABLE);
231
+ }
232
+ params(record) {
233
+ const chunk = record.chunk;
234
+ return [
235
+ chunk.chunkId,
236
+ chunk.docId,
237
+ chunk.uri,
238
+ chunk.index,
239
+ chunk.start,
240
+ chunk.end,
241
+ chunk.text,
242
+ dumpsSorted(chunk.metadata),
243
+ vectorLiteral(record.vector),
244
+ ];
245
+ }
246
+ record(row) {
247
+ return new StoreRecord({
248
+ chunk: new Chunk({
249
+ chunkId: String(row[0]),
250
+ docId: String(row[1]),
251
+ uri: String(row[2]),
252
+ index: Number(row[3]),
253
+ start: Number(row[4]),
254
+ end: Number(row[5]),
255
+ text: String(row[6]),
256
+ metadata: metadataFrom(row[7]),
257
+ }),
258
+ vector: parseVector(row[8]),
259
+ });
260
+ }
261
+ }
262
+ //# sourceMappingURL=pgvector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pgvector.js","sourceRoot":"","sources":["../../src/retrieval/pgvector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
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 { RetrievedItem } from './citations.js';
21
+ import type { RerankSpec } from './types.js';
22
+ /**
23
+ * How much of `query` the passage actually covers, in `[0, 1]`.
24
+ *
25
+ * Query-term coverage, not term frequency: for "which passages answer this", a
26
+ * passage containing each distinct query term once is as good a candidate as one
27
+ * repeating a term, and rewarding repetition is how a keyword-stuffed chunk wins. An
28
+ * exact phrase match breaks ties toward the passage quoting the query.
29
+ */
30
+ export declare function lexicalScore(query: string, text: string): number;
31
+ /** Reorder candidates for a query, deterministically. */
32
+ export interface Reranker {
33
+ readonly name: string;
34
+ rerank(query: string, items: readonly RetrievedItem[], init: {
35
+ readonly topN: number;
36
+ }): Promise<readonly RetrievedItem[]>;
37
+ }
38
+ /** Coverage-based reranking, with ties broken on chunk id. */
39
+ export declare class LexicalReranker implements Reranker {
40
+ private readonly _name;
41
+ constructor(init?: {
42
+ readonly name?: string;
43
+ });
44
+ get name(): string;
45
+ rerank(query: string, items: readonly RetrievedItem[], init: {
46
+ readonly topN: number;
47
+ }): Promise<readonly RetrievedItem[]>;
48
+ }
49
+ /**
50
+ * The reranker a retriever's `rerank` block asks for, if any.
51
+ *
52
+ * `rerank.model` is free-form in the IR, and Phase 1 ships exactly one
53
+ * implementation. A declared model outside the lexical family is refused rather than
54
+ * quietly served by {@link LexicalReranker}, for the same reason an unimplemented
55
+ * source kind or store kind is refused: a retriever that appears to rerank with a
56
+ * cross-encoder it never called is worse than one that says it cannot. The guard
57
+ * matches on the name because the name is the only signal the IR gives; the lexical
58
+ * family is what this runtime can honestly claim.
59
+ */
60
+ export declare function rerankerFor(spec: RerankSpec | null): Reranker | null;
61
+ //# sourceMappingURL=rerank.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rerank.d.ts","sourceRoot":"","sources":["../../src/retrieval/rerank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,EAAQ,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBhE;AAED,yDAAyD;AACzD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,MAAM,CACJ,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAC9B,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAAC;CACtC;AAED,8DAA8D;AAC9D,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B,YAAY,IAAI,GAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAO,EAEhD;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAEK,MAAM,CACV,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAC9B,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CA2BnC;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,CASpE"}