@noopolis/daimon 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/README.md +141 -5
  2. package/dist/core/siblingBuildFreshness.d.ts +21 -0
  3. package/dist/core/siblingBuildFreshness.d.ts.map +1 -0
  4. package/dist/core/siblingBuildFreshness.js +25 -0
  5. package/dist/core/types.d.ts +20 -1
  6. package/dist/core/types.d.ts.map +1 -1
  7. package/dist/examples/exampleCausalId.d.ts +3 -0
  8. package/dist/examples/exampleCausalId.d.ts.map +1 -0
  9. package/dist/examples/exampleCausalId.js +8 -0
  10. package/dist/examples/jungian-play-org.d.ts +2 -0
  11. package/dist/examples/jungian-play-org.d.ts.map +1 -0
  12. package/dist/examples/jungian-play-org.js +281 -0
  13. package/dist/examples/jungian-triad-org.d.ts +2 -0
  14. package/dist/examples/jungian-triad-org.d.ts.map +1 -0
  15. package/dist/examples/jungian-triad-org.js +281 -0
  16. package/dist/examples/jungianConversationPlan.d.ts +10 -0
  17. package/dist/examples/jungianConversationPlan.d.ts.map +1 -0
  18. package/dist/examples/jungianConversationPlan.js +64 -0
  19. package/dist/examples/jungianPiRepresentative.d.ts +36 -0
  20. package/dist/examples/jungianPiRepresentative.d.ts.map +1 -0
  21. package/dist/examples/jungianPiRepresentative.js +81 -0
  22. package/dist/examples/jungianPlayAgent.d.ts +36 -0
  23. package/dist/examples/jungianPlayAgent.d.ts.map +1 -0
  24. package/dist/examples/jungianPlayAgent.js +111 -0
  25. package/dist/examples/jungianProfiles.d.ts +34 -0
  26. package/dist/examples/jungianProfiles.d.ts.map +1 -0
  27. package/dist/examples/jungianProfiles.js +190 -0
  28. package/dist/examples/jungianTrace.d.ts +47 -0
  29. package/dist/examples/jungianTrace.d.ts.map +1 -0
  30. package/dist/examples/jungianTrace.js +101 -0
  31. package/dist/examples/jungianTriadProfiles.d.ts +35 -0
  32. package/dist/examples/jungianTriadProfiles.d.ts.map +1 -0
  33. package/dist/examples/jungianTriadProfiles.js +81 -0
  34. package/dist/examples/pi-agent.js +3 -2
  35. package/dist/examples/pi-memory-org.d.ts +2 -0
  36. package/dist/examples/pi-memory-org.d.ts.map +1 -0
  37. package/dist/examples/pi-memory-org.js +231 -0
  38. package/dist/index.d.ts +2 -3
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +2 -3
  41. package/dist/mcp/toolServer.d.ts +14 -0
  42. package/dist/mcp/toolServer.d.ts.map +1 -0
  43. package/dist/mcp/toolServer.js +105 -0
  44. package/dist/observability/causalEvents.d.ts +118 -0
  45. package/dist/observability/causalEvents.d.ts.map +1 -0
  46. package/dist/observability/causalEvents.js +135 -0
  47. package/dist/observability/controlCausal.d.ts +117 -0
  48. package/dist/observability/controlCausal.d.ts.map +1 -0
  49. package/dist/observability/controlCausal.js +107 -0
  50. package/dist/observability/emitCausalFixture.d.ts +25 -0
  51. package/dist/observability/emitCausalFixture.d.ts.map +1 -0
  52. package/dist/observability/emitCausalFixture.js +98 -0
  53. package/dist/observability/index.d.ts +4 -0
  54. package/dist/observability/index.d.ts.map +1 -0
  55. package/dist/observability/index.js +3 -0
  56. package/dist/observability/orgObserver.d.ts +98 -0
  57. package/dist/observability/orgObserver.d.ts.map +1 -0
  58. package/dist/observability/orgObserver.js +181 -0
  59. package/dist/pi/cliSession.d.ts +46 -0
  60. package/dist/pi/cliSession.d.ts.map +1 -0
  61. package/dist/pi/cliSession.js +224 -0
  62. package/dist/pi/index.d.ts +9 -0
  63. package/dist/pi/index.d.ts.map +1 -0
  64. package/dist/pi/index.js +8 -0
  65. package/dist/pi/memoryTools.d.ts +69 -0
  66. package/dist/pi/memoryTools.d.ts.map +1 -0
  67. package/dist/pi/memoryTools.js +190 -0
  68. package/dist/pi/modelRegistry.d.ts +13 -0
  69. package/dist/pi/modelRegistry.d.ts.map +1 -0
  70. package/dist/pi/modelRegistry.js +19 -0
  71. package/dist/pi/piAgentHandle.d.ts +45 -0
  72. package/dist/pi/piAgentHandle.d.ts.map +1 -0
  73. package/dist/pi/piAgentHandle.js +324 -0
  74. package/dist/pi/piAgentWakeSupport.d.ts +68 -0
  75. package/dist/pi/piAgentWakeSupport.d.ts.map +1 -0
  76. package/dist/pi/piAgentWakeSupport.js +147 -0
  77. package/dist/pi/piHarness.d.ts +36 -2
  78. package/dist/pi/piHarness.d.ts.map +1 -1
  79. package/dist/pi/piHarness.js +100 -127
  80. package/dist/pi/prompts.d.ts +9 -0
  81. package/dist/pi/prompts.d.ts.map +1 -0
  82. package/dist/pi/prompts.js +39 -0
  83. package/dist/pi/rawTrainingCapture.d.ts +59 -0
  84. package/dist/pi/rawTrainingCapture.d.ts.map +1 -0
  85. package/dist/pi/rawTrainingCapture.js +175 -0
  86. package/dist/pi/turnCausal.d.ts +73 -0
  87. package/dist/pi/turnCausal.d.ts.map +1 -0
  88. package/dist/pi/turnCausal.js +75 -0
  89. package/dist/pi/turnTrace.d.ts +128 -0
  90. package/dist/pi/turnTrace.d.ts.map +1 -0
  91. package/dist/pi/turnTrace.js +141 -0
  92. package/dist/pi/wakeAcceptance.d.ts +49 -0
  93. package/dist/pi/wakeAcceptance.d.ts.map +1 -0
  94. package/dist/pi/wakeAcceptance.js +281 -0
  95. package/dist/pi/wakeAcceptanceFs.d.ts +44 -0
  96. package/dist/pi/wakeAcceptanceFs.d.ts.map +1 -0
  97. package/dist/pi/wakeAcceptanceFs.js +318 -0
  98. package/dist/pi/wakeAcceptanceSchema.d.ts +75 -0
  99. package/dist/pi/wakeAcceptanceSchema.d.ts.map +1 -0
  100. package/dist/pi/wakeAcceptanceSchema.js +265 -0
  101. package/dist/pi/wakeModes.d.ts +9 -0
  102. package/dist/pi/wakeModes.d.ts.map +1 -0
  103. package/dist/pi/wakeModes.js +19 -0
  104. package/dist/pi/worldNudge.d.ts +22 -0
  105. package/dist/pi/worldNudge.d.ts.map +1 -0
  106. package/dist/pi/worldNudge.js +62 -0
  107. package/dist/pi/worldToolProtocol.d.ts +13 -0
  108. package/dist/pi/worldToolProtocol.d.ts.map +1 -0
  109. package/dist/pi/worldToolProtocol.js +49 -0
  110. package/dist/pi/worldTools.d.ts +32 -0
  111. package/dist/pi/worldTools.d.ts.map +1 -0
  112. package/dist/pi/worldTools.js +373 -0
  113. package/dist/pi/worldTrajectory.d.ts +52 -0
  114. package/dist/pi/worldTrajectory.d.ts.map +1 -0
  115. package/dist/pi/worldTrajectory.js +131 -0
  116. package/package.json +23 -4
