@noopolis/daimon 0.1.1 → 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 (102) hide show
  1. package/README.md +54 -10
  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 +10 -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.js +3 -2
  11. package/dist/examples/jungian-triad-org.js +3 -2
  12. package/dist/examples/jungianPlayAgent.d.ts +1 -1
  13. package/dist/examples/jungianPlayAgent.d.ts.map +1 -1
  14. package/dist/examples/jungianPlayAgent.js +1 -1
  15. package/dist/examples/jungianProfiles.d.ts +1 -1
  16. package/dist/examples/jungianProfiles.d.ts.map +1 -1
  17. package/dist/examples/jungianTriadProfiles.d.ts +1 -1
  18. package/dist/examples/jungianTriadProfiles.d.ts.map +1 -1
  19. package/dist/examples/pi-agent.js +3 -2
  20. package/dist/examples/pi-memory-org.js +6 -5
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +1 -0
  24. package/dist/mcp/toolServer.d.ts +14 -0
  25. package/dist/mcp/toolServer.d.ts.map +1 -0
  26. package/dist/mcp/toolServer.js +105 -0
  27. package/dist/observability/causalEvents.d.ts +118 -0
  28. package/dist/observability/causalEvents.d.ts.map +1 -0
  29. package/dist/observability/causalEvents.js +135 -0
  30. package/dist/observability/controlCausal.d.ts +117 -0
  31. package/dist/observability/controlCausal.d.ts.map +1 -0
  32. package/dist/observability/controlCausal.js +107 -0
  33. package/dist/observability/emitCausalFixture.d.ts +25 -0
  34. package/dist/observability/emitCausalFixture.d.ts.map +1 -0
  35. package/dist/observability/emitCausalFixture.js +98 -0
  36. package/dist/observability/index.d.ts +2 -0
  37. package/dist/observability/index.d.ts.map +1 -1
  38. package/dist/observability/index.js +2 -0
  39. package/dist/pi/cliSession.d.ts +46 -0
  40. package/dist/pi/cliSession.d.ts.map +1 -0
  41. package/dist/pi/cliSession.js +224 -0
  42. package/dist/pi/index.d.ts +5 -0
  43. package/dist/pi/index.d.ts.map +1 -1
  44. package/dist/pi/index.js +5 -0
  45. package/dist/pi/memoryTools.d.ts +55 -1
  46. package/dist/pi/memoryTools.d.ts.map +1 -1
  47. package/dist/pi/memoryTools.js +144 -24
  48. package/dist/pi/modelRegistry.d.ts +13 -0
  49. package/dist/pi/modelRegistry.d.ts.map +1 -0
  50. package/dist/pi/modelRegistry.js +19 -0
  51. package/dist/pi/piAgentHandle.d.ts +45 -0
  52. package/dist/pi/piAgentHandle.d.ts.map +1 -0
  53. package/dist/pi/piAgentHandle.js +324 -0
  54. package/dist/pi/piAgentWakeSupport.d.ts +68 -0
  55. package/dist/pi/piAgentWakeSupport.d.ts.map +1 -0
  56. package/dist/pi/piAgentWakeSupport.js +147 -0
  57. package/dist/pi/piHarness.d.ts +30 -4
  58. package/dist/pi/piHarness.d.ts.map +1 -1
  59. package/dist/pi/piHarness.js +97 -255
  60. package/dist/pi/prompts.d.ts +9 -0
  61. package/dist/pi/prompts.d.ts.map +1 -0
  62. package/dist/pi/prompts.js +39 -0
  63. package/dist/pi/rawTrainingCapture.d.ts +59 -0
  64. package/dist/pi/rawTrainingCapture.d.ts.map +1 -0
  65. package/dist/pi/rawTrainingCapture.js +175 -0
  66. package/dist/pi/turnCausal.d.ts +73 -0
  67. package/dist/pi/turnCausal.d.ts.map +1 -0
  68. package/dist/pi/turnCausal.js +75 -0
  69. package/dist/pi/turnTrace.d.ts +128 -0
  70. package/dist/pi/turnTrace.d.ts.map +1 -0
  71. package/dist/pi/turnTrace.js +141 -0
  72. package/dist/pi/wakeAcceptance.d.ts +49 -0
  73. package/dist/pi/wakeAcceptance.d.ts.map +1 -0
  74. package/dist/pi/wakeAcceptance.js +281 -0
  75. package/dist/pi/wakeAcceptanceFs.d.ts +44 -0
  76. package/dist/pi/wakeAcceptanceFs.d.ts.map +1 -0
  77. package/dist/pi/wakeAcceptanceFs.js +318 -0
  78. package/dist/pi/wakeAcceptanceSchema.d.ts +75 -0
  79. package/dist/pi/wakeAcceptanceSchema.d.ts.map +1 -0
  80. package/dist/pi/wakeAcceptanceSchema.js +265 -0
  81. package/dist/pi/wakeModes.d.ts +9 -0
  82. package/dist/pi/wakeModes.d.ts.map +1 -0
  83. package/dist/pi/wakeModes.js +19 -0
  84. package/dist/pi/worldNudge.d.ts +22 -0
  85. package/dist/pi/worldNudge.d.ts.map +1 -0
  86. package/dist/pi/worldNudge.js +62 -0
  87. package/dist/pi/worldToolProtocol.d.ts +13 -0
  88. package/dist/pi/worldToolProtocol.d.ts.map +1 -0
  89. package/dist/pi/worldToolProtocol.js +49 -0
  90. package/dist/pi/worldTools.d.ts +32 -0
  91. package/dist/pi/worldTools.d.ts.map +1 -0
  92. package/dist/pi/worldTools.js +373 -0
  93. package/dist/pi/worldTrajectory.d.ts +52 -0
  94. package/dist/pi/worldTrajectory.d.ts.map +1 -0
  95. package/dist/pi/worldTrajectory.js +131 -0
  96. package/package.json +10 -13
  97. package/dist/examples/mixed-engine-org.d.ts +0 -2
  98. package/dist/examples/mixed-engine-org.d.ts.map +0 -1
  99. package/dist/examples/mixed-engine-org.js +0 -351
  100. package/dist/examples/mixedEngineCli.d.ts +0 -15
  101. package/dist/examples/mixedEngineCli.d.ts.map +0 -1
  102. package/dist/examples/mixedEngineCli.js +0 -174
