@plur-ai/core 0.3.1 → 0.4.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-WPD4MPTT.js +348 -0
- package/dist/embeddings-Q76LNQ5B.js +11 -0
- package/dist/index.d.ts +484 -2
- package/dist/index.js +1004 -315
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
atomicWrite,
|
|
3
|
+
embeddingSearch,
|
|
4
|
+
engramSearchText,
|
|
5
|
+
ftsScore,
|
|
6
|
+
ftsTokenize,
|
|
7
|
+
getSyncStatus,
|
|
8
|
+
searchEngrams,
|
|
9
|
+
sync
|
|
10
|
+
} from "./chunk-WPD4MPTT.js";
|
|
1
11
|
import "./chunk-2ZDO52B4.js";
|
|
2
12
|
|
|
3
13
|
// src/storage.ts
|
|
@@ -37,7 +47,8 @@ var PlurConfigSchema = z.object({
|
|
|
37
47
|
spread_cap: z.number().default(3),
|
|
38
48
|
spread_budget: z.number().default(480),
|
|
39
49
|
co_access: z.boolean().default(true)
|
|
40
|
-
}).default({})
|
|
50
|
+
}).default({}),
|
|
51
|
+
allow_secrets: z.boolean().default(false)
|
|
41
52
|
}).partial();
|
|
42
53
|
|
|
43
54
|
// src/config.ts
|
|
@@ -146,7 +157,7 @@ var ExchangeMetadataSchema = z2.object({
|
|
|
146
157
|
});
|
|
147
158
|
var EngramSchema = z2.object({
|
|
148
159
|
// Identity
|
|
149
|
-
id: z2.string().regex(/^(ENG|ABS)-[A-Za-z0-9-]+$/),
|
|
160
|
+
id: z2.string().regex(/^(ENG|ABS|META)-[A-Za-z0-9-]+$/),
|
|
150
161
|
version: z2.number().int().min(1).default(2),
|
|
151
162
|
status: z2.enum(["active", "dormant", "retired", "candidate"]),
|
|
152
163
|
consolidated: z2.boolean().default(false),
|
|
@@ -196,7 +207,9 @@ var EngramSchema = z2.object({
|
|
|
196
207
|
/** Exchange marketplace metadata: fitness, adoption, diversity. */
|
|
197
208
|
exchange: ExchangeMetadataSchema.optional(),
|
|
198
209
|
/** Extensible key-value data for domain-specific fields. */
|
|
199
|
-
structured_data: z2.record(z2.string(), z2.unknown()).optional()
|
|
210
|
+
structured_data: z2.record(z2.string(), z2.unknown()).optional(),
|
|
211
|
+
/** Polarity classification: 'do' for directives, 'dont' for prohibitions, null for unclassified. */
|
|
212
|
+
polarity: z2.enum(["do", "dont"]).nullable().default(null)
|
|
200
213
|
});
|
|
201
214
|
|
|
202
215
|
// src/schemas/pack.ts
|
|
@@ -243,168 +256,6 @@ var logger = {
|
|
|
243
256
|
}
|
|
244
257
|
};
|
|
245
258
|
|
|
246
|
-
// src/sync.ts
|
|
247
|
-
import { execFileSync } from "child_process";
|
|
248
|
-
import { existsSync as existsSync3, writeFileSync, renameSync, mkdirSync as mkdirSync2 } from "fs";
|
|
249
|
-
import { join as join2, dirname } from "path";
|
|
250
|
-
var GITIGNORE = `# PLUR \u2014 derived/cache files (regenerated automatically)
|
|
251
|
-
embeddings/
|
|
252
|
-
.embeddings-cache.json
|
|
253
|
-
*.db
|
|
254
|
-
*.sqlite
|
|
255
|
-
exchange/
|
|
256
|
-
`;
|
|
257
|
-
function git(args, cwd) {
|
|
258
|
-
return execFileSync("git", args, { cwd, encoding: "utf8", timeout: 3e4 }).trim();
|
|
259
|
-
}
|
|
260
|
-
function gitSafe(args, cwd) {
|
|
261
|
-
try {
|
|
262
|
-
return git(args, cwd);
|
|
263
|
-
} catch {
|
|
264
|
-
return null;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
function isGitRepo(root) {
|
|
268
|
-
return existsSync3(join2(root, ".git"));
|
|
269
|
-
}
|
|
270
|
-
function hasGitCli() {
|
|
271
|
-
try {
|
|
272
|
-
execFileSync("git", ["--version"], { encoding: "utf8", timeout: 5e3 });
|
|
273
|
-
return true;
|
|
274
|
-
} catch {
|
|
275
|
-
return false;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
function getRemote(root) {
|
|
279
|
-
return gitSafe(["remote", "get-url", "origin"], root);
|
|
280
|
-
}
|
|
281
|
-
function isDirty(root) {
|
|
282
|
-
const status = gitSafe(["status", "--porcelain"], root);
|
|
283
|
-
return status !== null && status.length > 0;
|
|
284
|
-
}
|
|
285
|
-
function countDiff(root, direction) {
|
|
286
|
-
const tracking = gitSafe(["rev-parse", "--abbrev-ref", "@{u}"], root);
|
|
287
|
-
if (!tracking) return 0;
|
|
288
|
-
const flag = direction === "ahead" ? "--left-only" : "--right-only";
|
|
289
|
-
const count = gitSafe(["rev-list", flag, "--count", "HEAD...@{u}"], root);
|
|
290
|
-
return count ? parseInt(count, 10) : 0;
|
|
291
|
-
}
|
|
292
|
-
function getSyncStatus(root) {
|
|
293
|
-
if (!isGitRepo(root)) {
|
|
294
|
-
return { initialized: false, remote: null, dirty: false, branch: null, ahead: 0, behind: 0 };
|
|
295
|
-
}
|
|
296
|
-
const branch = gitSafe(["rev-parse", "--abbrev-ref", "HEAD"], root);
|
|
297
|
-
const remote = getRemote(root);
|
|
298
|
-
if (remote) gitSafe(["fetch", "origin", "--quiet"], root);
|
|
299
|
-
return {
|
|
300
|
-
initialized: true,
|
|
301
|
-
remote,
|
|
302
|
-
dirty: isDirty(root),
|
|
303
|
-
branch,
|
|
304
|
-
ahead: countDiff(root, "ahead"),
|
|
305
|
-
behind: countDiff(root, "behind")
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
function initRepo(root) {
|
|
309
|
-
git(["init"], root);
|
|
310
|
-
atomicWrite(join2(root, ".gitignore"), GITIGNORE);
|
|
311
|
-
git(["add", "-A"], root);
|
|
312
|
-
git(["commit", "-m", "Initial PLUR engram store"], root);
|
|
313
|
-
}
|
|
314
|
-
function commitChanges(root) {
|
|
315
|
-
if (!isDirty(root)) return 0;
|
|
316
|
-
git(["add", "-A"], root);
|
|
317
|
-
const diff = gitSafe(["diff", "--cached", "--stat", "--shortstat"], root);
|
|
318
|
-
const now = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
|
|
319
|
-
git(["commit", "-m", `plur sync ${now}`], root);
|
|
320
|
-
const match = diff?.match(/(\d+) file/);
|
|
321
|
-
return match ? parseInt(match[1], 10) : 1;
|
|
322
|
-
}
|
|
323
|
-
function hasConflictMarkers(root) {
|
|
324
|
-
const result = gitSafe(["grep", "-l", "<<<<<<<"], root);
|
|
325
|
-
return result !== null && result.length > 0;
|
|
326
|
-
}
|
|
327
|
-
function pullRebase(root) {
|
|
328
|
-
const result = gitSafe(["pull", "--rebase", "origin", "main"], root);
|
|
329
|
-
if (result !== null) return true;
|
|
330
|
-
gitSafe(["rebase", "--abort"], root);
|
|
331
|
-
const mergeResult = gitSafe(["pull", "origin", "main", "--no-edit"], root);
|
|
332
|
-
if (mergeResult !== null) return true;
|
|
333
|
-
if (hasConflictMarkers(root)) {
|
|
334
|
-
gitSafe(["merge", "--abort"], root);
|
|
335
|
-
throw new Error("Sync conflict: YAML files have merge conflicts that require manual resolution. Your local changes are preserved.");
|
|
336
|
-
}
|
|
337
|
-
git(["add", "-A"], root);
|
|
338
|
-
gitSafe(["commit", "-m", "plur sync: merge conflict resolved (kept both)"], root);
|
|
339
|
-
return true;
|
|
340
|
-
}
|
|
341
|
-
function sync(root, remote) {
|
|
342
|
-
if (!hasGitCli()) {
|
|
343
|
-
throw new Error("git is not installed. Install git to enable sync.");
|
|
344
|
-
}
|
|
345
|
-
if (!isGitRepo(root)) {
|
|
346
|
-
initRepo(root);
|
|
347
|
-
if (remote) {
|
|
348
|
-
git(["remote", "add", "origin", remote], root);
|
|
349
|
-
const branch = git(["rev-parse", "--abbrev-ref", "HEAD"], root);
|
|
350
|
-
git(["push", "-u", "origin", branch], root);
|
|
351
|
-
return { action: "initialized", message: `Initialized and pushed to ${remote}`, remote, files_changed: 0 };
|
|
352
|
-
}
|
|
353
|
-
return {
|
|
354
|
-
action: "initialized",
|
|
355
|
-
message: "Initialized local git repo. Call plur.sync with remote to enable cross-device sync.",
|
|
356
|
-
remote: null,
|
|
357
|
-
files_changed: 0
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
const existingRemote = getRemote(root);
|
|
361
|
-
if (remote && !existingRemote) {
|
|
362
|
-
git(["remote", "add", "origin", remote], root);
|
|
363
|
-
const filesChanged2 = commitChanges(root);
|
|
364
|
-
const branch = git(["rev-parse", "--abbrev-ref", "HEAD"], root);
|
|
365
|
-
git(["push", "-u", "origin", branch], root);
|
|
366
|
-
return { action: "synced", message: `Remote added and pushed to ${remote}`, remote, files_changed: filesChanged2 };
|
|
367
|
-
}
|
|
368
|
-
if (!existingRemote) {
|
|
369
|
-
const filesChanged2 = commitChanges(root);
|
|
370
|
-
if (filesChanged2 === 0) {
|
|
371
|
-
return { action: "up-to-date", message: 'No changes to commit. Add a remote with plur.sync({ remote: "..." }) to enable cross-device sync.', remote: null, files_changed: 0 };
|
|
372
|
-
}
|
|
373
|
-
return { action: "committed", message: `Committed ${filesChanged2} file(s) locally.`, remote: null, files_changed: filesChanged2 };
|
|
374
|
-
}
|
|
375
|
-
const filesChanged = commitChanges(root);
|
|
376
|
-
gitSafe(["fetch", "origin", "--quiet"], root);
|
|
377
|
-
const behind = countDiff(root, "behind");
|
|
378
|
-
const aheadBefore = countDiff(root, "ahead");
|
|
379
|
-
if (behind > 0) {
|
|
380
|
-
pullRebase(root);
|
|
381
|
-
}
|
|
382
|
-
const aheadAfter = countDiff(root, "ahead");
|
|
383
|
-
if (aheadAfter > 0) {
|
|
384
|
-
gitSafe(["push", "origin"], root);
|
|
385
|
-
}
|
|
386
|
-
if (filesChanged === 0 && behind === 0 && aheadBefore === 0) {
|
|
387
|
-
return { action: "up-to-date", message: "Already in sync.", remote: existingRemote, files_changed: 0 };
|
|
388
|
-
}
|
|
389
|
-
const parts = [];
|
|
390
|
-
if (filesChanged > 0) parts.push(`${filesChanged} file(s) committed`);
|
|
391
|
-
if (behind > 0) parts.push(`pulled ${behind} remote commit(s)`);
|
|
392
|
-
if (aheadAfter === 0 && aheadBefore > 0) parts.push("pushed");
|
|
393
|
-
return {
|
|
394
|
-
action: "synced",
|
|
395
|
-
message: `Synced. ${parts.join(", ")}.`,
|
|
396
|
-
remote: existingRemote,
|
|
397
|
-
files_changed: filesChanged
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
function atomicWrite(filePath, content) {
|
|
401
|
-
const dir = dirname(filePath);
|
|
402
|
-
if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
|
|
403
|
-
const tmp = filePath + ".tmp";
|
|
404
|
-
writeFileSync(tmp, content);
|
|
405
|
-
renameSync(tmp, filePath);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
259
|
// src/engrams.ts
|
|
409
260
|
function loadEngrams(filePath) {
|
|
410
261
|
if (!fs.existsSync(filePath)) return [];
|
|
@@ -475,68 +326,6 @@ function generateEngramId(existing) {
|
|
|
475
326
|
return `${prefix}${String(next).padStart(3, "0")}`;
|
|
476
327
|
}
|
|
477
328
|
|
|
478
|
-
// src/fts.ts
|
|
479
|
-
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
480
|
-
"the",
|
|
481
|
-
"and",
|
|
482
|
-
"for",
|
|
483
|
-
"that",
|
|
484
|
-
"this",
|
|
485
|
-
"with",
|
|
486
|
-
"from",
|
|
487
|
-
"are",
|
|
488
|
-
"was",
|
|
489
|
-
"were",
|
|
490
|
-
"been",
|
|
491
|
-
"have",
|
|
492
|
-
"has",
|
|
493
|
-
"not",
|
|
494
|
-
"but",
|
|
495
|
-
"its",
|
|
496
|
-
"you",
|
|
497
|
-
"your",
|
|
498
|
-
"can",
|
|
499
|
-
"will",
|
|
500
|
-
"should",
|
|
501
|
-
"would",
|
|
502
|
-
"could",
|
|
503
|
-
"may",
|
|
504
|
-
"might"
|
|
505
|
-
]);
|
|
506
|
-
function ftsTokenize(text) {
|
|
507
|
-
return text.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 2).filter((w) => !STOP_WORDS.has(w));
|
|
508
|
-
}
|
|
509
|
-
function engramSearchText(engram) {
|
|
510
|
-
const parts = [engram.statement];
|
|
511
|
-
if (engram.domain) parts.push(engram.domain.replace(/\./g, " "));
|
|
512
|
-
if (engram.tags.length > 0) parts.push(engram.tags.join(" "));
|
|
513
|
-
if (engram.entities) {
|
|
514
|
-
for (const e of engram.entities) {
|
|
515
|
-
parts.push(e.name);
|
|
516
|
-
if (e.type !== "other") parts.push(e.type);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
if (engram.temporal) {
|
|
520
|
-
if (engram.temporal.valid_from) parts.push(engram.temporal.valid_from);
|
|
521
|
-
if (engram.temporal.valid_until) parts.push(engram.temporal.valid_until);
|
|
522
|
-
}
|
|
523
|
-
if (engram.rationale) parts.push(engram.rationale);
|
|
524
|
-
return parts.join(" ");
|
|
525
|
-
}
|
|
526
|
-
function ftsScore(engram, queryTokens) {
|
|
527
|
-
const allTerms = ftsTokenize(engramSearchText(engram));
|
|
528
|
-
let matches = 0;
|
|
529
|
-
for (const qt of queryTokens) {
|
|
530
|
-
if (allTerms.some((t) => t.includes(qt) || qt.includes(t))) matches++;
|
|
531
|
-
}
|
|
532
|
-
return queryTokens.length > 0 ? matches / queryTokens.length : 0;
|
|
533
|
-
}
|
|
534
|
-
function searchEngrams(engrams, query, limit = 20) {
|
|
535
|
-
const queryTokens = ftsTokenize(query);
|
|
536
|
-
if (queryTokens.length === 0) return [];
|
|
537
|
-
return engrams.map((e) => ({ engram: e, score: ftsScore(e, queryTokens) })).filter((r) => r.score > 0).sort((a, b) => b.score - a.score).slice(0, limit).map((r) => r.engram);
|
|
538
|
-
}
|
|
539
|
-
|
|
540
329
|
// src/decay.ts
|
|
541
330
|
var DECAY_RATE = 0.05;
|
|
542
331
|
var FLOOR = 0.05;
|
|
@@ -557,6 +346,53 @@ function decayedCoAccessStrength(strength, daysSinceUpdate, lambda = 0.01) {
|
|
|
557
346
|
return floor + (strength - floor) * Math.exp(-lambda * daysSinceUpdate);
|
|
558
347
|
}
|
|
559
348
|
|
|
349
|
+
// src/polarity.ts
|
|
350
|
+
var DONT_PATTERNS = [
|
|
351
|
+
/\bnever\b/i,
|
|
352
|
+
/\bdo\s+not\b/i,
|
|
353
|
+
/\bdon'?t\b/i,
|
|
354
|
+
/\bavoid\b/i,
|
|
355
|
+
/\bmust\s+not\b/i,
|
|
356
|
+
/\bshould\s+not\b/i,
|
|
357
|
+
/\bNOT\b.*?\b(?:include|use|run|start|create|add|send|describe|reference|assume)\b/,
|
|
358
|
+
/\bstop\b.*?\b(?:generating|iterating|doing|running|creating)\b/i
|
|
359
|
+
];
|
|
360
|
+
function classifyPolarity(statement) {
|
|
361
|
+
if (!statement || statement.length < 5) return null;
|
|
362
|
+
const dotIndex = statement.indexOf(".");
|
|
363
|
+
const firstSentence = statement.slice(0, dotIndex > 0 ? Math.min(dotIndex, 200) : 200);
|
|
364
|
+
for (const pattern of DONT_PATTERNS) {
|
|
365
|
+
if (pattern.test(firstSentence)) return "dont";
|
|
366
|
+
}
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// src/confidence.ts
|
|
371
|
+
function computeConfidence(input) {
|
|
372
|
+
const fb = input.feedback_signals ?? { positive: 0, negative: 0, neutral: 0 };
|
|
373
|
+
const total = fb.positive + fb.negative + fb.neutral;
|
|
374
|
+
if (total === 0) return 0.5;
|
|
375
|
+
const netRatio = (fb.positive - fb.negative) / total;
|
|
376
|
+
const dampening = 1 - 1 / (total + 1);
|
|
377
|
+
const adjustedRatio = netRatio * dampening;
|
|
378
|
+
const steepness = 2;
|
|
379
|
+
const base = 1 / (1 + Math.exp(-steepness * adjustedRatio));
|
|
380
|
+
const consolidationBonus = input.consolidated ? 0.05 : 0;
|
|
381
|
+
return Math.min(1, Math.max(0, base + consolidationBonus));
|
|
382
|
+
}
|
|
383
|
+
function computeMetaConfidence(evidenceCount, domainCount, structuralDepth, validationRatio) {
|
|
384
|
+
const evidenceSignal = Math.min(evidenceCount / 5, 1) * 0.25;
|
|
385
|
+
const domainSignal = Math.min(domainCount / 3, 1) * 0.35;
|
|
386
|
+
const depthSignal = Math.min(structuralDepth / 3, 1) * 0.2;
|
|
387
|
+
const validationSignal = validationRatio * 0.2;
|
|
388
|
+
return evidenceSignal + domainSignal + depthSignal + validationSignal;
|
|
389
|
+
}
|
|
390
|
+
function confidenceBand(score) {
|
|
391
|
+
if (score >= 0.7) return "high";
|
|
392
|
+
if (score >= 0.4) return "medium";
|
|
393
|
+
return "low";
|
|
394
|
+
}
|
|
395
|
+
|
|
560
396
|
// src/inject.ts
|
|
561
397
|
var DEFAULT_MAX_TOKENS = 8e3;
|
|
562
398
|
var DEFAULT_MIN_RELEVANCE = 0.3;
|
|
@@ -614,7 +450,7 @@ function stripAssociations(engram) {
|
|
|
614
450
|
}
|
|
615
451
|
function stripScoring(engram) {
|
|
616
452
|
const { keyword_match: _, raw_score: _r, score: _s, ...rest } = engram;
|
|
617
|
-
return rest;
|
|
453
|
+
return { ...rest, confidence_score: computeConfidence(engram) };
|
|
618
454
|
}
|
|
619
455
|
function scoreEngram(engram, promptLower, promptWords, packMatchTerms, scopeFilter, isPack) {
|
|
620
456
|
if (scopeFilter) {
|
|
@@ -650,6 +486,8 @@ function scoreEngram(engram, promptLower, promptWords, packMatchTerms, scopeFilt
|
|
|
650
486
|
else if (netFeedback < 0) score *= Math.max(1 + netFeedback * 0.1, 0.5);
|
|
651
487
|
}
|
|
652
488
|
if (engram.consolidated) score *= 1.1;
|
|
489
|
+
const emotionalWeight = engram.episodic?.emotional_weight ?? 5;
|
|
490
|
+
score *= 1 + (emotionalWeight - 5) * 0.04;
|
|
653
491
|
return score;
|
|
654
492
|
}
|
|
655
493
|
function fillTokenBudget(scored, maxTokens) {
|
|
@@ -681,10 +519,13 @@ function selectAndSpread(ctx, personalEngrams, packs, config, embeddingBoosts) {
|
|
|
681
519
|
const promptWords = new Set(promptLower.split(/\W+/).filter((w) => w.length > 2));
|
|
682
520
|
const maxTokens = ctx.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
683
521
|
const minRelevance = ctx.minRelevance ?? DEFAULT_MIN_RELEVANCE;
|
|
522
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
684
523
|
const engramMap = /* @__PURE__ */ new Map();
|
|
685
524
|
const scored = [];
|
|
686
525
|
for (const engram of personalEngrams) {
|
|
687
526
|
if (engram.status !== "active") continue;
|
|
527
|
+
if (engram.temporal?.valid_until && engram.temporal.valid_until < today) continue;
|
|
528
|
+
if (engram.temporal?.valid_from && engram.temporal.valid_from > today) continue;
|
|
688
529
|
engramMap.set(engram.id, engram);
|
|
689
530
|
let raw = scoreEngram(engram, promptLower, promptWords, [], ctx.scope, false);
|
|
690
531
|
const embBoost = embeddingBoosts?.get(engram.id) ?? 0;
|
|
@@ -703,6 +544,8 @@ function selectAndSpread(ctx, personalEngrams, packs, config, embeddingBoosts) {
|
|
|
703
544
|
const matchTerms = packMeta.match_terms;
|
|
704
545
|
for (const engram of pack.engrams) {
|
|
705
546
|
if (engram.status !== "active") continue;
|
|
547
|
+
if (engram.temporal?.valid_until && engram.temporal.valid_until < today) continue;
|
|
548
|
+
if (engram.temporal?.valid_from && engram.temporal.valid_from > today) continue;
|
|
706
549
|
engramMap.set(engram.id, engram);
|
|
707
550
|
let raw = scoreEngram(engram, promptLower, promptWords, matchTerms, ctx.scope, true);
|
|
708
551
|
const embBoost = embeddingBoosts?.get(engram.id) ?? 0;
|
|
@@ -750,6 +593,7 @@ function selectAndSpread(ctx, personalEngrams, packs, config, embeddingBoosts) {
|
|
|
750
593
|
if (directives.length === 0 && dip19Pool.length === 0) {
|
|
751
594
|
return {
|
|
752
595
|
directives: [],
|
|
596
|
+
constraints: [],
|
|
753
597
|
consider: [],
|
|
754
598
|
tokens_used: { directives: 0, consider: 0 }
|
|
755
599
|
};
|
|
@@ -787,18 +631,29 @@ function selectAndSpread(ctx, personalEngrams, packs, config, embeddingBoosts) {
|
|
|
787
631
|
const allConsider = [...dip19Pool, ...spreadCandidates];
|
|
788
632
|
const agentDirectives = directives.map(stripAssociations);
|
|
789
633
|
const agentConsider = allConsider.map(stripAssociations);
|
|
790
|
-
const
|
|
634
|
+
const wireAll = agentDirectives.map(stripScoring);
|
|
791
635
|
const wireConsider = agentConsider.map(stripScoring);
|
|
636
|
+
const wireDirectives = [];
|
|
637
|
+
const wireConstraints = [];
|
|
638
|
+
for (const wire of wireAll) {
|
|
639
|
+
const polarity = wire.polarity ?? classifyPolarity(wire.statement);
|
|
640
|
+
if (polarity === "dont") {
|
|
641
|
+
wireConstraints.push(wire);
|
|
642
|
+
} else {
|
|
643
|
+
wireDirectives.push(wire);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
792
646
|
const considerTokens = dip19PoolTokens + spreadTokens;
|
|
793
647
|
return {
|
|
794
648
|
directives: wireDirectives,
|
|
649
|
+
constraints: wireConstraints,
|
|
795
650
|
consider: wireConsider,
|
|
796
651
|
tokens_used: { directives: directiveTokens, consider: considerTokens }
|
|
797
652
|
};
|
|
798
653
|
}
|
|
799
654
|
|
|
800
655
|
// src/episodes.ts
|
|
801
|
-
import { existsSync as
|
|
656
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
802
657
|
import yaml3 from "js-yaml";
|
|
803
658
|
function generateEpisodeId() {
|
|
804
659
|
const ts = Date.now();
|
|
@@ -833,7 +688,7 @@ function queryTimeline(path2, query) {
|
|
|
833
688
|
return episodes;
|
|
834
689
|
}
|
|
835
690
|
function loadEpisodes(path2) {
|
|
836
|
-
if (!
|
|
691
|
+
if (!existsSync4(path2)) return [];
|
|
837
692
|
try {
|
|
838
693
|
const raw = yaml3.load(readFileSync3(path2, "utf8"));
|
|
839
694
|
return Array.isArray(raw) ? raw : [];
|
|
@@ -905,86 +760,6 @@ Rules:
|
|
|
905
760
|
}
|
|
906
761
|
}
|
|
907
762
|
|
|
908
|
-
// src/embeddings.ts
|
|
909
|
-
import { existsSync as existsSync6, readFileSync as readFileSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
910
|
-
import { join as join3 } from "path";
|
|
911
|
-
import { createHash } from "crypto";
|
|
912
|
-
var embedPipeline = null;
|
|
913
|
-
var transformersUnavailable = false;
|
|
914
|
-
async function getEmbedder() {
|
|
915
|
-
if (transformersUnavailable) return null;
|
|
916
|
-
if (!embedPipeline) {
|
|
917
|
-
try {
|
|
918
|
-
const { pipeline } = await import("./transformers.node-PH5YK5EA.js");
|
|
919
|
-
embedPipeline = await pipeline("feature-extraction", "Xenova/bge-small-en-v1.5", {
|
|
920
|
-
dtype: "fp32"
|
|
921
|
-
});
|
|
922
|
-
} catch {
|
|
923
|
-
transformersUnavailable = true;
|
|
924
|
-
return null;
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
return embedPipeline;
|
|
928
|
-
}
|
|
929
|
-
async function embed(text) {
|
|
930
|
-
const embedder = await getEmbedder();
|
|
931
|
-
if (!embedder) return null;
|
|
932
|
-
const result = await embedder(text, { pooling: "cls", normalize: true });
|
|
933
|
-
return new Float32Array(result.data);
|
|
934
|
-
}
|
|
935
|
-
function cosineSimilarity(a, b) {
|
|
936
|
-
let dot = 0;
|
|
937
|
-
for (let i = 0; i < a.length; i++) dot += a[i] * b[i];
|
|
938
|
-
return dot;
|
|
939
|
-
}
|
|
940
|
-
function loadCache(cachePath) {
|
|
941
|
-
if (!existsSync6(cachePath)) return {};
|
|
942
|
-
try {
|
|
943
|
-
return JSON.parse(readFileSync4(cachePath, "utf8"));
|
|
944
|
-
} catch {
|
|
945
|
-
return {};
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
function saveCache(cachePath, cache2) {
|
|
949
|
-
const dir = cachePath.substring(0, cachePath.lastIndexOf("/"));
|
|
950
|
-
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
951
|
-
atomicWrite(cachePath, JSON.stringify(cache2));
|
|
952
|
-
}
|
|
953
|
-
function hashStatement(statement) {
|
|
954
|
-
return createHash("sha256").update(statement).digest("hex").slice(0, 16);
|
|
955
|
-
}
|
|
956
|
-
async function embeddingSearch(engrams, query, limit, storagePath) {
|
|
957
|
-
if (engrams.length === 0) return [];
|
|
958
|
-
const cachePath = storagePath ? join3(storagePath, ".embeddings-cache.json") : ".embeddings-cache.json";
|
|
959
|
-
const cache2 = loadCache(cachePath);
|
|
960
|
-
const queryEmbedding = await embed(query);
|
|
961
|
-
if (!queryEmbedding) {
|
|
962
|
-
return [];
|
|
963
|
-
}
|
|
964
|
-
const similarities = [];
|
|
965
|
-
for (const engram of engrams) {
|
|
966
|
-
const searchText = engramSearchText(engram);
|
|
967
|
-
const hash = hashStatement(searchText);
|
|
968
|
-
let engramEmbedding;
|
|
969
|
-
if (cache2[engram.id]?.hash === hash) {
|
|
970
|
-
engramEmbedding = new Float32Array(cache2[engram.id].embedding);
|
|
971
|
-
} else {
|
|
972
|
-
const emb = await embed(searchText);
|
|
973
|
-
if (!emb) return [];
|
|
974
|
-
engramEmbedding = emb;
|
|
975
|
-
cache2[engram.id] = {
|
|
976
|
-
hash,
|
|
977
|
-
embedding: Array.from(engramEmbedding)
|
|
978
|
-
};
|
|
979
|
-
}
|
|
980
|
-
const score = cosineSimilarity(queryEmbedding, engramEmbedding);
|
|
981
|
-
similarities.push({ engram, score });
|
|
982
|
-
}
|
|
983
|
-
saveCache(cachePath, cache2);
|
|
984
|
-
similarities.sort((a, b) => b.score - a.score);
|
|
985
|
-
return similarities.slice(0, limit).map((s) => s.engram);
|
|
986
|
-
}
|
|
987
|
-
|
|
988
763
|
// src/hybrid-search.ts
|
|
989
764
|
function rrfMerge(resultSets, k = 60) {
|
|
990
765
|
const scores = /* @__PURE__ */ new Map();
|
|
@@ -1183,6 +958,818 @@ ${manifest.description || ""}
|
|
|
1183
958
|
return { path: outputDir, engram_count: engrams.length };
|
|
1184
959
|
}
|
|
1185
960
|
|
|
961
|
+
// src/secrets.ts
|
|
962
|
+
var SECRET_PATTERNS = [
|
|
963
|
+
{ name: "aws_access_key", regex: /AKIA[0-9A-Z]{16}/ },
|
|
964
|
+
{ name: "aws_secret_key", regex: /(?:aws_secret_access_key|secret_access_key)\s*[=:]\s*[A-Za-z0-9/+=]{40}/i },
|
|
965
|
+
{ name: "generic_api_key", regex: /(?:^|[^a-z])(sk|pk)[-_][a-z0-9]{20,}/i },
|
|
966
|
+
{ name: "api_key_assignment", regex: /(?:api[_-]?key|api[_-]?secret|secret[_-]?key)\s*[=:]\s*\S{20,}/i },
|
|
967
|
+
{ name: "password_assignment", regex: /password\s*[=:]\s*\S{8,}/i },
|
|
968
|
+
{ name: "connection_string", regex: /(?:postgres|mysql|mongodb|redis):\/\/\S+/ },
|
|
969
|
+
{ name: "jwt", regex: /eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}/ },
|
|
970
|
+
{ name: "private_key", regex: /-----BEGIN\s+\S+\s+PRIVATE KEY-----/ },
|
|
971
|
+
{ name: "bearer_token", regex: /Bearer\s+[A-Za-z0-9._~+/=-]{20,}/ }
|
|
972
|
+
];
|
|
973
|
+
function detectSecrets(text) {
|
|
974
|
+
const matches = [];
|
|
975
|
+
for (const { name, regex } of SECRET_PATTERNS) {
|
|
976
|
+
const m = text.match(regex);
|
|
977
|
+
if (m) {
|
|
978
|
+
matches.push({ pattern: name, match: m[0].slice(0, 20) + "..." });
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
return matches;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
// src/meta/sanitize.ts
|
|
985
|
+
function sanitizeForPrompt(text) {
|
|
986
|
+
return text.replace(/```/g, "~~~").replace(/\n{3,}/g, "\n\n").replace(/^(system|assistant|user):/gim, "$1 -").slice(0, 2e3);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// src/meta/structural-analysis.ts
|
|
990
|
+
var FAILURE_TAGS = /* @__PURE__ */ new Set(["correction", "mistake", "bug", "fix", "error", "wrong", "broken"]);
|
|
991
|
+
var BATCH_SIZE = 5;
|
|
992
|
+
function isFailureDriven(engram) {
|
|
993
|
+
if (engram.tags.some((t) => FAILURE_TAGS.has(t.toLowerCase()))) return true;
|
|
994
|
+
const fb = engram.feedback_signals;
|
|
995
|
+
if (fb && fb.negative > fb.positive) return true;
|
|
996
|
+
return false;
|
|
997
|
+
}
|
|
998
|
+
function prioritize(engrams) {
|
|
999
|
+
return [...engrams].sort((a, b) => {
|
|
1000
|
+
const aFail = isFailureDriven(a) ? 0 : 1;
|
|
1001
|
+
const bFail = isFailureDriven(b) ? 0 : 1;
|
|
1002
|
+
if (aFail !== bFail) return aFail - bFail;
|
|
1003
|
+
const aFb = a.feedback_signals?.negative ?? 0;
|
|
1004
|
+
const bFb = b.feedback_signals?.negative ?? 0;
|
|
1005
|
+
return bFb - aFb;
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
function buildPrompt(engrams) {
|
|
1009
|
+
const items = engrams.map((e, i) => {
|
|
1010
|
+
const parts = [` Statement: "${sanitizeForPrompt(e.statement)}"`];
|
|
1011
|
+
if (e.rationale) parts.push(` Rationale: "${sanitizeForPrompt(e.rationale)}"`);
|
|
1012
|
+
if (e.domain) parts.push(` Domain: "${e.domain}"`);
|
|
1013
|
+
return `Engram ${i + 1} (${e.id}):
|
|
1014
|
+
${parts.join("\n")}`;
|
|
1015
|
+
}).join("\n\n");
|
|
1016
|
+
return `Given these learned lessons, extract relational structure for cross-domain transfer.
|
|
1017
|
+
|
|
1018
|
+
${items}
|
|
1019
|
+
|
|
1020
|
+
For EACH engram, extract:
|
|
1021
|
+
1. The GOAL the agent had (abstract type, not domain-specific)
|
|
1022
|
+
2. Relational triples: subject (role + domain instance), predicate, object (role + domain instance), outcome
|
|
1023
|
+
3. Use domain-GENERAL role types (e.g., "safety-metric" not "liquidation-price")
|
|
1024
|
+
|
|
1025
|
+
Return a JSON array with one object per engram:
|
|
1026
|
+
[{
|
|
1027
|
+
"engram_id": "ENG-...",
|
|
1028
|
+
"goal_context": "what the agent was trying to achieve (abstract)",
|
|
1029
|
+
"triples": [{ "subject": { "role": "...", "domain_instance": "..." }, "predicate": "...", "object": { "role": "...", "domain_instance": "..." }, "outcome": "..." }]
|
|
1030
|
+
}]
|
|
1031
|
+
|
|
1032
|
+
Rules:
|
|
1033
|
+
- Roles MUST be domain-general (e.g., "safety-metric" not "liquidation-price")
|
|
1034
|
+
- If a lesson is purely domain-specific with no transferable structure, return empty triples: []
|
|
1035
|
+
- Prefer causal chains over isolated attributes
|
|
1036
|
+
- Return ONLY valid JSON, no markdown fencing`;
|
|
1037
|
+
}
|
|
1038
|
+
async function analyzeStructure(engrams, llm) {
|
|
1039
|
+
const prioritized = prioritize(engrams.filter((e) => e.status === "active"));
|
|
1040
|
+
const results = [];
|
|
1041
|
+
for (let i = 0; i < prioritized.length; i += BATCH_SIZE) {
|
|
1042
|
+
const batch = prioritized.slice(i, i + BATCH_SIZE);
|
|
1043
|
+
const prompt = buildPrompt(batch);
|
|
1044
|
+
let parsed;
|
|
1045
|
+
try {
|
|
1046
|
+
const response = await llm(prompt);
|
|
1047
|
+
const cleaned = response.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
|
|
1048
|
+
parsed = JSON.parse(cleaned);
|
|
1049
|
+
} catch {
|
|
1050
|
+
try {
|
|
1051
|
+
const retryResponse = await llm(prompt + "\n\nIMPORTANT: Return ONLY raw JSON array, no text.");
|
|
1052
|
+
const cleaned = retryResponse.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
|
|
1053
|
+
parsed = JSON.parse(cleaned);
|
|
1054
|
+
} catch {
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
for (const item of parsed) {
|
|
1059
|
+
if (!item.triples || item.triples.length === 0) continue;
|
|
1060
|
+
const engram = batch.find((e) => e.id === item.engram_id) ?? batch[parsed.indexOf(item)];
|
|
1061
|
+
if (!engram) continue;
|
|
1062
|
+
results.push({
|
|
1063
|
+
engram_id: engram.id,
|
|
1064
|
+
triples: item.triples,
|
|
1065
|
+
goal_context: item.goal_context ?? "",
|
|
1066
|
+
is_failure_driven: isFailureDriven(engram),
|
|
1067
|
+
domain: engram.domain ?? "unknown",
|
|
1068
|
+
polarity: classifyPolarity(engram.statement) === "dont" ? "dont" : "do"
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
return results;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
// src/meta/similarity.ts
|
|
1076
|
+
function tokenSimilarity(a, b) {
|
|
1077
|
+
const wordsA = new Set(a.toLowerCase().split(/[\s\[\]→+\-]+/).filter((w) => w.length > 2));
|
|
1078
|
+
const wordsB = new Set(b.toLowerCase().split(/[\s\[\]→+\-]+/).filter((w) => w.length > 2));
|
|
1079
|
+
if (wordsA.size === 0 || wordsB.size === 0) return 0;
|
|
1080
|
+
let overlap = 0;
|
|
1081
|
+
for (const w of wordsA) {
|
|
1082
|
+
if (wordsB.has(w)) overlap++;
|
|
1083
|
+
}
|
|
1084
|
+
return overlap / Math.sqrt(wordsA.size * wordsB.size);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// src/meta/clustering.ts
|
|
1088
|
+
function tripleToTemplate(triple) {
|
|
1089
|
+
const parts = [triple.subject.role, triple.predicate, triple.object.role];
|
|
1090
|
+
if (triple.outcome) parts.push("\u2192", triple.outcome);
|
|
1091
|
+
return parts.join(" ");
|
|
1092
|
+
}
|
|
1093
|
+
function analysisTemplate(analysis) {
|
|
1094
|
+
return analysis.triples.map(tripleToTemplate).join("; ");
|
|
1095
|
+
}
|
|
1096
|
+
async function computeSimilarityMatrix(templates) {
|
|
1097
|
+
const n = templates.length;
|
|
1098
|
+
const matrix = Array.from({ length: n }, () => Array(n).fill(0));
|
|
1099
|
+
try {
|
|
1100
|
+
const { embed, cosineSimilarity } = await import("./embeddings-Q76LNQ5B.js");
|
|
1101
|
+
const embeddings = [];
|
|
1102
|
+
for (const t of templates) {
|
|
1103
|
+
embeddings.push(await embed(t));
|
|
1104
|
+
}
|
|
1105
|
+
if (embeddings[0] !== null) {
|
|
1106
|
+
for (let i = 0; i < n; i++) {
|
|
1107
|
+
for (let j = i + 1; j < n; j++) {
|
|
1108
|
+
if (embeddings[i] && embeddings[j]) {
|
|
1109
|
+
const sim = cosineSimilarity(embeddings[i], embeddings[j]);
|
|
1110
|
+
matrix[i][j] = sim;
|
|
1111
|
+
matrix[j][i] = sim;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
return { matrix, method: "embedding" };
|
|
1116
|
+
}
|
|
1117
|
+
} catch {
|
|
1118
|
+
}
|
|
1119
|
+
for (let i = 0; i < n; i++) {
|
|
1120
|
+
for (let j = i + 1; j < n; j++) {
|
|
1121
|
+
const sim = tokenSimilarity(templates[i], templates[j]);
|
|
1122
|
+
matrix[i][j] = sim;
|
|
1123
|
+
matrix[j][i] = sim;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
return { matrix, method: "token" };
|
|
1127
|
+
}
|
|
1128
|
+
var EMBEDDING_THRESHOLD = 0.65;
|
|
1129
|
+
var TOKEN_THRESHOLD = 0.35;
|
|
1130
|
+
async function clusterByStructure(analyses, threshold2) {
|
|
1131
|
+
if (analyses.length < 2) return [];
|
|
1132
|
+
const templates = analyses.map((a) => analysisTemplate(a));
|
|
1133
|
+
const { matrix, method } = await computeSimilarityMatrix(templates);
|
|
1134
|
+
const effectiveThreshold = threshold2 ?? (method === "embedding" ? EMBEDDING_THRESHOLD : TOKEN_THRESHOLD);
|
|
1135
|
+
const seenClusters = /* @__PURE__ */ new Set();
|
|
1136
|
+
const clusters = [];
|
|
1137
|
+
let clusterId = 0;
|
|
1138
|
+
for (let i = 0; i < analyses.length; i++) {
|
|
1139
|
+
const members = [analyses[i]];
|
|
1140
|
+
const memberIndices = [i];
|
|
1141
|
+
for (let j = 0; j < analyses.length; j++) {
|
|
1142
|
+
if (j === i) continue;
|
|
1143
|
+
if (matrix[i][j] >= effectiveThreshold) {
|
|
1144
|
+
members.push(analyses[j]);
|
|
1145
|
+
memberIndices.push(j);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
if (members.length < 2) continue;
|
|
1149
|
+
const memberKey = members.map((m) => m.engram_id).sort().join(",");
|
|
1150
|
+
if (seenClusters.has(memberKey)) continue;
|
|
1151
|
+
seenClusters.add(memberKey);
|
|
1152
|
+
const domains = [...new Set(members.map((m) => m.domain))];
|
|
1153
|
+
let totalSim = 0;
|
|
1154
|
+
let pairs = 0;
|
|
1155
|
+
for (let a = 0; a < memberIndices.length; a++) {
|
|
1156
|
+
for (let b = a + 1; b < memberIndices.length; b++) {
|
|
1157
|
+
totalSim += matrix[memberIndices[a]][memberIndices[b]];
|
|
1158
|
+
pairs++;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
clusters.push({
|
|
1162
|
+
cluster_id: `cluster-${clusterId++}`,
|
|
1163
|
+
members,
|
|
1164
|
+
domains,
|
|
1165
|
+
is_cross_domain: domains.length >= 2,
|
|
1166
|
+
cohesion: pairs > 0 ? totalSim / pairs : 0
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
return clusters;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
// src/meta/platitudes.ts
|
|
1173
|
+
var PLATITUDE_PATTERNS = [
|
|
1174
|
+
"always be careful",
|
|
1175
|
+
"verify before acting",
|
|
1176
|
+
"plan ahead",
|
|
1177
|
+
"consider edge cases",
|
|
1178
|
+
"communicate clearly",
|
|
1179
|
+
"test thoroughly",
|
|
1180
|
+
"keep it simple",
|
|
1181
|
+
"document your work",
|
|
1182
|
+
"think before you act",
|
|
1183
|
+
"double check"
|
|
1184
|
+
];
|
|
1185
|
+
function isPlatitude(statement) {
|
|
1186
|
+
const lower = statement.toLowerCase();
|
|
1187
|
+
return PLATITUDE_PATTERNS.some((p) => lower.includes(p)) || statement.length < 30;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
// src/meta/alignment.ts
|
|
1191
|
+
async function alignCluster(cluster, llm) {
|
|
1192
|
+
const tripleDescriptions = cluster.members.map((m) => {
|
|
1193
|
+
const domain = sanitizeForPrompt(m.domain);
|
|
1194
|
+
const triples = m.triples.map((t) => {
|
|
1195
|
+
const parts = [`${sanitizeForPrompt(t.subject.role)} ${sanitizeForPrompt(t.predicate)} ${sanitizeForPrompt(t.object.role)}`];
|
|
1196
|
+
if (t.outcome) parts.push(`\u2192 ${sanitizeForPrompt(t.outcome)}`);
|
|
1197
|
+
return parts.join(" ");
|
|
1198
|
+
}).join("; ");
|
|
1199
|
+
return `Domain ${domain} (${m.engram_id}): ${triples}`;
|
|
1200
|
+
}).join("\n");
|
|
1201
|
+
const prompt = `These lessons come from different domains but may share a common structural principle:
|
|
1202
|
+
|
|
1203
|
+
${tripleDescriptions}
|
|
1204
|
+
|
|
1205
|
+
Tasks:
|
|
1206
|
+
1. Is there a genuine common relational structure? (Not surface similarity, not a platitude)
|
|
1207
|
+
2. Choose the structural frame that BEST captures the pattern:
|
|
1208
|
+
- "goal-constraint-outcome": [goal] + [constraint] \u2192 [outcome]
|
|
1209
|
+
- "feedback-loop": [action] \u2192 [effect] \u2192 [feeds back to action]
|
|
1210
|
+
- "causal-chain": [A] causes [B] causes [C]
|
|
1211
|
+
- "tradeoff": [optimizing X] at the expense of [Y]
|
|
1212
|
+
- "recursive": [pattern] contains smaller instances of [same pattern]
|
|
1213
|
+
- "freeform": describe the structure in your own terms
|
|
1214
|
+
3. Express the common structure using your chosen frame
|
|
1215
|
+
4. Rate structural depth (1-5): 1=surface, 3=causal chain, 5=deep systematic
|
|
1216
|
+
5. For each member, rate alignment (0-1) and explain the mapping in one sentence
|
|
1217
|
+
6. What does this structure PREDICT in a domain not listed above?
|
|
1218
|
+
|
|
1219
|
+
Return JSON:
|
|
1220
|
+
{
|
|
1221
|
+
"common_structure": {
|
|
1222
|
+
"goal_type": "...",
|
|
1223
|
+
"constraint_type": "...",
|
|
1224
|
+
"outcome_type": "...",
|
|
1225
|
+
"template": "...",
|
|
1226
|
+
"structure_type": "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "tradeoff" | "recursive" | "freeform",
|
|
1227
|
+
"freeform_structure": "..." (only if structure_type is "freeform")
|
|
1228
|
+
} | null,
|
|
1229
|
+
"structural_depth": N,
|
|
1230
|
+
"member_alignments": [{ "engram_id": "...", "alignment_score": N, "mapping_rationale": "..." }],
|
|
1231
|
+
"candidate_inferences": ["..."]
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
If the commonality is shallow or trivially obvious (e.g., "mistakes happen", "always be careful"), return null for common_structure. We prefer no extraction over a false abstraction.
|
|
1235
|
+
Return ONLY valid JSON, no markdown fencing.`;
|
|
1236
|
+
try {
|
|
1237
|
+
const response = await llm(prompt);
|
|
1238
|
+
const cleaned = response.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
|
|
1239
|
+
if (cleaned === "null" || cleaned === '{"common_structure": null}') return null;
|
|
1240
|
+
const parsed = JSON.parse(cleaned);
|
|
1241
|
+
if (!parsed.common_structure) return null;
|
|
1242
|
+
if (parsed.structural_depth < 2) return null;
|
|
1243
|
+
if (isPlatitude(parsed.common_structure.template)) return null;
|
|
1244
|
+
if (parsed.common_structure.template.length < 30) return null;
|
|
1245
|
+
const alignments = parsed.member_alignments ?? [];
|
|
1246
|
+
const lowAlignments = alignments.filter((a) => a.alignment_score < 0.5);
|
|
1247
|
+
if (lowAlignments.length > alignments.length / 2) return null;
|
|
1248
|
+
return {
|
|
1249
|
+
cluster_id: cluster.cluster_id,
|
|
1250
|
+
common_structure: parsed.common_structure,
|
|
1251
|
+
member_alignments: alignments,
|
|
1252
|
+
structural_depth: parsed.structural_depth,
|
|
1253
|
+
systematicity: parsed.structural_depth,
|
|
1254
|
+
// Use depth as systematicity proxy
|
|
1255
|
+
candidate_inferences: parsed.candidate_inferences ?? []
|
|
1256
|
+
};
|
|
1257
|
+
} catch {
|
|
1258
|
+
return null;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// src/meta/formulation.ts
|
|
1263
|
+
var PIPELINE_VERSION = "1.0.0";
|
|
1264
|
+
function slugifyTemplate(template) {
|
|
1265
|
+
return template.toLowerCase().replace(/[\[\]→+]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
1266
|
+
}
|
|
1267
|
+
function isDuplicate(template, existingMetas) {
|
|
1268
|
+
for (const meta of existingMetas) {
|
|
1269
|
+
const metaField = meta.structured_data?.meta;
|
|
1270
|
+
if (!metaField?.structure?.template) continue;
|
|
1271
|
+
const sim = tokenSimilarity(template, metaField.structure.template);
|
|
1272
|
+
if (sim > 0.9) return meta;
|
|
1273
|
+
}
|
|
1274
|
+
return null;
|
|
1275
|
+
}
|
|
1276
|
+
async function formulateMetaEngram(alignment, llm, existingMetas = [], domains = []) {
|
|
1277
|
+
const { common_structure, member_alignments, structural_depth, candidate_inferences } = alignment;
|
|
1278
|
+
if (isPlatitude(common_structure.template)) return null;
|
|
1279
|
+
const memberSummary = member_alignments.map((m) => ` - ${m.engram_id}: ${sanitizeForPrompt(m.mapping_rationale)} (alignment: ${m.alignment_score})`).join("\n");
|
|
1280
|
+
const prompt = `Structural principle: ${sanitizeForPrompt(common_structure.template)}
|
|
1281
|
+
Goal type: ${common_structure.goal_type}
|
|
1282
|
+
Constraint type: ${common_structure.constraint_type}
|
|
1283
|
+
Outcome type: ${common_structure.outcome_type}
|
|
1284
|
+
Structural depth: ${structural_depth}
|
|
1285
|
+
Evidence from members:
|
|
1286
|
+
${memberSummary}
|
|
1287
|
+
Candidate inferences: ${candidate_inferences.map(sanitizeForPrompt).join(", ")}
|
|
1288
|
+
|
|
1289
|
+
Generate:
|
|
1290
|
+
1. A natural-language statement of this principle (1-2 sentences, precise, not generic)
|
|
1291
|
+
2. Conditions under which it holds (expected_conditions)
|
|
1292
|
+
3. Conditions under which it does NOT hold (expected_exceptions)
|
|
1293
|
+
4. A concrete test: pick a domain NOT in the evidence list, describe a scenario where this principle predicts a specific outcome (test_prediction)
|
|
1294
|
+
|
|
1295
|
+
The statement must be specific enough to be FALSIFIABLE. If you cannot write falsification criteria, return null.
|
|
1296
|
+
|
|
1297
|
+
Return JSON:
|
|
1298
|
+
{
|
|
1299
|
+
"statement": "...",
|
|
1300
|
+
"falsification": {
|
|
1301
|
+
"expected_conditions": "...",
|
|
1302
|
+
"expected_exceptions": "...",
|
|
1303
|
+
"test_prediction": "..."
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
Or return null if the principle is too vague to falsify.
|
|
1308
|
+
Return ONLY valid JSON, no markdown fencing.`;
|
|
1309
|
+
let parsed;
|
|
1310
|
+
try {
|
|
1311
|
+
const response = await llm(prompt);
|
|
1312
|
+
const cleaned = response.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
|
|
1313
|
+
if (cleaned === "null") return null;
|
|
1314
|
+
parsed = JSON.parse(cleaned);
|
|
1315
|
+
} catch {
|
|
1316
|
+
return null;
|
|
1317
|
+
}
|
|
1318
|
+
if (!parsed || !parsed.statement || !parsed.falsification) return null;
|
|
1319
|
+
if (!parsed.falsification.expected_conditions || !parsed.falsification.expected_exceptions) return null;
|
|
1320
|
+
const duplicate = isDuplicate(common_structure.template, existingMetas);
|
|
1321
|
+
if (duplicate) {
|
|
1322
|
+
return null;
|
|
1323
|
+
}
|
|
1324
|
+
const evidenceCount = member_alignments.length;
|
|
1325
|
+
const domainCount = domains.length > 0 ? domains.length : 1;
|
|
1326
|
+
const validationRatio = 0;
|
|
1327
|
+
const composite = computeMetaConfidence(evidenceCount, domainCount, structural_depth, validationRatio);
|
|
1328
|
+
const slug = slugifyTemplate(common_structure.template);
|
|
1329
|
+
const id = `META-${slug}`;
|
|
1330
|
+
const evidence = member_alignments.map((ma) => ({
|
|
1331
|
+
engram_id: ma.engram_id,
|
|
1332
|
+
domain: "unknown",
|
|
1333
|
+
// Will be enriched by pipeline orchestrator
|
|
1334
|
+
mapping_rationale: ma.mapping_rationale,
|
|
1335
|
+
alignment_score: ma.alignment_score
|
|
1336
|
+
}));
|
|
1337
|
+
const metaField = {
|
|
1338
|
+
structure: common_structure,
|
|
1339
|
+
evidence,
|
|
1340
|
+
domain_coverage: {
|
|
1341
|
+
validated: [],
|
|
1342
|
+
failed: [],
|
|
1343
|
+
predicted: candidate_inferences
|
|
1344
|
+
},
|
|
1345
|
+
falsification: parsed.falsification,
|
|
1346
|
+
confidence: {
|
|
1347
|
+
evidence_count: evidenceCount,
|
|
1348
|
+
domain_count: domainCount,
|
|
1349
|
+
structural_depth,
|
|
1350
|
+
validation_ratio: validationRatio,
|
|
1351
|
+
composite
|
|
1352
|
+
},
|
|
1353
|
+
hierarchy: {
|
|
1354
|
+
level: domainCount >= 3 ? "top" : "mop",
|
|
1355
|
+
parent: null,
|
|
1356
|
+
children: []
|
|
1357
|
+
},
|
|
1358
|
+
pipeline_version: PIPELINE_VERSION
|
|
1359
|
+
};
|
|
1360
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1361
|
+
const engram = {
|
|
1362
|
+
id,
|
|
1363
|
+
version: 2,
|
|
1364
|
+
status: "active",
|
|
1365
|
+
consolidated: false,
|
|
1366
|
+
type: "behavioral",
|
|
1367
|
+
scope: "global",
|
|
1368
|
+
visibility: "private",
|
|
1369
|
+
statement: parsed.statement,
|
|
1370
|
+
domain: "meta",
|
|
1371
|
+
tags: ["meta-engram", common_structure.goal_type, common_structure.constraint_type],
|
|
1372
|
+
activation: {
|
|
1373
|
+
retrieval_strength: composite,
|
|
1374
|
+
storage_strength: 1,
|
|
1375
|
+
frequency: 0,
|
|
1376
|
+
last_accessed: now.slice(0, 10)
|
|
1377
|
+
},
|
|
1378
|
+
feedback_signals: { positive: 0, negative: 0, neutral: 0 },
|
|
1379
|
+
knowledge_anchors: [],
|
|
1380
|
+
associations: [],
|
|
1381
|
+
derivation_count: evidenceCount,
|
|
1382
|
+
pack: null,
|
|
1383
|
+
abstract: null,
|
|
1384
|
+
derived_from: null,
|
|
1385
|
+
polarity: null,
|
|
1386
|
+
knowledge_type: {
|
|
1387
|
+
memory_class: "metacognitive",
|
|
1388
|
+
cognitive_level: "evaluate"
|
|
1389
|
+
},
|
|
1390
|
+
structured_data: { meta: metaField }
|
|
1391
|
+
};
|
|
1392
|
+
return engram;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
// src/meta/validation.ts
|
|
1396
|
+
async function validateMetaEngram(meta, testEngrams, testDomain, llm) {
|
|
1397
|
+
const metaField = meta.structured_data?.meta;
|
|
1398
|
+
if (!metaField) {
|
|
1399
|
+
return {
|
|
1400
|
+
meta_engram_id: meta.id,
|
|
1401
|
+
test_domain: testDomain,
|
|
1402
|
+
prediction_held: false,
|
|
1403
|
+
matching_engram_id: null,
|
|
1404
|
+
alignment_score: 0,
|
|
1405
|
+
rationale: "Meta-engram has no meta field"
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
const template = metaField.structure.template;
|
|
1409
|
+
const testEngramSummary = testEngrams.filter((e) => e.status === "active").slice(0, 10).map((e) => ` - [${e.id}] ${sanitizeForPrompt(e.statement)}`).join("\n");
|
|
1410
|
+
if (!testEngramSummary) {
|
|
1411
|
+
return {
|
|
1412
|
+
meta_engram_id: meta.id,
|
|
1413
|
+
test_domain: testDomain,
|
|
1414
|
+
prediction_held: false,
|
|
1415
|
+
matching_engram_id: null,
|
|
1416
|
+
alignment_score: 0,
|
|
1417
|
+
rationale: "No test engrams available for validation"
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1420
|
+
const prompt = `Meta-engram structural principle: ${sanitizeForPrompt(template)}
|
|
1421
|
+
Meta-engram statement: ${sanitizeForPrompt(meta.statement)}
|
|
1422
|
+
|
|
1423
|
+
Test domain: ${testDomain}
|
|
1424
|
+
Test engrams from this domain:
|
|
1425
|
+
${testEngramSummary}
|
|
1426
|
+
|
|
1427
|
+
Task: Does any of the test engrams instantiate or validate this structural principle?
|
|
1428
|
+
|
|
1429
|
+
If YES (a test engram matches):
|
|
1430
|
+
- prediction_held: true
|
|
1431
|
+
- matching_engram_id: the ID of the matching engram
|
|
1432
|
+
- alignment_score: 0.5-1.0 (how well the structural template maps)
|
|
1433
|
+
- rationale: one sentence explaining how the test engram maps to the template
|
|
1434
|
+
|
|
1435
|
+
If NO (no test engram matches):
|
|
1436
|
+
- prediction_held: false
|
|
1437
|
+
- matching_engram_id: null
|
|
1438
|
+
- alignment_score: 0
|
|
1439
|
+
- rationale: one sentence explaining WHY none of the test engrams match (e.g., "Test engrams cover X domain but none exhibit the structural pattern of [assumed independence] \u2192 [understated risk]")
|
|
1440
|
+
|
|
1441
|
+
Return JSON:
|
|
1442
|
+
{
|
|
1443
|
+
"prediction_held": true|false,
|
|
1444
|
+
"matching_engram_id": "ENG-..." | null,
|
|
1445
|
+
"alignment_score": 0.0-1.0,
|
|
1446
|
+
"rationale": "one sentence explanation \u2014 REQUIRED even when prediction_held is false"
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
Return ONLY valid JSON, no markdown fencing.`;
|
|
1450
|
+
try {
|
|
1451
|
+
const response = await llm(prompt);
|
|
1452
|
+
const cleaned = response.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
|
|
1453
|
+
const parsed = JSON.parse(cleaned);
|
|
1454
|
+
const result = {
|
|
1455
|
+
meta_engram_id: meta.id,
|
|
1456
|
+
test_domain: testDomain,
|
|
1457
|
+
prediction_held: Boolean(parsed.prediction_held),
|
|
1458
|
+
matching_engram_id: parsed.matching_engram_id ?? null,
|
|
1459
|
+
alignment_score: typeof parsed.alignment_score === "number" ? parsed.alignment_score : 0,
|
|
1460
|
+
rationale: parsed.rationale ?? ""
|
|
1461
|
+
};
|
|
1462
|
+
if (result.prediction_held) {
|
|
1463
|
+
if (!metaField.domain_coverage.validated.includes(testDomain)) {
|
|
1464
|
+
metaField.domain_coverage.validated.push(testDomain);
|
|
1465
|
+
}
|
|
1466
|
+
} else {
|
|
1467
|
+
if (!metaField.domain_coverage.failed.includes(testDomain)) {
|
|
1468
|
+
metaField.domain_coverage.failed.push(testDomain);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
const passes = metaField.domain_coverage.validated.length;
|
|
1472
|
+
const total = passes + metaField.domain_coverage.failed.length;
|
|
1473
|
+
const validationRatio = total > 0 ? passes / total : 0;
|
|
1474
|
+
const updatedComposite = computeMetaConfidence(
|
|
1475
|
+
metaField.confidence.evidence_count,
|
|
1476
|
+
metaField.confidence.domain_count,
|
|
1477
|
+
metaField.confidence.structural_depth,
|
|
1478
|
+
validationRatio
|
|
1479
|
+
);
|
|
1480
|
+
metaField.confidence.validation_ratio = validationRatio;
|
|
1481
|
+
metaField.confidence.composite = updatedComposite;
|
|
1482
|
+
metaField.last_validated = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1483
|
+
const failedCount = metaField.domain_coverage.failed.length;
|
|
1484
|
+
if (failedCount >= 3) {
|
|
1485
|
+
if (metaField.hierarchy.level === "top") {
|
|
1486
|
+
metaField.hierarchy.level = "mop";
|
|
1487
|
+
} else {
|
|
1488
|
+
meta.status = "retired";
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
return result;
|
|
1492
|
+
} catch {
|
|
1493
|
+
return {
|
|
1494
|
+
meta_engram_id: meta.id,
|
|
1495
|
+
test_domain: testDomain,
|
|
1496
|
+
prediction_held: false,
|
|
1497
|
+
matching_engram_id: null,
|
|
1498
|
+
alignment_score: 0,
|
|
1499
|
+
rationale: "LLM parsing failed during validation"
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
// src/meta/hierarchy.ts
|
|
1505
|
+
var SUBSUMPTION_THRESHOLD = 0.75;
|
|
1506
|
+
function getMetaField(engram) {
|
|
1507
|
+
return engram.structured_data?.meta ?? null;
|
|
1508
|
+
}
|
|
1509
|
+
function getDomainCount(metaField) {
|
|
1510
|
+
const validated = metaField.domain_coverage.validated.length;
|
|
1511
|
+
const evidenceDomains = new Set(metaField.evidence.map((e) => e.domain)).size;
|
|
1512
|
+
return Math.max(validated, evidenceDomains, metaField.confidence.domain_count);
|
|
1513
|
+
}
|
|
1514
|
+
function organizeHierarchy(metaEngrams) {
|
|
1515
|
+
const metas = metaEngrams.filter((e) => getMetaField(e) !== null && e.id.startsWith("META-"));
|
|
1516
|
+
if (metas.length === 0) return metaEngrams;
|
|
1517
|
+
for (const meta of metas) {
|
|
1518
|
+
const mf = getMetaField(meta);
|
|
1519
|
+
mf.hierarchy.parent = null;
|
|
1520
|
+
mf.hierarchy.children = [];
|
|
1521
|
+
}
|
|
1522
|
+
for (let i = 0; i < metas.length; i++) {
|
|
1523
|
+
for (let j = 0; j < metas.length; j++) {
|
|
1524
|
+
if (i === j) continue;
|
|
1525
|
+
const mfI = getMetaField(metas[i]);
|
|
1526
|
+
const mfJ = getMetaField(metas[j]);
|
|
1527
|
+
const sim = tokenSimilarity(mfI.structure.template, mfJ.structure.template);
|
|
1528
|
+
if (sim < SUBSUMPTION_THRESHOLD) continue;
|
|
1529
|
+
const domainsI = getDomainCount(mfI);
|
|
1530
|
+
const domainsJ = getDomainCount(mfJ);
|
|
1531
|
+
if (domainsI > domainsJ) {
|
|
1532
|
+
if (!mfI.hierarchy.children.includes(metas[j].id)) {
|
|
1533
|
+
mfI.hierarchy.children.push(metas[j].id);
|
|
1534
|
+
}
|
|
1535
|
+
if (!mfJ.hierarchy.parent) {
|
|
1536
|
+
mfJ.hierarchy.parent = metas[i].id;
|
|
1537
|
+
} else {
|
|
1538
|
+
const currentParent = metas.find((m) => m.id === mfJ.hierarchy.parent);
|
|
1539
|
+
const currentParentMf = currentParent ? getMetaField(currentParent) : null;
|
|
1540
|
+
if (currentParentMf && getDomainCount(currentParentMf) < domainsI) {
|
|
1541
|
+
mfJ.hierarchy.parent = metas[i].id;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
for (const meta of metas) {
|
|
1548
|
+
const mf = getMetaField(meta);
|
|
1549
|
+
const domains = getDomainCount(mf);
|
|
1550
|
+
if (domains >= 3 && !mf.hierarchy.parent) {
|
|
1551
|
+
mf.hierarchy.level = "top";
|
|
1552
|
+
} else {
|
|
1553
|
+
mf.hierarchy.level = "mop";
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
return metaEngrams;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
// src/meta/pipeline.ts
|
|
1560
|
+
async function extractMetaEngrams(engrams, llm, options = {}) {
|
|
1561
|
+
const start = Date.now();
|
|
1562
|
+
const {
|
|
1563
|
+
run_validation = false,
|
|
1564
|
+
validation_engrams = [],
|
|
1565
|
+
existing_metas = [],
|
|
1566
|
+
min_cluster_size = 2
|
|
1567
|
+
} = options;
|
|
1568
|
+
let rejected_as_platitudes = 0;
|
|
1569
|
+
const analyses = await analyzeStructure(engrams, llm);
|
|
1570
|
+
const clusters = await clusterByStructure(analyses);
|
|
1571
|
+
const viableClusters = clusters.filter((c) => c.members.length >= min_cluster_size);
|
|
1572
|
+
const alignmentResults = await Promise.all(
|
|
1573
|
+
viableClusters.map((cluster) => alignCluster(cluster, llm))
|
|
1574
|
+
);
|
|
1575
|
+
const validAlignments = alignmentResults.filter((r) => r !== null);
|
|
1576
|
+
const formulated = [];
|
|
1577
|
+
for (const alignment of validAlignments) {
|
|
1578
|
+
const cluster = viableClusters.find((c) => c.cluster_id === alignment.cluster_id);
|
|
1579
|
+
const clusterDomains = cluster ? [...new Set(cluster.members.map((m) => m.domain))] : [];
|
|
1580
|
+
const meta = await formulateMetaEngram(alignment, llm, [...existing_metas, ...formulated], clusterDomains);
|
|
1581
|
+
if (meta === null) {
|
|
1582
|
+
rejected_as_platitudes++;
|
|
1583
|
+
} else {
|
|
1584
|
+
if (cluster) {
|
|
1585
|
+
const metaField = meta.structured_data?.meta;
|
|
1586
|
+
if (metaField) {
|
|
1587
|
+
const domainMap = new Map(cluster.members.map((m) => [m.engram_id, m.domain]));
|
|
1588
|
+
for (const ev of metaField.evidence) {
|
|
1589
|
+
if (domainMap.has(ev.engram_id)) {
|
|
1590
|
+
ev.domain = domainMap.get(ev.engram_id);
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
metaField.domain_coverage.validated = clusterDomains;
|
|
1594
|
+
meta.domain = clusterDomains.length >= 3 ? "meta" : `meta.${clusterDomains[0] ?? "unknown"}`;
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
formulated.push(meta);
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
const validationResults = [];
|
|
1601
|
+
if (run_validation && validation_engrams.length > 0) {
|
|
1602
|
+
for (const meta of formulated) {
|
|
1603
|
+
const metaField = meta.structured_data?.meta;
|
|
1604
|
+
if (!metaField) continue;
|
|
1605
|
+
const evidenceDomains = new Set(metaField.evidence.map((e) => e.domain));
|
|
1606
|
+
const testEngrams = validation_engrams.filter((e) => !evidenceDomains.has(e.domain ?? ""));
|
|
1607
|
+
if (testEngrams.length > 0) {
|
|
1608
|
+
const byDomain = /* @__PURE__ */ new Map();
|
|
1609
|
+
for (const te of testEngrams) {
|
|
1610
|
+
const d = te.domain ?? "unknown";
|
|
1611
|
+
if (!byDomain.has(d)) byDomain.set(d, []);
|
|
1612
|
+
byDomain.get(d).push(te);
|
|
1613
|
+
}
|
|
1614
|
+
for (const [domain, domainEngrams] of byDomain) {
|
|
1615
|
+
const vr = await validateMetaEngram(meta, domainEngrams, domain, llm);
|
|
1616
|
+
validationResults.push(vr);
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
const organized = organizeHierarchy(formulated);
|
|
1622
|
+
const duration_ms = Date.now() - start;
|
|
1623
|
+
return {
|
|
1624
|
+
engrams_analyzed: analyses.length,
|
|
1625
|
+
clusters_found: clusters.length,
|
|
1626
|
+
alignments_passed: validAlignments.length,
|
|
1627
|
+
meta_engrams_extracted: organized.length,
|
|
1628
|
+
rejected_as_platitudes,
|
|
1629
|
+
validation_results: validationResults,
|
|
1630
|
+
results: organized,
|
|
1631
|
+
duration_ms
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
// src/session-state.ts
|
|
1636
|
+
var SessionBreadcrumbs = class {
|
|
1637
|
+
toolCalls = [];
|
|
1638
|
+
engramsRecalled = [];
|
|
1639
|
+
recordToolCall(tool, args) {
|
|
1640
|
+
this.toolCalls.push({
|
|
1641
|
+
tool,
|
|
1642
|
+
args_keys: Object.keys(args).join(", "),
|
|
1643
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
recordEngramRecalled(engramId) {
|
|
1647
|
+
if (!this.engramsRecalled.includes(engramId)) {
|
|
1648
|
+
this.engramsRecalled.push(engramId);
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
getToolCalls() {
|
|
1652
|
+
return this.toolCalls;
|
|
1653
|
+
}
|
|
1654
|
+
getEngramsRecalled() {
|
|
1655
|
+
return this.engramsRecalled;
|
|
1656
|
+
}
|
|
1657
|
+
/**
|
|
1658
|
+
* Returns only engram IDs that have the META- prefix.
|
|
1659
|
+
* These represent meta-engrams injected into the session context.
|
|
1660
|
+
*/
|
|
1661
|
+
getMetaEngramsRecalled() {
|
|
1662
|
+
return this.engramsRecalled.filter((id) => id.startsWith("META-"));
|
|
1663
|
+
}
|
|
1664
|
+
generateContinuationContext() {
|
|
1665
|
+
if (this.toolCalls.length === 0 && this.engramsRecalled.length === 0) return "";
|
|
1666
|
+
const lines = [];
|
|
1667
|
+
if (this.toolCalls.length > 0) {
|
|
1668
|
+
const uniqueTools = [...new Set(this.toolCalls.map((tc) => tc.tool))];
|
|
1669
|
+
lines.push(`Tools used: ${uniqueTools.join(", ")}`);
|
|
1670
|
+
lines.push(`Total tool calls: ${this.toolCalls.length}`);
|
|
1671
|
+
}
|
|
1672
|
+
if (this.engramsRecalled.length > 0) {
|
|
1673
|
+
lines.push(`Engrams recalled: ${this.engramsRecalled.length}`);
|
|
1674
|
+
const metaCount = this.getMetaEngramsRecalled().length;
|
|
1675
|
+
if (metaCount > 0) {
|
|
1676
|
+
lines.push(`Meta-engrams: ${metaCount}`);
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
return lines.join("\n");
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
|
|
1683
|
+
// src/guardrails.ts
|
|
1684
|
+
function generateGuardrails() {
|
|
1685
|
+
return `## PLUR Memory Guardrails
|
|
1686
|
+
|
|
1687
|
+
### Verification Protocol
|
|
1688
|
+
When recalling facts that will drive actions (server IPs, file paths, API endpoints, credential locations):
|
|
1689
|
+
1. State the recalled fact explicitly before acting on it
|
|
1690
|
+
2. Include the engram ID or search that produced it
|
|
1691
|
+
3. If no engram matches, say "No engram found \u2014 verifying from filesystem" and check directly
|
|
1692
|
+
4. Never interpolate between two engrams to produce a "probably correct" composite
|
|
1693
|
+
|
|
1694
|
+
When the user corrects a recalled fact: call plur.learn immediately, then plur.feedback with negative signal on the wrong engram, before continuing the task.
|
|
1695
|
+
|
|
1696
|
+
### Over-engineering Check
|
|
1697
|
+
Before proposing any new system, module, or architectural change:
|
|
1698
|
+
1. What is the simplest version that solves the actual problem?
|
|
1699
|
+
2. Is there an existing tool/pattern that already covers 80% of this?
|
|
1700
|
+
3. Will this create maintenance burden disproportionate to its value?
|
|
1701
|
+
|
|
1702
|
+
If a task can be done in <20 lines of shell script, do that first.
|
|
1703
|
+
|
|
1704
|
+
### Tool Selection Discipline
|
|
1705
|
+
Before invoking any external tool, apply the locality test:
|
|
1706
|
+
1. Is the answer already in engrams? \u2192 plur.recall
|
|
1707
|
+
2. Is the answer in the local filesystem? \u2192 Read/Grep/Glob
|
|
1708
|
+
3. Is the answer derivable from context already loaded? \u2192 Just answer
|
|
1709
|
+
4. Only if 1-3 fail \u2192 Use external tools
|
|
1710
|
+
|
|
1711
|
+
Meta-engrams flagged as "[structural transfer \u2014 untested in current domain]" are hypotheses, not rules. Test before applying.`;
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
// src/schemas/meta-engram.ts
|
|
1715
|
+
import { z as z4 } from "zod";
|
|
1716
|
+
var StructuralTemplateSchema = z4.object({
|
|
1717
|
+
goal_type: z4.string().min(1),
|
|
1718
|
+
constraint_type: z4.string().min(1),
|
|
1719
|
+
outcome_type: z4.string().min(1),
|
|
1720
|
+
template: z4.string().min(1),
|
|
1721
|
+
/** Structural frame — declares which relational pattern this meta-engram uses.
|
|
1722
|
+
* Allows flexible analogy beyond rigid [goal]+[constraint]->[outcome]. */
|
|
1723
|
+
structure_type: z4.enum([
|
|
1724
|
+
"goal-constraint-outcome",
|
|
1725
|
+
"feedback-loop",
|
|
1726
|
+
"causal-chain",
|
|
1727
|
+
"recursive",
|
|
1728
|
+
"tradeoff",
|
|
1729
|
+
"freeform"
|
|
1730
|
+
]).default("goal-constraint-outcome"),
|
|
1731
|
+
/** For patterns that don't fit the standard template fields — the LLM's own structural description */
|
|
1732
|
+
freeform_structure: z4.string().optional()
|
|
1733
|
+
});
|
|
1734
|
+
var EvidenceEntrySchema = z4.object({
|
|
1735
|
+
engram_id: z4.string(),
|
|
1736
|
+
domain: z4.string(),
|
|
1737
|
+
mapping_rationale: z4.string(),
|
|
1738
|
+
alignment_score: z4.number().min(0).max(1)
|
|
1739
|
+
});
|
|
1740
|
+
var FalsificationSchema = z4.object({
|
|
1741
|
+
expected_conditions: z4.string(),
|
|
1742
|
+
expected_exceptions: z4.string(),
|
|
1743
|
+
test_prediction: z4.string().optional()
|
|
1744
|
+
});
|
|
1745
|
+
var MetaConfidenceSchema = z4.object({
|
|
1746
|
+
evidence_count: z4.number().int().min(0),
|
|
1747
|
+
domain_count: z4.number().int().min(0),
|
|
1748
|
+
structural_depth: z4.number().int().min(1).max(5),
|
|
1749
|
+
validation_ratio: z4.number().min(0).max(1).default(0),
|
|
1750
|
+
composite: z4.number().min(0).max(1)
|
|
1751
|
+
});
|
|
1752
|
+
var DomainCoverageSchema = z4.object({
|
|
1753
|
+
validated: z4.array(z4.string()),
|
|
1754
|
+
failed: z4.array(z4.string()).default([]),
|
|
1755
|
+
predicted: z4.array(z4.string()).default([])
|
|
1756
|
+
});
|
|
1757
|
+
var HierarchyPositionSchema = z4.object({
|
|
1758
|
+
level: z4.enum(["mop", "top"]),
|
|
1759
|
+
parent: z4.string().nullable().default(null),
|
|
1760
|
+
children: z4.array(z4.string()).default([])
|
|
1761
|
+
});
|
|
1762
|
+
var MetaFieldSchema = z4.object({
|
|
1763
|
+
structure: StructuralTemplateSchema,
|
|
1764
|
+
evidence: z4.array(EvidenceEntrySchema).min(2),
|
|
1765
|
+
domain_coverage: DomainCoverageSchema,
|
|
1766
|
+
falsification: FalsificationSchema,
|
|
1767
|
+
confidence: MetaConfidenceSchema,
|
|
1768
|
+
hierarchy: HierarchyPositionSchema,
|
|
1769
|
+
pipeline_version: z4.string(),
|
|
1770
|
+
last_validated: z4.string().optional()
|
|
1771
|
+
});
|
|
1772
|
+
|
|
1186
1773
|
// src/version-check.ts
|
|
1187
1774
|
var cache = /* @__PURE__ */ new Map();
|
|
1188
1775
|
async function checkForUpdate(packageName, currentVersion, onResult) {
|
|
@@ -1251,6 +1838,12 @@ var Plur = class {
|
|
|
1251
1838
|
}
|
|
1252
1839
|
/** Create engram, detect conflicts, save. Returns the created engram. */
|
|
1253
1840
|
learn(statement, context) {
|
|
1841
|
+
if (!this.config.allow_secrets) {
|
|
1842
|
+
const secrets = detectSecrets(statement);
|
|
1843
|
+
if (secrets.length > 0) {
|
|
1844
|
+
throw new Error(`Secret detected in statement: ${secrets[0].pattern}. Use config.allow_secrets to override.`);
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1254
1847
|
const engrams = loadEngrams(this.paths.engrams);
|
|
1255
1848
|
const id = generateEngramId(engrams);
|
|
1256
1849
|
const scope = context?.scope ?? "global";
|
|
@@ -1282,6 +1875,7 @@ var Plur = class {
|
|
|
1282
1875
|
pack: null,
|
|
1283
1876
|
abstract: null,
|
|
1284
1877
|
derived_from: null,
|
|
1878
|
+
polarity: null,
|
|
1285
1879
|
relations: conflictIds.length > 0 ? {
|
|
1286
1880
|
broader: [],
|
|
1287
1881
|
narrower: [],
|
|
@@ -1339,10 +1933,20 @@ var Plur = class {
|
|
|
1339
1933
|
this._reactivateResults(results);
|
|
1340
1934
|
return results;
|
|
1341
1935
|
}
|
|
1936
|
+
/** List all active engrams, optionally filtered by scope/domain. No search — returns all matches. */
|
|
1937
|
+
list(options) {
|
|
1938
|
+
return this._filterEngrams(options);
|
|
1939
|
+
}
|
|
1342
1940
|
/** Filter engrams by scope/domain/strength (shared by both modes) */
|
|
1343
1941
|
_filterEngrams(options) {
|
|
1344
1942
|
let engrams = loadEngrams(this.paths.engrams);
|
|
1345
1943
|
engrams = engrams.filter((e) => e.status === "active");
|
|
1944
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1945
|
+
engrams = engrams.filter((e) => {
|
|
1946
|
+
if (e.temporal?.valid_until && e.temporal.valid_until < today) return false;
|
|
1947
|
+
if (e.temporal?.valid_from && e.temporal.valid_from > today) return false;
|
|
1948
|
+
return true;
|
|
1949
|
+
});
|
|
1346
1950
|
if (options?.domain) {
|
|
1347
1951
|
engrams = engrams.filter((e) => e.domain?.startsWith(options.domain));
|
|
1348
1952
|
}
|
|
@@ -1357,20 +1961,52 @@ var Plur = class {
|
|
|
1357
1961
|
}
|
|
1358
1962
|
return engrams;
|
|
1359
1963
|
}
|
|
1360
|
-
/** Reactivate accessed engrams
|
|
1964
|
+
/** Reactivate accessed engrams and update co-access associations */
|
|
1361
1965
|
_reactivateResults(results) {
|
|
1362
1966
|
if (results.length === 0) return;
|
|
1363
1967
|
const allEngrams = loadEngrams(this.paths.engrams);
|
|
1364
1968
|
const resultIds = new Set(results.map((e) => e.id));
|
|
1969
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1365
1970
|
let modified = false;
|
|
1366
1971
|
for (const e of allEngrams) {
|
|
1367
1972
|
if (resultIds.has(e.id)) {
|
|
1368
1973
|
e.activation.retrieval_strength = reactivate(e.activation.retrieval_strength);
|
|
1369
|
-
e.activation.last_accessed =
|
|
1974
|
+
e.activation.last_accessed = today;
|
|
1370
1975
|
e.activation.frequency += 1;
|
|
1371
1976
|
modified = true;
|
|
1372
1977
|
}
|
|
1373
1978
|
}
|
|
1979
|
+
if (results.length >= 2 && this.config.injection?.co_access !== false) {
|
|
1980
|
+
const topHalf = results.slice(0, Math.max(2, Math.ceil(results.length / 2)));
|
|
1981
|
+
const topIds = topHalf.map((e) => e.id);
|
|
1982
|
+
for (const sourceId of topIds) {
|
|
1983
|
+
const source = allEngrams.find((e) => e.id === sourceId);
|
|
1984
|
+
if (!source) continue;
|
|
1985
|
+
for (const targetId of topIds) {
|
|
1986
|
+
if (targetId === sourceId) continue;
|
|
1987
|
+
const existing = source.associations.find(
|
|
1988
|
+
(a) => a.type === "co_accessed" && a.target === targetId
|
|
1989
|
+
);
|
|
1990
|
+
if (existing) {
|
|
1991
|
+
existing.strength = Math.min(0.95, existing.strength + 0.05);
|
|
1992
|
+
existing.updated_at = today;
|
|
1993
|
+
modified = true;
|
|
1994
|
+
} else {
|
|
1995
|
+
const coAccessCount = source.associations.filter((a) => a.type === "co_accessed").length;
|
|
1996
|
+
if (coAccessCount < 5) {
|
|
1997
|
+
source.associations.push({
|
|
1998
|
+
target_type: "engram",
|
|
1999
|
+
target: targetId,
|
|
2000
|
+
type: "co_accessed",
|
|
2001
|
+
strength: 0.3,
|
|
2002
|
+
updated_at: today
|
|
2003
|
+
});
|
|
2004
|
+
modified = true;
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
1374
2010
|
if (modified) saveEngrams(this.paths.engrams, allEngrams);
|
|
1375
2011
|
}
|
|
1376
2012
|
/** Scored injection within token budget (BM25 only). Returns formatted strings. */
|
|
@@ -1416,11 +2052,13 @@ var Plur = class {
|
|
|
1416
2052
|
return wires.map((e) => `[${e.id}] ${e.statement}`).join("\n");
|
|
1417
2053
|
};
|
|
1418
2054
|
const directivesStr = formatEngrams(result.directives);
|
|
2055
|
+
const constraintsStr = formatEngrams(result.constraints);
|
|
1419
2056
|
const considerStr = formatEngrams(result.consider);
|
|
1420
|
-
const count = result.directives.length + result.consider.length;
|
|
2057
|
+
const count = result.directives.length + result.constraints.length + result.consider.length;
|
|
1421
2058
|
const tokensUsed = result.tokens_used.directives + result.tokens_used.consider;
|
|
1422
2059
|
return {
|
|
1423
2060
|
directives: directivesStr,
|
|
2061
|
+
constraints: constraintsStr,
|
|
1424
2062
|
consider: considerStr,
|
|
1425
2063
|
count,
|
|
1426
2064
|
tokens_used: tokensUsed
|
|
@@ -1442,6 +2080,32 @@ var Plur = class {
|
|
|
1442
2080
|
}
|
|
1443
2081
|
saveEngrams(this.paths.engrams, engrams);
|
|
1444
2082
|
}
|
|
2083
|
+
/** Save extracted meta-engrams to the engram store. Skips IDs that already exist. */
|
|
2084
|
+
saveMetaEngrams(metas) {
|
|
2085
|
+
const engrams = loadEngrams(this.paths.engrams);
|
|
2086
|
+
const existingIds = new Set(engrams.map((e) => e.id));
|
|
2087
|
+
let saved = 0;
|
|
2088
|
+
let skipped = 0;
|
|
2089
|
+
for (const meta of metas) {
|
|
2090
|
+
if (existingIds.has(meta.id)) {
|
|
2091
|
+
skipped++;
|
|
2092
|
+
} else {
|
|
2093
|
+
engrams.push(meta);
|
|
2094
|
+
saved++;
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
if (saved > 0) saveEngrams(this.paths.engrams, engrams);
|
|
2098
|
+
return { saved, skipped };
|
|
2099
|
+
}
|
|
2100
|
+
/** Update an existing engram in the store by ID. Returns true if found and updated. */
|
|
2101
|
+
updateEngram(updated) {
|
|
2102
|
+
const engrams = loadEngrams(this.paths.engrams);
|
|
2103
|
+
const idx = engrams.findIndex((e) => e.id === updated.id);
|
|
2104
|
+
if (idx === -1) return false;
|
|
2105
|
+
engrams[idx] = updated;
|
|
2106
|
+
saveEngrams(this.paths.engrams, engrams);
|
|
2107
|
+
return true;
|
|
2108
|
+
}
|
|
1445
2109
|
/** Set engram status to 'retired'. */
|
|
1446
2110
|
forget(id, reason) {
|
|
1447
2111
|
const engrams = loadEngrams(this.paths.engrams);
|
|
@@ -1472,6 +2136,7 @@ var Plur = class {
|
|
|
1472
2136
|
const captured = match.slice(1).filter(Boolean).join(" ").trim();
|
|
1473
2137
|
if (!captured || captured.length < 5) continue;
|
|
1474
2138
|
if (seen.has(captured.toLowerCase())) continue;
|
|
2139
|
+
if (!this.config.allow_secrets && detectSecrets(captured).length > 0) continue;
|
|
1475
2140
|
seen.add(captured.toLowerCase());
|
|
1476
2141
|
candidates.push({
|
|
1477
2142
|
statement: captured,
|
|
@@ -1527,10 +2192,34 @@ var Plur = class {
|
|
|
1527
2192
|
}
|
|
1528
2193
|
};
|
|
1529
2194
|
export {
|
|
2195
|
+
DomainCoverageSchema,
|
|
2196
|
+
EvidenceEntrySchema,
|
|
2197
|
+
FalsificationSchema,
|
|
2198
|
+
HierarchyPositionSchema,
|
|
2199
|
+
MetaConfidenceSchema,
|
|
2200
|
+
MetaFieldSchema,
|
|
2201
|
+
PLATITUDE_PATTERNS,
|
|
1530
2202
|
Plur,
|
|
2203
|
+
SessionBreadcrumbs,
|
|
2204
|
+
StructuralTemplateSchema,
|
|
2205
|
+
alignCluster,
|
|
2206
|
+
analyzeStructure,
|
|
1531
2207
|
checkForUpdate,
|
|
2208
|
+
classifyPolarity,
|
|
1532
2209
|
clearVersionCache,
|
|
2210
|
+
clusterByStructure,
|
|
2211
|
+
computeConfidence,
|
|
2212
|
+
computeMetaConfidence,
|
|
2213
|
+
confidenceBand,
|
|
1533
2214
|
detectPlurStorage,
|
|
2215
|
+
detectSecrets,
|
|
1534
2216
|
engramSearchText,
|
|
1535
|
-
|
|
2217
|
+
extractMetaEngrams,
|
|
2218
|
+
formulateMetaEngram,
|
|
2219
|
+
generateGuardrails,
|
|
2220
|
+
getCachedUpdateCheck,
|
|
2221
|
+
isPlatitude,
|
|
2222
|
+
organizeHierarchy,
|
|
2223
|
+
tokenSimilarity,
|
|
2224
|
+
validateMetaEngram
|
|
1536
2225
|
};
|