@seanhogg/builderforce-memory 2026.6.31 → 2026.6.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +3 -1
  2. package/dist/cognition/EvermindCognition.d.ts +46 -7
  3. package/dist/cognition/EvermindCognition.d.ts.map +1 -1
  4. package/dist/cognition/EvermindCognition.js +95 -25
  5. package/dist/cognition/EvermindCognition.js.map +1 -1
  6. package/dist/cognition/canonicalize.d.ts +37 -0
  7. package/dist/cognition/canonicalize.d.ts.map +1 -0
  8. package/dist/cognition/canonicalize.js +58 -0
  9. package/dist/cognition/canonicalize.js.map +1 -0
  10. package/dist/cognition/index.d.ts +4 -0
  11. package/dist/cognition/index.d.ts.map +1 -1
  12. package/dist/cognition/index.js +2 -0
  13. package/dist/cognition/index.js.map +1 -1
  14. package/dist/cognition/sanitize.d.ts +58 -0
  15. package/dist/cognition/sanitize.d.ts.map +1 -0
  16. package/dist/cognition/sanitize.js +103 -0
  17. package/dist/cognition/sanitize.js.map +1 -0
  18. package/dist/distillation/DistillationEngine.d.ts +32 -1
  19. package/dist/distillation/DistillationEngine.d.ts.map +1 -1
  20. package/dist/distillation/DistillationEngine.js +53 -5
  21. package/dist/distillation/DistillationEngine.js.map +1 -1
  22. package/dist/distillation/index.d.ts +1 -1
  23. package/dist/distillation/index.d.ts.map +1 -1
  24. package/dist/index.d.ts +5 -3
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +3 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/memory/MemoryStore.d.ts +35 -0
  29. package/dist/memory/MemoryStore.d.ts.map +1 -1
  30. package/dist/memory/MemoryStore.js +86 -13
  31. package/dist/memory/MemoryStore.js.map +1 -1
  32. package/dist/publish/huggingface.d.ts +77 -0
  33. package/dist/publish/huggingface.d.ts.map +1 -0
  34. package/dist/publish/huggingface.js +88 -0
  35. package/dist/publish/huggingface.js.map +1 -0
  36. package/dist/publish/index.d.ts +7 -0
  37. package/dist/publish/index.d.ts.map +1 -0
  38. package/dist/publish/index.js +6 -0
  39. package/dist/publish/index.js.map +1 -0
  40. package/dist/retrieval/HybridRetriever.d.ts +5 -0
  41. package/dist/retrieval/HybridRetriever.d.ts.map +1 -1
  42. package/dist/retrieval/HybridRetriever.js +9 -7
  43. package/dist/retrieval/HybridRetriever.js.map +1 -1
  44. package/dist/retrieval/hnsw.d.ts +71 -0
  45. package/dist/retrieval/hnsw.d.ts.map +1 -0
  46. package/dist/retrieval/hnsw.js +201 -0
  47. package/dist/retrieval/hnsw.js.map +1 -0
  48. package/dist/retrieval/index.d.ts +2 -0
  49. package/dist/retrieval/index.d.ts.map +1 -1
  50. package/dist/retrieval/index.js +1 -0
  51. package/dist/retrieval/index.js.map +1 -1
  52. package/dist/workflow/steps.d.ts.map +1 -1
  53. package/dist/workflow/steps.js +73 -1
  54. package/dist/workflow/steps.js.map +1 -1
  55. package/dist/workflow/templates.d.ts.map +1 -1
  56. package/dist/workflow/templates.js +3 -1
  57. package/dist/workflow/templates.js.map +1 -1
  58. package/package.json +3 -3
  59. package/src/cognition/EvermindCognition.ts +123 -27
  60. package/src/cognition/canonicalize.ts +61 -0
  61. package/src/cognition/index.ts +12 -0
  62. package/src/cognition/sanitize.ts +126 -0
  63. package/src/distillation/DistillationEngine.ts +72 -5
  64. package/src/distillation/index.ts +1 -1
  65. package/src/index.ts +18 -1
  66. package/src/memory/MemoryStore.ts +107 -12
  67. package/src/publish/huggingface.ts +139 -0
  68. package/src/publish/index.ts +7 -0
  69. package/src/retrieval/HybridRetriever.ts +14 -7
  70. package/src/retrieval/hnsw.ts +242 -0
  71. package/src/retrieval/index.ts +3 -0
  72. package/src/workflow/steps.ts +93 -0
  73. package/src/workflow/templates.ts +3 -1
