@plur-ai/core 0.8.3 → 0.9.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.
- 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 +76 -2
- package/dist/index.js +175 -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) */
|
|
@@ -1985,6 +2050,15 @@ declare class Plur {
|
|
|
1985
2050
|
shared?: boolean;
|
|
1986
2051
|
readonly?: boolean;
|
|
1987
2052
|
}): void;
|
|
2053
|
+
/**
|
|
2054
|
+
* Auto-discover .plur/engrams.yaml in CWD and parent dirs (up to git root).
|
|
2055
|
+
* If found and not already registered, auto-register as a project store.
|
|
2056
|
+
* Returns list of newly discovered stores (empty if none found or all already known).
|
|
2057
|
+
*/
|
|
2058
|
+
autoDiscoverStores(cwd?: string): Array<{
|
|
2059
|
+
path: string;
|
|
2060
|
+
scope: string;
|
|
2061
|
+
}>;
|
|
1988
2062
|
/** List all configured stores. */
|
|
1989
2063
|
listStores(): Array<{
|
|
1990
2064
|
path: string;
|
|
@@ -1995,4 +2069,4 @@ declare class Plur {
|
|
|
1995
2069
|
}>;
|
|
1996
2070
|
}
|
|
1997
2071
|
|
|
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 };
|
|
2072
|
+
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,14 +26,16 @@ 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
|
-
import
|
|
35
|
+
} from "./chunk-PRK3B7WR.js";
|
|
36
|
+
import {
|
|
37
|
+
__require
|
|
38
|
+
} from "./chunk-2ZDO52B4.js";
|
|
36
39
|
|
|
37
40
|
// src/index.ts
|
|
38
41
|
import * as fs4 from "fs";
|
|
@@ -316,6 +319,72 @@ function confidenceDecay(retrievalStrength, lastPositiveFeedbackDate, commitment
|
|
|
316
319
|
const decayed = retrievalStrength * multiplier;
|
|
317
320
|
return Math.max(CONFIDENCE_DECAY_FLOOR, decayed);
|
|
318
321
|
}
|
|
322
|
+
function strengthToStatus(strength) {
|
|
323
|
+
if (strength > 0.5) return "active";
|
|
324
|
+
if (strength > 0.3) return "fading";
|
|
325
|
+
if (strength > 0.1) return "dormant";
|
|
326
|
+
return "retirement_candidate";
|
|
327
|
+
}
|
|
328
|
+
function applyBatchDecay(engrams, historyRoot, options) {
|
|
329
|
+
const now = options?.now ?? /* @__PURE__ */ new Date();
|
|
330
|
+
const lambda = options?.lambda ?? DECAY_RATE;
|
|
331
|
+
const contextScope = options?.contextScope;
|
|
332
|
+
const active = engrams.filter((e) => e.status === "active");
|
|
333
|
+
const transitions = [];
|
|
334
|
+
const modified = [];
|
|
335
|
+
let decayed = 0;
|
|
336
|
+
let skipped = 0;
|
|
337
|
+
for (const engram of active) {
|
|
338
|
+
if (contextScope && isScopeMatched(engram.scope, contextScope)) {
|
|
339
|
+
skipped++;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
const days = daysSince(engram.activation.last_accessed, now);
|
|
343
|
+
if (days === 0) continue;
|
|
344
|
+
const emotionalWeight = engram.episodic?.emotional_weight ?? 5;
|
|
345
|
+
const effectiveLambda = lambda * (1 - emotionalWeight / 20);
|
|
346
|
+
const oldStrength = engram.activation.retrieval_strength;
|
|
347
|
+
const newStrength = decayedStrength(oldStrength, days, effectiveLambda);
|
|
348
|
+
if (Math.abs(newStrength - oldStrength) < 1e-10) continue;
|
|
349
|
+
const oldStatus = strengthToStatus(oldStrength);
|
|
350
|
+
const newStatus = strengthToStatus(newStrength);
|
|
351
|
+
engram.activation.retrieval_strength = newStrength;
|
|
352
|
+
modified.push(engram);
|
|
353
|
+
decayed++;
|
|
354
|
+
if (oldStatus !== newStatus) {
|
|
355
|
+
const transition = {
|
|
356
|
+
engram_id: engram.id,
|
|
357
|
+
old_strength: oldStrength,
|
|
358
|
+
new_strength: newStrength,
|
|
359
|
+
old_status: oldStatus,
|
|
360
|
+
new_status: newStatus
|
|
361
|
+
};
|
|
362
|
+
transitions.push(transition);
|
|
363
|
+
const event = {
|
|
364
|
+
event: "engram_updated",
|
|
365
|
+
engram_id: engram.id,
|
|
366
|
+
timestamp: now.toISOString(),
|
|
367
|
+
data: {
|
|
368
|
+
reason: "decay_status_transition",
|
|
369
|
+
old_strength: oldStrength,
|
|
370
|
+
new_strength: newStrength,
|
|
371
|
+
old_status: oldStatus,
|
|
372
|
+
new_status: newStatus
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
appendHistory(historyRoot, event);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
result: { total: active.length, decayed, skipped, transitions },
|
|
380
|
+
modified
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
function isScopeMatched(engramScope, contextScope) {
|
|
384
|
+
if (engramScope === contextScope) return true;
|
|
385
|
+
if (engramScope.startsWith(contextScope + "/")) return true;
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
319
388
|
|
|
320
389
|
// src/polarity.ts
|
|
321
390
|
var DONT_PATTERNS = [
|
|
@@ -1516,7 +1585,7 @@ async function computeSimilarityMatrix(templates) {
|
|
|
1516
1585
|
const n = templates.length;
|
|
1517
1586
|
const matrix = Array.from({ length: n }, () => Array(n).fill(0));
|
|
1518
1587
|
try {
|
|
1519
|
-
const { embed, cosineSimilarity } = await import("./embeddings-
|
|
1588
|
+
const { embed, cosineSimilarity } = await import("./embeddings-VXK2E2IF.js");
|
|
1520
1589
|
const embeddings = [];
|
|
1521
1590
|
for (const t of templates) {
|
|
1522
1591
|
embeddings.push(await embed(t));
|
|
@@ -2942,9 +3011,9 @@ var Plur = class {
|
|
|
2942
3011
|
}
|
|
2943
3012
|
/** Load engrams from a path with mtime-based caching */
|
|
2944
3013
|
_loadCached(path3) {
|
|
2945
|
-
let mtime
|
|
3014
|
+
let mtime;
|
|
2946
3015
|
try {
|
|
2947
|
-
mtime = fs4.statSync(path3).
|
|
3016
|
+
mtime = fs4.statSync(path3, { bigint: true }).mtimeNs;
|
|
2948
3017
|
} catch {
|
|
2949
3018
|
return [];
|
|
2950
3019
|
}
|
|
@@ -2954,6 +3023,21 @@ var Plur = class {
|
|
|
2954
3023
|
this._engramCache.set(path3, { mtime, engrams });
|
|
2955
3024
|
return engrams;
|
|
2956
3025
|
}
|
|
3026
|
+
/**
|
|
3027
|
+
* Write engrams to disk and invalidate the cache for that path.
|
|
3028
|
+
*
|
|
3029
|
+
* Why: `_loadCached` uses mtime-based invalidation, but on CI tmpfs
|
|
3030
|
+
* (ubuntu-latest runners) mtime resolution can be coarse enough that a
|
|
3031
|
+
* stat() taken before and after a write returns the same mtime. When that
|
|
3032
|
+
* happens the cache serves a pre-write snapshot and a subsequent `getById`
|
|
3033
|
+
* returns `undefined` for an engram that `learn()` just created. Explicit
|
|
3034
|
+
* invalidation on write removes the filesystem as a source of cache
|
|
3035
|
+
* freshness and closes the race. See issue #25.
|
|
3036
|
+
*/
|
|
3037
|
+
_writeEngrams(path3, engrams) {
|
|
3038
|
+
saveEngrams(path3, engrams);
|
|
3039
|
+
this._engramCache.delete(path3);
|
|
3040
|
+
}
|
|
2957
3041
|
/** Find which store owns an engram by ID. For namespaced IDs, strips prefix to find in store. */
|
|
2958
3042
|
_findEngramStore(id) {
|
|
2959
3043
|
const primaryEngrams = this._loadCached(this.paths.engrams);
|
|
@@ -3083,7 +3167,7 @@ var Plur = class {
|
|
|
3083
3167
|
} : void 0
|
|
3084
3168
|
};
|
|
3085
3169
|
engrams.push(engram);
|
|
3086
|
-
|
|
3170
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3087
3171
|
this._syncIndex();
|
|
3088
3172
|
appendHistory(this.paths.root, {
|
|
3089
3173
|
event: "engram_created",
|
|
@@ -3113,12 +3197,12 @@ var Plur = class {
|
|
|
3113
3197
|
}
|
|
3114
3198
|
/** Async learn with LLM-driven deduplication (Ideas 1+2+19). */
|
|
3115
3199
|
async learnAsync(statement, context) {
|
|
3116
|
-
const { learnAsync: learnAsyncImpl } = await import("./learn-async-
|
|
3200
|
+
const { learnAsync: learnAsyncImpl } = await import("./learn-async-UZAPPQK4.js");
|
|
3117
3201
|
return learnAsyncImpl(this._learnAsyncDeps(), statement, context);
|
|
3118
3202
|
}
|
|
3119
3203
|
/** Batch learn with LLM dedup. */
|
|
3120
3204
|
async learnBatch(statements, llm) {
|
|
3121
|
-
const { learnBatch: learnBatchImpl } = await import("./learn-async-
|
|
3205
|
+
const { learnBatch: learnBatchImpl } = await import("./learn-async-UZAPPQK4.js");
|
|
3122
3206
|
return learnBatchImpl(this._learnAsyncDeps(), statements, llm);
|
|
3123
3207
|
}
|
|
3124
3208
|
/**
|
|
@@ -3159,6 +3243,12 @@ var Plur = class {
|
|
|
3159
3243
|
this._reactivateResults(results);
|
|
3160
3244
|
return results;
|
|
3161
3245
|
}
|
|
3246
|
+
/** Embedding search returning {engram, score}[] with cosine similarity scores. Async, no API calls. */
|
|
3247
|
+
async similaritySearch(query, options) {
|
|
3248
|
+
const filtered = this._filterEngrams(options);
|
|
3249
|
+
const limit = options?.limit ?? 20;
|
|
3250
|
+
return embeddingSearchWithScores(filtered, query, limit, this.paths.root);
|
|
3251
|
+
}
|
|
3162
3252
|
/** Expanded search: LLM query expansion + hybrid search + RRF merge. Opt-in, requires LLM function. */
|
|
3163
3253
|
async recallExpanded(query, options) {
|
|
3164
3254
|
const filtered = this._filterEngrams(options);
|
|
@@ -3267,7 +3357,7 @@ var Plur = class {
|
|
|
3267
3357
|
}
|
|
3268
3358
|
}
|
|
3269
3359
|
if (modified) {
|
|
3270
|
-
|
|
3360
|
+
this._writeEngrams(this.paths.engrams, allEngrams);
|
|
3271
3361
|
this._syncIndex();
|
|
3272
3362
|
}
|
|
3273
3363
|
});
|
|
@@ -3347,7 +3437,7 @@ var Plur = class {
|
|
|
3347
3437
|
} else if (signal === "negative") {
|
|
3348
3438
|
engram.activation.retrieval_strength = Math.max(0, engram.activation.retrieval_strength - 0.1);
|
|
3349
3439
|
}
|
|
3350
|
-
|
|
3440
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3351
3441
|
this._syncIndex();
|
|
3352
3442
|
appendHistory(this.paths.root, {
|
|
3353
3443
|
event: "feedback_received",
|
|
@@ -3375,8 +3465,7 @@ var Plur = class {
|
|
|
3375
3465
|
} else if (signal === "negative") {
|
|
3376
3466
|
engram.activation.retrieval_strength = Math.max(0, engram.activation.retrieval_strength - 0.1);
|
|
3377
3467
|
}
|
|
3378
|
-
|
|
3379
|
-
this._engramCache.delete(storeInfo.path);
|
|
3468
|
+
this._writeEngrams(storeInfo.path, storeEngrams);
|
|
3380
3469
|
this._syncIndex();
|
|
3381
3470
|
return;
|
|
3382
3471
|
}
|
|
@@ -3399,7 +3488,7 @@ var Plur = class {
|
|
|
3399
3488
|
}
|
|
3400
3489
|
}
|
|
3401
3490
|
if (saved > 0) {
|
|
3402
|
-
|
|
3491
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3403
3492
|
this._syncIndex();
|
|
3404
3493
|
}
|
|
3405
3494
|
return { saved, skipped };
|
|
@@ -3412,7 +3501,7 @@ var Plur = class {
|
|
|
3412
3501
|
const idx = engrams.findIndex((e) => e.id === updated.id);
|
|
3413
3502
|
if (idx === -1) return false;
|
|
3414
3503
|
engrams[idx] = updated;
|
|
3415
|
-
|
|
3504
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3416
3505
|
this._syncIndex();
|
|
3417
3506
|
return true;
|
|
3418
3507
|
});
|
|
@@ -3427,7 +3516,7 @@ var Plur = class {
|
|
|
3427
3516
|
if (reason && !engram.rationale) {
|
|
3428
3517
|
engram.rationale = `Retired: ${reason}`;
|
|
3429
3518
|
}
|
|
3430
|
-
|
|
3519
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3431
3520
|
this._syncIndex();
|
|
3432
3521
|
appendHistory(this.paths.root, {
|
|
3433
3522
|
event: "engram_retired",
|
|
@@ -3450,8 +3539,7 @@ var Plur = class {
|
|
|
3450
3539
|
if (reason && !engram.rationale) {
|
|
3451
3540
|
engram.rationale = `Retired: ${reason}`;
|
|
3452
3541
|
}
|
|
3453
|
-
|
|
3454
|
-
this._engramCache.delete(storeInfo.path);
|
|
3542
|
+
this._writeEngrams(storeInfo.path, storeEngrams);
|
|
3455
3543
|
this._syncIndex();
|
|
3456
3544
|
return;
|
|
3457
3545
|
}
|
|
@@ -3465,12 +3553,28 @@ var Plur = class {
|
|
|
3465
3553
|
const active = engrams.filter((e) => e.status !== "retired");
|
|
3466
3554
|
const removed = engrams.length - active.length;
|
|
3467
3555
|
if (removed > 0) {
|
|
3468
|
-
|
|
3556
|
+
this._writeEngrams(this.paths.engrams, active);
|
|
3469
3557
|
this._syncIndex();
|
|
3470
3558
|
}
|
|
3471
3559
|
return { removed, remaining: active.length };
|
|
3472
3560
|
});
|
|
3473
3561
|
}
|
|
3562
|
+
/**
|
|
3563
|
+
* Apply ACT-R decay to all primary store engrams.
|
|
3564
|
+
* Scope-matched engrams are skipped, status transitions logged to history.
|
|
3565
|
+
* Modified engrams are saved back to the store.
|
|
3566
|
+
*/
|
|
3567
|
+
batchDecay(options) {
|
|
3568
|
+
return withLock(this.paths.engrams, () => {
|
|
3569
|
+
const engrams = loadEngrams(this.paths.engrams);
|
|
3570
|
+
const { result, modified } = applyBatchDecay(engrams, this.paths.root, options);
|
|
3571
|
+
if (result.transitions.length > 0) {
|
|
3572
|
+
this._writeEngrams(this.paths.engrams, modified);
|
|
3573
|
+
this._syncIndex();
|
|
3574
|
+
}
|
|
3575
|
+
return result;
|
|
3576
|
+
});
|
|
3577
|
+
}
|
|
3474
3578
|
/** Rebuild SQLite index from YAML source of truth. Only works when index: true. */
|
|
3475
3579
|
reindex() {
|
|
3476
3580
|
if (!this.indexedStorage) {
|
|
@@ -3672,7 +3776,7 @@ Generate an improved version of the procedure that prevents this failure. Return
|
|
|
3672
3776
|
raw.previous_version_ref = { event_id: eventId, changed_at: now };
|
|
3673
3777
|
if (!raw.episode_ids) raw.episode_ids = [];
|
|
3674
3778
|
raw.episode_ids.push(episode.id);
|
|
3675
|
-
|
|
3779
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3676
3780
|
this._syncIndex();
|
|
3677
3781
|
appendHistory(this.paths.root, {
|
|
3678
3782
|
event: "procedure_evolved",
|
|
@@ -3702,7 +3806,7 @@ Generate an improved version of the procedure that prevents this failure. Return
|
|
|
3702
3806
|
const raw = engrams[idx];
|
|
3703
3807
|
if (!raw.episode_ids) raw.episode_ids = [];
|
|
3704
3808
|
raw.episode_ids.push(episode.id);
|
|
3705
|
-
|
|
3809
|
+
this._writeEngrams(this.paths.engrams, engrams);
|
|
3706
3810
|
this._syncIndex();
|
|
3707
3811
|
}
|
|
3708
3812
|
});
|
|
@@ -3759,6 +3863,53 @@ Generate an improved version of the procedure that prevents this failure. Return
|
|
|
3759
3863
|
fs4.writeFileSync(this.paths.config, yaml6.dump(configData, { lineWidth: 120, noRefs: true }));
|
|
3760
3864
|
this.config = loadConfig(this.paths.config);
|
|
3761
3865
|
}
|
|
3866
|
+
/**
|
|
3867
|
+
* Auto-discover .plur/engrams.yaml in CWD and parent dirs (up to git root).
|
|
3868
|
+
* If found and not already registered, auto-register as a project store.
|
|
3869
|
+
* Returns list of newly discovered stores (empty if none found or all already known).
|
|
3870
|
+
*/
|
|
3871
|
+
autoDiscoverStores(cwd) {
|
|
3872
|
+
const startDir = cwd || process.cwd();
|
|
3873
|
+
const discovered = [];
|
|
3874
|
+
const os = __require("os");
|
|
3875
|
+
const tmpDir = os.tmpdir();
|
|
3876
|
+
if (this.paths.root.startsWith(tmpDir) || this.paths.root.startsWith("/tmp/")) {
|
|
3877
|
+
return discovered;
|
|
3878
|
+
}
|
|
3879
|
+
const knownPaths = new Set((this.config.stores ?? []).map((s) => s.path));
|
|
3880
|
+
const primaryDir = __require("path").dirname(this.paths.engrams);
|
|
3881
|
+
let dir = startDir;
|
|
3882
|
+
const { join: join5, dirname: dirname2, basename: basename2 } = __require("path");
|
|
3883
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3884
|
+
while (dir && !visited.has(dir)) {
|
|
3885
|
+
visited.add(dir);
|
|
3886
|
+
const candidate = join5(dir, ".plur", "engrams.yaml");
|
|
3887
|
+
if (join5(dir, ".plur") === primaryDir) {
|
|
3888
|
+
dir = dirname2(dir);
|
|
3889
|
+
continue;
|
|
3890
|
+
}
|
|
3891
|
+
if (fs4.existsSync(candidate) && !knownPaths.has(candidate)) {
|
|
3892
|
+
let scope = `project:${basename2(dir)}`;
|
|
3893
|
+
try {
|
|
3894
|
+
const plurYaml = join5(dir, ".plur.yaml");
|
|
3895
|
+
if (fs4.existsSync(plurYaml)) {
|
|
3896
|
+
const raw = yaml6.load(fs4.readFileSync(plurYaml, "utf8"));
|
|
3897
|
+
if (raw?.scope) scope = raw.scope;
|
|
3898
|
+
}
|
|
3899
|
+
} catch {
|
|
3900
|
+
}
|
|
3901
|
+
this.addStore(candidate, scope, { shared: true, readonly: false });
|
|
3902
|
+
discovered.push({ path: candidate, scope });
|
|
3903
|
+
knownPaths.add(candidate);
|
|
3904
|
+
logger.info(`Auto-discovered project store: ${candidate} (${scope})`);
|
|
3905
|
+
}
|
|
3906
|
+
if (fs4.existsSync(join5(dir, ".git"))) break;
|
|
3907
|
+
const parent = dirname2(dir);
|
|
3908
|
+
if (parent === dir) break;
|
|
3909
|
+
dir = parent;
|
|
3910
|
+
}
|
|
3911
|
+
return discovered;
|
|
3912
|
+
}
|
|
3762
3913
|
/** List all configured stores. */
|
|
3763
3914
|
listStores() {
|
|
3764
3915
|
const stores = this.config.stores ?? [];
|
|
@@ -3800,6 +3951,7 @@ export {
|
|
|
3800
3951
|
alignCluster,
|
|
3801
3952
|
analyzeStructure,
|
|
3802
3953
|
appendHistory,
|
|
3954
|
+
applyBatchDecay,
|
|
3803
3955
|
assignLayer,
|
|
3804
3956
|
asyncAtomicWrite,
|
|
3805
3957
|
autoSummary,
|
|
@@ -3851,6 +4003,7 @@ export {
|
|
|
3851
4003
|
selectModel,
|
|
3852
4004
|
selectModelForOperation,
|
|
3853
4005
|
setSchemaVersion,
|
|
4006
|
+
strengthToStatus,
|
|
3854
4007
|
tokenSimilarity,
|
|
3855
4008
|
validateMetaEngram,
|
|
3856
4009
|
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