@avantf/dsh-mem 0.4.2 → 0.6.1

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 (54) hide show
  1. package/README.md +19 -1
  2. package/lib/client.js +39 -9
  3. package/lib/engine/mem/config/config_files.d.ts +1 -1
  4. package/lib/engine/mem/db/dao/chunks.d.ts +80 -5
  5. package/lib/engine/mem/db/dao/entities.d.ts +35 -11
  6. package/lib/engine/mem/db/dao/fact_sources.d.ts +53 -0
  7. package/lib/engine/mem/db/dao/facts.d.ts +115 -12
  8. package/lib/engine/mem/db/dao/shared.d.ts +153 -0
  9. package/lib/engine/mem/db/invariants.d.ts +26 -0
  10. package/lib/engine/mem/db/tokenizer.d.ts +23 -0
  11. package/lib/engine/mem/db/vectors.d.ts +32 -6
  12. package/lib/engine/mem/entities/extract.d.ts +1 -1
  13. package/lib/engine/mem/eval/derive.d.ts +120 -0
  14. package/lib/engine/mem/eval/derived_runner.d.ts +88 -0
  15. package/lib/engine/mem/eval/index.d.ts +4 -0
  16. package/lib/engine/mem/eval/metrics.d.ts +24 -0
  17. package/lib/engine/mem/eval/runner.d.ts +8 -1
  18. package/lib/engine/mem/index.d.ts +2 -1
  19. package/lib/engine/mem/modelBootstrap.d.ts +2 -2
  20. package/lib/engine/mem/runtime.d.ts +3 -3
  21. package/lib/engine/mem/store/common.d.ts +18 -6
  22. package/lib/engine/mem/store/entity_leg.d.ts +95 -0
  23. package/lib/engine/mem/store/entity_sweep.d.ts +121 -0
  24. package/lib/engine/mem/store/floors.d.ts +51 -31
  25. package/lib/engine/mem/store/hybrid.d.ts +71 -26
  26. package/lib/engine/mem/store/knowledge.d.ts +134 -21
  27. package/lib/engine/mem/store/legs.d.ts +171 -0
  28. package/lib/engine/mem/store/lexical.d.ts +52 -0
  29. package/lib/engine/mem/store/memory.d.ts +177 -92
  30. package/lib/engine/mem/store/secret_guard.d.ts +34 -0
  31. package/lib/engine/mem/store/time_window.d.ts +74 -0
  32. package/lib/engine/mem/store/vector_repair.d.ts +248 -0
  33. package/lib/engine/mem-contract/config.d.ts +8 -16
  34. package/lib/engine/mem-contract/family.d.ts +1 -1
  35. package/lib/engine/mem-contract/tools.d.ts +14 -0
  36. package/lib/engine/mem-contract/types.d.ts +151 -15
  37. package/lib/engine/mem-retrieval/adapters/local_bge.d.ts +37 -7
  38. package/lib/engine/mem-retrieval/fusion.d.ts +14 -1
  39. package/lib/engine/mem-retrieval/index.d.ts +1 -3
  40. package/lib/engine/mem-retrieval/interfaces.d.ts +38 -14
  41. package/lib/engine/mem-retrieval/registry.d.ts +2 -4
  42. package/lib/engine/mem-retrieval/representation.d.ts +50 -0
  43. package/lib/engine/mem-retrieval/stats.d.ts +1 -3
  44. package/lib/index.js +3008 -1008
  45. package/lib/types/client/index.d.ts.map +1 -1
  46. package/lib/types/index.d.ts +1 -1
  47. package/lib/types/index.d.ts.map +1 -1
  48. package/lib/types/prompt.d.ts +7 -0
  49. package/lib/types/prompt.d.ts.map +1 -1
  50. package/lib/types/remote.d.ts +12 -6
  51. package/lib/types/remote.d.ts.map +1 -1
  52. package/lib/types/vectorMigration.d.ts +22 -18
  53. package/lib/types/vectorMigration.d.ts.map +1 -1
  54. package/package.json +5 -5
