@noopolis/daimon 0.1.0 → 0.1.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.
Files changed (55) hide show
  1. package/README.md +92 -0
  2. package/dist/core/types.d.ts +10 -0
  3. package/dist/core/types.d.ts.map +1 -1
  4. package/dist/examples/jungian-play-org.d.ts +2 -0
  5. package/dist/examples/jungian-play-org.d.ts.map +1 -0
  6. package/dist/examples/jungian-play-org.js +280 -0
  7. package/dist/examples/jungian-triad-org.d.ts +2 -0
  8. package/dist/examples/jungian-triad-org.d.ts.map +1 -0
  9. package/dist/examples/jungian-triad-org.js +280 -0
  10. package/dist/examples/jungianConversationPlan.d.ts +10 -0
  11. package/dist/examples/jungianConversationPlan.d.ts.map +1 -0
  12. package/dist/examples/jungianConversationPlan.js +64 -0
  13. package/dist/examples/jungianPiRepresentative.d.ts +36 -0
  14. package/dist/examples/jungianPiRepresentative.d.ts.map +1 -0
  15. package/dist/examples/jungianPiRepresentative.js +81 -0
  16. package/dist/examples/jungianPlayAgent.d.ts +36 -0
  17. package/dist/examples/jungianPlayAgent.d.ts.map +1 -0
  18. package/dist/examples/jungianPlayAgent.js +111 -0
  19. package/dist/examples/jungianProfiles.d.ts +34 -0
  20. package/dist/examples/jungianProfiles.d.ts.map +1 -0
  21. package/dist/examples/jungianProfiles.js +190 -0
  22. package/dist/examples/jungianTrace.d.ts +47 -0
  23. package/dist/examples/jungianTrace.d.ts.map +1 -0
  24. package/dist/examples/jungianTrace.js +101 -0
  25. package/dist/examples/jungianTriadProfiles.d.ts +35 -0
  26. package/dist/examples/jungianTriadProfiles.d.ts.map +1 -0
  27. package/dist/examples/jungianTriadProfiles.js +81 -0
  28. package/dist/examples/mixed-engine-org.d.ts +2 -0
  29. package/dist/examples/mixed-engine-org.d.ts.map +1 -0
  30. package/dist/examples/mixed-engine-org.js +351 -0
  31. package/dist/examples/mixedEngineCli.d.ts +15 -0
  32. package/dist/examples/mixedEngineCli.d.ts.map +1 -0
  33. package/dist/examples/mixedEngineCli.js +174 -0
  34. package/dist/examples/pi-memory-org.d.ts +2 -0
  35. package/dist/examples/pi-memory-org.d.ts.map +1 -0
  36. package/dist/examples/pi-memory-org.js +230 -0
  37. package/dist/index.d.ts +1 -3
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +1 -3
  40. package/dist/observability/index.d.ts +2 -0
  41. package/dist/observability/index.d.ts.map +1 -0
  42. package/dist/observability/index.js +1 -0
  43. package/dist/observability/orgObserver.d.ts +98 -0
  44. package/dist/observability/orgObserver.d.ts.map +1 -0
  45. package/dist/observability/orgObserver.js +181 -0
  46. package/dist/pi/index.d.ts +4 -0
  47. package/dist/pi/index.d.ts.map +1 -0
  48. package/dist/pi/index.js +3 -0
  49. package/dist/pi/memoryTools.d.ts +15 -0
  50. package/dist/pi/memoryTools.d.ts.map +1 -0
  51. package/dist/pi/memoryTools.js +70 -0
  52. package/dist/pi/piHarness.d.ts +8 -0
  53. package/dist/pi/piHarness.d.ts.map +1 -1
  54. package/dist/pi/piHarness.js +137 -6
  55. package/package.json +26 -4
@@ -1,6 +1,8 @@
1
+ import { createAgentSession } from "@earendil-works/pi-coding-agent";
1
2
  import type { AgentHandle, AgentHarnessAdapter, AgentStartInput, HarnessModelSpec } from "../core/types.js";