package/README.md CHANGED
@@ -5,9 +5,19 @@ Daimon is the Noopolis-native per-agent runtime harness.
5
5
  It defines a small per-agent contract and currently implements that contract on
6
6
  top of Pi. A Daimon runs one harnessed agent inside a caller-prepared workspace.
7
7
 
8
- Spawnfile should own orgs, nested teams, schedules, Moltnet wiring, workspace
9
- resource compilation, and the app that starts many harnessed agents. This package
10
- should not know what an org is.
8
+ Spawnfile compiles and deploys orgs, nested teams, member-owned schedules,
9
+ Moltnet wiring, and workspace resources. Daimon executes one agent runtime: it
10
+ accepts a wake selected by that runtime's organization policy and runs one
11
+ turn. It does not know the org graph, schedule other agents, or let Simfile or
12
+ a world service trigger cognition.
13
+
14
+ For a world-capable `kind: every` wake, the harness starts without a decision
15
+ token and privately calls `world_claim` before exposing any other world tool.
16
+ The claim binds authority to the schedule wake's run/request/wake identity; the
17
+ opaque token stays inside the harness. Subsequent observe/affordance/action
18
+ calls carry it without placing it in the model prompt or tool schema. Optional
19
+ world recommendations are ordinary observation fields discovered after the
20
+ independent wake and claim—they are never Daimon wake inputs.
11
21
 
