@metaharness/kernel 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -49,6 +49,89 @@ const ranked = await rankWithDecay(hits, {
49
49
 
50
50
  Wraps `@ruvector/emergent-time` for HNSW decay scoring.
51
51
 
52
+ ### RVF memory backend (optional, persistent)
53
+
54
+ `@metaharness/kernel/memory-rvf` stores memory vectors on disk in
55
+ [`@ruvector/rvf`](https://www.npmjs.com/package/@ruvector/rvf) files and searches
56
+ them with RVF's HNSW index. RVF is an optional peer dependency. Install it to
57
+ enable the backend:
58
+
59
+ ```sh
60
+ npm install @metaharness/kernel @ruvector/rvf
61
+ ```
62
+
63
+ ```js
64
+ import { createRvfBackend } from '@metaharness/kernel/memory-rvf';
65
+ import { rankWithDecay } from '@metaharness/kernel/memory';
66
+
67
+ const mem = await createRvfBackend({ dimensions: 384, dir: './.harness/memory' });
68
+ if (!mem) {
69
+ // @ruvector/rvf is not installed: keep using the default in-process memory.
70
+ } else {
71
+ await mem.insertBatch([{ id: 'note-1', embedding, metadata: { source: 'chat' } }], 'notes'); // re-insert = replace
72
+ const hits = await mem.search(query, 10, 'notes'); // [{ id, score, distance, namespace, storedAt, metadata }]
73
+ const ranked = await rankWithDecay(hits, { halfLifeMs: 7 * 24 * 3600e3 }); // newer first among near-ties
74
+ const exact = await mem.search(query, 10, 'notes', { exact: true }); // brute force
75
+ const fromChat = await mem.search(query, 10, 'notes', {
76
+ filter: { op: 'eq', field: 'source', value: 'chat' }, // metadata filter
77
+ });
78
+ await mem.delete(['note-1'], 'notes');
79
+ await mem.close(); // releases the file lock; reopen the same dir later to continue
80
+ }
81
+ ```
82
+
83
+ - Each namespace is one file, `<dir>/<namespace>.rvf`, plus its `.rvf.idmap.json`
84
+ id map. Keep the two together. Writes are committed when their promise
85
+ resolves. `flush()` is a no-op.
86
+ - `createRvfBackend()` returns `null` only when `@ruvector/rvf` is not installed.
87
+ Errors after that are thrown, not swallowed: a missing native binding, a
88
+ dimension mismatch, or a second writer on the same file (RVF holds a
89
+ single-writer lock until `close()`).
90
+ - With the default `cosine` metric, `score` is cosine similarity
91
+ (`1 - distance`). With `l2` it is `1 / (1 + distance)`, which ranks the same
92
+ way but is not a cosine similarity.
93
+ - Per-vector metadata (`@ruvector/rvf` 0.4.7 or later, with rvf-node 0.4.2): every
94
+ insert stores `storedAt` (ms since epoch; pass your own or it defaults to
95
+ `Date.now()`) and any `metadata` you pass, such as `{ source, tags }`. Hits return
96
+ `storedAt` and `metadata`, so `rankWithDecay` can reorder them by age. Numbers are
97
+ stored as f64, and objects and arrays as JSON. A field keeps the type of its first
98
+ value, and writing another type throws RVF's `MetadataTypeConflict`. `storedAt` is
99
+ a reserved key.
100
+ - `search(…, { filter })` takes RVF filter leaves `{ op, field, value }` (`eq`, `ne`,
101
+ `lt`, `le`, `gt`, `ge`, `in`, `range`) combined with `and`, `or` and `not`. A filter
102
+ that keeps most of the store is approximate on HNSW. Add `exact: true` for exact
103
+ filtered results.
104
+ - On an older RVF, writes skip metadata and hits come back without `storedAt`, as
105
+ in 0.1.5. RVF rejects metadata before it writes anything. The backend then retries
106
+ without metadata and reports `metadataSupported === false`. A `filter` throws in
107
+ this mode instead of returning unfiltered hits. Vectors written by 0.1.5 open
108
+ without changes and have no `storedAt`, so `rankWithDecay` treats them as age 0.
109
+ - `rankWithDecay` weights each hit by `0.5^(age / halfLifeMs)`. Before 0.1.6, it
110
+ looked for an emergent-time `AgenticClock.weight(ageMs)` that the package does not
111
+ have, and fell back to raw scores. So decay never reordered anything.
112
+ - `{ exact: true }` needs `@ruvector/rvf` 0.4.6 or later. Earlier versions ignore it.
113
+ - Supported range: `@ruvector/rvf` `^0.3.0 || ^0.4.7`. On 0.2.3, deletes did not
114
+ survive a reopen. In the 0.4 line the floor is 0.4.7, which adds per-vector metadata.
115
+
116
+ Measured with `bench/memory-rvf-bench.mjs` on `@ruvector/rvf` 0.4.7 (rvf-node 0.4.2),
117
+ Node 22 and kernel 0.1.6, where every insert carries its `storedAt` metadata. The data
118
+ was seeded uniform random vectors with cosine distance. Each run used 200 queries at
119
+ k = 10, scored against brute force after closing and reopening the store. Recall is
120
+ from unfiltered HNSW at the default efSearch 100. The figures are medians of 5
121
+ sequential runs on a shared host at load average about 19, so the latencies are
122
+ indicative only.
123
+
124
+ | Set | recall@10 (HNSW) | recall p50 / p95 | exact scan p50 (recall 1.0) | `insert()` p50 / p95 | `insertBatch` per vector |
125
+ |---|---|---|---|---|---|
126
+ | 10k × 128 | 0.972 | 0.76 ms / 1.20 ms | 0.58 ms | 16.8 ms / 21.7 ms | 0.039 ms |
127
+ | 10k × 384 | 0.8745 | 1.40 ms / 1.98 ms | 1.63 ms | – | 0.044 ms |
128
+
129
+ Recall is the same as on 0.4.6. At 384 dimensions, 0.4.7 does not raise HNSW recall.
130
+ In a same-host run of kernel 0.1.5 on rvf 0.4.6 (no metadata), `insert()` p50 was
131
+ 12.4 ms and `insertBatch` was 0.029 ms per vector at 10k × 128. Storing metadata adds
132
+ about a third to write cost. Each `insert()` is its own durable commit, so batch your
133
+ writes.
134
+
52
135
  ## Subsystems
53
136
 
54
137
  | Subsystem | What it does |
@@ -1,22 +1,135 @@
1
1
  import type { MemoryHit } from './memory.js';
2
+ export type RvfMetric = 'cosine' | 'l2';
3
+ /**
4
+ * A per-vector metadata value (@ruvector/rvf >= 0.4.7). Numbers are stored as
5
+ * f64, objects and arrays as JSON. A field keeps the type of the first
6
+ * non-null value written to it; writing another type throws RVF's
7
+ * MetadataTypeConflict (0xff09).
8
+ */
9
+ export type RvfMetadataValue = string | number | boolean | null | object;
10
+ /** Metadata key this module reserves for the insert timestamp. */
11
+ export declare const STORED_AT_FIELD = "storedAt";
12
+ type FilterLiteral = number | string | boolean;
13
+ /**
14
+ * A metadata filter, passed through to RVF. Leaves name a metadata key with
15
+ * `field` (`storedAt` or a key from your `metadata`).
16
+ */
17
+ export type RvfMetadataFilter = {
18
+ op: 'eq' | 'ne' | 'lt' | 'le' | 'gt' | 'ge';
19
+ field: string;
20
+ value: FilterLiteral;
21
+ } | {
22
+ op: 'in';
23
+ field: string;
24
+ values: FilterLiteral[];
25
+ } | {
26
+ op: 'range';
27
+ field: string;
28
+ low: FilterLiteral;
29
+ high: FilterLiteral;
30
+ } | {
31
+ op: 'and' | 'or';
32
+ exprs: RvfMetadataFilter[];
33
+ } | {
34
+ op: 'not';
35
+ expr: RvfMetadataFilter;
36
+ };
37
+ /** A memory hit from the RVF backend; carries RVF's raw distance as well. */
38
+ export interface RvfMemoryHit extends MemoryHit {
39
+ /**
40
+ * RVF distance (lower = closer). Cosine: `1 - cos_sim`. L2: squared
41
+ * Euclidean distance.
42
+ */
43
+ distance: number;
44
+ /**
45
+ * The caller metadata stored with the vector (without `storedAt`, which is
46
+ * lifted to `MemoryHit.storedAt`). Absent when the vector has none, or on
47
+ * @ruvector/rvf < 0.4.7.
48
+ */
49
+ metadata?: Record<string, RvfMetadataValue>;
50
+ }
51
+ export interface RvfSearchOptions {
52
+ /** Exact brute-force scan instead of HNSW (@ruvector/rvf >= 0.4.6; ignored earlier). */
53
+ exact?: boolean;
54
+ /** HNSW ef_search beam width. RVF default: 100. */
55
+ efSearch?: number;
56
+ /**
57
+ * Metadata filter (@ruvector/rvf >= 0.4.7). Throws when the installed RVF
58
+ * has no metadata support rather than returning unfiltered hits. A filter
59
+ * that keeps most of the store is approximate on HNSW; add `exact: true`
60
+ * for exact filtered results.
61
+ */
62
+ filter?: RvfMetadataFilter;
63
+ }
64
+ export interface RvfBackendOptions {
65
+ dimensions: number;
66
+ /**
67
+ * Distance metric. Default `'cosine'`, where `score = 1 - distance` is the
68
+ * cosine similarity. For `'l2'`, `score = 1 / (1 + distance)`: a monotone
69
+ * similarity in (0, 1], NOT a cosine similarity. The metric is fixed when a
70
+ * namespace file is created; reopening must use the same metric.
71
+ */
72
+ metric?: RvfMetric;
73
+ /**
74
+ * Directory holding one `.rvf` file per namespace. Created if missing.
75
+ * When omitted, a fresh temporary directory is used and deleted on
76
+ * `close()` — i.e. nothing persists.
77
+ */
78
+ dir?: string;
79
+ /** HNSW M (max edges per node per layer). RVF default: 16. */
80
+ m?: number;
81
+ /** HNSW ef_construction. RVF default: 200. */
82
+ efConstruction?: number;
83
+ }
84
+ export interface RvfBackendEntry {
85
+ id: string;
86
+ embedding: number[] | Float32Array;
87
+ /** Insert time in ms since epoch. Default: `Date.now()` at insert. */
88
+ storedAt?: number;
89
+ /** Extra per-vector metadata, e.g. `{ source, tags }`. `storedAt` is reserved. */
90
+ metadata?: Record<string, RvfMetadataValue>;
91
+ }
92
+ export interface RvfInsertOptions {
93
+ /** Insert time in ms since epoch. Default: `Date.now()` at insert. */
94
+ storedAt?: number;
95
+ /** Extra per-vector metadata, e.g. `{ source, tags }`. `storedAt` is reserved. */
96
+ metadata?: Record<string, RvfMetadataValue>;
97
+ }
2
98
  export interface RvfBackend {
3
- /** Insert a vector into the index. */
4
- insert(id: string, embedding: number[], namespace?: string): Promise<void>;
5
- /** Search by embedding similarity. */
6
- search(embedding: number[], k: number, namespace?: string): Promise<MemoryHit[]>;
7
- /** Total items currently indexed. */
8
- size(): Promise<number>;
9
- /** Persist + flush. */
99
+ /** Absolute directory holding the namespace files. */
100
+ readonly dir: string;
101
+ /** False when `dir` was not given (temporary directory, removed on close). */
102
+ readonly persistent: boolean;
103
+ /**
104
+ * Whether writes carry per-vector metadata. True on @ruvector/rvf >= 0.4.7
105
+ * (rvf-node >= 0.4.2); becomes false after the first write that RVF rejects
106
+ * with MetadataNotSupported, and stays false.
107
+ */
108
+ readonly metadataSupported: boolean;
109
+ /** Insert (or replace) one vector. */
110
+ insert(id: string, embedding: number[] | Float32Array, namespace?: string, opts?: RvfInsertOptions): Promise<void>;
111
+ /** Insert (or replace) many vectors in one RVF commit. */
112
+ insertBatch(entries: RvfBackendEntry[], namespace?: string): Promise<void>;
113
+ /** Top-k nearest neighbours, best first. Unknown namespace → []. */
114
+ search(embedding: number[] | Float32Array, k: number, namespace?: string, opts?: RvfSearchOptions): Promise<RvfMemoryHit[]>;
115
+ /** Delete ids; returns how many were live and removed. */
116
+ delete(ids: string[], namespace?: string): Promise<number>;
117
+ /** Live vectors in one namespace, or across all namespaces on disk. */
118
+ size(namespace?: string): Promise<number>;
119
+ /** Namespaces that exist on disk. */
120
+ namespaces(): string[];
121
+ /** No-op kept for the backend contract: writes are committed per call. */
10
122
  flush(): Promise<void>;
123
+ /** Close every open namespace file and release the writer locks. */
124
+ close(): Promise<void>;
11
125
  }
12
- /** Is the RVF package installed and importable in the current process? */
126
+ /** Is a usable @ruvector/rvf (with `RvfDatabase`) importable in this process? */
13
127
  export declare function isRvfAvailable(): Promise<boolean>;
14
128
  /**
15
- * Create an RVF-backed backend. Returns null if RVF isn't installed —
16
- * caller falls back to the in-process HNSW.
129
+ * Create an RVF-backed memory backend. Returns null only when
130
+ * @ruvector/rvf is not installed (or has no `RvfDatabase`), so the caller
131
+ * can fall back to its default memory. Namespace files are opened lazily.
17
132
  */
18
- export declare function createRvfBackend(opts: {
19
- dimensions: number;
20
- metric?: 'cosine' | 'l2';
21
- }): Promise<RvfBackend | null>;
133
+ export declare function createRvfBackend(opts: RvfBackendOptions): Promise<RvfBackend | null>;
134
+ export {};
22
135
  //# sourceMappingURL=memory-rvf.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory-rvf.d.ts","sourceRoot":"","sources":["../src/memory-rvf.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,UAAU;IACzB,sCAAsC;IACtC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,sCAAsC;IACtC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACjF,qCAAqC;IACrC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,uBAAuB;IACvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAiCD,0EAA0E;AAC1E,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAEvD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC1B,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA2C7B"}
1
+ {"version":3,"file":"memory-rvf.d.ts","sourceRoot":"","sources":["../src/memory-rvf.ts"],"names":[],"mappings":"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"}
@@ -1,86 +1,298 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  //
3
- // memory-rvf — graceful-fallback wrapper over @ruvector/rvf
3
+ // memory-rvf — persistent kernel memory on @ruvector/rvf
4
4
  // (https://www.npmjs.com/package/@ruvector/rvf).
5
5
  //
6
- // RVF is "RuVector Format — unified TypeScript SDK for vector intelligence":
7
- // HNSW-indexed binary vector format with SIMD, dual-target (TypeScript
8
- // runtime + optional @ruvector/rvf-wasm). When the user has RVF installed
9
- // AND wants RVF-backed memory storage, the kernel uses it; otherwise the
10
- // memory subsystem keeps using its plain in-process HNSW.
6
+ // RVF ("RuVector Format") is an HNSW-indexed, single-file vector store with a
7
+ // native Node backend (@ruvector/rvf-node). This module maps the kernel's
8
+ // memory backend contract onto `RvfDatabase`:
11
9
  //
12
- // RVF is declared as an OPTIONAL peer dep so the kernel doesn't bloat
13
- // install size for users who don't need it. The pairing matters most
14
- // for RVM-deployed harnesses — RVM's wasm guest can run rvf-wasm
15
- // inside the partition for hardware-isolated vector storage.
10
+ // kernel @ruvector/rvf
11
+ // ------------------------ -------------------------------------------
12
+ // namespace one `<namespace>.rvf` file under `dir`
13
+ // (+ its `.rvf.idmap.json` string-id sidecar)
14
+ // insert / insertBatch RvfDatabase.ingestBatch (re-insert = upsert),
15
+ // with per-vector metadata { storedAt, ... }
16
+ // search RvfDatabase.query(vec, k, { efSearch,
17
+ // forceExact, filter }); hits carry
18
+ // `storedAt` and `metadata`
19
+ // delete RvfDatabase.delete(ids)
20
+ // size RvfDatabase.status().totalVectors
21
+ // flush no-op: every ingest/delete is committed to
22
+ // the file when its promise resolves
23
+ // close RvfDatabase.close() (releases the writer lock)
24
+ //
25
+ // Per-vector metadata (ruvector #704) needs @ruvector/rvf >= 0.4.7 with
26
+ // rvf-node >= 0.4.2. Every insert stores `storedAt` (ms since epoch, default
27
+ // Date.now()) plus any caller `metadata`; hits return both, so `rankWithDecay`
28
+ // can reorder them by age, and `search(..., { filter })` filters on them.
29
+ // Earlier versions reject metadata with MetadataNotSupported before writing
30
+ // anything; this module then retries the same write WITHOUT metadata and
31
+ // stays in that mode for the backend's lifetime, i.e. it behaves exactly as
32
+ // kernel 0.1.5 did (no `storedAt` on hits, decay treats them as age 0).
33
+ // Vectors written before metadata existed (e.g. by kernel 0.1.5) also come
34
+ // back without `storedAt`. Namespaces stay separate files.
35
+ //
36
+ // What RVF cannot do, and how this module handles it:
37
+ // - `forceExact` (exact brute-force search) is passed through by
38
+ // @ruvector/rvf >= 0.4.6 (rvf-node >= 0.4.1). Earlier versions ignore it
39
+ // and search stays on HNSW.
40
+ // - Each `.rvf` file has a single-writer lock. A second backend (in this or
41
+ // another process) opening the same namespace for writing fails with
42
+ // RVF LockHeld. Call `close()` to release it.
43
+ //
44
+ // RVF is an OPTIONAL peer dependency (^0.3.0 || ^0.4.7). When it is not
45
+ // installed, `createRvfBackend()` returns null and the caller keeps its
46
+ // default in-process memory. When it IS installed but fails at use time
47
+ // (native binding missing, lock held, dimension mismatch), the error is
48
+ // thrown rather than silently swallowed.
49
+ import { existsSync, mkdirSync, mkdtempSync, readdirSync, rmSync } from 'node:fs';
50
+ import { tmpdir } from 'node:os';
51
+ import { join, resolve } from 'node:path';
52
+ /** Metadata key this module reserves for the insert timestamp. */
53
+ export const STORED_AT_FIELD = 'storedAt';
54
+ /** RvfErrorCode.MetadataNotSupported (0xff04). */
55
+ const METADATA_NOT_SUPPORTED = 0xff04;
16
56
  let _rvf;
17
57
  async function loadRvf() {
18
58
  if (_rvf !== undefined)
19
59
  return _rvf;
20
60
  try {
21
- // @ts-ignore — @ruvector/rvf is declared as an OPTIONAL peer
22
- // dependency, so a fresh CI install without it must build cleanly.
23
- // The graceful-fallback path returns null when the package is absent.
24
- _rvf = await import('@ruvector/rvf');
25
- return _rvf;
61
+ // @ts-ignore — @ruvector/rvf is an OPTIONAL peer dependency, so a fresh
62
+ // install without it must still type-check and build.
63
+ const mod = (await import('@ruvector/rvf'));
64
+ const db = mod.RvfDatabase ?? mod.default?.RvfDatabase;
65
+ const codes = mod.RvfErrorCode ?? mod.default?.RvfErrorCode;
66
+ _rvf =
67
+ db && typeof db.create === 'function' && typeof db.open === 'function'
68
+ ? { db, sdkHasMetadata: typeof codes?.MetadataTypeConflict === 'number' }
69
+ : null;
26
70
  }
27
71
  catch {
28
72
  _rvf = null;
29
- return null;
30
73
  }
74
+ return _rvf;
75
+ }
76
+ function isMetadataNotSupported(err) {
77
+ return typeof err === 'object' && err !== null && err.code === METADATA_NOT_SUPPORTED;
78
+ }
79
+ function checkStoredAt(storedAt, fallback) {
80
+ if (storedAt === undefined)
81
+ return fallback;
82
+ if (typeof storedAt !== 'number' || !Number.isFinite(storedAt)) {
83
+ throw new Error(`memory-rvf: storedAt must be a finite number (ms since epoch), got ${storedAt}`);
84
+ }
85
+ return storedAt;
31
86
  }
32
- /** Is the RVF package installed and importable in the current process? */
87
+ /** Is a usable @ruvector/rvf (with `RvfDatabase`) importable in this process? */
33
88
  export async function isRvfAvailable() {
34
89
  return (await loadRvf()) !== null;
35
90
  }
91
+ const NAMESPACE_RE = /^[A-Za-z0-9_-][A-Za-z0-9._-]{0,127}$/;
92
+ const FILE_SUFFIX = '.rvf';
93
+ function checkNamespace(ns) {
94
+ if (typeof ns !== 'string' || !NAMESPACE_RE.test(ns)) {
95
+ throw new Error(`memory-rvf: invalid namespace ${JSON.stringify(ns)} — use 1-128 chars of [A-Za-z0-9._-], not starting with '.'`);
96
+ }
97
+ return ns;
98
+ }
99
+ function toVector(embedding, dimensions) {
100
+ if (!embedding || embedding.length !== dimensions) {
101
+ throw new Error(`memory-rvf: embedding has ${embedding?.length} dims, backend expects ${dimensions}`);
102
+ }
103
+ const v = embedding instanceof Float32Array ? embedding : Float32Array.from(embedding);
104
+ for (let i = 0; i < v.length; i++) {
105
+ if (!Number.isFinite(v[i]))
106
+ throw new Error(`memory-rvf: embedding[${i}] is not finite`);
107
+ }
108
+ return v;
109
+ }
36
110
  /**
37
- * Create an RVF-backed backend. Returns null if RVF isn't installed —
38
- * caller falls back to the in-process HNSW.
111
+ * Create an RVF-backed memory backend. Returns null only when
112
+ * @ruvector/rvf is not installed (or has no `RvfDatabase`), so the caller
113
+ * can fall back to its default memory. Namespace files are opened lazily.
39
114
  */
40
115
  export async function createRvfBackend(opts) {
41
- const mod = await loadRvf();
42
- if (!mod)
43
- return null;
44
- const createIndex = mod.createIndex ?? mod.default?.createIndex;
45
- if (typeof createIndex !== 'function')
116
+ const loaded = await loadRvf();
117
+ if (!loaded)
46
118
  return null;
47
- const indexByNs = new Map();
48
- const ensure = async (ns) => {
49
- let idx = indexByNs.get(ns);
50
- if (!idx) {
51
- idx = await createIndex({ dimensions: opts.dimensions, metric: opts.metric ?? 'cosine' });
52
- indexByNs.set(ns, idx);
119
+ const Rvf = loaded.db;
120
+ let metadataSupported = loaded.sdkHasMetadata;
121
+ const dimensions = opts.dimensions;
122
+ if (!Number.isInteger(dimensions) || dimensions <= 0) {
123
+ throw new Error(`memory-rvf: dimensions must be a positive integer, got ${dimensions}`);
124
+ }
125
+ const metric = opts.metric ?? 'cosine';
126
+ if (metric !== 'cosine' && metric !== 'l2') {
127
+ throw new Error(`memory-rvf: unsupported metric ${JSON.stringify(metric)}`);
128
+ }
129
+ const persistent = typeof opts.dir === 'string' && opts.dir.length > 0;
130
+ const dir = persistent ? resolve(opts.dir) : mkdtempSync(join(tmpdir(), 'metaharness-rvf-'));
131
+ mkdirSync(dir, { recursive: true });
132
+ const toScore = metric === 'cosine' ? (d) => 1 - d : (d) => 1 / (1 + d);
133
+ const pathOf = (ns) => join(dir, checkNamespace(ns) + FILE_SUFFIX);
134
+ // Cache the promise, not the value, so concurrent first use of a namespace
135
+ // opens/creates the file exactly once.
136
+ const dbs = new Map();
137
+ let closed = false;
138
+ const openOrCreate = async (ns) => {
139
+ const p = pathOf(ns);
140
+ if (existsSync(p)) {
141
+ const db = await Rvf.open(p);
142
+ const dim = await db.dimension();
143
+ if (dim !== dimensions) {
144
+ await db.close();
145
+ throw new Error(`memory-rvf: ${p} has ${dim} dims, backend expects ${dimensions}`);
146
+ }
147
+ return db;
148
+ }
149
+ const createOpts = {
150
+ dimensions,
151
+ metric,
152
+ };
153
+ if (opts.m !== undefined)
154
+ createOpts.m = opts.m;
155
+ if (opts.efConstruction !== undefined)
156
+ createOpts.efConstruction = opts.efConstruction;
157
+ return Rvf.create(p, createOpts);
158
+ };
159
+ /** Returns the open db, or null when `create` is false and no file exists. */
160
+ const get = async (ns, create) => {
161
+ if (closed)
162
+ throw new Error('memory-rvf: backend is closed');
163
+ const cached = dbs.get(ns);
164
+ if (cached)
165
+ return cached;
166
+ if (!create && !existsSync(pathOf(ns)))
167
+ return null;
168
+ const pending = openOrCreate(ns);
169
+ dbs.set(ns, pending);
170
+ pending.catch(() => dbs.delete(ns));
171
+ return pending;
172
+ };
173
+ const listNamespaces = () => readdirSync(dir)
174
+ .filter(f => f.endsWith(FILE_SUFFIX))
175
+ .map(f => f.slice(0, -FILE_SUFFIX.length))
176
+ .filter(ns => NAMESPACE_RE.test(ns))
177
+ .sort();
178
+ const insertBatch = async (entries, namespace = 'default') => {
179
+ if (entries.length === 0)
180
+ return;
181
+ const now = Date.now();
182
+ const rows = entries.map(e => {
183
+ if (typeof e.id !== 'string' || e.id.length === 0)
184
+ throw new Error('memory-rvf: id must be a non-empty string');
185
+ if (e.metadata !== undefined && (typeof e.metadata !== 'object' || e.metadata === null || Array.isArray(e.metadata))) {
186
+ throw new Error('memory-rvf: metadata must be a plain object');
187
+ }
188
+ if (e.metadata && STORED_AT_FIELD in e.metadata) {
189
+ throw new Error(`memory-rvf: metadata key "${STORED_AT_FIELD}" is reserved; pass storedAt instead`);
190
+ }
191
+ const storedAt = checkStoredAt(e.storedAt, now);
192
+ return {
193
+ id: e.id,
194
+ vector: toVector(e.embedding, dimensions),
195
+ metadata: { ...e.metadata, [STORED_AT_FIELD]: storedAt },
196
+ };
197
+ });
198
+ const db = (await get(namespace, true));
199
+ const plain = () => rows.map(({ id, vector }) => ({ id, vector }));
200
+ let res;
201
+ if (!metadataSupported) {
202
+ res = await db.ingestBatch(plain());
203
+ }
204
+ else {
205
+ try {
206
+ res = await db.ingestBatch(rows);
207
+ }
208
+ catch (err) {
209
+ // RVF < 0.4.7 (or rvf-node < 0.4.2) rejects metadata before writing.
210
+ if (!isMetadataNotSupported(err))
211
+ throw err;
212
+ metadataSupported = false;
213
+ res = await db.ingestBatch(plain());
214
+ }
215
+ }
216
+ if (res.rejected > 0) {
217
+ throw new Error(`memory-rvf: RVF rejected ${res.rejected} of ${rows.length} vectors in namespace ${namespace}`);
53
218
  }
54
- return idx;
55
219
  };
56
220
  return {
57
- async insert(id, embedding, namespace = 'default') {
58
- const idx = await ensure(namespace);
59
- await idx.add(id, embedding);
221
+ dir,
222
+ persistent,
223
+ get metadataSupported() {
224
+ return metadataSupported;
60
225
  },
61
- async search(embedding, k, namespace = 'default') {
62
- const idx = await ensure(namespace);
63
- const raw = await idx.search(embedding, k);
64
- return raw.map(r => ({
65
- id: r.id,
66
- score: r.score,
67
- decayedScore: r.score, // memory.rankWithDecay applies decay separately
68
- namespace,
69
- }));
226
+ insert(id, embedding, namespace = 'default', io = {}) {
227
+ return insertBatch([{ id, embedding, storedAt: io.storedAt, metadata: io.metadata }], namespace);
228
+ },
229
+ insertBatch,
230
+ async search(embedding, k, namespace = 'default', so = {}) {
231
+ if (!Number.isInteger(k) || k <= 0)
232
+ throw new Error(`memory-rvf: k must be a positive integer, got ${k}`);
233
+ if (so.filter !== undefined && !metadataSupported) {
234
+ throw new Error('memory-rvf: metadata filters need @ruvector/rvf >= 0.4.7 with rvf-node >= 0.4.2');
235
+ }
236
+ const vec = toVector(embedding, dimensions);
237
+ const db = await get(namespace, false);
238
+ if (!db)
239
+ return [];
240
+ const q = {};
241
+ if (so.efSearch !== undefined)
242
+ q.efSearch = so.efSearch;
243
+ if (so.exact)
244
+ q.forceExact = true;
245
+ if (so.filter !== undefined)
246
+ q.filter = so.filter;
247
+ const raw = await db.query(vec, k, q);
248
+ return raw.map(r => {
249
+ const score = toScore(r.distance);
250
+ const hit = { id: r.id, score, decayedScore: score, distance: r.distance, namespace };
251
+ if (r.metadata) {
252
+ const { [STORED_AT_FIELD]: storedAt, ...rest } = r.metadata;
253
+ if (typeof storedAt === 'number')
254
+ hit.storedAt = storedAt;
255
+ if (Object.keys(rest).length > 0)
256
+ hit.metadata = rest;
257
+ }
258
+ return hit;
259
+ });
70
260
  },
71
- async size() {
261
+ async delete(ids, namespace = 'default') {
262
+ if (ids.length === 0)
263
+ return 0;
264
+ const db = await get(namespace, false);
265
+ if (!db)
266
+ return 0;
267
+ return (await db.delete(ids)).deleted;
268
+ },
269
+ async size(namespace) {
270
+ const targets = namespace === undefined ? listNamespaces() : [namespace];
72
271
  let total = 0;
73
- for (const idx of indexByNs.values()) {
74
- const count = await (idx.count?.() ?? idx.size?.() ?? Promise.resolve(0));
75
- total += count ?? 0;
272
+ for (const ns of targets) {
273
+ const db = await get(ns, false);
274
+ if (db)
275
+ total += (await db.status()).totalVectors;
76
276
  }
77
277
  return total;
78
278
  },
279
+ namespaces: listNamespaces,
79
280
  async flush() {
80
- for (const idx of indexByNs.values()) {
81
- if (typeof idx.flush === 'function')
82
- await idx.flush();
83
- }
281
+ if (closed)
282
+ throw new Error('memory-rvf: backend is closed');
283
+ await Promise.allSettled([...dbs.values()]);
284
+ },
285
+ async close() {
286
+ if (closed)
287
+ return;
288
+ closed = true;
289
+ const open = await Promise.allSettled([...dbs.values()]);
290
+ dbs.clear();
291
+ for (const r of open)
292
+ if (r.status === 'fulfilled')
293
+ await r.value.close();
294
+ if (!persistent)
295
+ rmSync(dir, { recursive: true, force: true });
84
296
  },
85
297
  };
86
298
  }
@@ -1 +1 @@
1
- {"version":3,"file":"memory-rvf.js","sourceRoot":"","sources":["../src/memory-rvf.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,4DAA4D;AAC5D,iDAAiD;AACjD,EAAE;AACF,6EAA6E;AAC7E,uEAAuE;AACvE,0EAA0E;AAC1E,yEAAyE;AACzE,0DAA0D;AAC1D,EAAE;AACF,sEAAsE;AACtE,qEAAqE;AACrE,iEAAiE;AACjE,6DAA6D;AA8B7D,IAAI,IAAkC,CAAC;AAEvC,KAAK,UAAU,OAAO;IACpB,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,CAAC;QACH,6DAA6D;QAC7D,mEAAmE;QACnE,sEAAsE;QACtE,IAAI,GAAG,MAAM,MAAM,CAAC,eAAe,CAAyB,CAAC;QAC7D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,GAAG,IAAI,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,OAAO,CAAC,MAAM,OAAO,EAAE,CAAC,KAAK,IAAI,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAGtC;IACC,MAAM,GAAG,GAAG,MAAM,OAAO,EAAE,CAAC;IAC5B,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC;IAChE,IAAI,OAAO,WAAW,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC9C,MAAM,MAAM,GAAG,KAAK,EAAE,EAAU,EAAqB,EAAE;QACrD,IAAI,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,MAAM,WAAW,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC,CAAC;YAC1F,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;IACF,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,SAAS,GAAG,SAAS;YAC/C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;YACpC,MAAM,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QAC/B,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS;YAC9C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YAC3C,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACnB,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,YAAY,EAAE,CAAC,CAAC,KAAK,EAAE,gDAAgD;gBACvE,SAAS;aACV,CAAC,CAAC,CAAC;QACN,CAAC;QACD,KAAK,CAAC,IAAI;YACR,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;gBACrC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC1E,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC;YACtB,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,KAAK,CAAC,KAAK;YACT,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;gBACrC,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,UAAU;oBAAE,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;YACzD,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"memory-rvf.js","sourceRoot":"","sources":["../src/memory-rvf.ts"],"names":[],"mappings":"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"}
package/dist/memory.d.ts CHANGED
@@ -26,8 +26,9 @@ export interface DecayConfig {
26
26
  halfLifeMs?: number;
27
27
  }
28
28
  /**
29
- * Rank a list of raw HNSW hits, applying AgenticClock decay weights when
30
- * `useDecay` is true and the emergent-time package is available.
29
+ * Rank a list of raw HNSW hits by decay-weighted score when `useDecay` is
30
+ * true: an emergent-time AgenticClock weight when one is usable, otherwise
31
+ * the half-life weight `linearDecay(age, halfLifeMs)`.
31
32
  *
32
33
  * Returns a NEW array sorted descending by decayedScore (when useDecay=true)
33
34
  * or score (when false).
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,SAAS;IACxB,uBAAuB;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA6BD;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,SAAS,EAAE,EACjB,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,SAAS,EAAE,CAAC,CAyBtB;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAC9F,CAAC,KAAK,EAAE,MAAM,KAAK;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAC/D,CASA;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAIrE"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,SAAS;IACxB,uBAAuB;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAyCD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,SAAS,EAAE,EACjB,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,SAAS,EAAE,CAAC,CAwBtB;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAC9F,CAAC,KAAK,EAAE,MAAM,KAAK;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAC/D,CASA;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAIrE"}
package/dist/memory.js CHANGED
@@ -40,9 +40,23 @@ async function loadEmergent() {
40
40
  return null;
41
41
  }
42
42
  }
43
+ /** An emergent-time clock with a callable `weight(ageMs)`, or null. */
44
+ async function emergentDecayClock(halfLifeMs) {
45
+ const emergent = await loadEmergent();
46
+ if (!emergent)
47
+ return null;
48
+ try {
49
+ const clock = new emergent.AgenticClock({ halfLifeMs });
50
+ return typeof clock.weight === 'function' ? clock : null;
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ }
43
56
  /**
44
- * Rank a list of raw HNSW hits, applying AgenticClock decay weights when
45
- * `useDecay` is true and the emergent-time package is available.
57
+ * Rank a list of raw HNSW hits by decay-weighted score when `useDecay` is
58
+ * true: an emergent-time AgenticClock weight when one is usable, otherwise
59
+ * the half-life weight `linearDecay(age, halfLifeMs)`.
46
60
  *
47
61
  * Returns a NEW array sorted descending by decayedScore (when useDecay=true)
48
62
  * or score (when false).
@@ -54,14 +68,14 @@ export async function rankWithDecay(hits, config = {}) {
54
68
  if (!useDecay) {
55
69
  return [...hits].sort((a, b) => b.score - a.score);
56
70
  }
57
- const emergent = await loadEmergent();
58
- if (!emergent) {
59
- // Graceful fallback — return raw scores in `decayedScore` so callers
60
- // don't have to special-case the absence of emergent-time.
61
- return [...hits].map(h => ({ ...h, decayedScore: h.score }))
62
- .sort((a, b) => b.decayedScore - a.decayedScore);
63
- }
64
- const clock = new emergent.AgenticClock({ halfLifeMs });
71
+ // Without a usable emergent-time clock, decay with the deterministic
72
+ // half-life weight 0.5^(age / halfLifeMs). `score` stays raw. Until 0.1.6
73
+ // this path returned raw scores, so decay never reordered anything:
74
+ // @ruvector/emergent-time 0.1.x has no `weight(ageMs)` (its AgenticClock
75
+ // measures internal agent time from state deltas, not age decay).
76
+ const clock = (await emergentDecayClock(halfLifeMs))
77
+ ?? { weight: (ageMs) => linearDecay(ageMs, halfLifeMs) };
78
+ // Hits without `storedAt` are treated as age 0 (weight 1).
65
79
  const ranked = hits.map(h => {
66
80
  const ageMs = h.storedAt !== undefined ? Math.max(0, now - h.storedAt) : 0;
67
81
  const weight = clock.weight(ageMs);
@@ -1 +1 @@
1
- {"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaharness/kernel",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Cross-platform kernel for the agent-harness-generator — wasm primary, NAPI-RS native fallback",
5
5
  "homepage": "https://github.com/ruvnet/metaharness",
6
6
  "repository": {
@@ -57,7 +57,7 @@
57
57
  "@ruvector/emergent-time": "^0.1.0"
58
58
  },
59
59
  "peerDependencies": {
60
- "@ruvector/rvf": "^0.2.0 || ^0.3.0 || ^0.4.0",
60
+ "@ruvector/rvf": "^0.3.0 || ^0.4.7",
61
61
  "@metaharness/kernel-darwin-arm64": "0.1.0",
62
62
  "@metaharness/kernel-darwin-x64": "0.1.0",
63
63
  "@metaharness/kernel-linux-x64-gnu": "0.1.0",
@@ -86,5 +86,8 @@
86
86
  },
87
87
  "engines": {
88
88
  "node": ">=20.0.0"
89
+ },
90
+ "devDependencies": {
91
+ "@ruvector/rvf": "^0.4.7"
89
92
  }
90
93
  }