@iworkforces/tracelattice 2.1.1 → 2.2.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/README.md +20 -3
- package/dist/contracts/PersistenceBackend.d.ts +10 -1
- package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
- package/dist/contracts/calibrator.d.ts +9 -6
- package/dist/contracts/calibrator.d.ts.map +1 -1
- package/dist/contracts/interfaces.d.ts +6 -0
- package/dist/contracts/interfaces.d.ts.map +1 -1
- package/dist/contracts/persistence-work.d.ts +13 -1
- package/dist/contracts/persistence-work.d.ts.map +1 -1
- package/dist/contracts/strategy.d.ts +14 -9
- package/dist/contracts/strategy.d.ts.map +1 -1
- package/dist/core/DurableThoughtIdentityIndex.d.ts +35 -0
- package/dist/core/DurableThoughtIdentityIndex.d.ts.map +1 -0
- package/dist/core/DurableThoughtIdentityIndex.js +94 -0
- package/dist/core/DurableThoughtIdentityIndex.js.map +1 -0
- package/dist/core/HistoryManager.d.ts +5 -0
- package/dist/core/HistoryManager.d.ts.map +1 -1
- package/dist/core/HistoryManager.js +37 -4
- package/dist/core/HistoryManager.js.map +1 -1
- package/dist/core/IHistoryManager.d.ts +2 -0
- package/dist/core/IHistoryManager.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.d.ts +7 -1
- package/dist/core/PersistenceBuffer.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.js +13 -1
- package/dist/core/PersistenceBuffer.js.map +1 -1
- package/dist/core/PersistenceRestore.d.ts.map +1 -1
- package/dist/core/PersistenceRestore.js +11 -3
- package/dist/core/PersistenceRestore.js.map +1 -1
- package/dist/core/PersistenceWorkQueue.d.ts +13 -1
- package/dist/core/PersistenceWorkQueue.d.ts.map +1 -1
- package/dist/core/PersistenceWorkQueue.js +86 -11
- package/dist/core/PersistenceWorkQueue.js.map +1 -1
- package/dist/core/PersistenceWriter.d.ts.map +1 -1
- package/dist/core/PersistenceWriter.js +3 -0
- package/dist/core/PersistenceWriter.js.map +1 -1
- package/dist/core/ThoughtEvaluator.d.ts +7 -4
- package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
- package/dist/core/ThoughtEvaluator.js +15 -7
- package/dist/core/ThoughtEvaluator.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +19 -7
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/ThoughtReferenceIndex.d.ts +4 -0
- package/dist/core/ThoughtReferenceIndex.d.ts.map +1 -1
- package/dist/core/ThoughtReferenceIndex.js +28 -1
- package/dist/core/ThoughtReferenceIndex.js.map +1 -1
- package/dist/core/VerificationOutcomeAdmission.d.ts +8 -1
- package/dist/core/VerificationOutcomeAdmission.d.ts.map +1 -1
- package/dist/core/VerificationOutcomeAdmission.js.map +1 -1
- package/dist/core/VerificationTargetRestore.d.ts +5 -0
- package/dist/core/VerificationTargetRestore.d.ts.map +1 -0
- package/dist/core/VerificationTargetRestore.js +61 -0
- package/dist/core/VerificationTargetRestore.js.map +1 -0
- package/dist/core/evaluator/Aggregator.d.ts +2 -1
- package/dist/core/evaluator/Aggregator.d.ts.map +1 -1
- package/dist/core/evaluator/Aggregator.js +4 -12
- package/dist/core/evaluator/Aggregator.js.map +1 -1
- package/dist/core/evaluator/Calibrator.d.ts +13 -9
- package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
- package/dist/core/evaluator/Calibrator.js +25 -11
- package/dist/core/evaluator/Calibrator.js.map +1 -1
- package/dist/core/evaluator/PatternDetector.d.ts +2 -1
- package/dist/core/evaluator/PatternDetector.d.ts.map +1 -1
- package/dist/core/evaluator/PatternDetector.js +13 -12
- package/dist/core/evaluator/PatternDetector.js.map +1 -1
- package/dist/core/evaluator/SignalComputer.d.ts +3 -2
- package/dist/core/evaluator/SignalComputer.d.ts.map +1 -1
- package/dist/core/evaluator/SignalComputer.js +4 -9
- package/dist/core/evaluator/SignalComputer.js.map +1 -1
- package/dist/core/evaluator/VerificationLinks.d.ts +19 -0
- package/dist/core/evaluator/VerificationLinks.d.ts.map +1 -0
- package/dist/core/evaluator/VerificationLinks.js +113 -0
- package/dist/core/evaluator/VerificationLinks.js.map +1 -0
- package/dist/core/evaluator/calibration-math.d.ts +12 -2
- package/dist/core/evaluator/calibration-math.d.ts.map +1 -1
- package/dist/core/evaluator/calibration-math.js +11 -2
- package/dist/core/evaluator/calibration-math.js.map +1 -1
- package/dist/core/graph/EdgeEmitter.d.ts.map +1 -1
- package/dist/core/graph/EdgeEmitter.js +2 -1
- package/dist/core/graph/EdgeEmitter.js.map +1 -1
- package/dist/core/graph/GraphView.d.ts +5 -5
- package/dist/core/graph/GraphView.d.ts.map +1 -1
- package/dist/core/graph/GraphView.js +11 -11
- package/dist/core/graph/GraphView.js.map +1 -1
- package/dist/core/reasoning/ActiveEvidenceProjection.d.ts +20 -0
- package/dist/core/reasoning/ActiveEvidenceProjection.d.ts.map +1 -0
- package/dist/core/reasoning/ActiveEvidenceProjection.js +100 -0
- package/dist/core/reasoning/ActiveEvidenceProjection.js.map +1 -0
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts +5 -4
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +24 -14
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +3 -1
- package/dist/lib.js.map +1 -1
- package/dist/persistence/BacktrackPersistence.d.ts +13 -0
- package/dist/persistence/BacktrackPersistence.d.ts.map +1 -0
- package/dist/persistence/BacktrackPersistence.js +90 -0
- package/dist/persistence/BacktrackPersistence.js.map +1 -0
- package/dist/persistence/FilePersistence.d.ts +2 -1
- package/dist/persistence/FilePersistence.d.ts.map +1 -1
- package/dist/persistence/FilePersistence.js +28 -0
- package/dist/persistence/FilePersistence.js.map +1 -1
- package/dist/persistence/FileSnapshotV2.d.ts +2 -0
- package/dist/persistence/FileSnapshotV2.d.ts.map +1 -1
- package/dist/persistence/FileSnapshotV2.js +6 -2
- package/dist/persistence/FileSnapshotV2.js.map +1 -1
- package/dist/persistence/MemoryPersistence.d.ts +2 -1
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
- package/dist/persistence/MemoryPersistence.js +21 -1
- package/dist/persistence/MemoryPersistence.js.map +1 -1
- package/dist/persistence/PersistenceCodec.d.ts.map +1 -1
- package/dist/persistence/PersistenceCodec.js +5 -0
- package/dist/persistence/PersistenceCodec.js.map +1 -1
- package/dist/persistence/PersistenceErrors.d.ts +1 -1
- package/dist/persistence/PersistenceErrors.d.ts.map +1 -1
- package/dist/persistence/PersistenceErrors.js.map +1 -1
- package/dist/persistence/PersistenceScope.d.ts +1 -1
- package/dist/persistence/PersistenceScope.d.ts.map +1 -1
- package/dist/persistence/PersistenceScope.js.map +1 -1
- package/dist/persistence/SqlitePersistence.d.ts +2 -1
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.js +18 -0
- package/dist/persistence/SqlitePersistence.js.map +1 -1
- package/dist/registry/BaseRegistry.d.ts +10 -2
- package/dist/registry/BaseRegistry.d.ts.map +1 -1
- package/dist/registry/BaseRegistry.js +128 -81
- package/dist/registry/BaseRegistry.js.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
function resolvedVerificationTarget(thought, references) {
|
|
2
|
+
return 'verification' === thought.thought_type ? references.verificationTargetThoughtId : void 0;
|
|
3
|
+
}
|
|
4
|
+
function resolveVerificationLinks(history, branches, admissionTargets = new Map()) {
|
|
5
|
+
const thoughts = collectActiveThoughts(history, branches);
|
|
6
|
+
const hypotheses = thoughts.filter((thought)=>'hypothesis' === thought.thought_type && Boolean(thought.id));
|
|
7
|
+
const hypothesisIds = new Set(hypotheses.flatMap((thought)=>thought.id ? [
|
|
8
|
+
thought.id
|
|
9
|
+
] : []));
|
|
10
|
+
const activeThoughtIds = new Set(thoughts.flatMap((thought)=>thought.id ? [
|
|
11
|
+
thought.id
|
|
12
|
+
] : []));
|
|
13
|
+
const targetsByVerifier = new Map();
|
|
14
|
+
const targetsByVerifierId = new Map();
|
|
15
|
+
const legacyTargets = uniqueLegacyTargets(hypotheses);
|
|
16
|
+
for (const verifier of thoughts){
|
|
17
|
+
if ('verification' !== verifier.thought_type) continue;
|
|
18
|
+
const target = resolveTarget(verifier, hypotheses, admissionTargets, activeThoughtIds, legacyTargets);
|
|
19
|
+
if (void 0 !== target) {
|
|
20
|
+
targetsByVerifier.set(verifier, target);
|
|
21
|
+
if (verifier.id && target.id) targetsByVerifierId.set(verifier.id, target.id);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const verifiedHypotheses = new Set(targetsByVerifier.values());
|
|
25
|
+
const verifiedHypothesisIds = new Set([
|
|
26
|
+
...verifiedHypotheses
|
|
27
|
+
].flatMap((thought)=>thought.id ? [
|
|
28
|
+
thought.id
|
|
29
|
+
] : []));
|
|
30
|
+
return Object.freeze({
|
|
31
|
+
thoughts: Object.freeze(thoughts),
|
|
32
|
+
hypotheses: Object.freeze(hypotheses),
|
|
33
|
+
hypothesisIds: new Set(hypothesisIds),
|
|
34
|
+
verifiedHypothesisIds: new Set(verifiedHypothesisIds),
|
|
35
|
+
verifiedHypothesisCount: verifiedHypotheses.size,
|
|
36
|
+
targetFor: (verifierId)=>targetsByVerifierId.get(verifierId),
|
|
37
|
+
isVerified: (hypothesis)=>verifiedHypotheses.has(hypothesis),
|
|
38
|
+
verifies: (verifier, hypothesis)=>targetsByVerifier.get(verifier) === hypothesis
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function collectActiveMainThoughts(history, branches) {
|
|
42
|
+
const branchThoughts = Object.values(branches).flat();
|
|
43
|
+
const allThoughts = [
|
|
44
|
+
...history,
|
|
45
|
+
...branchThoughts
|
|
46
|
+
];
|
|
47
|
+
const retractedIds = new Set(allThoughts.flatMap((thought)=>true === thought.retracted && thought.id ? [
|
|
48
|
+
thought.id
|
|
49
|
+
] : []));
|
|
50
|
+
const includedIds = new Set();
|
|
51
|
+
const active = [];
|
|
52
|
+
for (const thought of history)if (true !== thought.retracted) {
|
|
53
|
+
if (!thought.id) {
|
|
54
|
+
active.push(thought);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (!(retractedIds.has(thought.id) || includedIds.has(thought.id))) {
|
|
58
|
+
includedIds.add(thought.id);
|
|
59
|
+
active.push(thought);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return active;
|
|
63
|
+
}
|
|
64
|
+
function collectActiveThoughts(history, branches) {
|
|
65
|
+
const branchThoughts = Object.values(branches).flat();
|
|
66
|
+
const allThoughts = [
|
|
67
|
+
...history,
|
|
68
|
+
...branchThoughts
|
|
69
|
+
];
|
|
70
|
+
const retractedIds = new Set(allThoughts.flatMap((thought)=>true === thought.retracted && thought.id ? [
|
|
71
|
+
thought.id
|
|
72
|
+
] : []));
|
|
73
|
+
const active = collectActiveMainThoughts(history, branches);
|
|
74
|
+
const includedIds = new Set(active.flatMap((thought)=>thought.id ? [
|
|
75
|
+
thought.id
|
|
76
|
+
] : []));
|
|
77
|
+
for (const thought of branchThoughts)if (thought.id && true !== thought.retracted) {
|
|
78
|
+
if (!(retractedIds.has(thought.id) || includedIds.has(thought.id))) {
|
|
79
|
+
includedIds.add(thought.id);
|
|
80
|
+
active.push(thought);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return active;
|
|
84
|
+
}
|
|
85
|
+
function uniqueLegacyTargets(hypotheses) {
|
|
86
|
+
const candidates = new Map();
|
|
87
|
+
for (const hypothesis of hypotheses){
|
|
88
|
+
const label = hypothesis.hypothesis_id;
|
|
89
|
+
if (void 0 === label) continue;
|
|
90
|
+
const existing = candidates.get(label);
|
|
91
|
+
candidates.set(label, void 0 !== existing || candidates.has(label) ? void 0 : hypothesis);
|
|
92
|
+
}
|
|
93
|
+
return new Map([
|
|
94
|
+
...candidates
|
|
95
|
+
].flatMap(([label, target])=>void 0 === target ? [] : [
|
|
96
|
+
[
|
|
97
|
+
label,
|
|
98
|
+
target
|
|
99
|
+
]
|
|
100
|
+
]));
|
|
101
|
+
}
|
|
102
|
+
function resolveTarget(verifier, hypotheses, admissionTargets, activeThoughtIds, legacyTargets) {
|
|
103
|
+
if (void 0 !== verifier.verification_target) {
|
|
104
|
+
if (!verifier.id) return;
|
|
105
|
+
const targetId = admissionTargets.get(verifier.id);
|
|
106
|
+
if (void 0 === targetId || !activeThoughtIds.has(targetId)) return;
|
|
107
|
+
return hypotheses.find((hypothesis)=>hypothesis.id === targetId);
|
|
108
|
+
}
|
|
109
|
+
return verifier.id && void 0 !== verifier.hypothesis_id ? legacyTargets.get(verifier.hypothesis_id) : void 0;
|
|
110
|
+
}
|
|
111
|
+
export { collectActiveMainThoughts, collectActiveThoughts, resolveVerificationLinks, resolvedVerificationTarget };
|
|
112
|
+
|
|
113
|
+
//# sourceMappingURL=VerificationLinks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core/evaluator/VerificationLinks.js","sources":["../../../src/core/evaluator/VerificationLinks.ts"],"sourcesContent":["import type { ThoughtId } from '../../contracts/ids.js';\nimport type { ResolvedThoughtReferences } from '../IHistoryManager.js';\nimport type { ThoughtData } from '../thought.js';\n\nexport type ActiveThoughtBranches = Readonly<Record<string, readonly ThoughtData[]>>;\n\nexport interface VerificationLinks {\n\treadonly thoughts: readonly ThoughtData[];\n\treadonly hypotheses: readonly ThoughtData[];\n\treadonly hypothesisIds: ReadonlySet<ThoughtId>;\n\treadonly verifiedHypothesisIds: ReadonlySet<ThoughtId>;\n\treadonly verifiedHypothesisCount: number;\n\ttargetFor(verifierId: ThoughtId): ThoughtId | undefined;\n\tisVerified(hypothesis: ThoughtData): boolean;\n\tverifies(verifier: ThoughtData, hypothesis: ThoughtData): boolean;\n}\n\nexport function resolvedVerificationTarget(\n\tthought: ThoughtData,\n\treferences: ResolvedThoughtReferences\n): ThoughtId | undefined {\n\treturn thought.thought_type === 'verification'\n\t\t? references.verificationTargetThoughtId\n\t\t: undefined;\n}\n\nexport function resolveVerificationLinks(\n\thistory: readonly ThoughtData[],\n\tbranches: ActiveThoughtBranches,\n\tadmissionTargets: ReadonlyMap<ThoughtId, ThoughtId> = new Map()\n): VerificationLinks {\n\tconst thoughts = collectActiveThoughts(history, branches);\n\tconst hypotheses = thoughts.filter(\n\t\t(thought) => thought.thought_type === 'hypothesis' && Boolean(thought.id)\n\t);\n\tconst hypothesisIds = new Set(hypotheses.flatMap((thought) => (thought.id ? [thought.id] : [])));\n\tconst activeThoughtIds = new Set(thoughts.flatMap((thought) => (thought.id ? [thought.id] : [])));\n\tconst targetsByVerifier = new Map<ThoughtData, ThoughtData>();\n\tconst targetsByVerifierId = new Map<ThoughtId, ThoughtId>();\n\tconst legacyTargets = uniqueLegacyTargets(hypotheses);\n\n\tfor (const verifier of thoughts) {\n\t\tif (verifier.thought_type !== 'verification') continue;\n\t\tconst target = resolveTarget(\n\t\t\tverifier,\n\t\t\thypotheses,\n\t\t\tadmissionTargets,\n\t\t\tactiveThoughtIds,\n\t\t\tlegacyTargets\n\t\t);\n\t\tif (target === undefined) continue;\n\t\ttargetsByVerifier.set(verifier, target);\n\t\tif (verifier.id && target.id) {\n\t\t\ttargetsByVerifierId.set(verifier.id, target.id);\n\t\t}\n\t}\n\n\tconst verifiedHypotheses = new Set(targetsByVerifier.values());\n\tconst verifiedHypothesisIds = new Set(\n\t\t[...verifiedHypotheses].flatMap((thought) => (thought.id ? [thought.id] : []))\n\t);\n\treturn Object.freeze({\n\t\tthoughts: Object.freeze(thoughts),\n\t\thypotheses: Object.freeze(hypotheses),\n\t\thypothesisIds: new Set(hypothesisIds),\n\t\tverifiedHypothesisIds: new Set(verifiedHypothesisIds),\n\t\tverifiedHypothesisCount: verifiedHypotheses.size,\n\t\ttargetFor: (verifierId: ThoughtId) => targetsByVerifierId.get(verifierId),\n\t\tisVerified: (hypothesis: ThoughtData) => verifiedHypotheses.has(hypothesis),\n\t\tverifies: (verifier: ThoughtData, hypothesis: ThoughtData) =>\n\t\t\ttargetsByVerifier.get(verifier) === hypothesis,\n\t});\n}\n\nexport function collectActiveMainThoughts(\n\thistory: readonly ThoughtData[],\n\tbranches: ActiveThoughtBranches\n): ThoughtData[] {\n\tconst branchThoughts = Object.values(branches).flat();\n\tconst allThoughts = [...history, ...branchThoughts];\n\tconst retractedIds = new Set(\n\t\tallThoughts.flatMap((thought) => (thought.retracted === true && thought.id ? [thought.id] : []))\n\t);\n\tconst includedIds = new Set<ThoughtId>();\n\tconst active: ThoughtData[] = [];\n\tfor (const thought of history) {\n\t\tif (thought.retracted === true) continue;\n\t\tif (!thought.id) {\n\t\t\tactive.push(thought);\n\t\t\tcontinue;\n\t\t}\n\t\tif (retractedIds.has(thought.id) || includedIds.has(thought.id)) continue;\n\t\tincludedIds.add(thought.id);\n\t\tactive.push(thought);\n\t}\n\treturn active;\n}\n\nexport function collectActiveThoughts(\n\thistory: readonly ThoughtData[],\n\tbranches: ActiveThoughtBranches\n): ThoughtData[] {\n\tconst branchThoughts = Object.values(branches).flat();\n\tconst allThoughts = [...history, ...branchThoughts];\n\tconst retractedIds = new Set(\n\t\tallThoughts.flatMap((thought) => (thought.retracted === true && thought.id ? [thought.id] : []))\n\t);\n\tconst active = collectActiveMainThoughts(history, branches);\n\tconst includedIds = new Set(active.flatMap((thought) => (thought.id ? [thought.id] : [])));\n\tfor (const thought of branchThoughts) {\n\t\tif (!thought.id || thought.retracted === true) continue;\n\t\tif (retractedIds.has(thought.id) || includedIds.has(thought.id)) continue;\n\t\tincludedIds.add(thought.id);\n\t\tactive.push(thought);\n\t}\n\treturn active;\n}\n\nfunction uniqueLegacyTargets(hypotheses: readonly ThoughtData[]): ReadonlyMap<string, ThoughtData> {\n\tconst candidates = new Map<string, ThoughtData | undefined>();\n\tfor (const hypothesis of hypotheses) {\n\t\tconst label = hypothesis.hypothesis_id;\n\t\tif (label === undefined) continue;\n\t\tconst existing = candidates.get(label);\n\t\tcandidates.set(\n\t\t\tlabel,\n\t\t\texisting === undefined && !candidates.has(label) ? hypothesis : undefined\n\t\t);\n\t}\n\treturn new Map(\n\t\t[...candidates].flatMap(([label, target]) =>\n\t\t\ttarget === undefined ? [] : ([[label, target]] as const)\n\t\t)\n\t);\n}\n\nfunction resolveTarget(\n\tverifier: ThoughtData,\n\thypotheses: readonly ThoughtData[],\n\tadmissionTargets: ReadonlyMap<ThoughtId, ThoughtId>,\n\tactiveThoughtIds: ReadonlySet<ThoughtId>,\n\tlegacyTargets: ReadonlyMap<string, ThoughtData>\n): ThoughtData | undefined {\n\tif (verifier.verification_target !== undefined) {\n\t\tif (!verifier.id) return undefined;\n\t\tconst targetId = admissionTargets.get(verifier.id);\n\t\tif (targetId === undefined || !activeThoughtIds.has(targetId)) return undefined;\n\t\treturn hypotheses.find((hypothesis) => hypothesis.id === targetId);\n\t}\n\treturn !verifier.id || verifier.hypothesis_id === undefined\n\t\t? undefined\n\t\t: legacyTargets.get(verifier.hypothesis_id);\n}\n"],"names":["resolvedVerificationTarget","thought","references","undefined","resolveVerificationLinks","history","branches","admissionTargets","Map","thoughts","collectActiveThoughts","hypotheses","Boolean","hypothesisIds","Set","activeThoughtIds","targetsByVerifier","targetsByVerifierId","legacyTargets","uniqueLegacyTargets","verifier","target","resolveTarget","verifiedHypotheses","verifiedHypothesisIds","Object","verifierId","hypothesis","collectActiveMainThoughts","branchThoughts","allThoughts","retractedIds","includedIds","active","candidates","label","existing","targetId"],"mappings":"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"}
|
|
@@ -5,6 +5,17 @@ export declare const TEMPERATURE_GRID: readonly number[];
|
|
|
5
5
|
export declare const MIN_OUTCOMES_FOR_TEMPERATURE = 10;
|
|
6
6
|
/** Small epsilon to keep log() finite when probabilities approach 0 or 1. */
|
|
7
7
|
export declare const EPSILON = 1e-9;
|
|
8
|
+
export interface RawPriorBlend {
|
|
9
|
+
readonly blended: number;
|
|
10
|
+
readonly priorWeight: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Blend a raw confidence prior with the empirical mean for its thought type.
|
|
14
|
+
*
|
|
15
|
+
* The raw-signal weight is `10 / (10 + sampleCount)`, so an empty evidence set
|
|
16
|
+
* returns the raw confidence exactly and empirical influence grows with evidence.
|
|
17
|
+
*/
|
|
18
|
+
export declare function blendWithRawPrior(rawConfidence: number, empiricalMean: number, sampleCount: number): RawPriorBlend;
|
|
8
19
|
/**
|
|
9
20
|
* Apply temperature scaling to a probability `p`.
|
|
10
21
|
*
|
|
@@ -19,8 +30,7 @@ export declare function applyTemperature(p: number, temperature: number): number
|
|
|
19
30
|
/**
|
|
20
31
|
* Compute negative log-likelihood for a candidate temperature.
|
|
21
32
|
*
|
|
22
|
-
* @param outcomes -
|
|
23
|
-
* `actual` is the observed 0/1 label.
|
|
33
|
+
* @param outcomes - Prediction/label samples to score.
|
|
24
34
|
* @param temperature - Temperature to evaluate.
|
|
25
35
|
* @returns Mean NLL across outcomes (lower is better). Returns `Infinity` if
|
|
26
36
|
* `outcomes` is empty.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calibration-math.d.ts","sourceRoot":"","sources":["../../../src/core/evaluator/calibration-math.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAAqC,CAAC;AAEpF,uEAAuE;AACvE,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C,6EAA6E;AAC7E,eAAO,MAAM,OAAO,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"calibration-math.d.ts","sourceRoot":"","sources":["../../../src/core/evaluator/calibration-math.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAAqC,CAAC;AAEpF,uEAAuE;AACvE,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C,6EAA6E;AAC7E,eAAO,MAAM,OAAO,OAAO,CAAC;AAI5B,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAChC,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,GACjB,aAAa,CAMf;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACpC,QAAQ,EAAE,SAAS,mBAAmB,EAAE,EACxC,WAAW,EAAE,MAAM,GACjB,MAAM,CASR;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,mBAAmB,EAAE,GAAG,MAAM,CAY/E"}
|
|
@@ -8,7 +8,16 @@ const TEMPERATURE_GRID = [
|
|
|
8
8
|
];
|
|
9
9
|
const MIN_OUTCOMES_FOR_TEMPERATURE = 10;
|
|
10
10
|
const EPSILON = 1e-9;
|
|
11
|
+
const RAW_SIGNAL_PRIOR_STRENGTH = 10;
|
|
12
|
+
function blendWithRawPrior(rawConfidence, empiricalMean, sampleCount) {
|
|
13
|
+
const priorWeight = RAW_SIGNAL_PRIOR_STRENGTH / (RAW_SIGNAL_PRIOR_STRENGTH + sampleCount);
|
|
14
|
+
return {
|
|
15
|
+
blended: priorWeight * rawConfidence + (1 - priorWeight) * empiricalMean,
|
|
16
|
+
priorWeight
|
|
17
|
+
};
|
|
18
|
+
}
|
|
11
19
|
function applyTemperature(p, temperature) {
|
|
20
|
+
if (1 === temperature) return p;
|
|
12
21
|
const clamped = Math.min(1 - EPSILON, Math.max(EPSILON, p));
|
|
13
22
|
const logit = Math.log(clamped / (1 - clamped));
|
|
14
23
|
const scaled = logit / temperature;
|
|
@@ -27,7 +36,7 @@ function negativeLogLikelihood(outcomes, temperature) {
|
|
|
27
36
|
function fitTemperature(outcomes) {
|
|
28
37
|
if (outcomes.length < MIN_OUTCOMES_FOR_TEMPERATURE) return 1.0;
|
|
29
38
|
let best = 1.0;
|
|
30
|
-
let bestLoss =
|
|
39
|
+
let bestLoss = negativeLogLikelihood(outcomes, best);
|
|
31
40
|
for (const t of TEMPERATURE_GRID){
|
|
32
41
|
const loss = negativeLogLikelihood(outcomes, t);
|
|
33
42
|
if (loss < bestLoss) {
|
|
@@ -37,6 +46,6 @@ function fitTemperature(outcomes) {
|
|
|
37
46
|
}
|
|
38
47
|
return best;
|
|
39
48
|
}
|
|
40
|
-
export { EPSILON, MIN_OUTCOMES_FOR_TEMPERATURE, TEMPERATURE_GRID, applyTemperature, fitTemperature, negativeLogLikelihood };
|
|
49
|
+
export { EPSILON, MIN_OUTCOMES_FOR_TEMPERATURE, TEMPERATURE_GRID, applyTemperature, blendWithRawPrior, fitTemperature, negativeLogLikelihood };
|
|
41
50
|
|
|
42
51
|
//# sourceMappingURL=calibration-math.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/evaluator/calibration-math.js","sources":["../../../src/core/evaluator/calibration-math.ts"],"sourcesContent":["import type { VerificationOutcome } from '../../contracts/interfaces.js';\n\n/** Candidate temperatures evaluated during grid search refit. */\nexport const TEMPERATURE_GRID: readonly number[] = [0.5, 0.75, 1.0, 1.25, 1.5, 2.0];\n\n/** Minimum outcomes required before temperature scaling is applied. */\nexport const MIN_OUTCOMES_FOR_TEMPERATURE = 10;\n\n/** Small epsilon to keep log() finite when probabilities approach 0 or 1. */\nexport const EPSILON = 1e-9;\n\n/**\n * Apply temperature scaling to a probability `p`.\n *\n * Uses the standard logit re-scaling:\n * `sigmoid(logit(p) / T)`. T=1 is the identity.\n *\n * @param p - Probability in `[0, 1]`.\n * @param temperature - Temperature scalar (must be > 0).\n * @returns Scaled probability in `[0, 1]`.\n */\nexport function applyTemperature(p: number, temperature: number): number {\n\tconst clamped = Math.min(1 - EPSILON, Math.max(EPSILON, p));\n\tconst logit = Math.log(clamped / (1 - clamped));\n\tconst scaled = logit / temperature;\n\treturn 1 / (1 + Math.exp(-scaled));\n}\n\n/**\n * Compute negative log-likelihood for a candidate temperature.\n *\n * @param outcomes -
|
|
1
|
+
{"version":3,"file":"core/evaluator/calibration-math.js","sources":["../../../src/core/evaluator/calibration-math.ts"],"sourcesContent":["import type { VerificationOutcome } from '../../contracts/interfaces.js';\n\n/** Candidate temperatures evaluated during grid search refit. */\nexport const TEMPERATURE_GRID: readonly number[] = [0.5, 0.75, 1.0, 1.25, 1.5, 2.0];\n\n/** Minimum outcomes required before temperature scaling is applied. */\nexport const MIN_OUTCOMES_FOR_TEMPERATURE = 10;\n\n/** Small epsilon to keep log() finite when probabilities approach 0 or 1. */\nexport const EPSILON = 1e-9;\n\nconst RAW_SIGNAL_PRIOR_STRENGTH = 10;\n\nexport interface RawPriorBlend {\n\treadonly blended: number;\n\treadonly priorWeight: number;\n}\n\n/**\n * Blend a raw confidence prior with the empirical mean for its thought type.\n *\n * The raw-signal weight is `10 / (10 + sampleCount)`, so an empty evidence set\n * returns the raw confidence exactly and empirical influence grows with evidence.\n */\nexport function blendWithRawPrior(\n\trawConfidence: number,\n\tempiricalMean: number,\n\tsampleCount: number\n): RawPriorBlend {\n\tconst priorWeight = RAW_SIGNAL_PRIOR_STRENGTH / (RAW_SIGNAL_PRIOR_STRENGTH + sampleCount);\n\treturn {\n\t\tblended: priorWeight * rawConfidence + (1 - priorWeight) * empiricalMean,\n\t\tpriorWeight,\n\t};\n}\n\n/**\n * Apply temperature scaling to a probability `p`.\n *\n * Uses the standard logit re-scaling:\n * `sigmoid(logit(p) / T)`. T=1 is the identity.\n *\n * @param p - Probability in `[0, 1]`.\n * @param temperature - Temperature scalar (must be > 0).\n * @returns Scaled probability in `[0, 1]`.\n */\nexport function applyTemperature(p: number, temperature: number): number {\n\tif (temperature === 1) return p;\n\tconst clamped = Math.min(1 - EPSILON, Math.max(EPSILON, p));\n\tconst logit = Math.log(clamped / (1 - clamped));\n\tconst scaled = logit / temperature;\n\treturn 1 / (1 + Math.exp(-scaled));\n}\n\n/**\n * Compute negative log-likelihood for a candidate temperature.\n *\n * @param outcomes - Prediction/label samples to score.\n * @param temperature - Temperature to evaluate.\n * @returns Mean NLL across outcomes (lower is better). Returns `Infinity` if\n * `outcomes` is empty.\n */\nexport function negativeLogLikelihood(\n\toutcomes: readonly VerificationOutcome[],\n\ttemperature: number\n): number {\n\tif (outcomes.length === 0) return Number.POSITIVE_INFINITY;\n\tlet total = 0;\n\tfor (const o of outcomes) {\n\t\tconst p = applyTemperature(o.predicted, temperature);\n\t\tconst clamped = Math.min(1 - EPSILON, Math.max(EPSILON, p));\n\t\ttotal += -(o.actual * Math.log(clamped) + (1 - o.actual) * Math.log(1 - clamped));\n\t}\n\treturn total / outcomes.length;\n}\n\n/**\n * Grid-search the temperature minimizing NLL.\n *\n * Falls back to T=1.0 when there are fewer than {@link MIN_OUTCOMES_FOR_TEMPERATURE}\n * outcomes available.\n *\n * @param outcomes - Outcomes to fit against.\n * @returns Best temperature from {@link TEMPERATURE_GRID}.\n */\nexport function fitTemperature(outcomes: readonly VerificationOutcome[]): number {\n\tif (outcomes.length < MIN_OUTCOMES_FOR_TEMPERATURE) return 1.0;\n\tlet best = 1.0;\n\tlet bestLoss = negativeLogLikelihood(outcomes, best);\n\tfor (const t of TEMPERATURE_GRID) {\n\t\tconst loss = negativeLogLikelihood(outcomes, t);\n\t\tif (loss < bestLoss) {\n\t\t\tbestLoss = loss;\n\t\t\tbest = t;\n\t\t}\n\t}\n\treturn best;\n}\n"],"names":["TEMPERATURE_GRID","MIN_OUTCOMES_FOR_TEMPERATURE","EPSILON","RAW_SIGNAL_PRIOR_STRENGTH","blendWithRawPrior","rawConfidence","empiricalMean","sampleCount","priorWeight","applyTemperature","p","temperature","clamped","Math","logit","scaled","negativeLogLikelihood","outcomes","Number","total","o","fitTemperature","best","bestLoss","t","loss"],"mappings":"AAGO,MAAMA,mBAAsC;IAAC;IAAK;IAAM;IAAK;IAAM;IAAK;CAAI;AAG5E,MAAMC,+BAA+B;AAGrC,MAAMC,UAAU;AAEvB,MAAMC,4BAA4B;AAa3B,SAASC,kBACfC,aAAqB,EACrBC,aAAqB,EACrBC,WAAmB;IAEnB,MAAMC,cAAcL,4BAA6BA,CAAAA,4BAA4BI,WAAU;IACvF,OAAO;QACN,SAASC,cAAcH,gBAAiB,KAAIG,WAAU,IAAKF;QAC3DE;IACD;AACD;AAYO,SAASC,iBAAiBC,CAAS,EAAEC,WAAmB;IAC9D,IAAIA,AAAgB,MAAhBA,aAAmB,OAAOD;IAC9B,MAAME,UAAUC,KAAK,GAAG,CAAC,IAAIX,SAASW,KAAK,GAAG,CAACX,SAASQ;IACxD,MAAMI,QAAQD,KAAK,GAAG,CAACD,UAAW,KAAIA,OAAM;IAC5C,MAAMG,SAASD,QAAQH;IACvB,OAAO,IAAK,KAAIE,KAAK,GAAG,CAAC,CAACE,OAAM;AACjC;AAUO,SAASC,sBACfC,QAAwC,EACxCN,WAAmB;IAEnB,IAAIM,AAAoB,MAApBA,SAAS,MAAM,EAAQ,OAAOC,KAAwB;IAC1D,IAAIC,QAAQ;IACZ,KAAK,MAAMC,KAAKH,SAAU;QACzB,MAAMP,IAAID,iBAAiBW,EAAE,SAAS,EAAET;QACxC,MAAMC,UAAUC,KAAK,GAAG,CAAC,IAAIX,SAASW,KAAK,GAAG,CAACX,SAASQ;QACxDS,SAAS,CAAEC,CAAAA,EAAE,MAAM,GAAGP,KAAK,GAAG,CAACD,WAAY,KAAIQ,EAAE,MAAK,IAAKP,KAAK,GAAG,CAAC,IAAID,QAAO;IAChF;IACA,OAAOO,QAAQF,SAAS,MAAM;AAC/B;AAWO,SAASI,eAAeJ,QAAwC;IACtE,IAAIA,SAAS,MAAM,GAAGhB,8BAA8B,OAAO;IAC3D,IAAIqB,OAAO;IACX,IAAIC,WAAWP,sBAAsBC,UAAUK;IAC/C,KAAK,MAAME,KAAKxB,iBAAkB;QACjC,MAAMyB,OAAOT,sBAAsBC,UAAUO;QAC7C,IAAIC,OAAOF,UAAU;YACpBA,WAAWE;YACXH,OAAOE;QACR;IACD;IACA,OAAOF;AACR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EdgeEmitter.d.ts","sourceRoot":"","sources":["../../../src/core/graph/EdgeEmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAA6B,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"EdgeEmitter.d.ts","sourceRoot":"","sources":["../../../src/core/graph/EdgeEmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAA6B,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAGhG,OAAO,EAEN,KAAK,QAAQ,EAGb,MAAM,wBAAwB,CAAC;AAEhC,qDAAqD;AACrD,MAAM,WAAW,mBAAmB;IACnC,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;CAC1C;AAED,6CAA6C;AAC7C,MAAM,WAAW,iBAAiB;IACjC,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,qBAAa,WAAW;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,iBAAiB;IAMrC,yEAAyE;IAClE,SAAS,IAAI,OAAO;IAI3B;;;;;;;;;;;;;OAaG;IACI,mBAAmB,CACzB,OAAO,EAAE,mBAAmB,EAC5B,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,uBAAuB,GAC/B,OAAO;IA6BV,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,uBAAuB;IAsB/B,OAAO,CAAC,iBAAiB;IAczB;;;;OAIG;IACH,OAAO,CAAC,eAAe;CA2CvB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getErrorMessage } from "../../errors.js";
|
|
2
2
|
import { NullLogger } from "../../logger/NullLogger.js";
|
|
3
|
+
import { resolvedVerificationTarget } from "../evaluator/VerificationLinks.js";
|
|
3
4
|
import { generateEdgeId } from "../../contracts/ids.js";
|
|
4
5
|
class EdgeEmitter {
|
|
5
6
|
_edgeStore;
|
|
@@ -42,7 +43,7 @@ class EdgeEmitter {
|
|
|
42
43
|
}
|
|
43
44
|
_emitVerificationEdge(thought, references, sessionId) {
|
|
44
45
|
if (void 0 === thought.verification_target || 'verification' !== thought.thought_type) return false;
|
|
45
|
-
return this._addEdgeIfValid(thought.id, references
|
|
46
|
+
return this._addEdgeIfValid(thought.id, resolvedVerificationTarget(thought, references), 'verifies', sessionId);
|
|
46
47
|
}
|
|
47
48
|
_emitCritiqueEdge(thought, references, sessionId) {
|
|
48
49
|
if (void 0 === thought.verification_target || 'critique' !== thought.thought_type) return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/graph/EdgeEmitter.js","sources":["../../../src/core/graph/EdgeEmitter.ts"],"sourcesContent":["/**\n * EdgeEmitter — emits DAG edges for thoughts based on their metadata.\n *\n * Stateless helper extracted from HistoryManager. Holds a reference to an\n * optional `IEdgeStore` and a feature flag (`dagEdges`) gating writes.\n *\n * @module EdgeEmitter\n */\n\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport { getErrorMessage } from '../../errors.js';\nimport type { Logger } from '../../logger/StructuredLogger.js';\nimport { NullLogger } from '../../logger/NullLogger.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { ResolvedThoughtReferences, ThoughtAdmissionContext } from '../IHistoryManager.js';\nimport type { Edge, EdgeKind } from './Edge.js';\nimport {\n\tgenerateEdgeId,\n\ttype BranchId,\n\ttype SessionId,\n\ttype ThoughtId,\n} from '../../contracts/ids.js';\n\n/** Minimal session view needed for edge emission. */\nexport interface EdgeEmissionSession {\n\tthought_history: ThoughtData[];\n\tbranches: Record<BranchId, ThoughtData[]>;\n}\n\n/** Configuration options for EdgeEmitter. */\nexport interface EdgeEmitterConfig {\n\tedgeStore?: IEdgeStore;\n\tdagEdges: boolean;\n\tlogger?: Logger;\n}\n\n/**\n * Emits DAG edges for thought relationships when an `IEdgeStore` is configured\n * and the `dagEdges` feature flag is enabled. No-ops otherwise.\n */\nexport class EdgeEmitter {\n\tprivate readonly _edgeStore?: IEdgeStore;\n\tprivate readonly _dagEdges: boolean;\n\tprivate readonly _logger: Logger;\n\n\tconstructor(config: EdgeEmitterConfig) {\n\t\tthis._edgeStore = config.edgeStore;\n\t\tthis._dagEdges = config.dagEdges;\n\t\tthis._logger = config.logger ?? new NullLogger();\n\t}\n\n\t/** Returns true when edge emission is active (store + flag both set). */\n\tpublic isEnabled(): boolean {\n\t\treturn this._edgeStore !== undefined && this._dagEdges;\n\t}\n\n\t/**\n\t * Emits DAG edges for a thought based on its metadata fields.\n\t *\n\t * Edge kinds (in priority order):\n\t * - branch: branch_from_thought + branch_id → parent.id → current.id\n\t * - merge: merge_from_thoughts → source.id → current.id (per source)\n\t * - verifies: verification_target + thought_type=verification → current.id → target.id\n\t * - critiques: verification_target + thought_type=critique → current.id → target.id\n\t * - derives_from: synthesis_sources → source.id → current.id (per source)\n\t * - revises: revises_thought → current.id → target.id\n\t * - tool_invocation: stable admission source id → current.id\n\t * - sequence: default chronological link from previous thought (if none of the above)\n\t * @returns True only when at least one edge was added to the store\n\t */\n\tpublic emitEdgesForThought(\n\t\tsession: EdgeEmissionSession,\n\t\tthought: ThoughtData,\n\t\tcontext?: ThoughtAdmissionContext\n\t): boolean {\n\t\tif (!this._edgeStore || !this._dagEdges) return false;\n\t\tif (!thought.id) return false;\n\n\t\tconst sessionId = thought.session_id;\n\t\tconst references = context?.resolvedReferences ?? {};\n\t\tconst hasRelationalIntent =\n\t\t\t(thought.branch_from_thought !== undefined && thought.branch_id !== undefined) ||\n\t\t\t(thought.merge_from_thoughts?.length ?? 0) > 0 ||\n\t\t\t(thought.verification_target !== undefined &&\n\t\t\t\t(thought.thought_type === 'verification' || thought.thought_type === 'critique')) ||\n\t\t\t(thought.synthesis_sources?.length ?? 0) > 0 ||\n\t\t\tthought.revises_thought !== undefined ||\n\t\t\t(thought.thought_type === 'tool_observation' &&\n\t\t\t\tcontext?.toolInvocationSourceThoughtId !== undefined);\n\t\tconst emittedRelational = [\n\t\t\tthis._emitBranchEdge(thought, references, sessionId),\n\t\t\tthis._emitMergeEdges(thought, references, sessionId),\n\t\t\tthis._emitVerificationEdge(thought, references, sessionId),\n\t\t\tthis._emitCritiqueEdge(thought, references, sessionId),\n\t\t\tthis._emitSynthesisEdges(thought, references, sessionId),\n\t\t\tthis._emitRevisionEdge(thought, references, sessionId),\n\t\t\tthis._emitToolInvocationEdge(thought, sessionId, context),\n\t\t].some((emitted) => emitted);\n\n\t\tif (emittedRelational || hasRelationalIntent) return emittedRelational;\n\t\treturn this._emitSequenceEdge(session, thought, sessionId);\n\t}\n\n\tprivate _emitBranchEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.branch_from_thought === undefined || !thought.branch_id) return false;\n\n\t\treturn this._addEdgeIfValid(references.branchFromThoughtId, thought.id, 'branch', sessionId);\n\t}\n\n\tprivate _emitMergeEdges(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tlet emitted = false;\n\t\tfor (const srcId of references.mergeFromThoughtIds ?? []) {\n\t\t\temitted = this._addEdgeIfValid(srcId, thought.id, 'merge', sessionId) || emitted;\n\t\t}\n\t\treturn emitted;\n\t}\n\n\tprivate _emitVerificationEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.verification_target === undefined || thought.thought_type !== 'verification')\n\t\t\treturn false;\n\n\t\treturn this._addEdgeIfValid(\n\t\t\tthought.id,\n\t\t\treferences.verificationTargetThoughtId,\n\t\t\t'verifies',\n\t\t\tsessionId\n\t\t);\n\t}\n\n\tprivate _emitCritiqueEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.verification_target === undefined || thought.thought_type !== 'critique')\n\t\t\treturn false;\n\n\t\treturn this._addEdgeIfValid(\n\t\t\tthought.id,\n\t\t\treferences.verificationTargetThoughtId,\n\t\t\t'critiques',\n\t\t\tsessionId\n\t\t);\n\t}\n\n\tprivate _emitSynthesisEdges(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tlet emitted = false;\n\t\tfor (const srcId of references.synthesisSourceThoughtIds ?? []) {\n\t\t\temitted = this._addEdgeIfValid(srcId, thought.id, 'derives_from', sessionId) || emitted;\n\t\t}\n\t\treturn emitted;\n\t}\n\n\tprivate _emitRevisionEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.revises_thought === undefined) return false;\n\n\t\treturn this._addEdgeIfValid(thought.id, references.revisesThoughtId, 'revises', sessionId);\n\t}\n\n\tprivate _emitToolInvocationEdge(\n\t\tthought: ThoughtData,\n\t\tsessionId: SessionId,\n\t\tcontext?: ThoughtAdmissionContext\n\t): boolean {\n\t\tif (\n\t\t\tthought.thought_type !== 'tool_observation' ||\n\t\t\tcontext?.toolInvocationSourceThoughtId === undefined\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst metadata = thought.tool_name !== undefined ? { tool_name: thought.tool_name } : undefined;\n\t\treturn this._addEdgeIfValid(\n\t\t\tcontext.toolInvocationSourceThoughtId,\n\t\t\tthought.id,\n\t\t\t'tool_invocation',\n\t\t\tsessionId,\n\t\t\tmetadata\n\t\t);\n\t}\n\n\tprivate _emitSequenceEdge(\n\t\tsession: EdgeEmissionSession,\n\t\tthought: ThoughtData,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tconst history = session.thought_history;\n\t\tif (history.length < 2) return false;\n\n\t\tconst prev = history[history.length - 2];\n\t\tif (!prev?.id) return false;\n\n\t\treturn this._addEdgeIfValid(prev.id, thought.id, 'sequence', sessionId);\n\t}\n\n\t/**\n\t * Adds an edge to the edge store if both endpoints are non-empty strings.\n\t * Returns true if added, false if skipped (missing endpoint).\n\t * Failures (e.g. self-edge) are caught and logged.\n\t */\n\tprivate _addEdgeIfValid(\n\t\tfrom: ThoughtId | undefined,\n\t\tto: ThoughtId | undefined,\n\t\tkind: EdgeKind,\n\t\tsessionId: SessionId,\n\t\tmetadata?: Record<string, unknown>\n\t): boolean {\n\t\tif (!from || !to) {\n\t\t\tthis._logger.debug('Skipping edge: unresolved endpoint', {\n\t\t\t\tkind,\n\t\t\t\tfrom: from ?? null,\n\t\t\t\tto: to ?? null,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t\tconst edge: Edge = {\n\t\t\tid: generateEdgeId(),\n\t\t\tfrom: from as Edge['from'],\n\t\t\tto: to as Edge['to'],\n\t\t\tkind,\n\t\t\tsessionId: sessionId as Edge['sessionId'],\n\t\t\tcreatedAt: Date.now(),\n\t\t\t...(metadata !== undefined ? { metadata } : {}),\n\t\t};\n\t\tif (!this._edgeStore) {\n\t\t\tthis._logger.warn('EdgeStore not available; skipping edge', { kind });\n\t\t\treturn false;\n\t\t}\n\t\tconst duplicate = this._edgeStore\n\t\t\t.edgesForSession(sessionId)\n\t\t\t.some((existing) => existing.kind === kind && existing.from === from && existing.to === to);\n\t\tif (duplicate) return false;\n\t\ttry {\n\t\t\tthis._edgeStore.addEdge(edge);\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tthis._logger.info('Failed to add DAG edge', {\n\t\t\t\tkind,\n\t\t\t\terror: getErrorMessage(err),\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"],"names":["EdgeEmitter","config","NullLogger","undefined","session","thought","context","sessionId","references","hasRelationalIntent","emittedRelational","emitted","srcId","metadata","history","prev","from","to","kind","edge","generateEdgeId","Date","duplicate","existing","err","getErrorMessage"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core/graph/EdgeEmitter.js","sources":["../../../src/core/graph/EdgeEmitter.ts"],"sourcesContent":["/**\n * EdgeEmitter — emits DAG edges for thoughts based on their metadata.\n *\n * Stateless helper extracted from HistoryManager. Holds a reference to an\n * optional `IEdgeStore` and a feature flag (`dagEdges`) gating writes.\n *\n * @module EdgeEmitter\n */\n\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport { getErrorMessage } from '../../errors.js';\nimport type { Logger } from '../../logger/StructuredLogger.js';\nimport { NullLogger } from '../../logger/NullLogger.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { ResolvedThoughtReferences, ThoughtAdmissionContext } from '../IHistoryManager.js';\nimport { resolvedVerificationTarget } from '../evaluator/VerificationLinks.js';\nimport type { Edge, EdgeKind } from './Edge.js';\nimport {\n\tgenerateEdgeId,\n\ttype BranchId,\n\ttype SessionId,\n\ttype ThoughtId,\n} from '../../contracts/ids.js';\n\n/** Minimal session view needed for edge emission. */\nexport interface EdgeEmissionSession {\n\tthought_history: ThoughtData[];\n\tbranches: Record<BranchId, ThoughtData[]>;\n}\n\n/** Configuration options for EdgeEmitter. */\nexport interface EdgeEmitterConfig {\n\tedgeStore?: IEdgeStore;\n\tdagEdges: boolean;\n\tlogger?: Logger;\n}\n\n/**\n * Emits DAG edges for thought relationships when an `IEdgeStore` is configured\n * and the `dagEdges` feature flag is enabled. No-ops otherwise.\n */\nexport class EdgeEmitter {\n\tprivate readonly _edgeStore?: IEdgeStore;\n\tprivate readonly _dagEdges: boolean;\n\tprivate readonly _logger: Logger;\n\n\tconstructor(config: EdgeEmitterConfig) {\n\t\tthis._edgeStore = config.edgeStore;\n\t\tthis._dagEdges = config.dagEdges;\n\t\tthis._logger = config.logger ?? new NullLogger();\n\t}\n\n\t/** Returns true when edge emission is active (store + flag both set). */\n\tpublic isEnabled(): boolean {\n\t\treturn this._edgeStore !== undefined && this._dagEdges;\n\t}\n\n\t/**\n\t * Emits DAG edges for a thought based on its metadata fields.\n\t *\n\t * Edge kinds (in priority order):\n\t * - branch: branch_from_thought + branch_id → parent.id → current.id\n\t * - merge: merge_from_thoughts → source.id → current.id (per source)\n\t * - verifies: verification_target + thought_type=verification → current.id → target.id\n\t * - critiques: verification_target + thought_type=critique → current.id → target.id\n\t * - derives_from: synthesis_sources → source.id → current.id (per source)\n\t * - revises: revises_thought → current.id → target.id\n\t * - tool_invocation: stable admission source id → current.id\n\t * - sequence: default chronological link from previous thought (if none of the above)\n\t * @returns True only when at least one edge was added to the store\n\t */\n\tpublic emitEdgesForThought(\n\t\tsession: EdgeEmissionSession,\n\t\tthought: ThoughtData,\n\t\tcontext?: ThoughtAdmissionContext\n\t): boolean {\n\t\tif (!this._edgeStore || !this._dagEdges) return false;\n\t\tif (!thought.id) return false;\n\n\t\tconst sessionId = thought.session_id;\n\t\tconst references = context?.resolvedReferences ?? {};\n\t\tconst hasRelationalIntent =\n\t\t\t(thought.branch_from_thought !== undefined && thought.branch_id !== undefined) ||\n\t\t\t(thought.merge_from_thoughts?.length ?? 0) > 0 ||\n\t\t\t(thought.verification_target !== undefined &&\n\t\t\t\t(thought.thought_type === 'verification' || thought.thought_type === 'critique')) ||\n\t\t\t(thought.synthesis_sources?.length ?? 0) > 0 ||\n\t\t\tthought.revises_thought !== undefined ||\n\t\t\t(thought.thought_type === 'tool_observation' &&\n\t\t\t\tcontext?.toolInvocationSourceThoughtId !== undefined);\n\t\tconst emittedRelational = [\n\t\t\tthis._emitBranchEdge(thought, references, sessionId),\n\t\t\tthis._emitMergeEdges(thought, references, sessionId),\n\t\t\tthis._emitVerificationEdge(thought, references, sessionId),\n\t\t\tthis._emitCritiqueEdge(thought, references, sessionId),\n\t\t\tthis._emitSynthesisEdges(thought, references, sessionId),\n\t\t\tthis._emitRevisionEdge(thought, references, sessionId),\n\t\t\tthis._emitToolInvocationEdge(thought, sessionId, context),\n\t\t].some((emitted) => emitted);\n\n\t\tif (emittedRelational || hasRelationalIntent) return emittedRelational;\n\t\treturn this._emitSequenceEdge(session, thought, sessionId);\n\t}\n\n\tprivate _emitBranchEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.branch_from_thought === undefined || !thought.branch_id) return false;\n\n\t\treturn this._addEdgeIfValid(references.branchFromThoughtId, thought.id, 'branch', sessionId);\n\t}\n\n\tprivate _emitMergeEdges(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tlet emitted = false;\n\t\tfor (const srcId of references.mergeFromThoughtIds ?? []) {\n\t\t\temitted = this._addEdgeIfValid(srcId, thought.id, 'merge', sessionId) || emitted;\n\t\t}\n\t\treturn emitted;\n\t}\n\n\tprivate _emitVerificationEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.verification_target === undefined || thought.thought_type !== 'verification')\n\t\t\treturn false;\n\n\t\treturn this._addEdgeIfValid(\n\t\t\tthought.id,\n\t\t\tresolvedVerificationTarget(thought, references),\n\t\t\t'verifies',\n\t\t\tsessionId\n\t\t);\n\t}\n\n\tprivate _emitCritiqueEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.verification_target === undefined || thought.thought_type !== 'critique')\n\t\t\treturn false;\n\n\t\treturn this._addEdgeIfValid(\n\t\t\tthought.id,\n\t\t\treferences.verificationTargetThoughtId,\n\t\t\t'critiques',\n\t\t\tsessionId\n\t\t);\n\t}\n\n\tprivate _emitSynthesisEdges(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tlet emitted = false;\n\t\tfor (const srcId of references.synthesisSourceThoughtIds ?? []) {\n\t\t\temitted = this._addEdgeIfValid(srcId, thought.id, 'derives_from', sessionId) || emitted;\n\t\t}\n\t\treturn emitted;\n\t}\n\n\tprivate _emitRevisionEdge(\n\t\tthought: ThoughtData,\n\t\treferences: ResolvedThoughtReferences,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tif (thought.revises_thought === undefined) return false;\n\n\t\treturn this._addEdgeIfValid(thought.id, references.revisesThoughtId, 'revises', sessionId);\n\t}\n\n\tprivate _emitToolInvocationEdge(\n\t\tthought: ThoughtData,\n\t\tsessionId: SessionId,\n\t\tcontext?: ThoughtAdmissionContext\n\t): boolean {\n\t\tif (\n\t\t\tthought.thought_type !== 'tool_observation' ||\n\t\t\tcontext?.toolInvocationSourceThoughtId === undefined\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst metadata = thought.tool_name !== undefined ? { tool_name: thought.tool_name } : undefined;\n\t\treturn this._addEdgeIfValid(\n\t\t\tcontext.toolInvocationSourceThoughtId,\n\t\t\tthought.id,\n\t\t\t'tool_invocation',\n\t\t\tsessionId,\n\t\t\tmetadata\n\t\t);\n\t}\n\n\tprivate _emitSequenceEdge(\n\t\tsession: EdgeEmissionSession,\n\t\tthought: ThoughtData,\n\t\tsessionId: SessionId\n\t): boolean {\n\t\tconst history = session.thought_history;\n\t\tif (history.length < 2) return false;\n\n\t\tconst prev = history[history.length - 2];\n\t\tif (!prev?.id) return false;\n\n\t\treturn this._addEdgeIfValid(prev.id, thought.id, 'sequence', sessionId);\n\t}\n\n\t/**\n\t * Adds an edge to the edge store if both endpoints are non-empty strings.\n\t * Returns true if added, false if skipped (missing endpoint).\n\t * Failures (e.g. self-edge) are caught and logged.\n\t */\n\tprivate _addEdgeIfValid(\n\t\tfrom: ThoughtId | undefined,\n\t\tto: ThoughtId | undefined,\n\t\tkind: EdgeKind,\n\t\tsessionId: SessionId,\n\t\tmetadata?: Record<string, unknown>\n\t): boolean {\n\t\tif (!from || !to) {\n\t\t\tthis._logger.debug('Skipping edge: unresolved endpoint', {\n\t\t\t\tkind,\n\t\t\t\tfrom: from ?? null,\n\t\t\t\tto: to ?? null,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t\tconst edge: Edge = {\n\t\t\tid: generateEdgeId(),\n\t\t\tfrom: from as Edge['from'],\n\t\t\tto: to as Edge['to'],\n\t\t\tkind,\n\t\t\tsessionId: sessionId as Edge['sessionId'],\n\t\t\tcreatedAt: Date.now(),\n\t\t\t...(metadata !== undefined ? { metadata } : {}),\n\t\t};\n\t\tif (!this._edgeStore) {\n\t\t\tthis._logger.warn('EdgeStore not available; skipping edge', { kind });\n\t\t\treturn false;\n\t\t}\n\t\tconst duplicate = this._edgeStore\n\t\t\t.edgesForSession(sessionId)\n\t\t\t.some((existing) => existing.kind === kind && existing.from === from && existing.to === to);\n\t\tif (duplicate) return false;\n\t\ttry {\n\t\t\tthis._edgeStore.addEdge(edge);\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tthis._logger.info('Failed to add DAG edge', {\n\t\t\t\tkind,\n\t\t\t\terror: getErrorMessage(err),\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"],"names":["EdgeEmitter","config","NullLogger","undefined","session","thought","context","sessionId","references","hasRelationalIntent","emittedRelational","emitted","srcId","resolvedVerificationTarget","metadata","history","prev","from","to","kind","edge","generateEdgeId","Date","duplicate","existing","err","getErrorMessage"],"mappings":";;;;AAyCO,MAAMA;IACK,WAAwB;IACxB,UAAmB;IACnB,QAAgB;IAEjC,YAAYC,MAAyB,CAAE;QACtC,IAAI,CAAC,UAAU,GAAGA,OAAO,SAAS;QAClC,IAAI,CAAC,SAAS,GAAGA,OAAO,QAAQ;QAChC,IAAI,CAAC,OAAO,GAAGA,OAAO,MAAM,IAAI,IAAIC;IACrC;IAGO,YAAqB;QAC3B,OAAO,AAAoBC,WAApB,IAAI,CAAC,UAAU,IAAkB,IAAI,CAAC,SAAS;IACvD;IAgBO,oBACNC,OAA4B,EAC5BC,OAAoB,EACpBC,OAAiC,EACvB;QACV,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO;QAChD,IAAI,CAACD,QAAQ,EAAE,EAAE,OAAO;QAExB,MAAME,YAAYF,QAAQ,UAAU;QACpC,MAAMG,aAAaF,SAAS,sBAAsB,CAAC;QACnD,MAAMG,sBACJJ,AAAgCF,WAAhCE,QAAQ,mBAAmB,IAAkBA,AAAsBF,WAAtBE,QAAQ,SAAS,IAC9DA,AAAAA,CAAAA,QAAQ,mBAAmB,EAAE,UAAU,KAAK,KAC5CA,AAAgCF,WAAhCE,QAAQ,mBAAmB,IAC1BA,CAAAA,AAAyB,mBAAzBA,QAAQ,YAAY,IAAuBA,AAAyB,eAAzBA,QAAQ,YAAY,AAAc,KAC9EA,AAAAA,CAAAA,QAAQ,iBAAiB,EAAE,UAAU,KAAK,KAC3CA,AAA4BF,WAA5BE,QAAQ,eAAe,IACtBA,AAAyB,uBAAzBA,QAAQ,YAAY,IACpBC,SAAS,kCAAkCH;QAC7C,MAAMO,oBAAoB;YACzB,IAAI,CAAC,eAAe,CAACL,SAASG,YAAYD;YAC1C,IAAI,CAAC,eAAe,CAACF,SAASG,YAAYD;YAC1C,IAAI,CAAC,qBAAqB,CAACF,SAASG,YAAYD;YAChD,IAAI,CAAC,iBAAiB,CAACF,SAASG,YAAYD;YAC5C,IAAI,CAAC,mBAAmB,CAACF,SAASG,YAAYD;YAC9C,IAAI,CAAC,iBAAiB,CAACF,SAASG,YAAYD;YAC5C,IAAI,CAAC,uBAAuB,CAACF,SAASE,WAAWD;SACjD,CAAC,IAAI,CAAC,CAACK,UAAYA;QAEpB,IAAID,qBAAqBD,qBAAqB,OAAOC;QACrD,OAAO,IAAI,CAAC,iBAAiB,CAACN,SAASC,SAASE;IACjD;IAEQ,gBACPF,OAAoB,EACpBG,UAAqC,EACrCD,SAAoB,EACV;QACV,IAAIF,AAAgCF,WAAhCE,QAAQ,mBAAmB,IAAkB,CAACA,QAAQ,SAAS,EAAE,OAAO;QAE5E,OAAO,IAAI,CAAC,eAAe,CAACG,WAAW,mBAAmB,EAAEH,QAAQ,EAAE,EAAE,UAAUE;IACnF;IAEQ,gBACPF,OAAoB,EACpBG,UAAqC,EACrCD,SAAoB,EACV;QACV,IAAII,UAAU;QACd,KAAK,MAAMC,SAASJ,WAAW,mBAAmB,IAAI,EAAE,CACvDG,UAAU,IAAI,CAAC,eAAe,CAACC,OAAOP,QAAQ,EAAE,EAAE,SAASE,cAAcI;QAE1E,OAAOA;IACR;IAEQ,sBACPN,OAAoB,EACpBG,UAAqC,EACrCD,SAAoB,EACV;QACV,IAAIF,AAAgCF,WAAhCE,QAAQ,mBAAmB,IAAkBA,AAAyB,mBAAzBA,QAAQ,YAAY,EACpE,OAAO;QAER,OAAO,IAAI,CAAC,eAAe,CAC1BA,QAAQ,EAAE,EACVQ,2BAA2BR,SAASG,aACpC,YACAD;IAEF;IAEQ,kBACPF,OAAoB,EACpBG,UAAqC,EACrCD,SAAoB,EACV;QACV,IAAIF,AAAgCF,WAAhCE,QAAQ,mBAAmB,IAAkBA,AAAyB,eAAzBA,QAAQ,YAAY,EACpE,OAAO;QAER,OAAO,IAAI,CAAC,eAAe,CAC1BA,QAAQ,EAAE,EACVG,WAAW,2BAA2B,EACtC,aACAD;IAEF;IAEQ,oBACPF,OAAoB,EACpBG,UAAqC,EACrCD,SAAoB,EACV;QACV,IAAII,UAAU;QACd,KAAK,MAAMC,SAASJ,WAAW,yBAAyB,IAAI,EAAE,CAC7DG,UAAU,IAAI,CAAC,eAAe,CAACC,OAAOP,QAAQ,EAAE,EAAE,gBAAgBE,cAAcI;QAEjF,OAAOA;IACR;IAEQ,kBACPN,OAAoB,EACpBG,UAAqC,EACrCD,SAAoB,EACV;QACV,IAAIF,AAA4BF,WAA5BE,QAAQ,eAAe,EAAgB,OAAO;QAElD,OAAO,IAAI,CAAC,eAAe,CAACA,QAAQ,EAAE,EAAEG,WAAW,gBAAgB,EAAE,WAAWD;IACjF;IAEQ,wBACPF,OAAoB,EACpBE,SAAoB,EACpBD,OAAiC,EACvB;QACV,IACCD,AAAyB,uBAAzBA,QAAQ,YAAY,IACpBC,SAAS,kCAAkCH,QAE3C,OAAO;QAGR,MAAMW,WAAWT,AAAsBF,WAAtBE,QAAQ,SAAS,GAAiB;YAAE,WAAWA,QAAQ,SAAS;QAAC,IAAIF;QACtF,OAAO,IAAI,CAAC,eAAe,CAC1BG,QAAQ,6BAA6B,EACrCD,QAAQ,EAAE,EACV,mBACAE,WACAO;IAEF;IAEQ,kBACPV,OAA4B,EAC5BC,OAAoB,EACpBE,SAAoB,EACV;QACV,MAAMQ,UAAUX,QAAQ,eAAe;QACvC,IAAIW,QAAQ,MAAM,GAAG,GAAG,OAAO;QAE/B,MAAMC,OAAOD,OAAO,CAACA,QAAQ,MAAM,GAAG,EAAE;QACxC,IAAI,CAACC,MAAM,IAAI,OAAO;QAEtB,OAAO,IAAI,CAAC,eAAe,CAACA,KAAK,EAAE,EAAEX,QAAQ,EAAE,EAAE,YAAYE;IAC9D;IAOQ,gBACPU,IAA2B,EAC3BC,EAAyB,EACzBC,IAAc,EACdZ,SAAoB,EACpBO,QAAkC,EACxB;QACV,IAAI,CAACG,QAAQ,CAACC,IAAI;YACjB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,sCAAsC;gBACxDC;gBACA,MAAMF,QAAQ;gBACd,IAAIC,MAAM;YACX;YACA,OAAO;QACR;QACA,MAAME,OAAa;YAClB,IAAIC;YACJ,MAAMJ;YACN,IAAIC;YACJC;YACA,WAAWZ;YACX,WAAWe,KAAK,GAAG;YACnB,GAAIR,AAAaX,WAAbW,WAAyB;gBAAEA;YAAS,IAAI,CAAC,CAAC;QAC/C;QACA,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;YACrB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,0CAA0C;gBAAEK;YAAK;YACnE,OAAO;QACR;QACA,MAAMI,YAAY,IAAI,CAAC,UAAU,CAC/B,eAAe,CAAChB,WAChB,IAAI,CAAC,CAACiB,WAAaA,SAAS,IAAI,KAAKL,QAAQK,SAAS,IAAI,KAAKP,QAAQO,SAAS,EAAE,KAAKN;QACzF,IAAIK,WAAW,OAAO;QACtB,IAAI;YACH,IAAI,CAAC,UAAU,CAAC,OAAO,CAACH;YACxB,OAAO;QACR,EAAE,OAAOK,KAAK;YACb,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,0BAA0B;gBAC3CN;gBACA,OAAOO,gBAAgBD;YACxB;YACA,OAAO;QACR;IACD;AACD"}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @module core/graph/GraphView
|
|
14
14
|
*/
|
|
15
|
-
import type {
|
|
15
|
+
import type { IGraphViewStore } from '../../contracts/interfaces.js';
|
|
16
16
|
import type { SessionId, ThoughtId } from '../../contracts/ids.js';
|
|
17
17
|
/**
|
|
18
18
|
* Read-only traversal queries over an {@link IEdgeStore}.
|
|
@@ -37,7 +37,7 @@ export declare class GraphView {
|
|
|
37
37
|
* const view = new GraphView(edgeStore);
|
|
38
38
|
* ```
|
|
39
39
|
*/
|
|
40
|
-
constructor(store:
|
|
40
|
+
constructor(store: IGraphViewStore);
|
|
41
41
|
/**
|
|
42
42
|
* Return all thought ids in the session, ordered by BFS from roots.
|
|
43
43
|
*
|
|
@@ -57,9 +57,9 @@ export declare class GraphView {
|
|
|
57
57
|
/**
|
|
58
58
|
* Return the shortest directed distance from any retained root to a thought.
|
|
59
59
|
*
|
|
60
|
-
* Nodes are derived from
|
|
61
|
-
*
|
|
62
|
-
* kind participates in the traversal.
|
|
60
|
+
* Nodes are derived from edges unless an immutable snapshot supplies original
|
|
61
|
+
* endpoint nodes. Thoughts never referenced by an audit edge remain invisible.
|
|
62
|
+
* Every edge kind participates in the traversal.
|
|
63
63
|
*
|
|
64
64
|
* @param sessionId - Session to query
|
|
65
65
|
* @param thoughtId - Thought whose root distance to resolve
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GraphView.d.ts","sourceRoot":"","sources":["../../../src/core/graph/GraphView.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"GraphView.d.ts","sourceRoot":"","sources":["../../../src/core/graph/GraphView.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAInE;;;;;;;;;;GAUG;AACH,qBAAa,SAAS;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IAEzC;;;;;;;;;OASG;gBACS,KAAK,EAAE,eAAe;IAIlC;;;;;;;;;;;;;;OAcG;IACH,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IAWzD;;;;;;;;;;OAUG;IACH,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS;IAqC9E;;;;;;;;;;;;;;;OAeG;IACH,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IAkBpF;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IA0BvD;;;;;;;;;;;;;;OAcG;IACH,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE;IAI9F;;;;;;;;;;;;;;OAcG;IACH,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE;IAIhG;;;;;;;;;;OAUG;IACH,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IAalD;;;OAGG;IACH,OAAO,CAAC,aAAa;IAiBrB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAmBlB;;OAEG;IACH,OAAO,CAAC,aAAa;IAsBrB;;OAEG;IACH,OAAO,CAAC,cAAc;IAatB;;;OAGG;IACH,OAAO,CAAC,WAAW;CA+BnB"}
|
|
@@ -6,15 +6,14 @@ class GraphView {
|
|
|
6
6
|
}
|
|
7
7
|
chronological(sessionId) {
|
|
8
8
|
const edges = this._store.edgesForSession(sessionId);
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const { nodes, hasIncoming } = this._collectNodes(edges, this._store.nodesForSession?.(sessionId));
|
|
10
|
+
if (0 === nodes.size) return [];
|
|
11
11
|
const roots = this._findRoots(nodes, hasIncoming, edges);
|
|
12
12
|
return this._bfsFromRoots(sessionId, roots);
|
|
13
13
|
}
|
|
14
14
|
depthFromRoots(sessionId, thoughtId) {
|
|
15
15
|
const edges = this._store.edgesForSession(sessionId);
|
|
16
|
-
|
|
17
|
-
const nodes = new Set();
|
|
16
|
+
const nodes = new Set(this._store.nodesForSession?.(sessionId) ?? []);
|
|
18
17
|
const hasIncoming = new Set();
|
|
19
18
|
const outgoing = new Map();
|
|
20
19
|
for (const edge of edges){
|
|
@@ -70,8 +69,8 @@ class GraphView {
|
|
|
70
69
|
}
|
|
71
70
|
topological(sessionId) {
|
|
72
71
|
const edges = this._store.edgesForSession(sessionId);
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
const inDegree = this._buildInDegree(edges, this._store.nodesForSession?.(sessionId));
|
|
73
|
+
if (0 === inDegree.size) return [];
|
|
75
74
|
const queue = [];
|
|
76
75
|
for (const [node, deg] of inDegree)if (0 === deg) queue.push(node);
|
|
77
76
|
const order = [];
|
|
@@ -95,14 +94,14 @@ class GraphView {
|
|
|
95
94
|
}
|
|
96
95
|
leaves(sessionId) {
|
|
97
96
|
const edges = this._store.edgesForSession(sessionId);
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
const { nodes } = this._collectNodes(edges, this._store.nodesForSession?.(sessionId));
|
|
98
|
+
if (0 === nodes.size) return [];
|
|
100
99
|
const result = [];
|
|
101
100
|
for (const node of nodes)if (0 === this._store.outgoing(sessionId, node).length) result.push(node);
|
|
102
101
|
return result;
|
|
103
102
|
}
|
|
104
|
-
_collectNodes(edges) {
|
|
105
|
-
const nodes = new Set();
|
|
103
|
+
_collectNodes(edges, explicitNodes = []) {
|
|
104
|
+
const nodes = new Set(explicitNodes);
|
|
106
105
|
const hasIncoming = new Set();
|
|
107
106
|
for (const edge of edges){
|
|
108
107
|
nodes.add(edge.from);
|
|
@@ -141,8 +140,9 @@ class GraphView {
|
|
|
141
140
|
}
|
|
142
141
|
return order;
|
|
143
142
|
}
|
|
144
|
-
_buildInDegree(edges) {
|
|
143
|
+
_buildInDegree(edges, explicitNodes = []) {
|
|
145
144
|
const inDegree = new Map();
|
|
145
|
+
for (const node of explicitNodes)inDegree.set(node, 0);
|
|
146
146
|
for (const edge of edges){
|
|
147
147
|
if (!inDegree.has(edge.from)) inDegree.set(edge.from, 0);
|
|
148
148
|
inDegree.set(edge.to, (inDegree.get(edge.to) ?? 0) + 1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/graph/GraphView.js","sources":["../../../src/core/graph/GraphView.ts"],"sourcesContent":["/**\n * GraphView — read-only graph traversal queries over an {@link IEdgeStore}.\n *\n * Provides BFS / topological / ancestor / descendant queries over the\n * thought DAG. Queries return thought ids or graph distances,\n * never `ThoughtData` objects — the view is intentionally decoupled from\n * `HistoryManager` so it can be reused by strategies that work purely in\n * terms of graph structure.\n *\n * Construction is cheap (stores a reference to the underlying store).\n * Each query reads the latest store state — no caching, no snapshots.\n *\n * @module core/graph/GraphView\n */\n\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport type { SessionId, ThoughtId } from '../../contracts/ids.js';\nimport { CycleDetectedError } from '../../errors.js';\nimport type { Edge } from './Edge.js';\n\n/**\n * Read-only traversal queries over an {@link IEdgeStore}.\n *\n * @example\n * ```typescript\n * const store = new EdgeStore();\n * // ... populate store ...\n * const view = new GraphView(store);\n * const order = view.topological('s1');\n * ```\n */\nexport class GraphView {\n\tprivate readonly _store: IEdgeStore;\n\n\t/**\n\t * Create a new GraphView backed by the given edge store.\n\t *\n\t * @param store - The edge store to query (held by reference, read-only access)\n\t *\n\t * @example\n\t * ```typescript\n\t * const view = new GraphView(edgeStore);\n\t * ```\n\t */\n\tconstructor(store: IEdgeStore) {\n\t\tthis._store = store;\n\t}\n\n\t/**\n\t * Return all thought ids in the session, ordered by BFS from roots.\n\t *\n\t * Roots are nodes with no incoming edges. Within a layer, neighbours\n\t * are visited in `outgoing` order (which the underlying store keeps\n\t * sorted by `createdAt` ascending).\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Thought ids in chronological BFS order\n\t *\n\t * @example\n\t * ```typescript\n\t * const ids = view.chronological('s1');\n\t * ```\n\t */\n\tchronological(sessionId: SessionId): readonly ThoughtId[] {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tif (edges.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst { nodes, hasIncoming } = this._collectNodes(edges);\n\t\tconst roots = this._findRoots(nodes, hasIncoming, edges);\n\t\treturn this._bfsFromRoots(sessionId, roots) as readonly ThoughtId[];\n\t}\n\n\t/**\n\t * Return the shortest directed distance from any retained root to a thought.\n\t *\n\t * Nodes are derived from the current edge store, so isolated thoughts are\n\t * invisible and pruning can expose a retained node as a new root. Every edge\n\t * kind participates in the traversal.\n\t *\n\t * @param sessionId - Session to query\n\t * @param thoughtId - Thought whose root distance to resolve\n\t * @returns Zero for a root, or `undefined` when no root can reach the thought\n\t */\n\tdepthFromRoots(sessionId: SessionId, thoughtId: ThoughtId): number | undefined {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tif (edges.length === 0) return undefined;\n\n\t\tconst nodes = new Set<ThoughtId>();\n\t\tconst hasIncoming = new Set<ThoughtId>();\n\t\tconst outgoing = new Map<ThoughtId, ThoughtId[]>();\n\t\tfor (const edge of edges) {\n\t\t\tnodes.add(edge.from);\n\t\t\tnodes.add(edge.to);\n\t\t\thasIncoming.add(edge.to);\n\t\t\tconst children = outgoing.get(edge.from);\n\t\t\tif (children === undefined) outgoing.set(edge.from, [edge.to]);\n\t\t\telse children.push(edge.to);\n\t\t}\n\t\tif (!nodes.has(thoughtId)) return undefined;\n\n\t\tlet frontier: ThoughtId[] = [];\n\t\tfor (const node of nodes) {\n\t\t\tif (!hasIncoming.has(node)) frontier.push(node);\n\t\t}\n\t\tconst visited = new Set<ThoughtId>(frontier);\n\t\tlet depth = 0;\n\t\twhile (frontier.length > 0) {\n\t\t\tconst next: ThoughtId[] = [];\n\t\t\tfor (const node of frontier) {\n\t\t\t\tif (node === thoughtId) return depth;\n\t\t\t\tfor (const child of outgoing.get(node) ?? []) {\n\t\t\t\t\tif (visited.has(child)) continue;\n\t\t\t\t\tvisited.add(child);\n\t\t\t\t\tnext.push(child);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfrontier = next;\n\t\t\tdepth++;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Return all thought ids reachable from `rootThoughtId` via `'branch'`\n\t * edges, including the root itself.\n\t *\n\t * Non-branch edges are ignored. Cycles (if any) do not cause infinite\n\t * loops because each node is visited at most once.\n\t *\n\t * @param sessionId - Session to query\n\t * @param rootThoughtId - The starting thought id (typically the branch root)\n\t * @returns Thought ids forming the branch (includes root)\n\t *\n\t * @example\n\t * ```typescript\n\t * const branchIds = view.branchThoughts('s1', 'thought-root');\n\t * ```\n\t */\n\tbranchThoughts(sessionId: SessionId, rootThoughtId: ThoughtId): readonly ThoughtId[] {\n\t\tconst visited = new Set<string>([rootThoughtId]);\n\t\tconst order: string[] = [rootThoughtId];\n\t\tconst queue: string[] = [rootThoughtId];\n\t\twhile (queue.length > 0) {\n\t\t\tconst current = queue.shift()!;\n\t\t\tconst out = this._store.outgoing(sessionId, current as ThoughtId);\n\t\t\tfor (const edge of out) {\n\t\t\t\tif (edge.kind !== 'branch') continue;\n\t\t\t\tif (visited.has(edge.to)) continue;\n\t\t\t\tvisited.add(edge.to);\n\t\t\t\torder.push(edge.to);\n\t\t\t\tqueue.push(edge.to);\n\t\t\t}\n\t\t}\n\t\treturn order as ThoughtId[];\n\t}\n\n\t/**\n\t * Return a topological ordering of all thought ids in the session\n\t * using Kahn's algorithm.\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Thought ids in topological order\n\t * @throws {CycleDetectedError} If the graph contains a cycle\n\t *\n\t * @example\n\t * ```typescript\n\t * const order = view.topological('s1');\n\t * ```\n\t */\n\ttopological(sessionId: SessionId): readonly ThoughtId[] {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tif (edges.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst inDegree = this._buildInDegree(edges);\n\t\tconst queue: string[] = [];\n\t\tfor (const [node, deg] of inDegree) {\n\t\t\tif (deg === 0) queue.push(node);\n\t\t}\n\t\tconst order: string[] = [];\n\t\twhile (queue.length > 0) {\n\t\t\tconst node = queue.shift()!;\n\t\t\torder.push(node);\n\t\t\tfor (const edge of this._store.outgoing(sessionId, node as ThoughtId)) {\n\t\t\t\tconst next = (inDegree.get(edge.to) ?? 0) - 1;\n\t\t\t\tinDegree.set(edge.to, next);\n\t\t\t\tif (next === 0) queue.push(edge.to);\n\t\t\t}\n\t\t}\n\t\tif (order.length !== inDegree.size) {\n\t\t\tthrow new CycleDetectedError(\n\t\t\t\t`Cycle detected in session '${sessionId}': topological sort incomplete (${order.length}/${inDegree.size})`\n\t\t\t);\n\t\t}\n\t\treturn order as ThoughtId[];\n\t}\n\n\t/**\n\t * Return all ancestors of `thoughtId` via incoming-edge BFS.\n\t *\n\t * The starting node is NOT included. Cycles do not cause infinite loops.\n\t *\n\t * @param sessionId - Session to query\n\t * @param thoughtId - The thought to traverse from\n\t * @param maxDepth - Optional maximum traversal depth (1 = direct parents only)\n\t * @returns Ancestor thought ids in BFS order\n\t *\n\t * @example\n\t * ```typescript\n\t * const parents = view.ancestors('s1', 'thought-id', 1);\n\t * ```\n\t */\n\tancestors(sessionId: SessionId, thoughtId: ThoughtId, maxDepth?: number): readonly ThoughtId[] {\n\t\treturn this._bfsClosure(sessionId, thoughtId, maxDepth, 'incoming') as readonly ThoughtId[];\n\t}\n\n\t/**\n\t * Return all descendants of `thoughtId` via outgoing-edge BFS.\n\t *\n\t * The starting node is NOT included. Cycles do not cause infinite loops.\n\t *\n\t * @param sessionId - Session to query\n\t * @param thoughtId - The thought to traverse from\n\t * @param maxDepth - Optional maximum traversal depth (1 = direct children only)\n\t * @returns Descendant thought ids in BFS order\n\t *\n\t * @example\n\t * ```typescript\n\t * const children = view.descendants('s1', 'thought-id');\n\t * ```\n\t */\n\tdescendants(sessionId: SessionId, thoughtId: ThoughtId, maxDepth?: number): readonly ThoughtId[] {\n\t\treturn this._bfsClosure(sessionId, thoughtId, maxDepth, 'outgoing') as readonly ThoughtId[];\n\t}\n\n\t/**\n\t * Return all thought ids in the session that have no outgoing edges.\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Thought ids that are graph leaves\n\t *\n\t * @example\n\t * ```typescript\n\t * const tips = view.leaves('s1');\n\t * ```\n\t */\n\tleaves(sessionId: SessionId): readonly ThoughtId[] {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tif (edges.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst { nodes } = this._collectNodes(edges);\n\t\tconst result: string[] = [];\n\t\tfor (const node of nodes) {\n\t\t\tif (this._store.outgoing(sessionId, node as ThoughtId).length === 0) {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t}\n\t\treturn result as ThoughtId[];\n\t}\n\n\t/**\n\t * Collect every node id referenced by the edges and a set of nodes\n\t * that have at least one incoming edge.\n\t */\n\tprivate _collectNodes(edges: readonly Edge[]): {\n\t\tnodes: Set<string>;\n\t\thasIncoming: Set<string>;\n\t} {\n\t\tconst nodes = new Set<string>();\n\t\tconst hasIncoming = new Set<string>();\n\t\tfor (const edge of edges) {\n\t\t\tnodes.add(edge.from);\n\t\t\tnodes.add(edge.to);\n\t\t\thasIncoming.add(edge.to);\n\t\t}\n\t\treturn { nodes, hasIncoming };\n\t}\n\n\t/**\n\t * Find roots (no incoming) ordered by the earliest outgoing edge\n\t * `createdAt`. Nodes with no outgoing edges fall back to the order\n\t * they appear among edges (already sorted by `createdAt`).\n\t */\n\tprivate _findRoots(\n\t\tnodes: Set<string>,\n\t\thasIncoming: Set<string>,\n\t\tedges: readonly Edge[]\n\t): string[] {\n\t\tconst earliest = new Map<string, number>();\n\t\tfor (const edge of edges) {\n\t\t\tif (!earliest.has(edge.from)) {\n\t\t\t\tearliest.set(edge.from, edge.createdAt);\n\t\t\t}\n\t\t}\n\t\tconst roots: string[] = [];\n\t\tfor (const node of nodes) {\n\t\t\tif (!hasIncoming.has(node)) roots.push(node);\n\t\t}\n\t\troots.sort((a, b) => (earliest.get(a) ?? Infinity) - (earliest.get(b) ?? Infinity));\n\t\treturn roots;\n\t}\n\n\t/**\n\t * BFS from a list of root ids, visiting each node at most once.\n\t */\n\tprivate _bfsFromRoots(sessionId: SessionId, roots: readonly string[]): readonly string[] {\n\t\tconst visited = new Set<string>();\n\t\tconst order: string[] = [];\n\t\tconst queue: string[] = [];\n\t\tfor (const root of roots) {\n\t\t\tif (visited.has(root)) continue;\n\t\t\tvisited.add(root);\n\t\t\torder.push(root);\n\t\t\tqueue.push(root);\n\t\t}\n\t\twhile (queue.length > 0) {\n\t\t\tconst node = queue.shift()!;\n\t\t\tfor (const edge of this._store.outgoing(sessionId, node as ThoughtId)) {\n\t\t\t\tif (visited.has(edge.to)) continue;\n\t\t\t\tvisited.add(edge.to);\n\t\t\t\torder.push(edge.to);\n\t\t\t\tqueue.push(edge.to);\n\t\t\t}\n\t\t}\n\t\treturn order;\n\t}\n\n\t/**\n\t * Build an in-degree map covering every node referenced by the edges.\n\t */\n\tprivate _buildInDegree(edges: readonly Edge[]): Map<string, number> {\n\t\tconst inDegree = new Map<string, number>();\n\t\tfor (const edge of edges) {\n\t\t\tif (!inDegree.has(edge.from)) inDegree.set(edge.from, 0);\n\t\t\tinDegree.set(edge.to, (inDegree.get(edge.to) ?? 0) + 1);\n\t\t}\n\t\treturn inDegree;\n\t}\n\n\t/**\n\t * Generic BFS closure in either direction. Excludes the start node\n\t * from the result and respects an optional depth cap.\n\t */\n\tprivate _bfsClosure(\n\t\tsessionId: SessionId,\n\t\tstartId: string,\n\t\tmaxDepth: number | undefined,\n\t\tdirection: 'incoming' | 'outgoing'\n\t): readonly string[] {\n\t\tconst cap = maxDepth ?? Number.POSITIVE_INFINITY;\n\t\tconst visited = new Set<string>([startId]);\n\t\tconst order: string[] = [];\n\t\tlet frontier: string[] = [startId];\n\t\tlet depth = 0;\n\t\twhile (frontier.length > 0 && depth < cap) {\n\t\t\tconst next: string[] = [];\n\t\t\tfor (const node of frontier) {\n\t\t\t\tconst edges =\n\t\t\t\t\tdirection === 'outgoing'\n\t\t\t\t\t\t? this._store.outgoing(sessionId, node as ThoughtId)\n\t\t\t\t\t\t: this._store.incoming(sessionId, node as ThoughtId);\n\t\t\t\tfor (const edge of edges) {\n\t\t\t\t\tconst neighbour = direction === 'outgoing' ? edge.to : edge.from;\n\t\t\t\t\tif (visited.has(neighbour)) continue;\n\t\t\t\t\tvisited.add(neighbour);\n\t\t\t\t\torder.push(neighbour);\n\t\t\t\t\tnext.push(neighbour);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfrontier = next;\n\t\t\tdepth++;\n\t\t}\n\t\treturn order;\n\t}\n}\n"],"names":["GraphView","store","sessionId","edges","nodes","hasIncoming","roots","thoughtId","Set","outgoing","Map","edge","children","undefined","frontier","node","visited","depth","next","child","rootThoughtId","order","queue","current","out","inDegree","deg","CycleDetectedError","maxDepth","result","earliest","a","b","Infinity","root","startId","direction","cap","Number","neighbour"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core/graph/GraphView.js","sources":["../../../src/core/graph/GraphView.ts"],"sourcesContent":["/**\n * GraphView — read-only graph traversal queries over an {@link IEdgeStore}.\n *\n * Provides BFS / topological / ancestor / descendant queries over the\n * thought DAG. Queries return thought ids or graph distances,\n * never `ThoughtData` objects — the view is intentionally decoupled from\n * `HistoryManager` so it can be reused by strategies that work purely in\n * terms of graph structure.\n *\n * Construction is cheap (stores a reference to the underlying store).\n * Each query reads the latest store state — no caching, no snapshots.\n *\n * @module core/graph/GraphView\n */\n\nimport type { IGraphViewStore } from '../../contracts/interfaces.js';\nimport type { SessionId, ThoughtId } from '../../contracts/ids.js';\nimport { CycleDetectedError } from '../../errors.js';\nimport type { Edge } from './Edge.js';\n\n/**\n * Read-only traversal queries over an {@link IEdgeStore}.\n *\n * @example\n * ```typescript\n * const store = new EdgeStore();\n * // ... populate store ...\n * const view = new GraphView(store);\n * const order = view.topological('s1');\n * ```\n */\nexport class GraphView {\n\tprivate readonly _store: IGraphViewStore;\n\n\t/**\n\t * Create a new GraphView backed by the given edge store.\n\t *\n\t * @param store - The edge store to query (held by reference, read-only access)\n\t *\n\t * @example\n\t * ```typescript\n\t * const view = new GraphView(edgeStore);\n\t * ```\n\t */\n\tconstructor(store: IGraphViewStore) {\n\t\tthis._store = store;\n\t}\n\n\t/**\n\t * Return all thought ids in the session, ordered by BFS from roots.\n\t *\n\t * Roots are nodes with no incoming edges. Within a layer, neighbours\n\t * are visited in `outgoing` order (which the underlying store keeps\n\t * sorted by `createdAt` ascending).\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Thought ids in chronological BFS order\n\t *\n\t * @example\n\t * ```typescript\n\t * const ids = view.chronological('s1');\n\t * ```\n\t */\n\tchronological(sessionId: SessionId): readonly ThoughtId[] {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tconst { nodes, hasIncoming } = this._collectNodes(\n\t\t\tedges,\n\t\t\tthis._store.nodesForSession?.(sessionId)\n\t\t);\n\t\tif (nodes.size === 0) return [];\n\t\tconst roots = this._findRoots(nodes, hasIncoming, edges);\n\t\treturn this._bfsFromRoots(sessionId, roots) as readonly ThoughtId[];\n\t}\n\n\t/**\n\t * Return the shortest directed distance from any retained root to a thought.\n\t *\n\t * Nodes are derived from edges unless an immutable snapshot supplies original\n\t * endpoint nodes. Thoughts never referenced by an audit edge remain invisible.\n\t * Every edge kind participates in the traversal.\n\t *\n\t * @param sessionId - Session to query\n\t * @param thoughtId - Thought whose root distance to resolve\n\t * @returns Zero for a root, or `undefined` when no root can reach the thought\n\t */\n\tdepthFromRoots(sessionId: SessionId, thoughtId: ThoughtId): number | undefined {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tconst nodes = new Set<ThoughtId>(this._store.nodesForSession?.(sessionId) ?? []);\n\t\tconst hasIncoming = new Set<ThoughtId>();\n\t\tconst outgoing = new Map<ThoughtId, ThoughtId[]>();\n\t\tfor (const edge of edges) {\n\t\t\tnodes.add(edge.from);\n\t\t\tnodes.add(edge.to);\n\t\t\thasIncoming.add(edge.to);\n\t\t\tconst children = outgoing.get(edge.from);\n\t\t\tif (children === undefined) outgoing.set(edge.from, [edge.to]);\n\t\t\telse children.push(edge.to);\n\t\t}\n\t\tif (!nodes.has(thoughtId)) return undefined;\n\n\t\tlet frontier: ThoughtId[] = [];\n\t\tfor (const node of nodes) {\n\t\t\tif (!hasIncoming.has(node)) frontier.push(node);\n\t\t}\n\t\tconst visited = new Set<ThoughtId>(frontier);\n\t\tlet depth = 0;\n\t\twhile (frontier.length > 0) {\n\t\t\tconst next: ThoughtId[] = [];\n\t\t\tfor (const node of frontier) {\n\t\t\t\tif (node === thoughtId) return depth;\n\t\t\t\tfor (const child of outgoing.get(node) ?? []) {\n\t\t\t\t\tif (visited.has(child)) continue;\n\t\t\t\t\tvisited.add(child);\n\t\t\t\t\tnext.push(child);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfrontier = next;\n\t\t\tdepth++;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Return all thought ids reachable from `rootThoughtId` via `'branch'`\n\t * edges, including the root itself.\n\t *\n\t * Non-branch edges are ignored. Cycles (if any) do not cause infinite\n\t * loops because each node is visited at most once.\n\t *\n\t * @param sessionId - Session to query\n\t * @param rootThoughtId - The starting thought id (typically the branch root)\n\t * @returns Thought ids forming the branch (includes root)\n\t *\n\t * @example\n\t * ```typescript\n\t * const branchIds = view.branchThoughts('s1', 'thought-root');\n\t * ```\n\t */\n\tbranchThoughts(sessionId: SessionId, rootThoughtId: ThoughtId): readonly ThoughtId[] {\n\t\tconst visited = new Set<string>([rootThoughtId]);\n\t\tconst order: string[] = [rootThoughtId];\n\t\tconst queue: string[] = [rootThoughtId];\n\t\twhile (queue.length > 0) {\n\t\t\tconst current = queue.shift()!;\n\t\t\tconst out = this._store.outgoing(sessionId, current as ThoughtId);\n\t\t\tfor (const edge of out) {\n\t\t\t\tif (edge.kind !== 'branch') continue;\n\t\t\t\tif (visited.has(edge.to)) continue;\n\t\t\t\tvisited.add(edge.to);\n\t\t\t\torder.push(edge.to);\n\t\t\t\tqueue.push(edge.to);\n\t\t\t}\n\t\t}\n\t\treturn order as ThoughtId[];\n\t}\n\n\t/**\n\t * Return a topological ordering of all thought ids in the session\n\t * using Kahn's algorithm.\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Thought ids in topological order\n\t * @throws {CycleDetectedError} If the graph contains a cycle\n\t *\n\t * @example\n\t * ```typescript\n\t * const order = view.topological('s1');\n\t * ```\n\t */\n\ttopological(sessionId: SessionId): readonly ThoughtId[] {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tconst inDegree = this._buildInDegree(edges, this._store.nodesForSession?.(sessionId));\n\t\tif (inDegree.size === 0) return [];\n\t\tconst queue: string[] = [];\n\t\tfor (const [node, deg] of inDegree) {\n\t\t\tif (deg === 0) queue.push(node);\n\t\t}\n\t\tconst order: string[] = [];\n\t\twhile (queue.length > 0) {\n\t\t\tconst node = queue.shift()!;\n\t\t\torder.push(node);\n\t\t\tfor (const edge of this._store.outgoing(sessionId, node as ThoughtId)) {\n\t\t\t\tconst next = (inDegree.get(edge.to) ?? 0) - 1;\n\t\t\t\tinDegree.set(edge.to, next);\n\t\t\t\tif (next === 0) queue.push(edge.to);\n\t\t\t}\n\t\t}\n\t\tif (order.length !== inDegree.size) {\n\t\t\tthrow new CycleDetectedError(\n\t\t\t\t`Cycle detected in session '${sessionId}': topological sort incomplete (${order.length}/${inDegree.size})`\n\t\t\t);\n\t\t}\n\t\treturn order as ThoughtId[];\n\t}\n\n\t/**\n\t * Return all ancestors of `thoughtId` via incoming-edge BFS.\n\t *\n\t * The starting node is NOT included. Cycles do not cause infinite loops.\n\t *\n\t * @param sessionId - Session to query\n\t * @param thoughtId - The thought to traverse from\n\t * @param maxDepth - Optional maximum traversal depth (1 = direct parents only)\n\t * @returns Ancestor thought ids in BFS order\n\t *\n\t * @example\n\t * ```typescript\n\t * const parents = view.ancestors('s1', 'thought-id', 1);\n\t * ```\n\t */\n\tancestors(sessionId: SessionId, thoughtId: ThoughtId, maxDepth?: number): readonly ThoughtId[] {\n\t\treturn this._bfsClosure(sessionId, thoughtId, maxDepth, 'incoming') as readonly ThoughtId[];\n\t}\n\n\t/**\n\t * Return all descendants of `thoughtId` via outgoing-edge BFS.\n\t *\n\t * The starting node is NOT included. Cycles do not cause infinite loops.\n\t *\n\t * @param sessionId - Session to query\n\t * @param thoughtId - The thought to traverse from\n\t * @param maxDepth - Optional maximum traversal depth (1 = direct children only)\n\t * @returns Descendant thought ids in BFS order\n\t *\n\t * @example\n\t * ```typescript\n\t * const children = view.descendants('s1', 'thought-id');\n\t * ```\n\t */\n\tdescendants(sessionId: SessionId, thoughtId: ThoughtId, maxDepth?: number): readonly ThoughtId[] {\n\t\treturn this._bfsClosure(sessionId, thoughtId, maxDepth, 'outgoing') as readonly ThoughtId[];\n\t}\n\n\t/**\n\t * Return all thought ids in the session that have no outgoing edges.\n\t *\n\t * @param sessionId - Session to query\n\t * @returns Thought ids that are graph leaves\n\t *\n\t * @example\n\t * ```typescript\n\t * const tips = view.leaves('s1');\n\t * ```\n\t */\n\tleaves(sessionId: SessionId): readonly ThoughtId[] {\n\t\tconst edges = this._store.edgesForSession(sessionId);\n\t\tconst { nodes } = this._collectNodes(edges, this._store.nodesForSession?.(sessionId));\n\t\tif (nodes.size === 0) return [];\n\t\tconst result: string[] = [];\n\t\tfor (const node of nodes) {\n\t\t\tif (this._store.outgoing(sessionId, node as ThoughtId).length === 0) {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t}\n\t\treturn result as ThoughtId[];\n\t}\n\n\t/**\n\t * Collect every node id referenced by the edges and a set of nodes\n\t * that have at least one incoming edge.\n\t */\n\tprivate _collectNodes(\n\t\tedges: readonly Edge[],\n\t\texplicitNodes: readonly ThoughtId[] = []\n\t): {\n\t\tnodes: Set<string>;\n\t\thasIncoming: Set<string>;\n\t} {\n\t\tconst nodes = new Set<string>(explicitNodes);\n\t\tconst hasIncoming = new Set<string>();\n\t\tfor (const edge of edges) {\n\t\t\tnodes.add(edge.from);\n\t\t\tnodes.add(edge.to);\n\t\t\thasIncoming.add(edge.to);\n\t\t}\n\t\treturn { nodes, hasIncoming };\n\t}\n\n\t/**\n\t * Find roots (no incoming) ordered by the earliest outgoing edge\n\t * `createdAt`. Nodes with no outgoing edges fall back to the order\n\t * they appear among edges (already sorted by `createdAt`).\n\t */\n\tprivate _findRoots(\n\t\tnodes: Set<string>,\n\t\thasIncoming: Set<string>,\n\t\tedges: readonly Edge[]\n\t): string[] {\n\t\tconst earliest = new Map<string, number>();\n\t\tfor (const edge of edges) {\n\t\t\tif (!earliest.has(edge.from)) {\n\t\t\t\tearliest.set(edge.from, edge.createdAt);\n\t\t\t}\n\t\t}\n\t\tconst roots: string[] = [];\n\t\tfor (const node of nodes) {\n\t\t\tif (!hasIncoming.has(node)) roots.push(node);\n\t\t}\n\t\troots.sort((a, b) => (earliest.get(a) ?? Infinity) - (earliest.get(b) ?? Infinity));\n\t\treturn roots;\n\t}\n\n\t/**\n\t * BFS from a list of root ids, visiting each node at most once.\n\t */\n\tprivate _bfsFromRoots(sessionId: SessionId, roots: readonly string[]): readonly string[] {\n\t\tconst visited = new Set<string>();\n\t\tconst order: string[] = [];\n\t\tconst queue: string[] = [];\n\t\tfor (const root of roots) {\n\t\t\tif (visited.has(root)) continue;\n\t\t\tvisited.add(root);\n\t\t\torder.push(root);\n\t\t\tqueue.push(root);\n\t\t}\n\t\twhile (queue.length > 0) {\n\t\t\tconst node = queue.shift()!;\n\t\t\tfor (const edge of this._store.outgoing(sessionId, node as ThoughtId)) {\n\t\t\t\tif (visited.has(edge.to)) continue;\n\t\t\t\tvisited.add(edge.to);\n\t\t\t\torder.push(edge.to);\n\t\t\t\tqueue.push(edge.to);\n\t\t\t}\n\t\t}\n\t\treturn order;\n\t}\n\n\t/**\n\t * Build an in-degree map covering every node referenced by the edges.\n\t */\n\tprivate _buildInDegree(\n\t\tedges: readonly Edge[],\n\t\texplicitNodes: readonly ThoughtId[] = []\n\t): Map<string, number> {\n\t\tconst inDegree = new Map<string, number>();\n\t\tfor (const node of explicitNodes) inDegree.set(node, 0);\n\t\tfor (const edge of edges) {\n\t\t\tif (!inDegree.has(edge.from)) inDegree.set(edge.from, 0);\n\t\t\tinDegree.set(edge.to, (inDegree.get(edge.to) ?? 0) + 1);\n\t\t}\n\t\treturn inDegree;\n\t}\n\n\t/**\n\t * Generic BFS closure in either direction. Excludes the start node\n\t * from the result and respects an optional depth cap.\n\t */\n\tprivate _bfsClosure(\n\t\tsessionId: SessionId,\n\t\tstartId: string,\n\t\tmaxDepth: number | undefined,\n\t\tdirection: 'incoming' | 'outgoing'\n\t): readonly string[] {\n\t\tconst cap = maxDepth ?? Number.POSITIVE_INFINITY;\n\t\tconst visited = new Set<string>([startId]);\n\t\tconst order: string[] = [];\n\t\tlet frontier: string[] = [startId];\n\t\tlet depth = 0;\n\t\twhile (frontier.length > 0 && depth < cap) {\n\t\t\tconst next: string[] = [];\n\t\t\tfor (const node of frontier) {\n\t\t\t\tconst edges =\n\t\t\t\t\tdirection === 'outgoing'\n\t\t\t\t\t\t? this._store.outgoing(sessionId, node as ThoughtId)\n\t\t\t\t\t\t: this._store.incoming(sessionId, node as ThoughtId);\n\t\t\t\tfor (const edge of edges) {\n\t\t\t\t\tconst neighbour = direction === 'outgoing' ? edge.to : edge.from;\n\t\t\t\t\tif (visited.has(neighbour)) continue;\n\t\t\t\t\tvisited.add(neighbour);\n\t\t\t\t\torder.push(neighbour);\n\t\t\t\t\tnext.push(neighbour);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfrontier = next;\n\t\t\tdepth++;\n\t\t}\n\t\treturn order;\n\t}\n}\n"],"names":["GraphView","store","sessionId","edges","nodes","hasIncoming","roots","thoughtId","Set","outgoing","Map","edge","children","undefined","frontier","node","visited","depth","next","child","rootThoughtId","order","queue","current","out","inDegree","deg","CycleDetectedError","maxDepth","result","explicitNodes","earliest","a","b","Infinity","root","startId","direction","cap","Number","neighbour"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IEdgeStore } from '../../contracts/interfaces.js';
|
|
2
|
+
import type { ActiveEvidenceProjection } from '../../contracts/strategy.js';
|
|
3
|
+
import type { SessionId } from '../../contracts/ids.js';
|
|
4
|
+
import { type ActiveThoughtBranches } from '../evaluator/VerificationLinks.js';
|
|
5
|
+
import type { ThoughtData } from '../thought.js';
|
|
6
|
+
export interface ActiveEvidenceProjectionInput {
|
|
7
|
+
readonly sessionId: SessionId;
|
|
8
|
+
readonly history: readonly ThoughtData[];
|
|
9
|
+
readonly branches: ActiveThoughtBranches;
|
|
10
|
+
readonly edgeStore: IEdgeStore | undefined;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Build immutable, deep-copied active evidence for strategy reads.
|
|
14
|
+
*
|
|
15
|
+
* Main history keeps retained main order. Active thoughts include branch-only retained entries.
|
|
16
|
+
* The graph is induced by active endpoints only, without path contraction, and never mutates the
|
|
17
|
+
* audit edge store.
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildActiveEvidenceProjection(input: ActiveEvidenceProjectionInput): ActiveEvidenceProjection;
|
|
20
|
+
//# sourceMappingURL=ActiveEvidenceProjection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActiveEvidenceProjection.d.ts","sourceRoot":"","sources":["../../../src/core/reasoning/ActiveEvidenceProjection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,+BAA+B,CAAC;AACjF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAGN,KAAK,qBAAqB,EAC1B,MAAM,mCAAmC,CAAC;AAG3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,UAAU,GAAG,SAAS,CAAC;CAC3C;AAkCD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC5C,KAAK,EAAE,6BAA6B,GAClC,wBAAwB,CAO1B"}
|