12
22
  ## Install
13
23
 
@@ -15,10 +25,55 @@ should not know what an org is.
15
25
  npm install @noopolis/daimon
16
26
  ```
17
27
 
28
+ The latest published version is 0.1.1; this README describes the source tree (0.1.2).
29
+
30
+ For Pi agents with memory enabled, install Mneme too:
31
+
32
+ ```bash
33
+ npm install @noopolis/daimon @noopolis/mneme
34
+ ```
35
+
36
+ During local incubation, use the sibling Mneme checkout:
37
+
38
+ ```json
39
+ {
40
+ "devDependencies": {
41
+ "@noopolis/mneme": "file:../mneme"
42
+ }
43
+ }
44
+ ```
45
+
46
+ Pi-specific exports live under the Pi subpath:
47
+
48
+ ```ts
49
+ import { PiHarnessAdapter } from "@noopolis/daimon/pi";
50
+ ```
51
+
52
+ By default, the in-process Mneme runtime uses the same path as each agent's
53
+ `runtimeHomePath`. If you need agents to keep separate Pi/runtime directories but
54
+ share one memory bank, pass an explicit `memory.runtimeHomePath` in
55
+ `PiHarnessOptions`.
56
+
57
+ ```ts
58
+ const adapter = new PiHarnessAdapter({
59
+ authPath: "/tmp/daimon-auth.json",
60
+ memory: {
61
+ runtimeHomePath: "/shared/memory/bank"
62
+ }
63
+ });
64
+ ```
65
+
66
+ Pi agents receive Mneme tools in awake mode for normal work. Dream wakes use a
67
+ fresh one-off Pi session under `sessions/dream/<wake-id>-<random>` and inject
68
+ the Mneme dream guidance instead. Daimon does not automatically record every
69
+ turn as memory; agents write memories only by calling Mneme tools such as
70
+ `memory_register`, `memory_summarize`, and `memory_forget`.
71
+
18
72
  ## Tests
19
73
 
20
- The package has a non-live test suite for auth seeding and Pi model config
21
- generation:
74
+ The package has a non-live test suite covering auth seeding, Pi model config
75
+ generation, the harness contract, memory tool wiring, wake and turn traces, and
76
+ the org observer:
22
77
 
23
78
  ```bash
24
79
  npm test
@@ -46,11 +101,92 @@ upstream-documented dummy `ollama` value.
46
101
  The Pi E2E uses the local Codex CLI subscription auth file to seed an ignored Pi
47
102
  `auth.json` under `.runtime/`.
48
103
 
104
+ These are live runs: they spend real tokens and require local engine auth
105
+ (`~/.codex/auth.json` for Pi/Codex; mixed-engine and triad additionally need
106
+ authenticated `grok` and `agy` CLIs on PATH). They are not part of `npm test`.
107
+
49
108
  ```bash
50
109
  npm install
51
110
  npm run e2e:pi-agent
111
+ npm run e2e:pi-memory-org
112
+ npm run e2e:mixed-engine-org
113
+ npm run e2e:jungian-play-org
114
+ npm run e2e:jungian-triad-org
52
115
  ```
53
116
 
54
117
  The example starts two harnessed Pi agents from plain caller code. The example
55
118
  creates the workspaces and shared resource itself to demonstrate the intended
56
119
  boundary: the caller prepares files, the harness runs agent turns.
