@plur-ai/core 0.8.2 → 0.9.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.
- package/dist/{chunk-GRDNBUIJ.js → chunk-3ZPTRZE3.js} +1 -1
- package/dist/{chunk-UETCDULF.js → chunk-MW5EPL7G.js} +35 -2
- package/dist/{chunk-MY4XVDCE.js → chunk-PRK3B7WR.js} +3 -2
- package/dist/embeddings-VXK2E2IF.js +14 -0
- package/dist/index.d.ts +67 -2
- package/dist/index.js +126 -22
- package/dist/{learn-async-VXBH3TYE.js → learn-async-UZAPPQK4.js} +2 -2
- package/package.json +1 -1
- package/dist/embeddings-EX7QPXJS.js +0 -12
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
atomicWrite
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-PRK3B7WR.js";
|
|
4
4
|
|
|
5
5
|
// src/fts.ts
|
|
6
6
|
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
@@ -183,6 +183,38 @@ async function embeddingSearch(engrams, query, limit, storagePath) {
|
|
|
183
183
|
similarities.sort((a, b) => b.score - a.score);
|
|
184
184
|
return similarities.slice(0, limit).map((s) => s.engram);
|
|
185
185
|
}
|
|
186
|
+
async function embeddingSearchWithScores(engrams, query, limit, storagePath) {
|
|
187
|
+
if (engrams.length === 0) return [];
|
|
188
|
+
const cachePath = storagePath ? join(storagePath, ".embeddings-cache.json") : ".embeddings-cache.json";
|
|
189
|
+
const cache = loadCache(cachePath);
|
|
190
|
+
const queryEmbedding = await embed(query);
|
|
191
|
+
if (!queryEmbedding) {
|
|
192
|
+
return [];
|
|
193
|
+
}
|
|
194
|
+
const similarities = [];
|
|
195
|
+
for (const engram of engrams) {
|
|
196
|
+
const searchText = engramSearchText(engram);
|
|
197
|
+
const hash = hashStatement(searchText);
|
|
198
|
+
let engramEmbedding;
|
|
199
|
+
if (cache[engram.id]?.hash === hash) {
|
|
200
|
+
engramEmbedding = new Float32Array(cache[engram.id].embedding);
|
|
201
|
+
} else {
|
|
202
|
+
const emb = await embed(searchText);
|
|
203
|
+
if (!emb) return [];
|
|
204
|
+
engramEmbedding = emb;
|
|
205
|
+
cache[engram.id] = {
|
|
206
|
+
hash,
|
|
207
|
+
embedding: Array.from(engramEmbedding)
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
const rawScore = cosineSimilarity(queryEmbedding, engramEmbedding);
|
|
211
|
+
const score = Math.max(0, Math.min(1, rawScore));
|
|
212
|
+
similarities.push({ engram, score });
|
|
213
|
+
}
|
|
214
|
+
saveCache(cachePath, cache);
|
|
215
|
+
similarities.sort((a, b) => b.score - a.score);
|
|
216
|
+
return similarities.slice(0, limit);
|
|
217
|
+
}
|
|
186
218
|
|
|
187
219
|
export {
|
|
188
220
|
ftsTokenize,
|
|
@@ -192,5 +224,6 @@ export {
|
|
|
192
224
|
searchEngrams,
|
|
193
225
|
embed,
|
|
194
226
|
cosineSimilarity,
|
|
195
|
-
embeddingSearch
|
|
227
|
+
embeddingSearch,
|
|
228
|
+
embeddingSearchWithScores
|
|
196
229
|
};
|
|
@@ -80,10 +80,11 @@ function hasConflictMarkers(root) {
|
|
|
80
80
|
return result !== null && result.length > 0;
|
|
81
81
|
}
|
|
82
82
|
function pullRebase(root) {
|
|
83
|
-
const
|
|
83
|
+
const branch = gitSafe(["rev-parse", "--abbrev-ref", "HEAD"], root) || "main";
|
|
84
|
+
const result = gitSafe(["pull", "--rebase", "origin", branch], root);
|
|
84
85
|
if (result !== null) return true;
|
|
85
86
|
gitSafe(["rebase", "--abort"], root);
|
|
86
|
-
const mergeResult = gitSafe(["pull", "origin",
|
|
87
|
+
const mergeResult = gitSafe(["pull", "origin", branch, "--no-edit"], root);
|
|
87
88
|
if (mergeResult !== null) return true;
|
|
88
89
|
if (hasConflictMarkers(root)) {
|
|
89
90
|
gitSafe(["merge", "--abort"], root);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cosineSimilarity,
|
|
3
|
+
embed,
|
|
4
|
+
embeddingSearch,
|
|
5
|
+
embeddingSearchWithScores
|
|
6
|
+
} from "./chunk-MW5EPL7G.js";
|
|
7
|
+
import "./chunk-PRK3B7WR.js";
|
|
8
|
+
import "./chunk-2ZDO52B4.js";
|
|
9
|
+
export {
|
|
10
|
+
cosineSimilarity,
|
|
11
|
+
embed,
|
|
12
|
+
embeddingSearch,
|
|
13
|
+
embeddingSearchWithScores
|
|
14
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
3
|
interface HistoryEvent {
|
|
4
|
-
event: 'engram_created' | 'engram_updated' | 'engram_merged' | 'feedback_received' | 'engram_retired' | 'engram_promoted' | 'failure_reported' | 'procedure_evolved';
|
|
4
|
+
event: 'engram_created' | 'engram_updated' | 'engram_merged' | 'feedback_received' | 'engram_retired' | 'engram_promoted' | 'failure_reported' | 'procedure_evolved' | 'recurrence_detected' | 'contradiction_detected' | 'scope_promoted' | 'buffer_pruned' | 'weekly_review';
|
|
5
5
|
engram_id: string;
|
|
6
6
|
timestamp: string;
|
|
7
7
|
data: Record<string, unknown>;
|
|
@@ -536,6 +536,43 @@ type KnowledgeAnchor = z.infer<typeof KnowledgeAnchorSchema>;
|
|
|
536
536
|
type Association = z.infer<typeof AssociationSchema>;
|
|
537
537
|
type PreviousVersionRef = z.infer<typeof PreviousVersionRefSchema>;
|
|
538
538
|
|
|
539
|
+
/** Map retrieval strength to a human-readable status label. */
|
|
540
|
+
declare function strengthToStatus(strength: number): string;
|
|
541
|
+
interface DecayTransition {
|
|
542
|
+
engram_id: string;
|
|
543
|
+
old_strength: number;
|
|
544
|
+
new_strength: number;
|
|
545
|
+
old_status: string;
|
|
546
|
+
new_status: string;
|
|
547
|
+
}
|
|
548
|
+
interface BatchDecayResult {
|
|
549
|
+
total: number;
|
|
550
|
+
decayed: number;
|
|
551
|
+
skipped: number;
|
|
552
|
+
transitions: DecayTransition[];
|
|
553
|
+
}
|
|
554
|
+
interface BatchDecayOptions {
|
|
555
|
+
contextScope?: string;
|
|
556
|
+
lambda?: number;
|
|
557
|
+
now?: Date;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Apply ACT-R decay to a batch of engrams.
|
|
561
|
+
* Scope-matched engrams are skipped (they never decay).
|
|
562
|
+
* Status transitions are logged to history.
|
|
563
|
+
* Returns the result summary and the list of engrams that were modified.
|
|
564
|
+
*/
|
|
565
|
+
declare function applyBatchDecay(engrams: Engram[], historyRoot: string, options?: BatchDecayOptions): {
|
|
566
|
+
result: BatchDecayResult;
|
|
567
|
+
modified: Engram[];
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
/** Result with cosine similarity score attached. */
|
|
571
|
+
interface SimilarityResult {
|
|
572
|
+
engram: Engram;
|
|
573
|
+
score: number;
|
|
574
|
+
}
|
|
575
|
+
|
|
539
576
|
declare const EpisodeSchema: z.ZodObject<{
|
|
540
577
|
id: z.ZodString;
|
|
541
578
|
summary: z.ZodString;
|
|
@@ -1850,6 +1887,18 @@ declare class Plur {
|
|
|
1850
1887
|
private _loadAllEngrams;
|
|
1851
1888
|
/** Load engrams from a path with mtime-based caching */
|
|
1852
1889
|
private _loadCached;
|
|
1890
|
+
/**
|
|
1891
|
+
* Write engrams to disk and invalidate the cache for that path.
|
|
1892
|
+
*
|
|
1893
|
+
* Why: `_loadCached` uses mtime-based invalidation, but on CI tmpfs
|
|
1894
|
+
* (ubuntu-latest runners) mtime resolution can be coarse enough that a
|
|
1895
|
+
* stat() taken before and after a write returns the same mtime. When that
|
|
1896
|
+
* happens the cache serves a pre-write snapshot and a subsequent `getById`
|
|
1897
|
+
* returns `undefined` for an engram that `learn()` just created. Explicit
|
|
1898
|
+
* invalidation on write removes the filesystem as a source of cache
|
|
1899
|
+
* freshness and closes the race. See issue #25.
|
|
1900
|
+
*/
|
|
1901
|
+
private _writeEngrams;
|
|
1853
1902
|
/** Find which store owns an engram by ID. For namespaced IDs, strips prefix to find in store. */
|
|
1854
1903
|
private _findEngramStore;
|
|
1855
1904
|
/** Content hash fast-path dedup. */
|
|
@@ -1886,6 +1935,12 @@ declare class Plur {
|
|
|
1886
1935
|
recallSemantic(query: string, options?: Omit<RecallOptions, 'mode' | 'llm'>): Promise<Engram[]>;
|
|
1887
1936
|
/** Hybrid search: BM25 + embeddings merged via Reciprocal Rank Fusion. Async, no API calls. */
|
|
1888
1937
|
recallHybrid(query: string, options?: Omit<RecallOptions, 'mode' | 'llm'>): Promise<Engram[]>;
|
|
1938
|
+
/** Embedding search returning {engram, score}[] with cosine similarity scores. Async, no API calls. */
|
|
1939
|
+
similaritySearch(query: string, options?: {
|
|
1940
|
+
limit?: number;
|
|
1941
|
+
scope?: string;
|
|
1942
|
+
domain?: string;
|
|
1943
|
+
}): Promise<SimilarityResult[]>;
|
|
1889
1944
|
/** Expanded search: LLM query expansion + hybrid search + RRF merge. Opt-in, requires LLM function. */
|
|
1890
1945
|
recallExpanded(query: string, options: RecallOptions & {
|
|
1891
1946
|
llm: LlmFunction;
|
|
@@ -1924,6 +1979,16 @@ declare class Plur {
|
|
|
1924
1979
|
removed: number;
|
|
1925
1980
|
remaining: number;
|
|
1926
1981
|
};
|
|
1982
|
+
/**
|
|
1983
|
+
* Apply ACT-R decay to all primary store engrams.
|
|
1984
|
+
* Scope-matched engrams are skipped, status transitions logged to history.
|
|
1985
|
+
* Modified engrams are saved back to the store.
|
|
1986
|
+
*/
|
|
1987
|
+
batchDecay(options?: {
|
|
1988
|
+
contextScope?: string;
|
|
1989
|
+
lambda?: number;
|
|
1990
|
+
now?: Date;
|
|
1991
|
+
}): BatchDecayResult;
|
|
1927
1992
|
/** Rebuild SQLite index from YAML source of truth. Only works when index: true. */
|
|
1928
1993
|
reindex(): void;
|
|
1929
1994
|
/** Sync SQLite index after YAML write (no-op if index disabled) */
|
|
@@ -1995,4 +2060,4 @@ declare class Plur {
|
|
|
1995
2060
|
}>;
|
|
1996
2061
|
}
|
|
1997
2062
|
|
|
1998
|
-
export { ALL_MIGRATIONS, type AlignmentResult, type Association, type AutoSearchResult, type BoundedRecallResult, COMMITMENT_MULTIPLIER, CURRENT_SCHEMA_VERSION, type CaptureContext, type DedupConfig, type DedupDecision, type DomainCoverage, DomainCoverageSchema, type Engram, type EngramCluster, type EngramStore, type Episode, type EvidenceEntry, EvidenceEntrySchema, type ExtractOptions, type ExtractionResult, type Falsification, FalsificationSchema, type HierarchyPosition, HierarchyPositionSchema, type HistoryEvent, IndexedStorage, type IngestCandidate, type IngestOptions, type InjectOptions, type InjectionLayer, type InjectionResult, type KnowledgeAnchor, type LearnAsyncContext, type LearnAsyncResult, type LearnBatchResult, type LearnContext, type LlmFunction, type LlmTierConfig, type MemberAlignment, type MetaConfidence, MetaConfidenceSchema, type MetaField, MetaFieldSchema, type Migration, type MigrationResult, type ModelTier, PLATITUDE_PATTERNS, type PackManifest, Plur, type PlurConfig, type PlurPaths, type PreviewResult, type PreviousVersionRef, type PrivacyIssue, type PrivacyScanResult, type ProfileCache, type RecallBudget, type RecallOptions, type RegistryEntry, type RelationalAnalysis, type RelationalTriple, type SearchStrategy, SessionBreadcrumbs, SqliteStore, type StatusResult, type StorageBackend, type StorageConfig, type StoreEntry, type StructuralTemplate, StructuralTemplateSchema, type SyncResult, type SyncStatus, type TimelineQuery, type TypedRole, type ValidationResult, type VersionCheckResult, YamlStore, alignCluster, analyzeStructure, appendHistory, assignLayer, asyncAtomicWrite, autoSummary, buildBatchDedupPrompt, buildDedupPrompt, checkForUpdate, classifyPolarity, clearVersionCache, clusterByStructure, computeConfidence, computeContentHash, computeMetaConfidence, confidenceBand, createStore, detectPlurStorage, detectSecrets, engramSearchText, extractMetaEngrams, formatLayer1, formatLayer2, formatLayer3, formatWithLayer, formulateMetaEngram, freshTailBoost, generateEventId, generateGuardrails, generateProfile, generateSummary, getCachedUpdateCheck, getProfileForInjection, getSchemaVersion, isPlatitude, listHistoryMonths, loadProfileCache, markProfileDirty, migrateStore, needsSummary, normalizeStatement, organizeHierarchy, parseDedupResponse, profileNeedsRegeneration, readHistory, readHistoryForEngram, recallAuto, resolveOperationTier, rollbackMigrations, runMigrations, saveProfileCache, selectModel, selectModelForOperation, setSchemaVersion, tokenSimilarity, validateMetaEngram, withAsyncLock };
|
|
2063
|
+
export { ALL_MIGRATIONS, type AlignmentResult, type Association, type AutoSearchResult, type BatchDecayOptions, type BatchDecayResult, type BoundedRecallResult, COMMITMENT_MULTIPLIER, CURRENT_SCHEMA_VERSION, type CaptureContext, type DecayTransition, type DedupConfig, type DedupDecision, type DomainCoverage, DomainCoverageSchema, type Engram, type EngramCluster, type EngramStore, type Episode, type EvidenceEntry, EvidenceEntrySchema, type ExtractOptions, type ExtractionResult, type Falsification, FalsificationSchema, type HierarchyPosition, HierarchyPositionSchema, type HistoryEvent, IndexedStorage, type IngestCandidate, type IngestOptions, type InjectOptions, type InjectionLayer, type InjectionResult, type KnowledgeAnchor, type LearnAsyncContext, type LearnAsyncResult, type LearnBatchResult, type LearnContext, type LlmFunction, type LlmTierConfig, type MemberAlignment, type MetaConfidence, MetaConfidenceSchema, type MetaField, MetaFieldSchema, type Migration, type MigrationResult, type ModelTier, PLATITUDE_PATTERNS, type PackManifest, Plur, type PlurConfig, type PlurPaths, type PreviewResult, type PreviousVersionRef, type PrivacyIssue, type PrivacyScanResult, type ProfileCache, type RecallBudget, type RecallOptions, type RegistryEntry, type RelationalAnalysis, type RelationalTriple, type SearchStrategy, SessionBreadcrumbs, type SimilarityResult, SqliteStore, type StatusResult, type StorageBackend, type StorageConfig, type StoreEntry, type StructuralTemplate, StructuralTemplateSchema, type SyncResult, type SyncStatus, type TimelineQuery, type TypedRole, type ValidationResult, type VersionCheckResult, YamlStore, alignCluster, analyzeStructure, appendHistory, applyBatchDecay, assignLayer, asyncAtomicWrite, autoSummary, buildBatchDedupPrompt, buildDedupPrompt, checkForUpdate, classifyPolarity, clearVersionCache, clusterByStructure, computeConfidence, computeContentHash, computeMetaConfidence, confidenceBand, createStore, detectPlurStorage, detectSecrets, engramSearchText, extractMetaEngrams, formatLayer1, formatLayer2, formatLayer3, formatWithLayer, formulateMetaEngram, freshTailBoost, generateEventId, generateGuardrails, generateProfile, generateSummary, getCachedUpdateCheck, getProfileForInjection, getSchemaVersion, isPlatitude, listHistoryMonths, loadProfileCache, markProfileDirty, migrateStore, needsSummary, normalizeStatement, organizeHierarchy, parseDedupResponse, profileNeedsRegeneration, readHistory, readHistoryForEngram, recallAuto, resolveOperationTier, rollbackMigrations, runMigrations, saveProfileCache, selectModel, selectModelForOperation, setSchemaVersion, strengthToStatus, tokenSimilarity, validateMetaEngram, withAsyncLock };
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
computeIdf,
|
|
3
3
|
embeddingSearch,
|
|
4
|
+
embeddingSearchWithScores,
|
|
4
5
|
engramSearchText,
|
|
5
6
|
ftsScore,
|
|
6
7
|
ftsTokenize,
|
|
7
8
|
searchEngrams
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-MW5EPL7G.js";
|
|
9
10
|
import {
|
|
10
11
|
EngramSchemaPassthrough,
|
|
11
12
|
appendHistory,
|
|
@@ -25,13 +26,13 @@ import {
|
|
|
25
26
|
readHistoryForEngram,
|
|
26
27
|
saveEngrams,
|
|
27
28
|
storePrefix
|
|
28
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-3ZPTRZE3.js";
|
|
29
30
|
import {
|
|
30
31
|
atomicWrite,
|
|
31
32
|
getSyncStatus,
|
|
32
33
|
sync,
|
|
33
34
|
withLock
|
|
34
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-PRK3B7WR.js";
|
|
35
36
|
import "./chunk-2ZDO52B4.js";
|
|
36
37
|
|
|
37
38
|
// src/index.ts
|
|
@@ -316,6 +317,72 @@ function confidenceDecay(retrievalStrength, lastPositiveFeedbackDate, commitment
|
|
|
316
317
|
const decayed = retrievalStrength * multiplier;
|
|
317
318
|
return Math.max(CONFIDENCE_DECAY_FLOOR, decayed);
|
|
318
319
|
}
|
|
320
|
+
function strengthToStatus(strength) {
|
|
321
|
+
if (strength > 0.5) return "active";
|
|
322
|
+
if (strength > 0.3) return "fading";
|
|
323
|
+
if (strength > 0.1) return "dormant";
|
|
324
|
+
return "retirement_candidate";
|
|
325
|
+
}
|
|
326
|
+
function applyBatchDecay(engrams, historyRoot, options) {
|
|
327
|
+
const now = options?.now ?? /* @__PURE__ */ new Date();
|
|
328
|
+
const lambda = options?.lambda ?? DECAY_RATE;
|
|
329
|
+
const contextScope = options?.contextScope;
|
|
330
|
+
const active = engrams.filter((e) => e.status === "active");
|
|
331
|
+
const transitions = [];
|
|
332
|
+
const modified = [];
|
|
333
|
+
let decayed = 0;
|
|
334
|
+
let skipped = 0;
|
|
335
|
+
for (const engram of active) {
|
|
336
|
+
if (contextScope && isScopeMatched(engram.scope, contextScope)) {
|
|
337
|
+
skipped++;
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
const days = daysSince(engram.activation.last_accessed, now);
|
|
341
|
+
if (days === 0) continue;
|
|
342
|
+
const emotionalWeight = engram.episodic?.emotional_weight ?? 5;
|
|
343
|
+
const effectiveLambda = lambda * (1 - emotionalWeight / 20);
|
|
344
|
+
const oldStrength = engram.activation.retrieval_strength;
|
|
345
|
+
const newStrength = decayedStrength(oldStrength, days, effectiveLambda);
|
|
346
|
+
if (Math.abs(newStrength - oldStrength) < 1e-10) continue;
|
|
347
|
+
const oldStatus = strengthToStatus(oldStrength);
|
|
348
|
+
const newStatus = strengthToStatus(newStrength);
|
|
349
|
+
engram.activation.retrieval_strength = newStrength;
|
|
350
|
+
modified.push(engram);
|
|
351
|
+
decayed++;
|
|
352
|
+
if (oldStatus !== newStatus) {
|
|
353
|
+
const transition = {
|
|
354
|
+
engram_id: engram.id,
|
|
355
|
+
old_strength: oldStrength,
|
|
356
|
+
new_strength: newStrength,
|
|
357
|
+
old_status: oldStatus,
|
|
358
|
+
new_status: newStatus
|
|
359
|
+
};
|
|
360
|
+
transitions.push(transition);
|
|
361
|
+
const event = {
|
|
362
|
+
event: "engram_updated",
|
|
363
|
+
engram_id: engram.id,
|
|
364
|
+
timestamp: now.toISOString(),
|
|
365
|
+
data: {
|
|
366
|
+
reason: "decay_status_transition",
|
|
367
|
+
old_strength: oldStrength,
|
|
368
|
+
new_strength: newStrength,
|
|
369
|
+
old_status: oldStatus,
|
|
370
|
+
new_status: newStatus
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
appendHistory(historyRoot, event);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return {
|
|
377
|
+
result: { total: active.length, decayed, skipped, transitions },
|
|
378
|
+
modified
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
function isScopeMatched(engramScope, contextScope) {
|
|
382
|
+
if (engramScope === contextScope) return true;
|
|
383
|
+
if (engramScope.startsWith(contextScope + "/")) return true;
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
319
386
|
|
|
320
387
|
// src/polarity.ts
|
|
321
388
|
var DONT_PATTERNS = [
|
|
@@ -1516,7 +1583,7 @@ async function computeSimilarityMatrix(templates) {
|
|
|
1516
1583
|
const n = templates.length;
|
|
1517
1584
|
const matrix = Array.from({ length: n }, () => Array(n).fill(0));
|
|
1518
1585
|
try {
|
|
1519
|
-
const { embed, cosineSimilarity } = await import("./embeddings-
|
|
1586
|
+
const { embed, cosineSimilarity } = await import("./embeddings-VXK2E2IF.js");
|
|
1520
1587
|
const embeddings = [];
|
|
1521
1588
|
for (const t of templates) {
|
|
1522
1589
|
embeddings.push(await embed(t));
|
|
@@ -2601,7 +2668,7 @@ async function withAsyncLock(filePath, fn, options) {
|
|
|
2601
2668
|
if (attempt === maxRetries) {
|
|
2602
2669
|
throw new Error(`Failed to acquire lock on ${filePath} after ${maxRetries} retries`);
|
|
2603
2670
|
}
|
|
2604
|
-
const delay = baseDelay * Math.pow(2, attempt);
|
|
2671
|
+
const delay = Math.min(baseDelay * Math.pow(2, attempt), 5e3);
|
|
2605
2672
|
await sleep(delay);
|
|
2606
2673
|
}
|
|
2607
2674
|
}
|
|
@@ -2942,9 +3009,9 @@ var Plur = class {
|
|
|
2942
3009
|
}
|
|
2943
3010
|
/** Load engrams from a path with mtime-based caching */
|
|
2944
3011
|
_loadCached(path3) {
|
|
2945
|
-
let mtime
|
|
3012
|
+
let mtime;
|
|
2946
3013
|
try {
|
|
2947
|
-
mtime = fs4.statSync(path3).
|
|
3014
|
+
mtime = fs4.statSync(path3, { bigint: true }).mtimeNs;
|
|
2948
3015
|
} catch {
|
|
2949
3016
|
return [];
|
|
2950
3017
|
}
|
|
@@ -2954,6 +3021,21 @@ var Plur = class {
|
|
|
2954
3021
|
this._engramCache.set(path3, { mtime, engrams });
|
|
2955
3022
|
return engrams;
|
|
2956
3023
|
}
|
|
3024
|
+
/**
|
|
3025
|
+
* Write engrams to disk and invalidate the cache for that path.
|
|
3026
|
+
*
|
|
3027
|
+
* Why: `_loadCached` uses mtime-based invalidation, but on CI tmpfs
|
|
3028
|
+
* (ubuntu-latest runners) mtime resolution can be coarse enough that a
|
|
3029
|
+
* stat() taken before and after a write returns the same mtime. When that
|
|
3030
|
+
* happens the cache serves a pre-write snapshot and a subsequent `getById`
|
|
3031
|
+
* returns `undefined` for an engram that `learn()` just created. Explicit
|
|
3032
|
+
* invalidation on write removes the filesystem as a source of cache
|
|
3033
|
+
* freshness and closes the race. See issue #25.
|
|
3034
|
+
*/
|
|
3035
|
+
_writeEngrams(path3, engrams) {
|
|
3036
|
+
saveEngrams(path3, engrams);
|
|
3037
|
+
this._engramCache.delete(path3);
|
|
3038
|
+
}
|
|
2957
3039
|
/** Find which store owns an engram by ID. For namespaced IDs, strips prefix to find in store. */
|
|
2958
3040
|
_findEngramStore(id) {
|
|
2959
3041
|
const primaryEngrams = this._loadCached(this.paths.engrams);
|
|
@@ -3083,7 +3165,7 @@ var Plur = class {
|
|
|
3083
3165
|
} : void 0
|
|
3084
3166
|
};
|
|
3085
3167
|
engrams.push(engram);
|
|
3086
|
-
|
|
3168
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3087
3169
|
this._syncIndex();
|
|
3088
3170
|
appendHistory(this.paths.root, {
|
|
3089
3171
|
event: "engram_created",
|
|
@@ -3113,12 +3195,12 @@ var Plur = class {
|
|
|
3113
3195
|
}
|
|
3114
3196
|
/** Async learn with LLM-driven deduplication (Ideas 1+2+19). */
|
|
3115
3197
|
async learnAsync(statement, context) {
|
|
3116
|
-
const { learnAsync: learnAsyncImpl } = await import("./learn-async-
|
|
3198
|
+
const { learnAsync: learnAsyncImpl } = await import("./learn-async-UZAPPQK4.js");
|
|
3117
3199
|
return learnAsyncImpl(this._learnAsyncDeps(), statement, context);
|
|
3118
3200
|
}
|
|
3119
3201
|
/** Batch learn with LLM dedup. */
|
|
3120
3202
|
async learnBatch(statements, llm) {
|
|
3121
|
-
const { learnBatch: learnBatchImpl } = await import("./learn-async-
|
|
3203
|
+
const { learnBatch: learnBatchImpl } = await import("./learn-async-UZAPPQK4.js");
|
|
3122
3204
|
return learnBatchImpl(this._learnAsyncDeps(), statements, llm);
|
|
3123
3205
|
}
|
|
3124
3206
|
/**
|
|
@@ -3159,6 +3241,12 @@ var Plur = class {
|
|
|
3159
3241
|
this._reactivateResults(results);
|
|
3160
3242
|
return results;
|
|
3161
3243
|
}
|
|
3244
|
+
/** Embedding search returning {engram, score}[] with cosine similarity scores. Async, no API calls. */
|
|
3245
|
+
async similaritySearch(query, options) {
|
|
3246
|
+
const filtered = this._filterEngrams(options);
|
|
3247
|
+
const limit = options?.limit ?? 20;
|
|
3248
|
+
return embeddingSearchWithScores(filtered, query, limit, this.paths.root);
|
|
3249
|
+
}
|
|
3162
3250
|
/** Expanded search: LLM query expansion + hybrid search + RRF merge. Opt-in, requires LLM function. */
|
|
3163
3251
|
async recallExpanded(query, options) {
|
|
3164
3252
|
const filtered = this._filterEngrams(options);
|
|
@@ -3267,7 +3355,7 @@ var Plur = class {
|
|
|
3267
3355
|
}
|
|
3268
3356
|
}
|
|
3269
3357
|
if (modified) {
|
|
3270
|
-
|
|
3358
|
+
this._writeEngrams(this.paths.engrams, allEngrams);
|
|
3271
3359
|
this._syncIndex();
|
|
3272
3360
|
}
|
|
3273
3361
|
});
|
|
@@ -3347,7 +3435,7 @@ var Plur = class {
|
|
|
3347
3435
|
} else if (signal === "negative") {
|
|
3348
3436
|
engram.activation.retrieval_strength = Math.max(0, engram.activation.retrieval_strength - 0.1);
|
|
3349
3437
|
}
|
|
3350
|
-
|
|
3438
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3351
3439
|
this._syncIndex();
|
|
3352
3440
|
appendHistory(this.paths.root, {
|
|
3353
3441
|
event: "feedback_received",
|
|
@@ -3375,8 +3463,7 @@ var Plur = class {
|
|
|
3375
3463
|
} else if (signal === "negative") {
|
|
3376
3464
|
engram.activation.retrieval_strength = Math.max(0, engram.activation.retrieval_strength - 0.1);
|
|
3377
3465
|
}
|
|
3378
|
-
|
|
3379
|
-
this._engramCache.delete(storeInfo.path);
|
|
3466
|
+
this._writeEngrams(storeInfo.path, storeEngrams);
|
|
3380
3467
|
this._syncIndex();
|
|
3381
3468
|
return;
|
|
3382
3469
|
}
|
|
@@ -3399,7 +3486,7 @@ var Plur = class {
|
|
|
3399
3486
|
}
|
|
3400
3487
|
}
|
|
3401
3488
|
if (saved > 0) {
|
|
3402
|
-
|
|
3489
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3403
3490
|
this._syncIndex();
|
|
3404
3491
|
}
|
|
3405
3492
|
return { saved, skipped };
|
|
@@ -3412,7 +3499,7 @@ var Plur = class {
|
|
|
3412
3499
|
const idx = engrams.findIndex((e) => e.id === updated.id);
|
|
3413
3500
|
if (idx === -1) return false;
|
|
3414
3501
|
engrams[idx] = updated;
|
|
3415
|
-
|
|
3502
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3416
3503
|
this._syncIndex();
|
|
3417
3504
|
return true;
|
|
3418
3505
|
});
|
|
@@ -3427,7 +3514,7 @@ var Plur = class {
|
|
|
3427
3514
|
if (reason && !engram.rationale) {
|
|
3428
3515
|
engram.rationale = `Retired: ${reason}`;
|
|
3429
3516
|
}
|
|
3430
|
-
|
|
3517
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3431
3518
|
this._syncIndex();
|
|
3432
3519
|
appendHistory(this.paths.root, {
|
|
3433
3520
|
event: "engram_retired",
|
|
@@ -3450,8 +3537,7 @@ var Plur = class {
|
|
|
3450
3537
|
if (reason && !engram.rationale) {
|
|
3451
3538
|
engram.rationale = `Retired: ${reason}`;
|
|
3452
3539
|
}
|
|
3453
|
-
|
|
3454
|
-
this._engramCache.delete(storeInfo.path);
|
|
3540
|
+
this._writeEngrams(storeInfo.path, storeEngrams);
|
|
3455
3541
|
this._syncIndex();
|
|
3456
3542
|
return;
|
|
3457
3543
|
}
|
|
@@ -3465,12 +3551,28 @@ var Plur = class {
|
|
|
3465
3551
|
const active = engrams.filter((e) => e.status !== "retired");
|
|
3466
3552
|
const removed = engrams.length - active.length;
|
|
3467
3553
|
if (removed > 0) {
|
|
3468
|
-
|
|
3554
|
+
this._writeEngrams(this.paths.engrams, active);
|
|
3469
3555
|
this._syncIndex();
|
|
3470
3556
|
}
|
|
3471
3557
|
return { removed, remaining: active.length };
|
|
3472
3558
|
});
|
|
3473
3559
|
}
|
|
3560
|
+
/**
|
|
3561
|
+
* Apply ACT-R decay to all primary store engrams.
|
|
3562
|
+
* Scope-matched engrams are skipped, status transitions logged to history.
|
|
3563
|
+
* Modified engrams are saved back to the store.
|
|
3564
|
+
*/
|
|
3565
|
+
batchDecay(options) {
|
|
3566
|
+
return withLock(this.paths.engrams, () => {
|
|
3567
|
+
const engrams = loadEngrams(this.paths.engrams);
|
|
3568
|
+
const { result, modified } = applyBatchDecay(engrams, this.paths.root, options);
|
|
3569
|
+
if (result.transitions.length > 0) {
|
|
3570
|
+
this._writeEngrams(this.paths.engrams, modified);
|
|
3571
|
+
this._syncIndex();
|
|
3572
|
+
}
|
|
3573
|
+
return result;
|
|
3574
|
+
});
|
|
3575
|
+
}
|
|
3474
3576
|
/** Rebuild SQLite index from YAML source of truth. Only works when index: true. */
|
|
3475
3577
|
reindex() {
|
|
3476
3578
|
if (!this.indexedStorage) {
|
|
@@ -3672,7 +3774,7 @@ Generate an improved version of the procedure that prevents this failure. Return
|
|
|
3672
3774
|
raw.previous_version_ref = { event_id: eventId, changed_at: now };
|
|
3673
3775
|
if (!raw.episode_ids) raw.episode_ids = [];
|
|
3674
3776
|
raw.episode_ids.push(episode.id);
|
|
3675
|
-
|
|
3777
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3676
3778
|
this._syncIndex();
|
|
3677
3779
|
appendHistory(this.paths.root, {
|
|
3678
3780
|
event: "procedure_evolved",
|
|
@@ -3702,7 +3804,7 @@ Generate an improved version of the procedure that prevents this failure. Return
|
|
|
3702
3804
|
const raw = engrams[idx];
|
|
3703
3805
|
if (!raw.episode_ids) raw.episode_ids = [];
|
|
3704
3806
|
raw.episode_ids.push(episode.id);
|
|
3705
|
-
|
|
3807
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3706
3808
|
this._syncIndex();
|
|
3707
3809
|
}
|
|
3708
3810
|
});
|
|
@@ -3800,6 +3902,7 @@ export {
|
|
|
3800
3902
|
alignCluster,
|
|
3801
3903
|
analyzeStructure,
|
|
3802
3904
|
appendHistory,
|
|
3905
|
+
applyBatchDecay,
|
|
3803
3906
|
assignLayer,
|
|
3804
3907
|
asyncAtomicWrite,
|
|
3805
3908
|
autoSummary,
|
|
@@ -3851,6 +3954,7 @@ export {
|
|
|
3851
3954
|
selectModel,
|
|
3852
3955
|
selectModelForOperation,
|
|
3853
3956
|
setSchemaVersion,
|
|
3957
|
+
strengthToStatus,
|
|
3854
3958
|
tokenSimilarity,
|
|
3855
3959
|
validateMetaEngram,
|
|
3856
3960
|
withAsyncLock
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
logger,
|
|
7
7
|
parseDedupResponse,
|
|
8
8
|
saveEngrams
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-3ZPTRZE3.js";
|
|
10
10
|
import {
|
|
11
11
|
withLock
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-PRK3B7WR.js";
|
|
13
13
|
import "./chunk-2ZDO52B4.js";
|
|
14
14
|
|
|
15
15
|
// src/learn-async.ts
|
package/package.json
CHANGED