@windagency/valora-plugin-memory-vault 1.0.0

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.

Potentially problematic release.


This version of @windagency/valora-plugin-memory-vault might be problematic. Click here for more details.

Files changed (94) hide show
  1. package/dist/config-schema.d.ts +134 -0
  2. package/dist/config-schema.d.ts.map +1 -0
  3. package/dist/config-schema.js +61 -0
  4. package/dist/config-schema.js.map +1 -0
  5. package/dist/consolidation/cluster.d.ts +17 -0
  6. package/dist/consolidation/cluster.d.ts.map +1 -0
  7. package/dist/consolidation/cluster.js +59 -0
  8. package/dist/consolidation/cluster.js.map +1 -0
  9. package/dist/consolidation-service.d.ts +75 -0
  10. package/dist/consolidation-service.d.ts.map +1 -0
  11. package/dist/consolidation-service.js +373 -0
  12. package/dist/consolidation-service.js.map +1 -0
  13. package/dist/constants.d.ts +30 -0
  14. package/dist/constants.d.ts.map +1 -0
  15. package/dist/constants.js +30 -0
  16. package/dist/constants.js.map +1 -0
  17. package/dist/decay.d.ts +51 -0
  18. package/dist/decay.d.ts.map +1 -0
  19. package/dist/decay.js +59 -0
  20. package/dist/decay.js.map +1 -0
  21. package/dist/embeddings/embedder.port.d.ts +9 -0
  22. package/dist/embeddings/embedder.port.d.ts.map +1 -0
  23. package/dist/embeddings/embedder.port.js +2 -0
  24. package/dist/embeddings/embedder.port.js.map +1 -0
  25. package/dist/embeddings/llm-provider-embedder.d.ts +26 -0
  26. package/dist/embeddings/llm-provider-embedder.d.ts.map +1 -0
  27. package/dist/embeddings/llm-provider-embedder.js +34 -0
  28. package/dist/embeddings/llm-provider-embedder.js.map +1 -0
  29. package/dist/embeddings/resolve-embedder.d.ts +27 -0
  30. package/dist/embeddings/resolve-embedder.d.ts.map +1 -0
  31. package/dist/embeddings/resolve-embedder.js +38 -0
  32. package/dist/embeddings/resolve-embedder.js.map +1 -0
  33. package/dist/embeddings/vector-store.d.ts +35 -0
  34. package/dist/embeddings/vector-store.d.ts.map +1 -0
  35. package/dist/embeddings/vector-store.js +174 -0
  36. package/dist/embeddings/vector-store.js.map +1 -0
  37. package/dist/extraction-service.d.ts +33 -0
  38. package/dist/extraction-service.d.ts.map +1 -0
  39. package/dist/extraction-service.js +168 -0
  40. package/dist/extraction-service.js.map +1 -0
  41. package/dist/index.d.ts +42 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +6498 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/manager.d.ts +62 -0
  46. package/dist/manager.d.ts.map +1 -0
  47. package/dist/manager.js +377 -0
  48. package/dist/manager.js.map +1 -0
  49. package/dist/migration/auto-migrate.d.ts +20 -0
  50. package/dist/migration/auto-migrate.d.ts.map +1 -0
  51. package/dist/migration/auto-migrate.js +49 -0
  52. package/dist/migration/auto-migrate.js.map +1 -0
  53. package/dist/migration/json-to-vault.d.ts +10 -0
  54. package/dist/migration/json-to-vault.d.ts.map +1 -0
  55. package/dist/migration/json-to-vault.js +88 -0
  56. package/dist/migration/json-to-vault.js.map +1 -0
  57. package/dist/migration/vault-version.d.ts +4 -0
  58. package/dist/migration/vault-version.d.ts.map +1 -0
  59. package/dist/migration/vault-version.js +19 -0
  60. package/dist/migration/vault-version.js.map +1 -0
  61. package/dist/retrieval/cosine-ann.d.ts +13 -0
  62. package/dist/retrieval/cosine-ann.d.ts.map +1 -0
  63. package/dist/retrieval/cosine-ann.js +26 -0
  64. package/dist/retrieval/cosine-ann.js.map +1 -0
  65. package/dist/retrieval/spreading-activation.d.ts +12 -0
  66. package/dist/retrieval/spreading-activation.d.ts.map +1 -0
  67. package/dist/retrieval/spreading-activation.js +70 -0
  68. package/dist/retrieval/spreading-activation.js.map +1 -0
  69. package/dist/store.d.ts +38 -0
  70. package/dist/store.d.ts.map +1 -0
  71. package/dist/store.js +192 -0
  72. package/dist/store.js.map +1 -0
  73. package/dist/vault/default-vault-dir.d.ts +17 -0
  74. package/dist/vault/default-vault-dir.d.ts.map +1 -0
  75. package/dist/vault/default-vault-dir.js +23 -0
  76. package/dist/vault/default-vault-dir.js.map +1 -0
  77. package/dist/vault/file-format.d.ts +44 -0
  78. package/dist/vault/file-format.d.ts.map +1 -0
  79. package/dist/vault/file-format.js +214 -0
  80. package/dist/vault/file-format.js.map +1 -0
  81. package/dist/vault/vault-index.d.ts +28 -0
  82. package/dist/vault/vault-index.d.ts.map +1 -0
  83. package/dist/vault/vault-index.js +98 -0
  84. package/dist/vault/vault-index.js.map +1 -0
  85. package/dist/vault/vault-store.d.ts +75 -0
  86. package/dist/vault/vault-store.d.ts.map +1 -0
  87. package/dist/vault/vault-store.js +369 -0
  88. package/dist/vault/vault-store.js.map +1 -0
  89. package/dist/vault-memory-provider.d.ts +53 -0
  90. package/dist/vault-memory-provider.d.ts.map +1 -0
  91. package/dist/vault-memory-provider.js +139 -0
  92. package/dist/vault-memory-provider.js.map +1 -0
  93. package/package.json +58 -0
  94. package/valora-plugin.json +10 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,MAAM,CAAC,MAAM,gBAAgB,GAA6B;IACzD,YAAY,EAAE,CAAC,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,CAAC;IACrF,WAAW,EAAE,oFAAoF;IACjG,KAAK,EAAE,cAAc;CACrB,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,GAAc;IACtC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,CAAC,CAAC;AACrE,CAAC;AAED,2FAA2F;AAC3F,oEAAoE;AAEpE,OAAO,EAAE,sBAAsB,EAAE,0BAA0B,EAA0B,MAAM,oBAAoB,CAAC;AAEhH,OAAO,EAGN,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEpF,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AACvG,OAAO,EAAuB,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxF,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAoB,MAAM,8BAA8B,CAAC;AACtG,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC9G,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAA+C,MAAM,8BAA8B,CAAC;AAE/G,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEzG,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,uFAAuF;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACpF,OAAO,EACN,kBAAkB,EAElB,eAAe,EACf,mBAAmB,EACnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,cAAc,EAAmB,UAAU,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Memory Manager — CRUD, decay computation, queries, and retrieval strengthening.