120
+
121
+ The memory-org example starts three harnessed Pi agents, gives each agent a
122
+ private marker memory, clears Pi session history, then runs a room-style recall
123
+ conversation. It restarts one agent again before the final check, so the final
124
+ answer must come from Daimon's persisted memory rather than Pi's live chat
125
+ session.
126
+
127
+ The mixed-engine example starts a small org backed by real local CLIs:
128
+ Navigator uses Codex, Cartographer uses Grok, and Sentinel uses Agy. Each engine
129
+ invents its own private signal, then the room conversation verifies that later
130
+ turns recall those LLM-generated signals through Daimon memory.
131
+
132
+ The Jungian play example starts two selves as characters in a play. Each self
133
+ has archetype voices such as Persona, Shadow, Anima/Animus, Wise One, Great
134
+ Mother, Hero, and Trickster. The inner voices run first, the representative self
135
+ then speaks externally, and the run writes play traces plus memory/latency
136
+ telemetry under `.runtime/jungian-play-org/`.
137
+
138
+ The Jungian triad example uses three complete Jungian selves in one
139
+ conversation: Maya speaks through Codex CLI, Leo speaks through Grok, and Priya
140
+ speaks through a Pi agent seeded from local Codex subscription auth. All three
141
+ selves carry the same full archetype set, rotated through the run so every
142
+ archetype gets consulted.
143
+
144
+ ## Design Notes
145
+
146
+ - `MEMORY-SYSTEM.md` describes the implemented scoped memory runtime.
147
+ - `ENGINE-SYSTEM.md` describes the engine abstraction plan: Pi, local/API
148
+ model providers, and CLI-backed engines such as `codex`, `claude`, `grok`,
149
+ and `agy`.
150
+ - Mneme is a sibling package, `@noopolis/mneme`, published separately and used
151
+ by Daimon in-process for Pi agents. Other runtimes can use Mneme through its
152
+ MCP server. The agent-facing tools stay named `memory_search`,
153
+ `memory_register`, and `memory.*` at the protocol boundary because those names
154
+ are clearer to agents.
155
+
156
+ ## Runtime Artifact Image
157
+
158
+ Daimon defines a local copy-only runtime artifact image build for Spawnfile:
159
+
160
+ ```bash
161
+ npm run image:runtime:local
162
+ ```
163
+
164
+ Status: this build currently fails against the public npm registry. The
165
+ Dockerfile pins `@noopolis/daimon@0.1.2` and `@noopolis/mneme@0.1.1`, and
166
+ neither is published yet (registry has daimon 0.1.1 and mneme 0.1.0). Works
167
+ only after those versions publish or against a registry that has them. Treat
168
+ as pending publish.
169
+
170
+ This creates:
171
+
172
+ ```text
173
+ noopolis/spawnfile-runtime-daimon:0.1.2-local
174
+ ```
175
+
176
+ The image is not a full organization image and is not intended to be run
177
+ directly. It contains only:
178
+
179
+ ```text
180
+ /opt/spawnfile/runtime-installs/daimon
181
+ ```
182
+
183
+ Spawnfile can copy that path into generated organization images:
184
+
185
+ ```bash
186
+ SPAWNFILE_DAIMON_RUNTIME_IMAGE=noopolis/spawnfile-runtime-daimon:0.1.2-local \
187
+ spawnfile build ./agentic-org
188
+ ```
189
+
190
+ This keeps mixed-runtime organizations composable: a generated image can copy
191
+ Daimon, OpenClaw, PicoClaw, or any future runtime artifact independently instead
192
+ of depending on one prebuilt image for every runtime combination.
@@ -0,0 +1,21 @@
1
+ export type SiblingFileFact = {
2
+ path: string;
3
+ mtimeMs: number;
4
+ };
5
+ export type SiblingBuildFacts = {
6
+ packageName: string;
7
+ packageDirectory: string;
8
+ hasSourceDirectory: boolean;
9
+ sourceFiles: SiblingFileFact[];
10
+ outputFiles: SiblingFileFact[];
11
+ };
12
+ export type SiblingBuildFreshness = {
13
+ packageName: string;
14
+ linked: boolean;
15
+ sourcesScanned: number;
16
+ outputsScanned: number;
17
+ ok: boolean;
18
+ message?: string;
19
+ };
20
+ export declare function checkSiblingBuildFreshness(facts: SiblingBuildFacts): SiblingBuildFreshness;
21
+ //# sourceMappingURL=siblingBuildFreshness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"siblingBuildFreshness.d.ts","sourceRoot":"","sources":["../../src/core/siblingBuildFreshness.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,WAAW,EAAE,eAAe,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAIF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,iBAAiB,GAAG,qBAAqB,CA2B1F"}
@@ -0,0 +1,25 @@
1
+ const excludedSource = /(?:\.test\.ts|\.test-helper\.ts|\.d\.ts)$/u;
2
+ export function checkSiblingBuildFreshness(facts) {
3
+ if (!facts.hasSourceDirectory) {
4
+ return { packageName: facts.packageName, linked: false, sourcesScanned: 0, outputsScanned: 0, ok: true };
5
+ }
6
+ const sourceFiles = facts.sourceFiles.filter(({ path }) => !excludedSource.test(path));
7
+ const outputFiles = facts.outputFiles.filter(({ path }) => path.endsWith(".js"));
8
+ const command = `run "npm run build" in ${facts.packageDirectory}`;
9
+ if (sourceFiles.length === 0) {
10
+ return failure(facts.packageName, sourceFiles.length, outputFiles.length, `linked package ${facts.packageName} scanned zero source files; ${command}`);
11
+ }
12
+ if (outputFiles.length === 0) {
13
+ return failure(facts.packageName, sourceFiles.length, outputFiles.length, `linked package ${facts.packageName} has no emitted JavaScript; ${command}`);
14
+ }
15
+ const newestSource = sourceFiles.reduce((newest, file) => file.mtimeMs > newest.mtimeMs ? file : newest);
16
+ const oldestOutput = outputFiles.reduce((oldest, file) => file.mtimeMs < oldest.mtimeMs ? file : oldest);
17
+ if (newestSource.mtimeMs > oldestOutput.mtimeMs) {
18
+ return failure(facts.packageName, sourceFiles.length, outputFiles.length, `linked package ${facts.packageName} is stale: newest source ${newestSource.path} (${newestSource.mtimeMs}) `
19
+ + `is newer than oldest output ${oldestOutput.path} (${oldestOutput.mtimeMs}); ${command}`);
20
+ }
21
+ return { packageName: facts.packageName, linked: true, sourcesScanned: sourceFiles.length, outputsScanned: outputFiles.length, ok: true };
22
+ }
23
+ function failure(packageName, sourcesScanned, outputsScanned, message) {
24
+ return { packageName, linked: true, sourcesScanned, outputsScanned, ok: false, message };
25
+ }
@@ -20,11 +20,30 @@ export interface HarnessModelSpec {
20
20
  name: string;
21
21
  provider: string;
22
22
  }