2
3
  export interface PiHarnessOptions {
3
4
  authPath: string;
5
+ sessionFactory?: PiSessionFactory;
4
6
  model?: {
5
7
  auth?: HarnessModelSpec["auth"];
6
8
  endpoint?: HarnessModelSpec["endpoint"];
@@ -8,11 +10,17 @@ export interface PiHarnessOptions {
8
10
  name: string;
9
11
  };
10
12
  modelsPath?: string;
13
+ memory?: {
14
+ source?: string;
15
+ tokenBudget?: number;
16
+ };
11
17
  }
18
+ export type PiSessionFactory = (input: Parameters<typeof createAgentSession>[0]) => ReturnType<typeof createAgentSession>;
12
19
  export declare class PiHarnessAdapter implements AgentHarnessAdapter {
13
20
  private readonly options;
14
21
  private readonly authStorage;
15
22
  private readonly modelRegistry;
23
+ private readonly sessionFactory;
16
24
  constructor(options: PiHarnessOptions);
17
25
  startAgent(input: AgentStartInput): Promise<AgentHandle>;
18
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"piHarness.d.ts","sourceRoot":"","sources":["../../src/pi/piHarness.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,eAAe,EAEf,gBAAgB,EAGjB,MAAM,kBAAkB,CAAC;AAM1B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACxC,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA4HD,qBAAa,gBAAiB,YAAW,mBAAmB;IAI9C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;gBAEjB,OAAO,EAAE,gBAAgB;IAKhD,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;CAgC/D"}
1
+ {"version":3,"file":"piHarness.d.ts","sourceRoot":"","sources":["../../src/pi/piHarness.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,kBAAkB,EAMnB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,eAAe,EAEf,gBAAgB,EAGjB,MAAM,kBAAkB,CAAC;AAe1B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACxC,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,MAAM,MAAM,gBAAgB,GAAG,CAC7B,KAAK,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC,KAC5C,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAwP3C,qBAAa,gBAAiB,YAAW,mBAAmB;IAK9C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAmB;gBAErB,OAAO,EAAE,gBAAgB;IAMhD,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;CAiD/D"}
@@ -2,6 +2,8 @@ import { mkdir } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { AuthStorage, createAgentSession, createExtensionRuntime, ModelRegistry, SessionManager, SettingsManager } from "@earendil-works/pi-coding-agent";
4
4
  import { resolvePiHarnessModel } from "./modelConfig.js";
5
+ import { createPiMemoryTools, piMemoryToolNames } from "./memoryTools.js";
6
+ import { createMemoryRuntime, memoryScopeId, readMemoryContext } from "@noopolis/mneme";
5
7
  const createModelRegistry = (authStorage, options) => {
6
8
  const registry = options.modelsPath
7
9
  ? ModelRegistry.create(authStorage, options.modelsPath)
@@ -19,23 +21,46 @@ const createModelRegistry = (authStorage, options) => {
19
21
  }
20
22
  return registry;
21
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();
22
33
  class PiAgentHandle {
23
34
  id;
24
35
  session;
36
+ memory;
37
+ memoryToolContext;
25
38
  state = "idle";
26
39
  lastWakeAt;
27
40
  lastError;
28
- constructor(id, session) {
41
+ wakeQueue = Promise.resolve();
42
+ constructor(id, session, memory, memoryToolContext) {
29
43
  this.id = id;
30
44
  this.session = session;
45
+ this.memory = memory;
46
+ this.memoryToolContext = memoryToolContext;
31
47
  }
32
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) {
33
54
  const startedAt = Date.now();
34
55
  const chunks = [];
56
+ const toolEvents = [];
35
57
  this.state = "running";
36
58
  this.lastWakeAt = new Date().toISOString();
37
59
  this.lastError = undefined;
38
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
+ }
39
64
  if (piEvent.type !== "turn_end") {
40
65
  return;
41
66
  }
@@ -54,21 +79,107 @@ class PiAgentHandle {
54
79
  .join(""));
55
80
  }
56
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);
57
98
  try {
58
- await this.session.prompt(formatWakePrompt(event), { expandPromptTemplates: false });
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 });
59
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
+ }
60
139
  return {
61
140
  agentId: this.id,
62
- text: chunks.join("\n").trim(),
141
+ text: outputText,
63
142
  durationMs: Date.now() - startedAt
64
143
  };
65
144
  }
66
145
  catch (error) {
67
146
  this.state = "failed";
68
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
+ }
69
177
  throw error;
70
178
  }
71
179
  finally {
180
+ if (this.memoryToolContext) {
181
+ this.memoryToolContext.current = undefined;
182
+ }
72
183
  unsubscribe();
73
184
  }
74
185
  }
@@ -97,6 +208,7 @@ const createResourceLoader = (input) => {
97
208
  input.instructions,
98
209
  "You are running inside a harnessed workspace prepared by the caller.",
99
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.",
100
212
  "Keep responses brief and report the exact files you created or modified."
101
213
  ].join("\n\n");