@@ -0,0 +1,77 @@
1
+ /**
2
+ * publish/huggingface.ts — push an exported Evermind model to the Hugging Face Hub.
3
+ *
4
+ * The runtime stays zero-dependency: the actual Hub I/O is delegated to an
5
+ * injectable {@link HubClient}. In production it is dynamically imported from the
6
+ * optional `@huggingface/hub` package (which handles LFS for the binary weight
7
+ * files correctly); tests inject a fake. There is also a credential-free path —
8
+ * {@link writeExportToDir} — that writes the repo to a local folder you push with
9
+ * `git` / `huggingface-cli upload`.
10
+ *
11
+ * The export itself (turning a trained model into the file set) lives in the
12
+ * engine's `export/` module; this module is only the *transport*.
13
+ */
14
+ import type { ExportResult } from "@seanhogg/builderforce-memory-engine";
15
+ /** Where/how to publish. `repoId` is "owner/name" (e.g. "builderforce/Evermind"). */
16
+ export interface HuggingFaceTarget {
17
+ repoId: string;
18
+ /** A write-scoped HF access token (hf_…). */
19
+ token: string;
20
+ /** Create the repo private. Default false (public). */
21
+ private?: boolean;
22
+ /** Commit title. Default "Publish <repoId>". */
23
+ commitTitle?: string;
24
+ /** Target branch. Default "main". */
25
+ branch?: string;
26
+ }
27
+ export interface PublishOutcome {
28
+ repoId: string;
29
+ url: string;
30
+ files: string[];
31
+ }
32
+ /** The slice of `@huggingface/hub` we use — injectable for testing. */
33
+ export interface HubClient {
34
+ createRepo(args: {
35
+ repo: {
36
+ type: "model";
37
+ name: string;
38
+ };
39
+ accessToken: string;
40
+ private?: boolean;
41
+ }): Promise<unknown>;
42
+ uploadFiles(args: {
43
+ repo: {
44
+ type: "model";
45
+ name: string;
46
+ };
47
+ accessToken: string;
48
+ branch?: string;
49
+ commitTitle?: string;
50
+ files: {
51
+ path: string;
52
+ content: Blob;
53
+ }[];
54
+ }): Promise<unknown>;
55
+ }
56
+ /**
57
+ * Publish an export to the Hub: create the repo (idempotent) then upload every
58
+ * file. Pass `deps.hub` to inject a client; otherwise `@huggingface/hub` is
59
+ * loaded dynamically. Requires a write-scoped token (the credential-gated step).
60
+ */
61
+ export declare function publishToHuggingFace(result: ExportResult, target: HuggingFaceTarget, deps?: {
62
+ hub?: HubClient;
63
+ }): Promise<PublishOutcome>;
64
+ /** A minimal fs surface (Node `fs/promises`) — injectable for testing. */
65
+ export interface FsLike {
66
+ mkdir(path: string, opts: {
67
+ recursive: boolean;
68
+ }): Promise<unknown>;
69
+ writeFile(path: string, data: Uint8Array | string): Promise<void>;
70
+ }
71
+ /**
72
+ * Credential-free publish: write the export to a local directory (a ready-to-push
73
+ * HF repo folder). Returns the relative paths written. Inject `fs` in tests;
74
+ * otherwise Node's `fs/promises` is used.
75
+ */
76
+ export declare function writeExportToDir(result: ExportResult, dir: string, fs?: FsLike): Promise<string[]>;
77
+ //# sourceMappingURL=huggingface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"huggingface.d.ts","sourceRoot":"","sources":["../../src/publish/huggingface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,sCAAsC,CAAC;AAErF,qFAAqF;AACrF,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,uEAAuE;AACvE,MAAM,WAAW,SAAS;IACxB,UAAU,CAAC,IAAI,EAAE;QACf,IAAI,EAAE;YAAE,IAAI,EAAE,OAAO,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;QACtC,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrB,WAAW,CAAC,IAAI,EAAE;QAChB,IAAI,EAAE;YAAE,IAAI,EAAE,OAAO,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;QACtC,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,IAAI,CAAA;SAAE,EAAE,CAAC;KAC1C,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACtB;AA0BD;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,iBAAiB,EACzB,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,SAAS,CAAA;CAAO,GAC7B,OAAO,CAAC,cAAc,CAAC,CA2BzB;AAED,0EAA0E;AAC1E,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnE;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAcxG"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * publish/huggingface.ts — push an exported Evermind model to the Hugging Face Hub.
3
+ *
4
+ * The runtime stays zero-dependency: the actual Hub I/O is delegated to an
5
+ * injectable {@link HubClient}. In production it is dynamically imported from the
6
+ * optional `@huggingface/hub` package (which handles LFS for the binary weight
7
+ * files correctly); tests inject a fake. There is also a credential-free path —
8
+ * {@link writeExportToDir} — that writes the repo to a local folder you push with
9
+ * `git` / `huggingface-cli upload`.
10
+ *
11
+ * The export itself (turning a trained model into the file set) lives in the
12
+ * engine's `export/` module; this module is only the *transport*.
13
+ */
14
+ /** Turn an emitted file into a Blob (binary or text) for upload. */
15
+ function toBlob(file) {
16
+ const part = (typeof file.data === "string" ? file.data : file.data);
17
+ return new Blob([part], { type: file.contentType });
18
+ }
19
+ async function loadHub() {
20
+ try {
21
+ // Optional peer dep — only required when actually uploading. A variable
22
+ // specifier keeps it out of the static module graph (no build-time dep).
23
+ const spec = "@huggingface/hub";
24
+ const mod = (await import(spec));
25
+ if (typeof mod.createRepo !== "function" || typeof mod.uploadFiles !== "function") {
26
+ throw new Error("module shape unexpected");
27
+ }
28
+ return mod;
29
+ }
30
+ catch {
31
+ throw new Error("publishToHuggingFace needs the optional '@huggingface/hub' package " +
32
+ "(npm i @huggingface/hub) — or use writeExportToDir() + `huggingface-cli upload`.");
33
+ }
34
+ }
35
+ /**
36
+ * Publish an export to the Hub: create the repo (idempotent) then upload every
37
+ * file. Pass `deps.hub` to inject a client; otherwise `@huggingface/hub` is
38
+ * loaded dynamically. Requires a write-scoped token (the credential-gated step).
39
+ */
40
+ export async function publishToHuggingFace(result, target, deps = {}) {
41
+ if (!target.repoId.includes("/")) {
42
+ throw new Error(`publishToHuggingFace: repoId must be "owner/name" (got "${target.repoId}")`);
43
+ }
44
+ if (!target.token)
45
+ throw new Error("publishToHuggingFace: a write-scoped HF token is required");
46
+ const hub = deps.hub ?? (await loadHub());
47
+ const repo = { type: "model", name: target.repoId };
48
+ try {
49
+ await hub.createRepo({ repo, accessToken: target.token, private: target.private ?? false });
50
+ }
51
+ catch (e) {
52
+ // Re-creating an existing repo is fine; only rethrow unexpected failures.
53
+ const msg = e instanceof Error ? e.message : String(e);
54
+ if (!/exist|409|conflict/i.test(msg))
55
+ throw e;
56
+ }
57
+ const files = result.files.map((f) => ({ path: f.path, content: toBlob(f) }));
58
+ await hub.uploadFiles({
59
+ repo,
60
+ accessToken: target.token,
61
+ branch: target.branch ?? "main",
62
+ commitTitle: target.commitTitle ?? `Publish ${target.repoId}`,
63
+ files,
64
+ });
65
+ return { repoId: target.repoId, url: `https://huggingface.co/${target.repoId}`, files: files.map((f) => f.path) };
66
+ }
67
+ /**
68
+ * Credential-free publish: write the export to a local directory (a ready-to-push
69
+ * HF repo folder). Returns the relative paths written. Inject `fs` in tests;
70
+ * otherwise Node's `fs/promises` is used.
71
+ */
72
+ export async function writeExportToDir(result, dir, fs) {
73
+ const spec = "node:fs/promises";
74
+ const realFs = fs ?? (await import(spec));
75
+ const sep = dir.endsWith("/") || dir.endsWith("\\") ? "" : "/";
76
+ await realFs.mkdir(dir, { recursive: true });
77
+ const written = [];
78
+ for (const f of result.files) {
79
+ const full = `${dir}${sep}${f.path}`;
80
+ const slash = Math.max(full.lastIndexOf("/"), full.lastIndexOf("\\"));
81
+ if (slash > dir.length)
82
+ await realFs.mkdir(full.slice(0, slash), { recursive: true });
83
+ await realFs.writeFile(full, f.data);
84
+ written.push(f.path);
85
+ }
86
+ return written;
87
+ }
88
+ //# sourceMappingURL=huggingface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"huggingface.js","sourceRoot":"","sources":["../../src/publish/huggingface.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * publish/ — transport for published Evermind exports (the engine builds the
3
+ * files; this ships them). Hugging Face Hub upload + local-folder writer.
4
+ */
5
+ export { publishToHuggingFace, writeExportToDir } from "./huggingface.js";
6
+ export type { HuggingFaceTarget, PublishOutcome, HubClient, FsLike } from "./huggingface.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/publish/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * publish/ — transport for published Evermind exports (the engine builds the
3
+ * files; this ships them). Hugging Face Hub upload + local-folder writer.
4
+ */
5
+ export { publishToHuggingFace, writeExportToDir } from "./huggingface.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/publish/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -40,6 +40,11 @@ export interface HybridRetrieveOptions {
40
40
  mmrLambda?: number;
