@seanhogg/builderforce-memory 2026.7.14 → 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,42 @@
1
+ /**
2
+ * vectorstore/filter.ts — the ONE evaluator and the ONE scope compiler.
3
+ *
4
+ * Two rules this file exists to enforce:
5
+ *
6
+ * • A filter means the same thing everywhere. The in-process store, the
7
+ * post-filter a remote adapter applies when its dialect cannot express a
8
+ * clause, the ingest de-duplicator and the eval harness all call
9
+ * {@link matchesFilter}. A second implementation would eventually disagree
10
+ * about `null` or about a missing field, and a filter that disagrees with
11
+ * itself across two code paths is a cross-tenant leak waiting for traffic.
12
+ *
13
+ * • Access scope is compiled, never hand-written. {@link accessFilter} is the
14
+ * single definition of "what may this caller see", so a new adapter or a new
15
+ * query path inherits the rule instead of re-deriving it.
16
+ */
17
+ import { type AccessScope, type MetadataFilter, type MetadataRecord } from './types.js';
18
+ /**
19
+ * Compiles an access scope into a filter.
20
+ *
21
+ * The ACL clause is `anyOf(acl, [...principals, '*'])`. Records are required to
22
+ * carry a non-empty `acl` (ingestion defaults it to `['*']`), which is what makes
23
+ * the rule fail CLOSED: a record written without an ACL matches nothing rather
24
+ * than matching everyone.
25
+ */
26
+ export declare function accessFilter(scope: AccessScope): MetadataFilter;
27
+ /**
28
+ * ANDs a caller filter with a scope, dropping either when absent.
29
+ * Returns `undefined` only when neither is present — an unscoped query, which is
30
+ * legitimate for single-tenant use but never happens by accident, because the
31
+ * caller had to omit the scope explicitly.
32
+ */
33
+ export declare function combineFilters(filter?: MetadataFilter, scope?: AccessScope): MetadataFilter | undefined;
34
+ /** Evaluates a filter against one record's metadata. */
35
+ export declare function matchesFilter(metadata: MetadataRecord, filter?: MetadataFilter): boolean;
36
+ /**
37
+ * Walks a filter tree, reporting every field it touches. Adapters use this to
38
+ * decide up front whether a dialect can push the whole filter down, or whether a
39
+ * post-filter pass is needed.
40
+ */
41
+ export declare function filterFields(filter: MetadataFilter, out?: Set<string>): Set<string>;
42
+ //# sourceMappingURL=filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/vectorstore/filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAKH,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,cAAc,EAEtB,MAAM,YAAY,CAAC;AAEpB;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,cAAc,CAW/D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC1B,MAAM,CAAC,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,WAAW,GACpB,cAAc,GAAG,SAAS,CAI5B;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,OAAO,CA8BxF;AAkCD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,cAAoB,GAAG,GAAG,CAAC,MAAM,CAAC,CAazF"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * vectorstore/filter.ts — the ONE evaluator and the ONE scope compiler.
3
+ *
4
+ * Two rules this file exists to enforce:
5
+ *
6
+ * • A filter means the same thing everywhere. The in-process store, the
7
+ * post-filter a remote adapter applies when its dialect cannot express a
8
+ * clause, the ingest de-duplicator and the eval harness all call
9
+ * {@link matchesFilter}. A second implementation would eventually disagree
10
+ * about `null` or about a missing field, and a filter that disagrees with
11
+ * itself across two code paths is a cross-tenant leak waiting for traffic.
12
+ *
13
+ * • Access scope is compiled, never hand-written. {@link accessFilter} is the
14
+ * single definition of "what may this caller see", so a new adapter or a new
15
+ * query path inherits the rule instead of re-deriving it.
16
+ */
17
+ import { ACL_FIELD, ACL_PUBLIC, SENSITIVITY_FIELD, TENANT_FIELD, } from './types.js';
18
+ /**
19
+ * Compiles an access scope into a filter.
20
+ *
21
+ * The ACL clause is `anyOf(acl, [...principals, '*'])`. Records are required to
22
+ * carry a non-empty `acl` (ingestion defaults it to `['*']`), which is what makes
23
+ * the rule fail CLOSED: a record written without an ACL matches nothing rather
24
+ * than matching everyone.
25
+ */
26
+ export function accessFilter(scope) {
27
+ const clauses = [
28
+ { op: 'eq', field: TENANT_FIELD, value: scope.tenantId },
29
+ { op: 'anyOf', field: ACL_FIELD, values: [...(scope.principals ?? []), ACL_PUBLIC] },
30
+ ];
31
+ if (scope.maxSensitivity !== undefined) {
32
+ clauses.push({ op: 'lte', field: SENSITIVITY_FIELD, value: scope.maxSensitivity });
33
+ }
34
+ return { op: 'and', filters: clauses };
35
+ }
36
+ /**
37
+ * ANDs a caller filter with a scope, dropping either when absent.
38
+ * Returns `undefined` only when neither is present — an unscoped query, which is
39
+ * legitimate for single-tenant use but never happens by accident, because the
40
+ * caller had to omit the scope explicitly.
41
+ */
42
+ export function combineFilters(filter, scope) {
43
+ const scoped = scope ? accessFilter(scope) : undefined;
44
+ if (filter && scoped)
45
+ return { op: 'and', filters: [scoped, filter] };
46
+ return filter ?? scoped;
47
+ }
48
+ /** Evaluates a filter against one record's metadata. */
49
+ export function matchesFilter(metadata, filter) {
50
+ if (!filter)
51
+ return true;
52
+ switch (filter.op) {
53
+ case 'and':
54
+ return filter.filters.every((f) => matchesFilter(metadata, f));
55
+ case 'or':
56
+ return filter.filters.some((f) => matchesFilter(metadata, f));
57
+ case 'not':
58
+ return !matchesFilter(metadata, filter.filter);
59
+ case 'exists':
60
+ return metadata[filter.field] !== undefined && metadata[filter.field] !== null;
61
+ case 'in':
62
+ return filter.values.some((v) => scalarEquals(metadata[filter.field], v));
63
+ case 'nin':
64
+ return !filter.values.some((v) => scalarEquals(metadata[filter.field], v));
65
+ case 'anyOf': {
66
+ const actual = metadata[filter.field];
67
+ if (actual === undefined || actual === null)
68
+ return false;
69
+ const held = Array.isArray(actual) ? actual : [actual];
70
+ return held.some((h) => filter.values.some((v) => scalarEquals(h, v)));
71
+ }
72
+ case 'contains': {
73
+ const actual = metadata[filter.field];
74
+ if (typeof actual !== 'string')
75
+ return false;
76
+ return actual.toLowerCase().includes(filter.value.toLowerCase());
77
+ }
78
+ default:
79
+ return compare(metadata[filter.field], filter.op, filter.value);
80
+ }
81
+ }
82
+ function scalarEquals(a, b) {
83
+ if (Array.isArray(a) || Array.isArray(b)) {
84
+ return Array.isArray(a) && Array.isArray(b)
85
+ && a.length === b.length
86
+ && a.every((v, i) => v === b[i]);
87
+ }
88
+ return a === b;
89
+ }
90
+ function compare(actual, op, expected) {
91
+ if (op === 'eq')
92
+ return scalarEquals(actual, expected);
93
+ if (op === 'ne')
94
+ return !scalarEquals(actual, expected);
95
+ // Ordering comparisons on a missing or non-scalar field are false rather than
96
+ // throwing: a record without the field simply does not satisfy `sensitivity <= n`.
97
+ if (actual === undefined || actual === null)
98
+ return false;
99
+ if (Array.isArray(actual) || Array.isArray(expected) || expected === null)
100
+ return false;
101
+ if (typeof actual !== typeof expected)
102
+ return false;
103
+ if (typeof actual === 'boolean' || typeof expected === 'boolean')
104
+ return false;
105
+ switch (op) {
106
+ case 'gt': return actual > expected;
107
+ case 'gte': return actual >= expected;
108
+ case 'lt': return actual < expected;
109
+ default: return actual <= expected;
110
+ }
111
+ }
112
+ /**
113
+ * Walks a filter tree, reporting every field it touches. Adapters use this to
114
+ * decide up front whether a dialect can push the whole filter down, or whether a
115
+ * post-filter pass is needed.
116
+ */
117
+ export function filterFields(filter, out = new Set()) {
118
+ switch (filter.op) {
119
+ case 'and':
120
+ case 'or':
121
+ for (const f of filter.filters)
122
+ filterFields(f, out);
123
+ break;
124
+ case 'not':
125
+ filterFields(filter.filter, out);
126
+ break;
127
+ default:
128
+ out.add(filter.field);
129
+ }
130
+ return out;
131
+ }
132
+ //# sourceMappingURL=filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../src/vectorstore/filter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * vectorstore — the VectorStore port, its declarative filter algebra, and the
3
+ * adapters. Tenant/ACL scope is compiled into every read, so multi-tenant RAG
4
+ * fails closed rather than depending on each caller remembering to scope.
5
+ */
6
+ export { MemoryVectorStore } from './MemoryVectorStore.js';
7
+ export type { MemoryVectorStoreOptions } from './MemoryVectorStore.js';
8
+ export { RestVectorStore } from './RestVectorStore.js';
9
+ export type { RestVectorStoreOptions } from './RestVectorStore.js';
10
+ export { getDialect, listDialects, registerDialect, evermindDialect, qdrantDialect, pineconeDialect, vertexAiDialect, } from './dialects.js';
11
+ export type { VectorDialect, DialectContext, HttpRequest, TranslatedFilter, } from './dialects.js';
12
+ export { accessFilter, combineFilters, matchesFilter, filterFields, } from './filter.js';
13
+ export { TENANT_FIELD, ACL_FIELD, SENSITIVITY_FIELD, ACL_PUBLIC, } from './types.js';
14
+ export type { AccessScope, ComparisonOp, MetadataFilter, MetadataRecord, MetadataValue, UpsertResult, VectorMatch, VectorQuery, VectorRecord, VectorStore, } from './types.js';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vectorstore/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EACH,UAAU,EACV,YAAY,EACZ,eAAe,EACf,eAAe,EACf,aAAa,EACb,eAAe,EACf,eAAe,GAClB,MAAM,eAAe,CAAC;AACvB,YAAY,EACR,aAAa,EACb,cAAc,EACd,WAAW,EACX,gBAAgB,GACnB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACH,YAAY,EACZ,cAAc,EACd,aAAa,EACb,YAAY,GACf,MAAM,aAAa,CAAC;AAErB,OAAO,EACH,YAAY,EACZ,SAAS,EACT,iBAAiB,EACjB,UAAU,GACb,MAAM,YAAY,CAAC;AACpB,YAAY,EACR,WAAW,EACX,YAAY,EACZ,cAAc,EACd,cAAc,EACd,aAAa,EACb,YAAY,EACZ,WAAW,EACX,WAAW,EACX,YAAY,EACZ,WAAW,GACd,MAAM,YAAY,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * vectorstore — the VectorStore port, its declarative filter algebra, and the
3
+ * adapters. Tenant/ACL scope is compiled into every read, so multi-tenant RAG
4
+ * fails closed rather than depending on each caller remembering to scope.
5
+ */
6
+ export { MemoryVectorStore } from './MemoryVectorStore.js';
7
+ export { RestVectorStore } from './RestVectorStore.js';
8
+ export { getDialect, listDialects, registerDialect, evermindDialect, qdrantDialect, pineconeDialect, vertexAiDialect, } from './dialects.js';
9
+ export { accessFilter, combineFilters, matchesFilter, filterFields, } from './filter.js';
10
+ export { TENANT_FIELD, ACL_FIELD, SENSITIVITY_FIELD, ACL_PUBLIC, } from './types.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vectorstore/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD,OAAO,EACH,UAAU,EACV,YAAY,EACZ,eAAe,EACf,eAAe,EACf,aAAa,EACb,eAAe,EACf,eAAe,GAClB,MAAM,eAAe,CAAC;AAQvB,OAAO,EACH,YAAY,EACZ,cAAc,EACd,aAAa,EACb,YAAY,GACf,MAAM,aAAa,CAAC;AAErB,OAAO,EACH,YAAY,EACZ,SAAS,EACT,iBAAiB,EACjB,UAAU,GACb,MAAM,YAAY,CAAC"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * vectorstore/types.ts — the VectorStore port.
3
+ *
4
+ * Enterprise deployments do not get to choose the vector database; the customer
5
+ * already has one (pgvector in their Cloud SQL, Vertex AI Vector Search because
6
+ * they are a GCP shop, Qdrant because platform standardised on it). So the store
7
+ * is a PORT, and every adapter is infrastructure behind it. Retrieval, ingestion
8
+ * and evaluation depend on this interface and never on a vendor.
9
+ *
10
+ * Two things make it enterprise-grade rather than a toy vector index:
11
+ *
12
+ * 1. **Filters are DATA, not predicates.** A `(record) => boolean` cannot be
13
+ * pushed down to a remote database — it forces fetch-everything-then-filter,
14
+ * which is both slow and a data-leak: rows the caller may not see are read
15
+ * into the process before being dropped. {@link MetadataFilter} is a small
16
+ * declarative algebra each adapter translates into its own query language.
17
+ *
18
+ * 2. **Access scope is first-class.** Multi-tenant RAG fails closed only if the
19
+ * tenant predicate is part of the query the database runs. {@link AccessScope}
20
+ * compiles to a filter that is AND-ed into every read, so "forgot to scope the
21
+ * query" is not a reachable state.
22
+ */
23
+ export type MetadataValue = string | number | boolean | null | string[];
24
+ export type MetadataRecord = Record<string, MetadataValue>;
25
+ /** A stored unit of retrievable knowledge. */
26
+ export interface VectorRecord {
27
+ id: string;
28
+ /** The chunk text — returned with matches so a retriever can rerank on it. */
29
+ text: string;
30
+ /** Embedding. Optional so a store can embed server-side. */
31
+ vector?: Float32Array;
32
+ metadata: MetadataRecord;
33
+ }
34
+ export interface VectorMatch {
35
+ id: string;
36
+ text: string;
37
+ /** Similarity in [0,1] — cosine for every adapter here. */
38
+ score: number;
39
+ metadata: MetadataRecord;
40
+ vector?: Float32Array;
41
+ }
42
+ export type ComparisonOp = 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte';
43
+ export type MetadataFilter = {
44
+ op: ComparisonOp;
45
+ field: string;
46
+ value: MetadataValue;
47
+ }
48
+ /** Field equals any of `values` (scalar field). */
49
+ | {
50
+ op: 'in' | 'nin';
51
+ field: string;
52
+ values: MetadataValue[];
53
+ }
54
+ /**
55
+ * Field (an array, or a scalar treated as a one-element array) intersects
56
+ * `values`. This is the ACL primitive — every mainstream vector database can
57
+ * express "array field matches any of", which is why ACLs are modelled as an
58
+ * array rather than as a bitmask or a nested object.
59
+ */
60
+ | {
61
+ op: 'anyOf';
62
+ field: string;
63
+ values: MetadataValue[];
64
+ }
65
+ /** Case-insensitive substring match on a string field. */
66
+ | {
67
+ op: 'contains';
68
+ field: string;
69
+ value: string;
70
+ } | {
71
+ op: 'exists';
72
+ field: string;
73
+ } | {
74
+ op: 'and';
75
+ filters: MetadataFilter[];
76
+ } | {
77
+ op: 'or';
78
+ filters: MetadataFilter[];
79
+ } | {
80
+ op: 'not';
81
+ filter: MetadataFilter;
82
+ };
83
+ /**
84
+ * The non-composite half of the algebra — every variant that names a `field`.
85
+ * Dialect translation works leaf-by-leaf, so having the type say so removes a
86
+ * cast from every adapter.
87
+ */
88
+ export type LeafFilter = Extract<MetadataFilter, {
89
+ field: string;
90
+ }>;
91
+ /** Metadata keys the access model reserves. Ingestion always populates them. */
92
+ export declare const TENANT_FIELD = "tenantId";
93
+ export declare const ACL_FIELD = "acl";
94
+ export declare const SENSITIVITY_FIELD = "sensitivity";
95
+ /** ACL entry meaning "any principal within the tenant". */
96
+ export declare const ACL_PUBLIC = "*";
97
+ export interface AccessScope {
98
+ /** Hard tenant boundary. Every read is AND-ed with an equality on this. */
99
+ tenantId: string;
100
+ /**
101
+ * Group / role / user ids the caller holds. A record is visible when its `acl`
102
+ * array intersects these, or contains {@link ACL_PUBLIC}. Omit for
103
+ * tenant-wide access to public records only.
104
+ */
105
+ principals?: string[];
106
+ /**
107
+ * Highest classification level the caller may read (records carry a numeric
108
+ * `sensitivity`). Omit for no ceiling.
109
+ */
110
+ maxSensitivity?: number;
111
+ }
112
+ export interface VectorQuery {
113
+ /** Dense query embedding. Required unless the adapter embeds server-side. */
114
+ vector?: Float32Array;
115
+ /** Raw query text — used by `keywordSearch`, and by server-side embedders. */
116
+ text?: string;
117
+ /** Results to return. Default 10. */
118
+ topK?: number;
119
+ /** Declarative metadata predicate, pushed down to the store. */
120
+ filter?: MetadataFilter;
121
+ /** Tenant/ACL scope, AND-ed with `filter`. */
122
+ scope?: AccessScope;
123
+ /** Drop matches scoring below this. Default 0. */
124
+ minScore?: number;
125
+ /** Return stored vectors on matches (costs bandwidth). Default false. */
126
+ includeVectors?: boolean;
127
+ }
128
+ export interface UpsertResult {
129
+ upserted: number;
130
+ /** Ids the store considered unchanged and skipped, when it can tell. */
131
+ skipped: number;
132
+ }
133
+ /**
134
+ * The port. `keywordSearch` is optional because not every vector database has a
135
+ * lexical index; retrievers degrade to dense-only and SAY SO on the span rather
136
+ * than silently returning worse results.
137
+ */
138
+ export interface VectorStore {
139
+ /** Adapter name, stamped on telemetry spans. */
140
+ readonly name: string;
141
+ upsert(records: readonly VectorRecord[]): Promise<UpsertResult>;
142
+ query(query: VectorQuery): Promise<VectorMatch[]>;
143
+ delete(ids: readonly string[]): Promise<number>;
144
+ /** Bulk delete by predicate — how an incremental sync removes a stale source. */
145
+ deleteByFilter(filter: MetadataFilter, scope?: AccessScope): Promise<number>;
146
+ fetch(ids: readonly string[]): Promise<VectorRecord[]>;
147
+ count(filter?: MetadataFilter, scope?: AccessScope): Promise<number>;
148
+ /** Lexical/BM25 search, when the adapter supports one. */
149
+ keywordSearch?(query: VectorQuery): Promise<VectorMatch[]>;
150
+ }
151
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/vectorstore/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * vectorstore/types.ts — the VectorStore port.
3
+ *
4
+ * Enterprise deployments do not get to choose the vector database; the customer
5
+ * already has one (pgvector in their Cloud SQL, Vertex AI Vector Search because
6
+ * they are a GCP shop, Qdrant because platform standardised on it). So the store
7
+ * is a PORT, and every adapter is infrastructure behind it. Retrieval, ingestion
8
+ * and evaluation depend on this interface and never on a vendor.
9
+ *
10
+ * Two things make it enterprise-grade rather than a toy vector index:
11
+ *
12
+ * 1. **Filters are DATA, not predicates.** A `(record) => boolean` cannot be
13
+ * pushed down to a remote database — it forces fetch-everything-then-filter,
14
+ * which is both slow and a data-leak: rows the caller may not see are read
15
+ * into the process before being dropped. {@link MetadataFilter} is a small
16
+ * declarative algebra each adapter translates into its own query language.
17
+ *
18
+ * 2. **Access scope is first-class.** Multi-tenant RAG fails closed only if the
19
+ * tenant predicate is part of the query the database runs. {@link AccessScope}
20
+ * compiles to a filter that is AND-ed into every read, so "forgot to scope the
21
+ * query" is not a reachable state.
22
+ */
23
+ // ── Access scope ──────────────────────────────────────────────────────────────
24
+ /** Metadata keys the access model reserves. Ingestion always populates them. */
25
+ export const TENANT_FIELD = 'tenantId';
26
+ export const ACL_FIELD = 'acl';
27
+ export const SENSITIVITY_FIELD = 'sensitivity';
28
+ /** ACL entry meaning "any principal within the tenant". */
29
+ export const ACL_PUBLIC = '*';
30
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/vectorstore/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AA0DH,iFAAiF;AAEjF,gFAAgF;AAChF,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;AACvC,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC;AAC/B,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAC/C,2DAA2D;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@seanhogg/builderforce-memory",
3
- "version": "2026.7.14",
4
- "description": "BuilderForce Agent Memory — runtime layer. SSM execution, Transformer orchestration, online distillation, hybrid RAG retrieval, and persistent agent memory for BuilderForce.ai agents.",
3
+ "version": "2026.9.27",
4
+ "description": "BuilderForce Agent Memory — runtime layer. SSM execution, Transformer orchestration, online distillation, enterprise RAG (ingestion pipelines, vector-store adapters, tenant/ACL-scoped hybrid retrieval), multi-agent graph orchestration, LLM telemetry and cost accounting, and persistent agent memory for BuilderForce.ai agents.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -13,6 +13,34 @@
13
13
  "./retrieval": {
14
14
  "types": "./dist/retrieval/index.d.ts",
15
15
  "import": "./dist/retrieval/index.js"
16
+ },
17
+ "./telemetry": {
18
+ "types": "./dist/telemetry/index.d.ts",
19
+ "import": "./dist/telemetry/index.js"
20
+ },
21
+ "./vectorstore": {
22
+ "types": "./dist/vectorstore/index.d.ts",
23
+ "import": "./dist/vectorstore/index.js"
24
+ },
25
+ "./ingest": {
26
+ "types": "./dist/ingest/index.d.ts",
27
+ "import": "./dist/ingest/index.js"
28
+ },
29
+ "./rag": {
30
+ "types": "./dist/rag/index.d.ts",
31
+ "import": "./dist/rag/index.js"
32
+ },
33
+ "./orchestration": {
34
+ "types": "./dist/orchestration/index.d.ts",
35
+ "import": "./dist/orchestration/index.js"
36
+ },
37
+ "./eval": {
38
+ "types": "./dist/eval/index.d.ts",
39
+ "import": "./dist/eval/index.js"
40
+ },
41
+ "./evermind": {
42
+ "types": "./dist/evermind/index.d.ts",
43
+ "import": "./dist/evermind/index.js"
16
44
  }
