@hviana/sema 0.2.3 → 0.2.4
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/src/mind/attention.d.ts +14 -2
- package/dist/src/mind/attention.js +54 -8
- package/dist/src/mind/bridge.d.ts +30 -0
- package/dist/src/mind/bridge.js +569 -0
- package/dist/src/mind/match.d.ts +15 -2
- package/dist/src/mind/match.js +3 -8
- package/dist/src/mind/mechanisms/cast.d.ts +54 -0
- package/dist/src/mind/mechanisms/cast.js +268 -37
- package/dist/src/mind/mechanisms/cover.js +16 -31
- package/dist/src/mind/mechanisms/recall.js +66 -0
- package/dist/src/mind/reasoning.d.ts +11 -0
- package/dist/src/mind/reasoning.js +58 -2
- package/dist/src/mind/recognition.js +127 -7
- package/dist/src/mind/traverse.js +16 -15
- package/dist/src/mind/types.d.ts +39 -2
- package/dist/src/mind/types.js +38 -7
- package/dist/src/store.d.ts +12 -3
- package/dist/src/store.js +9 -3
- package/package.json +1 -1
- package/src/mind/attention.ts +65 -7
- package/src/mind/bridge.ts +596 -0
- package/src/mind/match.ts +19 -5
- package/src/mind/mechanisms/cast.ts +290 -38
- package/src/mind/mechanisms/cover.ts +23 -36
- package/src/mind/mechanisms/recall.ts +79 -0
- package/src/mind/reasoning.ts +71 -2
- package/src/mind/recognition.ts +132 -7
- package/src/mind/traverse.ts +16 -17
- package/src/mind/types.ts +70 -6
- package/src/store.ts +19 -5
- package/test/36-already-answered-fusion.test.mjs +128 -0
- package/test/37-cluster-dispersion-fusion.test.mjs +190 -0
- package/test/38-reason-restate-guard.test.mjs +94 -0
- package/test/39-cast-restate-guard.test.mjs +102 -0
- package/test/40-choosenext-scale-guard.test.mjs +75 -0
- package/test/41-seatofnode-direction.test.mjs +85 -0
- package/test/42-recognise-trace-idempotence.test.mjs +106 -0
- package/test/43-cast-analog-seat.test.mjs +244 -0
- package/test/44-recognise-edge-whitespace.test.mjs +63 -0
- package/test/45-liftanswer-restated-trim.test.mjs +60 -0
- package/test/46-recognise-multibyte-edge.test.mjs +85 -0
- package/test/47-cast-comparison-coverage.test.mjs +134 -0
- package/test/48-recognise-turn-connective.test.mjs +125 -0
- package/test/49-natural-units-synonym-bridge.test.mjs +175 -0
- package/test/50-cast-analog-consensus-floor.test.mjs +179 -0
package/src/mind/attention.ts
CHANGED
|
@@ -57,8 +57,17 @@ export async function climbAttention(
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/** Full read-out of one consensus climb: both the roots (dominant points of
|
|
60
|
-
* attention) and the entire ranked list. Cached via ctx.climbMemo
|
|
61
|
-
*
|
|
60
|
+
* attention) and the entire ranked list. Cached via ctx.climbMemo, ALWAYS —
|
|
61
|
+
* see {@link recognise} for why this memo (and recognise()'s own) must
|
|
62
|
+
* never be skipped while tracing: computeAttention's collectRegions walks
|
|
63
|
+
* the query's perceived tree via the same foldTree whose subtree-resolution
|
|
64
|
+
* fast path makes a second call on identical bytes non-idempotent once
|
|
65
|
+
* ctx._resolvedSubtrees is warm (which a multi-turn conversation's shared
|
|
66
|
+
* prefix subtrees guarantee by the second turn). A cache hit still emits
|
|
67
|
+
* a trace step — abbreviated, since the full per-sub-region voting detail
|
|
68
|
+
* {@link traceAttention} builds isn't preserved by the cached read-out —
|
|
69
|
+
* so a traced response is never silently blacked out for a repeated
|
|
70
|
+
* query. */
|
|
62
71
|
export async function climbAttentionAll(
|
|
63
72
|
ctx: MindContext,
|
|
64
73
|
query: Uint8Array,
|
|
@@ -66,8 +75,8 @@ export async function climbAttentionAll(
|
|
|
66
75
|
mode: DFMode = "inverse",
|
|
67
76
|
): Promise<AttentionRead> {
|
|
68
77
|
// Content-keyed memo — works for both single-turn respond() and multi-turn
|
|
69
|
-
// respondTurn().
|
|
70
|
-
if (ctx.climbMemo
|
|
78
|
+
// respondTurn().
|
|
79
|
+
if (ctx.climbMemo) {
|
|
71
80
|
const contentKey = latin1Key(query);
|
|
72
81
|
const modeKey = `${k}:${mode}`;
|
|
73
82
|
let byRead = ctx.climbMemo.get(contentKey);
|
|
@@ -75,7 +84,16 @@ export async function climbAttentionAll(
|
|
|
75
84
|
ctx.climbMemo.set(contentKey, byRead = new Map());
|
|
76
85
|
}
|
|
77
86
|
const hit = byRead.get(modeKey);
|
|
78
|
-
if (hit !== undefined)
|
|
87
|
+
if (hit !== undefined) {
|
|
88
|
+
ctx.trace?.step(
|
|
89
|
+
"climbConsensus",
|
|
90
|
+
[rItem(query, "query")],
|
|
91
|
+
hit.roots.map((r) => rNode(ctx, r.anchor, "anchor", r.vote)),
|
|
92
|
+
`(cached) consensus already computed for this query — ` +
|
|
93
|
+
`${hit.roots.length} point(s) of attention`,
|
|
94
|
+
);
|
|
95
|
+
return hit;
|
|
96
|
+
}
|
|
79
97
|
const read = await computeAttention(ctx, query, k, mode);
|
|
80
98
|
byRead.set(modeKey, read);
|
|
81
99
|
return read;
|
|
@@ -420,6 +438,8 @@ export function poolVotes(
|
|
|
420
438
|
/** Per-anchor SCALE-INVARIANT support: Σ RegionVote.absorbed over the
|
|
421
439
|
* distinct contributing regions — see Attention.breadth. */
|
|
422
440
|
regionSupport: Map<number, number>;
|
|
441
|
+
/** Per-anchor contributing region spans — see Attention.clusters. */
|
|
442
|
+
regionSpans: Map<number, Array<[number, number]>>;
|
|
423
443
|
steps: DerivationStep[];
|
|
424
444
|
} {
|
|
425
445
|
const eligible: number[] = [];
|
|
@@ -500,6 +520,7 @@ export function poolVotes(
|
|
|
500
520
|
{ start: number; end: number; w: number }
|
|
501
521
|
>();
|
|
502
522
|
const regionSupport = new Map<number, number>();
|
|
523
|
+
const regionSpans = new Map<number, Array<[number, number]>>();
|
|
503
524
|
const steps: DerivationStep[] = [];
|
|
504
525
|
let order = 0;
|
|
505
526
|
for (const pc of pool.values()) {
|
|
@@ -508,6 +529,7 @@ export function poolVotes(
|
|
|
508
529
|
const premises: DerivationItem[] = [];
|
|
509
530
|
const seenRi = new Set<number>();
|
|
510
531
|
let breadthSum = 0;
|
|
532
|
+
const spans: Array<[number, number]> = [];
|
|
511
533
|
for (const c of pc.contributions) {
|
|
512
534
|
const p0 = c.premises[0].item;
|
|
513
535
|
if (p0.kind !== "region" || seenRi.has(p0.ri)) continue;
|
|
@@ -515,8 +537,10 @@ export function poolVotes(
|
|
|
515
537
|
const rv = regionVotes[p0.ri];
|
|
516
538
|
breadthSum += rv.absorbed ?? 1;
|
|
517
539
|
premises.push({ kind: "form", span: [rv.start, rv.end] });
|
|
540
|
+
spans.push([rv.start, rv.end]);
|
|
518
541
|
}
|
|
519
542
|
regionSupport.set(pc.item.id, breadthSum);
|
|
543
|
+
regionSpans.set(pc.item.id, spans);
|
|
520
544
|
steps.push({
|
|
521
545
|
order: order++,
|
|
522
546
|
move: "pool-vote",
|
|
@@ -543,7 +567,35 @@ export function poolVotes(
|
|
|
543
567
|
}
|
|
544
568
|
}
|
|
545
569
|
}
|
|
546
|
-
return { votes, votesIdf, support, regionSupport, steps };
|
|
570
|
+
return { votes, votesIdf, support, regionSupport, regionSpans, steps };
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/** The number of DISTINCT clusters a root's contributing regions form —
|
|
574
|
+
* see Attention.clusters. Two regions belong to the same cluster iff the
|
|
575
|
+
* gap between them is strictly less than one river-fold quantum W: at
|
|
576
|
+
* that distance there is no room for a genuinely separate, independently
|
|
577
|
+
* perceivable unit of content between them (the same "smallest meaningful
|
|
578
|
+
* distinction" quantum {@link reachThreshold}'s own doc invokes). A gap
|
|
579
|
+
* of a full quantum or more means real, separate structure could sit
|
|
580
|
+
* between the two spans, so they count as independent corroboration.
|
|
581
|
+
* Strict `<` (not `<=`): verified against gap 3.1's own "gender equality"
|
|
582
|
+
* root, whose two genuine clusters sit EXACTLY W bytes apart — `<= W`
|
|
583
|
+
* would wrongly merge them into one and break that pinned requirement. */
|
|
584
|
+
function countClusters(spans: readonly [number, number][], W: number): number {
|
|
585
|
+
if (spans.length === 0) return 0;
|
|
586
|
+
const sorted = [...spans].sort((a, b) => a[0] - b[0]);
|
|
587
|
+
let clusters = 1;
|
|
588
|
+
let curEnd = sorted[0][1];
|
|
589
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
590
|
+
const [s, e] = sorted[i];
|
|
591
|
+
if (s - curEnd < W) {
|
|
592
|
+
curEnd = Math.max(curEnd, e);
|
|
593
|
+
} else {
|
|
594
|
+
clusters++;
|
|
595
|
+
curEnd = e;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return clusters;
|
|
547
599
|
}
|
|
548
600
|
|
|
549
601
|
export function commitVotes(
|
|
@@ -553,6 +605,7 @@ export function commitVotes(
|
|
|
553
605
|
votesIdf: Map<number, number>;
|
|
554
606
|
support: Map<number, { start: number; end: number; w: number }>;
|
|
555
607
|
regionSupport: Map<number, number>;
|
|
608
|
+
regionSpans: Map<number, Array<[number, number]>>;
|
|
556
609
|
steps: DerivationStep[];
|
|
557
610
|
},
|
|
558
611
|
sat: SaturationInfo,
|
|
@@ -560,7 +613,8 @@ export function commitVotes(
|
|
|
560
613
|
regionVoter: ReadonlyArray<{ id: number; score: number; w: number } | null>,
|
|
561
614
|
N: number,
|
|
562
615
|
): AttentionRead {
|
|
563
|
-
const { votes, votesIdf, support, regionSupport, steps } =
|
|
616
|
+
const { votes, votesIdf, support, regionSupport, regionSpans, steps } =
|
|
617
|
+
pooled;
|
|
564
618
|
if (votes.size === 0) {
|
|
565
619
|
traceAttention(ctx, regions, regionVoter, [], steps);
|
|
566
620
|
return { roots: [], ranked: [] };
|
|
@@ -580,6 +634,10 @@ export function commitVotes(
|
|
|
580
634
|
start: s.start,
|
|
581
635
|
end: s.end,
|
|
582
636
|
breadth: (regionSupport.get(anchor) ?? 0) / totalRegions,
|
|
637
|
+
clusters: countClusters(
|
|
638
|
+
regionSpans.get(anchor) ?? [],
|
|
639
|
+
ctx.space.maxGroup,
|
|
640
|
+
),
|
|
583
641
|
};
|
|
584
642
|
})
|
|
585
643
|
.sort((a, b) => b.vote - a.vote);
|