@@ -1,228 +1,14 @@
1
1
  import { mkdir } from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { AuthStorage, createAgentSession, createExtensionRuntime, ModelRegistry, SessionManager, SettingsManager } from "@earendil-works/pi-coding-agent";
3
+ import { AuthStorage, createAgentSession, SessionManager, SettingsManager } from "@earendil-works/pi-coding-agent";
4
+ import { createMemoryRuntime } from "@noopolis/mneme";
4
5
  import { resolvePiHarnessModel } from "./modelConfig.js";
6
+ import { createPiModelRegistry } from "./modelRegistry.js";
5
7
  import { createPiMemoryTools, piMemoryToolNames } from "./memoryTools.js";
6
- import { createMemoryRuntime, memoryScopeId, readMemoryContext } from "@noopolis/mneme";
7
- const createModelRegistry = (authStorage, options) => {
8
- const registry = options.modelsPath
9
- ? ModelRegistry.create(authStorage, options.modelsPath)
10
- : ModelRegistry.inMemory(authStorage);
11
- if (!options.modelsPath && options.model?.endpoint) {
12
- const { modelsConfig } = resolvePiHarnessModel(options.model);
13
- for (const [provider, config] of Object.entries(modelsConfig.providers)) {
14
- registry.registerProvider(provider, {
15
- api: config.api,
16
- apiKey: config.apiKey,
17
- baseUrl: config.baseUrl,
18
- models: config.models
19
- });
20
- }
21
- }
22
- return registry;
23
- };
24
- const fallbackPacket = (input) => ({
25
- principal: {
26
- agentId: "unknown",
27
- scope: "global"
28
- },
29
- sections: [{ heading: "Wake event", text: formatWakePrompt(input) }],
30
- rawHint: "memory bypass active"
31
- });
32
- const extractOutputText = (chunks) => chunks.join("\n").trim();
33
- class PiAgentHandle {
34
- id;
35
- session;
36
- memory;
37
- memoryToolContext;
38
- state = "idle";
39
- lastWakeAt;
40
- lastError;
41
- wakeQueue = Promise.resolve();
42
- constructor(id, session, memory, memoryToolContext) {
43
- this.id = id;
44
- this.session = session;
45
- this.memory = memory;
46
- this.memoryToolContext = memoryToolContext;
47
- }
48
- async wake(event) {
49
- const queued = this.wakeQueue.then(() => this.runWake(event), () => this.runWake(event));
50
- this.wakeQueue = queued.then(() => undefined, () => undefined);
51
- return queued;
52
- }
53
- async runWake(event) {
54
- const startedAt = Date.now();
55
- const chunks = [];
56
- const toolEvents = [];
57
- this.state = "running";
58
- this.lastWakeAt = new Date().toISOString();
59
- this.lastError = undefined;
60
- const unsubscribe = this.session.subscribe((piEvent) => {
61
- if (piEvent && typeof piEvent === "object" && "type" in piEvent && piEvent.type !== "turn_end") {
62
- toolEvents.push(piEvent);
63
- }
64
- if (piEvent.type !== "turn_end") {
65
- return;
66
- }
67
- const message = piEvent.message;
68
- const content = message.content;
69
- if (typeof content === "string") {
70
- chunks.push(content);
71
- }
72
- else if (Array.isArray(content)) {
73
- chunks.push(content
74
- .filter((item) => {
75
- const candidate = item;
76
- return candidate.type === "text" && typeof candidate.text === "string";
77
- })
78
- .map((item) => item.text)
79
- .join(""));
80
- }
81
- });
82
- const memoryContext = readMemoryContext({
83
- kind: event.kind,
84
- id: event.id,
85
- from: event.from,
86
- text: event.text,
87
- context: event.context
88
- });
89
- const request = {
90
- eventId: event.id,
91
- kind: event.kind,
92
- text: event.text,
93
- from: event.from,
94
- context: memoryContext
95
- };
96
- let prepared;
97
- let promptText = formatWakePrompt(event);
98
- try {
99
- if (this.memory) {
100
- prepared = await this.memory.prepareTurn(request);
101
- promptText = prepared.promptText;
102
- if (this.memoryToolContext) {
103
- this.memoryToolContext.current = {
104
- wakeId: event.id,
105
- threadId: `${memoryContext.networkId ?? "local"}:${memoryContext.roomId ?? event.from ?? "manual"}`,
106
- principal: prepared.principal,
107
- conversationScope: memoryScopeId(prepared.principal),
108
- audienceKey: memoryContext.roomId ?? event.from ?? this.id,
109
- transport: "in_process"
110
- };
111
- }
112
- }
113
- await this.session.prompt(promptText, { expandPromptTemplates: false });
114
- this.state = "idle";
115
- const outputText = extractOutputText(chunks);
116
- if (this.memory) {
117
- const promptPacket = prepared?.packet ?? fallbackPacket(event);
118
- await this.memory.recordTurn({
119
- principal: {
120
- agentId: this.id,
121
- scope: prepared?.principal.scope ?? "global",
122
- qualifier: prepared?.principal.qualifier
123
- },
124
- prompt: {
125
- ...promptPacket,
126
- principal: {
127
- agentId: this.id,
128
- scope: prepared?.principal.scope ?? "global",
129
- qualifier: prepared?.principal.qualifier
130
- }
131
- },
132
- request,
133
- recall: prepared?.recall,
134
- result: "completed",
135
- outputText,
136
- toolEvents
137
- });
138
- }
139
- return {
140
- agentId: this.id,
141
- text: outputText,
142
- durationMs: Date.now() - startedAt
143
- };
144
- }
145
- catch (error) {
146
- this.state = "failed";
147
- this.lastError = error instanceof Error ? error.message : String(error);
148
- if (this.memory) {
149
- try {
150
- const promptPacket = prepared?.packet ?? fallbackPacket(event);
151
- await this.memory.recordTurn({
152
- principal: {
153
- agentId: this.id,
154
- scope: prepared?.principal.scope ?? "global",
155
- qualifier: prepared?.principal.qualifier
156
- },
157
- prompt: {
158
- ...promptPacket,
159
- principal: {
160
- agentId: this.id,
161
- scope: prepared?.principal.scope ?? "global",
162
- qualifier: prepared?.principal.qualifier
163
- }
164
- },
165
- request,
166
- recall: prepared?.recall,
167
- result: "failed",
168
- outputText: extractOutputText(chunks),
169
- toolEvents,
170
- error: this.lastError
171
- });
172
- }
173
- catch {
174
- // Memory write-back is best-effort when waking fails.
175
- }
176
- }
177
- throw error;
178
- }
179
- finally {
180
- if (this.memoryToolContext) {
181
- this.memoryToolContext.current = undefined;
182
- }
183
- unsubscribe();
184
- }
185
- }
186
- status() {
187
- return {
188
- agentId: this.id,
189
- state: this.state,
190
- lastWakeAt: this.lastWakeAt,
191
- lastError: this.lastError
192
- };
193
- }
194
- async stop() {
195
- this.session.dispose();
196
- this.state = "stopped";
197
- }
198
- }
199
- const formatWakePrompt = (event) => `Wake event:
200
- - id: ${event.id}
201
- - kind: ${event.kind}
202
- - from: ${event.from ?? "operator"}
203
-
204
- ${event.text}`;
205
- const createResourceLoader = (input) => {
206
- const systemPrompt = [
207
- `You are ${input.name} (${input.id}).`,
208
- input.instructions,
209
- "You are running inside a harnessed workspace prepared by the caller.",
210
- "Use the available coding tools when asked to read, write, edit, or inspect files.",
211
- "Use memory_search, memory_locate, memory_register, memory_summarize, and memory_forget when scoped memory matters.",
212
- "Keep responses brief and report the exact files you created or modified."
213
- ].join("\n\n");
214
- return {
215
- getExtensions: () => ({ extensions: [], errors: [], runtime: createExtensionRuntime() }),
216
- getSkills: () => ({ skills: [], diagnostics: [] }),
217
- getPrompts: () => ({ prompts: [], diagnostics: [] }),
218
- getThemes: () => ({ themes: [], diagnostics: [] }),
219
- getAgentsFiles: () => ({ agentsFiles: [] }),
220
- getSystemPrompt: () => systemPrompt,
221
- getAppendSystemPrompt: () => [],
222
- extendResources: () => { },
223
- reload: async () => { }
224
- };
225
- };
8
+ import { createResourceLoader } from "./prompts.js";
9
+ import { PiAgentHandle } from "./piAgentHandle.js";
10
+ import { createPiWorldTools, piWorldToolNames } from "./worldTools.js";
11
+ import { bindPiRawTrainingCapture, validatePiRawTrainingCaptureOptions } from "./rawTrainingCapture.js";
226
12
  export class PiHarnessAdapter {
227
13
  options;
228
14
  authStorage;
@@ -231,12 +17,15 @@ export class PiHarnessAdapter {
231
17
  constructor(options) {
232
18
  this.options = options;
233
19
  this.authStorage = AuthStorage.create(options.authPath);
234
- this.modelRegistry = createModelRegistry(this.authStorage, options);
20
+ this.modelRegistry = createPiModelRegistry(this.authStorage, options);
235
21
  this.sessionFactory = options.sessionFactory ?? createAgentSession;
236
22
  }
237
23
  async startAgent(input) {
24
+ validatePiRawTrainingCaptureOptions(this.options.rawTrainingCapture);
238
25
  await mkdir(input.runtimeHomePath, { recursive: true });
239
26
  await mkdir(input.workspacePath, { recursive: true });
27
+ const memoryRuntimeHomePath = this.options.memory?.runtimeHomePath ?? input.runtimeHomePath;
28
+ await mkdir(memoryRuntimeHomePath, { recursive: true });
240
29
  const modelSpec = this.options.model ?? {
241
30
  auth: { method: "codex" },
242
31
  provider: "openai",
@@ -247,38 +36,91 @@ export class PiHarnessAdapter {
247
36
  if (!model) {
248
37
  throw new Error(`Pi model not found: ${resolvedModel.provider}/${resolvedModel.name}`);
249
38
  }
250
- const memory = createMemoryRuntime({
251
- agentId: input.id,
252
- runtimeHomePath: input.runtimeHomePath,
253
- source: this.options.memory?.source,
254
- tokenBudget: this.options.memory?.tokenBudget
255
- });
256
- const memoryToolContext = {};
257
- const memoryTools = createPiMemoryTools({
258
- agentId: input.id,
259
- memory,
260
- contextRef: memoryToolContext
261
- });
262
- const toolNames = [
263
- ...(input.tools ?? ["read", "write", "edit", "bash", "grep", "find", "ls"]),
264
- ...piMemoryToolNames(memoryTools)
265
- ];
266
- const { session } = await this.sessionFactory({
267
- cwd: input.workspacePath,
268
- agentDir: input.runtimeHomePath,
269
- authStorage: this.authStorage,
270
- modelRegistry: this.modelRegistry,
271
- model,
272
- thinkingLevel: "off",
273
- resourceLoader: createResourceLoader(input),
274
- tools: [...new Set(toolNames)],
275
- customTools: memoryTools,
276
- sessionManager: SessionManager.create(input.workspacePath, path.join(input.runtimeHomePath, "sessions")),
277
- settingsManager: SettingsManager.inMemory({
278
- compaction: { enabled: false },
279
- retry: { enabled: true, maxRetries: 1 }
280
- })
281
- });
282
- return new PiAgentHandle(input.id, session, memory, memoryToolContext);
39
+ const memory = this.options.memory === undefined
40
+ ? undefined
41
+ : createMemoryRuntime({
42
+ agentId: input.id,
43
+ authority: this.options.memory.authority,
44
+ embeddingProvider: this.options.memory.embeddingProvider,
45
+ runtimeHomePath: memoryRuntimeHomePath,
46
+ source: this.options.memory.source,
47
+ tokenBudget: this.options.memory.tokenBudget
48
+ });
49
+ const memoryToolContext = memory === undefined ? undefined : {};
50
+ const worldToolContext = this.options.world === undefined ? undefined : {};
51
+ const rawTrainingCaptureRef = this.options.rawTrainingCapture === undefined ? undefined : {};
52
+ const sessionInput = (mode, sessionDirectory) => {
53
+ const memoryTools = memory === undefined || memoryToolContext === undefined
54
+ ? []
55
+ : createPiMemoryTools({
56
+ agentId: input.id,
57
+ memory,
58
+ contextRef: memoryToolContext,
59
+ mode
60
+ });
61
+ const worldTools = this.options.world === undefined
62
+ ? undefined
63
+ : createPiWorldTools({
64
+ world: this.options.world,
65
+ contextRef: worldToolContext
66
+ });
67
+ const toolNames = [
68
+ ...(input.tools ?? ["read", "write", "edit", "bash", "grep", "find", "ls"]),
69
+ ...piMemoryToolNames(memoryTools),
70
+ ...(worldTools === undefined ? [] : piWorldToolNames(worldTools))
71
+ ];
72
+ return {
73
+ cwd: input.workspacePath,
74
+ agentDir: input.runtimeHomePath,
75
+ daimonSecretEnvironmentNames: this.options.world === undefined ? [] : [this.options.world.tokenEnv],
76
+ authStorage: this.authStorage,
77
+ modelRegistry: this.modelRegistry,
78
+ model,
79
+ thinkingLevel: this.options.thinkingLevel ?? "off",
80
+ resourceLoader: createResourceLoader(input, mode, {
81
+ memory: memory !== undefined,
82
+ world: worldTools !== undefined
83
+ }),
84
+ tools: [...new Set(toolNames)],
85
+ customTools: worldTools === undefined ? memoryTools : [...memoryTools, ...worldTools],
86
+ sessionManager: SessionManager.create(input.workspacePath, sessionDirectory),
87
+ settingsManager: SettingsManager.inMemory({
88
+ compaction: { enabled: false },
89
+ retry: { enabled: true, maxRetries: 1 }
90
+ })
91
+ };
92
+ };
93
+ if (this.options.rawTrainingCapture !== undefined) {
94
+ const createSession = async (mode, sessionDirectory) => {
95
+ const { session } = await createAgentSession(sessionInput(mode, sessionDirectory));
96
+ if (rawTrainingCaptureRef !== undefined) {
97
+ bindPiRawTrainingCapture(session, rawTrainingCaptureRef);
98
+ }
99
+ return session;
100
+ };
101
+ const session = await createSession("awake", path.join(input.runtimeHomePath, "sessions"));
102
+ return new PiAgentHandle(input.id, session, createSession, input.runtimeHomePath, {
103
+ authMethod: modelSpec.auth?.method ?? "none",
104
+ model: resolvedModel.name,
105
+ provider: resolvedModel.provider
106
+ }, memory, memoryToolContext, {}, worldToolContext, rawTrainingCaptureRef, this.options.rawTrainingCapture, worldToolContext === undefined
107
+ ? undefined
108
+ : { instructions: input.instructions, thinkingLevel: this.options.thinkingLevel ?? "off" }, session);
109
+ }
110
+ const createSession = async (mode, sessionDirectory) => {
111
+ const { session } = await (this.options.sessionFactory ?? createAgentSession)(sessionInput(mode, sessionDirectory));
112
+ return session;
113
+ };
114
+ const session = await createSession("awake", path.join(input.runtimeHomePath, "sessions"));
115
+ return new PiAgentHandle(input.id, session, createSession, input.runtimeHomePath, {
116
+ authMethod: modelSpec.auth?.method ?? "none",
117
+ model: resolvedModel.name,
118
+ provider: resolvedModel.provider
119
+ }, memory, memoryToolContext, {}, worldToolContext, undefined, undefined, worldToolContext === undefined
120
+ ? undefined
121
+ : {
122
+ instructions: input.instructions,
123
+ thinkingLevel: this.options.thinkingLevel ?? "off"
124
+ }, undefined);
283
125
  }
284
126
  }
@@ -0,0 +1,9 @@
1
+ import { type ResourceLoader } from "@earendil-works/pi-coding-agent";
2
+ import { type MemoryWakeMode } from "@noopolis/mneme";
3
+ import type { AgentStartInput, WakeEvent } from "../core/types.js";
4
+ export declare const formatWakePrompt: (event: WakeEvent) => string;
5
+ export declare const createResourceLoader: (input: AgentStartInput, mode: MemoryWakeMode, capabilities: Readonly<{
6
+ memory: boolean;
7
+ world: boolean;
8
+ }>) => ResourceLoader;
9
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/pi/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEnE,eAAO,MAAM,gBAAgB,GAAI,OAAO,SAAS,KAAG,MAKtC,CAAC;AAEf,eAAO,MAAM,oBAAoB,GAC/B,OAAO,eAAe,EACtB,MAAM,cAAc,EACpB,cAAc,QAAQ,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,KAC1D,cA+BF,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { createExtensionRuntime } from "@earendil-works/pi-coding-agent";
2
+ import { getMemorySkillTextForMode } from "@noopolis/mneme";
3
+ export const formatWakePrompt = (event) => `Wake event:
4
+ - id: ${event.id}
5
+ - kind: ${event.kind}
6
+ - from: ${event.from === undefined ? "[no attribution supplied] (absence)" : JSON.stringify(event.from)}
7
+
8
+ ${event.text}`;
9
+ export const createResourceLoader = (input, mode, capabilities) => {
10
+ const systemPrompt = [
11
+ `You are ${input.name} (${input.id}).`,
12
+ input.instructions,
13
+ "You are running inside a harnessed workspace prepared by the caller.",
14
+ ...(input.tools === undefined || input.tools.length > 0
15
+ ? [
16
+ "Use the available coding tools when asked to read, write, edit, or inspect files.",
17
+ "Keep responses brief and report the exact files you created or modified."
18
+ ]
19
+ : []),
20
+ ...(capabilities.memory ? [getMemorySkillTextForMode(mode)] : []),
21
+ ...(capabilities.world
22
+ ? [
23
+ "Use only the authenticated world tools and standing instructions to perceive and act. "
24
+ + "The harness binds wake authority and request identity; choose only the sense, affordance, target, and typed action input exposed by tool schemas."
25
+ ]
26
+ : [])
27
+ ].filter((section) => section.length > 0).join("\n\n");
28
+ return {
29
+ getExtensions: () => ({ extensions: [], errors: [], runtime: createExtensionRuntime() }),
30
+ getSkills: () => ({ skills: [], diagnostics: [] }),
31
+ getPrompts: () => ({ prompts: [], diagnostics: [] }),
32
+ getThemes: () => ({ themes: [], diagnostics: [] }),
33
+ getAgentsFiles: () => ({ agentsFiles: [] }),
34
+ getSystemPrompt: () => systemPrompt,
35
+ getAppendSystemPrompt: () => [],
36
+ extendResources: () => { },
37
+ reload: async () => { }
38
+ };
39
+ };
@@ -0,0 +1,59 @@
1
+ import type { createAgentSession } from "@earendil-works/pi-coding-agent";
2
+ import type { PiWorldTurnContext } from "./worldNudge.js";
3
+ export declare const PI_RAW_TRAINING_CAPTURE_SCHEMA: "daimon.pi.raw_training_capture.v2";
4
+ export interface PiRawTrainingCaptureOptions {
5
+ enabled: true;
6
+ retention: {
7
+ maxTurns: number;
8
+ };
9
+ }
10
+ export interface PiRawTrainingCapture {
11
+ readonly events: string[];
12
+ readonly requests: Array<{
13
+ model: unknown;
14
+ payload: unknown;
15
+ requested_at: string;
16
+ response?: unknown;
17
+ response_at?: string;
18
+ sequence: number;
19
+ }>;
20
+ }
21
+ export interface PiRawTrainingCaptureRef {
22
+ current?: PiRawTrainingCapture;
23
+ }
24
+ type PiNativeSession = Awaited<ReturnType<typeof createAgentSession>>["session"];
25
+ type PiRawTrainingSession = Pick<PiNativeSession, "agent" | "model" | "sessionFile" | "sessionId" | "thinkingLevel">;
26
+ export interface PersistPiRawTrainingCaptureInput {
27
+ agentId: string;
28
+ capture: PiRawTrainingCapture;
29
+ completedAt: Date;
30
+ options: PiRawTrainingCaptureOptions;
31
+ runtimeHomePath: string;
32
+ session: PiRawTrainingSession;
33
+ startedAt: Date;
34
+ status: "completed" | "failed";
35
+ totalMs: number;
36
+ turnId: string;
37
+ world?: PiWorldTurnContext;
38
+ }
39
+ /**
40
+ * Installs a transparent recorder at Pi's native provider-payload seam.
41
+ *
42
+ * The recorder returns the exact result of any pre-existing hook, so enabling
43
+ * capture cannot alter the request sent to the model.
44
+ */
45
+ export declare const bindPiRawTrainingCapture: (session: PiRawTrainingSession, ref: PiRawTrainingCaptureRef) => void;
46
+ export declare const createPiRawTrainingCapture: () => PiRawTrainingCapture;
47
+ export declare const capturePiRawTrainingEvent: (capture: PiRawTrainingCapture, event: unknown, now?: Date) => void;
48
+ export declare const validatePiRawTrainingCaptureOptions: (options: PiRawTrainingCaptureOptions | undefined) => void;
49
+ /**
50
+ * Persists a deliberately private, unredacted training artifact.
51
+ *
52
+ * `pi-session.jsonl` is copied byte-for-byte from Pi's SessionManager. The
53
+ * request payloads come from Pi AI's `onPayload` seam after any prior payload
54
+ * transform, so they contain the exact structured provider input, including
55
+ * system/character prompts, messages, tool schemas, and sampling fields.
56
+ */
57
+ export declare const persistPiRawTrainingCapture: (input: PersistPiRawTrainingCaptureInput) => Promise<string>;
58
+ export {};
59
+ //# sourceMappingURL=rawTrainingCapture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rawTrainingCapture.d.ts","sourceRoot":"","sources":["../../src/pi/rawTrainingCapture.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAG1D,eAAO,MAAM,8BAA8B,EACzC,mCAA4C,CAAC;AAE/C,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,EAAE;QACT,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;QACvB,KAAK,EAAE,OAAO,CAAC;QACf,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAED,KAAK,eAAe,GAClB,OAAO,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAC5D,KAAK,oBAAoB,GAAG,IAAI,CAC9B,eAAe,EACf,OAAO,GAAG,OAAO,GAAG,aAAa,GAAG,WAAW,GAAG,eAAe,CAClE,CAAC;AAEF,MAAM,WAAW,gCAAgC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,WAAW,EAAE,IAAI,CAAC;IAClB,OAAO,EAAE,2BAA2B,CAAC;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC5B;AAMD;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,GACnC,SAAS,oBAAoB,EAC7B,KAAK,uBAAuB,KAC3B,IA4BF,CAAC;AAEF,eAAO,MAAM,0BAA0B,QAAO,oBAG5C,CAAC;AAEH,eAAO,MAAM,yBAAyB,GACpC,SAAS,oBAAoB,EAC7B,OAAO,OAAO,EACd,UAAgB,KACf,IAKF,CAAC;AAEF,eAAO,MAAM,mCAAmC,GAC9C,SAAS,2BAA2B,GAAG,SAAS,KAC/C,IAUF,CAAC;AAaF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,GACtC,OAAO,gCAAgC,KACtC,OAAO,CAAC,MAAM,CAoIhB,CAAC"}
@@ -0,0 +1,175 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { chmod, readFile, readdir, rename, rm, mkdir, writeFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { sanitizeTraceFileId } from "./turnTrace.js";
5
+ export const PI_RAW_TRAINING_CAPTURE_SCHEMA = "daimon.pi.raw_training_capture.v2";
6
+ const json = (value) => JSON.stringify(value);
7
+ const sha256 = (value) => createHash("sha256").update(value).digest("hex");
8
+ /**
9
+ * Installs a transparent recorder at Pi's native provider-payload seam.
10
+ *
11
+ * The recorder returns the exact result of any pre-existing hook, so enabling
12
+ * capture cannot alter the request sent to the model.
13
+ */
14
+ export const bindPiRawTrainingCapture = (session, ref) => {
15
+ const previousPayload = session.agent.onPayload;
16
+ const previousResponse = session.agent.onResponse;
17
+ session.agent.onPayload = async (payload, model) => {
18
+ const transformed = await previousPayload?.(payload, model);
19
+ const effectivePayload = transformed === undefined ? payload : transformed;
20
+ const capture = ref.current;
21
+ if (capture !== undefined) {
22
+ capture.requests.push({
23
+ model: structuredClone(model),
24
+ payload: structuredClone(effectivePayload),
25
+ requested_at: new Date().toISOString(),
26
+ sequence: capture.requests.length
27
+ });
28
+ }
29
+ return transformed;
30
+ };
31
+ session.agent.onResponse = async (response, model) => {
32
+ await previousResponse?.(response, model);
33
+ const capture = ref.current;
34
+ const request = capture?.requests.at(-1);
35
+ if (request !== undefined) {
36
+ request.response = structuredClone(response);
37
+ request.response_at = new Date().toISOString();
38
+ }
39
+ };
40
+ };
41
+ export const createPiRawTrainingCapture = () => ({
42
+ events: [],
43
+ requests: []
44
+ });
45
+ export const capturePiRawTrainingEvent = (capture, event, now = new Date()) => {
46
+ // Serialize at event time so later mutation cannot change the captured event.
47
+ capture.events.push(`{"recorded_at":${json(now.toISOString())},"event":${json(event)}}`);
48
+ };
49
+ export const validatePiRawTrainingCaptureOptions = (options) => {
50
+ if (options === undefined)
51
+ return;
52
+ if (options.enabled !== true
53
+ || !Number.isSafeInteger(options.retention.maxTurns)
54
+ || options.retention.maxTurns < 1
55
+ || options.retention.maxTurns > 100_000) {
56
+ throw new Error("Pi raw training capture requires enabled: true and retention.maxTurns between 1 and 100000");
57
+ }
58
+ };
59
+ const pruneTurns = async (turnsPath, maxTurns) => {
60
+ const names = (await readdir(turnsPath, { withFileTypes: true }))
61
+ .filter((entry) => entry.isDirectory())
62
+ .map((entry) => entry.name)
63
+ .sort();
64
+ await Promise.all(names.slice(0, Math.max(0, names.length - maxTurns))
65
+ .map((name) => rm(path.join(turnsPath, name), { force: true, recursive: true })));
66
+ };
67
+ /**
68
+ * Persists a deliberately private, unredacted training artifact.
69
+ *
70
+ * `pi-session.jsonl` is copied byte-for-byte from Pi's SessionManager. The
71
+ * request payloads come from Pi AI's `onPayload` seam after any prior payload
72
+ * transform, so they contain the exact structured provider input, including
73
+ * system/character prompts, messages, tool schemas, and sampling fields.
74
+ */
75
+ export const persistPiRawTrainingCapture = async (input) => {
76
+ validatePiRawTrainingCaptureOptions(input.options);
77
+ if (input.session.sessionFile === undefined) {
78
+ throw new Error("Pi raw training capture requires a persisted native session");
79
+ }
80
+ const nativeSessionBytes = await readFile(input.session.sessionFile);
81
+ const privateTrainingPath = path.join(input.runtimeHomePath, "private-training");
82
+ const piPath = path.join(privateTrainingPath, "pi");
83
+ const root = path.join(piPath, "raw");
84
+ const turnsPath = path.join(root, "turns");
85
+ const turnPath = path.join(turnsPath, `${String(input.startedAt.getTime()).padStart(13, "0")}-${sanitizeTraceFileId(input.turnId)}`);
86
+ const partialTurnPath = path.join(turnsPath, `.partial-${path.basename(turnPath)}-${randomUUID()}`);
87
+ await mkdir(turnsPath, { mode: 0o700, recursive: true });
88
+ await Promise.all([privateTrainingPath, piPath, root, turnsPath]
89
+ .map((directory) => chmod(directory, 0o700)));
90
+ await mkdir(partialTurnPath, { mode: 0o700 });
91
+ const providerExchange = {
92
+ model: structuredClone(input.session.model),
93
+ requests: input.capture.requests,
94
+ session_id: input.session.sessionId,
95
+ thinking_level: input.session.thinkingLevel
96
+ };
97
+ const eventsBytes = Buffer.from(input.capture.events.length === 0 ? "" : `${input.capture.events.join("\n")}\n`, "utf8");
98
+ const providerExchangeBytes = Buffer.from(`${JSON.stringify(providerExchange, null, 2)}\n`, "utf8");
99
+ const manifest = {
100
+ access: {
101
+ classification: "private_raw_training",
102
+ export_by_default: false,
103
+ contains_unredacted_model_context: true
104
+ },
105
+ agent_id: input.agentId,
106
+ completed_at: input.completedAt.toISOString(),
107
+ files: {
108
+ events: "events.ndjson",
109
+ native_pi_session: "pi-session.jsonl",
110
+ provider_exchange: "provider-exchange.json"
111
+ },
112
+ integrity: {
113
+ capture_boundary: "post_turn",
114
+ files: {
115
+ events: {
116
+ bytes: eventsBytes.byteLength,
117
+ records: input.capture.events.length,
118
+ sha256: sha256(eventsBytes)
119
+ },
120
+ native_pi_session: {
121
+ bytes: nativeSessionBytes.byteLength,
122
+ sha256: sha256(nativeSessionBytes)
123
+ },
124
+ provider_exchange: {
125
+ bytes: providerExchangeBytes.byteLength,
126
+ requests: input.capture.requests.length,
127
+ sha256: sha256(providerExchangeBytes)
128
+ }
129
+ }
130
+ },
131
+ join: input.world === undefined ? undefined : {
132
+ run_id: input.world.runId,
133
+ tick: input.world.tick,
134
+ wake_id: input.world.wakeId
135
+ },
136
+ native_session: {
137
+ id: input.session.sessionId
138
+ },
139
+ retention: {
140
+ max_turns: input.options.retention.maxTurns
141
+ },
142
+ schema: PI_RAW_TRAINING_CAPTURE_SCHEMA,
143
+ started_at: input.startedAt.toISOString(),
144
+ terminal_status: input.status,
145
+ timings_ms: {
146
+ total: input.totalMs
147
+ },
148
+ turn_id: input.turnId
149
+ };
150
+ const files = [
151
+ "manifest.json",
152
+ "provider-exchange.json",
153
+ "events.ndjson",
154
+ "pi-session.jsonl"
155
+ ];
156
+ try {
157
+ await Promise.all([
158
+ writeFile(path.join(partialTurnPath, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`, { encoding: "utf8", mode: 0o600 }),
159
+ writeFile(path.join(partialTurnPath, "provider-exchange.json"), providerExchangeBytes, { mode: 0o600 }),
160
+ writeFile(path.join(partialTurnPath, "events.ndjson"), eventsBytes, { mode: 0o600 }),
161
+ writeFile(path.join(partialTurnPath, "pi-session.jsonl"), nativeSessionBytes, { mode: 0o600 })
162
+ ]);
163
+ await Promise.all([
164
+ chmod(partialTurnPath, 0o700),
165
+ ...files.map((name) => chmod(path.join(partialTurnPath, name), 0o600))
166
+ ]);
167
+ await rename(partialTurnPath, turnPath);
168
+ }
169
+ catch (error) {
170
+ await rm(partialTurnPath, { force: true, recursive: true });
171
+ throw error;
172
+ }
173
+ await pruneTurns(turnsPath, input.options.retention.maxTurns);
174
+ return turnPath;
175
+ };