17
45
  },
18
46
  "type": "module",
@@ -35,7 +63,13 @@
35
63
  "browser-ai",
36
64
  "agent-memory",
37
65
  "builderforce",
38
- "typescript"
66
+ "typescript",
67
+ "rag",
68
+ "vector-database",
69
+ "multi-agent",
70
+ "observability",
71
+ "enterprise-ai",
72
+ "langgraph-alternative"
39
73
  ],
40
74
  "author": {
41
75
  "name": "Sean Hogg",
@@ -53,7 +87,7 @@
53
87
  },
54
88
  "homepage": "https://github.com/SeanHogg/builderforce-memory/tree/main/packages/memory#readme",
55
89
  "peerDependencies": {
56
- "@seanhogg/builderforce-memory-engine": "^2026.7.14"
90
+ "@seanhogg/builderforce-memory-engine": "^2026.9.27"
57
91
  },
58
92
  "devDependencies": {
59
93
  "@jest/globals": "^29.7.0",
@@ -67,7 +101,7 @@
67
101
  "ts-jest": "^29.2.0",
68
102
  "typescript": "^6.0.3",
69
103
  "@typescript/native-preview": "7.0.0-dev.20260627.2",
70
- "@seanhogg/builderforce-memory-engine": "2026.7.14"
104
+ "@seanhogg/builderforce-memory-engine": "2026.9.27"
71
105
  },
