@hviana/sema 0.1.0 → 0.1.2
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/example/demo.d.ts +1 -0
- package/dist/example/demo.js +39 -0
- package/dist/example/train_base.d.ts +87 -0
- package/dist/example/train_base.js +2216 -0
- package/dist/src/alphabet.d.ts +7 -0
- package/dist/src/alphabet.js +33 -0
- package/dist/src/alu/src/alu.d.ts +185 -0
- package/dist/src/alu/src/alu.js +440 -0
- package/dist/src/alu/src/expr.d.ts +61 -0
- package/dist/src/alu/src/expr.js +318 -0
- package/dist/src/alu/src/index.d.ts +11 -0
- package/dist/src/alu/src/index.js +19 -0
- package/dist/src/alu/src/kernel-arith.d.ts +16 -0
- package/dist/src/alu/src/kernel-arith.js +264 -0
- package/dist/src/alu/src/kernel-bits.d.ts +19 -0
- package/dist/src/alu/src/kernel-bits.js +152 -0
- package/dist/src/alu/src/kernel-logic.d.ts +4 -0
- package/dist/src/alu/src/kernel-logic.js +60 -0
- package/dist/src/alu/src/kernel-nd.d.ts +3 -0
- package/dist/src/alu/src/kernel-nd.js +208 -0
- package/dist/src/alu/src/kernel-numeric.d.ts +54 -0
- package/dist/src/alu/src/kernel-numeric.js +366 -0
- package/dist/src/alu/src/operation.d.ts +168 -0
- package/dist/src/alu/src/operation.js +189 -0
- package/dist/src/alu/src/parser.d.ts +212 -0
- package/dist/src/alu/src/parser.js +469 -0
- package/dist/src/alu/src/resonance.d.ts +55 -0
- package/dist/src/alu/src/resonance.js +126 -0
- package/dist/src/alu/src/text.d.ts +31 -0
- package/dist/src/alu/src/text.js +73 -0
- package/dist/src/alu/src/value.d.ts +109 -0
- package/dist/src/alu/src/value.js +300 -0
- package/dist/src/alu/test/alu.test.d.ts +1 -0
- package/dist/src/alu/test/alu.test.js +764 -0
- package/dist/src/bytes.d.ts +14 -0
- package/dist/src/bytes.js +59 -0
- package/dist/src/config.d.ts +114 -0
- package/dist/src/config.js +96 -0
- package/dist/src/derive/src/deduction.d.ts +125 -0
- package/dist/src/derive/src/deduction.js +155 -0
- package/dist/src/derive/src/index.d.ts +7 -0
- package/dist/src/derive/src/index.js +11 -0
- package/dist/src/derive/src/priority-queue.d.ts +20 -0
- package/dist/src/derive/src/priority-queue.js +73 -0
- package/dist/src/derive/src/rewrite.d.ts +56 -0
- package/dist/src/derive/src/rewrite.js +100 -0
- package/dist/src/derive/src/trie.d.ts +90 -0
- package/dist/src/derive/src/trie.js +217 -0
- package/dist/src/derive/test/derive.test.d.ts +1 -0
- package/dist/src/derive/test/derive.test.js +122 -0
- package/dist/src/extension.d.ts +37 -0
- package/dist/src/extension.js +7 -0
- package/dist/src/geometry.d.ts +137 -0
- package/dist/src/geometry.js +430 -0
- package/dist/src/index.d.ts +15 -0
- package/dist/src/index.js +21 -0
- package/dist/src/ingest-cache.d.ts +41 -0
- package/dist/src/ingest-cache.js +161 -0
- package/dist/src/mind/articulation.d.ts +6 -0
- package/dist/src/mind/articulation.js +99 -0
- package/dist/src/mind/attention.d.ts +72 -0
- package/dist/src/mind/attention.js +894 -0
- package/dist/src/mind/canonical.d.ts +29 -0
- package/dist/src/mind/canonical.js +88 -0
- package/dist/src/mind/graph-search.d.ts +270 -0
- package/dist/src/mind/graph-search.js +847 -0
- package/dist/src/mind/index.d.ts +5 -0
- package/dist/src/mind/index.js +5 -0
- package/dist/src/mind/junction.d.ts +95 -0
- package/dist/src/mind/junction.js +262 -0
- package/dist/src/mind/learning.d.ts +47 -0
- package/dist/src/mind/learning.js +201 -0
- package/dist/src/mind/match.d.ts +111 -0
- package/dist/src/mind/match.js +422 -0
- package/dist/src/mind/mechanisms/alu.d.ts +4 -0
- package/dist/src/mind/mechanisms/alu.js +29 -0
- package/dist/src/mind/mechanisms/cast.d.ts +35 -0
- package/dist/src/mind/mechanisms/cast.js +447 -0
- package/dist/src/mind/mechanisms/confluence.d.ts +24 -0
- package/dist/src/mind/mechanisms/confluence.js +213 -0
- package/dist/src/mind/mechanisms/cover.d.ts +6 -0
- package/dist/src/mind/mechanisms/cover.js +179 -0
- package/dist/src/mind/mechanisms/extraction.d.ts +67 -0
- package/dist/src/mind/mechanisms/extraction.js +342 -0
- package/dist/src/mind/mechanisms/recall.d.ts +13 -0
- package/dist/src/mind/mechanisms/recall.js +151 -0
- package/dist/src/mind/mind.d.ts +147 -0
- package/dist/src/mind/mind.js +300 -0
- package/dist/src/mind/pipeline-mechanism.d.ts +142 -0
- package/dist/src/mind/pipeline-mechanism.js +213 -0
- package/dist/src/mind/pipeline.d.ts +20 -0
- package/dist/src/mind/pipeline.js +185 -0
- package/dist/src/mind/primitives.d.ts +43 -0
- package/dist/src/mind/primitives.js +162 -0
- package/dist/src/mind/rationale.d.ts +134 -0
- package/dist/src/mind/rationale.js +162 -0
- package/dist/src/mind/reasoning.d.ts +15 -0
- package/dist/src/mind/reasoning.js +162 -0
- package/dist/src/mind/recognition.d.ts +20 -0
- package/dist/src/mind/recognition.js +223 -0
- package/dist/src/mind/resonance.d.ts +23 -0
- package/dist/src/mind/resonance.js +0 -0
- package/dist/src/mind/trace.d.ts +15 -0
- package/dist/src/mind/trace.js +73 -0
- package/dist/src/mind/traverse.d.ts +100 -0
- package/dist/src/mind/traverse.js +447 -0
- package/dist/src/mind/types.d.ts +174 -0
- package/dist/src/mind/types.js +84 -0
- package/dist/src/rabitq-hnsw/src/database.d.ts +200 -0
- package/dist/src/rabitq-hnsw/src/database.js +388 -0
- package/dist/src/rabitq-hnsw/src/heap.d.ts +22 -0
- package/dist/src/rabitq-hnsw/src/heap.js +89 -0
- package/dist/src/rabitq-hnsw/src/hnsw.d.ts +125 -0
- package/dist/src/rabitq-hnsw/src/hnsw.js +474 -0
- package/dist/src/rabitq-hnsw/src/index.d.ts +10 -0
- package/dist/src/rabitq-hnsw/src/index.js +6 -0
- package/dist/src/rabitq-hnsw/src/prng.d.ts +19 -0
- package/dist/src/rabitq-hnsw/src/prng.js +36 -0
- package/dist/src/rabitq-hnsw/src/rabitq.d.ts +95 -0
- package/dist/src/rabitq-hnsw/src/rabitq.js +283 -0
- package/dist/src/rabitq-hnsw/src/store.d.ts +162 -0
- package/dist/src/rabitq-hnsw/src/store.js +825 -0
- package/dist/src/rabitq-hnsw/test/hnsw.test.d.ts +1 -0
- package/dist/src/rabitq-hnsw/test/hnsw.test.js +948 -0
- package/dist/src/store-sqlite.d.ts +149 -0
- package/dist/src/store-sqlite.js +702 -0
- package/dist/src/store.d.ts +638 -0
- package/dist/src/store.js +1618 -0
- package/dist/src/vec.d.ts +31 -0
- package/dist/src/vec.js +109 -0
- package/package.json +1 -1
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
// extraction.ts — Extraction (Skill) — Section 4 of the mind.
|
|
2
|
+
//
|
|
3
|
+
// Given a query and its consensus-ranked anchors, find the first span-shaped
|
|
4
|
+
// skill exemplar among the ranked anchors and read the analogous span of the
|
|
5
|
+
// query. A skill exemplar is a learnt fact whose context and answer together
|
|
6
|
+
// form a span-in-context pattern: the answer is a subsequence of the context
|
|
7
|
+
// (or one of its pieces is), and the context is the smallest spanning frame
|
|
8
|
+
// that contains it.
|
|
9
|
+
import { foldTree, perceive, read, resolve } from "../primitives.js";
|
|
10
|
+
import { follow, locate } from "../match.js";
|
|
11
|
+
import { chooseAmong, hubBound } from "../traverse.js";
|
|
12
|
+
import { concatBytes, indexOf } from "../../bytes.js";
|
|
13
|
+
import { decodeText, unexplainedLabel } from "../rationale.js";
|
|
14
|
+
import { CONCEPT, STEP } from "../graph-search.js";
|
|
15
|
+
import { rItem, rNode, traceFail } from "../trace.js";
|
|
16
|
+
// ── Extraction ────────────────────────────────────────────────────────────
|
|
17
|
+
/** Find the first span-shaped skill exemplar among the ranked anchors from
|
|
18
|
+
* climbAttentionAll and read the analogous span from the query. Returns
|
|
19
|
+
* the extracted bytes PLUS the query spans the skill ACCOUNTED FOR — the
|
|
20
|
+
* located frames AND any read span BOUNDED by located frames on both
|
|
21
|
+
* sides, the elementary evidence think's grounding decider weighs. A
|
|
22
|
+
* bounded read is explained: the skill located both its borders in the
|
|
23
|
+
* query and emitted exactly what sits between them. An OPEN-ENDED read
|
|
24
|
+
* (the exemplar's answer reaches the context's end, so the query is read
|
|
25
|
+
* to its own end with no located right border) remains a guess about where
|
|
26
|
+
* the span stops — it stays unaccounted, priced by exclusion like the
|
|
27
|
+
* cover's bridged bytes. (Accounting frames only — the earlier convention
|
|
28
|
+
* — let a CAST juxtaposition that merely echoed the query's exact site
|
|
29
|
+
* outweigh a correct bounded extraction: the same span counted as
|
|
30
|
+
* explained for one mechanism and not the other, and the asymmetry, not
|
|
31
|
+
* the answers' merits, decided the grounding.) Null when no skill
|
|
32
|
+
* applies. */
|
|
33
|
+
export async function extractBySkill(ctx, query, pre) {
|
|
34
|
+
const t = ctx.trace?.enter("extractBySkill", [
|
|
35
|
+
rItem(query, "query"),
|
|
36
|
+
]);
|
|
37
|
+
const fail = traceFail(t);
|
|
38
|
+
// Use climbAttentionAll to get the FULL ranked list, not just the
|
|
39
|
+
// roots that cleared commitVotes' significance floor. The floor
|
|
40
|
+
// gates further points of attention for fusion, but extraction only
|
|
41
|
+
// needs ONE anchor that IS a span-shaped skill exemplar — and on
|
|
42
|
+
// some seeds the top-voted anchor is not one (e.g. a concept-merge
|
|
43
|
+
// nickname outvotes the painting exemplars on shared substrings,
|
|
44
|
+
// while the exemplars' votes fall below the floor). Iterating the
|
|
45
|
+
// ranked list instead of just the roots lets extraction reach the
|
|
46
|
+
// first painting-exemplar anchor regardless of its floor status.
|
|
47
|
+
//
|
|
48
|
+
const { ranked } = await pre.attention();
|
|
49
|
+
if (ranked.length === 0) {
|
|
50
|
+
return fail("no consensus anchor — no skill to apply");
|
|
51
|
+
}
|
|
52
|
+
let exemplar = null;
|
|
53
|
+
let chosenAnchor = null;
|
|
54
|
+
let skipped = 0;
|
|
55
|
+
for (const cand of ranked) {
|
|
56
|
+
const ex = await pre.spanShapedOf(cand.anchor);
|
|
57
|
+
if (ex) {
|
|
58
|
+
exemplar = ex;
|
|
59
|
+
chosenAnchor = cand.anchor;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
skipped++;
|
|
63
|
+
}
|
|
64
|
+
if (exemplar === null) {
|
|
65
|
+
ctx.trace?.step("trySkillAnchors", [], [], `none of ${ranked.length} ranked anchor(s) is a span-shaped skill exemplar`);
|
|
66
|
+
return fail("no consensus root is a span-shaped skill exemplar");
|
|
67
|
+
}
|
|
68
|
+
if (skipped > 0) {
|
|
69
|
+
ctx.trace?.step("trySkillAnchors", [
|
|
70
|
+
rItem(query.subarray(0, 0), `skipped ${skipped}`),
|
|
71
|
+
rNode(ctx, chosenAnchor, "chosen"),
|
|
72
|
+
], [], `skipped ${skipped} anchor(s) that are not skill exemplars`);
|
|
73
|
+
}
|
|
74
|
+
const { contextBytes, answerBytes } = exemplar;
|
|
75
|
+
const ansCtxRuns = answerRunsInContext(ctx, contextBytes, answerBytes);
|
|
76
|
+
if (ansCtxRuns === null || ansCtxRuns.length === 0) {
|
|
77
|
+
return fail("answer is not a subsequence of the context");
|
|
78
|
+
}
|
|
79
|
+
if (ansCtxRuns.length > 1) {
|
|
80
|
+
ctx.trace?.step("decomposeAnswer", [rItem(answerBytes, "multi-piece-answer")], ansCtxRuns.map((r) => rItem(contextBytes.subarray(r.start, r.end), "piece", undefined, [
|
|
81
|
+
r.start,
|
|
82
|
+
r.end,
|
|
83
|
+
])), `answer splits into ${ansCtxRuns.length} piece(s) within the exemplar context`);
|
|
84
|
+
}
|
|
85
|
+
const pieces = [];
|
|
86
|
+
const accounted = [];
|
|
87
|
+
for (let ri = 0; ri < ansCtxRuns.length; ri++) {
|
|
88
|
+
const run = ansCtxRuns[ri];
|
|
89
|
+
const isLast = ri === ansCtxRuns.length - 1;
|
|
90
|
+
const framePreLen = Math.min(run.start, ctx.space.maxGroup);
|
|
91
|
+
const framePre = run.start > 0
|
|
92
|
+
? contextBytes.subarray(run.start - framePreLen, run.start)
|
|
93
|
+
: null;
|
|
94
|
+
const frames = [];
|
|
95
|
+
let start = 0;
|
|
96
|
+
if (framePre) {
|
|
97
|
+
const prePos = locate(ctx, query, framePre, 0, pre.rec.sites);
|
|
98
|
+
if (prePos < 0)
|
|
99
|
+
continue;
|
|
100
|
+
start = prePos + framePre.length;
|
|
101
|
+
frames.push([prePos, start]); // the located frame IS matched evidence
|
|
102
|
+
}
|
|
103
|
+
let end;
|
|
104
|
+
if (isLast) {
|
|
105
|
+
if (run.end < contextBytes.length) {
|
|
106
|
+
const framePostLen = Math.min(contextBytes.length - run.end, ctx.space.maxGroup);
|
|
107
|
+
const framePost = contextBytes.subarray(run.end, run.end + framePostLen);
|
|
108
|
+
const postPos = locate(ctx, query.subarray(start), framePost, 0, pre.rec.sites);
|
|
109
|
+
if (postPos < 0)
|
|
110
|
+
continue;
|
|
111
|
+
end = start + postPos;
|
|
112
|
+
frames.push([end, end + framePost.length]); // matched post-frame
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
end = query.length;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
const nextRun = ansCtxRuns[ri + 1];
|
|
120
|
+
const nextPreLen = Math.min(nextRun.start, ctx.space.maxGroup);
|
|
121
|
+
const nextPre = contextBytes.subarray(nextRun.start - nextPreLen, nextRun.start);
|
|
122
|
+
const nextPos = locate(ctx, query.subarray(start), nextPre, 0, pre.rec.sites);
|
|
123
|
+
if (nextPos < 0) {
|
|
124
|
+
end = start + run.ansLen;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
end = start + nextPos;
|
|
128
|
+
frames.push([end, end + nextPre.length]); // matched next-frame
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (start >= end)
|
|
132
|
+
continue;
|
|
133
|
+
pieces.push(query.subarray(start, end));
|
|
134
|
+
accounted.push(...frames);
|
|
135
|
+
// Bounded on both sides ⇒ the read span itself is explained (see doc).
|
|
136
|
+
// frames carries the pre-border (when the answer is not at the context's
|
|
137
|
+
// start) and the located right border (post-frame or next piece's
|
|
138
|
+
// pre-frame); only when BOTH borders were located is the read bounded.
|
|
139
|
+
const preBounded = run.start === 0 || frames.some(([, e]) => e === start);
|
|
140
|
+
const postBounded = frames.some(([b]) => b === end);
|
|
141
|
+
if (preBounded && postBounded)
|
|
142
|
+
accounted.push([start, end]);
|
|
143
|
+
}
|
|
144
|
+
if (pieces.length === 0) {
|
|
145
|
+
return fail("no answer piece's frame located in the query");
|
|
146
|
+
}
|
|
147
|
+
const out = pieces.length === 1 ? pieces[0] : concatBytes(pieces);
|
|
148
|
+
t?.done([rItem(out, "extracted")], pieces.length === 1
|
|
149
|
+
? `apply a learnt extraction skill — read the analogous span of the query` +
|
|
150
|
+
` framed like "${decodeText(answerBytes)}" sits in its exemplar`
|
|
151
|
+
: `apply a learnt MULTI-PIECE skill — read ${pieces.length} analogous` +
|
|
152
|
+
` pieces of the query and synthesize them like "${decodeText(answerBytes)}"`);
|
|
153
|
+
return {
|
|
154
|
+
bytes: out,
|
|
155
|
+
accounted,
|
|
156
|
+
unexplained: unexplainedLabel(query, accounted),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// ── The two span-shape readings: OPEN acceptance vs. STRONG decomposition ──
|
|
160
|
+
//
|
|
161
|
+
// isSpanShaped and answerRunsInContext read the SAME relation ("the answer is
|
|
162
|
+
// drawn from the context") at two deliberately different strengths, and they
|
|
163
|
+
// are NOT interchangeable:
|
|
164
|
+
//
|
|
165
|
+
// • isSpanShaped — the OPEN reading: any in-order embedding (a sparse
|
|
166
|
+
// subsequence, arbitrary gaps). O(|context|) byte scan. Used to ACCEPT
|
|
167
|
+
// an exemplar candidate.
|
|
168
|
+
// • answerRunsInContext — the STRONG reading: a greedy longest-run
|
|
169
|
+
// DECOMPOSITION into contiguous pieces. Greedy-longest is strictly
|
|
170
|
+
// stronger than subsequence (a long late match can consume context an
|
|
171
|
+
// earlier shorter choice needed), so an ACCEPTED exemplar can still fail
|
|
172
|
+
// to decompose — extractBySkill then fails with "answer is not a
|
|
173
|
+
// subsequence of the context" and think falls through to recall. That
|
|
174
|
+
// fall-through is BEHAVIOUR, pinned by the extraction suites: do not
|
|
175
|
+
// "unify" the two into one machine — replacing the open reading with the
|
|
176
|
+
// strong one silently rejects exemplars extraction today accepts, and
|
|
177
|
+
// replacing the strong one with a backtracking embedding changes which
|
|
178
|
+
// pieces are read out of the query.
|
|
179
|
+
/** Decompose an answer into substrings of its surrounding context, in order —
|
|
180
|
+
* the STRONG span-shape reading (see the section note above). Returns null
|
|
181
|
+
* when no greedy longest-run decomposition exists. Adjacent runs that
|
|
182
|
+
* connect contiguously are merged. */
|
|
183
|
+
export function answerRunsInContext(_ctx, context, answer) {
|
|
184
|
+
const pos = indexOf(context, answer, 0);
|
|
185
|
+
if (pos >= 0) {
|
|
186
|
+
return [{ start: pos, end: pos + answer.length, ansLen: answer.length }];
|
|
187
|
+
}
|
|
188
|
+
const runs = [];
|
|
189
|
+
let ai = 0;
|
|
190
|
+
let ci = 0;
|
|
191
|
+
while (ai < answer.length) {
|
|
192
|
+
// Longest match of the remaining answer at any position of the remaining
|
|
193
|
+
// context: one direct extend per context position — O(|ctx|·match) per
|
|
194
|
+
// run, replacing the previous longest-first indexOf countdown whose
|
|
195
|
+
// repeated scans were cubic on long sparse-subsequence answers.
|
|
196
|
+
let bestLen = 0;
|
|
197
|
+
let bestPos = -1;
|
|
198
|
+
for (let p = ci; p < context.length; p++) {
|
|
199
|
+
let l = 0;
|
|
200
|
+
const maxL = Math.min(context.length - p, answer.length - ai);
|
|
201
|
+
if (maxL <= bestLen)
|
|
202
|
+
break; // no later position can beat the best
|
|
203
|
+
while (l < maxL && context[p + l] === answer[ai + l])
|
|
204
|
+
l++;
|
|
205
|
+
if (l > bestLen) {
|
|
206
|
+
bestLen = l;
|
|
207
|
+
bestPos = p;
|
|
208
|
+
if (ai + l === answer.length)
|
|
209
|
+
break; // the whole remainder matched
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (bestLen === 0)
|
|
213
|
+
return null;
|
|
214
|
+
runs.push({ start: bestPos, end: bestPos + bestLen, ansLen: bestLen });
|
|
215
|
+
ai += bestLen;
|
|
216
|
+
ci = bestPos + bestLen;
|
|
217
|
+
}
|
|
218
|
+
const merged = [];
|
|
219
|
+
for (const r of runs) {
|
|
220
|
+
const last = merged[merged.length - 1];
|
|
221
|
+
if (last && r.start === last.end) {
|
|
222
|
+
last.end = r.end;
|
|
223
|
+
last.ansLen += r.ansLen;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
merged.push({ ...r });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return merged.length > 0 ? merged : null;
|
|
230
|
+
}
|
|
231
|
+
/** Check whether an anchor is a span-shaped skill exemplar: it represents a
|
|
232
|
+
* fact whose context and answer together form a span-in-context pattern.
|
|
233
|
+
* If the anchor has a nextOf continuation, that is the answer and the anchor
|
|
234
|
+
* itself is the context. Otherwise the anchor's prevOf parents provide
|
|
235
|
+
* candidate contexts, and the longest one whose span is span-shaped wins. */
|
|
236
|
+
export async function skillExemplar(ctx, anchor, guide) {
|
|
237
|
+
if (ctx.store.hasNext(anchor)) {
|
|
238
|
+
const contextBytes = read(ctx, anchor);
|
|
239
|
+
const answerBytes = await follow(ctx, anchor, guide);
|
|
240
|
+
if (answerBytes !== null && isSpanShaped(ctx, contextBytes, answerBytes)) {
|
|
241
|
+
return { contextBytes, answerBytes };
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
const answerBytes = read(ctx, anchor);
|
|
246
|
+
// Candidate contexts, capped at the hub bound (a common answer's reverse
|
|
247
|
+
// fan-in is corpus-sized).
|
|
248
|
+
const capped = ctx.store.prevFirst(anchor, hubBound(ctx));
|
|
249
|
+
const spanShaped = [];
|
|
250
|
+
for (const p of capped) {
|
|
251
|
+
const ctxB = read(ctx, p);
|
|
252
|
+
if (ctxB.length > 0 && isSpanShaped(ctx, ctxB, answerBytes)) {
|
|
253
|
+
spanShaped.push({ id: p, bytes: ctxB });
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (spanShaped.length === 0)
|
|
257
|
+
return null;
|
|
258
|
+
// Among span-shaped contexts, the longest wins (the smallest spanning frame
|
|
259
|
+
// heuristic's dual: more frame to locate in the query); the query gist,
|
|
260
|
+
// when given, breaks LENGTH TIES via chooseAmong — the same reverse-regime
|
|
261
|
+
// disambiguator every context pick uses, whose gist cache spares the
|
|
262
|
+
// re-fold this block once paid per tied candidate. Same strict first-seen
|
|
263
|
+
// tie-break as the hand loop it replaces.
|
|
264
|
+
const maxLen = Math.max(...spanShaped.map((s) => s.bytes.length));
|
|
265
|
+
const longest = spanShaped.filter((s) => s.bytes.length === maxLen);
|
|
266
|
+
let contextBytes = longest[0].bytes;
|
|
267
|
+
if (guide && longest.length > 1) {
|
|
268
|
+
const pick = chooseAmong(ctx, longest.map((s) => s.id), guide).id;
|
|
269
|
+
contextBytes = longest.find((s) => s.id === pick).bytes;
|
|
270
|
+
}
|
|
271
|
+
return { contextBytes, answerBytes };
|
|
272
|
+
}
|
|
273
|
+
/** Whether the answer is a SPARSE subsequence of the context (bytes in
|
|
274
|
+
* order, arbitrary gaps) — the OPEN span-shape reading (see the section
|
|
275
|
+
* note above). This is what lets extraction validate a MULTI-PIECE
|
|
276
|
+
* exemplar whose answer is stitched from several context runs — but it is
|
|
277
|
+
* deliberately permissive, so it must never be used as evidence that one
|
|
278
|
+
* span was "drawn from" another (see {@link containsSpan} for that).
|
|
279
|
+
*
|
|
280
|
+
* There is deliberately NO containsSpan pre-check here: strict containment
|
|
281
|
+
* IMPLIES the subsequence embedding (a contiguous run, or a resolved node —
|
|
282
|
+
* whose content-addressed identity means its bytes occur contiguously — is
|
|
283
|
+
* an in-order embedding with zero gaps), so the scan below decides alone,
|
|
284
|
+
* with the same truth value. The old pre-check re-perceived the context
|
|
285
|
+
* (a full river fold) per CANDIDATE in skillExemplar's √N-capped loop —
|
|
286
|
+
* pure cost, no discrimination. */
|
|
287
|
+
export function isSpanShaped(_ctx, context, answer) {
|
|
288
|
+
let ai = 0;
|
|
289
|
+
for (let ci = 0; ci < context.length && ai < answer.length; ci++) {
|
|
290
|
+
if (context[ci] === answer[ai])
|
|
291
|
+
ai++;
|
|
292
|
+
}
|
|
293
|
+
return ai === answer.length;
|
|
294
|
+
}
|
|
295
|
+
/** STRICT containment: the answer's resolved node appears in the context's
|
|
296
|
+
* folded tree, or the answer occurs as one CONTIGUOUS byte run of the
|
|
297
|
+
* context. This is real evidence the answer was drawn from the context.
|
|
298
|
+
* Fusion gates on this — the sparse-subsequence reading of
|
|
299
|
+
* {@link isSpanShaped} is trivially satisfied by short answers over long
|
|
300
|
+
* queries ("cold" is a gap-tolerant subsequence of most sentences holding
|
|
301
|
+
* c…o…l…d in order), and gating fusion on it silently starved multi-topic
|
|
302
|
+
* queries of their further points of attention. */
|
|
303
|
+
export function containsSpan(ctx, context, answer) {
|
|
304
|
+
const ansId = resolve(ctx, answer);
|
|
305
|
+
if (ansId !== null) {
|
|
306
|
+
let found = false;
|
|
307
|
+
foldTree(ctx, perceive(ctx, context), 0, (_n, _s, _e, node) => {
|
|
308
|
+
if (node === ansId)
|
|
309
|
+
found = true;
|
|
310
|
+
});
|
|
311
|
+
if (found)
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
return indexOf(context, answer, 0) >= 0;
|
|
315
|
+
}
|
|
316
|
+
// ── Pipeline mechanism ──────────────────────────────────────────────────────
|
|
317
|
+
export const extractionMechanism = {
|
|
318
|
+
name: "extraction",
|
|
319
|
+
provenance: "extract",
|
|
320
|
+
async floor(_ctx, _query, pre, worthRunning) {
|
|
321
|
+
// Extraction's floor is always exactly CONCEPT+STEP when it exists —
|
|
322
|
+
// same investment discipline as CAST's (see cast.ts): when the bound
|
|
323
|
+
// already cannot beat the incumbent, return it UNINVESTED (never
|
|
324
|
+
// first-touch the climb just to be pruned).
|
|
325
|
+
if (!worthRunning(CONCEPT + STEP))
|
|
326
|
+
return CONCEPT + STEP;
|
|
327
|
+
if ((await pre.attention()).ranked.length === 0)
|
|
328
|
+
return null;
|
|
329
|
+
return CONCEPT + STEP;
|
|
330
|
+
},
|
|
331
|
+
async run(ctx, query, pre) {
|
|
332
|
+
const ex = await extractBySkill(ctx, query, pre);
|
|
333
|
+
if (!ex)
|
|
334
|
+
return [];
|
|
335
|
+
return [{
|
|
336
|
+
bytes: ex.bytes,
|
|
337
|
+
accounted: ex.accounted,
|
|
338
|
+
moves: CONCEPT + STEP * ex.accounted.length,
|
|
339
|
+
unexplained: ex.unexplained,
|
|
340
|
+
}];
|
|
341
|
+
},
|
|
342
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MindContext } from "../types.js";
|
|
2
|
+
import type { PipelineMechanism, Precomputed } from "../pipeline-mechanism.js";
|
|
3
|
+
/** A recall result. */
|
|
4
|
+
export interface RecallResult {
|
|
5
|
+
bytes: Uint8Array;
|
|
6
|
+
echoed: boolean;
|
|
7
|
+
accounted: Array<[number, number]>;
|
|
8
|
+
moves: number;
|
|
9
|
+
unexplained: string;
|
|
10
|
+
}
|
|
11
|
+
/** Recall the answer by resonating the whole query against the content index. */
|
|
12
|
+
export declare function recallByResonance(ctx: MindContext, query: Uint8Array, pre: Precomputed): Promise<RecallResult | null>;
|
|
13
|
+
export declare const recallMechanism: PipelineMechanism;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// mechanisms/recall.ts — Recall by resonance (Grounding IV).
|
|
2
|
+
//
|
|
3
|
+
// The recall mechanism resonates the whole query's gist against the content
|
|
4
|
+
// index and grounds the nearest learned form. Four tiers, orderly degrading
|
|
5
|
+
// from exact self-match to honest echo.
|
|
6
|
+
import { cosine } from "../../vec.js";
|
|
7
|
+
import { consensusFloor, identityBar, reachThreshold, significanceBar, } from "../../geometry.js";
|
|
8
|
+
import { gistOf, read, resolve } from "../primitives.js";
|
|
9
|
+
import { corpusN, hubBound } from "../traverse.js";
|
|
10
|
+
import { project, reverseContext } from "../match.js";
|
|
11
|
+
import { CONCEPT, STEP } from "../graph-search.js";
|
|
12
|
+
import { unexplainedLabel } from "../rationale.js";
|
|
13
|
+
import { rItem, rNode } from "../trace.js";
|
|
14
|
+
/** Recall the answer by resonating the whole query against the content index. */
|
|
15
|
+
export async function recallByResonance(ctx, query, pre) {
|
|
16
|
+
const t = ctx.trace?.enter("recallByResonance", [
|
|
17
|
+
rItem(query, "query"),
|
|
18
|
+
]);
|
|
19
|
+
const whole_ = [[0, query.length]];
|
|
20
|
+
const nothing = [];
|
|
21
|
+
const ground = (bytes, note, accounted, moves, echoed = false) => {
|
|
22
|
+
t?.done(bytes === null
|
|
23
|
+
? []
|
|
24
|
+
: [rItem(bytes, "answer", resolve(ctx, bytes) ?? undefined)], note);
|
|
25
|
+
return bytes === null ? null : {
|
|
26
|
+
bytes,
|
|
27
|
+
echoed,
|
|
28
|
+
accounted,
|
|
29
|
+
moves,
|
|
30
|
+
unexplained: unexplainedLabel(query, accounted),
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
const k = pre.k;
|
|
34
|
+
const queryGist = pre.guide;
|
|
35
|
+
// 0. Exact self-match — content-addressed, deterministic.
|
|
36
|
+
const qId = pre.queryResolved;
|
|
37
|
+
if (qId !== null) {
|
|
38
|
+
const rev = ctx.store.prevFirst(qId, hubBound(ctx));
|
|
39
|
+
const g = reverseContext(ctx, qId, queryGist, rev);
|
|
40
|
+
if (g !== null) {
|
|
41
|
+
return ground(g, rev.length === 1
|
|
42
|
+
? "exact self-match — reverse recall to the sole predecessor"
|
|
43
|
+
: "exact self-match — reverse recall to the best-resonating predecessor", nothing, STEP);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const whole = await ctx.store.resonate(queryGist, k);
|
|
47
|
+
if (whole.length === 0) {
|
|
48
|
+
return ground(null, "empty store — nothing to resonate with", [], 0);
|
|
49
|
+
}
|
|
50
|
+
const top = whole[0];
|
|
51
|
+
ctx.trace?.step("resonate", [rItem(query, "query-gist")], whole.map((h) => rNode(ctx, h.id, "hit", h.score)), `resonate the whole-query gist → ${whole.length} nearest learnt form(s)`);
|
|
52
|
+
// 1. Clean resonance — the scale-aware identity claim. The ANGLE
|
|
53
|
+
// (top.score) carries the shared fraction; the query's MAGNITUDE (√len,
|
|
54
|
+
// the linear fold's own norm) converts the tolerated foreign fraction
|
|
55
|
+
// into bytes — at most one river window (see {@link identityBar}). A
|
|
56
|
+
// fixed cosine bar let long queries claim "near-identical" while whole
|
|
57
|
+
// windows — an answer word — differed.
|
|
58
|
+
if (top.score >= identityBar(ctx.store.D, ctx.space.maxGroup, query.length)) {
|
|
59
|
+
for (const h of whole) {
|
|
60
|
+
if (h.id === qId || h.score >= 1.0) {
|
|
61
|
+
const rev = ctx.store.prevFirst(h.id, hubBound(ctx));
|
|
62
|
+
const g = reverseContext(ctx, h.id, queryGist, rev);
|
|
63
|
+
if (g !== null) {
|
|
64
|
+
return ground(g, rev.length === 1
|
|
65
|
+
? "perfect self-match — reverse recall to the sole predecessor"
|
|
66
|
+
: "perfect self-match — reverse recall to the best-resonating predecessor", nothing, STEP);
|
|
67
|
+
}
|
|
68
|
+
const own = read(ctx, h.id);
|
|
69
|
+
if (own.length > 0) {
|
|
70
|
+
return ground(own, "perfect self-match — the query IS this node", nothing, STEP);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const g = await project(ctx, h.id, queryGist);
|
|
74
|
+
if (g) {
|
|
75
|
+
return ground(g, "clean whole-query resonance — ground the nearest hit", whole_, STEP);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// 2. Scaffolding-dominated.
|
|
80
|
+
if (top.score >= significanceBar(ctx.store.D)) {
|
|
81
|
+
const N = corpusN(ctx);
|
|
82
|
+
const minVote = consensusFloor(N);
|
|
83
|
+
// The committed points of attention ARE the shared climb's roots (same
|
|
84
|
+
// query, same k, same DF mode) — read them from Precomputed instead of
|
|
85
|
+
// re-climbing, so even a traced response pays for the climb once.
|
|
86
|
+
const forest = (await pre.attention()).roots;
|
|
87
|
+
if (forest.length > 0 && forest[0].vote >= minVote) {
|
|
88
|
+
const g = await project(ctx, forest[0].anchor, queryGist);
|
|
89
|
+
if (g) {
|
|
90
|
+
return ground(g, "scaffolding-dominated query — ground the consensus-climb anchor", [[forest[0].start, forest[0].end]], CONCEPT);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// 3. Last resort — gated on the FRACTION OF THE QUERY the grounding
|
|
95
|
+
// explains, not the raw cosine. Root gists are unit vectors, but their
|
|
96
|
+
// magnitudes are recoverable from the byte lengths (‖·‖ = √len under the
|
|
97
|
+
// linear fold): cos = shared/√(lenQ·lenG), so shared/lenQ = cos·√(lenG/lenQ).
|
|
98
|
+
// The raw cosine punished honest containment — a query fully inside a
|
|
99
|
+
// longer grounded answer scored √(lenQ/lenG) and was refused — and let a
|
|
100
|
+
// long answer sharing only scaffolding pass; the query-relative fraction
|
|
101
|
+
// measures exactly what the reach bar means: how much of THE QUERY the
|
|
102
|
+
// store accounts for.
|
|
103
|
+
const fracOfQuery = (cos, otherLen) => Math.min(1, cos * Math.sqrt(otherLen / Math.max(1, query.length)));
|
|
104
|
+
for (const h of whole) {
|
|
105
|
+
const g = await project(ctx, h.id, queryGist);
|
|
106
|
+
if (g) {
|
|
107
|
+
if (fracOfQuery(cosine(queryGist, gistOf(ctx, g)), g.length) >=
|
|
108
|
+
reachThreshold(ctx.space.maxGroup)) {
|
|
109
|
+
return ground(g, "last resort: the nearest grounded whole-query hit", [], STEP);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// The refusal/echo decision, in the same query-relative units — the top
|
|
114
|
+
// hit's magnitude read from the store (contentLen: √bytes IS the linear
|
|
115
|
+
// fold's gist norm), never from re-reading its bytes.
|
|
116
|
+
// The magnitude read SATURATES at the decision point: frac reaches the
|
|
117
|
+
// reach bar exactly when lenH = lenQ·(reach/score)², so the walk never
|
|
118
|
+
// needs to see past that — a huge conversation root costs a capped read,
|
|
119
|
+
// and a clamped return decides "pass" identically (frac ≥ reach).
|
|
120
|
+
const reach = reachThreshold(ctx.space.maxGroup);
|
|
121
|
+
const lenCap = Math.ceil(query.length * (reach / Math.max(top.score, 1e-6)) ** 2) + 1;
|
|
122
|
+
if (fracOfQuery(top.score, ctx.store.contentLen(top.id, lenCap)) < reach) {
|
|
123
|
+
return ground(null, "below reach threshold — nothing in the store relates to this query", [], 0);
|
|
124
|
+
}
|
|
125
|
+
// Honest echo.
|
|
126
|
+
return ground(read(ctx, top.id), "last resort: the nearest resonant form's own bytes (echo, not grounded)", [], 0, true);
|
|
127
|
+
}
|
|
128
|
+
// ── Pipeline mechanism ──────────────────────────────────────────────────────
|
|
129
|
+
export const recallMechanism = {
|
|
130
|
+
name: "recall",
|
|
131
|
+
provenance: "recall",
|
|
132
|
+
// Recall's floor is free to state (one STEP-grade projection) and its run
|
|
133
|
+
// gates its own tiers — no expensive investment happens inside floor, so
|
|
134
|
+
// there is nothing to guard with worthRunning here: the pipeline's own
|
|
135
|
+
// check prunes run() against the incumbent.
|
|
136
|
+
async floor(_ctx, _query, _pre, _worthRunning) {
|
|
137
|
+
return STEP;
|
|
138
|
+
},
|
|
139
|
+
async run(ctx, query, pre) {
|
|
140
|
+
const r = await recallByResonance(ctx, query, pre);
|
|
141
|
+
if (!r)
|
|
142
|
+
return [];
|
|
143
|
+
return [{
|
|
144
|
+
bytes: r.bytes,
|
|
145
|
+
accounted: r.accounted,
|
|
146
|
+
moves: r.moves,
|
|
147
|
+
unexplained: r.unexplained,
|
|
148
|
+
provenance: r.echoed ? "recall-echo" : "recall",
|
|
149
|
+
}];
|
|
150
|
+
},
|
|
151
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Vec } from "../vec.js";
|
|
2
|
+
import { Sema, Space } from "../sema.js";
|
|
3
|
+
import { Alphabet } from "../alphabet.js";
|
|
4
|
+
import { Grid } from "../geometry.js";
|
|
5
|
+
import { BoundedMap, type Store } from "../store.js";
|
|
6
|
+
import { type MindConfig } from "../config.js";
|
|
7
|
+
import { GraphSearch, type Leaf, type Site } from "./graph-search.js";
|
|
8
|
+
import type { ComputedSpan, ExtensionHost } from "../extension.js";
|
|
9
|
+
export type { ComputedSpan, ExtensionHost };
|
|
10
|
+
import { type InspectRationale, Rationale } from "./rationale.js";
|
|
11
|
+
export type { InspectRationale, RationaleItem, RationaleStep, } from "./rationale.js";
|
|
12
|
+
export type Input = string | Uint8Array | Grid | Grid[];
|
|
13
|
+
export interface Response {
|
|
14
|
+
v: Vec | null;
|
|
15
|
+
bytes: Uint8Array;
|
|
16
|
+
/** How the answer was grounded (see {@link Provenance}). `"recall-echo"`
|
|
17
|
+
* marks the last-resort fallback that returned the nearest stored form's
|
|
18
|
+
* own bytes verbatim — an echo, NOT a grounded fact. Absent when there is
|
|
19
|
+
* no answer. */
|
|
20
|
+
provenance?: import("./pipeline.js").Provenance;
|
|
21
|
+
}
|
|
22
|
+
import type { AttentionRead, MindContext, Recognition } from "./types.js";
|
|
23
|
+
export interface MindOptions {
|
|
24
|
+
seed?: number;
|
|
25
|
+
recallQueryK?: number;
|
|
26
|
+
haloQueryK?: number;
|
|
27
|
+
normalizeEpsilon?: number;
|
|
28
|
+
cosineEpsilon?: number;
|
|
29
|
+
geometry?: Partial<import("../config.js").GeometryConfig>;
|
|
30
|
+
alphabet?: Partial<import("../config.js").AlphabetConfig>;
|
|
31
|
+
storeConfig?: Partial<import("../config.js").StoreConfig>;
|
|
32
|
+
store?: Store;
|
|
33
|
+
/** Additional grounding mechanisms (appended after the built-in defaults). */
|
|
34
|
+
mechanisms?: import("./pipeline-mechanism.js").PipelineMechanism[];
|
|
35
|
+
/** Factories that receive the {@link ExtensionHost} and return mechanisms. */
|
|
36
|
+
mechanismFactories?: ((host: import("../extension.js").ExtensionHost) => import("./pipeline-mechanism.js").PipelineMechanism)[];
|
|
37
|
+
}
|
|
38
|
+
export declare class Mind implements MindContext {
|
|
39
|
+
readonly space: Space;
|
|
40
|
+
readonly alphabet: Alphabet;
|
|
41
|
+
readonly store: Store;
|
|
42
|
+
readonly cfg: MindConfig;
|
|
43
|
+
/** The lightest-derivation engine over the Sema graph. */
|
|
44
|
+
readonly search: GraphSearch;
|
|
45
|
+
/** The grounding mechanisms iterated by {@link think}. */
|
|
46
|
+
readonly mechanisms: import("./pipeline-mechanism.js").PipelineMechanism[];
|
|
47
|
+
/** The live rationale tracer for the inference currently in flight, or null. */
|
|
48
|
+
trace: Rationale | null;
|
|
49
|
+
/** Per-response memo of the consensus climb. NOTE: this memo and
|
|
50
|
+
* {@link recogniseMemo} are BYPASSED while a rationale trace is attached
|
|
51
|
+
* (every mechanism must emit its own steps), so a traced respond re-pays
|
|
52
|
+
* up to four consensus climbs plus repeat recognitions — that is where the
|
|
53
|
+
* traced-vs-untraced latency multiple comes from, by design. */
|
|
54
|
+
climbMemo: WeakMap<Uint8Array, Map<string, AttentionRead>> | null;
|
|
55
|
+
/** Per-response memo of recognise() — see {@link MindContext.recogniseMemo}. */
|
|
56
|
+
recogniseMemo: WeakMap<Uint8Array, Recognition> | null;
|
|
57
|
+
/** Per-response memo of perceive() — see {@link MindContext.perceiveMemo}. */
|
|
58
|
+
perceiveMemo: Map<string, import("../sema.js").Sema> | null;
|
|
59
|
+
/** The perceived gist of the query currently being answered. Set by `think`
|
|
60
|
+
* before the graph search runs; `chooseNext` consults it as a gate (a null
|
|
61
|
+
* guide means no query is in flight, so structural walkers keep plain
|
|
62
|
+
* first-edge behaviour) and the reverse projection uses it for
|
|
63
|
+
* reverse-recall disambiguation via `chooseAmong`. */
|
|
64
|
+
_edgeGuide: Vec | null;
|
|
65
|
+
/** Per-response memo of {@link chooseNext} picks — ensures every mechanism
|
|
66
|
+
* of a single response follows the SAME continuation for each ambiguous
|
|
67
|
+
* context node. */
|
|
68
|
+
_edgeChoice: Map<number, number>;
|
|
69
|
+
/** Previous deposit's seen node ids for incremental change detection. */
|
|
70
|
+
_prevSeen: Set<number> | null;
|
|
71
|
+
/** Session cache of node-id → perceived gist for candidate scoring — see
|
|
72
|
+
* {@link MindContext._gistCache}. 32 MB ≈ 8K gists at D=1024; hub
|
|
73
|
+
* candidate sets (√N at most) fit comfortably and recur across queries. */
|
|
74
|
+
_gistCache: BoundedMap<number, Vec>;
|
|
75
|
+
_depositTrees: BoundedMap<string, import("../geometry.js").FoldPyramid>;
|
|
76
|
+
_depositLens: Set<number>;
|
|
77
|
+
_internIds: WeakMap<Sema, number>;
|
|
78
|
+
/** Canonical node id of a byte span. Required by GraphSearchHost & MindContext. */
|
|
79
|
+
resolve(bytes: Uint8Array): number | null;
|
|
80
|
+
recogniseSpan(bytes: Uint8Array): {
|
|
81
|
+
sites: ReadonlyArray<Site>;
|
|
82
|
+
leaves: ReadonlyArray<Leaf>;
|
|
83
|
+
splits: ReadonlySet<number>;
|
|
84
|
+
};
|
|
85
|
+
/** Disambiguate among multiple learnt continuations of the same context node.
|
|
86
|
+
* Required by {@link GraphSearchHost} — the graph search calls this through the
|
|
87
|
+
* host interface when a recognised form has more than one outgoing edge.
|
|
88
|
+
* Delegates to the standalone {@link chooseNext} which picks the candidate
|
|
89
|
+
* with the most distributional evidence (highest `prevOf` count — the
|
|
90
|
+
* structural manifestation of its halo). When evidence is equal the
|
|
91
|
+
* first-inserted edge wins. */
|
|
92
|
+
chooseNext(node: number): number | undefined;
|
|
93
|
+
constructor(opts?: MindOptions);
|
|
94
|
+
constructor(cfg: MindConfig, store: Store, _fromStore: true);
|
|
95
|
+
/** Exposed for tests: the consensus climb over query sub-regions. */
|
|
96
|
+
climbAttention(query: Uint8Array, k: number, mode?: import("./types.js").DFMode): Promise<import("./types.js").Attention[]>;
|
|
97
|
+
/** Exposed for tests: climb the structural DAG from a node to its
|
|
98
|
+
* edge-bearing ancestor contexts. */
|
|
99
|
+
edgeAncestors(id: number, contextCount: number): import("./types.js").AncestorReach;
|
|
100
|
+
/** Exposed for tests: find the natural break point in a sorted vote list. */
|
|
101
|
+
naturalBreak(votes: number[]): number;
|
|
102
|
+
/** Perceive input into a content-defined tree. Deterministic — identical
|
|
103
|
+
* bytes always produce an identical tree. Public for ingest-cache. */
|
|
104
|
+
perceive(input: Input, leafAt?: (i: number) => number | null, lookup?: (ids: number[]) => number | null): Sema;
|
|
105
|
+
/** Open one response's transient state — the tracer and the per-response
|
|
106
|
+
* memos. Paired with {@link endResponse}; the ONE place this state is
|
|
107
|
+
* created, so adding a memo cannot forget its reset. */
|
|
108
|
+
private beginResponse;
|
|
109
|
+
/** Close one response's transient state — every per-response field, incl.
|
|
110
|
+
* the edge guide/choices `think` sets mid-flight. */
|
|
111
|
+
private endResponse;
|
|
112
|
+
respond(input: Input, inspectRationale?: InspectRationale): Promise<Response>;
|
|
113
|
+
/** Text view of {@link respond}. NUL bytes (0x00) are stripped before
|
|
114
|
+
* decoding — they are structural padding in text answers. LOSSY for a
|
|
115
|
+
* binary answer that legitimately contains NULs: use {@link respond} and
|
|
116
|
+
* read `bytes` directly for binary/grid modalities. */
|
|
117
|
+
respondText(input: string, inspectRationale?: InspectRationale): Promise<string>;
|
|
118
|
+
embedding(input: Input): Promise<Vec | null>;
|
|
119
|
+
/** Kinship note: the vector arm below is a miniature of recall's tier 3
|
|
120
|
+
* (resonate → reach gate → read out the nearest form's bytes) — the
|
|
121
|
+
* read-out direction of the same operation, without recall's grounding
|
|
122
|
+
* ladder. If either side's acceptance rule changes, revisit the other. */
|
|
123
|
+
express(idOrV: number | Vec): Promise<Uint8Array>;
|
|
124
|
+
ingest(input: Input | (Input | [Input, Input])[], second?: Input): Promise<(Sema & {
|
|
125
|
+
id: number;
|
|
126
|
+
}) | undefined>;
|
|
127
|
+
private extensionHost;
|
|
128
|
+
private groundedContinuation;
|
|
129
|
+
/** Re-index structurally-important nodes whose gists were evicted from the
|
|
130
|
+
* pending cache before they reached the content index. See {@link
|
|
131
|
+
* Store.repairContentIndex} for the contract; this method wires the
|
|
132
|
+
* Mind's perception into the store's repair walk.
|
|
133
|
+
*
|
|
134
|
+
* Run this after training or at checkpoints to restore recall reach for
|
|
135
|
+
* nodes that bridge experiences but were never indexed. A pure interior
|
|
136
|
+
* node (no edges, no halo) is deliberately skipped — it is scaffolding,
|
|
137
|
+
* not an experience root or bridge, and regenerating its gist would waste
|
|
138
|
+
* I/O and index space for no recall benefit.
|
|
139
|
+
*
|
|
140
|
+
* @param minParents only repair nodes with ≥ this many structural parents
|
|
141
|
+
* (default 2 — structural bridges)
|
|
142
|
+
* @returns number of nodes added to the content index */
|
|
143
|
+
repairContentIndex(minParents?: number): Promise<number>;
|
|
144
|
+
save(): Promise<Uint8Array>;
|
|
145
|
+
static load(snapshot: Uint8Array, store: Store): Promise<Mind>;
|
|
146
|
+
static loadFromStore(store: Store): Promise<Mind>;
|
|
147
|
+
}
|