23
+ export interface WakeDeliveryMetadata {
24
+ eventId: string;
25
+ sender: string;
26
+ target: string;
27
+ contextId: string;
28
+ }
23
29
  export interface WakeEvent {
24
30
  id: string;
25
- kind: "manual" | "message" | "schedule";
31
+ kind: "manual" | "message" | "schedule" | "dream";
26
32
  from?: string;
27
33
  text: string;
34
+ context?: {
35
+ networkId?: string;
36
+ roomId?: string;
37
+ teamId?: string;
38
+ taskId?: string;
39
+ roleId?: string;
40
+ from?: string;
41
+ pairPeers?: string[];
42
+ artifactPaths?: string[];
43
+ };
44
+ delivery?: WakeDeliveryMetadata;
45
+ /** Exact transport body retained outside the runtime-enriched model prompt. */
46
+ transportText?: string;
28
47
  }
29
48
  export interface WakeResult {
30
49
  agentId: AgentId;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,WAAW,GAAG,QAAQ,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;KACtD,CAAC;IACF,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,IAAI,WAAW,CAAC;IACtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAC1D"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,WAAW,GAAG,QAAQ,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;KACtD,CAAC;IACF,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;KAC1B,CAAC;IACF,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,IAAI,WAAW,CAAC;IACtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAC1D"}
