@seanhogg/builderforce-memory 2026.7.12 → 2026.9.27

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 (223) hide show
  1. package/README.md +10 -0
  2. package/dist/bridges/AnthropicBridge.d.ts +9 -1
  3. package/dist/bridges/AnthropicBridge.d.ts.map +1 -1
  4. package/dist/bridges/AnthropicBridge.js +58 -2
  5. package/dist/bridges/AnthropicBridge.js.map +1 -1
  6. package/dist/bridges/CachingBridge.d.ts +9 -1
  7. package/dist/bridges/CachingBridge.d.ts.map +1 -1
  8. package/dist/bridges/CachingBridge.js +24 -1
  9. package/dist/bridges/CachingBridge.js.map +1 -1
  10. package/dist/bridges/OpenAIBridge.d.ts +4 -1
  11. package/dist/bridges/OpenAIBridge.d.ts.map +1 -1
  12. package/dist/bridges/OpenAIBridge.js +40 -2
  13. package/dist/bridges/OpenAIBridge.js.map +1 -1
  14. package/dist/bridges/SemanticCachingBridge.d.ts +8 -1
  15. package/dist/bridges/SemanticCachingBridge.d.ts.map +1 -1
  16. package/dist/bridges/SemanticCachingBridge.js +26 -1
  17. package/dist/bridges/SemanticCachingBridge.js.map +1 -1
  18. package/dist/bridges/TransformerBridge.d.ts +13 -0
  19. package/dist/bridges/TransformerBridge.d.ts.map +1 -1
  20. package/dist/bridges/VertexAIBridge.d.ts +102 -0
  21. package/dist/bridges/VertexAIBridge.d.ts.map +1 -0
  22. package/dist/bridges/VertexAIBridge.js +224 -0
  23. package/dist/bridges/VertexAIBridge.js.map +1 -0
  24. package/dist/bridges/index.d.ts +3 -1
  25. package/dist/bridges/index.d.ts.map +1 -1
  26. package/dist/bridges/index.js +1 -0
  27. package/dist/bridges/index.js.map +1 -1
  28. package/dist/eval/EvalHarness.d.ts +37 -0
  29. package/dist/eval/EvalHarness.d.ts.map +1 -0
  30. package/dist/eval/EvalHarness.js +178 -0
  31. package/dist/eval/EvalHarness.js.map +1 -0
  32. package/dist/eval/graders.d.ts +76 -0
  33. package/dist/eval/graders.d.ts.map +1 -0
  34. package/dist/eval/graders.js +168 -0
  35. package/dist/eval/graders.js.map +1 -0
  36. package/dist/eval/index.d.ts +26 -0
  37. package/dist/eval/index.d.ts.map +1 -0
  38. package/dist/eval/index.js +26 -0
  39. package/dist/eval/index.js.map +1 -0
  40. package/dist/eval/types.d.ts +97 -0
  41. package/dist/eval/types.d.ts.map +1 -0
  42. package/dist/eval/types.js +5 -0
  43. package/dist/eval/types.js.map +1 -0
  44. package/dist/evermind/contract.d.ts +40 -0
  45. package/dist/evermind/contract.d.ts.map +1 -0
  46. package/dist/evermind/contract.js +13 -0
  47. package/dist/evermind/contract.js.map +1 -0
  48. package/dist/evermind/index.d.ts +15 -0
  49. package/dist/evermind/index.d.ts.map +1 -0
  50. package/dist/evermind/index.js +4 -0
  51. package/dist/evermind/index.js.map +1 -0
  52. package/dist/evermind/memoryBlock.d.ts +7 -0
  53. package/dist/evermind/memoryBlock.d.ts.map +1 -0
  54. package/dist/evermind/memoryBlock.js +37 -0
  55. package/dist/evermind/memoryBlock.js.map +1 -0
  56. package/dist/evermind/recall.d.ts +55 -0
  57. package/dist/evermind/recall.d.ts.map +1 -0
  58. package/dist/evermind/recall.js +105 -0
  59. package/dist/evermind/recall.js.map +1 -0
  60. package/dist/index.d.ts +18 -3
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +14 -1
  63. package/dist/index.js.map +1 -1
  64. package/dist/ingest/IngestionPipeline.d.ts +95 -0
  65. package/dist/ingest/IngestionPipeline.d.ts.map +1 -0
  66. package/dist/ingest/IngestionPipeline.js +295 -0
  67. package/dist/ingest/IngestionPipeline.js.map +1 -0
  68. package/dist/ingest/index.d.ts +10 -0
  69. package/dist/ingest/index.d.ts.map +1 -0
  70. package/dist/ingest/index.js +8 -0
  71. package/dist/ingest/index.js.map +1 -0
  72. package/dist/ingest/parsers.d.ts +53 -0
  73. package/dist/ingest/parsers.d.ts.map +1 -0
  74. package/dist/ingest/parsers.js +306 -0
  75. package/dist/ingest/parsers.js.map +1 -0
  76. package/dist/ingest/types.d.ts +114 -0
  77. package/dist/ingest/types.d.ts.map +1 -0
  78. package/dist/ingest/types.js +19 -0
  79. package/dist/ingest/types.js.map +1 -0
  80. package/dist/memory/MemoryStore.d.ts +33 -0
  81. package/dist/memory/MemoryStore.d.ts.map +1 -1
  82. package/dist/memory/MemoryStore.js +29 -3
  83. package/dist/memory/MemoryStore.js.map +1 -1
  84. package/dist/memory/index.d.ts +1 -1
  85. package/dist/memory/index.d.ts.map +1 -1
  86. package/dist/orchestration/AgentGraph.d.ts +104 -0
  87. package/dist/orchestration/AgentGraph.d.ts.map +1 -0
  88. package/dist/orchestration/AgentGraph.js +364 -0
  89. package/dist/orchestration/AgentGraph.js.map +1 -0
  90. package/dist/orchestration/checkpoint.d.ts +58 -0
  91. package/dist/orchestration/checkpoint.d.ts.map +1 -0
  92. package/dist/orchestration/checkpoint.js +92 -0
  93. package/dist/orchestration/checkpoint.js.map +1 -0
  94. package/dist/orchestration/index.d.ts +14 -0
  95. package/dist/orchestration/index.d.ts.map +1 -0
  96. package/dist/orchestration/index.js +10 -0
  97. package/dist/orchestration/index.js.map +1 -0
  98. package/dist/orchestration/patterns.d.ts +159 -0
  99. package/dist/orchestration/patterns.d.ts.map +1 -0
  100. package/dist/orchestration/patterns.js +371 -0
  101. package/dist/orchestration/patterns.js.map +1 -0
  102. package/dist/orchestration/types.d.ts +146 -0
  103. package/dist/orchestration/types.d.ts.map +1 -0
  104. package/dist/orchestration/types.js +20 -0
  105. package/dist/orchestration/types.js.map +1 -0
  106. package/dist/rag/EnterpriseRetriever.d.ts +114 -0
  107. package/dist/rag/EnterpriseRetriever.d.ts.map +1 -0
  108. package/dist/rag/EnterpriseRetriever.js +240 -0
  109. package/dist/rag/EnterpriseRetriever.js.map +1 -0
  110. package/dist/rag/index.d.ts +6 -0
  111. package/dist/rag/index.d.ts.map +1 -0
  112. package/dist/rag/index.js +5 -0
  113. package/dist/rag/index.js.map +1 -0
  114. package/dist/retrieval/bm25.d.ts +48 -1
  115. package/dist/retrieval/bm25.d.ts.map +1 -1
  116. package/dist/retrieval/bm25.js +59 -13
  117. package/dist/retrieval/bm25.js.map +1 -1
  118. package/dist/retrieval/index.d.ts +2 -2
  119. package/dist/retrieval/index.d.ts.map +1 -1
  120. package/dist/retrieval/index.js +1 -1
  121. package/dist/retrieval/index.js.map +1 -1
  122. package/dist/telemetry/InstrumentedBridge.d.ts +62 -0
  123. package/dist/telemetry/InstrumentedBridge.d.ts.map +1 -0
  124. package/dist/telemetry/InstrumentedBridge.js +120 -0
  125. package/dist/telemetry/InstrumentedBridge.js.map +1 -0
  126. package/dist/telemetry/MetricsRegistry.d.ts +88 -0
  127. package/dist/telemetry/MetricsRegistry.d.ts.map +1 -0
  128. package/dist/telemetry/MetricsRegistry.js +167 -0
  129. package/dist/telemetry/MetricsRegistry.js.map +1 -0
  130. package/dist/telemetry/Tracer.d.ts +137 -0
  131. package/dist/telemetry/Tracer.d.ts.map +1 -0
  132. package/dist/telemetry/Tracer.js +244 -0
  133. package/dist/telemetry/Tracer.js.map +1 -0
  134. package/dist/telemetry/exporters.d.ts +68 -0
  135. package/dist/telemetry/exporters.d.ts.map +1 -0
  136. package/dist/telemetry/exporters.js +145 -0
  137. package/dist/telemetry/exporters.js.map +1 -0
  138. package/dist/telemetry/index.d.ts +19 -0
  139. package/dist/telemetry/index.d.ts.map +1 -0
  140. package/dist/telemetry/index.js +12 -0
  141. package/dist/telemetry/index.js.map +1 -0
  142. package/dist/telemetry/pricing.d.ts +74 -0
  143. package/dist/telemetry/pricing.d.ts.map +1 -0
  144. package/dist/telemetry/pricing.js +98 -0
  145. package/dist/telemetry/pricing.js.map +1 -0
  146. package/dist/telemetry/traceparent.d.ts +50 -0
  147. package/dist/telemetry/traceparent.d.ts.map +1 -0
  148. package/dist/telemetry/traceparent.js +77 -0
  149. package/dist/telemetry/traceparent.js.map +1 -0
  150. package/dist/telemetry/types.d.ts +90 -0
  151. package/dist/telemetry/types.d.ts.map +1 -0
  152. package/dist/telemetry/types.js +17 -0
  153. package/dist/telemetry/types.js.map +1 -0
  154. package/dist/vectorstore/MemoryVectorStore.d.ts +72 -0
  155. package/dist/vectorstore/MemoryVectorStore.d.ts.map +1 -0
  156. package/dist/vectorstore/MemoryVectorStore.js +205 -0
  157. package/dist/vectorstore/MemoryVectorStore.js.map +1 -0
  158. package/dist/vectorstore/RestVectorStore.d.ts +79 -0
  159. package/dist/vectorstore/RestVectorStore.d.ts.map +1 -0
  160. package/dist/vectorstore/RestVectorStore.js +170 -0
  161. package/dist/vectorstore/RestVectorStore.js.map +1 -0
  162. package/dist/vectorstore/dialects.d.ts +101 -0
  163. package/dist/vectorstore/dialects.d.ts.map +1 -0
  164. package/dist/vectorstore/dialects.js +618 -0
  165. package/dist/vectorstore/dialects.js.map +1 -0
  166. package/dist/vectorstore/filter.d.ts +42 -0
  167. package/dist/vectorstore/filter.d.ts.map +1 -0
  168. package/dist/vectorstore/filter.js +132 -0
  169. package/dist/vectorstore/filter.js.map +1 -0
  170. package/dist/vectorstore/index.d.ts +15 -0
  171. package/dist/vectorstore/index.d.ts.map +1 -0
  172. package/dist/vectorstore/index.js +11 -0
  173. package/dist/vectorstore/index.js.map +1 -0
  174. package/dist/vectorstore/types.d.ts +151 -0
  175. package/dist/vectorstore/types.d.ts.map +1 -0
  176. package/dist/vectorstore/types.js +30 -0
  177. package/dist/vectorstore/types.js.map +1 -0
  178. package/package.json +39 -5
  179. package/src/bridges/AnthropicBridge.ts +68 -3
  180. package/src/bridges/CachingBridge.ts +28 -2
  181. package/src/bridges/OpenAIBridge.ts +48 -3
  182. package/src/bridges/SemanticCachingBridge.ts +29 -2
  183. package/src/bridges/TransformerBridge.ts +16 -0
  184. package/src/bridges/VertexAIBridge.ts +297 -0
  185. package/src/bridges/index.ts +3 -1
  186. package/src/eval/EvalHarness.ts +214 -0
  187. package/src/eval/graders.ts +218 -0
  188. package/src/eval/index.ts +26 -0
  189. package/src/eval/types.ts +107 -0
  190. package/src/evermind/contract.ts +39 -0
  191. package/src/evermind/index.ts +21 -0
  192. package/src/evermind/memoryBlock.ts +38 -0
  193. package/src/evermind/recall.ts +122 -0
  194. package/src/index.ts +232 -0
  195. package/src/ingest/IngestionPipeline.ts +378 -0
  196. package/src/ingest/index.ts +46 -0
  197. package/src/ingest/parsers.ts +318 -0
  198. package/src/ingest/types.ts +116 -0
  199. package/src/memory/MemoryStore.ts +55 -3
  200. package/src/memory/index.ts +1 -1
  201. package/src/orchestration/AgentGraph.ts +462 -0
  202. package/src/orchestration/checkpoint.ts +129 -0
  203. package/src/orchestration/index.ts +63 -0
  204. package/src/orchestration/patterns.ts +532 -0
  205. package/src/orchestration/types.ts +128 -0
  206. package/src/rag/EnterpriseRetriever.ts +348 -0
  207. package/src/rag/index.ts +18 -0
  208. package/src/retrieval/bm25.ts +71 -13
  209. package/src/retrieval/index.ts +2 -2
  210. package/src/telemetry/InstrumentedBridge.ts +152 -0
  211. package/src/telemetry/MetricsRegistry.ts +263 -0
  212. package/src/telemetry/Tracer.ts +310 -0
  213. package/src/telemetry/exporters.ts +187 -0
  214. package/src/telemetry/index.ts +56 -0
  215. package/src/telemetry/pricing.ts +129 -0
  216. package/src/telemetry/traceparent.ts +89 -0
  217. package/src/telemetry/types.ts +105 -0
  218. package/src/vectorstore/MemoryVectorStore.ts +250 -0
  219. package/src/vectorstore/RestVectorStore.ts +236 -0
  220. package/src/vectorstore/dialects.ts +702 -0
  221. package/src/vectorstore/filter.ts +148 -0
  222. package/src/vectorstore/index.ts +53 -0
  223. package/src/vectorstore/types.ts +149 -0