@@ -1,4 +1,4 @@
1
- import type { SemanticBackend } from '../interfaces.js';
1
+ import type { SemanticBackend, SemanticRepresentation } from '../interfaces.js';
2
2
  /**
3
3
  * The injected pipeline surface: one text OR an array of texts in, a tensor out.
4
4
  *
@@ -31,6 +31,18 @@ export interface ModelEnv {
31
31
  * text first and logs it once (`text_budget.ts`).
32
32
  */
33
33
  maxInputTokens?: number;
34
+ /**
35
+ * Pooling strategy handed to the feature-extraction pipeline (`mean` by default). Part of the
36
+ * representation fingerprint (`representationKey`): `mean` and `cls` produce DIFFERENT
37
+ * coordinates from the same weights, so a change here is a data migration, not a tuning knob.
38
+ */
39
+ pooling?: string;
40
+ /**
41
+ * Whether the pipeline L2-normalizes (`true` by default). Also part of the representation:
42
+ * an un-normalized vector ranks differently under cosine, so switching it invalidates every
43
+ * persisted vector exactly like a model swap does.
44
+ */
45
+ normalize?: boolean;
34
46
  /**
35
47
  * Do NOT warm in the constructor: the first `encode()` / `encodeBatch()` warms lazily.
36
48
  *
@@ -61,13 +73,34 @@ export declare class LocalBgeBackend implements SemanticBackend {
61
73
  private _dimWarned;
62
74
  private _lengthWarned;
63
75
  private _window;
76
+ /** Cached so the fingerprint cannot move while the process runs (see {@link representation}). */
77
+ private _representation;
64
78
  private readonly configuredMax;
79
+ private readonly pooling;
80
+ private readonly normalize;
65
81
  private readonly model;
66
82
  private readonly env;
67
83
  private readonly pipeFactory;
68
84
  private readonly gate;
69
85
  constructor(model: string, dim: number, env?: Partial<ModelEnv>, pipeFactory?: PipeFactory);
70
86
  isAvailable(): boolean;
87
+ /**
88
+ * The representation knobs this adapter applies, resolved ONCE per instance.
89
+ *
90
+ * Resolved once on purpose: the model revision comes from disk, and a fingerprint that changed
91
+ * mid-process (install settles, sidecar appears) would make the store declare the rows it just
92
+ * wrote stale. The cost of reading it early is bounded and honest — a process that starts BEFORE
93
+ * the family provisioner lands the model writes a revision-less fingerprint for that session, and
94
+ * the next start re-encodes once into the revision-carrying one. The alternative (reading late)
95
+ * would re-encode on every restart instead.
96
+ *
97
+ * A missing sidecar is reported once, as a DEGRADATION: the fingerprint then cannot see a repo
98
+ * whose weights were re-pushed under the same name, which is a real (narrow) blind spot and must
99
+ * not be mistaken for a healthy state. It never throws, and it stays quiet while the weights are
100
+ * not on disk yet (a fresh install in flight has nothing to fingerprint; the sidecar arrives with
101
+ * the weights). The resolved representation is CACHED, so the warning is one line per process.
102
+ */
103
+ representation(): SemanticRepresentation;
71
104
  /**
72
105
  * Fire-and-forget retry for call sites that only observe availability. No-op
73
106
  * while the model is ready or an attempt is already in flight; otherwise
@@ -111,11 +144,8 @@ export declare class LocalBgeBackend implements SemanticBackend {
111
144
  /**
112
145
  * Apply this project's cache/mirror policy to transformers.js.
113
146
  *
114
- * `mod.env` is PROCESS-GLOBAL and last-writer-wins: the embedder and the reranker are two adapters
115
- * over ONE module, so whichever warms second decides what both see. Setting the keys from a single
116
- * place is what keeps the two from disagreeing — the reranker used to set `allowLocalModels` on its
117
- * own, which reads as a policy difference between the adapters and was really an accident of which
118
- * file got edited last. `allowLocalModels` is already the library default; it is stated here so the
119
- * policy is explicit rather than inherited, and identical for both adapters.
147
+ * `mod.env` is PROCESS-GLOBAL and last-writer-wins. Setting the keys from a single place is what
148
+ * keeps every future adapter over this module from disagreeing: `allowLocalModels` is already the
149
+ * library default, stated here so the policy is explicit rather than inherited.
120
150
  */