@@ -0,0 +1,3 @@
1
+ /** Namespaces caller-authored example wakes for the shared causal contract. */
2
+ export declare const exampleCausalId: (localId: string) => string;
3
+ //# sourceMappingURL=exampleCausalId.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exampleCausalId.d.ts","sourceRoot":"","sources":["../../src/examples/exampleCausalId.ts"],"names":[],"mappings":"AAEA,+EAA+E;AAC/E,eAAO,MAAM,eAAe,GAAI,SAAS,MAAM,KAAG,MAKjD,CAAC"}
@@ -0,0 +1,8 @@
1
+ const LOCAL_CAUSAL_ID = /^[a-z0-9][a-z0-9._-]{0,255}$/u;
2
+ /** Namespaces caller-authored example wakes for the shared causal contract. */
3
+ export const exampleCausalId = (localId) => {
4
+ if (!LOCAL_CAUSAL_ID.test(localId)) {
5
+ throw new Error("Daimon example causal id must be a bounded local id");
6
+ }
7
+ return `daimon:${localId}`;
8
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=jungian-play-org.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jungian-play-org.d.ts","sourceRoot":"","sources":["../../src/examples/jungian-play-org.ts"],"names":[],"mappings":""}
@@ -0,0 +1,281 @@
1
+ import { rm, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { JsonlMemoryStore } from "@noopolis/mneme";
5
+ import { OrgObserver } from "../observability/index.js";
6
+ import { beatsFor, defaultDialogueTurns, selectVoicesForBeat } from "./jungianConversationPlan.js";
7
+ import { exampleCausalId } from "./exampleCausalId.js";
8
+ import { JungianVoice, runLimited } from "./jungianPlayAgent.js";
9
+ import { jungianSelves, playScenario } from "./jungianProfiles.js";
10
+ import { JungianTrace, parseInnerUsed, parseSpeakLine } from "./jungianTrace.js";
11
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ const daimonRoot = path.resolve(__dirname, "../..");
13
+ const runtimeRoot = path.join(daimonRoot, ".runtime", "jungian-play-org");
14
+ const runId = `run-${Date.now().toString(36)}`;
15
+ const councilConcurrency = Number.parseInt(process.env.DAIMON_JUNGIAN_COUNCIL_CONCURRENCY ?? "3", 10);
16
+ const dialogueTurnCount = Math.max(10, Number.parseInt(process.env.DAIMON_JUNGIAN_TURNS ?? String(defaultDialogueTurns), 10));
17
+ const voicesPerTurn = Math.max(1, Number.parseInt(process.env.DAIMON_JUNGIAN_VOICES_PER_TURN ?? "2", 10));
18
+ const observer = new OrgObserver({ orgId: "jungian-play-org", runId });
19
+ const trace = new JungianTrace({ runId, title: playScenario.title });
20
+ const roomContext = {
21
+ networkId: "jungian-sitcom",
22
+ roomId: "community-kitchen",
23
+ teamId: "jungian-play-org",
24
+ participants: jungianSelves.map((self) => self.representative.id)
25
+ };
26
+ const observeTurn = (turn) => {
27
+ observer.recordTurn({
28
+ agent: turn.voice.id,
29
+ engine: turn.voice.engine,
30
+ event: turn.event.id,
31
+ eventText: turn.event.text,
32
+ totalMs: turn.totalMs,
33
+ memoryPrepareMs: turn.memoryPrepareMs,
34
+ engineMs: turn.engineResult.durationMs,
35
+ memoryRecordMs: turn.memoryRecordMs,
36
+ promptChars: turn.engineResult.promptChars,
37
+ outputChars: turn.engineResult.outputChars,
38
+ outputText: turn.outputText,
39
+ recall: turn.recall
40
+ });
41
+ };
42
+ const archetypeInstructions = (self, voice) => [
43
+ `You are ${voice.name}, the ${voice.archetype} voice inside ${self.name}.`,
44
+ `Agenda: ${voice.agenda}`,
45
+ `Fear: ${voice.fear}`,
46
+ `Gift: ${voice.gift}`,
47
+ `Wound: ${voice.wound}`,
48
+ "You are an inner counselor, not the public speaker.",
49
+ "Keep counsel psychologically specific but grounded in ordinary human behavior.",
50
+ "No mythic language, no grand symbols, no fantasy imagery.",
51
+ "Use recalled memory if the same conversation pattern returns."
52
+ ];
53
+ const representativeInstructions = (self) => [
54
+ `You are ${self.representative.name}, the outward speaking Self for ${self.name}.`,
55
+ `Play role: ${self.playRole}`,
56
+ `Public mask: ${self.publicMask}`,
57
+ `Backstory: ${self.backstory}`,
58
+ `Core conflict: ${self.conflict}`,
59
+ `Secret want: ${self.secretWant}`,
60
+ `Style: ${self.representative.style}`,
61
+ "You speak externally after listening to inner archetypal counsel.",
62
+ "Sound like a real person in a grounded TV drama or workplace sitcom.",
63
+ "Use short, conversational lines. No speeches. No poetic metaphors.",
64
+ "Do not mention the machinery of prompts, engines, memory, or tests.",
65
+ "Return the requested SPEAK/STAGE/INNER_USED shape exactly."
66
+ ];
67
+ const buildSelf = (profile) => ({
68
+ profile,
69
+ representative: new JungianVoice({
70
+ id: profile.representative.id,
71
+ name: profile.representative.name,
72
+ selfId: profile.id,
73
+ selfName: profile.name,
74
+ engine: profile.engine,
75
+ runtimeRoot,
76
+ instructions: representativeInstructions(profile)
77
+ }),
78
+ archetypes: profile.voices.map((voice) => new JungianVoice({
79
+ id: `${profile.id}-${voice.id}`,
80
+ name: voice.name,
81
+ selfId: profile.id,
82
+ selfName: profile.name,
83
+ archetype: voice.archetype,
84
+ engine: voice.engine,
85
+ runtimeRoot,
86
+ instructions: archetypeInstructions(profile, voice)
87
+ }))
88
+ });
89
+ const selves = jungianSelves.map(buildSelf);
90
+ const transcriptText = (transcript) => transcript.length === 0 ? "(no external dialogue yet)" : transcript.join("\n");
91
+ const councilPrompt = (self, focus, transcript) => [
92
+ `Scene: ${playScenario.title}`,
93
+ `Premise: ${playScenario.premise}`,
94
+ `Set: ${playScenario.openingImage}`,
95
+ "",
96
+ `Self under counsel: ${self.name}`,
97
+ `Current focus: ${focus}`,
98
+ "",
99
+ "External dialogue so far:",
100
+ transcriptText(transcript),
101
+ "",
102
+ "Respond as this archetype only.",
103
+ "Keep it plain and practical. No poetic stage images.",
104
+ "Use exactly this shape:",
105
+ "ARCHETYPE: <archetype name>",
106
+ "COUNSEL: <one short practical note>",
107
+ "RISK: <what could go wrong emotionally>",
108
+ "LINE_NOTE: <what the representative should sound like>"
109
+ ].join("\n");
110
+ const representativePrompt = (self, focus, transcript, counsel) => [
111
+ `Scene: ${playScenario.title}`,
112
+ `Premise: ${playScenario.premise}`,
113
+ `Set: ${playScenario.openingImage}`,
114
+ "",
115
+ "External dialogue so far:",
116
+ transcriptText(transcript),
117
+ "",
118
+ `Current focus: ${focus}`,
119
+ "",
120
+ "Inner council counsel:",
121
+ ...counsel.map((turn) => `- ${turn.voice.id}: ${turn.outputText.replace(/\n/g, " ")}`),
122
+ "",
123
+ "Choose one natural next line of dialogue.",
124
+ "The line must sound like a normal person, not a symbol or narrator.",
125
+ "Keep SPEAK under 22 words. Avoid words like ledger, mercy, truth, blood, crown, soul, destiny, wound unless the transcript already used them.",
126
+ "Do not use Markdown, bullets, bold markers, or quotation marks inside SPEAK.",
127
+ "Use exactly this shape:",
128
+ "SPEAK: <one natural spoken line, without wrapping quotation marks>",
129
+ "STAGE: <one tiny normal action>",
130
+ `INNER_USED: <comma-separated ids from ${self.voices.map((voice) => voice.id).join(", ")}>`
131
+ ].join("\n");
132
+ const runCouncil = async (self, eventId, focus, transcript, voices) => {
133
+ console.log(`\n== ${self.profile.name} inner council: ${focus} ==`);
134
+ const turns = await runLimited(voices, councilConcurrency, async (voice) => {
135
+ const event = {
136
+ id: exampleCausalId(`${eventId}-${voice.config.id}`),
137
+ kind: "manual",
138
+ context: roomContext,
139
+ text: councilPrompt(self.profile, focus, transcript)
140
+ };
141
+ const turn = await voice.wake(event);
142
+ observeTurn(turn);
143
+ trace.addCounsel({
144
+ archetype: voice.config.archetype ?? "unknown",
145
+ engine: voice.config.engine,
146
+ event: event.id,
147
+ output: turn.outputText,
148
+ recallSelected: turn.recall.selectedEventIds.length,
149
+ self: self.profile.name,
150
+ voice: voice.config.id
151
+ });
152
+ console.log(`${voice.config.id}: ${turn.outputText.split("\n")[0]}`);
153
+ return turn;
154
+ });
155
+ return turns;
156
+ };
157
+ const runRepresentative = async (self, eventId, focus, transcript, counsel) => {
158
+ const event = {
159
+ id: exampleCausalId(eventId),
160
+ kind: "manual",
161
+ context: roomContext,
162
+ text: representativePrompt(self.profile, focus, transcript, counsel)
163
+ };
164
+ const turn = await self.representative.wake(event);
165
+ observeTurn(turn);
166
+ const used = parseInnerUsed(turn.outputText);
167
+ const selectedVoiceIds = new Set(counsel.flatMap((entry) => [
168
+ entry.voice.id,
169
+ entry.voice.id.replace(`${self.profile.id}-`, "")
170
+ ]));
171
+ const passed = used.some((voiceId) => selectedVoiceIds.has(voiceId));
172
+ observer.recordAssertion({
173
+ detail: `${self.profile.representative.id} should declare at least one selected inner voice used`,
174
+ event: event.id,
175
+ kind: "consultation",
176
+ passed
177
+ });
178
+ if (!passed) {
179
+ throw new Error(`${self.profile.representative.id} did not declare a selected INNER_USED voice:\n${turn.outputText}`);
180
+ }
181
+ trace.addDialogue({
182
+ engine: self.profile.engine,
183
+ event: event.id,
184
+ innerUsed: used,
185
+ output: turn.outputText,
186
+ recallSelected: turn.recall.selectedEventIds.length,
187
+ self: self.profile.name,
188
+ speaker: self.profile.representative.name
189
+ });
190
+ const line = `${self.profile.name}: ${parseSpeakLine(turn.outputText)}`;
191
+ transcript.push(line);
192
+ console.log(`\n${line}`);
193
+ return line;
194
+ };
195
+ const prepareAll = async () => {
196
+ await rm(runtimeRoot, { recursive: true, force: true });
197
+ await Promise.all(selves.flatMap((self) => [
198
+ self.representative.prepare(),
199
+ ...self.archetypes.map((voice) => voice.prepare())
200
+ ]));
201
+ await writeFile(path.join(runtimeRoot, "org.json"), JSON.stringify({
202
+ scenario: playScenario,
203
+ selves: jungianSelves.map((self) => ({
204
+ id: self.id,
205
+ name: self.name,
206
+ engine: self.engine,
207
+ representative: self.representative,
208
+ voices: self.voices.map((voice) => ({
209
+ id: voice.id,
210
+ archetype: voice.archetype,
211
+ engine: voice.engine,
212
+ name: voice.name
213
+ }))
214
+ }))
215
+ }, null, 2));
216
+ };
217
+ const writeMemoryCounts = async () => {
218
+ const rows = await Promise.all(selves.flatMap((self) => [
219
+ self.representative,
220
+ ...self.archetypes
221
+ ]).map(async (voice) => {
222
+ const events = await new JsonlMemoryStore(voice.runtimeHomePath).read();
223
+ const counts = events.reduce((memo, event) => {
224
+ memo[event.type] = (memo[event.type] ?? 0) + 1;
225
+ return memo;
226
+ }, {});
227
+ return {
228
+ voice: voice.config.id,
229
+ self: voice.config.selfId,
230
+ engine: voice.config.engine,
231
+ counts
232
+ };
233
+ }));
234
+ await writeFile(path.join(runtimeRoot, "play-memory-counts.jsonl"), `${rows.map((row) => JSON.stringify(row)).join("\n")}\n`);
235
+ };
236
+ const writePlaySummary = async () => {
237
+ const behavior = observer.behaviorSummary();
238
+ const byRole = observer.turns.reduce((memo, turn) => {
239
+ const role = turn.agent.endsWith("-self") ? "representative" : "archetype";
240
+ const current = memo[role] ?? { count: 0, engineMs: 0, recallSelected: 0 };
241
+ current.count += 1;
242
+ current.engineMs += turn.engineMs;
243
+ current.recallSelected += turn.recallSelected;
244
+ memo[role] = current;
245
+ return memo;
246
+ }, {});
247
+ await writeFile(path.join(runtimeRoot, "play-summary.json"), `${JSON.stringify({ behavior, by_role: byRole, run_id: runId, schema: "daimon.jungian-play.summary/v1" }, null, 2)}\n`);
248
+ };
249
+ const run = async () => {
250
+ await prepareAll();
251
+ const selfById = new Map(selves.map((self) => [self.profile.id, self]));
252
+ const transcript = [];
253
+ const beats = beatsFor(dialogueTurnCount);
254
+ for (const [index, beat] of beats.entries()) {
255
+ const self = selfById.get(beat.speakerId);
256
+ if (!self) {
257
+ throw new Error(`Unknown Jungian self ${beat.speakerId}`);
258
+ }
259
+ const selectedProfiles = selectVoicesForBeat(self.profile, index, voicesPerTurn);
260
+ const selectedIds = new Set(selectedProfiles.map((voice) => `${self.profile.id}-${voice.id}`));
261
+ const selectedVoices = self.archetypes.filter((voice) => selectedIds.has(voice.config.id));
262
+ const eventBase = `${self.profile.id}-turn-${String(index + 1).padStart(2, "0")}`;
263
+ const counsel = await runCouncil(self, `${eventBase}-council`, beat.focus, transcript, selectedVoices);
264
+ await runRepresentative(self, `${eventBase}-speaks`, beat.focus, transcript, counsel);
265
+ }
266
+ await observer.write(runtimeRoot);
267
+ await trace.write(runtimeRoot);
268
+ await writeMemoryCounts();
269
+ await writePlaySummary();
270
+ console.log("\nExternal dialogue:");
271
+ for (const line of transcript) {
272
+ console.log(line);
273
+ }
274
+ console.log(`\nTrace: ${path.join(runtimeRoot, "jungian-trace.md")}`);
275
+ console.log(`Telemetry: ${path.join(runtimeRoot, "trace.md")}`);
276
+ console.log("\ne2e:jungian-play-org ok");
277
+ };
278
+ run().catch((error) => {
279
+ console.error(error instanceof Error ? error.stack ?? error.message : String(error));
280
+ process.exitCode = 1;
281
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=jungian-triad-org.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jungian-triad-org.d.ts","sourceRoot":"","sources":["../../src/examples/jungian-triad-org.ts"],"names":[],"mappings":""}