@@ -0,0 +1,306 @@
1
+ /**
2
+ * ingest/parsers.ts — format handlers, as a registry.
3
+ *
4
+ * Each parser turns a source into sections and recovers whatever STRUCTURE the
5
+ * format carries, because structure that survives parsing becomes filterable
6
+ * metadata, and metadata is what makes retrieval precise:
7
+ *
8
+ * • Markdown keeps its heading path, so a chunk knows it lives under
9
+ * "Security › Data retention" and a citation can say so.
10
+ * • Rows keep every typed column, so `status = 'open'` is a database predicate
11
+ * rather than something the embedding has to imply.
12
+ * • JSON keeps its pointer, so a value can be traced back to its exact location.
13
+ *
14
+ * A parser that returned only text would throw all of that away and force the
15
+ * retriever to recover it statistically — the single most common reason a RAG
16
+ * pilot answers plausibly and cites nothing verifiable.
17
+ */
18
+ const textOf = (source) => source.content.kind === 'text' ? source.content.text : '';
19
+ const mediaTypeOf = (source) => source.content.kind === 'text' ? (source.content.mediaType ?? 'text/plain').toLowerCase() : '';
20
+ // ── structured rows ───────────────────────────────────────────────────────────
21
+ /**
22
+ * Serialises a row as `field: value` lines.
23
+ *
24
+ * Field names are kept in the text on purpose: an embedding of `"status: open"`
25
+ * sits near a question about open items, whereas a bare `"open"` sits near
26
+ * nothing useful. The typed values are ALSO emitted as metadata, so the same fact
27
+ * is both semantically searchable and exactly filterable.
28
+ */
29
+ export function serializeRow(row) {
30
+ return Object.entries(row)
31
+ .filter(([, v]) => v !== null && v !== undefined && v !== '')
32
+ .map(([k, v]) => `${k}: ${Array.isArray(v) ? v.join(', ') : String(v)}`)
33
+ .join('\n');
34
+ }
35
+ export const rowsParser = {
36
+ id: 'rows',
37
+ accepts: (source) => source.content.kind === 'rows',
38
+ parse: (source) => {
39
+ if (source.content.kind !== 'rows')
40
+ return [];
41
+ const { rows, rowIdField } = source.content;
42
+ return rows.map((row, index) => {
43
+ const metadata = { ...row };
44
+ metadata['rowIndex'] = index;
45
+ if (rowIdField && row[rowIdField] !== undefined) {
46
+ metadata['rowId'] = String(row[rowIdField]);
47
+ }
48
+ return { text: serializeRow(row), metadata };
49
+ });
50
+ },
51
+ };
52
+ // ── CSV ───────────────────────────────────────────────────────────────────────
53
+ /**
54
+ * RFC 4180 subset: quoted fields, doubled quotes, embedded newlines and commas.
55
+ * Enough for the exports enterprises actually hand over, without a dependency.
56
+ */
57
+ export function parseCsv(text, delimiter = ',') {
58
+ const rows = [];
59
+ let field = '';
60
+ let record = [];
61
+ let quoted = false;
62
+ for (let i = 0; i < text.length; i++) {
63
+ const ch = text[i];
64
+ if (quoted) {
65
+ if (ch === '"') {
66
+ if (text[i + 1] === '"') {
67
+ field += '"';
68
+ i++;
69
+ }
70
+ else
71
+ quoted = false;
72
+ }
73
+ else
74
+ field += ch;
75
+ continue;
76
+ }
77
+ if (ch === '"') {
78
+ quoted = true;
79
+ continue;
80
+ }
81
+ if (ch === delimiter) {
82
+ record.push(field);
83
+ field = '';
84
+ continue;
85
+ }
86
+ if (ch === '\n' || ch === '\r') {
87
+ if (ch === '\r' && text[i + 1] === '\n')
88
+ i++;
89
+ record.push(field);
90
+ rows.push(record);
91
+ record = [];
92
+ field = '';
93
+ continue;
94
+ }
95
+ field += ch;
96
+ }
97
+ if (field !== '' || record.length > 0) {
98
+ record.push(field);
99
+ rows.push(record);
100
+ }
101
+ const header = rows.shift();
102
+ if (!header)
103
+ return [];
104
+ return rows
105
+ .filter((r) => r.some((cell) => cell.trim() !== ''))
106
+ .map((cells) => {
107
+ const row = {};
108
+ header.forEach((name, i) => {
109
+ row[name.trim()] = coerce(cells[i] ?? '');
110
+ });
111
+ return row;
112
+ });
113
+ }
114
+ /**
115
+ * Numbers and booleans are recovered from CSV text so range filters work.
116
+ * A value that merely *looks* numeric but has a leading zero (an account number,
117
+ * a zip code) stays a string — coercing it would silently destroy the identifier.
118
+ */
119
+ function coerce(raw) {
120
+ const value = raw.trim();
121
+ if (value === '')
122
+ return '';
123
+ if (value === 'true')
124
+ return true;
125
+ if (value === 'false')
126
+ return false;
127
+ if (/^-?(0|[1-9]\d*)(\.\d+)?$/.test(value)) {
128
+ const n = Number(value);
129
+ if (Number.isFinite(n))
130
+ return n;
131
+ }
132
+ return value;
133
+ }
134
+ export const csvParser = {
135
+ id: 'csv',
136
+ accepts: (source) => {
137
+ const type = mediaTypeOf(source);
138
+ return type.includes('csv') || type.includes('tab-separated');
139
+ },
140
+ parse: (source) => {
141
+ const delimiter = mediaTypeOf(source).includes('tab-separated') ? '\t' : ',';
142
+ const rows = parseCsv(textOf(source), delimiter);
143
+ return rowsParser.parse({ ...source, content: { kind: 'rows', rows } });
144
+ },
145
+ };
146
+ // ── JSON ──────────────────────────────────────────────────────────────────────
147
+ /**
148
+ * An array of objects is treated as rows (the common export shape); anything else
149
+ * is flattened to leaf paths so a value keeps its JSON pointer.
150
+ */
151
+ export const jsonParser = {
152
+ id: 'json',
153
+ accepts: (source) => mediaTypeOf(source).includes('json'),
154
+ parse: (source) => {
155
+ let parsed;
156
+ try {
157
+ parsed = JSON.parse(textOf(source));
158
+ }
159
+ catch {
160
+ // Malformed JSON is still text worth indexing; degrading beats dropping
161
+ // the document, and the parser name on the chunk records what happened.
162
+ return plainTextParser.parse(source);
163
+ }
164
+ if (Array.isArray(parsed) && parsed.every((v) => v && typeof v === 'object' && !Array.isArray(v))) {
165
+ return rowsParser.parse({
166
+ ...source,
167
+ content: { kind: 'rows', rows: parsed },
168
+ });
169
+ }
170
+ const leaves = flatten(parsed, '');
171
+ if (leaves.length === 0)
172
+ return [];
173
+ return [{
174
+ text: leaves.map(([path, value]) => `${path}: ${value}`).join('\n'),
175
+ metadata: { leafCount: leaves.length },
176
+ }];
177
+ },
178
+ };
179
+ function flatten(value, path, out = []) {
180
+ if (value === null || typeof value !== 'object') {
181
+ out.push([path || '/', String(value)]);
182
+ return out;
183
+ }
184
+ if (Array.isArray(value)) {
185
+ value.forEach((v, i) => flatten(v, `${path}/${i}`, out));
186
+ return out;
187
+ }
188
+ for (const [key, v] of Object.entries(value)) {
189
+ flatten(v, `${path}/${key}`, out);
190
+ }
191
+ return out;
192
+ }
193
+ // ── Markdown ──────────────────────────────────────────────────────────────────
194
+ export const markdownParser = {
195
+ id: 'markdown',
196
+ accepts: (source) => {
197
+ const type = mediaTypeOf(source);
198
+ return type.includes('markdown') || type.includes('/md');
199
+ },
200
+ parse: (source) => {
201
+ const lines = textOf(source).split('\n');
202
+ const sections = [];
203
+ // Heading level -> text, so a chunk carries its full breadcrumb rather than
204
+ // only its nearest heading.
205
+ const path = [];
206
+ let buffer = [];
207
+ const flush = () => {
208
+ const text = buffer.join('\n').trim();
209
+ buffer = [];
210
+ if (!text)
211
+ return;
212
+ const metadata = {};
213
+ if (path.length) {
214
+ metadata['headingPath'] = path.join(' › ');
215
+ metadata['heading'] = path[path.length - 1];
216
+ metadata['headingDepth'] = path.length;
217
+ }
218
+ sections.push({ text, metadata });
219
+ };
220
+ let inFence = false;
221
+ for (const line of lines) {
222
+ if (/^\s*```/.test(line))
223
+ inFence = !inFence;
224
+ const heading = inFence ? null : /^(#{1,6})\s+(.*)$/.exec(line);
225
+ if (heading) {
226
+ flush();
227
+ const depth = heading[1].length;
228
+ path.length = Math.min(path.length, depth - 1);
229
+ path[depth - 1] = heading[2].trim();
230
+ path.length = depth;
231
+ continue;
232
+ }
233
+ buffer.push(line);
234
+ }
235
+ flush();
236
+ return sections;
237
+ },
238
+ };
239
+ // ── HTML ──────────────────────────────────────────────────────────────────────
240
+ export const htmlParser = {
241
+ id: 'html',
242
+ accepts: (source) => mediaTypeOf(source).includes('html') || mediaTypeOf(source).includes('xml'),
243
+ parse: (source) => {
244
+ const raw = textOf(source);
245
+ const titleMatch = /<title[^>]*>([\s\S]*?)<\/title>/i.exec(raw);
246
+ const text = raw
247
+ // script/style content is code, not prose — indexing it poisons recall.
248
+ .replace(/<(script|style)[^>]*>[\s\S]*?<\/\1>/gi, ' ')
249
+ .replace(/<!--[\s\S]*?-->/g, ' ')
250
+ .replace(/<\/(p|div|section|article|li|tr|h[1-6])>/gi, '\n')
251
+ .replace(/<br\s*\/?>/gi, '\n')
252
+ .replace(/<[^>]+>/g, ' ')
253
+ .replace(/&nbsp;/g, ' ')
254
+ .replace(/&amp;/g, '&')
255
+ .replace(/&lt;/g, '<')
256
+ .replace(/&gt;/g, '>')
257
+ .replace(/&quot;/g, '"')
258
+ .replace(/&#39;/g, "'")
259
+ .replace(/[ \t]+/g, ' ')
260
+ .replace(/\n{3,}/g, '\n\n')
261
+ .trim();
262
+ if (!text)
263
+ return [];
264
+ const metadata = {};
265
+ if (titleMatch?.[1])
266
+ metadata['htmlTitle'] = titleMatch[1].trim();
267
+ return [{ text, metadata }];
268
+ },
269
+ };
270
+ // ── plain text ────────────────────────────────────────────────────────────────
271
+ export const plainTextParser = {
272
+ id: 'text',
273
+ accepts: (source) => source.content.kind === 'text',
274
+ parse: (source) => {
275
+ const text = textOf(source).trim();
276
+ return text ? [{ text }] : [];
277
+ },
278
+ };
279
+ // ── registry ──────────────────────────────────────────────────────────────────
280
+ /** Order matters: the first parser that accepts a source handles it. */
281
+ export const BUILTIN_PARSERS = [
282
+ rowsParser,
283
+ csvParser,
284
+ jsonParser,
285
+ markdownParser,
286
+ htmlParser,
287
+ plainTextParser,
288
+ ];
289
+ export class ParserRegistry {
290
+ _parsers;
291
+ constructor(parsers = BUILTIN_PARSERS) {
292
+ this._parsers = [...parsers];
293
+ }
294
+ /** Registers a parser at the FRONT, so it can override a builtin. */
295
+ register(parser) {
296
+ this._parsers.unshift(parser);
297
+ return this;
298
+ }
299
+ resolve(source) {
300
+ return this._parsers.find((p) => p.accepts(source));
301
+ }
302
+ list() {
303
+ return this._parsers.map((p) => p.id);
304
+ }
305
+ }
306
+ //# sourceMappingURL=parsers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsers.js","sourceRoot":"","sources":["../../src/ingest/parsers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * ingest/types.ts — the ingestion vocabulary.
3
+ *
4
+ * The pipeline handles STRUCTURED and UNSTRUCTURED sources through one path, which
5
+ * is the point. A support ticket export (rows, typed columns, foreign keys) and a
6
+ * policy PDF's text both end up as chunks with typed metadata; the difference is
7
+ * which parser ran, not which pipeline. That is what makes a query like
8
+ * "summarise open P1 tickets about billing" answerable — `priority` and `status`
9
+ * survive as *filterable metadata* instead of being flattened into prose the
10
+ * embedding has to recover.
11
+ */
12
+ import type { MetadataRecord, MetadataValue } from '../vectorstore/types.js';
13
+ /** One row of a structured source (a DB result set, a CSV, a spreadsheet). */
14
+ export type StructuredRow = Record<string, MetadataValue>;
15
+ export type SourceContent = {
16
+ kind: 'text';
17
+ text: string;
18
+ mediaType?: string;
19
+ } | {
20
+ kind: 'rows';
21
+ rows: StructuredRow[];
22
+ rowIdField?: string;
23
+ };
24
+ export interface SourceDocument {
25
+ /** Stable id in the ORIGIN system. Re-ingesting the same id replaces its chunks. */
26
+ id: string;
27
+ content: SourceContent;
28
+ /** Owning tenant. Written to every chunk and enforced on every read. */
29
+ tenantId: string;
30
+ /**
31
+ * Principal ids permitted to retrieve this document. Defaults to `['*']`
32
+ * (tenant-public). Written to every chunk so ACL evaluation happens inside the
33
+ * database query, not after the fact.
34
+ */
35
+ acl?: string[];
36
+ /** Classification level; readers declare a ceiling via `AccessScope`. */
37
+ sensitivity?: number;
38
+ /** Arbitrary filterable metadata copied onto every chunk. */
39
+ metadata?: MetadataRecord;
40
+ /** Human-facing title, used in citations. */
41
+ title?: string;
42
+ /** Origin URI, used in citations. */
43
+ uri?: string;
44
+ }
45
+ /** A parser's output: a span of text plus whatever structure it recovered. */
46
+ export interface ParsedSection {
47
+ text: string;
48
+ /** Section-scoped metadata — heading path, row id, JSON pointer, … */
49
+ metadata?: MetadataRecord;
50
+ }
51
+ /**
52
+ * Parsers are registry entries, so a new format (PDF text layer, DOCX, a bespoke
53
+ * log) is registered rather than branched into the pipeline.
54
+ */
55
+ export interface DocumentParser {
56
+ readonly id: string;
57
+ /** True when this parser handles the source. First match in registry order wins. */
58
+ accepts(source: SourceDocument): boolean;
59
+ parse(source: SourceDocument): ParsedSection[];
60
+ }
61
+ /** Identity of one stored chunk, for incremental sync. */
62
+ export interface ChunkFingerprint {
63
+ id: string;
64
+ /** Content hash — an unchanged hash means the chunk need not be re-embedded. */
65
+ hash: string;
66
+ }
67
+ /**
68
+ * Records which chunks each source produced last time.
69
+ *
70
+ * Supplying one enables `diff` sync: only changed chunks are re-embedded (the
71
+ * expensive step) and only vanished chunks are deleted. Without it the pipeline
72
+ * falls back to `replace`, which is correct but re-embeds everything.
73
+ */
74
+ export interface IngestManifest {
75
+ get(sourceId: string): Promise<ChunkFingerprint[] | undefined>;
76
+ set(sourceId: string, fingerprints: ChunkFingerprint[]): Promise<void>;
77
+ delete(sourceId: string): Promise<void>;
78
+ }
79
+ /** Batch embedder. Batched because per-text calls are the classic N+1 of RAG. */
80
+ export type BatchEmbedder = (texts: string[]) => Promise<Float32Array[]>;
81
+ export type SyncStrategy =
82
+ /** Re-embed only changed chunks, delete only vanished ones. Needs a manifest. */
83
+ 'diff'
84
+ /** Delete the source's existing chunks, then write the new set. */
85
+ | 'replace'
86
+ /** Write without deleting anything — for append-only corpora. */
87
+ | 'append';
88
+ export interface IngestionReport {
89
+ documents: number;
90
+ sections: number;
91
+ chunks: number;
92
+ /** Chunks sent to the embedder — the cost driver. */
93
+ embedded: number;
94
+ upserted: number;
95
+ /** Chunks whose hash was unchanged and were skipped entirely. */
96
+ skippedUnchanged: number;
97
+ /** Chunks deleted because they no longer exist in the source. */
98
+ deletedStale: number;
99
+ failures: Array<{
100
+ sourceId: string;
101
+ error: string;
102
+ }>;
103
+ durationMs: number;
104
+ /** Trace id covering the whole run, when a tracer is attached. */
105
+ traceId?: string;
106
+ }
107
+ /** Metadata keys the pipeline reserves on every chunk it writes. */
108
+ export declare const SOURCE_ID_FIELD = "sourceId";
109
+ export declare const CHUNK_INDEX_FIELD = "chunkIndex";
110
+ export declare const CONTENT_HASH_FIELD = "contentHash";
111
+ export declare const TITLE_FIELD = "title";
112
+ export declare const URI_FIELD = "uri";
113
+ export declare const PARSER_FIELD = "parser";
114
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ingest/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * ingest/types.ts — the ingestion vocabulary.
3
+ *
4
+ * The pipeline handles STRUCTURED and UNSTRUCTURED sources through one path, which
5
+ * is the point. A support ticket export (rows, typed columns, foreign keys) and a
6
+ * policy PDF's text both end up as chunks with typed metadata; the difference is
7
+ * which parser ran, not which pipeline. That is what makes a query like
8
+ * "summarise open P1 tickets about billing" answerable — `priority` and `status`
9
+ * survive as *filterable metadata* instead of being flattened into prose the
10
+ * embedding has to recover.
11
+ */
12
+ /** Metadata keys the pipeline reserves on every chunk it writes. */
13
+ export const SOURCE_ID_FIELD = 'sourceId';
14
+ export const CHUNK_INDEX_FIELD = 'chunkIndex';
15
+ export const CONTENT_HASH_FIELD = 'contentHash';
16
+ export const TITLE_FIELD = 'title';
17
+ export const URI_FIELD = 'uri';
18
+ export const PARSER_FIELD = 'parser';
19
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ingest/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAmGH,oEAAoE;AACpE,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAC;AAC1C,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAC;AAC9C,MAAM,CAAC,MAAM,kBAAkB,GAAG,aAAa,CAAC;AAChD,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC;AACnC,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC;AAC/B,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAAC"}
@@ -30,6 +30,23 @@ export interface MemoryEntry {
30
30
  /** Importance weight in the range 0–1. Default: 0.5. */
31
31
  importance?: number;
32
32
  }
33
+ /**
34
+ * Which ranker produced a recall ordering. Matches the vocabulary the gateway's
35
+ * Evermind recall/validate surfaces already report, so a host can render one chip
36
+ * ("Semantic recall" / "Lexical recall (fallback)") regardless of which layer
37
+ * answered.
38
+ */
39
+ export type RecallMethod = 'embedding' | 'lexical';
40
+ /** A recalled entry with its relevance score (higher = closer). */
41
+ export interface ScoredMemory {
42
+ entry: MemoryEntry;
43
+ score: number;
44
+ }
45
+ /** A ranked recall: the hits plus the ranker that ordered them. */
46
+ export interface RankedRecall {
47
+ hits: ScoredMemory[];
48
+ method: RecallMethod;
49
+ }
33
50
  export interface RememberOptions {
34
51
  /** Override the store-level defaultTtlMs for this entry. */
35
52
  ttlMs?: number;
@@ -171,6 +188,22 @@ export declare class MemoryStore {
171
188
  * so it is always strictly at least as good as the lexical fallback.
172
189
  */
173
190
  recallHybrid(query: string, topK: number, runtime?: SSMRuntimeRef, opts?: HybridRetrieveOptions): Promise<MemoryEntry[]>;
191
+ /**
192
+ * The hybrid retrieval path with its evidence attached: each hit's fused score,
193
+ * plus WHICH ranker produced the ordering.
194
+ *
195
+ * {@link recallHybrid} is the convenience wrapper that throws both away, so
196
+ * there is exactly one implementation of the blend — and it is the shared
197
+ * `hybridRetrieve` → `reciprocalRankFusion` primitive, never a second hand-
198
+ * rolled mix of cosine and word overlap.
199
+ *
200
+ * `method` is honest rather than aspirational: `'embedding'` means the query
201
+ * really did embed and the dense ranking really did participate in the fusion;
202
+ * `'lexical'` means no model was available (or embedding failed) and the
203
+ * ordering is BM25 alone. Callers surface it so a user can tell semantic
204
+ * recall from the fallback instead of guessing.
205
+ */
206
+ recallRanked(query: string, topK: number, runtime?: SSMRuntimeRef, opts?: HybridRetrieveOptions): Promise<RankedRecall>;
174
207
  /**
175
208
  * Returns a cached embedding for `text`, computing it via `runtime.embed()`
176
209
  * on a cache miss. Returns `null` (never throws) when embedding is
@@ -1 +1 @@
1
- {"version":3,"file":"MemoryStore.d.ts","sourceRoot":"","sources":["../../src/memory/MemoryStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MemoryStore.d.ts","sourceRoot":"","sources":["../../src/memory/MemoryStore.ts"],"names":[],"mappings":"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"}
@@ -261,21 +261,47 @@ export class MemoryStore {
261
261
  * so it is always strictly at least as good as the lexical fallback.
262
262
  */
263
263
  async recallHybrid(query, topK, runtime, opts) {
264
+ return (await this.recallRanked(query, topK, runtime, opts)).hits.map(h => h.entry);
265
+ }
266
+ /**
267
+ * The hybrid retrieval path with its evidence attached: each hit's fused score,
268
+ * plus WHICH ranker produced the ordering.
269
+ *
270
+ * {@link recallHybrid} is the convenience wrapper that throws both away, so
271
+ * there is exactly one implementation of the blend — and it is the shared
272
+ * `hybridRetrieve` → `reciprocalRankFusion` primitive, never a second hand-
273
+ * rolled mix of cosine and word overlap.
274
+ *
275
+ * `method` is honest rather than aspirational: `'embedding'` means the query
276
+ * really did embed and the dense ranking really did participate in the fusion;
277
+ * `'lexical'` means no model was available (or embedding failed) and the
278
+ * ordering is BM25 alone. Callers surface it so a user can tell semantic
279
+ * recall from the fallback instead of guessing.
280
+ */
281
+ async recallRanked(query, topK, runtime, opts) {
264
282
  const all = await this.recallAll();
265
283
  if (all.length === 0)
266
- return [];
284
+ return { hits: [], method: 'lexical' };
267
285
  // Embed candidates + query where a runtime is available; null vectors are
268
286
  // fine — hybridRetrieve degrades that candidate to BM25-only.
269
287
  const canEmbed = runtime != null && typeof runtime.embed === 'function';
270
288
  const queryVec = canEmbed ? (await this._embedWithCache(runtime, query)) ?? undefined : undefined;
271
289
  const candidates = [];
272
290
  for (const entry of all) {
273
- const vector = canEmbed ? (await this._embedWithCache(runtime, entry.content)) ?? undefined : undefined;
291
+ const vector = queryVec ? (await this._embedWithCache(runtime, entry.content)) ?? undefined : undefined;
274
292
  candidates.push({ id: entry.key, text: entry.content, vector });
275
293
  }
294
+ // The dense ranking only exists when the query embedded AND at least one
295
+ // candidate did — anything less is a lexical ordering wearing a label.
296
+ const dense = !!queryVec && candidates.some(c => !!c.vector);
276
297
  const hits = hybridRetrieve({ text: query, vector: queryVec }, candidates, { topK, annThreshold: this._annThreshold, ...opts });
277
298
  const byKey = new Map(all.map(e => [e.key, e]));
278
- return hits.map(h => byKey.get(h.id)).filter((e) => !!e);
299
+ return {
300
+ hits: hits
301
+ .map(h => { const entry = byKey.get(h.id); return entry ? { entry, score: h.score } : null; })
302
+ .filter((h) => !!h),
303
+ method: dense ? 'embedding' : 'lexical',
304
+ };
279
305
  }
280
306
  /**
281
307
  * Returns a cached embedding for `text`, computing it via `runtime.embed()`