121
151
  export declare function applyModelEnv(mod: TransformersModule, env: ModelEnv): void;
@@ -29,6 +29,17 @@ export interface FusionPath {
29
29
  export interface Hit {
30
30
  id: number;
31
31
  score: number;
32
+ /**
33
+ * P-01 per-leg evidence, aligned to the `paths` array the caller passed, and only present when
34
+ * the caller asked for it (`opts.includeLegs`). `null` at an index means that leg did not
35
+ * recall this candidate — the explicit "no evidence", which a missing entry would hide.
36
+ */
37
+ legs?: (LegScore | null)[];
38
+ }
39
+ /** P-01: one leg's contribution to one candidate (raw on the leg's scale + the value fused). */
40
+ export interface LegScore {
41
+ raw: number;
42
+ normalized: number;
32
43
  }
33
44
  /**
34
45
  * Scale raw scores by the set's maximum, into [0,1].
@@ -50,4 +61,6 @@ export declare function scaleByMax(scores: Map<number, number>): Map<number, num
50
61
  * scaled scores collide far more often than min-max ones did (both legs of a pair can rank two
51
62
  * candidates identically), and the previous order was Map-insertion order.
52
63
  */
53
- export declare function fuse(paths: FusionPath[], topK: number): Hit[];
64
+ export declare function fuse(paths: FusionPath[], topK: number, opts?: {
65
+ includeLegs?: boolean;
66
+ }): Hit[];
@@ -1,14 +1,12 @@
1
1
  export * from './interfaces.js';
2
+ export * from './representation.js';
2
3
  export * from './log.js';
3
4
  export * from './stats.js';
4
5
  export * from './text_budget.js';
5
6
  export * from './budget.js';
6
7
  export * from './registry.js';
7
8
  export * from './fusion.js';
8
- export * from './rerank.js';
9
9
  export * from './adapters/local_numpy.js';
10
10
  export * from './adapters/hnswlib.js';
11
11
  export * from './adapters/auto_vstore.js';
12
- export * from './adapters/none_reranker.js';
13
12
  export * from './adapters/local_bge.js';
14
- export * from './adapters/local_reranker.js';
@@ -1,8 +1,38 @@
1
1
  /**
2
- * The three stable contracts the business flow depends on.
2
+ * The two stable contracts the business flow depends on.
3
3
  * The business flow (fusion pipeline, stores, tools, router, UI) must depend only on
4
4
  * these interfaces — never on a concrete backend. See DESIGN §5.
5
5
  */
6
+ /**
7
+ * HOW a backend turns text into a vector — the knobs that decide which coordinates a stored vector
8
+ * lives in, beyond `name`/`dim`.
9
+ *
10
+ * The vector-space identity used to record only `backend/model/dim`, so a change of pooling,
11
+ * normalization, input window or the weights behind the same repo name produced the SAME identity:
12
+ * new vectors were written into an index that still held the old ones and nothing detected the
13
+ * migration (see `db/vectors.ts` and DESIGN §20). A backend that can name these knobs declares them
14
+ * here and the space id carries them (see `representationKey`).
15
+ */
16
+ export interface SemanticRepresentation {
17
+ /** Pooling strategy handed to the feature-extraction pipeline (`mean`, `cls`, …). */
18
+ readonly pooling: string;
19
+ /** Whether vectors are L2-normalized by the pipeline (cosine relies on it). */
20
+ readonly normalize: boolean;
21
+ /**
22
+ * The CONFIGURED input-token cap (`0` = auto/declared window), i.e. the truncation window the
23
+ * adapter bounds text to before encoding. The CONFIGURED value, not the resolved one: the
24
+ * resolved window depends on the loaded tokenizer, so it is unknown before warmup — and the
25
+ * fingerprint must be identical before and after warmup, or a store would declare its own rows
26
+ * stale the moment the model finished loading.
27
+ */
28
+ readonly maxInputTokens: number;
29
+ /**
30
+ * Content identity of the model files (the family sidecar's revision sha), when one could be
31
+ * read. Absent = "could not be read" (not "known to be empty"): the fingerprint then omits it,
32
+ * which is the documented degradation, never an error.
33
+ */
34
+ readonly revision?: string;
35
+ }
6
36
  /** Encodes text into a normalized embedding vector. */
7
37
  export interface SemanticBackend {
8
38
  readonly name: string;
@@ -10,6 +40,13 @@ export interface SemanticBackend {
10
40
  encode(text: string): Promise<Float32Array>;
11
41
  encodeBatch(texts: string[]): Promise<Float32Array[]>;
12
42
  isAvailable(): boolean;
43
+ /**
44
+ * Optional declaration of the representation knobs this backend applies. The built-in
45
+ * `local_bge` declares them; a third-party backend that omits this is fingerprinted as
46
+ * `rep=undeclared` (the space id still changes with name/dim), which is honest rather than a
47
+ * silent claim to a representation nobody verified.
48
+ */
49
+ representation?(): SemanticRepresentation;
13
50
  /** Optional async bootstrap: configure env + download/load the model. */
14
51
  warmUp?(): Promise<void>;
15
52
  /**
@@ -20,19 +57,6 @@ export interface SemanticBackend {
20
57
  */
21
58
  ensureWarm?(): void;
22
59
  }
23
- /** Re-ranks candidate facts/chunks by query relevance. */
24
- export interface Reranker {
25
- readonly name: string;
26
- rerank(query: string, candidates: {
27
- id: number;
28
- text: string;
29
- }[]): Promise<number[]>;
30
- isAvailable(): boolean;
31
- /** Optional async bootstrap: configure env + download/load the model. */
32
- warmUp?(): Promise<void>;
33
- /** Optional non-blocking retry — see {@link SemanticBackend.ensureWarm}. */
34
- ensureWarm?(): void;
35
- }
36
60
  /** Distance/ann index over entry vectors (per-store instance). */
37
61
  export interface VectorStore {
38
62
  readonly name: string;
@@ -1,5 +1,5 @@
1
1
  import type { Config } from '../mem-contract/index.js';
2
- import type { Reranker, SemanticBackend, VectorStore } from './interfaces.js';
2
+ import type { SemanticBackend, VectorStore } from './interfaces.js';
3
3
  type Factory<T> = (cfg: Config, opts?: ResolveOptions) => T;
4
4
  /**
5
5
  * How a backend is resolved.
@@ -8,16 +8,14 @@ type Factory<T> = (cfg: Config, opts?: ResolveOptions) => T;
8
8
  * family framework installs the model into the managed root ASYNCHRONOUSLY, so a constructor-time
9
9
  * warm would race that install and fetch a second copy. The plugin passes `deferWarm: true` and
10
10
  * warms from the model item's `onSettled`; every other caller (CLI, MCP, tests) keeps the eager
11
- * constructor warm. `encode()` / `rerank()` still warm lazily, so deferring never loses the model.
11
+ * constructor warm. `encode()` still warms lazily, so deferring never loses the model.
12
12
  */
13
13
  export interface ResolveOptions {
14
14
  /** Skip the constructor warm; the caller warms explicitly (see `ModelEnv.deferWarm`). */
15
15
  readonly deferWarm?: boolean;
16
16
  }
17
17
  export declare function registerSemanticBackend(name: string, factory: Factory<SemanticBackend>): void;
18
- export declare function registerReranker(name: string, factory: Factory<Reranker>): void;
19
18
  export declare function registerVectorStore(name: string, factory: Factory<VectorStore>): void;
20
19
  export declare function resolveSemantic(cfg: Config, opts?: ResolveOptions): SemanticBackend;
21
- export declare function resolveReranker(cfg: Config, opts?: ResolveOptions): Reranker;
22
20
  export declare function resolveVStore(cfg: Config): VectorStore;
23
21
  export {};
@@ -0,0 +1,50 @@
1
+ import type { SemanticBackend, SemanticRepresentation } from './interfaces.js';
2
+ /** The declared representation of a backend that does not implement `representation()`. */
3
+ export declare const UNDECLARED_REPRESENTATION = "rep=undeclared";
4
+ /** What {@link readModelRevision} found (or why it found nothing). */
5
+ export interface ModelRevisionRead {
6
+ /** The model's content identity when the sidecar recorded one. */
7
+ readonly revision?: string;
8
+ /** Where it was looked for (the degradation warning names it). */
9
+ readonly path: string;
10
+ /** Why the revision is absent — short, for the one-line degradation warning. */
11
+ readonly detail: string;
12
+ }
13
+ /**
14
+ * Normalized, stable representation key embedded in a vector-space id.
15
+ *
16
+ * Field order is fixed and each value is normalized (lowercased pooling, 1/0 normalize, a
17
+ * truncated non-negative integer window), so two runs that describe the SAME representation always
18
+ * produce the SAME key — a fingerprint that changed spuriously would re-encode a whole corpus for
19
+ * nothing. A blank/absent revision is OMITTED rather than encoded as a placeholder: "unknown" then
20
+ * looks different from any known revision, which is the honest reading (the weights could have
21
+ * changed without this process being able to tell).
22
+ */
23
+ export declare function representationKey(rep: SemanticRepresentation): string;
24
+ /** {@link representationKey} for a live backend, or the explicit "undeclared" marker. */
25
+ export declare function representationKeyOf(backend: SemanticBackend): string;
26
+ /** The sidecar path for `model` under `cacheDir`, mirroring the base's flat-layout naming
27
+ * (`models--<owner>--<name>`), which is why a slash in the repo id becomes `--`.
28
+ */
29
+ export declare function modelRecordPath(cacheDir: string, model: string): string;
30
+ /**
31
+ * Whether the model's weights are actually on disk in the flat layout the adapter reads
32
+ * (`<cacheDir>/<repo>/config.json`).
33
+ *
34
+ * Only used to decide whether a missing revision is worth a WARNING: a machine that has never
35
+ * installed the model (a fresh install still in flight) has nothing to fingerprint yet, so the
36
+ * degradation is real but not yet reportable — warning there would be noise on every first run.
37
+ * Once the weights are present and the sidecar still is not, "no revision" is a genuine blind spot.
38
+ */
39
+ export declare function modelFilesPresent(cacheDir: string, model: string): boolean;
40
+ /**
41
+ * Read the family sidecar's revision for `model`, never throwing.
42
+ *
43
+ * Absence is a legitimate state (a model fetched by transformers.js directly, a machine that never
44
+ * ran the family provisioner, an install still in flight), not an error: the caller reports the
45
+ * degradation once and the fingerprint simply omits the revision.
46
+ *
47
+ * @param cacheDir - the model cache root the adapter actually reads (`semantic.cache_dir`).
48
+ * @param model - the repo id (`Xenova/bge-base-zh-v1.5`).
49
+ */
50
+ export declare function readModelRevision(cacheDir: string, model: string): ModelRevisionRead;
@@ -21,8 +21,6 @@ export interface RetrievalEvent {
21
21
  results: number;
22
22
  latencyMs: number;
23
23
  semanticLive: boolean;
24
- rerankUsed?: boolean;
25
- rerankFallback?: boolean;
26
24
  /**
27
25
  * Per-leg candidates removed by the relevance floors before fusion. The per-leg shape is what
28
26
  * makes an empty result readable ("the FTS floor cut 7 rows" vs "no leg had a candidate"); the
@@ -32,7 +30,7 @@ export interface RetrievalEvent {
32
30
  }
33
31
  /** Record one completed retrieval. */
34
32
  export declare function recordRetrieval(event: RetrievalEvent): void;
35
- export type TruncationKind = 'embedding' | 'rerank' | 'output';
33
+ export type TruncationKind = 'embedding' | 'output';
36
34
  /**
37
35
  * Record that a retrieval LEG returned exactly its cap, i.e. that its tail was dropped.
38
36
  *