simfile 0.0.1
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 +143 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +348 -0
- package/dist/coverage/index.d.ts +2 -0
- package/dist/coverage/index.d.ts.map +1 -0
- package/dist/coverage/index.js +1 -0
- package/dist/coverage/matrix.d.ts +21 -0
- package/dist/coverage/matrix.d.ts.map +1 -0
- package/dist/coverage/matrix.js +173 -0
- package/dist/coverage/render.d.ts +3 -0
- package/dist/coverage/render.d.ts.map +1 -0
- package/dist/coverage/render.js +26 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/kernel/duration.d.ts +9 -0
- package/dist/kernel/duration.d.ts.map +1 -0
- package/dist/kernel/duration.js +44 -0
- package/dist/kernel/index.d.ts +4 -0
- package/dist/kernel/index.d.ts.map +1 -0
- package/dist/kernel/index.js +3 -0
- package/dist/kernel/range.d.ts +6 -0
- package/dist/kernel/range.d.ts.map +1 -0
- package/dist/kernel/range.js +16 -0
- package/dist/kernel/stochastic.d.ts +10 -0
- package/dist/kernel/stochastic.d.ts.map +1 -0
- package/dist/kernel/stochastic.js +25 -0
- package/dist/ledger/index.d.ts +4 -0
- package/dist/ledger/index.d.ts.map +1 -0
- package/dist/ledger/index.js +3 -0
- package/dist/ledger/markers.d.ts +46 -0
- package/dist/ledger/markers.d.ts.map +1 -0
- package/dist/ledger/markers.js +108 -0
- package/dist/ledger/stable.d.ts +65 -0
- package/dist/ledger/stable.d.ts.map +1 -0
- package/dist/ledger/stable.js +78 -0
- package/dist/ledger/validation.d.ts +16 -0
- package/dist/ledger/validation.d.ts.map +1 -0
- package/dist/ledger/validation.js +127 -0
- package/dist/moltnet/index.d.ts +3 -0
- package/dist/moltnet/index.d.ts.map +1 -0
- package/dist/moltnet/index.js +2 -0
- package/dist/moltnet/transcript-export.d.ts +34 -0
- package/dist/moltnet/transcript-export.d.ts.map +1 -0
- package/dist/moltnet/transcript-export.js +68 -0
- package/dist/moltnet/world-participant.d.ts +77 -0
- package/dist/moltnet/world-participant.d.ts.map +1 -0
- package/dist/moltnet/world-participant.js +221 -0
- package/dist/observe/artifacts.d.ts +16 -0
- package/dist/observe/artifacts.d.ts.map +1 -0
- package/dist/observe/artifacts.js +31 -0
- package/dist/observe/causalStreams.d.ts +19 -0
- package/dist/observe/causalStreams.d.ts.map +1 -0
- package/dist/observe/causalStreams.js +38 -0
- package/dist/observe/compute.d.ts +17 -0
- package/dist/observe/compute.d.ts.map +1 -0
- package/dist/observe/compute.js +97 -0
- package/dist/observe/index.d.ts +11 -0
- package/dist/observe/index.d.ts.map +1 -0
- package/dist/observe/index.js +10 -0
- package/dist/observe/manifest.d.ts +79 -0
- package/dist/observe/manifest.d.ts.map +1 -0
- package/dist/observe/manifest.js +87 -0
- package/dist/observe/memoryBanks.d.ts +38 -0
- package/dist/observe/memoryBanks.d.ts.map +1 -0
- package/dist/observe/memoryBanks.js +86 -0
- package/dist/observe/observe.d.ts +32 -0
- package/dist/observe/observe.d.ts.map +1 -0
- package/dist/observe/observe.js +73 -0
- package/dist/observe/report.d.ts +165 -0
- package/dist/observe/report.d.ts.map +1 -0
- package/dist/observe/report.js +138 -0
- package/dist/observe/seedSpread.d.ts +49 -0
- package/dist/observe/seedSpread.d.ts.map +1 -0
- package/dist/observe/seedSpread.js +262 -0
- package/dist/observe/seedSpreadArtifacts.d.ts +49 -0
- package/dist/observe/seedSpreadArtifacts.d.ts.map +1 -0
- package/dist/observe/seedSpreadArtifacts.js +118 -0
- package/dist/observe/spreadMatcher.d.ts +45 -0
- package/dist/observe/spreadMatcher.d.ts.map +1 -0
- package/dist/observe/spreadMatcher.js +124 -0
- package/dist/report/index.d.ts +4 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +3 -0
- package/dist/report/probeArtifact.d.ts +26 -0
- package/dist/report/probeArtifact.d.ts.map +1 -0
- package/dist/report/probeArtifact.js +119 -0
- package/dist/report/probes.d.ts +52 -0
- package/dist/report/probes.d.ts.map +1 -0
- package/dist/report/probes.js +164 -0
- package/dist/report/score.d.ts +27 -0
- package/dist/report/score.d.ts.map +1 -0
- package/dist/report/score.js +14 -0
- package/dist/report/transcripts.d.ts +12 -0
- package/dist/report/transcripts.d.ts.map +1 -0
- package/dist/report/transcripts.js +17 -0
- package/dist/runtime/causal-fixture.d.ts +26 -0
- package/dist/runtime/causal-fixture.d.ts.map +1 -0
- package/dist/runtime/causal-fixture.js +36 -0
- package/dist/runtime/clock.d.ts +25 -0
- package/dist/runtime/clock.d.ts.map +1 -0
- package/dist/runtime/clock.js +63 -0
- package/dist/runtime/condition.d.ts +55 -0
- package/dist/runtime/condition.d.ts.map +1 -0
- package/dist/runtime/condition.js +122 -0
- package/dist/runtime/emit-causal-fixture.d.ts +2 -0
- package/dist/runtime/emit-causal-fixture.d.ts.map +1 -0
- package/dist/runtime/emit-causal-fixture.js +45 -0
- package/dist/runtime/expression.d.ts +11 -0
- package/dist/runtime/expression.d.ts.map +1 -0
- package/dist/runtime/expression.js +305 -0
- package/dist/runtime/numeric.d.ts +7 -0
- package/dist/runtime/numeric.d.ts.map +1 -0
- package/dist/runtime/numeric.js +11 -0
- package/dist/runtime/rule-actions.d.ts +5 -0
- package/dist/runtime/rule-actions.d.ts.map +1 -0
- package/dist/runtime/rule-actions.js +82 -0
- package/dist/runtime/run-record.d.ts +73 -0
- package/dist/runtime/run-record.d.ts.map +1 -0
- package/dist/runtime/run-record.js +179 -0
- package/dist/runtime/step-tick.d.ts +43 -0
- package/dist/runtime/step-tick.d.ts.map +1 -0
- package/dist/runtime/step-tick.js +177 -0
- package/dist/runtime/trace-compile.d.ts +66 -0
- package/dist/runtime/trace-compile.d.ts.map +1 -0
- package/dist/runtime/trace-compile.js +157 -0
- package/dist/runtime/trace-export.d.ts +5 -0
- package/dist/runtime/trace-export.d.ts.map +1 -0
- package/dist/runtime/trace-export.js +4 -0
- package/dist/runtime/trace-run.d.ts +15 -0
- package/dist/runtime/trace-run.d.ts.map +1 -0
- package/dist/runtime/trace-run.js +92 -0
- package/dist/runtime/trace.d.ts +10 -0
- package/dist/runtime/trace.d.ts.map +1 -0
- package/dist/runtime/trace.js +9 -0
- package/dist/runtime/types.d.ts +61 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/viewer-trace.d.ts +64 -0
- package/dist/runtime/viewer-trace.d.ts.map +1 -0
- package/dist/runtime/viewer-trace.js +164 -0
- package/dist/runtime/world-act.d.ts +55 -0
- package/dist/runtime/world-act.d.ts.map +1 -0
- package/dist/runtime/world-act.js +156 -0
- package/dist/schema/binding.d.ts +23 -0
- package/dist/schema/binding.d.ts.map +1 -0
- package/dist/schema/binding.js +249 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +4 -0
- package/dist/schema/model.d.ts +244 -0
- package/dist/schema/model.d.ts.map +1 -0
- package/dist/schema/model.js +222 -0
- package/dist/schema/parse.d.ts +10 -0
- package/dist/schema/parse.d.ts.map +1 -0
- package/dist/schema/parse.js +15 -0
- package/dist/schema/semantic.d.ts +3 -0
- package/dist/schema/semantic.d.ts.map +1 -0
- package/dist/schema/semantic.js +135 -0
- package/dist/sims/composeRunManifest.d.ts +54 -0
- package/dist/sims/composeRunManifest.d.ts.map +1 -0
- package/dist/sims/composeRunManifest.js +40 -0
- package/dist/sims/composedJungianSimDriver.d.ts +50 -0
- package/dist/sims/composedJungianSimDriver.d.ts.map +1 -0
- package/dist/sims/composedJungianSimDriver.js +199 -0
- package/dist/sims/composedOfficeSimDriver.d.ts +53 -0
- package/dist/sims/composedOfficeSimDriver.d.ts.map +1 -0
- package/dist/sims/composedOfficeSimDriver.js +162 -0
- package/dist/sims/exchangeWait.d.ts +56 -0
- package/dist/sims/exchangeWait.d.ts.map +1 -0
- package/dist/sims/exchangeWait.js +66 -0
- package/dist/sims/index.d.ts +14 -0
- package/dist/sims/index.d.ts.map +1 -0
- package/dist/sims/index.js +13 -0
- package/dist/sims/moltnetRoomClient.d.ts +47 -0
- package/dist/sims/moltnetRoomClient.d.ts.map +1 -0
- package/dist/sims/moltnetRoomClient.js +41 -0
- package/dist/sims/poll.d.ts +19 -0
- package/dist/sims/poll.d.ts.map +1 -0
- package/dist/sims/poll.js +23 -0
- package/dist/sims/spawnfileCli.d.ts +49 -0
- package/dist/sims/spawnfileCli.d.ts.map +1 -0
- package/dist/sims/spawnfileCli.js +90 -0
- package/dist/sims/spawnfileReceipts.d.ts +76 -0
- package/dist/sims/spawnfileReceipts.d.ts.map +1 -0
- package/dist/sims/spawnfileReceipts.js +107 -0
- package/dist/sims/worldDrivenOfficeSimDriver.d.ts +59 -0
- package/dist/sims/worldDrivenOfficeSimDriver.d.ts.map +1 -0
- package/dist/sims/worldDrivenOfficeSimDriver.js +182 -0
- package/dist/sims/worldLedgerWriter.d.ts +32 -0
- package/dist/sims/worldLedgerWriter.d.ts.map +1 -0
- package/dist/sims/worldLedgerWriter.js +39 -0
- package/dist/sims/worldSeedLint.d.ts +42 -0
- package/dist/sims/worldSeedLint.d.ts.map +1 -0
- package/dist/sims/worldSeedLint.js +73 -0
- package/dist/sims/worldTickIngest.d.ts +27 -0
- package/dist/sims/worldTickIngest.d.ts.map +1 -0
- package/dist/sims/worldTickIngest.js +35 -0
- package/dist/sims/worldTickLoop.d.ts +64 -0
- package/dist/sims/worldTickLoop.d.ts.map +1 -0
- package/dist/sims/worldTickLoop.js +122 -0
- package/dist/view/engineProvenance.d.ts +46 -0
- package/dist/view/engineProvenance.d.ts.map +1 -0
- package/dist/view/engineProvenance.js +76 -0
- package/dist/view/index.d.ts +14 -0
- package/dist/view/index.d.ts.map +1 -0
- package/dist/view/index.js +107 -0
- package/dist/view/membranes.d.ts +14 -0
- package/dist/view/membranes.d.ts.map +1 -0
- package/dist/view/membranes.js +127 -0
- package/dist/view/runDetect.d.ts +2 -0
- package/dist/view/runDetect.d.ts.map +1 -0
- package/dist/view/runDetect.js +47 -0
- package/dist/view/runRawArtifacts.d.ts +48 -0
- package/dist/view/runRawArtifacts.d.ts.map +1 -0
- package/dist/view/runRawArtifacts.js +143 -0
- package/dist/view/runTimeline.d.ts +24 -0
- package/dist/view/runTimeline.d.ts.map +1 -0
- package/dist/view/runTimeline.js +204 -0
- package/dist/view/runTimelineRecords.d.ts +42 -0
- package/dist/view/runTimelineRecords.d.ts.map +1 -0
- package/dist/view/runTimelineRecords.js +244 -0
- package/dist/view/runTimelineRefs.d.ts +27 -0
- package/dist/view/runTimelineRefs.d.ts.map +1 -0
- package/dist/view/runTimelineRefs.js +31 -0
- package/dist/view/runTimelineTypes.d.ts +99 -0
- package/dist/view/runTimelineTypes.d.ts.map +1 -0
- package/dist/view/runTimelineTypes.js +1 -0
- package/dist/view/runViewModel.d.ts +21 -0
- package/dist/view/runViewModel.d.ts.map +1 -0
- package/dist/view/runViewModel.js +66 -0
- package/dist/view/runViewModelCompute.d.ts +24 -0
- package/dist/view/runViewModelCompute.d.ts.map +1 -0
- package/dist/view/runViewModelCompute.js +157 -0
- package/dist/view/runViewModelTypes.d.ts +177 -0
- package/dist/view/runViewModelTypes.d.ts.map +1 -0
- package/dist/view/runViewModelTypes.js +1 -0
- package/dist/view/runWorldTrace.d.ts +97 -0
- package/dist/view/runWorldTrace.d.ts.map +1 -0
- package/dist/view/runWorldTrace.js +88 -0
- package/dist/view/server.d.ts +12 -0
- package/dist/view/server.d.ts.map +1 -0
- package/dist/view/server.js +306 -0
- package/package.json +65 -0
- package/web/dist/assets/index-CJHLjfsG.js +49 -0
- package/web/dist/assets/index-DJOsPsU8.css +1 -0
- package/web/dist/index.html +13 -0
- package/web/dist/models/AnimatedMushnub.glb +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ElementRef, RunTimeline } from "./runTimelineTypes.js";
|
|
2
|
+
/**
|
|
3
|
+
* One room the run declares (`manifest.world`): a `room:<network>:<room>`
|
|
4
|
+
* ref, its network + bare room id, and its member agent ids. Exported so
|
|
5
|
+
* `server.ts` can tell an OUTER (parent-floor) room from an interior one —
|
|
6
|
+
* a membrane's `interiorRooms` are also entries of this same list — when it
|
|
7
|
+
* builds the outer map's `/api/world` trace (`runWorldTrace.ts`'s
|
|
8
|
+
* `buildRunWorldTrace` `rooms` param).
|
|
9
|
+
*/
|
|
10
|
+
export interface WorldRoom {
|
|
11
|
+
ref: ElementRef;
|
|
12
|
+
networkId: string;
|
|
13
|
+
roomId: string;
|
|
14
|
+
members: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Reads and parses `manifest.json`'s `world` field into its declared rooms —
|
|
18
|
+
* the same parse `buildRunTimeline` does internally, exported so `server.ts`
|
|
19
|
+
* can tell an outer (parent-floor) room from an interior one when it builds
|
|
20
|
+
* the outer map's `/api/world` trace, without re-deriving the whole timeline.
|
|
21
|
+
*/
|
|
22
|
+
export declare const readWorldRooms: (runDir: string) => Promise<WorldRoom[]>;
|
|
23
|
+
export declare const buildRunTimeline: (runDir: string) => Promise<RunTimeline>;
|
|
24
|
+
//# sourceMappingURL=runTimeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runTimeline.d.ts","sourceRoot":"","sources":["../../src/view/runTimeline.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAA0D,MAAM,uBAAuB,CAAC;AAgE7H;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,UAAU,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAkFD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,SAAS,EAAE,CAGxE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,WAAW,CA6D1E,CAAC"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { collectCausalStreams } from "../observe/causalStreams.js";
|
|
4
|
+
import { parseRunManifest } from "../observe/manifest.js";
|
|
5
|
+
import { readMnemeEventsByBank, readTranscript } from "./runRawArtifacts.js";
|
|
6
|
+
import { agentIdFromStreamId, agentRef, bankFromRelativePath, bankRef, roomRef, stringField } from "./runTimelineRefs.js";
|
|
7
|
+
import { readRunMembranes } from "./membranes.js";
|
|
8
|
+
import { buildBankLogRecord, buildCausalRecord, roomForMoltnetMessage } from "./runTimelineRecords.js";
|
|
9
|
+
/**
|
|
10
|
+
* `buildRunTimeline` merges every causal record in a sealed run directory
|
|
11
|
+
* into one deterministic, scrubbable `RunTimeline` (see `runTimelineTypes.ts`
|
|
12
|
+
* for the shape and `docs/VIEW_DESIGN.md` rule 7). This is the only file that
|
|
13
|
+
* assigns the scrub key `t`; everything downstream (the world-trace adapter,
|
|
14
|
+
* the web store, the chat/minds/portal views) treats `t` as ground truth.
|
|
15
|
+
*
|
|
16
|
+
* The per-authority record-building logic itself lives in
|
|
17
|
+
* `runTimelineRecords.ts` (split out to keep this file, the orchestrator,
|
|
18
|
+
* under 400 lines — `AGENTS.md`); this file owns merge order (`sortRecords`),
|
|
19
|
+
* causal repair, dense `t` assignment, and element enumeration.
|
|
20
|
+
*/
|
|
21
|
+
const sortRecords = (records) => [...records].sort((left, right) => {
|
|
22
|
+
const timeDiff = Date.parse(left.recordedAt) - Date.parse(right.recordedAt);
|
|
23
|
+
if (timeDiff !== 0)
|
|
24
|
+
return timeDiff;
|
|
25
|
+
if (left.authority !== right.authority)
|
|
26
|
+
return left.authority.localeCompare(right.authority);
|
|
27
|
+
if (left.streamId !== right.streamId)
|
|
28
|
+
return left.streamId.localeCompare(right.streamId);
|
|
29
|
+
if (left.seq !== right.seq)
|
|
30
|
+
return left.seq - right.seq;
|
|
31
|
+
return left.eventId.localeCompare(right.eventId);
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Stable causal-repair pass: an event may not precede any of its own
|
|
35
|
+
* `causeIds`. Repeatedly finds the first record whose latest-known cause
|
|
36
|
+
* sits after it and re-splices it immediately after that cause, restarting
|
|
37
|
+
* the scan after each move (small run sizes at this increment's scale make
|
|
38
|
+
* the O(n^2) worst case negligible; correctness first).
|
|
39
|
+
*/
|
|
40
|
+
const causalRepair = (records) => {
|
|
41
|
+
const order = [...records];
|
|
42
|
+
const maxPasses = order.length + 5;
|
|
43
|
+
for (let pass = 0; pass < maxPasses; pass += 1) {
|
|
44
|
+
const indexOf = new Map(order.map((record, index) => [record.eventId, index]));
|
|
45
|
+
let moved = false;
|
|
46
|
+
for (let index = 0; index < order.length; index += 1) {
|
|
47
|
+
const record = order[index];
|
|
48
|
+
let latestCauseIndex = -1;
|
|
49
|
+
for (const causeId of record.causeIds) {
|
|
50
|
+
const causeIndex = indexOf.get(causeId);
|
|
51
|
+
if (causeIndex !== undefined)
|
|
52
|
+
latestCauseIndex = Math.max(latestCauseIndex, causeIndex);
|
|
53
|
+
}
|
|
54
|
+
if (latestCauseIndex > index) {
|
|
55
|
+
order.splice(index, 1);
|
|
56
|
+
order.splice(latestCauseIndex, 0, record);
|
|
57
|
+
moved = true;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!moved)
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
return order;
|
|
65
|
+
};
|
|
66
|
+
const buildElements = (params) => {
|
|
67
|
+
const elements = new Map();
|
|
68
|
+
for (const room of params.rooms) {
|
|
69
|
+
elements.set(room.ref, { ref: room.ref, kind: "room", label: room.roomId });
|
|
70
|
+
for (const member of room.members) {
|
|
71
|
+
const ref = agentRef(member);
|
|
72
|
+
if (!elements.has(ref))
|
|
73
|
+
elements.set(ref, { ref, kind: "agent", label: member });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
for (const membrane of params.membranes) {
|
|
77
|
+
if (!elements.has(membrane.ref))
|
|
78
|
+
elements.set(membrane.ref, { ref: membrane.ref, kind: "team", label: membrane.label });
|
|
79
|
+
}
|
|
80
|
+
for (const stream of params.streams) {
|
|
81
|
+
if (stream.authority !== "daimon")
|
|
82
|
+
continue;
|
|
83
|
+
for (const event of stream.events) {
|
|
84
|
+
const agentId = agentIdFromStreamId(event.emitter.stream_id);
|
|
85
|
+
if (!agentId)
|
|
86
|
+
continue;
|
|
87
|
+
const ref = agentRef(agentId);
|
|
88
|
+
if (!elements.has(ref))
|
|
89
|
+
elements.set(ref, { ref, kind: "agent", label: agentId });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (const bankName of params.mnemeByBank.keys()) {
|
|
93
|
+
const ref = bankRef(bankName);
|
|
94
|
+
if (!elements.has(ref))
|
|
95
|
+
elements.set(ref, { ref, kind: "bank", label: bankName });
|
|
96
|
+
}
|
|
97
|
+
// Increment 4: a variable element per distinct `variable:<id>` subject
|
|
98
|
+
// that actually appears somewhere in this run's own world-authority
|
|
99
|
+
// records (`buildWorldRecord`'s `variable:<id>` subjects, joined from a
|
|
100
|
+
// `rule.fired`/`world.message`/`world.act` event's own `payload.variables`
|
|
101
|
+
// or `payload.target`) — derived purely from what this run's own records
|
|
102
|
+
// name, never from a separate schema/telemetry read.
|
|
103
|
+
for (const record of params.records) {
|
|
104
|
+
for (const subject of record.subjects) {
|
|
105
|
+
if (!subject.startsWith("variable:") || elements.has(subject))
|
|
106
|
+
continue;
|
|
107
|
+
elements.set(subject, { ref: subject, kind: "variable", label: subject.slice("variable:".length) });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return [...elements.values()];
|
|
111
|
+
};
|
|
112
|
+
const stringMembers = (value) => Array.isArray(value) ? value.filter((member) => typeof member === "string") : [];
|
|
113
|
+
/**
|
|
114
|
+
* Parses `manifest.world` into the run's rooms, supporting both shapes: a
|
|
115
|
+
* single-network run's flat `{network_id, room_id, members}` (office-sim
|
|
116
|
+
* golden) and a multi-network composed run's `{rooms: [{network_id, room_id,
|
|
117
|
+
* members}, ...]}` (the jungian psyche, one entry per network's room).
|
|
118
|
+
*/
|
|
119
|
+
const parseWorldRooms = (worldRecord) => {
|
|
120
|
+
const toRoom = (record) => {
|
|
121
|
+
const networkId = stringField(record, "network_id");
|
|
122
|
+
const roomId = stringField(record, "room_id");
|
|
123
|
+
if (!networkId || !roomId)
|
|
124
|
+
return undefined;
|
|
125
|
+
return { ref: roomRef(networkId, roomId), networkId, roomId, members: stringMembers(record?.members) };
|
|
126
|
+
};
|
|
127
|
+
const roomsRaw = worldRecord?.rooms;
|
|
128
|
+
if (Array.isArray(roomsRaw)) {
|
|
129
|
+
return roomsRaw
|
|
130
|
+
.map((entry) => toRoom(typeof entry === "object" && entry !== null ? entry : undefined))
|
|
131
|
+
.filter((room) => room !== undefined);
|
|
132
|
+
}
|
|
133
|
+
const single = toRoom(worldRecord);
|
|
134
|
+
return single ? [single] : [];
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Reads and parses `manifest.json`'s `world` field into its declared rooms —
|
|
138
|
+
* the same parse `buildRunTimeline` does internally, exported so `server.ts`
|
|
139
|
+
* can tell an outer (parent-floor) room from an interior one when it builds
|
|
140
|
+
* the outer map's `/api/world` trace, without re-deriving the whole timeline.
|
|
141
|
+
*/
|
|
142
|
+
export const readWorldRooms = async (runDir) => {
|
|
143
|
+
const manifest = parseRunManifest(JSON.parse(await readFile(path.join(runDir, "manifest.json"), "utf8")));
|
|
144
|
+
return parseWorldRooms(manifest.world);
|
|
145
|
+
};
|
|
146
|
+
export const buildRunTimeline = async (runDir) => {
|
|
147
|
+
const manifest = parseRunManifest(JSON.parse(await readFile(path.join(runDir, "manifest.json"), "utf8")));
|
|
148
|
+
const worldRecord = manifest.world;
|
|
149
|
+
const rooms = parseWorldRooms(worldRecord);
|
|
150
|
+
const room = rooms[0]?.ref;
|
|
151
|
+
const [streams, mnemeByBank, transcript, membranes] = await Promise.all([
|
|
152
|
+
collectCausalStreams(runDir),
|
|
153
|
+
readMnemeEventsByBank(runDir),
|
|
154
|
+
readTranscript(runDir),
|
|
155
|
+
readRunMembranes(runDir),
|
|
156
|
+
]);
|
|
157
|
+
const messagesById = new Map(transcript.transcript.map((message) => [message.id, message]));
|
|
158
|
+
const roomsByMessageEventId = new Map();
|
|
159
|
+
for (const stream of streams) {
|
|
160
|
+
if (stream.authority !== "moltnet")
|
|
161
|
+
continue;
|
|
162
|
+
for (const event of stream.events) {
|
|
163
|
+
const messageRoom = roomForMoltnetMessage(event);
|
|
164
|
+
if (messageRoom)
|
|
165
|
+
roomsByMessageEventId.set(event.event_id, messageRoom);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const memoryContentById = new Map();
|
|
169
|
+
for (const bankEvents of mnemeByBank.values()) {
|
|
170
|
+
for (const event of bankEvents)
|
|
171
|
+
memoryContentById.set(event.id, event.content.text);
|
|
172
|
+
}
|
|
173
|
+
const ctx = { room, messagesById, roomsByMessageEventId, memoryContentById };
|
|
174
|
+
const records = [];
|
|
175
|
+
for (const stream of streams) {
|
|
176
|
+
const bank = bankFromRelativePath(stream.relativePath);
|
|
177
|
+
for (const event of stream.events) {
|
|
178
|
+
records.push(buildCausalRecord(event, stream.authority, bank, ctx));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
for (const [bankName, bankEvents] of mnemeByBank) {
|
|
182
|
+
for (const event of bankEvents)
|
|
183
|
+
records.push(buildBankLogRecord(event, bankName));
|
|
184
|
+
}
|
|
185
|
+
const repaired = causalRepair(sortRecords(records));
|
|
186
|
+
const events = repaired.map((record, index) => ({
|
|
187
|
+
t: index,
|
|
188
|
+
eventId: record.eventId,
|
|
189
|
+
authority: record.authority,
|
|
190
|
+
streamId: record.streamId,
|
|
191
|
+
seq: record.seq,
|
|
192
|
+
type: record.type,
|
|
193
|
+
viewClass: record.viewClass,
|
|
194
|
+
recordedAt: record.recordedAt,
|
|
195
|
+
actor: record.actor,
|
|
196
|
+
subjects: record.subjects,
|
|
197
|
+
causes: record.causeIds,
|
|
198
|
+
text: record.text,
|
|
199
|
+
worldEventId: record.worldEventId,
|
|
200
|
+
payload: record.payload,
|
|
201
|
+
}));
|
|
202
|
+
const elements = buildElements({ rooms, membranes, streams, mnemeByBank, records });
|
|
203
|
+
return { version: "simfile.run-timeline.v1", runId: manifest.run_id, events, elements, membranes };
|
|
204
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CausalEvent } from "@noopolis/stele";
|
|
2
|
+
import type { RawMnemeEvent, RawTranscriptMessage } from "./runViewModelTypes.js";
|
|
3
|
+
import type { ElementRef, TimelineViewClass } from "./runTimelineTypes.js";
|
|
4
|
+
/**
|
|
5
|
+
* Per-authority (`moltnet`/`daimon`/`mneme`/`world`/mneme-bank-log) raw
|
|
6
|
+
* record builders, split out of `runTimeline.ts` (`AGENTS.md`: split before
|
|
7
|
+
* 400 lines) so the orchestrator (`buildRunTimeline`: merge, sort, causal
|
|
8
|
+
* repair, dense `t` assignment) stays the file that's easy to read
|
|
9
|
+
* end-to-end. `buildCausalRecord` is the one dispatcher every
|
|
10
|
+
* `raw/<authority>/causal.jsonl` record goes through; `buildBankLogRecord`
|
|
11
|
+
* is the parallel path for a mneme bank's `events.jsonl` rows.
|
|
12
|
+
*/
|
|
13
|
+
/** Internal pre-`t` record: everything a `TimelineEvent` needs except its dense scrub index. */
|
|
14
|
+
export interface RawRecord {
|
|
15
|
+
eventId: string;
|
|
16
|
+
authority: string;
|
|
17
|
+
streamId: string;
|
|
18
|
+
seq: number;
|
|
19
|
+
type: string;
|
|
20
|
+
viewClass: TimelineViewClass;
|
|
21
|
+
recordedAt: string;
|
|
22
|
+
causeIds: string[];
|
|
23
|
+
actor?: string;
|
|
24
|
+
subjects: ElementRef[];
|
|
25
|
+
text?: string;
|
|
26
|
+
/** See `TimelineEvent.worldEventId`'s doc comment (`runTimelineTypes.ts`). */
|
|
27
|
+
worldEventId?: string;
|
|
28
|
+
payload: unknown;
|
|
29
|
+
}
|
|
30
|
+
export interface JoinContext {
|
|
31
|
+
room?: ElementRef;
|
|
32
|
+
messagesById: ReadonlyMap<string, RawTranscriptMessage>;
|
|
33
|
+
roomsByMessageEventId: ReadonlyMap<string, ElementRef>;
|
|
34
|
+
memoryContentById: ReadonlyMap<string, string>;
|
|
35
|
+
}
|
|
36
|
+
/** Resolves the room a moltnet `message.accepted` event targeted — `buildRunTimeline` uses this directly (not just `buildMoltnetRecord`) to build `roomsByMessageEventId`, the daimon-attribution join surface. */
|
|
37
|
+
export declare const roomForMoltnetMessage: (event: CausalEvent) => ElementRef | undefined;
|
|
38
|
+
/** The one dispatcher every `raw/<authority>/causal.jsonl` record goes through. */
|
|
39
|
+
export declare const buildCausalRecord: (event: CausalEvent, authority: string, bank: string | undefined, ctx: JoinContext) => RawRecord;
|
|
40
|
+
/** The parallel path for a mneme bank's `events.jsonl` rows (the human-readable memory log, distinct from that bank's `causal.jsonl`). */
|
|
41
|
+
export declare const buildBankLogRecord: (event: RawMnemeEvent, bankName: string) => RawRecord;
|
|
42
|
+
//# sourceMappingURL=runTimelineRecords.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runTimelineRecords.d.ts","sourceRoot":"","sources":["../../src/view/runTimelineRecords.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG3E;;;;;;;;GAQG;AAEH,gGAAgG;AAChG,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,iBAAiB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IACxD,qBAAqB,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvD,iBAAiB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChD;AA8BD,mNAAmN;AACnN,eAAO,MAAM,qBAAqB,GAAI,OAAO,WAAW,KAAG,UAAU,GAAG,SAQvE,CAAC;AAuLF,mFAAmF;AACnF,eAAO,MAAM,iBAAiB,GAC5B,OAAO,WAAW,EAClB,WAAW,MAAM,EACjB,MAAM,MAAM,GAAG,SAAS,EACxB,KAAK,WAAW,KACf,SAkBF,CAAC;AAEF,0IAA0I;AAC1I,eAAO,MAAM,kBAAkB,GAAI,OAAO,aAAa,EAAE,UAAU,MAAM,KAAG,SAgB3E,CAAC"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { agentIdFromStreamId, agentRef, bankRef, isDefined, messageText, networkIdFromStreamId, roomRef, stringField, variableRef } from "./runTimelineRefs.js";
|
|
2
|
+
const viewClassForCausalType = (type) => {
|
|
3
|
+
switch (type) {
|
|
4
|
+
case "message.accepted": return "message";
|
|
5
|
+
case "control.wake.accepted": return "wake";
|
|
6
|
+
case "turn.input.submitted": return "turn.input";
|
|
7
|
+
case "turn.output.completed": return "turn.output";
|
|
8
|
+
case "memory.recalled": return "memory.recalled";
|
|
9
|
+
// World-authority additions (increment 3, `buildWorldRecord` below):
|
|
10
|
+
// `world.message` is a message like any other room chat line;
|
|
11
|
+
// `wake.recommended` shares the daimon `control.wake.accepted` class
|
|
12
|
+
// (both mean "a wake was recommended/accepted for an agent").
|
|
13
|
+
case "clock.sync": return "clock";
|
|
14
|
+
case "marker.seen": return "marker";
|
|
15
|
+
case "world.message": return "message";
|
|
16
|
+
case "wake.recommended": return "wake";
|
|
17
|
+
default: return "other";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const viewClassForBankLogType = (type) => {
|
|
21
|
+
switch (type) {
|
|
22
|
+
case "memory.claimed": return "memory.claimed";
|
|
23
|
+
case "memory.observed": return "memory.observed";
|
|
24
|
+
case "memory.recalled": return "memory.recalled";
|
|
25
|
+
default: return "other";
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/** Resolves the room a moltnet `message.accepted` event targeted — `buildRunTimeline` uses this directly (not just `buildMoltnetRecord`) to build `roomsByMessageEventId`, the daimon-attribution join surface. */
|
|
29
|
+
export const roomForMoltnetMessage = (event) => {
|
|
30
|
+
if (event.type !== "message.accepted")
|
|
31
|
+
return undefined;
|
|
32
|
+
const networkId = networkIdFromStreamId(event.emitter.stream_id);
|
|
33
|
+
const target = event.payload?.target;
|
|
34
|
+
if (!networkId || typeof target !== "object" || target === null)
|
|
35
|
+
return undefined;
|
|
36
|
+
const targetRecord = target;
|
|
37
|
+
const roomId = stringField(targetRecord, "room_id");
|
|
38
|
+
return targetRecord.kind === "room" && roomId ? roomRef(networkId, roomId) : undefined;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* The `simfile_event_id` breadcrumb `src/moltnet/world-participant.ts`'s
|
|
42
|
+
* `metadataFromEvent` attaches to a message's first text part's `data` when
|
|
43
|
+
* that message originated from a world action — the real join surface for
|
|
44
|
+
* "this moltnet message echoes that world-authority event" (increment 3
|
|
45
|
+
* dedup rule). Undefined for a genuine agent-authored message, which has no
|
|
46
|
+
* such breadcrumb.
|
|
47
|
+
*/
|
|
48
|
+
const worldEventIdFromMessage = (message) => {
|
|
49
|
+
const breadcrumb = message.parts.find((part) => part.kind === "text")?.data?.simfile_event_id;
|
|
50
|
+
return typeof breadcrumb === "string" ? breadcrumb : undefined;
|
|
51
|
+
};
|
|
52
|
+
const buildMoltnetRecord = (event, base, ctx) => {
|
|
53
|
+
// A message.accepted names its OWN room from its network stream_id +
|
|
54
|
+
// target.room_id (`roomForMoltnetMessage`), never the run's single primary
|
|
55
|
+
// room — the fix that keeps an inner-council message under
|
|
56
|
+
// `room:<inner_net>:<room>` in a multi-network run instead of collapsing
|
|
57
|
+
// every network's messages onto the floor room. Falls back to `ctx.room`
|
|
58
|
+
// only when the event carries no resolvable target (never, for a
|
|
59
|
+
// message.accepted).
|
|
60
|
+
const messageRoom = roomForMoltnetMessage(event) ?? ctx.room;
|
|
61
|
+
if (event.type !== "message.accepted") {
|
|
62
|
+
return { ...base, subjects: [ctx.room].filter(isDefined) };
|
|
63
|
+
}
|
|
64
|
+
const messageId = stringField(event.payload, "message_id");
|
|
65
|
+
const message = messageId ? ctx.messagesById.get(messageId) : undefined;
|
|
66
|
+
const authorId = message?.from.id;
|
|
67
|
+
return {
|
|
68
|
+
...base,
|
|
69
|
+
actor: authorId,
|
|
70
|
+
subjects: [messageRoom, authorId ? agentRef(authorId) : undefined].filter(isDefined),
|
|
71
|
+
text: message ? messageText(message) : undefined,
|
|
72
|
+
worldEventId: message ? worldEventIdFromMessage(message) : undefined,
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
const buildDaimonRecord = (event, base, ctx) => {
|
|
76
|
+
const agentId = agentIdFromStreamId(event.emitter.stream_id);
|
|
77
|
+
const turnId = stringField(event.payload, "turn_id");
|
|
78
|
+
const causingMessageEventIds = [
|
|
79
|
+
turnId?.startsWith("moltnet:") ? turnId : undefined,
|
|
80
|
+
...event.cause_event_ids,
|
|
81
|
+
].filter(isDefined);
|
|
82
|
+
const causingRoom = causingMessageEventIds
|
|
83
|
+
.map((eventId) => ctx.roomsByMessageEventId.get(eventId))
|
|
84
|
+
.find(isDefined);
|
|
85
|
+
const subjects = [agentId ? agentRef(agentId) : undefined, causingRoom].filter(isDefined);
|
|
86
|
+
let text;
|
|
87
|
+
if (event.type === "turn.input.submitted") {
|
|
88
|
+
const causingMessageId = turnId?.startsWith("moltnet:") ? turnId.slice("moltnet:".length) : undefined;
|
|
89
|
+
const causingMessage = causingMessageId ? ctx.messagesById.get(causingMessageId) : undefined;
|
|
90
|
+
text = causingMessage ? messageText(causingMessage) : undefined;
|
|
91
|
+
}
|
|
92
|
+
return { ...base, actor: agentId, subjects, text };
|
|
93
|
+
};
|
|
94
|
+
const buildMnemeCausalRecord = (event, bank, base, ctx) => {
|
|
95
|
+
const agentId = event.principal_id.startsWith("agent:") ? event.principal_id.slice("agent:".length) : undefined;
|
|
96
|
+
const subjects = [bank ? bankRef(bank) : undefined, agentId ? agentRef(agentId) : undefined].filter(isDefined);
|
|
97
|
+
let text;
|
|
98
|
+
if (event.type === "memory.recalled") {
|
|
99
|
+
const memoryId = stringField(event.payload, "memory_id");
|
|
100
|
+
text = memoryId ? ctx.memoryContentById.get(memoryId) : undefined;
|
|
101
|
+
}
|
|
102
|
+
return { ...base, actor: agentId, subjects, text };
|
|
103
|
+
};
|
|
104
|
+
const roomTargetPattern = /^room:[^:]+:[^:]+$/u;
|
|
105
|
+
const agentTargetPattern = /^agent:[^:]+$/u;
|
|
106
|
+
/**
|
|
107
|
+
* The world clock's own anchor — increment 3's `clock.sync` subject. A
|
|
108
|
+
* `clock.sync` event names the tick axis itself, not any one room or agent,
|
|
109
|
+
* so it gets a dedicated ref rather than an empty `subjects` array (which
|
|
110
|
+
* would make it invisible to any future "world clock" storyline portal).
|
|
111
|
+
*/
|
|
112
|
+
const globalClockRef = "clock:global";
|
|
113
|
+
/**
|
|
114
|
+
* The world stream's own `payload.target` is already an `ElementRef`-shaped
|
|
115
|
+
* string (`room:<network>:<room>` or `agent:<id>`, per
|
|
116
|
+
* `src/runtime/rule-actions.ts`'s `action.to` — a Simfile rule's `to:`
|
|
117
|
+
* field, e.g. `room:office_lab:office-room` or `agent:eleanor`) for every
|
|
118
|
+
* world event kind this run emits. Returned verbatim when it matches one of
|
|
119
|
+
* those two shapes; `undefined` otherwise (e.g. `clock.sync`'s `"global"`,
|
|
120
|
+
* which has no per-room/per-agent subject of its own).
|
|
121
|
+
*/
|
|
122
|
+
const worldTargetRef = (payload) => {
|
|
123
|
+
const target = stringField(payload, "target");
|
|
124
|
+
if (!target)
|
|
125
|
+
return undefined;
|
|
126
|
+
return roomTargetPattern.test(target) || agentTargetPattern.test(target) ? target : undefined;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Increment 4's variable storyline join: the `variables: string[]` payload
|
|
130
|
+
* field `src/runtime/step-tick.ts`'s `runRule` (and `rule-actions.ts`'s
|
|
131
|
+
* `emitRuleActionEvents`) stamps onto a `rule.fired` event and every
|
|
132
|
+
* world-effect event it emits, whenever that rule's own `when:` condition
|
|
133
|
+
* references at least one variable (`conditionVariableIds`). Read straight
|
|
134
|
+
* off the event's own payload — never invented — and turned into
|
|
135
|
+
* `variable:<id>` subjects so the variable's storyline
|
|
136
|
+
* (`eventsForElement(timeline, "variable:<id>")`) includes the rule firing
|
|
137
|
+
* and the message/dm/wake it caused. Absent on a `clock.sync` (every tick,
|
|
138
|
+
* not this rule's own event) and on any rule with no variable condition.
|
|
139
|
+
*/
|
|
140
|
+
const variableRefsFromPayload = (payload) => {
|
|
141
|
+
const raw = payload?.variables;
|
|
142
|
+
if (!Array.isArray(raw))
|
|
143
|
+
return [];
|
|
144
|
+
return raw.filter((id) => typeof id === "string").map(variableRef);
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* World-authority records (`raw/world/causal.jsonl`, increment 3): the
|
|
148
|
+
* mechanical clock/marker/message/wake stream a world-driven run emits
|
|
149
|
+
* alongside the agents' own moltnet/daimon/mneme streams.
|
|
150
|
+
* - `clock.sync` anchors the tick axis itself (`globalClockRef`), never a
|
|
151
|
+
* room — it is the run's own heartbeat, not a room event.
|
|
152
|
+
* - `marker.seen` is attributed to the room plus the real agent who
|
|
153
|
+
* authored the moltnet message that tripped it, joined by
|
|
154
|
+
* `source_event_id` (a bare transcript message `id`, never `moltnet:`-
|
|
155
|
+
* prefixed — confirmed against this run's own fixture) against
|
|
156
|
+
* `ctx.messagesById`, never invented from the marker's own `alias`.
|
|
157
|
+
* - `world.message`/`world.dm` are attributed to the room/agent the action
|
|
158
|
+
* targeted, with `text` joined from the event's own `content` field (the
|
|
159
|
+
* same text moltnet re-delivers as the echo message this dedups against).
|
|
160
|
+
* - `world.act` is attributed directly to the fed variable it wrote
|
|
161
|
+
* (`payload.target` IS the variable id for this event type, unlike every
|
|
162
|
+
* other world event kind where `target` is a room/agent ref).
|
|
163
|
+
* - `wake.recommended` and any other world event type (`rule.fired`, ...)
|
|
164
|
+
* fall back to the event's own `target` ref, or the run's single room
|
|
165
|
+
* when `target` doesn't resolve to one.
|
|
166
|
+
* - Every branch additionally folds in `variable:<id>` subjects from the
|
|
167
|
+
* event's own `payload.variables` (`variableRefsFromPayload`) when
|
|
168
|
+
* present — increment 4's variable storyline join.
|
|
169
|
+
*/
|
|
170
|
+
const buildWorldRecord = (event, base, ctx) => {
|
|
171
|
+
const payload = event.payload;
|
|
172
|
+
const targetRef = worldTargetRef(payload);
|
|
173
|
+
const variableSubjects = variableRefsFromPayload(payload);
|
|
174
|
+
const withVariableSubjects = (record) => variableSubjects.length === 0 ? record : { ...record, subjects: [...new Set([...record.subjects, ...variableSubjects])] };
|
|
175
|
+
if (event.type === "clock.sync") {
|
|
176
|
+
return withVariableSubjects({ ...base, subjects: [globalClockRef] });
|
|
177
|
+
}
|
|
178
|
+
if (event.type === "marker.seen") {
|
|
179
|
+
const sourceEventId = stringField(payload, "source_event_id");
|
|
180
|
+
const sourceMessage = sourceEventId ? ctx.messagesById.get(sourceEventId) : undefined;
|
|
181
|
+
const authorId = sourceMessage?.from.id;
|
|
182
|
+
return withVariableSubjects({
|
|
183
|
+
...base,
|
|
184
|
+
actor: authorId,
|
|
185
|
+
subjects: [ctx.room ?? targetRef, authorId ? agentRef(authorId) : undefined].filter(isDefined),
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
if (event.type === "world.message" || event.type === "world.dm") {
|
|
189
|
+
return withVariableSubjects({
|
|
190
|
+
...base,
|
|
191
|
+
subjects: [ctx.room ?? targetRef].filter(isDefined),
|
|
192
|
+
text: stringField(payload, "content"),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (event.type === "world.act") {
|
|
196
|
+
const fedVariableId = stringField(payload, "target");
|
|
197
|
+
return withVariableSubjects({
|
|
198
|
+
...base,
|
|
199
|
+
subjects: [fedVariableId ? variableRef(fedVariableId) : (targetRef ?? ctx.room)].filter(isDefined),
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return withVariableSubjects({ ...base, subjects: [targetRef ?? ctx.room].filter(isDefined) });
|
|
203
|
+
};
|
|
204
|
+
/** The one dispatcher every `raw/<authority>/causal.jsonl` record goes through. */
|
|
205
|
+
export const buildCausalRecord = (event, authority, bank, ctx) => {
|
|
206
|
+
const base = {
|
|
207
|
+
eventId: event.event_id,
|
|
208
|
+
authority,
|
|
209
|
+
streamId: event.emitter.stream_id,
|
|
210
|
+
seq: event.emitter.seq,
|
|
211
|
+
type: event.type,
|
|
212
|
+
viewClass: viewClassForCausalType(event.type),
|
|
213
|
+
recordedAt: event.recorded_at,
|
|
214
|
+
causeIds: event.cause_event_ids,
|
|
215
|
+
payload: event.payload,
|
|
216
|
+
};
|
|
217
|
+
if (authority === "moltnet")
|
|
218
|
+
return buildMoltnetRecord(event, base, ctx);
|
|
219
|
+
if (authority === "daimon")
|
|
220
|
+
return buildDaimonRecord(event, base, ctx);
|
|
221
|
+
if (authority === "mneme")
|
|
222
|
+
return buildMnemeCausalRecord(event, bank, base, ctx);
|
|
223
|
+
if (authority === "world")
|
|
224
|
+
return buildWorldRecord(event, base, ctx);
|
|
225
|
+
return { ...base, subjects: [] };
|
|
226
|
+
};
|
|
227
|
+
/** The parallel path for a mneme bank's `events.jsonl` rows (the human-readable memory log, distinct from that bank's `causal.jsonl`). */
|
|
228
|
+
export const buildBankLogRecord = (event, bankName) => {
|
|
229
|
+
const agentId = event.principal.agentId;
|
|
230
|
+
return {
|
|
231
|
+
eventId: event.id,
|
|
232
|
+
authority: "mneme",
|
|
233
|
+
streamId: bankRef(bankName),
|
|
234
|
+
seq: event.seq ?? 0,
|
|
235
|
+
type: event.type,
|
|
236
|
+
viewClass: viewClassForBankLogType(event.type),
|
|
237
|
+
recordedAt: event.createdAt,
|
|
238
|
+
causeIds: event.parentEventIds ?? [],
|
|
239
|
+
actor: agentId,
|
|
240
|
+
subjects: [bankRef(bankName), agentRef(agentId)],
|
|
241
|
+
text: event.content.text,
|
|
242
|
+
payload: event.content,
|
|
243
|
+
};
|
|
244
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { RawTranscriptMessage } from "./runViewModelTypes.js";
|
|
2
|
+
import type { ElementRef } from "./runTimelineTypes.js";
|
|
3
|
+
/**
|
|
4
|
+
* The small, generic `ElementRef`/string helpers `runTimeline.ts` (the
|
|
5
|
+
* orchestrator) and `runTimelineRecords.ts` (the per-authority record
|
|
6
|
+
* builders) both need — split out so neither file has to import the other
|
|
7
|
+
* just for a one-line ref constructor (`AGENTS.md`: small composable
|
|
8
|
+
* modules, split before 400 lines).
|
|
9
|
+
*/
|
|
10
|
+
export declare const agentRef: (id: string) => ElementRef;
|
|
11
|
+
export declare const roomRef: (network: string, room: string) => ElementRef;
|
|
12
|
+
export declare const bankRef: (bank: string) => ElementRef;
|
|
13
|
+
export declare const variableRef: (id: string) => ElementRef;
|
|
14
|
+
/** Inverse of `roomRef`: splits a `room:<network>:<room>` ref back into its parts. `undefined` for anything else. */
|
|
15
|
+
export declare const parseRoomRef: (ref: ElementRef) => {
|
|
16
|
+
networkId: string;
|
|
17
|
+
roomId: string;
|
|
18
|
+
} | undefined;
|
|
19
|
+
/** Strips a ref's `<kind>:` prefix, e.g. `agent:luna-shadow` -> `luna-shadow`. Refs with no `:` pass through unchanged. */
|
|
20
|
+
export declare const stripRefPrefix: (ref: ElementRef) => string;
|
|
21
|
+
export declare const isDefined: <T>(value: T | undefined) => value is T;
|
|
22
|
+
export declare const stringField: (record: Record<string, unknown> | undefined, key: string) => string | undefined;
|
|
23
|
+
export declare const messageText: (message: RawTranscriptMessage) => string;
|
|
24
|
+
export declare const agentIdFromStreamId: (streamId: string) => string | undefined;
|
|
25
|
+
export declare const networkIdFromStreamId: (streamId: string) => string | undefined;
|
|
26
|
+
export declare const bankFromRelativePath: (relativePath: string) => string | undefined;
|
|
27
|
+
//# sourceMappingURL=runTimelineRefs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runTimelineRefs.d.ts","sourceRoot":"","sources":["../../src/view/runTimelineRefs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD;;;;;;GAMG;AAEH,eAAO,MAAM,QAAQ,GAAI,IAAI,MAAM,KAAG,UAA2B,CAAC;AAClE,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,EAAE,MAAM,MAAM,KAAG,UAAuC,CAAC;AAChG,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,KAAG,UAA4B,CAAC;AACpE,eAAO,MAAM,WAAW,GAAI,IAAI,MAAM,KAAG,UAA8B,CAAC;AAExE,qHAAqH;AACrH,eAAO,MAAM,YAAY,GAAI,KAAK,UAAU,KAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAGtF,CAAC;AAEF,2HAA2H;AAC3H,eAAO,MAAM,cAAc,GAAI,KAAK,UAAU,KAAG,MAAqE,CAAC;AAEvH,eAAO,MAAM,SAAS,GAAI,CAAC,EAAG,OAAO,CAAC,GAAG,SAAS,KAAG,KAAK,IAAI,CAAwB,CAAC;AAEvF,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,KAAK,MAAM,KAAG,MAAM,GAAG,SAG/F,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,SAAS,oBAAoB,KAAG,MACI,CAAC;AAEjE,eAAO,MAAM,mBAAmB,GAAI,UAAU,MAAM,KAAG,MAAM,GAAG,SAAiD,CAAC;AAElH,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,KAAG,MAAM,GAAG,SAAmD,CAAC;AAEtH,eAAO,MAAM,oBAAoB,GAAI,cAAc,MAAM,KAAG,MAAM,GAAG,SAGpE,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
/**
|
|
3
|
+
* The small, generic `ElementRef`/string helpers `runTimeline.ts` (the
|
|
4
|
+
* orchestrator) and `runTimelineRecords.ts` (the per-authority record
|
|
5
|
+
* builders) both need — split out so neither file has to import the other
|
|
6
|
+
* just for a one-line ref constructor (`AGENTS.md`: small composable
|
|
7
|
+
* modules, split before 400 lines).
|
|
8
|
+
*/
|
|
9
|
+
export const agentRef = (id) => `agent:${id}`;
|
|
10
|
+
export const roomRef = (network, room) => `room:${network}:${room}`;
|
|
11
|
+
export const bankRef = (bank) => `bank:${bank}`;
|
|
12
|
+
export const variableRef = (id) => `variable:${id}`;
|
|
13
|
+
/** Inverse of `roomRef`: splits a `room:<network>:<room>` ref back into its parts. `undefined` for anything else. */
|
|
14
|
+
export const parseRoomRef = (ref) => {
|
|
15
|
+
const match = ref.match(/^room:([^:]+):(.+)$/u);
|
|
16
|
+
return match ? { networkId: match[1], roomId: match[2] } : undefined;
|
|
17
|
+
};
|
|
18
|
+
/** Strips a ref's `<kind>:` prefix, e.g. `agent:luna-shadow` -> `luna-shadow`. Refs with no `:` pass through unchanged. */
|
|
19
|
+
export const stripRefPrefix = (ref) => (ref.includes(":") ? ref.slice(ref.indexOf(":") + 1) : ref);
|
|
20
|
+
export const isDefined = (value) => value !== undefined;
|
|
21
|
+
export const stringField = (record, key) => {
|
|
22
|
+
const value = record?.[key];
|
|
23
|
+
return typeof value === "string" ? value : undefined;
|
|
24
|
+
};
|
|
25
|
+
export const messageText = (message) => message.parts.find((part) => part.kind === "text")?.text ?? "";
|
|
26
|
+
export const agentIdFromStreamId = (streamId) => streamId.match(/^agent:(.+)$/u)?.[1];
|
|
27
|
+
export const networkIdFromStreamId = (streamId) => streamId.match(/^network:(.+)$/u)?.[1];
|
|
28
|
+
export const bankFromRelativePath = (relativePath) => {
|
|
29
|
+
const segments = relativePath.split(path.sep);
|
|
30
|
+
return segments[0] === "raw" && segments[1] === "mneme" ? segments[2] : undefined;
|
|
31
|
+
};
|