102
214
  return {
@@ -115,10 +227,12 @@ export class PiHarnessAdapter {
115
227
  options;
116
228
  authStorage;
117
229
  modelRegistry;
230
+ sessionFactory;
118
231
  constructor(options) {
119
232
  this.options = options;
120
233
  this.authStorage = AuthStorage.create(options.authPath);
121
234
  this.modelRegistry = createModelRegistry(this.authStorage, options);
235
+ this.sessionFactory = options.sessionFactory ?? createAgentSession;
122
236
  }
123
237
  async startAgent(input) {
124
238
  await mkdir(input.runtimeHomePath, { recursive: true });
@@ -133,7 +247,23 @@ export class PiHarnessAdapter {
133
247
  if (!model) {
134
248
  throw new Error(`Pi model not found: ${resolvedModel.provider}/${resolvedModel.name}`);
135
249
  }
136
- const { session } = await createAgentSession({
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({
137
267
  cwd: input.workspacePath,
138
268
  agentDir: input.runtimeHomePath,
139
269
  authStorage: this.authStorage,
@@ -141,13 +271,14 @@ export class PiHarnessAdapter {
141
271
  model,
142
272
  thinkingLevel: "off",
143
273
  resourceLoader: createResourceLoader(input),
144
- tools: input.tools ?? ["read", "write", "edit", "bash", "grep", "find", "ls"],
274
+ tools: [...new Set(toolNames)],
275
+ customTools: memoryTools,
145
276
  sessionManager: SessionManager.create(input.workspacePath, path.join(input.runtimeHomePath, "sessions")),
146
277
  settingsManager: SettingsManager.inMemory({
147
278
  compaction: { enabled: false },
148
279
  retry: { enabled: true, maxRetries: 1 }
149
280
  })
150
281
  });
151
- return new PiAgentHandle(input.id, session);
282
+ return new PiAgentHandle(input.id, session, memory, memoryToolContext);
152
283
  }
153
284
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noopolis/daimon",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Noopolis native per-agent runtime harness built on Pi.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -10,6 +10,14 @@
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
12
  "import": "./dist/index.js"
13
+ },
14
+ "./pi": {
15
+ "types": "./dist/pi/index.d.ts",
16
+ "import": "./dist/pi/index.js"
17
+ },
18
+ "./observability": {
19
+ "types": "./dist/observability/index.d.ts",
20
+ "import": "./dist/observability/index.js"
13
21
  }
14
22
  },
15
23
  "files": [
@@ -30,16 +38,30 @@
30
38
  "prepublishOnly": "npm run typecheck && npm test",
31
39
  "typecheck": "tsc --project tsconfig.json --noEmit",
32
40
  "test": "node --import tsx --test \"src/**/*.test.ts\"",
33
- "e2e:pi-agent": "tsx src/examples/pi-agent.ts"
41
+ "e2e:pi-agent": "tsx src/examples/pi-agent.ts",
42
+ "e2e:pi-memory-org": "tsx src/examples/pi-memory-org.ts",
43
+ "e2e:mixed-engine-org": "tsx src/examples/mixed-engine-org.ts",
44
+ "e2e:jungian-play-org": "tsx src/examples/jungian-play-org.ts",
45
+ "e2e:jungian-triad-org": "tsx src/examples/jungian-triad-org.ts",
46
+ "image:runtime:local": "docker build -f Dockerfile.runtime -t noopolis/spawnfile-runtime-daimon:0.1.1-local --build-arg DAIMON_VERSION=0.1.1 --build-arg MNEME_VERSION=0.1.0 --build-arg PI_VERSION=0.79.10 ."
34
47
  },
35
48
  "engines": {
36
49
  "node": ">=22.19.0"
37
50
  },
38
51
  "dependencies": {
39
- "@earendil-works/pi-ai": "^0.79.9",
40
- "@earendil-works/pi-coding-agent": "^0.79.9"
52
+ "@earendil-works/pi-ai": "^0.79.10",
53
+ "@earendil-works/pi-coding-agent": "^0.79.10"
54
+ },
55
+ "peerDependencies": {
56
+ "@noopolis/mneme": "^0.1.0"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "@noopolis/mneme": {
60
+ "optional": true
61
+ }
41
62
  },
42
63
  "devDependencies": {
64
+ "@noopolis/mneme": "^0.1.0",
43
65
  "@types/node": "^24.12.4",
44
66
  "tsx": "^4.21.0",
45
67
  "typescript": "^5.9.3"