@hviana/sema 0.4.2 → 0.4.3
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 +2252 -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 +221 -0
- package/dist/src/alu/src/parser.js +577 -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/canon.d.ts +26 -0
- package/dist/src/canon.js +57 -0
- package/dist/src/config.d.ts +111 -0
- package/dist/src/config.js +91 -0
- package/dist/src/derive/src/deduction.d.ts +136 -0
- package/dist/src/derive/src/deduction.js +159 -0
- package/dist/src/derive/src/index.d.ts +8 -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 +175 -0
- package/dist/src/geometry.js +823 -0
- package/dist/src/index.d.ts +17 -0
- package/dist/src/index.js +19 -0
- package/dist/src/ingest-cache.d.ts +41 -0
- package/dist/src/ingest-cache.js +165 -0
- package/dist/src/meter.d.ts +176 -0
- package/dist/src/meter.js +274 -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 +414 -0
- package/dist/src/mind/attention.js +2082 -0
- package/dist/src/mind/bridge.d.ts +39 -0
- package/dist/src/mind/bridge.js +947 -0
- package/dist/src/mind/canonical.d.ts +34 -0
- package/dist/src/mind/canonical.js +93 -0
- package/dist/src/mind/graph-search.d.ts +294 -0
- package/dist/src/mind/graph-search.js +996 -0
- package/dist/src/mind/index.d.ts +9 -0
- package/dist/src/mind/index.js +5 -0
- package/dist/src/mind/junction.d.ts +137 -0
- package/dist/src/mind/junction.js +342 -0
- package/dist/src/mind/learning.d.ts +75 -0
- package/dist/src/mind/learning.js +270 -0
- package/dist/src/mind/match.d.ts +181 -0
- package/dist/src/mind/match.js +655 -0
- package/dist/src/mind/mechanisms/alu.d.ts +4 -0
- package/dist/src/mind/mechanisms/alu.js +36 -0
- package/dist/src/mind/mechanisms/cast.d.ts +89 -0
- package/dist/src/mind/mechanisms/cast.js +784 -0
- package/dist/src/mind/mechanisms/confluence.d.ts +24 -0
- package/dist/src/mind/mechanisms/confluence.js +255 -0
- package/dist/src/mind/mechanisms/cover.d.ts +6 -0
- package/dist/src/mind/mechanisms/cover.js +227 -0
- package/dist/src/mind/mechanisms/extraction.d.ts +33 -0
- package/dist/src/mind/mechanisms/extraction.js +300 -0
- package/dist/src/mind/mechanisms/recall.d.ts +16 -0
- package/dist/src/mind/mechanisms/recall.js +364 -0
- package/dist/src/mind/mind.d.ts +337 -0
- package/dist/src/mind/mind.js +617 -0
- package/dist/src/mind/pipeline-mechanism.d.ts +172 -0
- package/dist/src/mind/pipeline-mechanism.js +465 -0
- package/dist/src/mind/pipeline.d.ts +49 -0
- package/dist/src/mind/pipeline.js +275 -0
- package/dist/src/mind/primitives.d.ts +66 -0
- package/dist/src/mind/primitives.js +306 -0
- package/dist/src/mind/rationale.d.ts +139 -0
- package/dist/src/mind/rationale.js +163 -0
- package/dist/src/mind/reasoning.d.ts +40 -0
- package/dist/src/mind/reasoning.js +280 -0
- package/dist/src/mind/recognition.d.ts +20 -0
- package/dist/src/mind/recognition.js +504 -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 +126 -0
- package/dist/src/mind/traverse.js +650 -0
- package/dist/src/mind/types.d.ts +333 -0
- package/dist/src/mind/types.js +130 -0
- package/dist/src/rabitq-ivf/src/database.d.ts +113 -0
- package/dist/src/rabitq-ivf/src/database.js +201 -0
- package/dist/src/rabitq-ivf/src/index.d.ts +7 -0
- package/dist/src/rabitq-ivf/src/index.js +4 -0
- package/dist/src/rabitq-ivf/src/ivf.d.ts +200 -0
- package/dist/src/rabitq-ivf/src/ivf.js +1165 -0
- package/dist/src/rabitq-ivf/src/prng.d.ts +19 -0
- package/dist/src/rabitq-ivf/src/prng.js +36 -0
- package/dist/src/rabitq-ivf/src/rabitq.d.ts +95 -0
- package/dist/src/rabitq-ivf/src/rabitq.js +283 -0
- package/dist/src/sema.d.ts +31 -0
- package/dist/src/sema.js +63 -0
- package/dist/src/store-sqlite.d.ts +184 -0
- package/dist/src/store-sqlite.js +942 -0
- package/dist/src/store.d.ts +678 -0
- package/dist/src/store.js +1703 -0
- package/dist/src/vec.d.ts +31 -0
- package/dist/src/vec.js +109 -0
- package/package.json +1 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { MindContext } from "./types.js";
|
|
2
|
+
import { type PipelineMechanism } from "./pipeline-mechanism.js";
|
|
3
|
+
export { resolveConcepts, resolveConnectors } from "./mechanisms/cover.js";
|
|
4
|
+
export { aluToMechanism } from "./mechanisms/alu.js";
|
|
5
|
+
export declare const defaultMechanisms: PipelineMechanism[];
|
|
6
|
+
export type Provenance = "cast" | "join" | "cover" | "extract" | "recall" | "recall-echo";
|
|
7
|
+
export interface Thought {
|
|
8
|
+
bytes: Uint8Array;
|
|
9
|
+
provenance: Provenance;
|
|
10
|
+
}
|
|
11
|
+
/** Structured payload of the "decideGrounding" rationale step — the same
|
|
12
|
+
* numbers the human-readable candidate labels already carry, exposed as
|
|
13
|
+
* data so a downstream tool need not parse free text. Purely additive
|
|
14
|
+
* instrumentation: built only under `ctx.trace?.` (optional chaining
|
|
15
|
+
* short-circuits its arguments), never read by inference. */
|
|
16
|
+
export interface DecideGroundingData {
|
|
17
|
+
version: 1;
|
|
18
|
+
/** Every grounding candidate weighed, in consideration order. */
|
|
19
|
+
candidates: Array<{
|
|
20
|
+
provenance: string;
|
|
21
|
+
/** The candidate's exact weight in the one cost ladder. */
|
|
22
|
+
weight: number;
|
|
23
|
+
/** The DISCRETE grade the decision actually compares (floor(weight/STEP)). */
|
|
24
|
+
grade: number;
|
|
25
|
+
/** Query bytes the candidate's accounted spans leave unexplained. */
|
|
26
|
+
unexplainedBytes: number;
|
|
27
|
+
/** Whether this candidate won the decision. */
|
|
28
|
+
decided: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
/** Grade margin between the winner and the runner-up, when both exist —
|
|
31
|
+
* the same quantity the "narrowDecision" step reports as narrow when
|
|
32
|
+
* ≤ 1. Absent for a single-candidate decision. */
|
|
33
|
+
runnerUpMargin?: number;
|
|
34
|
+
}
|
|
35
|
+
/** Structured payload of the "narrowDecision" rationale step. */
|
|
36
|
+
export interface NarrowDecisionData {
|
|
37
|
+
version: 1;
|
|
38
|
+
margin: number;
|
|
39
|
+
}
|
|
40
|
+
/** Think: a single lightest-derivation exploration of the Sema graph.
|
|
41
|
+
*
|
|
42
|
+
* Every answer travels the same path:
|
|
43
|
+
* 1. Pre-computation — recognise, extension parse, guide; everything
|
|
44
|
+
* expensive stays lazy on Precomputed until a mechanism asks.
|
|
45
|
+
* 2. Grounding — every mechanism yields candidates weighed in the one
|
|
46
|
+
* cost ladder; the lightest grounding derivation wins.
|
|
47
|
+
* 3. Post-grounding — diagnostics (narrowDecision, thinGrounding),
|
|
48
|
+
* reasoning (multi-hop), fusion (multi-topic). */
|
|
49
|
+
export declare function think(ctx: MindContext, query: Uint8Array, mechs?: readonly PipelineMechanism[]): Promise<Thought | null>;
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
// pipeline.ts — the think pipeline (Section 5 of the mind).
|
|
2
|
+
//
|
|
3
|
+
// think() is the whole file's job: one lightest-derivation choice among
|
|
4
|
+
// UNIFORM mechanisms. The pipeline sees mechanisms through the
|
|
5
|
+
// PipelineMechanism interface only — it never imports a mechanism-specific
|
|
6
|
+
// type and never has a special-case branch for any mechanism. Adding a
|
|
7
|
+
// mechanism means registering one object; removing one means dropping it
|
|
8
|
+
// from the list. The mechanisms themselves live in mechanisms/ (one file
|
|
9
|
+
// each); the shared pre-computation they exchange lives in Precomputed
|
|
10
|
+
// (pipeline-mechanism.ts).
|
|
11
|
+
import { PASS, STEP } from "./graph-search.js";
|
|
12
|
+
import { gistOf, resolve } from "./primitives.js";
|
|
13
|
+
import { recognise } from "./recognition.js";
|
|
14
|
+
import { fuseAttention, reason } from "./reasoning.js";
|
|
15
|
+
import { unexplainedSpans } from "./rationale.js";
|
|
16
|
+
import { rItem } from "./trace.js";
|
|
17
|
+
import { Precomputed } from "./pipeline-mechanism.js";
|
|
18
|
+
import { coverMechanism } from "./mechanisms/cover.js";
|
|
19
|
+
import { castMechanism } from "./mechanisms/cast.js";
|
|
20
|
+
import { confluenceMechanism } from "./mechanisms/confluence.js";
|
|
21
|
+
import { extractionMechanism } from "./mechanisms/extraction.js";
|
|
22
|
+
import { recallMechanism } from "./mechanisms/recall.js";
|
|
23
|
+
// Re-exports: cover's pre-resolution helpers and the ALU adapter kept
|
|
24
|
+
// importable from the pipeline module (their historical home).
|
|
25
|
+
export { resolveConcepts, resolveConnectors } from "./mechanisms/cover.js";
|
|
26
|
+
export { aluToMechanism } from "./mechanisms/alu.js";
|
|
27
|
+
// ── Extension dispatch (pre-loop parse) ─────────────────────────────────────
|
|
28
|
+
async function collectComputed(ctx, mechanisms, query) {
|
|
29
|
+
const out = [];
|
|
30
|
+
const meter = ctx.meter;
|
|
31
|
+
for (const m of mechanisms) {
|
|
32
|
+
if (!m.parse)
|
|
33
|
+
continue;
|
|
34
|
+
const spans = meter
|
|
35
|
+
? await meter.time(`${m.name}.parse`, () => m.parse(query))
|
|
36
|
+
: await m.parse(query);
|
|
37
|
+
out.push(...spans);
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
// ── Built-in mechanisms ─────────────────────────────────────────────────────
|
|
42
|
+
// ORDER MATTERS, but only through the uniform floor/worthRunning pruning —
|
|
43
|
+
// no mechanism is special-cased. Cover runs FIRST: when a computed
|
|
44
|
+
// extension result (e.g. ALU) exists, cover masks it in at near-zero cost
|
|
45
|
+
// (see mechanisms/cover.ts), which becomes `best` before any other mechanism
|
|
46
|
+
// invests in its own precomputation. CAST's and confluence's floors (2*STEP,
|
|
47
|
+
// 3*STEP) then fail `worthRunning` and are skipped by the SAME admissible-
|
|
48
|
+
// floor pruning every mechanism is already subject to — not by asking
|
|
49
|
+
// "is this an extension?". Grade TIES keep the earlier candidate, so this
|
|
50
|
+
// order is also the tie-break priority: cover, cast, confluence, extraction,
|
|
51
|
+
// recall.
|
|
52
|
+
export const defaultMechanisms = [
|
|
53
|
+
coverMechanism,
|
|
54
|
+
castMechanism,
|
|
55
|
+
confluenceMechanism,
|
|
56
|
+
extractionMechanism,
|
|
57
|
+
recallMechanism,
|
|
58
|
+
];
|
|
59
|
+
/** Think: a single lightest-derivation exploration of the Sema graph.
|
|
60
|
+
*
|
|
61
|
+
* Every answer travels the same path:
|
|
62
|
+
* 1. Pre-computation — recognise, extension parse, guide; everything
|
|
63
|
+
* expensive stays lazy on Precomputed until a mechanism asks.
|
|
64
|
+
* 2. Grounding — every mechanism yields candidates weighed in the one
|
|
65
|
+
* cost ladder; the lightest grounding derivation wins.
|
|
66
|
+
* 3. Post-grounding — diagnostics (narrowDecision, thinGrounding),
|
|
67
|
+
* reasoning (multi-hop), fusion (multi-topic). */
|
|
68
|
+
export async function think(ctx, query, mechs) {
|
|
69
|
+
if (query.length === 0)
|
|
70
|
+
return null;
|
|
71
|
+
ctx._edgeGuide = gistOf(ctx, query);
|
|
72
|
+
ctx._edgeChoice.clear();
|
|
73
|
+
const t = ctx.trace?.enter("think", [rItem(query, "query")]);
|
|
74
|
+
const done = (answer, note) => {
|
|
75
|
+
t?.done(answer
|
|
76
|
+
? [rItem(answer, "answer", resolve(ctx, answer) ?? undefined)]
|
|
77
|
+
: [], note);
|
|
78
|
+
return answer;
|
|
79
|
+
};
|
|
80
|
+
// ── Pre-computation ──────────────────────────────────────────────────
|
|
81
|
+
const mechanisms = mechs ?? defaultMechanisms;
|
|
82
|
+
const rec = recognise(ctx, query);
|
|
83
|
+
// Phase 1: collect computed spans from mechanisms that implement parse()
|
|
84
|
+
const computed = await collectComputed(ctx, mechanisms, query);
|
|
85
|
+
if (computed.length > 0) {
|
|
86
|
+
ctx.trace?.step("computeExtensions", [rItem(query, "query")], computed.map((u) => rItem(query.subarray(u.i, u.j), "operand", undefined, [u.i, u.j])), `extensions recognised and evaluated ${computed.length} computation(s)`);
|
|
87
|
+
for (const u of computed) {
|
|
88
|
+
ctx.trace?.step("evalComputation", [rItem(query.subarray(u.i, u.j), "expression", undefined, [u.i, u.j])], [rItem(u.bytes, "result", resolve(ctx, u.bytes) ?? undefined)], "evaluate the recognised operation to its authoritative result");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Phase 2: the shared pre-computation container. Eager fields only
|
|
92
|
+
// (recognition, computed spans, guide) — every expensive analysis
|
|
93
|
+
// (consensus climb, weave, span-shape classification) is a lazily-cached
|
|
94
|
+
// method on Precomputed, first-touched by whichever mechanism's floor
|
|
95
|
+
// survives its cheap gates and the worthRunning check. A query no
|
|
96
|
+
// mechanism climbs for (e.g. one an extension decided) never climbs.
|
|
97
|
+
const pre = new Precomputed(ctx, query, rec, computed, ctx._edgeGuide);
|
|
98
|
+
const grade = (w) => Math.floor(w / STEP);
|
|
99
|
+
const unaccounted = (spans) => unexplainedSpans(query.length, spans)
|
|
100
|
+
.reduce((sum, [s, e]) => sum + (e - s), 0);
|
|
101
|
+
const weigh = (accounted, moves) => moves + PASS * unaccounted(accounted);
|
|
102
|
+
const candidates = [];
|
|
103
|
+
let best = null;
|
|
104
|
+
const consider = (c) => {
|
|
105
|
+
if (c.bytes.length === 0)
|
|
106
|
+
return;
|
|
107
|
+
if (ctx.meter)
|
|
108
|
+
ctx.meter.candidates++;
|
|
109
|
+
candidates.push(c);
|
|
110
|
+
if (best === null || grade(c.weight) < grade(best.weight))
|
|
111
|
+
best = c;
|
|
112
|
+
};
|
|
113
|
+
const worthRunning = (floor) => best === null || grade(floor) < grade(best.weight);
|
|
114
|
+
// Phase 3: grounding loop
|
|
115
|
+
// Per-mechanism accounting (src/meter.ts). The market's whole premise is
|
|
116
|
+
// that mechanisms compete on one cost scale — so the profiling read-out is
|
|
117
|
+
// also per-mechanism, uniformly: the loop never asks which one it holds.
|
|
118
|
+
const meter = ctx.meter;
|
|
119
|
+
for (const mech of mechanisms) {
|
|
120
|
+
const floor = meter
|
|
121
|
+
? await meter.time(`${mech.name}.floor`, () => mech.floor(ctx, query, pre, worthRunning))
|
|
122
|
+
: await mech.floor(ctx, query, pre, worthRunning);
|
|
123
|
+
if (meter) {
|
|
124
|
+
if (floor === null)
|
|
125
|
+
meter.mechanismSkips++;
|
|
126
|
+
else
|
|
127
|
+
meter.mechanismFloors++;
|
|
128
|
+
}
|
|
129
|
+
if (floor === null) {
|
|
130
|
+
ctx.trace?.step("skipMechanism", [], [], `${mech.name} skipped — structural precondition failed`);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (!worthRunning(floor)) {
|
|
134
|
+
ctx.trace?.step("skipMechanism", [], [], `${mech.name} skipped — floor ${floor} cannot beat incumbent (grade ${grade(best.weight)})`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (meter)
|
|
138
|
+
meter.mechanismRuns++;
|
|
139
|
+
const results = meter
|
|
140
|
+
? await meter.time(`${mech.name}.run`, () => mech.run(ctx, query, pre))
|
|
141
|
+
: await mech.run(ctx, query, pre);
|
|
142
|
+
for (const r of results) {
|
|
143
|
+
const weight = r.weight ?? weigh(r.accounted, r.moves);
|
|
144
|
+
consider({
|
|
145
|
+
bytes: r.bytes,
|
|
146
|
+
provenance: r.provenance ?? mech.provenance,
|
|
147
|
+
weight,
|
|
148
|
+
used: r.used,
|
|
149
|
+
accounted: r.accounted,
|
|
150
|
+
unexplained: r.unexplained,
|
|
151
|
+
complete: r.complete,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// (TS cannot see the closure assignments into `best` and narrows it to its
|
|
156
|
+
// initial null, so the read-back needs the assertion.)
|
|
157
|
+
const decided = best;
|
|
158
|
+
if (candidates.length > 1) {
|
|
159
|
+
// The runner-up is computed BEFORE the decideGrounding step so its grade
|
|
160
|
+
// margin can ride along in the step's structured data payload; the
|
|
161
|
+
// computation itself is pure and was always unconditional — only its
|
|
162
|
+
// position moved.
|
|
163
|
+
let runnerUp = null;
|
|
164
|
+
if (decided !== null) {
|
|
165
|
+
for (const c of candidates) {
|
|
166
|
+
if (c === decided)
|
|
167
|
+
continue;
|
|
168
|
+
if (runnerUp === null || grade(c.weight) < grade(runnerUp.weight)) {
|
|
169
|
+
runnerUp = c;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const margin = decided !== null && runnerUp !== null
|
|
174
|
+
? grade(runnerUp.weight) - grade(decided.weight)
|
|
175
|
+
: null;
|
|
176
|
+
ctx.trace?.step("decideGrounding", candidates.map((c) => rItem(c.bytes, `${c.provenance} (weight ${c.weight.toFixed(3)}${c.unexplained ? `, unexplained: "${c.unexplained}"` : ""})`)), decided ? [rItem(decided.bytes, decided.provenance)] : [], "the lightest grounding derivation wins — every mechanism weighed in the one cost ladder", undefined, {
|
|
177
|
+
version: 1,
|
|
178
|
+
candidates: candidates.map((c) => ({
|
|
179
|
+
provenance: c.provenance,
|
|
180
|
+
weight: c.weight,
|
|
181
|
+
grade: grade(c.weight),
|
|
182
|
+
unexplainedBytes: unaccounted(c.accounted),
|
|
183
|
+
decided: c === decided,
|
|
184
|
+
})),
|
|
185
|
+
...(margin !== null ? { runnerUpMargin: margin } : {}),
|
|
186
|
+
});
|
|
187
|
+
if (decided !== null && runnerUp !== null && margin !== null) {
|
|
188
|
+
if (margin <= 1) {
|
|
189
|
+
ctx.trace?.step("narrowDecision", [
|
|
190
|
+
rItem(decided.bytes, `${decided.provenance} (weight ${decided.weight.toFixed(3)})`),
|
|
191
|
+
], [
|
|
192
|
+
rItem(runnerUp.bytes, `${runnerUp.provenance} (weight ${runnerUp.weight.toFixed(3)})`),
|
|
193
|
+
], `margin ${margin} grade-unit(s) — the decision could change with one more training fact`, undefined, { version: 1, margin });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (decided === null) {
|
|
198
|
+
done(null, "no mechanism grounded an answer");
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
// Honesty density
|
|
202
|
+
{
|
|
203
|
+
const covered = query.length - unaccounted(decided.accounted);
|
|
204
|
+
const density = query.length > 0 ? covered / query.length : 1;
|
|
205
|
+
const thinBar = 1 / ctx.space.maxGroup;
|
|
206
|
+
if (density < thinBar) {
|
|
207
|
+
ctx.trace?.step("thinGrounding", [rItem(decided.bytes, decided.provenance)], [], `grounded but thin — density ${density.toFixed(3)} is below 1/W (${thinBar.toFixed(3)})`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const answer = decided.bytes;
|
|
211
|
+
const provenance = decided.provenance;
|
|
212
|
+
const castUsed = decided.used ?? new Set();
|
|
213
|
+
// ── Post-grounding, gated by provenance ──────────────────────────────
|
|
214
|
+
const preConsumed = provenance === "cast" || provenance === "join"
|
|
215
|
+
? castUsed
|
|
216
|
+
: provenance === "recall" || provenance === "recall-echo"
|
|
217
|
+
? new Set()
|
|
218
|
+
: new Set(recognise(ctx, answer).sites.map((s) => s.payload));
|
|
219
|
+
// A grounding that DECLARED itself complete is not extended: the answer is
|
|
220
|
+
// already a trained form's own continuation, reached through an identity
|
|
221
|
+
// claim about the query, so a multi-hop pivot could only chain past the
|
|
222
|
+
// fact that produced it (see MechanismResult.complete).
|
|
223
|
+
const reasoned = decided.complete ? answer : meter
|
|
224
|
+
? await meter.time("reason", () => reason(ctx, query, answer, preConsumed, pre))
|
|
225
|
+
: await reason(ctx, query, answer, preConsumed, pre);
|
|
226
|
+
// Fuse only when the query has a genuine REMAINDER no mechanism's
|
|
227
|
+
// structural evidence touched at all. `decided.accounted` alone
|
|
228
|
+
// undercounts this: it is a COST-LADDER quantity (cover.ts prices its
|
|
229
|
+
// masked/computed spans at near-zero and deliberately leaves them out of
|
|
230
|
+
// `accounted` so PASS-bridged bytes are still charged), not a coverage
|
|
231
|
+
// one — a query fully explained by one computed span plus bridged
|
|
232
|
+
// connectors can report `accounted: []` while nothing is actually left
|
|
233
|
+
// unexplained. The genuine remainder is what NEITHER the winning
|
|
234
|
+
// candidate's accounted spans NOR any recognised extension's computed
|
|
235
|
+
// span (`pre.computed` — every mechanism's parse() output, ALU included)
|
|
236
|
+
// ever touched. A remainder under one river-fold quantum (W, the same
|
|
237
|
+
// floor cover.ts's restatedSpan and the honesty-density bar above both
|
|
238
|
+
// use) is bridging punctuation/whitespace, never a second topic —
|
|
239
|
+
// observed: a single space between two fully-computed arithmetic spans
|
|
240
|
+
// ("2+2 3+3") registered as "unaccounted" and pulled in an unrelated
|
|
241
|
+
// corpus fact, corrupting "4 6" into "4 63".
|
|
242
|
+
const explained = [
|
|
243
|
+
...decided.accounted,
|
|
244
|
+
...pre.computed.map((u) => [u.i, u.j]),
|
|
245
|
+
];
|
|
246
|
+
const remainder = unaccounted(explained);
|
|
247
|
+
// Whether the winning candidate's entire recognised substance is
|
|
248
|
+
// COMPUTED — every accounted span exactly a pre.computed span, nothing
|
|
249
|
+
// from a genuinely recognised/climbed site. fuseAttention's lone-root
|
|
250
|
+
// shortcut assumes a single point of attention already IS primary's own
|
|
251
|
+
// source; that assumption is exactly backwards for a pure computation
|
|
252
|
+
// (an ALU result has no anchor of its own) — see fuseAttention's
|
|
253
|
+
// `unclimbed` parameter, gated there by Attention.breadth so a
|
|
254
|
+
// coincidental echo (which this flag alone cannot distinguish) is still
|
|
255
|
+
// rejected.
|
|
256
|
+
const unclimbed = decided.accounted.length > 0 &&
|
|
257
|
+
decided.accounted.every(([i, j]) => pre.computed.some((u) => u.i === i && u.j === j));
|
|
258
|
+
// Where the winning grounding stands in the query — fusion places primary
|
|
259
|
+
// by it (see fuseAttention's `primarySpans`). `accounted` is the
|
|
260
|
+
// cost-ladder read and is authoritative when non-empty; when it is empty
|
|
261
|
+
// the grounding is a pure COMPUTATION, whose evidence is its computed span.
|
|
262
|
+
// Exactly the cost-ladder-vs-coverage distinction `explained` above draws,
|
|
263
|
+
// read here for POSITION instead of for coverage — and resolved here, where
|
|
264
|
+
// both readings are in hand, rather than inside fuseAttention.
|
|
265
|
+
const primarySpans = decided.accounted.length > 0
|
|
266
|
+
? decided.accounted
|
|
267
|
+
: pre.computed.map((u) => [u.i, u.j]);
|
|
268
|
+
const fused = remainder < ctx.space.maxGroup
|
|
269
|
+
? reasoned
|
|
270
|
+
: meter
|
|
271
|
+
? await meter.time("fuse", () => fuseAttention(ctx, query, reasoned, pre, unclimbed, primarySpans))
|
|
272
|
+
: await fuseAttention(ctx, query, reasoned, pre, unclimbed, decided.accounted);
|
|
273
|
+
done(fused, "grounded, reasoned forward, fused across points of attention");
|
|
274
|
+
return { bytes: fused, provenance };
|
|
275
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Vec } from "../vec.js";
|
|
2
|
+
import { Sema } from "../sema.js";
|
|
3
|
+
import type { Input, MindContext } from "./types.js";
|
|
4
|
+
/** The content key of a byte span — one latin1 char per byte, an exact,
|
|
5
|
+
* collision-free encoding. Spans on the perception path are query-scale
|
|
6
|
+
* (windows, regions, candidate spans), so key construction is far cheaper
|
|
7
|
+
* than the river fold it deduplicates. */
|
|
8
|
+
export declare function latin1Key(bytes: Uint8Array): string;
|
|
9
|
+
/** Perceive input into a content-defined tree (the river fold).
|
|
10
|
+
* Deterministic — identical bytes always produce an identical tree.
|
|
11
|
+
*
|
|
12
|
+
* `boundaries` is an optional sorted list of proper byte offsets where the
|
|
13
|
+
* fold must split so that each prefix segment folds identically to how it
|
|
14
|
+
* folded when it was learned (§10.3 stable-prefix contract). Only the
|
|
15
|
+
* CALLER — who assembled the multi-turn context — knows where those
|
|
16
|
+
* boundaries are; the geometry never guesses them from the bytes. */
|
|
17
|
+
export declare function perceive(ctx: MindContext, input: Input, leafAt?: (i: number) => number | null, lookup?: (ids: number[]) => number | null, boundaries?: readonly number[]): Sema;
|
|
18
|
+
/** The DEPOSIT-shaped perceive. Folds over the stream's own content cuts —
|
|
19
|
+
* bit-identical to what inference computes for the same bytes, and that
|
|
20
|
+
* train/inference agreement is load-bearing for exact recall. An input that
|
|
21
|
+
* EXTENDS a previously deposited one is a conversation context grown by one
|
|
22
|
+
* turn; the cached prefix length IS the turn boundary (derived from the deposit
|
|
23
|
+
* sequence itself, never from a content convention) and joins the cut set, so
|
|
24
|
+
* the trained context node and the query's context subtree are the SAME node.
|
|
25
|
+
* Segment folds reuse across deposits ({@link stablePrefixFoldIncremental}) —
|
|
26
|
+
* O(turn) instead of O(context) per turn. All of it is purely a cache: an
|
|
27
|
+
* evicted chain loses only the turn boundaries, and since the content cuts do
|
|
28
|
+
* not depend on the cache, the segments themselves are unchanged. */
|
|
29
|
+
export declare function perceiveDeposit(ctx: MindContext, bytes: Uint8Array, conversational?: boolean): Sema;
|
|
30
|
+
/** The raw bytes of an input — modality-neutral conversion. */
|
|
31
|
+
export declare function inputBytes(ctx: MindContext, input: Input): Uint8Array;
|
|
32
|
+
/** Convenience: the gist vector of a byte span. */
|
|
33
|
+
export declare function gistOf(ctx: MindContext, bytes: Uint8Array): Vec;
|
|
34
|
+
/** Fold a perceived tree bottom-up against the store's content-addressed maps:
|
|
35
|
+
* every leaf is named by findLeaf, every branch by findBranch over its kids'
|
|
36
|
+
* ids (null the moment any child is unknown). `visit`, when given, sees each
|
|
37
|
+
* node with its byte span and resolved id. Returns the node's byte end and
|
|
38
|
+
* resolved id. */
|
|
39
|
+
export declare function foldTree(ctx: MindContext, n: Sema, start: number, visit?: (n: Sema, start: number, end: number, node: number | null) => void): {
|
|
40
|
+
end: number;
|
|
41
|
+
node: number | null;
|
|
42
|
+
};
|
|
43
|
+
/** The canonical node id of a byte span: perceive it in isolation — the way
|
|
44
|
+
* training did — and recover its root bottom-up. Returns null if any part is
|
|
45
|
+
* unknown. */
|
|
46
|
+
export declare function resolve(ctx: MindContext, bytes: Uint8Array): number | null;
|
|
47
|
+
/** Equivalence-class resolution: when the exact content-addressed lookup
|
|
48
|
+
* misses, find a stored node whose CANONICAL key equals the span's — the
|
|
49
|
+
* store's canon index proposes candidates by key hash, and each is verified
|
|
50
|
+
* by re-canonicalizing its bytes (hash-then-verify, like every content
|
|
51
|
+
* lookup). Among verified candidates, one that leads somewhere (has a
|
|
52
|
+
* continuation edge) is preferred; ties break to the lowest id — a corpus
|
|
53
|
+
* property, not a seed property. Null when the response carries no
|
|
54
|
+
* canonicalizer, the store has no canon index, or nothing verifies. */
|
|
55
|
+
export declare function canonResolve(ctx: MindContext, bytes: Uint8Array): number | null;
|
|
56
|
+
/** Walk a perceived tree in POST-ORDER with byte offsets — children before
|
|
57
|
+
* their parent, `visit(node, start, end)` for every node including leaves.
|
|
58
|
+
* Returns the byte end. The one shared traversal the offset-carrying tree
|
|
59
|
+
* readers (recognition via foldTree's richer variant, attention's region
|
|
60
|
+
* collection, resonance's branch counting) build on, so each does not
|
|
61
|
+
* re-derive the offset bookkeeping. (recognition.segment keeps its own
|
|
62
|
+
* walk: its flush semantics need PRE-order decisions at leaf-parents, which
|
|
63
|
+
* a post-order visitor cannot express.) */
|
|
64
|
+
export declare function walkTree(n: Sema, start: number, visit: (node: Sema, start: number, end: number) => void): number;
|
|
65
|
+
/** Reconstruct a node's byte content from the DAG, up to `maxLen` bytes. */
|
|
66
|
+
export declare function read(ctx: MindContext, id: number, maxLen?: number): Uint8Array;
|