72
106
  "jest": {
73
107
  "preset": "ts-jest/presets/default-esm",
@@ -6,7 +6,8 @@
6
6
  */
7
7
 
8
8
  import { SSMError } from '../errors/SSMError.js';
9
- import type { TransformerBridge, BridgeGenerateOptions } from './TransformerBridge.js';
9
+ import type { LlmUsage } from '../telemetry/types.js';
10
+ import type { TransformerBridge, BridgeGenerateOptions, BridgeCallInfo } from './TransformerBridge.js';
10
11
 
11
12
  export interface AnthropicBridgeOptions {
12
13
  /** Anthropic API key. */
@@ -46,6 +47,8 @@ export class AnthropicBridge implements TransformerBridge {
46
47
  private readonly _maxTokens : number;
47
48
  private readonly _cacheSystem : boolean;
48
49
 
50
+ private _lastCall: BridgeCallInfo | undefined;
51
+
49
52
  constructor(opts: AnthropicBridgeOptions) {
50
53
  this._apiKey = opts.apiKey;
51
54
  this._model = opts.model ?? 'claude-haiku-4-5';
@@ -55,6 +58,16 @@ export class AnthropicBridge implements TransformerBridge {
55
58
  this._cacheSystem = opts.cacheSystem ?? true;
56
59
  }
57
60
 
61
+ /**
62
+ * Provider-reported usage for the last call. Anthropic splits input tokens
63
+ * three ways — fresh, cache read, and cache write — and each is billed at a
64
+ * different rate, so a cost model that only reads `input_tokens` is wrong on
65
+ * exactly the cache-heavy traffic this bridge is tuned to produce.
66
+ */
67
+ get lastCall(): BridgeCallInfo | undefined {
68
+ return this._lastCall;
69
+ }
70
+
58
71
  async generate(prompt: string, opts: BridgeGenerateOptions = {}): Promise<string> {
59
72
  const body = this._buildBody(prompt, opts, false);
60
73
  const res = await this._fetch(body);
@@ -72,6 +85,12 @@ export class AnthropicBridge implements TransformerBridge {
72
85
  if (typeof content !== 'string') {
73
86
  throw new SSMError('BRIDGE_RESPONSE_INVALID', 'Unexpected Anthropic response shape.');
74
87
  }
88
+ this._lastCall = {
89
+ usage: readAnthropicUsage(
90
+ (json as any).usage,
91
+ (json as any).model ?? opts.model ?? this._model,
92
+ ),
93
+ };
75
94
  return content;
76
95
  }
77
96
 
@@ -91,7 +110,32 @@ export class AnthropicBridge implements TransformerBridge {
91
110
  throw new SSMError('BRIDGE_RESPONSE_INVALID', 'Anthropic streaming response has no body.');
92
111
  }
93
112
 
94
- yield* parseAnthropicStream(res.body);
113
+ const model = opts.model ?? this._model;
114
+ let input = 0, output = 0, cacheRead = 0, cacheWrite = 0, reportedModel = model;
115
+
116
+ yield* parseAnthropicStream(res.body, (event) => {
117
+ // `message_start` carries the input split; `message_delta` the running
118
+ // output count. Both are folded so the final usage is provider-measured.
119
+ const start = (event as any).message?.usage;
120
+ const delta = (event as any).usage;
121
+ const usage = start ?? delta;
122
+ if (!usage) return;
123
+ if (typeof (event as any).message?.model === 'string') reportedModel = (event as any).message.model;
124
+ input = Math.max(input, Number(usage.input_tokens) || 0);
125
+ output = Math.max(output, Number(usage.output_tokens) || 0);
126
+ cacheRead = Math.max(cacheRead, Number(usage.cache_read_input_tokens) || 0);
127
+ cacheWrite = Math.max(cacheWrite, Number(usage.cache_creation_input_tokens) || 0);
128
+ });
129
+
130
+ this._lastCall = {
131
+ usage: {
132
+ model: reportedModel,
133
+ inputTokens: input,
134
+ outputTokens: output,
135
+ cachedInputTokens: cacheRead,
136
+ cacheWriteTokens: cacheWrite,
137
+ },
138
+ };
95
139
  }
96
140
 
97
141
  private _buildBody(prompt: string, opts: BridgeGenerateOptions, stream: boolean): string {
@@ -129,7 +173,10 @@ export class AnthropicBridge implements TransformerBridge {
129
173
 
130
174
  // ── SSE parser (Anthropic event format) ──────────────────────────────────────
131
175
 
132
- async function* parseAnthropicStream(body: ReadableStream<Uint8Array>): AsyncIterable<string> {
176
+ async function* parseAnthropicStream(
177
+ body: ReadableStream<Uint8Array>,
178
+ onEvent?: (event: Record<string, unknown>) => void,
179
+ ): AsyncIterable<string> {
133
180
  const reader = body.getReader();
134
181
  const decoder = new TextDecoder();
135
182
  let buffer = '';
@@ -150,6 +197,7 @@ async function* parseAnthropicStream(body: ReadableStream<Uint8Array>): AsyncIte
150
197
  const data = trimmed.slice(6);
151
198
  try {
152
199
  const event = JSON.parse(data) as Record<string, unknown>;
200
+ onEvent?.(event);
153
201
  // content_block_delta events carry the streamed text
154
202
  if (event['type'] === 'content_block_delta') {
155
203
  const text = (event as any).delta?.text;
@@ -164,3 +212,20 @@ async function* parseAnthropicStream(body: ReadableStream<Uint8Array>): AsyncIte
164
212
  reader.releaseLock();
165
213
  }
166
214
  }
215
+
216
+ /**
217
+ * Maps an Anthropic `usage` object onto the canonical {@link LlmUsage} shape.
218
+ * Absent when the response omits usage (an older gateway shim), in which case
219
+ * `InstrumentedBridge` falls back to an estimate and flags it as such.
220
+ */
221
+ function readAnthropicUsage(usage: unknown, model: string): LlmUsage | undefined {
222
+ if (!usage || typeof usage !== 'object') return undefined;
223
+ const u = usage as Record<string, unknown>;
224
+ return {
225
+ model,
226
+ inputTokens: Number(u['input_tokens']) || 0,
227
+ outputTokens: Number(u['output_tokens']) || 0,
228
+ cachedInputTokens: Number(u['cache_read_input_tokens']) || 0,
229
+ cacheWriteTokens: Number(u['cache_creation_input_tokens']) || 0,
230
+ };
231
+ }