@inetafrica/open-claudia 2.6.33 → 2.6.34

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.
@@ -0,0 +1,83 @@
1
+ // Discoverer engine: pre-gate, seed → (graph) → fail-open injection. The LLM
2
+ // walker is disabled here (RECALL_DISCOVERER_WALKER=off) so the engine takes
3
+ // its deterministic fail-open path: keep user-origin seeds, drop guesses.
4
+ const assert = require("assert");
5
+ const fs = require("fs");
6
+ const os = require("os");
7
+ const path = require("path");
8
+
9
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "recall-disc-"));
10
+ process.env.RECALL_GRAPH_DB = path.join(tmp, "graph.db");
11
+ process.env.RECALL_DISCOVERER_WALKER = "off";
12
+ process.env.RECALL_METRICS = "off";
13
+
14
+ const disc = require("./core/recall/discoverer");
15
+
16
+ // --- pre-gate ---
17
+ assert.strictEqual(disc.needsRecall("", 0), false, "empty → no recall");
18
+ assert.strictEqual(disc.needsRecall("thanks", 0), false, "pleasantry → no recall");
19
+ assert.strictEqual(disc.needsRecall("ok", 0), false, "terse ack → no recall");
20
+ assert.strictEqual(disc.needsRecall("yo", 0), false, "two words, no seeds → no recall");
21
+ assert.strictEqual(disc.needsRecall("how do I deploy the mobile app", 0), true, "substantive → recall");
22
+ assert.strictEqual(disc.needsRecall("k", 5), true, "seeds present always recall");
23
+
24
+ // --- shared stub corpus + helpers ---
25
+ const packs = {
26
+ "kazee-mobile": { dir: "kazee-mobile", name: "Kazee Mobile", description: "the app",
27
+ parent: "kazee", tags: [], sections: { Stance: "lime", Procedure: "", State: "", Journal: "" } },
28
+ "kazee-theme": { dir: "kazee-theme", name: "Kazee Theme", description: "palette",
29
+ parent: null, tags: ["shared"], sections: { Stance: "lime palette", Procedure: "", State: "", Journal: "" } },
30
+ };
31
+ const packsLib = {
32
+ matchPacks: (text) => /mobile/.test(text) ? [{ dir: "kazee-mobile", name: "Kazee Mobile", score: 4 }] : [],
33
+ readPack: (dir) => packs[dir] || null,
34
+ listPacks: () => Object.values(packs),
35
+ PACKS_DIR: tmp,
36
+ };
37
+ const entitiesLib = {
38
+ matchEntities: () => [],
39
+ readEntity: () => null,
40
+ listEntities: () => [],
41
+ ENTITIES_DIR: tmp,
42
+ };
43
+ const mergeMatches = (primary, secondary, keyOf) => {
44
+ const out = primary.map((m) => ({ ...m, origin: "user" }));
45
+ const seen = new Set(primary.map(keyOf));
46
+ for (const m of secondary) if (!seen.has(keyOf(m))) out.push({ ...m, origin: "context" });
47
+ return out;
48
+ };
49
+ let builtPacks = null;
50
+ const buildPackBlock = (matches) => { builtPacks = matches; return matches.length ? "PACKBLOCK" : ""; };
51
+ const buildEntityBlock = (matches) => (matches.length ? "ENTITYBLOCK" : "");
52
+ const helpers = { packsLib, entitiesLib, mergeMatches, buildPackBlock, buildEntityBlock };
53
+
54
+ (async () => {
55
+ // gated turn: trivial text, no seeds → empty result, builders not called
56
+ builtPacks = null;
57
+ const gated = await disc.run({
58
+ userText: "ok", contextText: "", fullContext: "", packLimit: 6, budget: {}, helpers,
59
+ });
60
+ assert.strictEqual(gated.packBlock, "");
61
+ assert.strictEqual(gated.packMatches.length, 0);
62
+ assert.strictEqual(builtPacks, null, "gated turn never builds blocks");
63
+
64
+ // seeded turn: FTS hits kazee-mobile → fail-open keeps it, block rendered
65
+ const out = await disc.run({
66
+ userText: "help with the mobile app", contextText: "", fullContext: "help with the mobile app",
67
+ packLimit: 6, budget: {}, helpers,
68
+ });
69
+ assert.strictEqual(out.packBlock, "PACKBLOCK");
70
+ assert.strictEqual(out.packMatches.length, 1);
71
+ assert.strictEqual(out.packMatches[0].dir, "kazee-mobile");
72
+ assert.ok(builtPacks && builtPacks.some((m) => m.dir === "kazee-mobile"), "seed reached the builder");
73
+
74
+ // resilient: a throwing matcher must not blow up the engine
75
+ const out2 = await disc.run({
76
+ userText: "deploy something substantive please", contextText: "", fullContext: "",
77
+ packLimit: 6, budget: {},
78
+ helpers: { ...helpers, packsLib: { ...packsLib, matchPacks: () => { throw new Error("boom"); } } },
79
+ });
80
+ assert.strictEqual(typeof out2.packBlock, "string");
81
+
82
+ console.log("recall discoverer OK");
83
+ })().catch((e) => { console.error(e); process.exit(1); });
@@ -0,0 +1,54 @@
1
+ // Recall engine selector + classic-engine smoke tests.
2
+ const assert = require("assert");
3
+ const recall = require("./core/recall");
4
+
5
+ // --- selector ---
6
+ assert.strictEqual(recall.activeEngineName({}), "classic", "default → classic");
7
+ assert.strictEqual(recall.activeEngineName({ recallEngine: "classic" }), "classic");
8
+ assert.strictEqual(recall.activeEngineName({ recallEngine: "nope" }), "classic", "unknown → classic");
9
+ assert.strictEqual(recall.activeEngineName({ recallEngine: "CLASSIC" }), "classic", "case-insensitive");
10
+ assert.ok(recall.listEngines().includes("classic"));
11
+ assert.strictEqual(typeof recall.getEngine("classic").run, "function");
12
+ assert.strictEqual(recall.getEngine("bogus").name, "classic", "getEngine falls back to classic");
13
+
14
+ // env override when no setting
15
+ const prev = process.env.RECALL_ENGINE;
16
+ process.env.RECALL_ENGINE = "classic";
17
+ assert.strictEqual(recall.activeEngineName(null), "classic");
18
+ if (prev === undefined) delete process.env.RECALL_ENGINE; else process.env.RECALL_ENGINE = prev;
19
+
20
+ // --- classic engine orchestration: calls helpers and returns their blocks ---
21
+ (async () => {
22
+ const calls = [];
23
+ const helpers = {
24
+ packsLib: { matchPacks: () => [{ dir: "p1", name: "P1" }] },
25
+ entitiesLib: { matchEntities: () => [{ slug: "e1", name: "E1" }] },
26
+ mergeMatches: (a, b) => { calls.push("merge"); return a.map((m) => ({ ...m, origin: "user" })); },
27
+ filterMatches: async (u, c, pm, em) => { calls.push("filter"); return { packMatches: pm, entityMatches: em }; },
28
+ logRecall: () => { calls.push("log"); },
29
+ buildPackBlock: (m) => { calls.push("buildPack"); return m.length ? "PACKBLOCK" : ""; },
30
+ buildEntityBlock: (m) => { calls.push("buildEntity"); return m.length ? "ENTITYBLOCK" : ""; },
31
+ };
32
+ const out = await recall.getEngine("classic").run({
33
+ userText: "hello", contextText: "", fullContext: "", packLimit: 6, budget: {}, helpers,
34
+ });
35
+ assert.strictEqual(out.packBlock, "PACKBLOCK");
36
+ assert.strictEqual(out.entityBlock, "ENTITYBLOCK");
37
+ assert.strictEqual(out.packMatches.length, 1);
38
+ assert.strictEqual(out.entityMatches.length, 1);
39
+ assert.ok(calls.includes("filter") && calls.includes("log") && calls.includes("buildPack"));
40
+
41
+ // resilient: a throwing matcher must not blow up the engine
42
+ const out2 = await recall.getEngine("classic").run({
43
+ userText: "x", contextText: "", fullContext: "",
44
+ packLimit: 6, budget: {},
45
+ helpers: {
46
+ ...helpers,
47
+ packsLib: { matchPacks: () => { throw new Error("boom"); } },
48
+ entitiesLib: { matchEntities: () => { throw new Error("boom"); } },
49
+ },
50
+ });
51
+ assert.strictEqual(typeof out2.packBlock, "string");
52
+
53
+ console.log("recall engine OK");
54
+ })().catch((e) => { console.error(e); process.exit(1); });
@@ -0,0 +1,94 @@
1
+ // Recall graph: edges, Hebbian reinforce, decay, spreading activation,
2
+ // structural sync, orphan prune. Uses a throwaway sqlite db under a temp dir.
3
+ const assert = require("assert");
4
+ const fs = require("fs");
5
+ const os = require("os");
6
+ const path = require("path");
7
+
8
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "recall-graph-"));
9
+ process.env.RECALL_GRAPH_DB = path.join(tmp, "graph.db");
10
+
11
+ const graph = require("./core/recall/graph");
12
+
13
+ if (!graph.available()) { console.log("recall graph OK (skipped — no node:sqlite)"); process.exit(0); }
14
+
15
+ // --- edges + neighbours ---
16
+ graph.addEdge("pack:a", "pack:b", "related");
17
+ graph.addEdge("pack:b", "pack:c", "related");
18
+ graph.addEdge("pack:a", "pack:theme", "governed-by");
19
+ const nb = graph.neighbors("pack:a").map((x) => x.node).sort();
20
+ assert.deepStrictEqual(nb, ["pack:b", "pack:theme"], "undirected neighbours of a");
21
+ assert.strictEqual(graph.allEdges().length, 3);
22
+
23
+ // addEdge keeps the max weight (structural re-derive never lowers reinforcement)
24
+ graph.addEdge("pack:a", "pack:b", "related", { weight: 99 });
25
+ let ab = graph.allEdges().find((e) => e.src === "pack:a" && e.dst === "pack:b");
26
+ assert.strictEqual(ab.weight, 99, "weight raised to max");
27
+ graph.addEdge("pack:a", "pack:b", "related", { weight: 1 });
28
+ ab = graph.allEdges().find((e) => e.src === "pack:a" && e.dst === "pack:b");
29
+ assert.strictEqual(ab.weight, 99, "weight not lowered by smaller structural weight");
30
+
31
+ // --- Hebbian reinforce (both directions) ---
32
+ graph.reinforce("pack:x", "pack:y", 2);
33
+ const xy = graph.allEdges().find((e) => e.src === "pack:x" && e.dst === "pack:y");
34
+ const yx = graph.allEdges().find((e) => e.src === "pack:y" && e.dst === "pack:x");
35
+ assert.ok(xy && yx, "reinforce creates both directions");
36
+ assert.ok(xy.last_reinforced, "reinforce stamps last_reinforced");
37
+ graph.reinforce("pack:x", "pack:y", 2);
38
+ const xy2 = graph.allEdges().find((e) => e.src === "pack:x" && e.dst === "pack:y");
39
+ assert.ok(xy2.weight > xy.weight, "repeat reinforce bumps weight");
40
+
41
+ graph.reinforceSet(["pack:a", "pack:b", "pack:c"]);
42
+ assert.ok(graph.neighbors("pack:a").some((n) => n.node === "pack:c"), "reinforceSet links all pairs");
43
+
44
+ // --- spreading activation ---
45
+ // strong chain a→b→c; seed a, expect b (1 hop) and possibly c (2 hops).
46
+ const act = graph.expand([{ id: "pack:a", score: 4 }], { hops: 2, threshold: 0.1 });
47
+ assert.ok(act.has("pack:b"), "1-hop neighbour activates");
48
+ assert.ok(!act.has("pack:a"), "seed excluded from activation result");
49
+ for (const [, v] of act) assert.ok(v.activation > 0 && v.hop >= 1, "activation has metadata");
50
+
51
+ // seeds with no edges produce nothing
52
+ assert.strictEqual(graph.expand([{ id: "pack:orphanseed", score: 5 }]).size, 0);
53
+
54
+ // --- decay (never below structural floor) ---
55
+ graph.addEdge("pack:d", "pack:e", "parent"); // base weight 3, no last_reinforced → untouched
56
+ graph.reinforce("pack:d", "pack:f", 10);
57
+ // backdate the reinforced edge well past the half-life
58
+ const db = graph.openDb();
59
+ const old = new Date(Date.now() - 400 * 86400000).toISOString();
60
+ db.prepare("UPDATE edges SET last_reinforced=? WHERE src=? AND dst=?").run(old, "pack:d", "pack:f");
61
+ graph.decay({ halfLifeDays: 30 });
62
+ const df = graph.allEdges().find((e) => e.src === "pack:d" && e.dst === "pack:f");
63
+ assert.ok(df.weight < 11 && df.weight >= 1, "reinforced edge decayed toward floor");
64
+ const de = graph.allEdges().find((e) => e.src === "pack:d" && e.dst === "pack:e");
65
+ assert.strictEqual(de.weight, 3, "structural edge with no reinforcement untouched by decay");
66
+
67
+ // --- structural sync from a stubbed corpus ---
68
+ const packsStub = {
69
+ listPacks: () => [
70
+ { dir: "kazee-mobile", name: "Kazee Mobile", tags: [], parent: "kazee",
71
+ sections: { Stance: "uses [[kazee-theme]]", Procedure: "", State: "", Journal: "" } },
72
+ { dir: "kazee", name: "Kazee", tags: [], parent: null,
73
+ sections: { Stance: "", Procedure: "", State: "", Journal: "" } },
74
+ { dir: "kazee-theme", name: "Kazee Theme", tags: ["shared"], parent: null,
75
+ sections: { Stance: "lime palette", Procedure: "", State: "", Journal: "" } },
76
+ ],
77
+ };
78
+ const entStub = { listEntities: () => [] };
79
+ const r = graph.syncFromCorpus(packsStub, entStub);
80
+ assert.ok(r.edges >= 2, "sync derived parent + link edges");
81
+ const edges = graph.allEdges();
82
+ assert.ok(edges.some((e) => e.src === "pack:kazee-mobile" && e.dst === "pack:kazee" && e.type === "parent"), "parent edge from frontmatter");
83
+ assert.ok(edges.some((e) => e.src === "pack:kazee-mobile" && e.dst === "pack:kazee-theme" && e.type === "governed-by"), "shared-concern link → governed-by");
84
+
85
+ // --- orphan prune ---
86
+ graph.addEdge("pack:ghost", "pack:kazee", "related");
87
+ const pruned = graph.pruneOrphans(packsStub, entStub);
88
+ assert.ok(pruned >= 1, "orphan edge pruned");
89
+ assert.ok(!graph.allEdges().some((e) => e.src === "pack:ghost"), "ghost edge gone");
90
+
91
+ // parseLinks
92
+ assert.deepStrictEqual(graph.parseLinks("see [[Foo-Bar]] and [[baz]]"), ["foo-bar", "baz"]);
93
+
94
+ console.log("recall graph OK");