@asm-agent/retrieval 0.8.2

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluation.js","sourceRoot":"","sources":["../src/evaluation.ts"],"names":[],"mappings":"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","sourcesContent":["import { performance } from \"node:perf_hooks\";\nimport type { RankedItem, RetrievalItem, RetrievalQuery } from \"./types.js\";\n\nexport interface Ranker {\n\treadonly name: string;\n\tretrieve(query: RetrievalQuery, items: readonly RetrievalItem[]): RankedItem[];\n}\n\nexport interface BenchmarkCase {\n\tid: string;\n\tquery: RetrievalQuery;\n\titems: RetrievalItem[];\n\trelevantIds: string[];\n}\n\nexport interface BenchmarkMetrics {\n\trecallAtK: number;\n\tmeanReciprocalRank: number;\n\tp95LatencyMs: number;\n\tp99LatencyMs: number;\n\tcapacityRetention: number;\n\tfalseForgettingRate: number;\n\trevocationLeakage: number;\n\tprojectIsolationLeakage: number;\n}\n\nexport interface PromotionThresholds {\n\tminimumRecallAtK: number;\n\tminimumMeanReciprocalRank: number;\n\tmaximumLatencyRatio: number;\n\tmaximumP99LatencyRatio: number;\n\tminimumCapacityRetention: number;\n\tmaximumFalseForgettingRate: number;\n\tmaximumRevocationLeakage: number;\n\tmaximumProjectIsolationLeakage: number;\n}\n\nexport interface PromotionEvaluation {\n\tpassed: boolean;\n\treasons: string[];\n\tbaseline: BenchmarkMetrics;\n\tcandidate: BenchmarkMetrics;\n\tthresholds: PromotionThresholds;\n}\n\nexport const DEFAULT_PROMOTION_THRESHOLDS: Readonly<PromotionThresholds> = {\n\tminimumRecallAtK: 0.9,\n\tminimumMeanReciprocalRank: 0.85,\n\tmaximumLatencyRatio: 2,\n\tmaximumP99LatencyRatio: 2.5,\n\tminimumCapacityRetention: 0.95,\n\tmaximumFalseForgettingRate: 0.02,\n\tmaximumRevocationLeakage: 0,\n\tmaximumProjectIsolationLeakage: 0,\n};\n\nexport function benchmark(\n\tranker: Ranker,\n\tcases: readonly BenchmarkCase[],\n\toptions: { capacityRetention?: number; forgottenRelevantIds?: ReadonlySet<string> } = {},\n): BenchmarkMetrics {\n\tif (cases.length === 0) throw new Error(\"Benchmark requires frozen cases\");\n\tlet recall = 0;\n\tlet reciprocalRank = 0;\n\tlet revokedReturned = 0;\n\tlet crossProjectReturned = 0;\n\tlet totalReturned = 0;\n\tlet relevantCount = 0;\n\tlet forgotten = 0;\n\tconst latencies: number[] = [];\n\tfor (const fixture of cases) {\n\t\tconst started = performance.now();\n\t\tconst ranked = ranker.retrieve(fixture.query, fixture.items);\n\t\tlatencies.push(Math.max(0.001, performance.now() - started));\n\t\tconst ids = ranked.map((item) => item.id);\n\t\tconst relevant = new Set(fixture.relevantIds);\n\t\tconst hits = ids.filter((id) => relevant.has(id));\n\t\trecall += relevant.size === 0 ? 1 : hits.length / relevant.size;\n\t\tconst firstRelevant = ids.findIndex((id) => relevant.has(id));\n\t\treciprocalRank += firstRelevant < 0 ? 0 : 1 / (firstRelevant + 1);\n\t\trelevantCount += relevant.size;\n\t\tforgotten += fixture.relevantIds.filter((id) => options.forgottenRelevantIds?.has(id)).length;\n\t\tfor (const result of ranked) {\n\t\t\tconst item = fixture.items.find((candidate) => candidate.id === result.id);\n\t\t\tif (item?.revoked) revokedReturned++;\n\t\t\tif (item && (item.ownerId !== fixture.query.ownerId || item.projectId !== fixture.query.projectId))\n\t\t\t\tcrossProjectReturned++;\n\t\t\ttotalReturned++;\n\t\t}\n\t}\n\tlatencies.sort((left, right) => left - right);\n\tconst p95Index = Math.min(latencies.length - 1, Math.ceil(latencies.length * 0.95) - 1);\n\tconst p99Index = Math.min(latencies.length - 1, Math.ceil(latencies.length * 0.99) - 1);\n\treturn {\n\t\trecallAtK: recall / cases.length,\n\t\tmeanReciprocalRank: reciprocalRank / cases.length,\n\t\tp95LatencyMs: latencies[p95Index] ?? 0,\n\t\tp99LatencyMs: latencies[p99Index] ?? 0,\n\t\tcapacityRetention: options.capacityRetention ?? 1,\n\t\tfalseForgettingRate: relevantCount === 0 ? 0 : forgotten / relevantCount,\n\t\trevocationLeakage: totalReturned === 0 ? 0 : revokedReturned / totalReturned,\n\t\tprojectIsolationLeakage: totalReturned === 0 ? 0 : crossProjectReturned / totalReturned,\n\t};\n}\n\nexport function evaluatePromotion(\n\tbaseline: BenchmarkMetrics,\n\tcandidate: BenchmarkMetrics,\n\tthresholds: PromotionThresholds,\n): PromotionEvaluation {\n\tconst reasons: string[] = [];\n\tif (candidate.recallAtK < thresholds.minimumRecallAtK) reasons.push(\"recall_below_threshold\");\n\tif (candidate.meanReciprocalRank < thresholds.minimumMeanReciprocalRank) reasons.push(\"mrr_below_threshold\");\n\tconst latencyRatio = baseline.p95LatencyMs === 0 ? 1 : candidate.p95LatencyMs / baseline.p95LatencyMs;\n\tif (latencyRatio > thresholds.maximumLatencyRatio) reasons.push(\"latency_ratio_above_threshold\");\n\tconst p99LatencyRatio = baseline.p99LatencyMs === 0 ? 1 : candidate.p99LatencyMs / baseline.p99LatencyMs;\n\tif (p99LatencyRatio > thresholds.maximumP99LatencyRatio) reasons.push(\"p99_latency_ratio_above_threshold\");\n\tif (candidate.capacityRetention < thresholds.minimumCapacityRetention)\n\t\treasons.push(\"capacity_retention_below_threshold\");\n\tif (candidate.falseForgettingRate > thresholds.maximumFalseForgettingRate)\n\t\treasons.push(\"false_forgetting_above_threshold\");\n\tif (candidate.revocationLeakage > thresholds.maximumRevocationLeakage)\n\t\treasons.push(\"revocation_leakage_above_threshold\");\n\tif (candidate.projectIsolationLeakage > thresholds.maximumProjectIsolationLeakage)\n\t\treasons.push(\"project_isolation_leakage_above_threshold\");\n\treturn { passed: reasons.length === 0, reasons, baseline, candidate, thresholds };\n}\n\nexport class ShadowRetrievalRunner {\n\tconstructor(\n\t\tprivate readonly primary: Ranker,\n\t\tprivate readonly shadow: Ranker,\n\t\tprivate readonly onObservation?: (observation: ShadowObservation) => void,\n\t) {}\n\n\tretrieve(query: RetrievalQuery, items: readonly RetrievalItem[]): RankedItem[] {\n\t\tconst primaryStarted = performance.now();\n\t\tconst primary = this.primary.retrieve(query, items);\n\t\tconst primaryLatencyMs = performance.now() - primaryStarted;\n\t\ttry {\n\t\t\tconst shadowStarted = performance.now();\n\t\t\tconst shadow = this.shadow.retrieve(query, items);\n\t\t\tthis.onObservation?.({\n\t\t\t\tprimaryBackend: this.primary.name,\n\t\t\t\tshadowBackend: this.shadow.name,\n\t\t\t\tprimaryIds: primary.map((item) => item.id),\n\t\t\t\tshadowIds: shadow.map((item) => item.id),\n\t\t\t\tprimaryLatencyMs,\n\t\t\t\tshadowLatencyMs: performance.now() - shadowStarted,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis.onObservation?.({\n\t\t\t\tprimaryBackend: this.primary.name,\n\t\t\t\tshadowBackend: this.shadow.name,\n\t\t\t\tprimaryIds: primary.map((item) => item.id),\n\t\t\t\tshadowIds: [],\n\t\t\t\tprimaryLatencyMs,\n\t\t\t\tshadowLatencyMs: 0,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t});\n\t\t}\n\t\treturn primary;\n\t}\n}\n\nexport interface ShadowObservation {\n\tprimaryBackend: string;\n\tshadowBackend: string;\n\tprimaryIds: string[];\n\tshadowIds: string[];\n\tprimaryLatencyMs: number;\n\tshadowLatencyMs: number;\n\terror?: string;\n}\n"]}
@@ -0,0 +1,9 @@
1
+ export { CausalHeadBackend, type CausalHeadParameters, type CausalHeadState } from "./causal-head.js";
2
+ export { type LoadedCheckpoint, loadCheckpoint } from "./checkpoint.js";
3
+ export { DualAsmBackend, type DualAsmParameters, type DualAsmState } from "./dual-asm.js";
4
+ export { type BenchmarkCase, type BenchmarkMetrics, benchmark, DEFAULT_PROMOTION_THRESHOLDS, evaluatePromotion, type PromotionEvaluation, type PromotionThresholds, type Ranker, type ShadowObservation, ShadowRetrievalRunner, } from "./evaluation.js";
5
+ export { type RetrievalConfiguration, RetrievalModelRepository } from "./repository.js";
6
+ export { DeterministicFallbackRanker, StatefulLearnedRanker, VectorBaselineRanker } from "./runtime.js";
7
+ export { canonicalJson, createStateSnapshot, restoreStateSnapshot } from "./state.js";
8
+ export type { BaselineBackendName, LearnedBackendName, RankedItem, RetrievalBackend, RetrievalBackendName, RetrievalItem, RetrievalQuery, } from "./types.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACtG,OAAO,EAAE,KAAK,gBAAgB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,KAAK,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAC1F,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,SAAS,EACT,4BAA4B,EAC5B,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,MAAM,EACX,KAAK,iBAAiB,EACtB,qBAAqB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,KAAK,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACxG,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACtF,YAAY,EACX,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,cAAc,GACd,MAAM,YAAY,CAAC","sourcesContent":["export { CausalHeadBackend, type CausalHeadParameters, type CausalHeadState } from \"./causal-head.js\";\nexport { type LoadedCheckpoint, loadCheckpoint } from \"./checkpoint.js\";\nexport { DualAsmBackend, type DualAsmParameters, type DualAsmState } from \"./dual-asm.js\";\nexport {\n\ttype BenchmarkCase,\n\ttype BenchmarkMetrics,\n\tbenchmark,\n\tDEFAULT_PROMOTION_THRESHOLDS,\n\tevaluatePromotion,\n\ttype PromotionEvaluation,\n\ttype PromotionThresholds,\n\ttype Ranker,\n\ttype ShadowObservation,\n\tShadowRetrievalRunner,\n} from \"./evaluation.js\";\nexport { type RetrievalConfiguration, RetrievalModelRepository } from \"./repository.js\";\nexport { DeterministicFallbackRanker, StatefulLearnedRanker, VectorBaselineRanker } from \"./runtime.js\";\nexport { canonicalJson, createStateSnapshot, restoreStateSnapshot } from \"./state.js\";\nexport type {\n\tBaselineBackendName,\n\tLearnedBackendName,\n\tRankedItem,\n\tRetrievalBackend,\n\tRetrievalBackendName,\n\tRetrievalItem,\n\tRetrievalQuery,\n} from \"./types.js\";\n"]}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { CausalHeadBackend } from "./causal-head.js";
2
+ export { loadCheckpoint } from "./checkpoint.js";
3
+ export { DualAsmBackend } from "./dual-asm.js";
4
+ export { benchmark, DEFAULT_PROMOTION_THRESHOLDS, evaluatePromotion, ShadowRetrievalRunner, } from "./evaluation.js";
5
+ export { RetrievalModelRepository } from "./repository.js";
6
+ export { DeterministicFallbackRanker, StatefulLearnedRanker, VectorBaselineRanker } from "./runtime.js";
7
+ export { canonicalJson, createStateSnapshot, restoreStateSnapshot } from "./state.js";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAmD,MAAM,kBAAkB,CAAC;AACtG,OAAO,EAAyB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,cAAc,EAA6C,MAAM,eAAe,CAAC;AAC1F,OAAO,EAGN,SAAS,EACT,4BAA4B,EAC5B,iBAAiB,EAKjB,qBAAqB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAA+B,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACxG,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export { CausalHeadBackend, type CausalHeadParameters, type CausalHeadState } from \"./causal-head.js\";\nexport { type LoadedCheckpoint, loadCheckpoint } from \"./checkpoint.js\";\nexport { DualAsmBackend, type DualAsmParameters, type DualAsmState } from \"./dual-asm.js\";\nexport {\n\ttype BenchmarkCase,\n\ttype BenchmarkMetrics,\n\tbenchmark,\n\tDEFAULT_PROMOTION_THRESHOLDS,\n\tevaluatePromotion,\n\ttype PromotionEvaluation,\n\ttype PromotionThresholds,\n\ttype Ranker,\n\ttype ShadowObservation,\n\tShadowRetrievalRunner,\n} from \"./evaluation.js\";\nexport { type RetrievalConfiguration, RetrievalModelRepository } from \"./repository.js\";\nexport { DeterministicFallbackRanker, StatefulLearnedRanker, VectorBaselineRanker } from \"./runtime.js\";\nexport { canonicalJson, createStateSnapshot, restoreStateSnapshot } from \"./state.js\";\nexport type {\n\tBaselineBackendName,\n\tLearnedBackendName,\n\tRankedItem,\n\tRetrievalBackend,\n\tRetrievalBackendName,\n\tRetrievalItem,\n\tRetrievalQuery,\n} from \"./types.js\";\n"]}
package/dist/math.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export declare function assertVector(vector: readonly number[], dimensions: number, label: string): void;
2
+ export declare function cosine(left: readonly number[], right: readonly number[]): number;
3
+ export declare function blend(left: readonly number[], right: readonly number[], rightWeight: number): number[];
4
+ export declare function average(vectors: readonly (readonly number[])[], dimensions: number): number[];
5
+ export declare function clamp01(value: number): number;
6
+ //# sourceMappingURL=math.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAI/F;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAahF;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAEtG;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAM7F;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7C","sourcesContent":["export function assertVector(vector: readonly number[], dimensions: number, label: string): void {\n\tif (vector.length !== dimensions || vector.some((value) => !Number.isFinite(value))) {\n\t\tthrow new Error(`${label} must contain exactly ${dimensions} finite values`);\n\t}\n}\n\nexport function cosine(left: readonly number[], right: readonly number[]): number {\n\tlet dot = 0;\n\tlet leftMagnitude = 0;\n\tlet rightMagnitude = 0;\n\tfor (let index = 0; index < left.length; index++) {\n\t\tconst a = left[index] ?? 0;\n\t\tconst b = right[index] ?? 0;\n\t\tdot += a * b;\n\t\tleftMagnitude += a * a;\n\t\trightMagnitude += b * b;\n\t}\n\tif (leftMagnitude === 0 || rightMagnitude === 0) return 0;\n\treturn clamp01((dot / Math.sqrt(leftMagnitude * rightMagnitude) + 1) / 2);\n}\n\nexport function blend(left: readonly number[], right: readonly number[], rightWeight: number): number[] {\n\treturn left.map((value, index) => value * (1 - rightWeight) + (right[index] ?? 0) * rightWeight);\n}\n\nexport function average(vectors: readonly (readonly number[])[], dimensions: number): number[] {\n\tif (vectors.length === 0) return Array.from({ length: dimensions }, () => 0);\n\treturn Array.from(\n\t\t{ length: dimensions },\n\t\t(_, index) => vectors.reduce((sum, vector) => sum + (vector[index] ?? 0), 0) / vectors.length,\n\t);\n}\n\nexport function clamp01(value: number): number {\n\treturn Math.max(0, Math.min(1, value));\n}\n"]}
package/dist/math.js ADDED
@@ -0,0 +1,32 @@
1
+ export function assertVector(vector, dimensions, label) {
2
+ if (vector.length !== dimensions || vector.some((value) => !Number.isFinite(value))) {
3
+ throw new Error(`${label} must contain exactly ${dimensions} finite values`);
4
+ }
5
+ }
6
+ export function cosine(left, right) {
7
+ let dot = 0;
8
+ let leftMagnitude = 0;
9
+ let rightMagnitude = 0;
10
+ for (let index = 0; index < left.length; index++) {
11
+ const a = left[index] ?? 0;
12
+ const b = right[index] ?? 0;
13
+ dot += a * b;
14
+ leftMagnitude += a * a;
15
+ rightMagnitude += b * b;
16
+ }
17
+ if (leftMagnitude === 0 || rightMagnitude === 0)
18
+ return 0;
19
+ return clamp01((dot / Math.sqrt(leftMagnitude * rightMagnitude) + 1) / 2);
20
+ }
21
+ export function blend(left, right, rightWeight) {
22
+ return left.map((value, index) => value * (1 - rightWeight) + (right[index] ?? 0) * rightWeight);
23
+ }
24
+ export function average(vectors, dimensions) {
25
+ if (vectors.length === 0)
26
+ return Array.from({ length: dimensions }, () => 0);
27
+ return Array.from({ length: dimensions }, (_, index) => vectors.reduce((sum, vector) => sum + (vector[index] ?? 0), 0) / vectors.length);
28
+ }
29
+ export function clamp01(value) {
30
+ return Math.max(0, Math.min(1, value));
31
+ }
32
+ //# sourceMappingURL=math.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.js","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CAAC,MAAyB,EAAE,UAAkB,EAAE,KAAa,EAAQ;IAChG,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACrF,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,yBAAyB,UAAU,gBAAgB,CAAC,CAAC;IAC9E,CAAC;AAAA,CACD;AAED,MAAM,UAAU,MAAM,CAAC,IAAuB,EAAE,KAAwB,EAAU;IACjF,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QAClD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5B,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACb,aAAa,IAAI,CAAC,GAAG,CAAC,CAAC;QACvB,cAAc,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IACD,IAAI,aAAa,KAAK,CAAC,IAAI,cAAc,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC1D,OAAO,OAAO,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAAA,CAC1E;AAED,MAAM,UAAU,KAAK,CAAC,IAAuB,EAAE,KAAwB,EAAE,WAAmB,EAAY;IACvG,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC;AAAA,CACjG;AAED,MAAM,UAAU,OAAO,CAAC,OAAuC,EAAE,UAAkB,EAAY;IAC9F,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7E,OAAO,KAAK,CAAC,IAAI,CAChB,EAAE,MAAM,EAAE,UAAU,EAAE,EACtB,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAC7F,CAAC;AAAA,CACF;AAED,MAAM,UAAU,OAAO,CAAC,KAAa,EAAU;IAC9C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AAAA,CACvC","sourcesContent":["export function assertVector(vector: readonly number[], dimensions: number, label: string): void {\n\tif (vector.length !== dimensions || vector.some((value) => !Number.isFinite(value))) {\n\t\tthrow new Error(`${label} must contain exactly ${dimensions} finite values`);\n\t}\n}\n\nexport function cosine(left: readonly number[], right: readonly number[]): number {\n\tlet dot = 0;\n\tlet leftMagnitude = 0;\n\tlet rightMagnitude = 0;\n\tfor (let index = 0; index < left.length; index++) {\n\t\tconst a = left[index] ?? 0;\n\t\tconst b = right[index] ?? 0;\n\t\tdot += a * b;\n\t\tleftMagnitude += a * a;\n\t\trightMagnitude += b * b;\n\t}\n\tif (leftMagnitude === 0 || rightMagnitude === 0) return 0;\n\treturn clamp01((dot / Math.sqrt(leftMagnitude * rightMagnitude) + 1) / 2);\n}\n\nexport function blend(left: readonly number[], right: readonly number[], rightWeight: number): number[] {\n\treturn left.map((value, index) => value * (1 - rightWeight) + (right[index] ?? 0) * rightWeight);\n}\n\nexport function average(vectors: readonly (readonly number[])[], dimensions: number): number[] {\n\tif (vectors.length === 0) return Array.from({ length: dimensions }, () => 0);\n\treturn Array.from(\n\t\t{ length: dimensions },\n\t\t(_, index) => vectors.reduce((sum, vector) => sum + (vector[index] ?? 0), 0) / vectors.length,\n\t);\n}\n\nexport function clamp01(value: number): number {\n\treturn Math.max(0, Math.min(1, value));\n}\n"]}
@@ -0,0 +1,45 @@
1
+ import type { InferenceManifestContract, StateSnapshotContract } from "@asm-agent/contracts";
2
+ import type { PostgresStore } from "@asm-agent/postgres";
3
+ import type { PromotionEvaluation } from "./evaluation.js";
4
+ import type { BaselineBackendName, LearnedBackendName, RetrievalBackendName } from "./types.js";
5
+ export interface RetrievalConfiguration {
6
+ projectId: string;
7
+ primaryBackend: RetrievalBackendName;
8
+ primaryManifestId?: string;
9
+ shadowBackend?: LearnedBackendName;
10
+ shadowManifestId?: string;
11
+ previousBackend?: RetrievalBackendName;
12
+ previousManifestId?: string;
13
+ revision: number;
14
+ }
15
+ export declare class RetrievalModelRepository {
16
+ private readonly database;
17
+ private readonly options;
18
+ constructor(database: PostgresStore, options?: {
19
+ allowAsmCmPromotion?: boolean;
20
+ });
21
+ saveManifest(projectId: string, manifest: InferenceManifestContract): Promise<void>;
22
+ saveSnapshot(input: {
23
+ projectId: string;
24
+ manifestId: string;
25
+ backend: "causal_head" | "dual_asm";
26
+ snapshot: StateSnapshotContract;
27
+ }): Promise<void>;
28
+ createShadowExperiment(input: {
29
+ id: string;
30
+ projectId: string;
31
+ manifestId: string;
32
+ baselineBackend: BaselineBackendName;
33
+ candidateBackend: LearnedBackendName;
34
+ fixtureDigest: string;
35
+ }): Promise<void>;
36
+ saveEvaluation(experimentId: string, evaluationId: string, evaluation: PromotionEvaluation, confirmation?: {
37
+ seed: number;
38
+ workloadDigest: string;
39
+ }): Promise<void>;
40
+ promote(experimentId: string): Promise<RetrievalConfiguration>;
41
+ rollback(projectId: string): Promise<RetrievalConfiguration>;
42
+ getConfiguration(projectId: string): Promise<RetrievalConfiguration | undefined>;
43
+ private getConfigurationWithClient;
44
+ }
45
+ //# sourceMappingURL=repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEhG,MAAM,WAAW,sBAAsB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,oBAAoB,CAAC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,oBAAoB,CAAC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;CACjB;AAaD,qBAAa,wBAAwB;IAEnC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFzB,YACkB,QAAQ,EAAE,aAAa,EACvB,OAAO,GAAE;QAAE,mBAAmB,CAAC,EAAE,OAAO,CAAA;KAAO,EAC7D;IAEE,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBxF;IAEK,YAAY,CAAC,KAAK,EAAE;QACzB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,aAAa,GAAG,UAAU,CAAC;QACpC,QAAQ,EAAE,qBAAqB,CAAC;KAChC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhB;IAEK,sBAAsB,CAAC,KAAK,EAAE;QACnC,EAAE,EAAE,MAAM,CAAC;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,eAAe,EAAE,mBAAmB,CAAC;QACrC,gBAAgB,EAAE,kBAAkB,CAAC;QACrC,aAAa,EAAE,MAAM,CAAC;KACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBhB;IAEK,cAAc,CACnB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,mBAAmB,EAC/B,YAAY,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,GACrD,OAAO,CAAC,IAAI,CAAC,CAmBf;IAEK,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAiDnE;IAEK,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAgBjE;IAEK,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC,CAMrF;YAEa,0BAA0B;CAYxC","sourcesContent":["import type { InferenceManifestContract, StateSnapshotContract } from \"@asm-agent/contracts\";\nimport type { PostgresStore } from \"@asm-agent/postgres\";\nimport type { PromotionEvaluation } from \"./evaluation.js\";\nimport type { BaselineBackendName, LearnedBackendName, RetrievalBackendName } from \"./types.js\";\n\nexport interface RetrievalConfiguration {\n\tprojectId: string;\n\tprimaryBackend: RetrievalBackendName;\n\tprimaryManifestId?: string;\n\tshadowBackend?: LearnedBackendName;\n\tshadowManifestId?: string;\n\tpreviousBackend?: RetrievalBackendName;\n\tpreviousManifestId?: string;\n\trevision: number;\n}\n\ninterface ConfigurationRow {\n\tproject_id: string;\n\tprimary_backend: RetrievalBackendName;\n\tprimary_manifest_id: string | null;\n\tshadow_backend: LearnedBackendName | null;\n\tshadow_manifest_id: string | null;\n\tprevious_backend: RetrievalBackendName | null;\n\tprevious_manifest_id: string | null;\n\trevision: string;\n}\n\nexport class RetrievalModelRepository {\n\tconstructor(\n\t\tprivate readonly database: PostgresStore,\n\t\tprivate readonly options: { allowAsmCmPromotion?: boolean } = {},\n\t) {}\n\n\tasync saveManifest(projectId: string, manifest: InferenceManifestContract): Promise<void> {\n\t\tawait this.database.pool.query(\n\t\t\t`INSERT INTO asm_agent.inference_manifests\n\t\t\t (id, project_id, backend, model_id, model_version, artifact_digest, contract_majors,\n\t\t\t parameters, created_at) VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8::jsonb,$9)`,\n\t\t\t[\n\t\t\t\tmanifest.manifestId,\n\t\t\t\tprojectId,\n\t\t\t\tmanifest.backend,\n\t\t\t\tmanifest.modelId,\n\t\t\t\tmanifest.modelVersion,\n\t\t\t\tmanifest.artifactDigest ?? null,\n\t\t\t\tJSON.stringify(manifest.contractMajors),\n\t\t\t\tJSON.stringify(manifest.parameters),\n\t\t\t\tmanifest.createdAt,\n\t\t\t],\n\t\t);\n\t}\n\n\tasync saveSnapshot(input: {\n\t\tprojectId: string;\n\t\tmanifestId: string;\n\t\tbackend: \"causal_head\" | \"dual_asm\";\n\t\tsnapshot: StateSnapshotContract;\n\t}): Promise<void> {\n\t\tawait this.database.pool.query(\n\t\t\t`INSERT INTO asm_agent.model_state_snapshots\n\t\t\t (id, project_id, session_id, manifest_id, backend, sequence, state, digest, created_at)\n\t\t\t VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9)`,\n\t\t\t[\n\t\t\t\tinput.snapshot.snapshotId,\n\t\t\t\tinput.projectId,\n\t\t\t\tinput.snapshot.sessionId,\n\t\t\t\tinput.manifestId,\n\t\t\t\tinput.backend,\n\t\t\t\tinput.snapshot.sequence,\n\t\t\t\tJSON.stringify(input.snapshot.state),\n\t\t\t\tinput.snapshot.digest,\n\t\t\t\tinput.snapshot.createdAt,\n\t\t\t],\n\t\t);\n\t}\n\n\tasync createShadowExperiment(input: {\n\t\tid: string;\n\t\tprojectId: string;\n\t\tmanifestId: string;\n\t\tbaselineBackend: BaselineBackendName;\n\t\tcandidateBackend: LearnedBackendName;\n\t\tfixtureDigest: string;\n\t}): Promise<void> {\n\t\tawait this.database.transaction(async (client) => {\n\t\t\tawait client.query(\n\t\t\t\t`INSERT INTO asm_agent.retrieval_experiments\n\t\t\t\t (id, project_id, manifest_id, baseline_backend, candidate_backend, fixture_digest)\n\t\t\t\t VALUES ($1,$2,$3,$4,$5,$6)`,\n\t\t\t\t[\n\t\t\t\t\tinput.id,\n\t\t\t\t\tinput.projectId,\n\t\t\t\t\tinput.manifestId,\n\t\t\t\t\tinput.baselineBackend,\n\t\t\t\t\tinput.candidateBackend,\n\t\t\t\t\tinput.fixtureDigest,\n\t\t\t\t],\n\t\t\t);\n\t\t\tawait client.query(\n\t\t\t\t`INSERT INTO asm_agent.retrieval_configurations\n\t\t\t\t (project_id, primary_backend, shadow_backend, shadow_manifest_id)\n\t\t\t\t VALUES ($1,$2,$3,$4) ON CONFLICT (project_id) DO UPDATE SET\n\t\t\t\t shadow_backend = EXCLUDED.shadow_backend, shadow_manifest_id = EXCLUDED.shadow_manifest_id,\n\t\t\t\t revision = asm_agent.retrieval_configurations.revision + 1, updated_at = clock_timestamp()`,\n\t\t\t\t[input.projectId, input.baselineBackend, input.candidateBackend, input.manifestId],\n\t\t\t);\n\t\t});\n\t}\n\n\tasync saveEvaluation(\n\t\texperimentId: string,\n\t\tevaluationId: string,\n\t\tevaluation: PromotionEvaluation,\n\t\tconfirmation?: { seed: number; workloadDigest: string },\n\t): Promise<void> {\n\t\tawait this.database.pool.query(\n\t\t\t`INSERT INTO asm_agent.retrieval_evaluations\n\t\t\t (id, experiment_id, metrics, thresholds, passed, seed, workload_digest)\n\t\t\t VALUES ($1,$2,$3::jsonb,$4::jsonb,$5,$6,$7)`,\n\t\t\t[\n\t\t\t\tevaluationId,\n\t\t\t\texperimentId,\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tbaseline: evaluation.baseline,\n\t\t\t\t\tcandidate: evaluation.candidate,\n\t\t\t\t\treasons: evaluation.reasons,\n\t\t\t\t}),\n\t\t\t\tJSON.stringify(evaluation.thresholds),\n\t\t\t\tevaluation.passed,\n\t\t\t\tconfirmation?.seed ?? null,\n\t\t\t\tconfirmation?.workloadDigest ?? null,\n\t\t\t],\n\t\t);\n\t}\n\n\tasync promote(experimentId: string): Promise<RetrievalConfiguration> {\n\t\treturn this.database.transaction(async (client) => {\n\t\t\tconst experiment = await client.query<{\n\t\t\t\tproject_id: string;\n\t\t\t\tmanifest_id: string;\n\t\t\t\tcandidate_backend: LearnedBackendName;\n\t\t\t}>(\n\t\t\t\t`SELECT experiment.project_id, experiment.manifest_id, experiment.candidate_backend\n\t\t\t\t FROM asm_agent.retrieval_experiments experiment\n\t\t\t\t WHERE experiment.id = $1 AND experiment.mode = 'shadow'\n\t\t\t\t AND EXISTS (SELECT 1 FROM asm_agent.retrieval_evaluations evaluation\n\t\t\t\t WHERE evaluation.experiment_id = experiment.id AND evaluation.passed) FOR UPDATE`,\n\t\t\t\t[experimentId],\n\t\t\t);\n\t\t\tconst candidate = experiment.rows[0];\n\t\t\tif (!candidate) throw new Error(\"Experiment has no passing evaluation or is not in shadow mode\");\n\t\t\tif (candidate.candidate_backend === \"asm-cm-v1\") {\n\t\t\t\tif (!this.options.allowAsmCmPromotion) throw new Error(\"ASM-CM promotion is disabled by default\");\n\t\t\t\tconst confirmation = await client.query<{ confirmations: string }>(\n\t\t\t\t\t`SELECT count(DISTINCT workload_digest)::text AS confirmations\n\t\t\t\t\t FROM asm_agent.retrieval_evaluations\n\t\t\t\t\t WHERE experiment_id=$1 AND passed AND seed IS NOT NULL AND workload_digest IS NOT NULL\n\t\t\t\t\t AND (metrics->'candidate'->>'revocationLeakage')::double precision = 0\n\t\t\t\t\t AND (metrics->'candidate'->>'projectIsolationLeakage')::double precision = 0`,\n\t\t\t\t\t[experimentId],\n\t\t\t\t);\n\t\t\t\tif (Number(confirmation.rows[0]?.confirmations ?? 0) < 2)\n\t\t\t\t\tthrow new Error(\"ASM-CM promotion requires two independent passing workloads\");\n\t\t\t}\n\t\t\tconst configuration = await client.query<ConfigurationRow>(\n\t\t\t\t\"SELECT * FROM asm_agent.retrieval_configurations WHERE project_id = $1 FOR UPDATE\",\n\t\t\t\t[candidate.project_id],\n\t\t\t);\n\t\t\tconst current = configuration.rows[0];\n\t\t\tif (!current) throw new Error(\"Retrieval configuration is missing\");\n\t\t\tawait client.query(\n\t\t\t\t`UPDATE asm_agent.retrieval_configurations SET\n\t\t\t\t previous_backend = primary_backend, previous_manifest_id = primary_manifest_id,\n\t\t\t\t primary_backend = $2, primary_manifest_id = $3, shadow_backend = NULL,\n\t\t\t\t shadow_manifest_id = NULL, revision = revision + 1, updated_at = clock_timestamp()\n\t\t\t\t WHERE project_id = $1`,\n\t\t\t\t[candidate.project_id, candidate.candidate_backend, candidate.manifest_id],\n\t\t\t);\n\t\t\tawait client.query(\n\t\t\t\t\"UPDATE asm_agent.retrieval_experiments SET mode = 'promoted', updated_at = clock_timestamp() WHERE id = $1\",\n\t\t\t\t[experimentId],\n\t\t\t);\n\t\t\treturn this.getConfigurationWithClient(client, candidate.project_id);\n\t\t});\n\t}\n\n\tasync rollback(projectId: string): Promise<RetrievalConfiguration> {\n\t\treturn this.database.transaction(async (client) => {\n\t\t\tconst result = await client.query<ConfigurationRow>(\n\t\t\t\t\"SELECT * FROM asm_agent.retrieval_configurations WHERE project_id = $1 FOR UPDATE\",\n\t\t\t\t[projectId],\n\t\t\t);\n\t\t\tconst current = result.rows[0];\n\t\t\tif (!current?.previous_backend) throw new Error(\"No retrieval configuration is available for rollback\");\n\t\t\tawait client.query(\n\t\t\t\t`UPDATE asm_agent.retrieval_configurations SET primary_backend = previous_backend,\n\t\t\t\t primary_manifest_id = previous_manifest_id, previous_backend = NULL, previous_manifest_id = NULL,\n\t\t\t\t revision = revision + 1, updated_at = clock_timestamp() WHERE project_id = $1`,\n\t\t\t\t[projectId],\n\t\t\t);\n\t\t\treturn this.getConfigurationWithClient(client, projectId);\n\t\t});\n\t}\n\n\tasync getConfiguration(projectId: string): Promise<RetrievalConfiguration | undefined> {\n\t\tconst result = await this.database.pool.query<ConfigurationRow>(\n\t\t\t\"SELECT * FROM asm_agent.retrieval_configurations WHERE project_id = $1\",\n\t\t\t[projectId],\n\t\t);\n\t\treturn result.rows[0] ? fromConfigurationRow(result.rows[0]) : undefined;\n\t}\n\n\tprivate async getConfigurationWithClient(\n\t\tclient: Parameters<Parameters<PostgresStore[\"transaction\"]>[0]>[0],\n\t\tprojectId: string,\n\t): Promise<RetrievalConfiguration> {\n\t\tconst result = await client.query<ConfigurationRow>(\n\t\t\t\"SELECT * FROM asm_agent.retrieval_configurations WHERE project_id = $1\",\n\t\t\t[projectId],\n\t\t);\n\t\tconst row = result.rows[0];\n\t\tif (!row) throw new Error(\"Retrieval configuration is missing\");\n\t\treturn fromConfigurationRow(row);\n\t}\n}\n\nfunction fromConfigurationRow(row: ConfigurationRow): RetrievalConfiguration {\n\treturn {\n\t\tprojectId: row.project_id,\n\t\tprimaryBackend: row.primary_backend,\n\t\tprimaryManifestId: row.primary_manifest_id ?? undefined,\n\t\tshadowBackend: row.shadow_backend ?? undefined,\n\t\tshadowManifestId: row.shadow_manifest_id ?? undefined,\n\t\tpreviousBackend: row.previous_backend ?? undefined,\n\t\tpreviousManifestId: row.previous_manifest_id ?? undefined,\n\t\trevision: Number(row.revision),\n\t};\n}\n"]}
@@ -0,0 +1,144 @@
1
+ export class RetrievalModelRepository {
2
+ database;
3
+ options;
4
+ constructor(database, options = {}) {
5
+ this.database = database;
6
+ this.options = options;
7
+ }
8
+ async saveManifest(projectId, manifest) {
9
+ await this.database.pool.query(`INSERT INTO asm_agent.inference_manifests
10
+ (id, project_id, backend, model_id, model_version, artifact_digest, contract_majors,
11
+ parameters, created_at) VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8::jsonb,$9)`, [
12
+ manifest.manifestId,
13
+ projectId,
14
+ manifest.backend,
15
+ manifest.modelId,
16
+ manifest.modelVersion,
17
+ manifest.artifactDigest ?? null,
18
+ JSON.stringify(manifest.contractMajors),
19
+ JSON.stringify(manifest.parameters),
20
+ manifest.createdAt,
21
+ ]);
22
+ }
23
+ async saveSnapshot(input) {
24
+ await this.database.pool.query(`INSERT INTO asm_agent.model_state_snapshots
25
+ (id, project_id, session_id, manifest_id, backend, sequence, state, digest, created_at)
26
+ VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9)`, [
27
+ input.snapshot.snapshotId,
28
+ input.projectId,
29
+ input.snapshot.sessionId,
30
+ input.manifestId,
31
+ input.backend,
32
+ input.snapshot.sequence,
33
+ JSON.stringify(input.snapshot.state),
34
+ input.snapshot.digest,
35
+ input.snapshot.createdAt,
36
+ ]);
37
+ }
38
+ async createShadowExperiment(input) {
39
+ await this.database.transaction(async (client) => {
40
+ await client.query(`INSERT INTO asm_agent.retrieval_experiments
41
+ (id, project_id, manifest_id, baseline_backend, candidate_backend, fixture_digest)
42
+ VALUES ($1,$2,$3,$4,$5,$6)`, [
43
+ input.id,
44
+ input.projectId,
45
+ input.manifestId,
46
+ input.baselineBackend,
47
+ input.candidateBackend,
48
+ input.fixtureDigest,
49
+ ]);
50
+ await client.query(`INSERT INTO asm_agent.retrieval_configurations
51
+ (project_id, primary_backend, shadow_backend, shadow_manifest_id)
52
+ VALUES ($1,$2,$3,$4) ON CONFLICT (project_id) DO UPDATE SET
53
+ shadow_backend = EXCLUDED.shadow_backend, shadow_manifest_id = EXCLUDED.shadow_manifest_id,
54
+ revision = asm_agent.retrieval_configurations.revision + 1, updated_at = clock_timestamp()`, [input.projectId, input.baselineBackend, input.candidateBackend, input.manifestId]);
55
+ });
56
+ }
57
+ async saveEvaluation(experimentId, evaluationId, evaluation, confirmation) {
58
+ await this.database.pool.query(`INSERT INTO asm_agent.retrieval_evaluations
59
+ (id, experiment_id, metrics, thresholds, passed, seed, workload_digest)
60
+ VALUES ($1,$2,$3::jsonb,$4::jsonb,$5,$6,$7)`, [
61
+ evaluationId,
62
+ experimentId,
63
+ JSON.stringify({
64
+ baseline: evaluation.baseline,
65
+ candidate: evaluation.candidate,
66
+ reasons: evaluation.reasons,
67
+ }),
68
+ JSON.stringify(evaluation.thresholds),
69
+ evaluation.passed,
70
+ confirmation?.seed ?? null,
71
+ confirmation?.workloadDigest ?? null,
72
+ ]);
73
+ }
74
+ async promote(experimentId) {
75
+ return this.database.transaction(async (client) => {
76
+ const experiment = await client.query(`SELECT experiment.project_id, experiment.manifest_id, experiment.candidate_backend
77
+ FROM asm_agent.retrieval_experiments experiment
78
+ WHERE experiment.id = $1 AND experiment.mode = 'shadow'
79
+ AND EXISTS (SELECT 1 FROM asm_agent.retrieval_evaluations evaluation
80
+ WHERE evaluation.experiment_id = experiment.id AND evaluation.passed) FOR UPDATE`, [experimentId]);
81
+ const candidate = experiment.rows[0];
82
+ if (!candidate)
83
+ throw new Error("Experiment has no passing evaluation or is not in shadow mode");
84
+ if (candidate.candidate_backend === "asm-cm-v1") {
85
+ if (!this.options.allowAsmCmPromotion)
86
+ throw new Error("ASM-CM promotion is disabled by default");
87
+ const confirmation = await client.query(`SELECT count(DISTINCT workload_digest)::text AS confirmations
88
+ FROM asm_agent.retrieval_evaluations
89
+ WHERE experiment_id=$1 AND passed AND seed IS NOT NULL AND workload_digest IS NOT NULL
90
+ AND (metrics->'candidate'->>'revocationLeakage')::double precision = 0
91
+ AND (metrics->'candidate'->>'projectIsolationLeakage')::double precision = 0`, [experimentId]);
92
+ if (Number(confirmation.rows[0]?.confirmations ?? 0) < 2)
93
+ throw new Error("ASM-CM promotion requires two independent passing workloads");
94
+ }
95
+ const configuration = await client.query("SELECT * FROM asm_agent.retrieval_configurations WHERE project_id = $1 FOR UPDATE", [candidate.project_id]);
96
+ const current = configuration.rows[0];
97
+ if (!current)
98
+ throw new Error("Retrieval configuration is missing");
99
+ await client.query(`UPDATE asm_agent.retrieval_configurations SET
100
+ previous_backend = primary_backend, previous_manifest_id = primary_manifest_id,
101
+ primary_backend = $2, primary_manifest_id = $3, shadow_backend = NULL,
102
+ shadow_manifest_id = NULL, revision = revision + 1, updated_at = clock_timestamp()
103
+ WHERE project_id = $1`, [candidate.project_id, candidate.candidate_backend, candidate.manifest_id]);
104
+ await client.query("UPDATE asm_agent.retrieval_experiments SET mode = 'promoted', updated_at = clock_timestamp() WHERE id = $1", [experimentId]);
105
+ return this.getConfigurationWithClient(client, candidate.project_id);
106
+ });
107
+ }
108
+ async rollback(projectId) {
109
+ return this.database.transaction(async (client) => {
110
+ const result = await client.query("SELECT * FROM asm_agent.retrieval_configurations WHERE project_id = $1 FOR UPDATE", [projectId]);
111
+ const current = result.rows[0];
112
+ if (!current?.previous_backend)
113
+ throw new Error("No retrieval configuration is available for rollback");
114
+ await client.query(`UPDATE asm_agent.retrieval_configurations SET primary_backend = previous_backend,
115
+ primary_manifest_id = previous_manifest_id, previous_backend = NULL, previous_manifest_id = NULL,
116
+ revision = revision + 1, updated_at = clock_timestamp() WHERE project_id = $1`, [projectId]);
117
+ return this.getConfigurationWithClient(client, projectId);
118
+ });
119
+ }
120
+ async getConfiguration(projectId) {
121
+ const result = await this.database.pool.query("SELECT * FROM asm_agent.retrieval_configurations WHERE project_id = $1", [projectId]);
122
+ return result.rows[0] ? fromConfigurationRow(result.rows[0]) : undefined;
123
+ }
124
+ async getConfigurationWithClient(client, projectId) {
125
+ const result = await client.query("SELECT * FROM asm_agent.retrieval_configurations WHERE project_id = $1", [projectId]);
126
+ const row = result.rows[0];
127
+ if (!row)
128
+ throw new Error("Retrieval configuration is missing");
129
+ return fromConfigurationRow(row);
130
+ }
131
+ }
132
+ function fromConfigurationRow(row) {
133
+ return {
134
+ projectId: row.project_id,
135
+ primaryBackend: row.primary_backend,
136
+ primaryManifestId: row.primary_manifest_id ?? undefined,
137
+ shadowBackend: row.shadow_backend ?? undefined,
138
+ shadowManifestId: row.shadow_manifest_id ?? undefined,
139
+ previousBackend: row.previous_backend ?? undefined,
140
+ previousManifestId: row.previous_manifest_id ?? undefined,
141
+ revision: Number(row.revision),
142
+ };
143
+ }
144
+ //# sourceMappingURL=repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.js","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InferenceManifestContract, StateSnapshotContract } from \"@asm-agent/contracts\";\nimport type { PostgresStore } from \"@asm-agent/postgres\";\nimport type { PromotionEvaluation } from \"./evaluation.js\";\nimport type { BaselineBackendName, LearnedBackendName, RetrievalBackendName } from \"./types.js\";\n\nexport interface RetrievalConfiguration {\n\tprojectId: string;\n\tprimaryBackend: RetrievalBackendName;\n\tprimaryManifestId?: string;\n\tshadowBackend?: LearnedBackendName;\n\tshadowManifestId?: string;\n\tpreviousBackend?: RetrievalBackendName;\n\tpreviousManifestId?: string;\n\trevision: number;\n}\n\ninterface ConfigurationRow {\n\tproject_id: string;\n\tprimary_backend: RetrievalBackendName;\n\tprimary_manifest_id: string | null;\n\tshadow_backend: LearnedBackendName | null;\n\tshadow_manifest_id: string | null;\n\tprevious_backend: RetrievalBackendName | null;\n\tprevious_manifest_id: string | null;\n\trevision: string;\n}\n\nexport class RetrievalModelRepository {\n\tconstructor(\n\t\tprivate readonly database: PostgresStore,\n\t\tprivate readonly options: { allowAsmCmPromotion?: boolean } = {},\n\t) {}\n\n\tasync saveManifest(projectId: string, manifest: InferenceManifestContract): Promise<void> {\n\t\tawait this.database.pool.query(\n\t\t\t`INSERT INTO asm_agent.inference_manifests\n\t\t\t (id, project_id, backend, model_id, model_version, artifact_digest, contract_majors,\n\t\t\t parameters, created_at) VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8::jsonb,$9)`,\n\t\t\t[\n\t\t\t\tmanifest.manifestId,\n\t\t\t\tprojectId,\n\t\t\t\tmanifest.backend,\n\t\t\t\tmanifest.modelId,\n\t\t\t\tmanifest.modelVersion,\n\t\t\t\tmanifest.artifactDigest ?? null,\n\t\t\t\tJSON.stringify(manifest.contractMajors),\n\t\t\t\tJSON.stringify(manifest.parameters),\n\t\t\t\tmanifest.createdAt,\n\t\t\t],\n\t\t);\n\t}\n\n\tasync saveSnapshot(input: {\n\t\tprojectId: string;\n\t\tmanifestId: string;\n\t\tbackend: \"causal_head\" | \"dual_asm\";\n\t\tsnapshot: StateSnapshotContract;\n\t}): Promise<void> {\n\t\tawait this.database.pool.query(\n\t\t\t`INSERT INTO asm_agent.model_state_snapshots\n\t\t\t (id, project_id, session_id, manifest_id, backend, sequence, state, digest, created_at)\n\t\t\t VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9)`,\n\t\t\t[\n\t\t\t\tinput.snapshot.snapshotId,\n\t\t\t\tinput.projectId,\n\t\t\t\tinput.snapshot.sessionId,\n\t\t\t\tinput.manifestId,\n\t\t\t\tinput.backend,\n\t\t\t\tinput.snapshot.sequence,\n\t\t\t\tJSON.stringify(input.snapshot.state),\n\t\t\t\tinput.snapshot.digest,\n\t\t\t\tinput.snapshot.createdAt,\n\t\t\t],\n\t\t);\n\t}\n\n\tasync createShadowExperiment(input: {\n\t\tid: string;\n\t\tprojectId: string;\n\t\tmanifestId: string;\n\t\tbaselineBackend: BaselineBackendName;\n\t\tcandidateBackend: LearnedBackendName;\n\t\tfixtureDigest: string;\n\t}): Promise<void> {\n\t\tawait this.database.transaction(async (client) => {\n\t\t\tawait client.query(\n\t\t\t\t`INSERT INTO asm_agent.retrieval_experiments\n\t\t\t\t (id, project_id, manifest_id, baseline_backend, candidate_backend, fixture_digest)\n\t\t\t\t VALUES ($1,$2,$3,$4,$5,$6)`,\n\t\t\t\t[\n\t\t\t\t\tinput.id,\n\t\t\t\t\tinput.projectId,\n\t\t\t\t\tinput.manifestId,\n\t\t\t\t\tinput.baselineBackend,\n\t\t\t\t\tinput.candidateBackend,\n\t\t\t\t\tinput.fixtureDigest,\n\t\t\t\t],\n\t\t\t);\n\t\t\tawait client.query(\n\t\t\t\t`INSERT INTO asm_agent.retrieval_configurations\n\t\t\t\t (project_id, primary_backend, shadow_backend, shadow_manifest_id)\n\t\t\t\t VALUES ($1,$2,$3,$4) ON CONFLICT (project_id) DO UPDATE SET\n\t\t\t\t shadow_backend = EXCLUDED.shadow_backend, shadow_manifest_id = EXCLUDED.shadow_manifest_id,\n\t\t\t\t revision = asm_agent.retrieval_configurations.revision + 1, updated_at = clock_timestamp()`,\n\t\t\t\t[input.projectId, input.baselineBackend, input.candidateBackend, input.manifestId],\n\t\t\t);\n\t\t});\n\t}\n\n\tasync saveEvaluation(\n\t\texperimentId: string,\n\t\tevaluationId: string,\n\t\tevaluation: PromotionEvaluation,\n\t\tconfirmation?: { seed: number; workloadDigest: string },\n\t): Promise<void> {\n\t\tawait this.database.pool.query(\n\t\t\t`INSERT INTO asm_agent.retrieval_evaluations\n\t\t\t (id, experiment_id, metrics, thresholds, passed, seed, workload_digest)\n\t\t\t VALUES ($1,$2,$3::jsonb,$4::jsonb,$5,$6,$7)`,\n\t\t\t[\n\t\t\t\tevaluationId,\n\t\t\t\texperimentId,\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tbaseline: evaluation.baseline,\n\t\t\t\t\tcandidate: evaluation.candidate,\n\t\t\t\t\treasons: evaluation.reasons,\n\t\t\t\t}),\n\t\t\t\tJSON.stringify(evaluation.thresholds),\n\t\t\t\tevaluation.passed,\n\t\t\t\tconfirmation?.seed ?? null,\n\t\t\t\tconfirmation?.workloadDigest ?? null,\n\t\t\t],\n\t\t);\n\t}\n\n\tasync promote(experimentId: string): Promise<RetrievalConfiguration> {\n\t\treturn this.database.transaction(async (client) => {\n\t\t\tconst experiment = await client.query<{\n\t\t\t\tproject_id: string;\n\t\t\t\tmanifest_id: string;\n\t\t\t\tcandidate_backend: LearnedBackendName;\n\t\t\t}>(\n\t\t\t\t`SELECT experiment.project_id, experiment.manifest_id, experiment.candidate_backend\n\t\t\t\t FROM asm_agent.retrieval_experiments experiment\n\t\t\t\t WHERE experiment.id = $1 AND experiment.mode = 'shadow'\n\t\t\t\t AND EXISTS (SELECT 1 FROM asm_agent.retrieval_evaluations evaluation\n\t\t\t\t WHERE evaluation.experiment_id = experiment.id AND evaluation.passed) FOR UPDATE`,\n\t\t\t\t[experimentId],\n\t\t\t);\n\t\t\tconst candidate = experiment.rows[0];\n\t\t\tif (!candidate) throw new Error(\"Experiment has no passing evaluation or is not in shadow mode\");\n\t\t\tif (candidate.candidate_backend === \"asm-cm-v1\") {\n\t\t\t\tif (!this.options.allowAsmCmPromotion) throw new Error(\"ASM-CM promotion is disabled by default\");\n\t\t\t\tconst confirmation = await client.query<{ confirmations: string }>(\n\t\t\t\t\t`SELECT count(DISTINCT workload_digest)::text AS confirmations\n\t\t\t\t\t FROM asm_agent.retrieval_evaluations\n\t\t\t\t\t WHERE experiment_id=$1 AND passed AND seed IS NOT NULL AND workload_digest IS NOT NULL\n\t\t\t\t\t AND (metrics->'candidate'->>'revocationLeakage')::double precision = 0\n\t\t\t\t\t AND (metrics->'candidate'->>'projectIsolationLeakage')::double precision = 0`,\n\t\t\t\t\t[experimentId],\n\t\t\t\t);\n\t\t\t\tif (Number(confirmation.rows[0]?.confirmations ?? 0) < 2)\n\t\t\t\t\tthrow new Error(\"ASM-CM promotion requires two independent passing workloads\");\n\t\t\t}\n\t\t\tconst configuration = await client.query<ConfigurationRow>(\n\t\t\t\t\"SELECT * FROM asm_agent.retrieval_configurations WHERE project_id = $1 FOR UPDATE\",\n\t\t\t\t[candidate.project_id],\n\t\t\t);\n\t\t\tconst current = configuration.rows[0];\n\t\t\tif (!current) throw new Error(\"Retrieval configuration is missing\");\n\t\t\tawait client.query(\n\t\t\t\t`UPDATE asm_agent.retrieval_configurations SET\n\t\t\t\t previous_backend = primary_backend, previous_manifest_id = primary_manifest_id,\n\t\t\t\t primary_backend = $2, primary_manifest_id = $3, shadow_backend = NULL,\n\t\t\t\t shadow_manifest_id = NULL, revision = revision + 1, updated_at = clock_timestamp()\n\t\t\t\t WHERE project_id = $1`,\n\t\t\t\t[candidate.project_id, candidate.candidate_backend, candidate.manifest_id],\n\t\t\t);\n\t\t\tawait client.query(\n\t\t\t\t\"UPDATE asm_agent.retrieval_experiments SET mode = 'promoted', updated_at = clock_timestamp() WHERE id = $1\",\n\t\t\t\t[experimentId],\n\t\t\t);\n\t\t\treturn this.getConfigurationWithClient(client, candidate.project_id);\n\t\t});\n\t}\n\n\tasync rollback(projectId: string): Promise<RetrievalConfiguration> {\n\t\treturn this.database.transaction(async (client) => {\n\t\t\tconst result = await client.query<ConfigurationRow>(\n\t\t\t\t\"SELECT * FROM asm_agent.retrieval_configurations WHERE project_id = $1 FOR UPDATE\",\n\t\t\t\t[projectId],\n\t\t\t);\n\t\t\tconst current = result.rows[0];\n\t\t\tif (!current?.previous_backend) throw new Error(\"No retrieval configuration is available for rollback\");\n\t\t\tawait client.query(\n\t\t\t\t`UPDATE asm_agent.retrieval_configurations SET primary_backend = previous_backend,\n\t\t\t\t primary_manifest_id = previous_manifest_id, previous_backend = NULL, previous_manifest_id = NULL,\n\t\t\t\t revision = revision + 1, updated_at = clock_timestamp() WHERE project_id = $1`,\n\t\t\t\t[projectId],\n\t\t\t);\n\t\t\treturn this.getConfigurationWithClient(client, projectId);\n\t\t});\n\t}\n\n\tasync getConfiguration(projectId: string): Promise<RetrievalConfiguration | undefined> {\n\t\tconst result = await this.database.pool.query<ConfigurationRow>(\n\t\t\t\"SELECT * FROM asm_agent.retrieval_configurations WHERE project_id = $1\",\n\t\t\t[projectId],\n\t\t);\n\t\treturn result.rows[0] ? fromConfigurationRow(result.rows[0]) : undefined;\n\t}\n\n\tprivate async getConfigurationWithClient(\n\t\tclient: Parameters<Parameters<PostgresStore[\"transaction\"]>[0]>[0],\n\t\tprojectId: string,\n\t): Promise<RetrievalConfiguration> {\n\t\tconst result = await client.query<ConfigurationRow>(\n\t\t\t\"SELECT * FROM asm_agent.retrieval_configurations WHERE project_id = $1\",\n\t\t\t[projectId],\n\t\t);\n\t\tconst row = result.rows[0];\n\t\tif (!row) throw new Error(\"Retrieval configuration is missing\");\n\t\treturn fromConfigurationRow(row);\n\t}\n}\n\nfunction fromConfigurationRow(row: ConfigurationRow): RetrievalConfiguration {\n\treturn {\n\t\tprojectId: row.project_id,\n\t\tprimaryBackend: row.primary_backend,\n\t\tprimaryManifestId: row.primary_manifest_id ?? undefined,\n\t\tshadowBackend: row.shadow_backend ?? undefined,\n\t\tshadowManifestId: row.shadow_manifest_id ?? undefined,\n\t\tpreviousBackend: row.previous_backend ?? undefined,\n\t\tpreviousManifestId: row.previous_manifest_id ?? undefined,\n\t\trevision: Number(row.revision),\n\t};\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import type { Ranker } from "./evaluation.js";
2
+ import type { RankedItem, RetrievalBackend, RetrievalItem, RetrievalQuery } from "./types.js";
3
+ export declare class VectorBaselineRanker implements Ranker {
4
+ readonly dimensions: number;
5
+ readonly name = "vector-l2-v1";
6
+ constructor(dimensions: number);
7
+ retrieve(query: RetrievalQuery, items: readonly RetrievalItem[]): RankedItem[];
8
+ }
9
+ export declare class StatefulLearnedRanker<State extends object> implements Ranker {
10
+ readonly backend: RetrievalBackend<State>;
11
+ private state;
12
+ readonly name: string;
13
+ constructor(backend: RetrievalBackend<State>, state: State);
14
+ retrieve(query: RetrievalQuery, items: readonly RetrievalItem[]): RankedItem[];
15
+ update(selected: readonly RetrievalItem[], feedback?: "positive" | "negative"): State;
16
+ getState(): State;
17
+ }
18
+ export declare class DeterministicFallbackRanker implements Ranker {
19
+ private readonly candidate;
20
+ private readonly fallback;
21
+ readonly name: string;
22
+ constructor(candidate: Ranker, fallback: Ranker);
23
+ retrieve(query: RetrievalQuery, items: readonly RetrievalItem[]): RankedItem[];
24
+ }
25
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE9F,qBAAa,oBAAqB,YAAW,MAAM;IAGtC,QAAQ,CAAC,UAAU,EAAE,MAAM;IAFvC,QAAQ,CAAC,IAAI,kBAAkB;IAE/B,YAAqB,UAAU,EAAE,MAAM,EAAI;IAE3C,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,UAAU,EAAE,CAc7E;CACD;AAED,qBAAa,qBAAqB,CAAC,KAAK,SAAS,MAAM,CAAE,YAAW,MAAM;IAIxE,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,KAAK,CAAC;IACzC,OAAO,CAAC,KAAK;IAJd,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,YACU,OAAO,EAAE,gBAAgB,CAAC,KAAK,CAAC,EACjC,KAAK,EAAE,KAAK,EAGpB;IAED,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,UAAU,EAAE,CAE7E;IAED,MAAM,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,EAAE,QAAQ,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,KAAK,CAGpF;IAED,QAAQ,IAAI,KAAK,CAEhB;CACD;AAED,qBAAa,2BAA4B,YAAW,MAAM;IAIxD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAJ1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,YACkB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAGjC;IAED,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,UAAU,EAAE,CAM7E;CACD","sourcesContent":["import type { Ranker } from \"./evaluation.js\";\nimport { assertVector, cosine } from \"./math.js\";\nimport type { RankedItem, RetrievalBackend, RetrievalItem, RetrievalQuery } from \"./types.js\";\n\nexport class VectorBaselineRanker implements Ranker {\n\treadonly name = \"vector-l2-v1\";\n\n\tconstructor(readonly dimensions: number) {}\n\n\tretrieve(query: RetrievalQuery, items: readonly RetrievalItem[]): RankedItem[] {\n\t\tassertVector(query.embedding, this.dimensions, \"query embedding\");\n\t\treturn items\n\t\t\t.filter((item) => {\n\t\t\t\tassertVector(item.embedding, this.dimensions, \"item embedding\");\n\t\t\t\treturn item.ownerId === query.ownerId && item.projectId === query.projectId && !item.revoked;\n\t\t\t})\n\t\t\t.map((item) => ({\n\t\t\t\tid: item.id,\n\t\t\t\tscore: cosine(query.embedding, item.embedding),\n\t\t\t\treasonCodes: [\"vector_similarity\"],\n\t\t\t}))\n\t\t\t.sort((left, right) => right.score - left.score || left.id.localeCompare(right.id))\n\t\t\t.slice(0, query.limit);\n\t}\n}\n\nexport class StatefulLearnedRanker<State extends object> implements Ranker {\n\treadonly name: string;\n\n\tconstructor(\n\t\treadonly backend: RetrievalBackend<State>,\n\t\tprivate state: State,\n\t) {\n\t\tthis.name = backend.name;\n\t}\n\n\tretrieve(query: RetrievalQuery, items: readonly RetrievalItem[]): RankedItem[] {\n\t\treturn this.backend.retrieve(query, items, this.state);\n\t}\n\n\tupdate(selected: readonly RetrievalItem[], feedback?: \"positive\" | \"negative\"): State {\n\t\tthis.state = this.backend.update(this.state, selected, feedback);\n\t\treturn this.getState();\n\t}\n\n\tgetState(): State {\n\t\treturn structuredClone(this.state);\n\t}\n}\n\nexport class DeterministicFallbackRanker implements Ranker {\n\treadonly name: string;\n\n\tconstructor(\n\t\tprivate readonly candidate: Ranker,\n\t\tprivate readonly fallback: Ranker,\n\t) {\n\t\tthis.name = `${candidate.name}-with-${fallback.name}-fallback`;\n\t}\n\n\tretrieve(query: RetrievalQuery, items: readonly RetrievalItem[]): RankedItem[] {\n\t\ttry {\n\t\t\treturn this.candidate.retrieve(query, items);\n\t\t} catch {\n\t\t\treturn this.fallback.retrieve(query, items);\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,62 @@
1
+ import { assertVector, cosine } from "./math.js";
2
+ export class VectorBaselineRanker {
3
+ dimensions;
4
+ name = "vector-l2-v1";
5
+ constructor(dimensions) {
6
+ this.dimensions = dimensions;
7
+ }
8
+ retrieve(query, items) {
9
+ assertVector(query.embedding, this.dimensions, "query embedding");
10
+ return items
11
+ .filter((item) => {
12
+ assertVector(item.embedding, this.dimensions, "item embedding");
13
+ return item.ownerId === query.ownerId && item.projectId === query.projectId && !item.revoked;
14
+ })
15
+ .map((item) => ({
16
+ id: item.id,
17
+ score: cosine(query.embedding, item.embedding),
18
+ reasonCodes: ["vector_similarity"],
19
+ }))
20
+ .sort((left, right) => right.score - left.score || left.id.localeCompare(right.id))
21
+ .slice(0, query.limit);
22
+ }
23
+ }
24
+ export class StatefulLearnedRanker {
25
+ backend;
26
+ state;
27
+ name;
28
+ constructor(backend, state) {
29
+ this.backend = backend;
30
+ this.state = state;
31
+ this.name = backend.name;
32
+ }
33
+ retrieve(query, items) {
34
+ return this.backend.retrieve(query, items, this.state);
35
+ }
36
+ update(selected, feedback) {
37
+ this.state = this.backend.update(this.state, selected, feedback);
38
+ return this.getState();
39
+ }
40
+ getState() {
41
+ return structuredClone(this.state);
42
+ }
43
+ }
44
+ export class DeterministicFallbackRanker {
45
+ candidate;
46
+ fallback;
47
+ name;
48
+ constructor(candidate, fallback) {
49
+ this.candidate = candidate;
50
+ this.fallback = fallback;
51
+ this.name = `${candidate.name}-with-${fallback.name}-fallback`;
52
+ }
53
+ retrieve(query, items) {
54
+ try {
55
+ return this.candidate.retrieve(query, items);
56
+ }
57
+ catch {
58
+ return this.fallback.retrieve(query, items);
59
+ }
60
+ }
61
+ }
62
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGjD,MAAM,OAAO,oBAAoB;IAGX,UAAU;IAFtB,IAAI,GAAG,cAAc,CAAC;IAE/B,YAAqB,UAAkB,EAAE;0BAApB,UAAU;IAAW,CAAC;IAE3C,QAAQ,CAAC,KAAqB,EAAE,KAA+B,EAAgB;QAC9E,YAAY,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC;QAClE,OAAO,KAAK;aACV,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACjB,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;YAChE,OAAO,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;QAAA,CAC7F,CAAC;aACD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACf,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC;YAC9C,WAAW,EAAE,CAAC,mBAAmB,CAAC;SAClC,CAAC,CAAC;aACF,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;aAClF,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAAA,CACxB;CACD;AAED,MAAM,OAAO,qBAAqB;IAIvB,OAAO;IACR,KAAK;IAJL,IAAI,CAAS;IAEtB,YACU,OAAgC,EACjC,KAAY,EACnB;uBAFQ,OAAO;qBACR,KAAK;QAEb,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAAA,CACzB;IAED,QAAQ,CAAC,KAAqB,EAAE,KAA+B,EAAgB;QAC9E,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAAA,CACvD;IAED,MAAM,CAAC,QAAkC,EAAE,QAAkC,EAAS;QACrF,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACjE,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;IAAA,CACvB;IAED,QAAQ,GAAU;QACjB,OAAO,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAAA,CACnC;CACD;AAED,MAAM,OAAO,2BAA2B;IAIrB,SAAS;IACT,QAAQ;IAJjB,IAAI,CAAS;IAEtB,YACkB,SAAiB,EACjB,QAAgB,EAChC;yBAFgB,SAAS;wBACT,QAAQ;QAEzB,IAAI,CAAC,IAAI,GAAG,GAAG,SAAS,CAAC,IAAI,SAAS,QAAQ,CAAC,IAAI,WAAW,CAAC;IAAA,CAC/D;IAED,QAAQ,CAAC,KAAqB,EAAE,KAA+B,EAAgB;QAC9E,IAAI,CAAC;YACJ,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC7C,CAAC;IAAA,CACD;CACD","sourcesContent":["import type { Ranker } from \"./evaluation.js\";\nimport { assertVector, cosine } from \"./math.js\";\nimport type { RankedItem, RetrievalBackend, RetrievalItem, RetrievalQuery } from \"./types.js\";\n\nexport class VectorBaselineRanker implements Ranker {\n\treadonly name = \"vector-l2-v1\";\n\n\tconstructor(readonly dimensions: number) {}\n\n\tretrieve(query: RetrievalQuery, items: readonly RetrievalItem[]): RankedItem[] {\n\t\tassertVector(query.embedding, this.dimensions, \"query embedding\");\n\t\treturn items\n\t\t\t.filter((item) => {\n\t\t\t\tassertVector(item.embedding, this.dimensions, \"item embedding\");\n\t\t\t\treturn item.ownerId === query.ownerId && item.projectId === query.projectId && !item.revoked;\n\t\t\t})\n\t\t\t.map((item) => ({\n\t\t\t\tid: item.id,\n\t\t\t\tscore: cosine(query.embedding, item.embedding),\n\t\t\t\treasonCodes: [\"vector_similarity\"],\n\t\t\t}))\n\t\t\t.sort((left, right) => right.score - left.score || left.id.localeCompare(right.id))\n\t\t\t.slice(0, query.limit);\n\t}\n}\n\nexport class StatefulLearnedRanker<State extends object> implements Ranker {\n\treadonly name: string;\n\n\tconstructor(\n\t\treadonly backend: RetrievalBackend<State>,\n\t\tprivate state: State,\n\t) {\n\t\tthis.name = backend.name;\n\t}\n\n\tretrieve(query: RetrievalQuery, items: readonly RetrievalItem[]): RankedItem[] {\n\t\treturn this.backend.retrieve(query, items, this.state);\n\t}\n\n\tupdate(selected: readonly RetrievalItem[], feedback?: \"positive\" | \"negative\"): State {\n\t\tthis.state = this.backend.update(this.state, selected, feedback);\n\t\treturn this.getState();\n\t}\n\n\tgetState(): State {\n\t\treturn structuredClone(this.state);\n\t}\n}\n\nexport class DeterministicFallbackRanker implements Ranker {\n\treadonly name: string;\n\n\tconstructor(\n\t\tprivate readonly candidate: Ranker,\n\t\tprivate readonly fallback: Ranker,\n\t) {\n\t\tthis.name = `${candidate.name}-with-${fallback.name}-fallback`;\n\t}\n\n\tretrieve(query: RetrievalQuery, items: readonly RetrievalItem[]): RankedItem[] {\n\t\ttry {\n\t\t\treturn this.candidate.retrieve(query, items);\n\t\t} catch {\n\t\t\treturn this.fallback.retrieve(query, items);\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import type { StateSnapshotContract } from "@asm-agent/contracts";
2
+ import type { RetrievalBackend } from "./types.js";
3
+ export declare function createStateSnapshot<State extends object>(input: {
4
+ snapshotId: string;
5
+ sessionId: string;
6
+ sequence: number;
7
+ backend: RetrievalBackend<State>;
8
+ state: State;
9
+ now?: Date;
10
+ }): StateSnapshotContract;
11
+ export declare function restoreStateSnapshot<State extends object>(backend: RetrievalBackend<State>, snapshot: StateSnapshotContract, options?: {
12
+ minimumSequence?: number;
13
+ }): State;
14
+ export declare function canonicalJson(value: unknown): string;
15
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,wBAAgB,mBAAmB,CAAC,KAAK,SAAS,MAAM,EAAE,KAAK,EAAE;IAChE,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACjC,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,CAAC,EAAE,IAAI,CAAC;CACX,GAAG,qBAAqB,CAYxB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,SAAS,MAAM,EACxD,OAAO,EAAE,gBAAgB,CAAC,KAAK,CAAC,EAChC,QAAQ,EAAE,qBAAqB,EAC/B,OAAO,GAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAA;CAAO,GACxC,KAAK,CAWP;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CASpD","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { StateSnapshotContract } from \"@asm-agent/contracts\";\nimport type { RetrievalBackend } from \"./types.js\";\n\nexport function createStateSnapshot<State extends object>(input: {\n\tsnapshotId: string;\n\tsessionId: string;\n\tsequence: number;\n\tbackend: RetrievalBackend<State>;\n\tstate: State;\n\tnow?: Date;\n}): StateSnapshotContract {\n\tconst state = input.backend.serializeState(input.state);\n\tconst digest = createHash(\"sha256\").update(canonicalJson(state)).digest(\"hex\");\n\treturn {\n\t\theader: { namespace: \"ai.aletheion.asm\", major: 1, minor: 1 },\n\t\tsnapshotId: input.snapshotId,\n\t\tsessionId: input.sessionId,\n\t\tsequence: input.sequence,\n\t\tstate: { backend: input.backend.name, data: state },\n\t\tdigest,\n\t\tcreatedAt: (input.now ?? new Date()).toISOString(),\n\t};\n}\n\nexport function restoreStateSnapshot<State extends object>(\n\tbackend: RetrievalBackend<State>,\n\tsnapshot: StateSnapshotContract,\n\toptions: { minimumSequence?: number } = {},\n): State {\n\tif (options.minimumSequence !== undefined && snapshot.sequence < options.minimumSequence)\n\t\tthrow new Error(\"State snapshot is stale\");\n\tconst storedBackend = snapshot.state.backend;\n\tconst data = snapshot.state.data;\n\tif (storedBackend !== backend.name) throw new Error(\"State snapshot backend mismatch\");\n\tif (!data || typeof data !== \"object\" || Array.isArray(data))\n\t\tthrow new Error(\"State snapshot data must be an object\");\n\tconst digest = createHash(\"sha256\").update(canonicalJson(data)).digest(\"hex\");\n\tif (digest !== snapshot.digest) throw new Error(\"State snapshot digest mismatch\");\n\treturn backend.deserializeState(data);\n}\n\nexport function canonicalJson(value: unknown): string {\n\tif (Array.isArray(value)) return `[${value.map(canonicalJson).join(\",\")}]`;\n\tif (value && typeof value === \"object\") {\n\t\treturn `{${Object.entries(value as Record<string, unknown>)\n\t\t\t.sort(([left], [right]) => left.localeCompare(right))\n\t\t\t.map(([key, item]) => `${JSON.stringify(key)}:${canonicalJson(item)}`)\n\t\t\t.join(\",\")}}`;\n\t}\n\treturn JSON.stringify(value);\n}\n"]}
package/dist/state.js ADDED
@@ -0,0 +1,40 @@
1
+ import { createHash } from "node:crypto";
2
+ export function createStateSnapshot(input) {
3
+ const state = input.backend.serializeState(input.state);
4
+ const digest = createHash("sha256").update(canonicalJson(state)).digest("hex");
5
+ return {
6
+ header: { namespace: "ai.aletheion.asm", major: 1, minor: 1 },
7
+ snapshotId: input.snapshotId,
8
+ sessionId: input.sessionId,
9
+ sequence: input.sequence,
10
+ state: { backend: input.backend.name, data: state },
11
+ digest,
12
+ createdAt: (input.now ?? new Date()).toISOString(),
13
+ };
14
+ }
15
+ export function restoreStateSnapshot(backend, snapshot, options = {}) {
16
+ if (options.minimumSequence !== undefined && snapshot.sequence < options.minimumSequence)
17
+ throw new Error("State snapshot is stale");
18
+ const storedBackend = snapshot.state.backend;
19
+ const data = snapshot.state.data;
20
+ if (storedBackend !== backend.name)
21
+ throw new Error("State snapshot backend mismatch");
22
+ if (!data || typeof data !== "object" || Array.isArray(data))
23
+ throw new Error("State snapshot data must be an object");
24
+ const digest = createHash("sha256").update(canonicalJson(data)).digest("hex");
25
+ if (digest !== snapshot.digest)
26
+ throw new Error("State snapshot digest mismatch");
27
+ return backend.deserializeState(data);
28
+ }
29
+ export function canonicalJson(value) {
30
+ if (Array.isArray(value))
31
+ return `[${value.map(canonicalJson).join(",")}]`;
32
+ if (value && typeof value === "object") {
33
+ return `{${Object.entries(value)
34
+ .sort(([left], [right]) => left.localeCompare(right))
35
+ .map(([key, item]) => `${JSON.stringify(key)}:${canonicalJson(item)}`)
36
+ .join(",")}}`;
37
+ }
38
+ return JSON.stringify(value);
39
+ }
40
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC,MAAM,UAAU,mBAAmB,CAAuB,KAOzD,EAAyB;IACzB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/E,OAAO;QACN,MAAM,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;QAC7D,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE;QACnD,MAAM;QACN,SAAS,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE;KAClD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,oBAAoB,CACnC,OAAgC,EAChC,QAA+B,EAC/B,OAAO,GAAiC,EAAE,EAClC;IACR,IAAI,OAAO,CAAC,eAAe,KAAK,SAAS,IAAI,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC,eAAe;QACvF,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC5C,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;IACjC,IAAI,aAAa,KAAK,OAAO,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACvF,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9E,IAAI,MAAM,KAAK,QAAQ,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAClF,OAAO,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAAA,CACtC;AAED,MAAM,UAAU,aAAa,CAAC,KAAc,EAAU;IACrD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC3E,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;aACzD,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;aACpD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;aACrE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAChB,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAAA,CAC7B","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { StateSnapshotContract } from \"@asm-agent/contracts\";\nimport type { RetrievalBackend } from \"./types.js\";\n\nexport function createStateSnapshot<State extends object>(input: {\n\tsnapshotId: string;\n\tsessionId: string;\n\tsequence: number;\n\tbackend: RetrievalBackend<State>;\n\tstate: State;\n\tnow?: Date;\n}): StateSnapshotContract {\n\tconst state = input.backend.serializeState(input.state);\n\tconst digest = createHash(\"sha256\").update(canonicalJson(state)).digest(\"hex\");\n\treturn {\n\t\theader: { namespace: \"ai.aletheion.asm\", major: 1, minor: 1 },\n\t\tsnapshotId: input.snapshotId,\n\t\tsessionId: input.sessionId,\n\t\tsequence: input.sequence,\n\t\tstate: { backend: input.backend.name, data: state },\n\t\tdigest,\n\t\tcreatedAt: (input.now ?? new Date()).toISOString(),\n\t};\n}\n\nexport function restoreStateSnapshot<State extends object>(\n\tbackend: RetrievalBackend<State>,\n\tsnapshot: StateSnapshotContract,\n\toptions: { minimumSequence?: number } = {},\n): State {\n\tif (options.minimumSequence !== undefined && snapshot.sequence < options.minimumSequence)\n\t\tthrow new Error(\"State snapshot is stale\");\n\tconst storedBackend = snapshot.state.backend;\n\tconst data = snapshot.state.data;\n\tif (storedBackend !== backend.name) throw new Error(\"State snapshot backend mismatch\");\n\tif (!data || typeof data !== \"object\" || Array.isArray(data))\n\t\tthrow new Error(\"State snapshot data must be an object\");\n\tconst digest = createHash(\"sha256\").update(canonicalJson(data)).digest(\"hex\");\n\tif (digest !== snapshot.digest) throw new Error(\"State snapshot digest mismatch\");\n\treturn backend.deserializeState(data);\n}\n\nexport function canonicalJson(value: unknown): string {\n\tif (Array.isArray(value)) return `[${value.map(canonicalJson).join(\",\")}]`;\n\tif (value && typeof value === \"object\") {\n\t\treturn `{${Object.entries(value as Record<string, unknown>)\n\t\t\t.sort(([left], [right]) => left.localeCompare(right))\n\t\t\t.map(([key, item]) => `${JSON.stringify(key)}:${canonicalJson(item)}`)\n\t\t\t.join(\",\")}}`;\n\t}\n\treturn JSON.stringify(value);\n}\n"]}
@@ -0,0 +1,32 @@
1
+ export type LearnedBackendName = "causal-head-v1" | "dual-asm-v1" | "asm-cm-v1";
2
+ export type BaselineBackendName = "lexical-v1" | "vector-l2-v1";
3
+ export type RetrievalBackendName = LearnedBackendName | BaselineBackendName;
4
+ export interface RetrievalItem {
5
+ id: string;
6
+ ownerId: string;
7
+ projectId: string;
8
+ embedding: readonly number[];
9
+ revoked?: boolean;
10
+ }
11
+ export interface RetrievalQuery {
12
+ ownerId: string;
13
+ projectId: string;
14
+ sessionId: string;
15
+ embedding: readonly number[];
16
+ limit: number;
17
+ }
18
+ export interface RankedItem {
19
+ id: string;
20
+ score: number;
21
+ reasonCodes: string[];
22
+ }
23
+ export interface RetrievalBackend<State extends object = object> {
24
+ readonly name: LearnedBackendName;
25
+ readonly dimensions: number;
26
+ retrieve(query: RetrievalQuery, items: readonly RetrievalItem[], state: State): RankedItem[];
27
+ update(state: State, selected: readonly RetrievalItem[], feedback?: "positive" | "negative"): State;
28
+ emptyState(): State;
29
+ serializeState(state: State): Record<string, unknown>;
30
+ deserializeState(value: unknown): State;
31
+ }
32
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG,gBAAgB,GAAG,aAAa,GAAG,WAAW,CAAC;AAChF,MAAM,MAAM,mBAAmB,GAAG,YAAY,GAAG,cAAc,CAAC;AAChE,MAAM,MAAM,oBAAoB,GAAG,kBAAkB,GAAG,mBAAmB,CAAC;AAE5E,MAAM,WAAW,aAAa;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IAC9D,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,aAAa,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,UAAU,EAAE,CAAC;IAC7F,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,aAAa,EAAE,EAAE,QAAQ,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,KAAK,CAAC;IACpG,UAAU,IAAI,KAAK,CAAC;IACpB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAAC;CACxC","sourcesContent":["export type LearnedBackendName = \"causal-head-v1\" | \"dual-asm-v1\" | \"asm-cm-v1\";\nexport type BaselineBackendName = \"lexical-v1\" | \"vector-l2-v1\";\nexport type RetrievalBackendName = LearnedBackendName | BaselineBackendName;\n\nexport interface RetrievalItem {\n\tid: string;\n\townerId: string;\n\tprojectId: string;\n\tembedding: readonly number[];\n\trevoked?: boolean;\n}\n\nexport interface RetrievalQuery {\n\townerId: string;\n\tprojectId: string;\n\tsessionId: string;\n\tembedding: readonly number[];\n\tlimit: number;\n}\n\nexport interface RankedItem {\n\tid: string;\n\tscore: number;\n\treasonCodes: string[];\n}\n\nexport interface RetrievalBackend<State extends object = object> {\n\treadonly name: LearnedBackendName;\n\treadonly dimensions: number;\n\tretrieve(query: RetrievalQuery, items: readonly RetrievalItem[], state: State): RankedItem[];\n\tupdate(state: State, selected: readonly RetrievalItem[], feedback?: \"positive\" | \"negative\"): State;\n\temptyState(): State;\n\tserializeState(state: State): Record<string, unknown>;\n\tdeserializeState(value: unknown): State;\n}\n"]}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type LearnedBackendName = \"causal-head-v1\" | \"dual-asm-v1\" | \"asm-cm-v1\";\nexport type BaselineBackendName = \"lexical-v1\" | \"vector-l2-v1\";\nexport type RetrievalBackendName = LearnedBackendName | BaselineBackendName;\n\nexport interface RetrievalItem {\n\tid: string;\n\townerId: string;\n\tprojectId: string;\n\tembedding: readonly number[];\n\trevoked?: boolean;\n}\n\nexport interface RetrievalQuery {\n\townerId: string;\n\tprojectId: string;\n\tsessionId: string;\n\tembedding: readonly number[];\n\tlimit: number;\n}\n\nexport interface RankedItem {\n\tid: string;\n\tscore: number;\n\treasonCodes: string[];\n}\n\nexport interface RetrievalBackend<State extends object = object> {\n\treadonly name: LearnedBackendName;\n\treadonly dimensions: number;\n\tretrieve(query: RetrievalQuery, items: readonly RetrievalItem[], state: State): RankedItem[];\n\tupdate(state: State, selected: readonly RetrievalItem[], feedback?: \"positive\" | \"negative\"): State;\n\temptyState(): State;\n\tserializeState(state: State): Record<string, unknown>;\n\tdeserializeState(value: unknown): State;\n}\n"]}