@seanhogg/builderforce-memory 2026.7.14 → 2026.9.28
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.
- package/README.md +10 -0
- package/dist/bridges/AnthropicBridge.d.ts +9 -1
- package/dist/bridges/AnthropicBridge.d.ts.map +1 -1
- package/dist/bridges/AnthropicBridge.js +58 -2
- package/dist/bridges/AnthropicBridge.js.map +1 -1
- package/dist/bridges/CachingBridge.d.ts +9 -1
- package/dist/bridges/CachingBridge.d.ts.map +1 -1
- package/dist/bridges/CachingBridge.js +24 -1
- package/dist/bridges/CachingBridge.js.map +1 -1
- package/dist/bridges/OpenAIBridge.d.ts +4 -1
- package/dist/bridges/OpenAIBridge.d.ts.map +1 -1
- package/dist/bridges/OpenAIBridge.js +40 -2
- package/dist/bridges/OpenAIBridge.js.map +1 -1
- package/dist/bridges/SemanticCachingBridge.d.ts +8 -1
- package/dist/bridges/SemanticCachingBridge.d.ts.map +1 -1
- package/dist/bridges/SemanticCachingBridge.js +26 -1
- package/dist/bridges/SemanticCachingBridge.js.map +1 -1
- package/dist/bridges/TransformerBridge.d.ts +13 -0
- package/dist/bridges/TransformerBridge.d.ts.map +1 -1
- package/dist/bridges/VertexAIBridge.d.ts +102 -0
- package/dist/bridges/VertexAIBridge.d.ts.map +1 -0
- package/dist/bridges/VertexAIBridge.js +224 -0
- package/dist/bridges/VertexAIBridge.js.map +1 -0
- package/dist/bridges/index.d.ts +3 -1
- package/dist/bridges/index.d.ts.map +1 -1
- package/dist/bridges/index.js +1 -0
- package/dist/bridges/index.js.map +1 -1
- package/dist/eval/EvalHarness.d.ts +37 -0
- package/dist/eval/EvalHarness.d.ts.map +1 -0
- package/dist/eval/EvalHarness.js +178 -0
- package/dist/eval/EvalHarness.js.map +1 -0
- package/dist/eval/graders.d.ts +76 -0
- package/dist/eval/graders.d.ts.map +1 -0
- package/dist/eval/graders.js +168 -0
- package/dist/eval/graders.js.map +1 -0
- package/dist/eval/index.d.ts +26 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js +26 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/eval/types.d.ts +97 -0
- package/dist/eval/types.d.ts.map +1 -0
- package/dist/eval/types.js +5 -0
- package/dist/eval/types.js.map +1 -0
- package/dist/evermind/contract.d.ts +40 -0
- package/dist/evermind/contract.d.ts.map +1 -0
- package/dist/evermind/contract.js +13 -0
- package/dist/evermind/contract.js.map +1 -0
- package/dist/evermind/index.d.ts +15 -0
- package/dist/evermind/index.d.ts.map +1 -0
- package/dist/evermind/index.js +4 -0
- package/dist/evermind/index.js.map +1 -0
- package/dist/evermind/memoryBlock.d.ts +7 -0
- package/dist/evermind/memoryBlock.d.ts.map +1 -0
- package/dist/evermind/memoryBlock.js +37 -0
- package/dist/evermind/memoryBlock.js.map +1 -0
- package/dist/evermind/recall.d.ts +48 -0
- package/dist/evermind/recall.d.ts.map +1 -0
- package/dist/evermind/recall.js +105 -0
- package/dist/evermind/recall.js.map +1 -0
- package/dist/index.d.ts +18 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/ingest/IngestionPipeline.d.ts +95 -0
- package/dist/ingest/IngestionPipeline.d.ts.map +1 -0
- package/dist/ingest/IngestionPipeline.js +295 -0
- package/dist/ingest/IngestionPipeline.js.map +1 -0
- package/dist/ingest/index.d.ts +10 -0
- package/dist/ingest/index.d.ts.map +1 -0
- package/dist/ingest/index.js +8 -0
- package/dist/ingest/index.js.map +1 -0
- package/dist/ingest/parsers.d.ts +53 -0
- package/dist/ingest/parsers.d.ts.map +1 -0
- package/dist/ingest/parsers.js +306 -0
- package/dist/ingest/parsers.js.map +1 -0
- package/dist/ingest/types.d.ts +114 -0
- package/dist/ingest/types.d.ts.map +1 -0
- package/dist/ingest/types.js +19 -0
- package/dist/ingest/types.js.map +1 -0
- package/dist/memory/MemoryStore.d.ts +33 -0
- package/dist/memory/MemoryStore.d.ts.map +1 -1
- package/dist/memory/MemoryStore.js +29 -3
- package/dist/memory/MemoryStore.js.map +1 -1
- package/dist/memory/index.d.ts +1 -1
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/orchestration/AgentGraph.d.ts +104 -0
- package/dist/orchestration/AgentGraph.d.ts.map +1 -0
- package/dist/orchestration/AgentGraph.js +364 -0
- package/dist/orchestration/AgentGraph.js.map +1 -0
- package/dist/orchestration/checkpoint.d.ts +58 -0
- package/dist/orchestration/checkpoint.d.ts.map +1 -0
- package/dist/orchestration/checkpoint.js +92 -0
- package/dist/orchestration/checkpoint.js.map +1 -0
- package/dist/orchestration/index.d.ts +14 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +10 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/patterns.d.ts +159 -0
- package/dist/orchestration/patterns.d.ts.map +1 -0
- package/dist/orchestration/patterns.js +371 -0
- package/dist/orchestration/patterns.js.map +1 -0
- package/dist/orchestration/types.d.ts +146 -0
- package/dist/orchestration/types.d.ts.map +1 -0
- package/dist/orchestration/types.js +20 -0
- package/dist/orchestration/types.js.map +1 -0
- package/dist/rag/EnterpriseRetriever.d.ts +114 -0
- package/dist/rag/EnterpriseRetriever.d.ts.map +1 -0
- package/dist/rag/EnterpriseRetriever.js +240 -0
- package/dist/rag/EnterpriseRetriever.js.map +1 -0
- package/dist/rag/index.d.ts +6 -0
- package/dist/rag/index.d.ts.map +1 -0
- package/dist/rag/index.js +5 -0
- package/dist/rag/index.js.map +1 -0
- package/dist/retrieval/bm25.d.ts +48 -1
- package/dist/retrieval/bm25.d.ts.map +1 -1
- package/dist/retrieval/bm25.js +59 -13
- package/dist/retrieval/bm25.js.map +1 -1
- package/dist/retrieval/index.d.ts +2 -2
- package/dist/retrieval/index.d.ts.map +1 -1
- package/dist/retrieval/index.js +1 -1
- package/dist/retrieval/index.js.map +1 -1
- package/dist/runtime/SSMRuntime.d.ts +1 -1
- package/dist/runtime/SSMRuntime.d.ts.map +1 -1
- package/dist/telemetry/InstrumentedBridge.d.ts +62 -0
- package/dist/telemetry/InstrumentedBridge.d.ts.map +1 -0
- package/dist/telemetry/InstrumentedBridge.js +120 -0
- package/dist/telemetry/InstrumentedBridge.js.map +1 -0
- package/dist/telemetry/MetricsRegistry.d.ts +88 -0
- package/dist/telemetry/MetricsRegistry.d.ts.map +1 -0
- package/dist/telemetry/MetricsRegistry.js +167 -0
- package/dist/telemetry/MetricsRegistry.js.map +1 -0
- package/dist/telemetry/Tracer.d.ts +137 -0
- package/dist/telemetry/Tracer.d.ts.map +1 -0
- package/dist/telemetry/Tracer.js +244 -0
- package/dist/telemetry/Tracer.js.map +1 -0
- package/dist/telemetry/exporters.d.ts +68 -0
- package/dist/telemetry/exporters.d.ts.map +1 -0
- package/dist/telemetry/exporters.js +145 -0
- package/dist/telemetry/exporters.js.map +1 -0
- package/dist/telemetry/index.d.ts +19 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +12 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/pricing.d.ts +74 -0
- package/dist/telemetry/pricing.d.ts.map +1 -0
- package/dist/telemetry/pricing.js +98 -0
- package/dist/telemetry/pricing.js.map +1 -0
- package/dist/telemetry/traceparent.d.ts +50 -0
- package/dist/telemetry/traceparent.d.ts.map +1 -0
- package/dist/telemetry/traceparent.js +77 -0
- package/dist/telemetry/traceparent.js.map +1 -0
- package/dist/telemetry/types.d.ts +90 -0
- package/dist/telemetry/types.d.ts.map +1 -0
- package/dist/telemetry/types.js +17 -0
- package/dist/telemetry/types.js.map +1 -0
- package/dist/vectorstore/MemoryVectorStore.d.ts +72 -0
- package/dist/vectorstore/MemoryVectorStore.d.ts.map +1 -0
- package/dist/vectorstore/MemoryVectorStore.js +205 -0
- package/dist/vectorstore/MemoryVectorStore.js.map +1 -0
- package/dist/vectorstore/RestVectorStore.d.ts +79 -0
- package/dist/vectorstore/RestVectorStore.d.ts.map +1 -0
- package/dist/vectorstore/RestVectorStore.js +170 -0
- package/dist/vectorstore/RestVectorStore.js.map +1 -0
- package/dist/vectorstore/dialects.d.ts +101 -0
- package/dist/vectorstore/dialects.d.ts.map +1 -0
- package/dist/vectorstore/dialects.js +618 -0
- package/dist/vectorstore/dialects.js.map +1 -0
- package/dist/vectorstore/filter.d.ts +42 -0
- package/dist/vectorstore/filter.d.ts.map +1 -0
- package/dist/vectorstore/filter.js +132 -0
- package/dist/vectorstore/filter.js.map +1 -0
- package/dist/vectorstore/index.d.ts +15 -0
- package/dist/vectorstore/index.d.ts.map +1 -0
- package/dist/vectorstore/index.js +11 -0
- package/dist/vectorstore/index.js.map +1 -0
- package/dist/vectorstore/types.d.ts +151 -0
- package/dist/vectorstore/types.d.ts.map +1 -0
- package/dist/vectorstore/types.js +30 -0
- package/dist/vectorstore/types.js.map +1 -0
- package/package.json +39 -5
- package/src/bridges/AnthropicBridge.ts +68 -3
- package/src/bridges/CachingBridge.ts +28 -2
- package/src/bridges/OpenAIBridge.ts +48 -3
- package/src/bridges/SemanticCachingBridge.ts +29 -2
- package/src/bridges/TransformerBridge.ts +16 -0
- package/src/bridges/VertexAIBridge.ts +297 -0
- package/src/bridges/index.ts +3 -1
- package/src/eval/EvalHarness.ts +214 -0
- package/src/eval/graders.ts +218 -0
- package/src/eval/index.ts +26 -0
- package/src/eval/types.ts +107 -0
- package/src/evermind/contract.ts +39 -0
- package/src/evermind/index.ts +18 -0
- package/src/evermind/memoryBlock.ts +38 -0
- package/src/evermind/recall.ts +122 -0
- package/src/index.ts +232 -0
- package/src/ingest/IngestionPipeline.ts +378 -0
- package/src/ingest/index.ts +46 -0
- package/src/ingest/parsers.ts +318 -0
- package/src/ingest/types.ts +116 -0
- package/src/memory/MemoryStore.ts +55 -3
- package/src/memory/index.ts +1 -1
- package/src/orchestration/AgentGraph.ts +462 -0
- package/src/orchestration/checkpoint.ts +129 -0
- package/src/orchestration/index.ts +63 -0
- package/src/orchestration/patterns.ts +532 -0
- package/src/orchestration/types.ts +128 -0
- package/src/rag/EnterpriseRetriever.ts +348 -0
- package/src/rag/index.ts +18 -0
- package/src/retrieval/bm25.ts +71 -13
- package/src/retrieval/index.ts +2 -2
- package/src/telemetry/InstrumentedBridge.ts +152 -0
- package/src/telemetry/MetricsRegistry.ts +263 -0
- package/src/telemetry/Tracer.ts +310 -0
- package/src/telemetry/exporters.ts +187 -0
- package/src/telemetry/index.ts +56 -0
- package/src/telemetry/pricing.ts +129 -0
- package/src/telemetry/traceparent.ts +89 -0
- package/src/telemetry/types.ts +105 -0
- package/src/vectorstore/MemoryVectorStore.ts +250 -0
- package/src/vectorstore/RestVectorStore.ts +236 -0
- package/src/vectorstore/dialects.ts +702 -0
- package/src/vectorstore/filter.ts +148 -0
- package/src/vectorstore/index.ts +53 -0
- 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.
|
|
4
|
-
"description": "BuilderForce Agent Memory — runtime layer. SSM execution, Transformer orchestration, online distillation,
|
|
3
|
+
"version": "2026.9.28",
|
|
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.
|
|
90
|
+
"@seanhogg/builderforce-memory-engine": "^2026.9.28"
|
|
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.
|
|
104
|
+
"@seanhogg/builderforce-memory-engine": "2026.9.28"
|
|
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 {
|
|
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
|
-
|
|
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(
|
|
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
|
+
}
|