3
+ *
4
+ * Provides the public API for the memory system. All reads compute decay on
5
+ * the fly; retrievals strengthen entries by extending their half-life.
6
+ */
7
+ import type {
8
+ MemoryCategory,
9
+ MemoryCreateOptions,
10
+ MemoryEntry,
11
+ MemoryQueryOptions,
12
+ MemoryQueryResult,
13
+ MemoryRetentionConfig,
14
+ MemoryStorePort,
15
+ PurgeCriteria,
16
+ PurgeResult
17
+ } from '@windagency/valora-plugin-api';
18
+ import type { EmbedderPort } from './embeddings/embedder.port.js';
19
+ import type { MemoryStore } from './store.js';
20
+ export type { PurgeCriteria, PurgeResult };
21
+ export declare class MemoryManager {
22
+ private readonly config;
23
+ private embedder?;
24
+ private readonly store;
25
+ constructor(store: MemoryStore | MemoryStorePort, config?: Partial<MemoryRetentionConfig>, embedder?: EmbedderPort);
26
+ create(category: MemoryCategory, options: MemoryCreateOptions): Promise<MemoryEntry>;
27
+ delete(category: MemoryCategory, id: string): Promise<boolean>;
28
+ findByPaths(paths: string[]): Promise<MemoryQueryResult[]>;
29
+ flush(): Promise<void>;
30
+ get(category: MemoryCategory, id: string, strengthen?: boolean): Promise<MemoryQueryResult | null>;
31
+ invalidateByPaths(changedPaths: string[]): Promise<number>;
32
+ markStaleByPaths(paths: string[]): Promise<number>;
33
+ promote(episodicId: string, semanticContent: string, tags?: string[]): Promise<MemoryEntry>;
34
+ prune(): Promise<number>;
35
+ pruneCategory(category: MemoryCategory): Promise<number>;
36
+ purge(criteria: PurgeCriteria): Promise<PurgeResult>;
37
+ query(options: MemoryQueryOptions): Promise<MemoryQueryResult[]>;
38
+ /**
39
+ * Late-bind an embedder so consumers (e.g. the bundled provider) can
40
+ * resolve it asynchronously after construction. Calling with `undefined`
41
+ * clears it and reverts subsequent queries to lexical recall.
42
+ */
43
+ setEmbedder(embedder: EmbedderPort | undefined): void;
44
+ update(
45
+ category: MemoryCategory,
46
+ id: string,
47
+ patch: Partial<Pick<MemoryEntry, 'confidence' | 'content' | 'relatedPaths' | 'tags'>>
48
+ ): Promise<boolean>;
49
+ private collectPurgeIds;
50
+ private getDefaultHalfLife;
51
+ private incrementCoAccess;
52
+ private lexicalRecall;
53
+ private postProcess;
54
+ private recall;
55
+ /** Returns true when the entry has at least one of the requested paths (or no filter is set). */
56
+ private hasPathMatch;
57
+ /** Returns true when the entry has at least one tag from the filter list (or no filter is set). */
58
+ private hasTagMatch;
59
+ private matchesQueryOptions;
60
+ private strengthenEntry;
61
+ }
62
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACX,cAAc,EACd,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,aAAa,EACb,WAAW,EACX,MAAM,+BAA+B,CAAC;AAIvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAa9C,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC;AAI3C,qBAAa,aAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAC/C,OAAO,CAAC,QAAQ,CAAC,CAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;gBAE5B,KAAK,EAAE,WAAW,GAAG,eAAe,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,EAAE,QAAQ,CAAC,EAAE,YAAY;IAM5G,MAAM,CAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC;IAkDpF,MAAM,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9D,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAiB1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,GAAG,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,UAAO,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAgB/F,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAkB1D,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAiBlD,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IA0C3F,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAQxB,aAAa,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAexD,KAAK,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC;IA0BpD,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAQtE;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI;IAI/C,MAAM,CACX,QAAQ,EAAE,cAAc,EACxB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,GAAG,SAAS,GAAG,cAAc,GAAG,MAAM,CAAC,CAAC,GACnF,OAAO,CAAC,OAAO,CAAC;YAKL,eAAe;IAa7B,OAAO,CAAC,kBAAkB;YASZ,iBAAiB;YA8BjB,aAAa;YAeb,WAAW;YAOX,MAAM;IAYpB,iGAAiG;IACjG,OAAO,CAAC,YAAY;IAIpB,mGAAmG;IACnG,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,mBAAmB;YAUb,eAAe;CAgB7B"}
@@ -0,0 +1,377 @@
1
+ /**
2
+ * Memory Manager — CRUD, decay computation, queries, and retrieval strengthening.
3
+ *
4
+ * Provides the public API for the memory system. All reads compute decay on
5
+ * the fly; retrievals strengthen entries by extending their half-life.
6
+ */
7
+ import { generateMemoryId } from '@windagency/valora-runtime';
8
+ import {
9
+ DEFAULT_MEMORY_DECISION_HALF_LIFE_DAYS,
10
+ DEFAULT_MEMORY_EPISODIC_HALF_LIFE_DAYS,
11
+ DEFAULT_MEMORY_ERROR_HALF_LIFE_MULTIPLIER,
12
+ DEFAULT_MEMORY_PRUNE_THRESHOLD,
13
+ DEFAULT_MEMORY_RETRIEVAL_BOOST_DAYS,
14
+ DEFAULT_MEMORY_SEMANTIC_HALF_LIFE_DAYS,
15
+ MEMORY_HALF_LIFE_CAP_MULTIPLIER
16
+ } from './constants.js';
17
+ import { computeEffectiveHalfLife, computeStrength } from './decay.js';
18
+ const ALL_CATEGORIES = ['episodic', 'semantic', 'decisions'];
19
+ export class MemoryManager {
20
+ config;
21
+ embedder;
22
+ store;
23
+ constructor(store, config, embedder) {
24
+ this.store = store;
25
+ this.config = resolveConfig(config);
26
+ this.embedder = embedder;
27
+ }
28
+ async create(category, options) {
29
+ const id = generateMemoryId();
30
+ const now = new Date().toISOString();
31
+ const retrievalBoostDays = this.config.retrieval_boost_days ?? DEFAULT_MEMORY_RETRIEVAL_BOOST_DAYS;
32
+ const errorMultiplier = this.config.error_half_life_multiplier ?? DEFAULT_MEMORY_ERROR_HALF_LIFE_MULTIPLIER;
33
+ const defaultHalfLife = this.getDefaultHalfLife(category);
34
+ let halfLifeDays = computeEffectiveHalfLife(
35
+ defaultHalfLife,
36
+ 0,
37
+ options.isError ?? false,
38
+ retrievalBoostDays,
39
+ errorMultiplier
40
+ );
41
+ if (options.halfLifeDays !== undefined) {
42
+ halfLifeDays = options.halfLifeDays;
43
+ }
44
+ const entry = {
45
+ accessCount: 0,
46
+ agentRole: options.agentRole,
47
+ category,
48
+ confidence: options.confidence,
49
+ content: options.content,
50
+ createdAt: now,
51
+ halfLifeDays,
52
+ id,
53
+ isError: options.isError ?? false,
54
+ lastAccessedAt: now,
55
+ relatedPaths: options.relatedPaths ?? [],
56
+ sessionId: options.sessionId,
57
+ source: options.source,
58
+ tags: options.tags,
59
+ updatedAt: now
60
+ };
61
+ if (options.supersedes !== undefined) {
62
+ entry.supersedes = options.supersedes;
63
+ await this.store.updateEntry(category, options.supersedes, {
64
+ confidence: 'stale',
65
+ supersededBy: id
66
+ });
67
+ }
68
+ await this.store.appendEntry(category, entry);
69
+ return entry;
70
+ }
71
+ async delete(category, id) {
72
+ return this.store.removeEntry(category, id);
73
+ }
74
+ async findByPaths(paths) {
75
+ const results = [];
76
+ for (const category of ALL_CATEGORIES) {
77
+ const entries = await this.store.getEntries(category);
78
+ for (const entry of entries) {
79
+ const hasOverlap = paths.some((p) => entry.relatedPaths.includes(p));
80
+ if (hasOverlap) {
81
+ const strength = computeStrength(entry.createdAt, entry.halfLifeDays);
82
+ results.push({ entry, strength });
83
+ }
84
+ }
85
+ }
86
+ return results;
87
+ }
88
+ async flush() {
89
+ return this.store.flush();
90
+ }
91
+ async get(category, id, strengthen = true) {
92
+ const entries = await this.store.getEntries(category);
93
+ const entry = entries.find((e) => e.id === id);
94
+ if (entry === undefined) {
95
+ return null;
96
+ }
97
+ const strength = computeStrength(entry.createdAt, entry.halfLifeDays);
98
+ if (strengthen) {
99
+ await this.strengthenEntry(category, entry);
100
+ }
101
+ return { entry, strength };
102
+ }
103
+ async invalidateByPaths(changedPaths) {
104
+ let count = 0;
105
+ for (const category of ALL_CATEGORIES) {
106
+ const entries = await this.store.getEntries(category);
107
+ for (const entry of entries) {
108
+ const hasOverlap = changedPaths.some((p) => entry.relatedPaths.includes(p));
109
+ if (hasOverlap) {
110
+ const newHalfLife = Math.max(1, entry.halfLifeDays / 2);
111
+ await this.store.updateEntry(category, entry.id, { halfLifeDays: newHalfLife });
112
+ count++;
113
+ }
114
+ }
115
+ }
116
+ return count;
117
+ }
118
+ async markStaleByPaths(paths) {
119
+ let count = 0;
120
+ for (const category of ALL_CATEGORIES) {
121
+ const entries = await this.store.getEntries(category);
122
+ for (const entry of entries) {
123
+ const hasOverlap = paths.some((p) => entry.relatedPaths.includes(p));
124
+ if (hasOverlap) {
125
+ await this.store.updateEntry(category, entry.id, { confidence: 'stale' });
126
+ count++;
127
+ }
128
+ }
129
+ }
130
+ return count;
131
+ }
132
+ async promote(episodicId, semanticContent, tags) {
133
+ const entries = await this.store.getEntries('episodic');
134
+ const episodicEntry = entries.find((e) => e.id === episodicId);
135
+ if (episodicEntry === undefined) {
136
+ throw new Error(`Episodic entry not found: ${episodicId}`);
137
+ }
138
+ const mergedTags = tags !== undefined ? [...new Set([...episodicEntry.tags, ...tags])] : episodicEntry.tags;
139
+ const newEntry = await this.create('semantic', {
140
+ agentRole: episodicEntry.agentRole,
141
+ confidence: episodicEntry.confidence,
142
+ content: semanticContent,
143
+ relatedPaths: episodicEntry.relatedPaths,
144
+ sessionId: episodicEntry.sessionId,
145
+ source: episodicEntry.source,
146
+ tags: mergedTags
147
+ });
148
+ // Mark the source episodic stale and record the cross-category
149
+ // supersession. `create()` above only handles same-category cases.
150
+ await this.store.updateEntry('episodic', episodicId, {
151
+ confidence: 'stale',
152
+ supersededBy: newEntry.id
153
+ });
154
+ // Persist the supersedes wikilink/edge via the port. Backends with
155
+ // graph support (vault) overwrite the entry's file with the new
156
+ // supersedes field set and store the outbound edge for audit traversal.
157
+ // Backends without graph support safely ignore the `links` argument;
158
+ // the `appendEntry` contract is idempotent on entry id, so the second
159
+ // call replaces the first instead of duplicating. The supersedes edge
160
+ // is one-way authorial intent and is intentionally not traversed by
161
+ // spreading activation (see TRAVERSAL_KINDS in retrieval/spreading-activation.ts).
162
+ const supersededEntry = { ...newEntry, supersedes: episodicId };
163
+ await this.store.appendEntry('semantic', supersededEntry, [
164
+ { fromId: newEntry.id, kind: 'supersedes', toId: episodicId }
165
+ ]);
166
+ return supersededEntry;
167
+ }
168
+ async prune() {
169
+ let total = 0;
170
+ for (const category of ALL_CATEGORIES) {
171
+ total += await this.pruneCategory(category);
172
+ }
173
+ return total;
174
+ }
175
+ async pruneCategory(category) {
176
+ const pruneThreshold = this.config.prune_threshold ?? DEFAULT_MEMORY_PRUNE_THRESHOLD;
177
+ const entries = await this.store.getEntries(category);
178
+ const idsToRemove = new Set();
179
+ for (const entry of entries) {
180
+ const strength = computeStrength(entry.createdAt, entry.halfLifeDays);
181
+ if (strength < pruneThreshold) {
182
+ idsToRemove.add(entry.id);
183
+ }
184
+ }
185
+ return this.store.removeEntries(category, idsToRemove);
186
+ }
187
+ async purge(criteria) {
188
+ const { all, categories, dryRun, olderThanMs } = criteria;
189
+ if (all !== true && categories === undefined && olderThanMs === undefined) {
190
+ throw new Error(
191
+ 'purge requires explicit criteria: pass `all: true`, supply a `categories` array, or set `olderThanMs` to avoid accidentally deleting every memory.'
192
+ );
193
+ }
194
+ const targetCategories = all === true ? [...ALL_CATEGORIES] : (categories ?? [...ALL_CATEGORIES]);
195
+ let totalDeleted = 0;
196
+ let totalWouldDelete = 0;
197
+ for (const category of targetCategories) {
198
+ const idsToRemove = await this.collectPurgeIds(category, olderThanMs);
199
+ if (dryRun) {
200
+ totalWouldDelete += idsToRemove.size;
201
+ } else {
202
+ totalDeleted += await this.store.removeEntries(category, idsToRemove);
203
+ }
204
+ }
205
+ return { dryRun: dryRun ?? false, totalDeleted, totalWouldDelete };
206
+ }
207
+ async query(options) {
208
+ const limit = options.limit ?? 50;
209
+ const recalled = await this.recall(options, limit);
210
+ const results = applyTokenBudget(recalled, options.tokenBudget);
211
+ await this.postProcess(results, options);
212
+ return results;
213
+ }
214
+ /**
215
+ * Late-bind an embedder so consumers (e.g. the bundled provider) can
216
+ * resolve it asynchronously after construction. Calling with `undefined`
217
+ * clears it and reverts subsequent queries to lexical recall.
218
+ */
219
+ setEmbedder(embedder) {
220
+ this.embedder = embedder;
221
+ }
222
+ async update(category, id, patch) {
223
+ const now = new Date().toISOString();
224
+ return this.store.updateEntry(category, id, { ...patch, updatedAt: now });
225
+ }
226
+ async collectPurgeIds(category, olderThanMs) {
227
+ const entries = await this.store.getEntries(category);
228
+ const ids = new Set();
229
+ for (const entry of entries) {
230
+ if (olderThanMs !== undefined) {
231
+ const ageMs = Date.now() - new Date(entry.createdAt).getTime();
232
+ if (ageMs < olderThanMs) continue;
233
+ }
234
+ ids.add(entry.id);
235
+ }
236
+ return ids;
237
+ }
238
+ getDefaultHalfLife(category) {
239
+ const lookup = {
240
+ decisions: this.config.decision_half_life_days ?? DEFAULT_MEMORY_DECISION_HALF_LIFE_DAYS,
241
+ episodic: this.config.episodic_half_life_days ?? DEFAULT_MEMORY_EPISODIC_HALF_LIFE_DAYS,
242
+ semantic: this.config.semantic_half_life_days ?? DEFAULT_MEMORY_SEMANTIC_HALF_LIFE_DAYS
243
+ };
244
+ return lookup[category];
245
+ }
246
+ async incrementCoAccess(results) {
247
+ if (results.length < 2) return;
248
+ // Accumulate per-entry deltas in a single in-memory pass. The pair loop
249
+ // is still O(N²) but every disk write is deferred so we end up with at
250
+ // most one write per affected entry (O(N), not O(N²)). Batching also
251
+ // closes the lost-update window where the read-modify-write loop holds
252
+ // stale entry references after the underlying store has rewritten the
253
+ // record.
254
+ const deltas = new Map();
255
+ for (let i = 0; i < results.length; i++) {
256
+ for (let j = i + 1; j < results.length; j++) {
257
+ const a = results[i].entry;
258
+ const b = results[j].entry;
259
+ bumpDelta(deltas, a.id, b.id);
260
+ bumpDelta(deltas, b.id, a.id);
261
+ }
262
+ }
263
+ for (const result of results) {
264
+ const delta = deltas.get(result.entry.id);
265
+ if (!delta) continue;
266
+ const merged = { ...result.entry.coAccess };
267
+ for (const [peerId, count] of Object.entries(delta)) {
268
+ merged[peerId] = (merged[peerId] ?? 0) + count;
269
+ }
270
+ await this.store.updateEntry(result.entry.category, result.entry.id, { coAccess: merged });
271
+ }
272
+ }
273
+ async lexicalRecall(options, limit) {
274
+ const categories = options.category !== undefined ? [options.category] : ALL_CATEGORIES;
275
+ const allResults = [];
276
+ for (const category of categories) {
277
+ // Clone the array so callers cannot mutate the store's internal cache.
278
+ const entries = [...(await this.store.getEntries(category))];
279
+ for (const entry of entries) {
280
+ const strength = computeStrength(entry.createdAt, entry.halfLifeDays);
281
+ if (this.matchesQueryOptions(entry, options, strength)) allResults.push({ entry, strength });
282
+ }
283
+ }
284
+ allResults.sort((a, b) => b.strength - a.strength);
285
+ return allResults.slice(0, limit);
286
+ }
287
+ async postProcess(results, options) {
288
+ if (options.strengthen !== false) {
289
+ for (const result of results) await this.strengthenEntry(result.entry.category, result.entry);
290
+ }
291
+ await this.incrementCoAccess(results);
292
+ }
293
+ async recall(options, limit) {
294
+ // Dispatch via the port: backends that advertise `semanticRecall`
295
+ // (e.g. vault) own the embedding-driven graph traversal; backends
296
+ // that do not fall through to lexical retrieval. A null return from
297
+ // semanticRecall signals "no usable seeds — fall back to lexical".
298
+ if (options.text && this.embedder && this.store.semanticRecall) {
299
+ const semantic = await this.store.semanticRecall(options, limit, this.embedder, this.config.recall);
300
+ if (semantic !== null) return semantic;
301
+ }
302
+ return this.lexicalRecall(options, limit);
303
+ }
304
+ /** Returns true when the entry has at least one of the requested paths (or no filter is set). */
305
+ hasPathMatch(entry, paths) {
306
+ return paths === undefined || paths.length === 0 || paths.some((p) => entry.relatedPaths.includes(p));
307
+ }
308
+ /** Returns true when the entry has at least one tag from the filter list (or no filter is set). */
309
+ hasTagMatch(entry, tags) {
310
+ return tags === undefined || tags.length === 0 || tags.some((t) => entry.tags.includes(t));
311
+ }
312
+ matchesQueryOptions(entry, options, strength) {
313
+ if (entry.confidence === 'stale') return false;
314
+ const minStrength = options.minStrength ?? DEFAULT_MEMORY_PRUNE_THRESHOLD;
315
+ if (strength < minStrength) return false;
316
+ if (!this.hasTagMatch(entry, options.tags)) return false;
317
+ if (!this.hasPathMatch(entry, options.paths)) return false;
318
+ if (options.agentRole !== undefined && entry.agentRole !== options.agentRole) return false;
319
+ return true;
320
+ }
321
+ async strengthenEntry(category, entry) {
322
+ const retrievalBoostDays = this.config.retrieval_boost_days ?? DEFAULT_MEMORY_RETRIEVAL_BOOST_DAYS;
323
+ const cap = this.getDefaultHalfLife(category) * MEMORY_HALF_LIFE_CAP_MULTIPLIER;
324
+ const accessCount = entry.accessCount + 1;
325
+ // Heavily-queried memories would otherwise grow their half-life
326
+ // without bound — capping at MULT × the category default keeps decay
327
+ // meaningful even for hot entries.
328
+ const halfLifeDays = Math.min(cap, entry.halfLifeDays + retrievalBoostDays);
329
+ const lastAccessedAt = new Date().toISOString();
330
+ entry.accessCount = accessCount;
331
+ entry.halfLifeDays = halfLifeDays;
332
+ entry.lastAccessedAt = lastAccessedAt;
333
+ await this.store.updateEntry(category, entry.id, { accessCount, halfLifeDays, lastAccessedAt });
334
+ }
335
+ }
336
+ const TOKEN_ESTIMATE_CHARS = 4;
337
+ /**
338
+ * Truncate `results` so the cumulative content size fits within `tokenBudget`.
339
+ * Returns the input unchanged when no budget is set (tokenBudget undefined or
340
+ * non-positive). Estimation uses ~4 characters per token, matching the
341
+ * convention in `memory-formatter.ts` so both layers agree on the cost model.
342
+ */
343
+ function applyTokenBudget(results, tokenBudget) {
344
+ if (tokenBudget === undefined || tokenBudget <= 0) return results;
345
+ const charBudget = tokenBudget * TOKEN_ESTIMATE_CHARS;
346
+ const fitted = [];
347
+ let used = 0;
348
+ for (const result of results) {
349
+ const cost = result.entry.content.length;
350
+ if (used + cost > charBudget && fitted.length > 0) break; // always include at least one
351
+ used += cost;
352
+ fitted.push(result);
353
+ }
354
+ return fitted;
355
+ }
356
+ function bumpDelta(deltas, fromId, toId) {
357
+ const existing = deltas.get(fromId) ?? {};
358
+ existing[toId] = (existing[toId] ?? 0) + 1;
359
+ deltas.set(fromId, existing);
360
+ }
361
+ function resolveConfig(config) {
362
+ const defaults = {
363
+ backend: 'vault',
364
+ decision_half_life_days: DEFAULT_MEMORY_DECISION_HALF_LIFE_DAYS,
365
+ enabled: true,
366
+ episodic_half_life_days: DEFAULT_MEMORY_EPISODIC_HALF_LIFE_DAYS,
367
+ error_half_life_multiplier: DEFAULT_MEMORY_ERROR_HALF_LIFE_MULTIPLIER,
368
+ injection_strength_threshold: 0.2,
369
+ injection_token_budget: 2000,
370
+ max_entries_per_store: 500,
371
+ prune_threshold: DEFAULT_MEMORY_PRUNE_THRESHOLD,
372
+ retrieval_boost_days: DEFAULT_MEMORY_RETRIEVAL_BOOST_DAYS,
373
+ semantic_half_life_days: DEFAULT_MEMORY_SEMANTIC_HALF_LIFE_DAYS
374
+ };
375
+ return config === undefined ? defaults : { ...defaults, ...config };
376
+ }
377
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type MigrationResult } from './json-to-vault.js';
2
+ /**
3
+ * Run the legacy JSON → vault migration if any legacy file is present and the
4
+ * vault has not yet been stamped with a schema version.
5
+ *
6
+ * The check is intentionally cheap (a few `existsSync` calls) so it can fire
7
+ * on every process boot without measurable overhead. The migration itself is
8
+ * idempotent — see `migrateJsonToVault`.
9
+ *
10
+ * Within a single process, each `vaultDir` is only checked once: subsequent
11
+ * calls become cache hits to keep per-stage hot paths free of stat syscalls.
12
+ *
13
+ * Returns:
14
+ * - The {@link MigrationResult} when a migration ran.
15
+ * - `null` when no legacy data was found and no migration was needed.
16
+ */
17
+ export declare function runAutoMigrationIfNeeded(jsonDir: string, vaultDir: string): MigrationResult | null;
18
+ /** For tests — drop the in-process cache so a re-run will recheck disk. */
19
+ export declare function resetAutoMigrationCache(): void;
20
+ //# sourceMappingURL=auto-migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-migrate.d.ts","sourceRoot":"","sources":["../../src/migration/auto-migrate.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAO9E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAoBlG;AAED,2EAA2E;AAC3E,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C"}
@@ -0,0 +1,49 @@
1
+ import { getLogger } from '@windagency/valora-runtime';
2
+ import { existsSync } from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { migrateJsonToVault } from './json-to-vault.js';
5
+ import { readVaultVersion } from './vault-version.js';
6
+ const LEGACY_FILES = ['episodic.json', 'semantic.json', 'decisions.json'];
7
+ const checked = new Set();
8
+ /**
9
+ * Run the legacy JSON → vault migration if any legacy file is present and the
10
+ * vault has not yet been stamped with a schema version.
11
+ *
12
+ * The check is intentionally cheap (a few `existsSync` calls) so it can fire
13
+ * on every process boot without measurable overhead. The migration itself is
14
+ * idempotent — see `migrateJsonToVault`.
15
+ *
16
+ * Within a single process, each `vaultDir` is only checked once: subsequent
17
+ * calls become cache hits to keep per-stage hot paths free of stat syscalls.
18
+ *
19
+ * Returns:
20
+ * - The {@link MigrationResult} when a migration ran.
21
+ * - `null` when no legacy data was found and no migration was needed.
22
+ */
23
+ export function runAutoMigrationIfNeeded(jsonDir, vaultDir) {
24
+ const key = `${path.resolve(jsonDir)}::${path.resolve(vaultDir)}`;
25
+ if (checked.has(key)) return null;
26
+ if (!hasLegacyFiles(jsonDir)) {
27
+ checked.add(key);
28
+ return null;
29
+ }
30
+ if (readVaultVersion(vaultDir) !== null) {
31
+ // Vault already stamped — assume earlier migration already handled the data.
32
+ checked.add(key);
33
+ return null;
34
+ }
35
+ getLogger().warn('Legacy JSON memory detected — auto-migrating to vault.');
36
+ const result = migrateJsonToVault({ jsonDir, vaultDir });
37
+ // Cache only after a successful migration so a thrown attempt can be
38
+ // retried on the next call instead of being silently swallowed by the cache.
39
+ checked.add(key);
40
+ return result;
41
+ }
42
+ /** For tests — drop the in-process cache so a re-run will recheck disk. */
43
+ export function resetAutoMigrationCache() {
44
+ checked.clear();
45
+ }
46
+ function hasLegacyFiles(jsonDir) {
47
+ return LEGACY_FILES.some((name) => existsSync(path.join(jsonDir, name)));
48
+ }
49
+ //# sourceMappingURL=auto-migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-migrate.js","sourceRoot":"","sources":["../../src/migration/auto-migrate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,kBAAkB,EAAwB,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,YAAY,GAAG,CAAC,eAAe,EAAE,eAAe,EAAE,gBAAgB,CAAC,CAAC;AAE1E,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;AAElC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAe,EAAE,QAAgB;IACzE,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;IAClE,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAElC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IAAI,gBAAgB,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;QACzC,6EAA6E;QAC7E,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,SAAS,EAAE,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;IAC3E,MAAM,MAAM,GAAG,kBAAkB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IACzD,qEAAqE;IACrE,6EAA6E;IAC7E,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjB,OAAO,MAAM,CAAC;AACf,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,uBAAuB;IACtC,OAAO,CAAC,KAAK,EAAE,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,OAAe;IACtC,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface MigrationOptions {
2
+ jsonDir: string;
3
+ vaultDir: string;
4
+ }
5
+ export interface MigrationResult {
6
+ migrated: number;
7
+ skipped: number;
8
+ }
9
+ export declare function migrateJsonToVault(options: MigrationOptions): MigrationResult;
10
+ //# sourceMappingURL=json-to-vault.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-to-vault.d.ts","sourceRoot":"","sources":["../../src/migration/json-to-vault.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CAChB;AAyBD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAgC7E"}
@@ -0,0 +1,88 @@
1
+ import { getLogger } from '@windagency/valora-runtime';
2
+ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync } from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { atomicWriteFile, serialiseMemoryFile } from '../vault/file-format.js';
5
+ import { writeVaultVersion } from './vault-version.js';
6
+ const CATEGORIES = ['episodic', 'semantic', 'decisions'];
7
+ const LOCK_FILENAME = '.migration.lock';
8
+ export function migrateJsonToVault(options) {
9
+ const { jsonDir, vaultDir } = options;
10
+ mkdirSync(vaultDir, { recursive: true });
11
+ const lockPath = path.join(vaultDir, LOCK_FILENAME);
12
+ if (existsSync(lockPath)) {
13
+ throw new Error(
14
+ `Migration lock present at ${lockPath}. Another run is in progress, or a previous run crashed; remove the file and retry.`
15
+ );
16
+ }
17
+ atomicWriteFile(lockPath, new Date().toISOString());
18
+ try {
19
+ let migrated = 0;
20
+ let skipped = 0;
21
+ for (const category of CATEGORIES) {
22
+ const categoryResult = migrateCategory(jsonDir, vaultDir, category);
23
+ migrated += categoryResult.migrated;
24
+ skipped += categoryResult.skipped;
25
+ }
26
+ writeVaultVersion(vaultDir);
27
+ return { migrated, skipped };
28
+ } finally {
29
+ try {
30
+ rmSync(lockPath, { force: true });
31
+ } catch (err) {
32
+ getLogger().warn(`Migration: could not remove lock file ${lockPath}: ${String(err)}`);
33
+ }
34
+ }
35
+ }
36
+ function archiveSourceJson(jsonDir, jsonPath, category) {
37
+ if (!existsSync(jsonPath)) return;
38
+ try {
39
+ const legacyDir = path.join(jsonDir, '_legacy');
40
+ mkdirSync(legacyDir, { recursive: true });
41
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
42
+ renameSync(jsonPath, path.join(legacyDir, `${category}-${ts}.json`));
43
+ } catch (err) {
44
+ getLogger().warn(`Migration: could not archive ${category}.json: ${String(err)}`);
45
+ }
46
+ }
47
+ function buildEntryLinks(entry) {
48
+ const links = [];
49
+ if (entry.supersedes) {
50
+ links.push({ fromId: entry.id, kind: 'supersedes', toId: entry.supersedes });
51
+ }
52
+ return links;
53
+ }
54
+ function migrateCategory(jsonDir, vaultDir, category) {
55
+ const jsonPath = path.join(jsonDir, `${category}.json`);
56
+ const storeFile = readJsonStore(jsonPath);
57
+ if (storeFile === null) return { migrated: 0, skipped: 0 };
58
+ let migrated = 0;
59
+ let skipped = 0;
60
+ for (const entry of storeFile.entries) {
61
+ const result = migrateEntry(entry, vaultDir, category);
62
+ if (result === 'migrated') migrated++;
63
+ else skipped++;
64
+ }
65
+ archiveSourceJson(jsonDir, jsonPath, category);
66
+ return { migrated, skipped };
67
+ }
68
+ function migrateEntry(entry, vaultDir, category) {
69
+ const mdPath = path.join(vaultDir, category, `${entry.id}.md`);
70
+ if (existsSync(mdPath)) return 'skipped';
71
+ try {
72
+ const links = buildEntryLinks(entry);
73
+ atomicWriteFile(mdPath, serialiseMemoryFile(entry, links));
74
+ return 'migrated';
75
+ } catch (err) {
76
+ getLogger().warn(`Migration: skipping entry ${entry.id}: ${String(err)}`);
77
+ return 'skipped';
78
+ }
79
+ }
80
+ function readJsonStore(jsonPath) {
81
+ try {
82
+ const raw = readFileSync(jsonPath, 'utf-8');
83
+ return JSON.parse(raw);
84
+ } catch {
85
+ return null;
86
+ }
87
+ }
88
+ //# sourceMappingURL=json-to-vault.js.map