41
41
  /** BM25 tuning. */
42
42
  bm25?: Bm25Options;
43
+ /**
44
+ * Candidate count at/above which the dense pass uses an HNSW ANN index
45
+ * instead of an exact cosine scan (O(log N) vs O(N)). Default 256.
46
+ */
47
+ annThreshold?: number;
43
48
  }
44
49
  export interface HybridHit {
45
50
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"HybridRetriever.d.ts","sourceRoot":"","sources":["../../src/retrieval/HybridRetriever.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAGzD,MAAM,WAAW,kBAAkB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,MAAM,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IAClC,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB;IACnB,IAAI,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,kBAAkB,EAAE,EAChC,IAAI,GAAE,qBAA0B,GACjC,SAAS,EAAE,CAuDb"}
1
+ {"version":3,"file":"HybridRetriever.d.ts","sourceRoot":"","sources":["../../src/retrieval/HybridRetriever.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAIzD,MAAM,WAAW,kBAAkB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,MAAM,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IAClC,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB;IACnB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,kBAAkB,EAAE,EAChC,IAAI,GAAE,qBAA0B,GACjC,SAAS,EAAE,CAyDb"}
@@ -13,9 +13,9 @@
13
13
  * query (text + optional vector). It degrades gracefully: no query vector / no
14
14
  * candidate vectors → BM25-only; no overlap → dense-only.
15
15
  */
16
- import { cosineSimilarity } from '../similarity/index.js';
17
16
  import { bm25Search } from './bm25.js';
18
17
  import { reciprocalRankFusion, maximalMarginalRelevance } from './fusion.js';
18
+ import { denseSearch } from './hnsw.js';
19
19
  /**
20
20
  * Runs the full hybrid pipeline over `candidates` and returns the top-K hits.
21
21
  * Pure given its inputs (embeddings are supplied by the caller) so it is directly
@@ -26,14 +26,16 @@ export function hybridRetrieve(query, candidates, opts = {}) {
26
26
  if (candidates.length === 0)
27
27
  return [];
28
28
  const byId = new Map(candidates.map(c => [c.id, c]));
29
- // ── Dense ranking (cosine) ────────────────────────────────────────────────
29
+ // ── Dense ranking (cosine, ANN-accelerated above the threshold) ────────────
30
30
  let denseIds = [];
31
31
  if (query.vector) {
32
- denseIds = candidates
33
- .filter(c => c.vector && c.vector.length > 0)
34
- .map(c => ({ id: c.id, score: cosineSimilarity(query.vector, c.vector) }))
35
- .sort((a, b) => b.score - a.score)
36
- .map(h => h.id);
32
+ const vectored = candidates
33
+ .filter((c) => !!c.vector && c.vector.length > 0)
34
+ .map(c => ({ id: c.id, vector: c.vector }));
35
+ // Rank the full vectored set (k = all) so fusion sees the complete dense
36
+ // ordering; denseSearch uses an exact scan under the threshold and HNSW
37
+ // above it, so behaviour is identical for small stores.
38
+ denseIds = denseSearch(query.vector, vectored, vectored.length, opts.annThreshold ?? 256).map(h => h.id);
37
39
  }
38
40
  // ── Sparse ranking (BM25) ─────────────────────────────────────────────────
39
41
  const sparseIds = bm25Search(query.text, candidates, opts.bm25).map(h => h.id);
@@ -1 +1 @@
1
- {"version":3,"file":"HybridRetriever.js","sourceRoot":"","sources":["../../src/retrieval/HybridRetriever.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAoB,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAqB,MAAM,aAAa,CAAC;AAuChG;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC1B,KAAkB,EAClB,UAAgC,EAChC,OAA8B,EAAE;IAEhC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;IAC5B,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEvC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAErD,6EAA6E;IAC7E,IAAI,QAAQ,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACf,QAAQ,GAAG,UAAU;aAChB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;aAC5C,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,gBAAgB,CAAC,KAAK,CAAC,MAAO,EAAE,CAAC,CAAC,MAAO,CAAC,EAAE,CAAC,CAAC;aAC3E,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;aACjC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACxB,CAAC;IAED,6EAA6E;IAC7E,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAE/E,6EAA6E;IAC7E,MAAM,KAAK,GAAG,oBAAoB,CAC9B;QACI,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,IAAI,CAAC,EAAE;QAChD,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY,IAAI,CAAC,EAAE;KACrD,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,EAC/B,IAAI,CAAC,IAAI,IAAI,EAAE,CAClB,CAAC;IACF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAElC,8EAA8E;IAC9E,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;IACnC,IAAI,UAAoB,CAAC;IACzB,IAAI,MAAM,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACzB,iEAAiE;QACjE,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QACxD,MAAM,QAAQ,GAAmB,MAAM;aAClC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;aACxB,MAAM,CAAC,CAAC,CAAC,EAA2B,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;aAChF,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAO,EAAE,CAAC,CAAC,CAAC;QACjD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,wBAAwB,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,CAAC;YAC/F,4EAA4E;YAC5E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC/B,UAAU,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACpF,CAAC;aAAM,CAAC;YACJ,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACtC,CAAC;IACL,CAAC;SAAM,CAAC;QACJ,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5D,OAAO,UAAU;SACZ,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;SACd,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAE,EAAE,CAAC,CAAC,CAAC;AACnF,CAAC"}
1
+ {"version":3,"file":"HybridRetriever.js","sourceRoot":"","sources":["../../src/retrieval/HybridRetriever.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * hnsw.ts — a pure-TypeScript HNSW approximate-nearest-neighbour index.
3
+ *
4
+ * Recall over the fact store was an O(N) cosine scan per query, so the
5
+ * "lifetime of always-current knowledge" thesis hit a wall around ~10⁴ facts.
6
+ * HNSW (Hierarchical Navigable Small World) gives O(log N) expected query time
7
+ * with high recall, and this implementation is dependency-free so it keeps the
8
+ * engine/runtime zero-dep promise. For small sets an exact scan is both simpler
9
+ * and faster, so callers use {@link denseSearch} which switches to HNSW only
10
+ * above a threshold.
11
+ *
12
+ * Distance is cosine similarity (higher = closer); the graph stores `1 - cos`
13
+ * as the metric so "nearer" is "smaller". Construction is deterministic given a
14
+ * seed, so builds (and tests) reproduce exactly.
15
+ */
16
+ export interface HnswOptions {
17
+ /** Max neighbours per node on layers > 0. Default 16. */
18
+ M?: number;
19
+ /** Candidate-list size during construction. Default 200. */
20
+ efConstruction?: number;
21
+ /** Default candidate-list size during search. Default 50. */
22
+ efSearch?: number;
23
+ /** Deterministic seed for layer assignment. Default 0x5eed. */
24
+ seed?: number;
25
+ }
26
+ export interface SearchHit {
27
+ id: string;
28
+ /** Cosine similarity to the query (higher = closer). */
29
+ score: number;
30
+ }
31
+ export declare class HnswIndex {
32
+ private readonly _M;
33
+ private readonly _Mmax0;
34
+ private readonly _efC;
35
+ private readonly _efS;
36
+ private readonly _mL;
37
+ private readonly _rng;
38
+ private readonly _nodes;
39
+ private readonly _idToIdx;
40
+ private _entry;
41
+ private _maxLayer;
42
+ constructor(opts?: HnswOptions);
43
+ get size(): number;
44
+ has(id: string): boolean;
45
+ private _dist;
46
+ private _randomLayer;
47
+ /** Insert a vector. Ids are unique — re-adding a known id is ignored. */
48
+ add(id: string, vector: Float32Array): void;
49
+ /** Top-k nearest by cosine similarity (descending). */
50
+ search(query: Float32Array, k: number, ef?: number): SearchHit[];
51
+ clear(): void;
52
+ /** Greedy hill-climb to the single closest node to `q` on layer `lc`. */
53
+ private _greedyClosest;
54
+ /**
55
+ * ef-search on a single layer: returns candidates sorted nearest-first.
56
+ * A bounded best-first expansion (the standard HNSW layer search).
57
+ */
58
+ private _searchLayer;
59
+ /** Keep only the `Mmax` closest neighbours of `node` on layer `lc`. */
60
+ private _prune;
61
+ }
62
+ /**
63
+ * Dense KNN with an exact-scan fast path: below `threshold` candidates a linear
64
+ * cosine scan is simpler and faster; at/above it, build an HNSW index and query
65
+ * it. Returned hits are cosine-similarity descending. Pure given its inputs.
66
+ */
67
+ export declare function denseSearch(query: Float32Array, items: Array<{
68
+ id: string;
69
+ vector: Float32Array;
70
+ }>, k: number, threshold?: number, hnsw?: HnswOptions): SearchHit[];
71
+ //# sourceMappingURL=hnsw.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hnsw.d.ts","sourceRoot":"","sources":["../../src/retrieval/hnsw.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,MAAM,WAAW,WAAW;IACxB,yDAAyD;IACzD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;CACjB;AAkBD,qBAAa,SAAS;IAClB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IAEpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,SAAS,CAAM;gBAEX,IAAI,GAAE,WAAgB;IASlC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,YAAY;IAIpB,yEAAyE;IACzE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI;IA0C3C,uDAAuD;IACvD,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,SAAY,GAAG,SAAS,EAAE;IAUnE,KAAK,IAAI,IAAI;IASb,yEAAyE;IACzE,OAAO,CAAC,cAAc;IAkBtB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAoCpB,uEAAuE;IACvE,OAAO,CAAC,MAAM;CAKjB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACvB,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,CAAC,EAClD,CAAC,EAAE,MAAM,EACT,SAAS,SAAM,EACf,IAAI,CAAC,EAAE,WAAW,GACnB,SAAS,EAAE,CAWb"}
@@ -0,0 +1,201 @@
1
+ /**
2
+ * hnsw.ts — a pure-TypeScript HNSW approximate-nearest-neighbour index.
3
+ *
4
+ * Recall over the fact store was an O(N) cosine scan per query, so the
5
+ * "lifetime of always-current knowledge" thesis hit a wall around ~10⁴ facts.
6
+ * HNSW (Hierarchical Navigable Small World) gives O(log N) expected query time
7
+ * with high recall, and this implementation is dependency-free so it keeps the
8
+ * engine/runtime zero-dep promise. For small sets an exact scan is both simpler
9
+ * and faster, so callers use {@link denseSearch} which switches to HNSW only
10
+ * above a threshold.
11
+ *
12
+ * Distance is cosine similarity (higher = closer); the graph stores `1 - cos`
13
+ * as the metric so "nearer" is "smaller". Construction is deterministic given a
14
+ * seed, so builds (and tests) reproduce exactly.
15
+ */
16
+ import { cosineSimilarity } from '../similarity/index.js';
17
+ /** A small deterministic LCG → float in [0,1). Mirrors the engine's SeededRng. */
18
+ function makeRng(seed) {
19
+ let s = (seed >>> 0) || 1;
20
+ return () => {
21
+ s = (Math.imul(1664525, s) + 1013904223) >>> 0;
22
+ return s / 0x1_0000_0000;
23
+ };
24
+ }
25
+ export class HnswIndex {
26
+ _M;
27
+ _Mmax0;
28
+ _efC;
29
+ _efS;
30
+ _mL;
31
+ _rng;
32
+ _nodes = [];
33
+ _idToIdx = new Map();
34
+ _entry = -1; // index of the entry-point node
35
+ _maxLayer = -1;
36
+ constructor(opts = {}) {
37
+ this._M = Math.max(2, opts.M ?? 16);
38
+ this._Mmax0 = this._M * 2;
39
+ this._efC = Math.max(this._M, opts.efConstruction ?? 200);
40
+ this._efS = Math.max(1, opts.efSearch ?? 50);
41
+ this._mL = 1 / Math.log(this._M);
42
+ this._rng = makeRng(opts.seed ?? 0x5eed);
43
+ }
44
+ get size() {
45
+ return this._nodes.length;
46
+ }
47
+ has(id) {
48
+ return this._idToIdx.has(id);
49
+ }
50
+ _dist(a, b) {
51
+ return 1 - cosineSimilarity(a, b);
52
+ }
53
+ _randomLayer() {
54
+ return Math.floor(-Math.log(Math.max(this._rng(), 1e-12)) * this._mL);
55
+ }
56
+ /** Insert a vector. Ids are unique — re-adding a known id is ignored. */
57
+ add(id, vector) {
58
+ if (this._idToIdx.has(id))
59
+ return;
60
+ const layer = this._randomLayer();
61
+ const node = { id, vector, neighbours: Array.from({ length: layer + 1 }, () => []) };
62
+ const idx = this._nodes.length;
63
+ this._nodes.push(node);
64
+ this._idToIdx.set(id, idx);
65
+ if (this._entry === -1) {
66
+ this._entry = idx;
67
+ this._maxLayer = layer;
68
+ return;
69
+ }
70
+ // Descend from the top to just above the new node's top layer.
71
+ let ep = this._entry;
72
+ for (let lc = this._maxLayer; lc > layer; lc--) {
73
+ ep = this._greedyClosest(vector, ep, lc);
74
+ }
75
+ // From the node's top layer down to 0: find neighbours and link.
76
+ for (let lc = Math.min(layer, this._maxLayer); lc >= 0; lc--) {
77
+ const candidates = this._searchLayer(vector, ep, this._efC, lc);
78
+ const Mmax = lc === 0 ? this._Mmax0 : this._M;
79
+ const selected = candidates.slice(0, this._M).map((c) => c.idx);
80
+ node.neighbours[lc] = selected.slice();
81
+ // Add reverse links, pruning each neighbour back to Mmax.
82
+ for (const nIdx of selected) {
83
+ const nb = this._nodes[nIdx];
84
+ const list = nb.neighbours[lc] ?? (nb.neighbours[lc] = []);
85
+ list.push(idx);
86
+ if (list.length > Mmax)
87
+ this._prune(nb, lc, Mmax);
88
+ }
89
+ ep = candidates[0]?.idx ?? ep;
90
+ }
91
+ if (layer > this._maxLayer) {
92
+ this._maxLayer = layer;
93
+ this._entry = idx;
94
+ }
95
+ }
96
+ /** Top-k nearest by cosine similarity (descending). */
97
+ search(query, k, ef = this._efS) {
98
+ if (this._entry === -1 || k <= 0)
99
+ return [];
100
+ let ep = this._entry;
101
+ for (let lc = this._maxLayer; lc > 0; lc--) {
102
+ ep = this._greedyClosest(query, ep, lc);
103
+ }
104
+ const found = this._searchLayer(query, ep, Math.max(ef, k), 0);
105
+ return found.slice(0, k).map((c) => ({ id: this._nodes[c.idx].id, score: 1 - c.dist }));
106
+ }
107
+ clear() {
108
+ this._nodes.length = 0;
109
+ this._idToIdx.clear();
110
+ this._entry = -1;
111
+ this._maxLayer = -1;
112
+ }
113
+ // ── internals ──────────────────────────────────────────────────────────────
114
+ /** Greedy hill-climb to the single closest node to `q` on layer `lc`. */
115
+ _greedyClosest(q, start, lc) {
116
+ let best = start;
117
+ let bestDist = this._dist(q, this._nodes[best].vector);
118
+ let improved = true;
119
+ while (improved) {
120
+ improved = false;
121
+ for (const nIdx of this._nodes[best].neighbours[lc] ?? []) {
122
+ const d = this._dist(q, this._nodes[nIdx].vector);
123
+ if (d < bestDist) {
124
+ bestDist = d;
125
+ best = nIdx;
126
+ improved = true;
127
+ }
128
+ }
129
+ }
130
+ return best;
131
+ }
132
+ /**
133
+ * ef-search on a single layer: returns candidates sorted nearest-first.
134
+ * A bounded best-first expansion (the standard HNSW layer search).
135
+ */
136
+ _searchLayer(q, entry, ef, lc) {
137
+ const visited = new Set([entry]);
138
+ const entryDist = this._dist(q, this._nodes[entry].vector);
139
+ // `candidates` is a min-heap-ish frontier; `results` keeps the best ef.
140
+ const candidates = [{ idx: entry, dist: entryDist }];
141
+ const results = [{ idx: entry, dist: entryDist }];
142
+ while (candidates.length > 0) {
143
+ // Pop nearest candidate.
144
+ let ci = 0;
145
+ for (let i = 1; i < candidates.length; i++)
146
+ if (candidates[i].dist < candidates[ci].dist)
147
+ ci = i;
148
+ const cur = candidates.splice(ci, 1)[0];
149
+ // Farthest in results.
150
+ const worst = results.reduce((m, r) => (r.dist > m.dist ? r : m), results[0]);
151
+ if (cur.dist > worst.dist && results.length >= ef)
152
+ break;
153
+ for (const nIdx of this._nodes[cur.idx].neighbours[lc] ?? []) {
154
+ if (visited.has(nIdx))
155
+ continue;
156
+ visited.add(nIdx);
157
+ const d = this._dist(q, this._nodes[nIdx].vector);
158
+ const farthest = results.reduce((m, r) => (r.dist > m.dist ? r : m), results[0]);
159
+ if (results.length < ef || d < farthest.dist) {
160
+ candidates.push({ idx: nIdx, dist: d });
161
+ results.push({ idx: nIdx, dist: d });
162
+ if (results.length > ef) {
163
+ // Drop the current farthest.
164
+ let wi = 0;
165
+ for (let i = 1; i < results.length; i++)
166
+ if (results[i].dist > results[wi].dist)
167
+ wi = i;
168
+ results.splice(wi, 1);
169
+ }
170
+ }
171
+ }
172
+ }
173
+ return results.sort((a, b) => a.dist - b.dist);
174
+ }
175
+ /** Keep only the `Mmax` closest neighbours of `node` on layer `lc`. */
176
+ _prune(node, lc, Mmax) {
177
+ const list = node.neighbours[lc];
178
+ list.sort((a, b) => this._dist(node.vector, this._nodes[a].vector) - this._dist(node.vector, this._nodes[b].vector));
179
+ node.neighbours[lc] = list.slice(0, Mmax);
180
+ }
181
+ }
182
+ /**
183
+ * Dense KNN with an exact-scan fast path: below `threshold` candidates a linear
184
+ * cosine scan is simpler and faster; at/above it, build an HNSW index and query
185
+ * it. Returned hits are cosine-similarity descending. Pure given its inputs.
186
+ */
187
+ export function denseSearch(query, items, k, threshold = 256, hnsw) {
188
+ if (items.length === 0 || k <= 0)
189
+ return [];
190
+ if (items.length < threshold) {
191
+ return items
192
+ .map((it) => ({ id: it.id, score: cosineSimilarity(query, it.vector) }))
193
+ .sort((a, b) => b.score - a.score)
194
+ .slice(0, k);
195
+ }
196
+ const index = new HnswIndex(hnsw);
197
+ for (const it of items)
198
+ index.add(it.id, it.vector);
199
+ return index.search(query, k);
200
+ }
201
+ //# sourceMappingURL=hnsw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hnsw.js","sourceRoot":"","sources":["../../src/retrieval/hnsw.ts"],"names":[],"mappings":"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"}
@@ -13,4 +13,6 @@ export { reciprocalRankFusion, maximalMarginalRelevance } from './fusion.js';
13
13
  export type { RankedList, FusedHit, MmrCandidate } from './fusion.js';
14
14
  export { hybridRetrieve } from './HybridRetriever.js';
15
15
  export type { RetrievalCandidate, HybridQuery, HybridRetrieveOptions, HybridHit, } from './HybridRetriever.js';
16
+ export { HnswIndex, denseSearch } from './hnsw.js';
17
+ export type { HnswOptions, SearchHit } from './hnsw.js';
16
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/retrieval/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE/D,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC7E,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEtE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EACR,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,SAAS,GACZ,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/retrieval/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE/D,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC7E,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEtE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EACR,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,SAAS,GACZ,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
@@ -9,4 +9,5 @@ export { chunkText } from './chunk.js';
9
9
  export { bm25Search } from './bm25.js';
10
10
  export { reciprocalRankFusion, maximalMarginalRelevance } from './fusion.js';
11
11
  export { hybridRetrieve } from './HybridRetriever.js';
12
+ export { HnswIndex, denseSearch } from './hnsw.js';
12
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/retrieval/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAG7E,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/retrieval/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAG7E,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAQtD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../../src/workflow/steps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAsB,MAAM,YAAY,CAAC;AAgChF,UAAU,UAAU;IAClB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAyQpD,CAAC"}
1
+ {"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../../src/workflow/steps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAgBH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAsB,MAAM,YAAY,CAAC;AAyChF,UAAU,UAAU;IAClB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAyVpD,CAAC"}