@hviana/sema 0.1.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/AGENTS.md +470 -0
- package/AUTHORS.md +12 -0
- package/COMMERCIAL-LICENSE.md +19 -0
- package/CONTRIBUTING.md +15 -0
- package/HOW_IT_WORKS.md +4210 -0
- package/LICENSE.md +117 -0
- package/README.md +290 -0
- package/TRADEMARKS.md +19 -0
- package/example/demo.ts +46 -0
- package/example/train_base.ts +2675 -0
- package/index.html +893 -0
- package/package.json +25 -0
- package/src/alphabet.ts +34 -0
- package/src/alu/README.md +332 -0
- package/src/alu/src/alu.ts +541 -0
- package/src/alu/src/expr.ts +339 -0
- package/src/alu/src/index.ts +115 -0
- package/src/alu/src/kernel-arith.ts +377 -0
- package/src/alu/src/kernel-bits.ts +199 -0
- package/src/alu/src/kernel-logic.ts +102 -0
- package/src/alu/src/kernel-nd.ts +235 -0
- package/src/alu/src/kernel-numeric.ts +466 -0
- package/src/alu/src/operation.ts +344 -0
- package/src/alu/src/parser.ts +574 -0
- package/src/alu/src/resonance.ts +161 -0
- package/src/alu/src/text.ts +83 -0
- package/src/alu/src/value.ts +327 -0
- package/src/alu/test/alu.test.ts +1004 -0
- package/src/bytes.ts +62 -0
- package/src/config.ts +227 -0
- package/src/derive/README.md +295 -0
- package/src/derive/src/deduction.ts +263 -0
- package/src/derive/src/index.ts +24 -0
- package/src/derive/src/priority-queue.ts +70 -0
- package/src/derive/src/rewrite.ts +127 -0
- package/src/derive/src/trie.ts +242 -0
- package/src/derive/test/derive.test.ts +137 -0
- package/src/extension.ts +42 -0
- package/src/geometry.ts +511 -0
- package/src/index.ts +38 -0
- package/src/ingest-cache.ts +224 -0
- package/src/mind/articulation.ts +137 -0
- package/src/mind/attention.ts +1061 -0
- package/src/mind/canonical.ts +107 -0
- package/src/mind/graph-search.ts +1100 -0
- package/src/mind/index.ts +18 -0
- package/src/mind/junction.ts +347 -0
- package/src/mind/learning.ts +246 -0
- package/src/mind/match.ts +507 -0
- package/src/mind/mechanisms/alu.ts +33 -0
- package/src/mind/mechanisms/cast.ts +568 -0
- package/src/mind/mechanisms/confluence.ts +268 -0
- package/src/mind/mechanisms/cover.ts +248 -0
- package/src/mind/mechanisms/extraction.ts +422 -0
- package/src/mind/mechanisms/recall.ts +241 -0
- package/src/mind/mind.ts +483 -0
- package/src/mind/pipeline-mechanism.ts +326 -0
- package/src/mind/pipeline.ts +300 -0
- package/src/mind/primitives.ts +201 -0
- package/src/mind/rationale.ts +275 -0
- package/src/mind/reasoning.ts +198 -0
- package/src/mind/recognition.ts +234 -0
- package/src/mind/resonance.ts +0 -0
- package/src/mind/trace.ts +108 -0
- package/src/mind/traverse.ts +556 -0
- package/src/mind/types.ts +281 -0
- package/src/rabitq-hnsw/README.md +303 -0
- package/src/rabitq-hnsw/src/database.ts +492 -0
- package/src/rabitq-hnsw/src/heap.ts +90 -0
- package/src/rabitq-hnsw/src/hnsw.ts +514 -0
- package/src/rabitq-hnsw/src/index.ts +15 -0
- package/src/rabitq-hnsw/src/prng.ts +39 -0
- package/src/rabitq-hnsw/src/rabitq.ts +308 -0
- package/src/rabitq-hnsw/src/store.ts +994 -0
- package/src/rabitq-hnsw/test/hnsw.test.ts +1213 -0
- package/src/store-sqlite.ts +928 -0
- package/src/store.ts +2148 -0
- package/src/vec.ts +124 -0
- package/test/00-extract.test.mjs +151 -0
- package/test/01-floor.test.mjs +20 -0
- package/test/02-roundtrip.test.mjs +83 -0
- package/test/03-recall.test.mjs +98 -0
- package/test/04-think.test.mjs +627 -0
- package/test/05-concepts.test.mjs +84 -0
- package/test/08-storage.test.mjs +948 -0
- package/test/09-edges.test.mjs +65 -0
- package/test/11-universality.test.mjs +180 -0
- package/test/13-conversation.test.mjs +228 -0
- package/test/14-scaling.test.mjs +503 -0
- package/test/15-decomposition-gap.test.mjs +0 -0
- package/test/16-bridge.test.mjs +250 -0
- package/test/17-intelligence.test.mjs +240 -0
- package/test/18-alu.test.mjs +209 -0
- package/test/19-nd.test.mjs +254 -0
- package/test/20-stability.test.mjs +489 -0
- package/test/21-partial.test.mjs +158 -0
- package/test/22-multihop.test.mjs +130 -0
- package/test/23-rationale.test.mjs +316 -0
- package/test/24-generalization.test.mjs +416 -0
- package/test/25-embedding.test.mjs +75 -0
- package/test/26-cooperative.test.mjs +89 -0
- package/test/27-saturation-drop.test.mjs +637 -0
- package/test/28-unknowable.test.mjs +88 -0
- package/test/29-counterfactual.test.mjs +476 -0
- package/test/30-conflict-resolution.test.mjs +166 -0
- package/test/31-audit.test.mjs +288 -0
- package/test/32-confluence.test.mjs +173 -0
- package/test/33-multi-candidate.test.mjs +222 -0
- package/test/34-cross-region.test.mjs +252 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { Mind } from "../dist/src/index.js";
|
|
4
|
+
import { SQliteStore } from "../dist/src/store-sqlite.js";
|
|
5
|
+
|
|
6
|
+
// =========================================================================
|
|
7
|
+
// 1 — Single-step direct recall & chain basics
|
|
8
|
+
// =========================================================================
|
|
9
|
+
|
|
10
|
+
test("direct recall: trained fact answers immediately", async () => {
|
|
11
|
+
const m = new Mind({
|
|
12
|
+
seed: 7,
|
|
13
|
+
});
|
|
14
|
+
await m.ingest([["2+2", "4"], ["3+5", "8"]]);
|
|
15
|
+
assert.equal(await m.respondText("3+5"), "8");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("single chain: A→B", async () => {
|
|
19
|
+
const m = new Mind({
|
|
20
|
+
seed: 7,
|
|
21
|
+
});
|
|
22
|
+
await m.ingest([["fire", "hot"]]);
|
|
23
|
+
assert.equal(await m.respondText("fire"), "hot");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("two-step chain: A→B, B→C", async () => {
|
|
27
|
+
const m = new Mind({
|
|
28
|
+
seed: 7,
|
|
29
|
+
});
|
|
30
|
+
await m.ingest([["a", "b"], ["b", "c"]]);
|
|
31
|
+
assert.equal(await m.respondText("a"), "c");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("three-step chain: A→B, B→C, C→D", async () => {
|
|
35
|
+
const m = new Mind({
|
|
36
|
+
seed: 7,
|
|
37
|
+
});
|
|
38
|
+
await m.ingest([["a", "b"], ["b", "c"], ["c", "d"]]);
|
|
39
|
+
assert.equal(await m.respondText("a"), "d");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("four-step chain: A→B→C→D→E", async () => {
|
|
43
|
+
const m = new Mind({
|
|
44
|
+
seed: 7,
|
|
45
|
+
});
|
|
46
|
+
await m.ingest([["a", "b"], ["b", "c"], ["c", "d"], ["d", "e"]]);
|
|
47
|
+
assert.equal(await m.respondText("a"), "e");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// =========================================================================
|
|
51
|
+
// 2 — Known part fires inside unknown wrappers
|
|
52
|
+
// =========================================================================
|
|
53
|
+
|
|
54
|
+
test("known part with prefix", async () => {
|
|
55
|
+
const m = new Mind({
|
|
56
|
+
seed: 7,
|
|
57
|
+
});
|
|
58
|
+
await m.ingest([["2+2", "4"]]);
|
|
59
|
+
assert.equal(await m.respondText("what is 2+2"), "4");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("known part with suffix", async () => {
|
|
63
|
+
const m = new Mind({
|
|
64
|
+
seed: 7,
|
|
65
|
+
});
|
|
66
|
+
await m.ingest([["2+2", "4"]]);
|
|
67
|
+
assert.equal(await m.respondText("2+2 equals what"), "4");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("known part with prefix and suffix", async () => {
|
|
71
|
+
const m = new Mind({
|
|
72
|
+
seed: 7,
|
|
73
|
+
});
|
|
74
|
+
await m.ingest([["2+2", "4"]]);
|
|
75
|
+
assert.equal(await m.respondText("compute: 2+2 now"), "4");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("known part buried mid-sentence", async () => {
|
|
79
|
+
const m = new Mind({
|
|
80
|
+
seed: 7,
|
|
81
|
+
});
|
|
82
|
+
await m.ingest([["ice", "cold"]]);
|
|
83
|
+
assert.equal(await m.respondText("the nature of ice is known"), "cold");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// =========================================================================
|
|
87
|
+
// 3 — Multi-part: multiple known parts fire independently
|
|
88
|
+
// =========================================================================
|
|
89
|
+
|
|
90
|
+
test("two independent parts with gap", async () => {
|
|
91
|
+
const m = new Mind({
|
|
92
|
+
seed: 7,
|
|
93
|
+
});
|
|
94
|
+
await m.ingest([["ice", "cold"], ["fire", "hot"]]);
|
|
95
|
+
assert.equal(await m.respondText("ice fire"), "cold hot");
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("three independent parts", async () => {
|
|
99
|
+
const m = new Mind({
|
|
100
|
+
seed: 7,
|
|
101
|
+
});
|
|
102
|
+
await m.ingest([["a", "A"], ["b", "B"], ["c", "C"]]);
|
|
103
|
+
assert.equal(await m.respondText("a b c"), "A B C");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("four independent parts", async () => {
|
|
107
|
+
const m = new Mind({
|
|
108
|
+
seed: 7,
|
|
109
|
+
});
|
|
110
|
+
await m.ingest([["a", "A"], ["b", "B"], ["c", "C"], ["d", "D"]]);
|
|
111
|
+
const r = await m.respondText("a b c d");
|
|
112
|
+
assert.ok(
|
|
113
|
+
r.includes("A") && r.includes("B") && r.includes("C") && r.includes("D"),
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("five independent parts", async () => {
|
|
118
|
+
const m = new Mind({
|
|
119
|
+
seed: 7,
|
|
120
|
+
});
|
|
121
|
+
await m.ingest([["a", "A"], ["b", "B"], ["c", "C"], ["d", "D"], ["e", "E"]]);
|
|
122
|
+
const r = await m.respondText("a b c d e");
|
|
123
|
+
assert.ok(r.includes("A") && r.includes("E"));
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// =========================================================================
|
|
127
|
+
// 4 — Order independence
|
|
128
|
+
// =========================================================================
|
|
129
|
+
|
|
130
|
+
test("reversed order: fire ice → hot cold", async () => {
|
|
131
|
+
const m = new Mind({
|
|
132
|
+
seed: 7,
|
|
133
|
+
});
|
|
134
|
+
await m.ingest([["ice", "cold"], ["fire", "hot"]]);
|
|
135
|
+
const r = await m.respondText("fire ice");
|
|
136
|
+
assert.ok(r.includes("hot") && r.includes("cold"));
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("scrambled order: c a b → C A B", async () => {
|
|
140
|
+
const m = new Mind({
|
|
141
|
+
seed: 7,
|
|
142
|
+
});
|
|
143
|
+
await m.ingest([["a", "A"], ["b", "B"], ["c", "C"]]);
|
|
144
|
+
const r = await m.respondText("c a b");
|
|
145
|
+
assert.ok(r.includes("A") && r.includes("B") && r.includes("C"));
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("interspersed known and unknown", async () => {
|
|
149
|
+
const m = new Mind({
|
|
150
|
+
seed: 7,
|
|
151
|
+
});
|
|
152
|
+
await m.ingest([["ice", "cold"]]);
|
|
153
|
+
const r = await m.respondText("xyz ice uvw");
|
|
154
|
+
assert.ok(r.includes("cold"));
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// =========================================================================
|
|
158
|
+
// 5 — Punctuation and formatting preserved
|
|
159
|
+
// =========================================================================
|
|
160
|
+
|
|
161
|
+
test("comma between facts preserved", async () => {
|
|
162
|
+
const m = new Mind({
|
|
163
|
+
seed: 7,
|
|
164
|
+
});
|
|
165
|
+
await m.ingest([["ice", "cold"], ["fire", "hot"]]);
|
|
166
|
+
const r = await m.respondText("ice, fire");
|
|
167
|
+
assert.ok(r.includes("cold") && r.includes("hot"));
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("period preserved", async () => {
|
|
171
|
+
const m = new Mind({
|
|
172
|
+
seed: 7,
|
|
173
|
+
});
|
|
174
|
+
await m.ingest([["2+2", "4"]]);
|
|
175
|
+
assert.equal(await m.respondText("2+2."), "4.");
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("question mark preserved", async () => {
|
|
179
|
+
const m = new Mind({
|
|
180
|
+
seed: 7,
|
|
181
|
+
});
|
|
182
|
+
await m.ingest([["2+2", "4"]]);
|
|
183
|
+
assert.equal(await m.respondText("2+2?"), "4?");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// =========================================================================
|
|
187
|
+
// 6 — Chain + independent part in same query
|
|
188
|
+
// =========================================================================
|
|
189
|
+
|
|
190
|
+
test("chain and direct fact side by side", async () => {
|
|
191
|
+
const m = new Mind({
|
|
192
|
+
seed: 7,
|
|
193
|
+
});
|
|
194
|
+
await m.ingest([["a", "b"], ["b", "c"], ["ice", "cold"]]);
|
|
195
|
+
const r = await m.respondText("a ice");
|
|
196
|
+
assert.ok(r.includes("c") && r.includes("cold"));
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("two independent chains in one query", async () => {
|
|
200
|
+
const m = new Mind({
|
|
201
|
+
seed: 7,
|
|
202
|
+
});
|
|
203
|
+
await m.ingest([["a", "b"], ["b", "c"], ["x", "y"], ["y", "z"]]);
|
|
204
|
+
const r = await m.respondText("a x");
|
|
205
|
+
assert.ok(r.includes("c") && r.includes("z"));
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// =========================================================================
|
|
209
|
+
// 7 — Recursive rewriting to fixpoint
|
|
210
|
+
// =========================================================================
|
|
211
|
+
|
|
212
|
+
test("rewrite chains converge to fixpoint", async () => {
|
|
213
|
+
const m = new Mind({
|
|
214
|
+
seed: 7,
|
|
215
|
+
});
|
|
216
|
+
await m.ingest([["a", "b"], ["b", "c"], ["c", "d"]]);
|
|
217
|
+
assert.equal(await m.respondText("a"), "d");
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("bidirectional chain: reverse completion works", async () => {
|
|
221
|
+
const m = new Mind({
|
|
222
|
+
seed: 7,
|
|
223
|
+
});
|
|
224
|
+
await m.ingest([["question", "answer"]]);
|
|
225
|
+
// Asking the continuation should recall the context (seat symmetry)
|
|
226
|
+
assert.equal(await m.respondText("answer"), "question");
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test("echo termination: self-feeding rewrite halts", async () => {
|
|
230
|
+
const m = new Mind({
|
|
231
|
+
seed: 7,
|
|
232
|
+
});
|
|
233
|
+
await m.ingest([["ab", "ab ab"]]);
|
|
234
|
+
const r = await m.respond("xq ab zk");
|
|
235
|
+
assert.ok(r.v === null || new TextDecoder().decode(r.bytes).includes("ab"));
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// =========================================================================
|
|
239
|
+
// 8 — Definition expansion
|
|
240
|
+
// =========================================================================
|
|
241
|
+
|
|
242
|
+
test("definition lookup: term → meaning", async () => {
|
|
243
|
+
const m = new Mind({
|
|
244
|
+
seed: 7,
|
|
245
|
+
});
|
|
246
|
+
await m.ingest([["ice", "frozen water"]]);
|
|
247
|
+
assert.equal(await m.respondText("what is ice"), "frozen water");
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
test("definition lookup mid-sentence", async () => {
|
|
251
|
+
const m = new Mind({
|
|
252
|
+
seed: 7,
|
|
253
|
+
});
|
|
254
|
+
await m.ingest([["ice", "frozen water"]]);
|
|
255
|
+
assert.equal(await m.respondText("tell me about ice please"), "frozen water");
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test("definition chain through two levels", async () => {
|
|
259
|
+
const m = new Mind({
|
|
260
|
+
seed: 7,
|
|
261
|
+
});
|
|
262
|
+
await m.ingest([["x", "y"], ["y", "z"]]);
|
|
263
|
+
assert.equal(await m.respondText("x"), "z");
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test("synonym expansion via concept merge", async () => {
|
|
267
|
+
const m = new Mind({
|
|
268
|
+
seed: 7,
|
|
269
|
+
});
|
|
270
|
+
await m.ingest([["big", "large"]]);
|
|
271
|
+
// Ground both in the same context so they merge
|
|
272
|
+
await m.ingest(["ctx", "big"]);
|
|
273
|
+
await m.ingest(["ctx", "large"]);
|
|
274
|
+
// Now they're one concept — asking one recalls the other
|
|
275
|
+
assert.equal(await m.respondText("large"), "large");
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// =========================================================================
|
|
279
|
+
// 9 — Compositional synthesis from multiple facts
|
|
280
|
+
// =========================================================================
|
|
281
|
+
|
|
282
|
+
test("two facts compose: ice fire → cold hot", async () => {
|
|
283
|
+
const m = new Mind({
|
|
284
|
+
seed: 7,
|
|
285
|
+
});
|
|
286
|
+
await m.ingest([["ice", "cold"], ["fire", "hot"]]);
|
|
287
|
+
assert.equal(await m.respondText("ice fire"), "cold hot");
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("three facts compose", async () => {
|
|
291
|
+
const m = new Mind({
|
|
292
|
+
seed: 7,
|
|
293
|
+
});
|
|
294
|
+
await m.ingest([["a", "A"], ["b", "B"], ["c", "C"]]);
|
|
295
|
+
assert.equal(await m.respondText("a b c"), "A B C");
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test("synthesis across concept boundaries", async () => {
|
|
299
|
+
const m = new Mind({
|
|
300
|
+
seed: 7,
|
|
301
|
+
});
|
|
302
|
+
await m.ingest([["ice", "cold"], ["fire", "hot"]]);
|
|
303
|
+
await m.ingest(["ctx", "ice"]);
|
|
304
|
+
await m.ingest(["ctx", "hielo"]);
|
|
305
|
+
// ice and hielo merge. Asking hielo should still compose with fire.
|
|
306
|
+
const r = await m.respondText("hielo fire");
|
|
307
|
+
assert.ok(r.includes("cold") && r.includes("hot"));
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// =========================================================================
|
|
311
|
+
// 10 — Arithmetic chains (the classic use case)
|
|
312
|
+
// =========================================================================
|
|
313
|
+
|
|
314
|
+
const ARITH = [
|
|
315
|
+
["1+2", "3"],
|
|
316
|
+
["2+2", "4"],
|
|
317
|
+
["2+3", "5"],
|
|
318
|
+
["3+3", "6"],
|
|
319
|
+
["3+5", "8"],
|
|
320
|
+
["4+3", "7"],
|
|
321
|
+
["2+5", "7"],
|
|
322
|
+
["1+5", "6"],
|
|
323
|
+
["6+1", "7"],
|
|
324
|
+
["4+1", "5"],
|
|
325
|
+
["3+4", "7"],
|
|
326
|
+
["5+2", "7"],
|
|
327
|
+
["1+1", "2"],
|
|
328
|
+
["5+3", "8"],
|
|
329
|
+
["7+1", "8"],
|
|
330
|
+
];
|
|
331
|
+
|
|
332
|
+
test("arithmetic: direct fact", async () => {
|
|
333
|
+
const m = new Mind({
|
|
334
|
+
seed: 7,
|
|
335
|
+
});
|
|
336
|
+
await m.ingest(ARITH);
|
|
337
|
+
assert.equal(await m.respondText("3+5"), "8");
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
test("arithmetic: 2-step chain", async () => {
|
|
341
|
+
const m = new Mind({
|
|
342
|
+
seed: 7,
|
|
343
|
+
});
|
|
344
|
+
await m.ingest(ARITH);
|
|
345
|
+
assert.equal(await m.respondText("2+2+3"), "7");
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test("arithmetic: fact inside question", async () => {
|
|
349
|
+
const m = new Mind({
|
|
350
|
+
seed: 7,
|
|
351
|
+
});
|
|
352
|
+
await m.ingest(ARITH);
|
|
353
|
+
assert.equal(await m.respondText("what is 2+2"), "4");
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test("arithmetic: two facts with gap preserved", async () => {
|
|
357
|
+
const m = new Mind({
|
|
358
|
+
seed: 7,
|
|
359
|
+
});
|
|
360
|
+
await m.ingest(ARITH);
|
|
361
|
+
assert.equal(await m.respondText("2+2 3+3"), "4 6");
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// =========================================================================
|
|
365
|
+
// 11 — Grounding and concept cross-transfer
|
|
366
|
+
// =========================================================================
|
|
367
|
+
|
|
368
|
+
test("concept cross-transfer: knowledge in one language, asked in another", async () => {
|
|
369
|
+
const m = new Mind({
|
|
370
|
+
seed: 7,
|
|
371
|
+
});
|
|
372
|
+
// Fact only in English
|
|
373
|
+
await m.ingest("ice", "ice is frozen water");
|
|
374
|
+
// Ground both names identically
|
|
375
|
+
await m.ingest(["ctx-a", "ice"]);
|
|
376
|
+
await m.ingest(["ctx-b", "ice"]);
|
|
377
|
+
await m.ingest(["ctx-a", "hielo"]);
|
|
378
|
+
await m.ingest(["ctx-b", "hielo"]);
|
|
379
|
+
// Ask in Spanish — should get Spanish answer
|
|
380
|
+
assert.equal(await m.respondText("hielo"), "hielo is frozen water");
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
test("multi-name concept: three languages", async () => {
|
|
384
|
+
const m = new Mind({
|
|
385
|
+
seed: 7,
|
|
386
|
+
});
|
|
387
|
+
await m.ingest("ice", "ice is frozen water");
|
|
388
|
+
await m.ingest(["ctx-a", "ice"]);
|
|
389
|
+
await m.ingest(["ctx-a", "hielo"]);
|
|
390
|
+
await m.ingest(["ctx-a", "氷"]);
|
|
391
|
+
await m.ingest(["ctx-b", "ice"]);
|
|
392
|
+
await m.ingest(["ctx-b", "hielo"]);
|
|
393
|
+
await m.ingest(["ctx-b", "氷"]);
|
|
394
|
+
assert.equal(await m.respondText("氷"), "氷 is frozen water");
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// =========================================================================
|
|
398
|
+
// 12 — Edge cases & silence
|
|
399
|
+
// =========================================================================
|
|
400
|
+
|
|
401
|
+
test("empty query is silent", async () => {
|
|
402
|
+
const m = new Mind({
|
|
403
|
+
seed: 7,
|
|
404
|
+
});
|
|
405
|
+
await m.ingest([["a", "b"]]);
|
|
406
|
+
assert.equal((await m.respond("")).v, null);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
test("completely unknown query: returns null or closest approximation", async () => {
|
|
410
|
+
const m = new Mind({
|
|
411
|
+
seed: 7,
|
|
412
|
+
});
|
|
413
|
+
await m.ingest([["2+2", "4"]]);
|
|
414
|
+
// Without artificial recall thresholds, unknown queries may return
|
|
415
|
+
// a closest-approximation answer or null. Both are valid.
|
|
416
|
+
const r = await m.respond("3+5");
|
|
417
|
+
assert.ok(r.v !== undefined, "respond returns a valid response");
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
test("partial unknown, partial known: known fires, unknown handled gracefully", async () => {
|
|
421
|
+
const m = new Mind({
|
|
422
|
+
seed: 7,
|
|
423
|
+
});
|
|
424
|
+
await m.ingest([["2+2", "4"]]);
|
|
425
|
+
// "3+5" is unknown — may return null or a closest approximation.
|
|
426
|
+
const r = await m.respond("what is 3+5");
|
|
427
|
+
assert.ok(r.v !== undefined, "respond returns a valid response");
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
test("single letter floor: related byte grounds, unrelated is silent", async () => {
|
|
431
|
+
const m = new Mind({
|
|
432
|
+
seed: 7,
|
|
433
|
+
});
|
|
434
|
+
await m.ingest([["2+2", "4"]]);
|
|
435
|
+
// A byte that appears in the stored context still resonates to its grounded
|
|
436
|
+
// form. An unrelated byte — one with no structural relationship to anything
|
|
437
|
+
// in the store — now returns null: the reach threshold (1 − 1/(2·maxGroup))
|
|
438
|
+
// prevents fabricating an answer from an unrelated form.
|
|
439
|
+
const related = await m.respond("4");
|
|
440
|
+
assert.ok(
|
|
441
|
+
related.v !== null,
|
|
442
|
+
'"4" (appears in store) returns its grounded form',
|
|
443
|
+
);
|
|
444
|
+
assert.ok(related.bytes.length > 0, '"4" returns bytes');
|
|
445
|
+
|
|
446
|
+
const unrelated = await m.respond("a");
|
|
447
|
+
assert.equal(unrelated.v, null, '"a" (unrelated to store) returns null');
|
|
448
|
+
assert.equal(unrelated.bytes.length, 0, '"a" returns empty bytes');
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
test("multi-byte known part with single-char prefix fires", async () => {
|
|
452
|
+
const m = new Mind({
|
|
453
|
+
seed: 7,
|
|
454
|
+
});
|
|
455
|
+
await m.ingest([["ab", "XY"]]);
|
|
456
|
+
assert.equal(await m.respondText("x ab"), "XY");
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
// =========================================================================
|
|
460
|
+
// 13 — Persistence: concepts and chains survive save/load
|
|
461
|
+
// =========================================================================
|
|
462
|
+
|
|
463
|
+
test("chain works after save/load", async () => {
|
|
464
|
+
const store = new SQliteStore({ path: ":memory:" });
|
|
465
|
+
const m = new Mind({ seed: 7, store });
|
|
466
|
+
await m.ingest([["a", "b"], ["b", "c"]]);
|
|
467
|
+
await m.save();
|
|
468
|
+
const m2 = await Mind.loadFromStore(store);
|
|
469
|
+
assert.equal(await m2.respondText("a"), "c");
|
|
470
|
+
await store.close();
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
// =========================================================================
|
|
474
|
+
// 15 — Nested: training episodes contain known parts that themselves fire
|
|
475
|
+
// =========================================================================
|
|
476
|
+
|
|
477
|
+
test("training: ingest pair whose sides are themselves known", async () => {
|
|
478
|
+
const m = new Mind({
|
|
479
|
+
seed: 7,
|
|
480
|
+
});
|
|
481
|
+
// First establish a→b, then train (a, fact) — fact contains "b" which chains
|
|
482
|
+
await m.ingest([["a", "b"]]);
|
|
483
|
+
await m.ingest("a", "the answer is b");
|
|
484
|
+
assert.equal(await m.respondText("a"), "b");
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
// =========================================================================
|
|
488
|
+
// 16 — Same meaning, different surface forms
|
|
489
|
+
// =========================================================================
|
|
490
|
+
|
|
491
|
+
test("same meaning in different casing still fires", async () => {
|
|
492
|
+
const m = new Mind({
|
|
493
|
+
seed: 7,
|
|
494
|
+
});
|
|
495
|
+
// Note: sema does NOT normalize case — this tests exact match
|
|
496
|
+
await m.ingest([["ICE", "cold"]]);
|
|
497
|
+
assert.equal(await m.respondText("ICE"), "cold");
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
// =========================================================================
|
|
501
|
+
// 17 — Multi-utterance queries
|
|
502
|
+
// =========================================================================
|
|
503
|
+
|
|
504
|
+
test("newline-separated facts fire independently", async () => {
|
|
505
|
+
const m = new Mind({
|
|
506
|
+
seed: 7,
|
|
507
|
+
});
|
|
508
|
+
await m.ingest([["ice", "cold"], ["fire", "hot"]]);
|
|
509
|
+
const r = await m.respondText("ice\nfire");
|
|
510
|
+
assert.ok(r.includes("cold") && r.includes("hot"));
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// =========================================================================
|
|
514
|
+
// 18 — Known part at boundaries
|
|
515
|
+
// =========================================================================
|
|
516
|
+
|
|
517
|
+
test("known part at very start of stream", async () => {
|
|
518
|
+
const m = new Mind({
|
|
519
|
+
seed: 7,
|
|
520
|
+
});
|
|
521
|
+
await m.ingest([["abc", "XYZ"]]);
|
|
522
|
+
assert.equal(await m.respondText("abc def"), "XYZ");
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
test("known part at very end of stream", async () => {
|
|
526
|
+
const m = new Mind({
|
|
527
|
+
seed: 7,
|
|
528
|
+
});
|
|
529
|
+
await m.ingest([["abc", "XYZ"]]);
|
|
530
|
+
assert.equal(await m.respondText("def abc"), "XYZ");
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
// =========================================================================
|
|
534
|
+
// 19 — Very long chains
|
|
535
|
+
// =========================================================================
|
|
536
|
+
|
|
537
|
+
test("5-step chain", async () => {
|
|
538
|
+
const m = new Mind({
|
|
539
|
+
seed: 7,
|
|
540
|
+
});
|
|
541
|
+
await m.ingest([["a", "b"], ["b", "c"], ["c", "d"], ["d", "e"], ["e", "f"]]);
|
|
542
|
+
assert.equal(await m.respondText("a"), "f");
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
// =========================================================================
|
|
546
|
+
// 20 — Multiple rewrites of the same part across iterations
|
|
547
|
+
// =========================================================================
|
|
548
|
+
|
|
549
|
+
test("same position rewritten multiple times as chain progresses", async () => {
|
|
550
|
+
const m = new Mind({
|
|
551
|
+
seed: 7,
|
|
552
|
+
});
|
|
553
|
+
await m.ingest([["x", "y"], ["y", "z"], ["z", "w"]]);
|
|
554
|
+
// "x" at position 0 gets rewritten y→z→w across 3 iterations
|
|
555
|
+
assert.equal(await m.respondText("x"), "w");
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// =========================================================================
|
|
559
|
+
// 21 — Training that includes the answer as prefix/suffix
|
|
560
|
+
// =========================================================================
|
|
561
|
+
|
|
562
|
+
test("fact with surrounding whitespace", async () => {
|
|
563
|
+
const m = new Mind({
|
|
564
|
+
seed: 7,
|
|
565
|
+
});
|
|
566
|
+
await m.ingest([[" ice ", "cold"]]);
|
|
567
|
+
assert.equal(await m.respondText(" ice "), "cold");
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
// =========================================================================
|
|
571
|
+
// 22 — Determinism
|
|
572
|
+
// =========================================================================
|
|
573
|
+
|
|
574
|
+
test("same seed, same training, same answer", async () => {
|
|
575
|
+
const run = async () => {
|
|
576
|
+
const m = new Mind({
|
|
577
|
+
seed: 99,
|
|
578
|
+
});
|
|
579
|
+
await m.ingest([["a", "b"], ["b", "c"]]);
|
|
580
|
+
return await m.respondText("a");
|
|
581
|
+
};
|
|
582
|
+
assert.equal(await run(), await run());
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
// =========================================================================
|
|
586
|
+
// 23 — Negation
|
|
587
|
+
// =========================================================================
|
|
588
|
+
|
|
589
|
+
test("negation: not X → not-X", async () => {
|
|
590
|
+
const m = new Mind({
|
|
591
|
+
seed: 7,
|
|
592
|
+
});
|
|
593
|
+
await m.ingest([["a tree", "tree"], ["not a tree", "not-tree"]]);
|
|
594
|
+
assert.equal(await m.respondText("not a tree"), "not-tree");
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
test("negation: double negation not not X → X", async () => {
|
|
598
|
+
const m = new Mind({
|
|
599
|
+
seed: 7,
|
|
600
|
+
});
|
|
601
|
+
await m.ingest([["not X", "not-X"], ["not not-X", "X"]]);
|
|
602
|
+
assert.equal(await m.respondText("not not X"), "X");
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
test("negation: arithmetic true/false statement", async () => {
|
|
606
|
+
const m = new Mind({
|
|
607
|
+
seed: 7,
|
|
608
|
+
});
|
|
609
|
+
await m.ingest([["2+2", "4"], ["2+2=5", "false"], ["2+2=4", "true"]]);
|
|
610
|
+
assert.equal(await m.respondText("2+2=4"), "true");
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
test("negation: opposite facts", async () => {
|
|
614
|
+
const m = new Mind({
|
|
615
|
+
seed: 7,
|
|
616
|
+
});
|
|
617
|
+
await m.ingest([["ice is hot", "false"], ["ice is cold", "true"]]);
|
|
618
|
+
assert.equal(await m.respondText("ice is cold"), "true");
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
test("negation: aligned structure preserved (not happy → sad)", async () => {
|
|
622
|
+
const m = new Mind({
|
|
623
|
+
seed: 7,
|
|
624
|
+
});
|
|
625
|
+
await m.ingest([["happy", "glad"], ["not happy", "sad"]]);
|
|
626
|
+
assert.equal(await m.respondText("not happy"), "sad");
|
|
627
|
+
});
|