@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.
- package/README.md +92 -0
- package/dist/core/types.d.ts +10 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/examples/jungian-play-org.d.ts +2 -0
- package/dist/examples/jungian-play-org.d.ts.map +1 -0
- package/dist/examples/jungian-play-org.js +280 -0
- package/dist/examples/jungian-triad-org.d.ts +2 -0
- package/dist/examples/jungian-triad-org.d.ts.map +1 -0
- package/dist/examples/jungian-triad-org.js +280 -0
- package/dist/examples/jungianConversationPlan.d.ts +10 -0
- package/dist/examples/jungianConversationPlan.d.ts.map +1 -0
- package/dist/examples/jungianConversationPlan.js +64 -0
- package/dist/examples/jungianPiRepresentative.d.ts +36 -0
- package/dist/examples/jungianPiRepresentative.d.ts.map +1 -0
- package/dist/examples/jungianPiRepresentative.js +81 -0
- package/dist/examples/jungianPlayAgent.d.ts +36 -0
- package/dist/examples/jungianPlayAgent.d.ts.map +1 -0
- package/dist/examples/jungianPlayAgent.js +111 -0
- package/dist/examples/jungianProfiles.d.ts +34 -0
- package/dist/examples/jungianProfiles.d.ts.map +1 -0
- package/dist/examples/jungianProfiles.js +190 -0
- package/dist/examples/jungianTrace.d.ts +47 -0
- package/dist/examples/jungianTrace.d.ts.map +1 -0
- package/dist/examples/jungianTrace.js +101 -0
- package/dist/examples/jungianTriadProfiles.d.ts +35 -0
- package/dist/examples/jungianTriadProfiles.d.ts.map +1 -0
- package/dist/examples/jungianTriadProfiles.js +81 -0
- package/dist/examples/mixed-engine-org.d.ts +2 -0
- package/dist/examples/mixed-engine-org.d.ts.map +1 -0
- package/dist/examples/mixed-engine-org.js +351 -0
- package/dist/examples/mixedEngineCli.d.ts +15 -0
- package/dist/examples/mixedEngineCli.d.ts.map +1 -0
- package/dist/examples/mixedEngineCli.js +174 -0
- package/dist/examples/pi-memory-org.d.ts +2 -0
- package/dist/examples/pi-memory-org.d.ts.map +1 -0
- package/dist/examples/pi-memory-org.js +230 -0
- package/dist/index.d.ts +1 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/observability/index.d.ts +2 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +1 -0
- package/dist/observability/orgObserver.d.ts +98 -0
- package/dist/observability/orgObserver.d.ts.map +1 -0
- package/dist/observability/orgObserver.js +181 -0
- package/dist/pi/index.d.ts +4 -0
- package/dist/pi/index.d.ts.map +1 -0
- package/dist/pi/index.js +3 -0
- package/dist/pi/memoryTools.d.ts +15 -0
- package/dist/pi/memoryTools.d.ts.map +1 -0
- package/dist/pi/memoryTools.js +70 -0
- package/dist/pi/piHarness.d.ts +8 -0
- package/dist/pi/piHarness.d.ts.map +1 -1
- package/dist/pi/piHarness.js +137 -6
- package/package.json +26 -4
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { access, mkdir, 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 { seedPiOpenAICodexAuthFromCodex } from "../pi/auth.js";
|
|
6
|
+
import { PiHarnessAdapter } from "../pi/piHarness.js";
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const daimonRoot = path.resolve(__dirname, "../..");
|
|
9
|
+
const runtimeRoot = path.join(daimonRoot, ".runtime", "pi-memory-org");
|
|
10
|
+
const piAuthPath = path.join(runtimeRoot, "auth", "auth.json");
|
|
11
|
+
const codexAuthPath = path.join(process.env.HOME ?? "", ".codex", "auth.json");
|
|
12
|
+
const demoAgents = [
|
|
13
|
+
{ id: "atlas", name: "Atlas", marker: "ATLAS_BLUE_17" },
|
|
14
|
+
{ id: "oracle", name: "Oracle", marker: "ORACLE_GOLD_23" },
|
|
15
|
+
{ id: "keeper", name: "Keeper", marker: "KEEPER_GREEN_31" }
|
|
16
|
+
];
|
|
17
|
+
const roomContext = {
|
|
18
|
+
networkId: "memory-lab",
|
|
19
|
+
roomId: "council",
|
|
20
|
+
teamId: "memory-e2e",
|
|
21
|
+
participants: demoAgents.map((agent) => agent.id)
|
|
22
|
+
};
|
|
23
|
+
const assertIncludes = (label, content, expected) => {
|
|
24
|
+
if (!content.includes(expected)) {
|
|
25
|
+
throw new Error(`${label} did not include ${expected}.\nActual:\n${content}`);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const assertCurrentPromptDoesNotLeakMarkers = (event) => {
|
|
29
|
+
for (const agent of demoAgents) {
|
|
30
|
+
if (event.text.includes(agent.marker)) {
|
|
31
|
+
throw new Error(`wake ${event.id} leaked marker ${agent.marker} in current prompt`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const agentRuntimeHome = (agentId) => path.join(runtimeRoot, "agents", agentId, "runtime");
|
|
36
|
+
const prepareWorkspace = async (agentId) => {
|
|
37
|
+
const workspacePath = path.join(runtimeRoot, "agents", agentId, "workspace");
|
|
38
|
+
const runtimeHomePath = agentRuntimeHome(agentId);
|
|
39
|
+
await mkdir(workspacePath, { recursive: true });
|
|
40
|
+
await mkdir(runtimeHomePath, { recursive: true });
|
|
41
|
+
await writeFile(path.join(workspacePath, "AGENTS.md"), [
|
|
42
|
+
`# ${agentId}`,
|
|
43
|
+
"",
|
|
44
|
+
"This workspace is part of the Daimon Pi memory-org E2E.",
|
|
45
|
+
"The test intentionally disables file tools and verifies persisted Daimon memory."
|
|
46
|
+
].join("\n"));
|
|
47
|
+
return { workspacePath, runtimeHomePath };
|
|
48
|
+
};
|
|
49
|
+
const setupRuntime = async () => {
|
|
50
|
+
await access(codexAuthPath);
|
|
51
|
+
await rm(runtimeRoot, { recursive: true, force: true });
|
|
52
|
+
await mkdir(path.dirname(piAuthPath), { recursive: true });
|
|
53
|
+
await seedPiOpenAICodexAuthFromCodex({ codexAuthPath, piAuthPath });
|
|
54
|
+
};
|
|
55
|
+
const resetPiSessionHistory = async (agentId) => {
|
|
56
|
+
await rm(path.join(agentRuntimeHome(agentId), "sessions"), { recursive: true, force: true });
|
|
57
|
+
};
|
|
58
|
+
const startAgent = async (adapter, agent) => {
|
|
59
|
+
const paths = await prepareWorkspace(agent.id);
|
|
60
|
+
return adapter.startAgent({
|
|
61
|
+
id: agent.id,
|
|
62
|
+
name: agent.name,
|
|
63
|
+
instructions: [
|
|
64
|
+
"You are participating in a live Daimon memory E2E.",
|
|
65
|
+
"Use the Memory context injected above the wake event as authoritative recalled memory.",
|
|
66
|
+
"When asked to recall marker tokens, copy exact marker tokens from memory.",
|
|
67
|
+
"Keep every response to one concise line unless the wake explicitly asks otherwise."
|
|
68
|
+
].join(" "),
|
|
69
|
+
tools: [],
|
|
70
|
+
...paths
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
const startAllAgents = async (adapter) => {
|
|
74
|
+
const handles = new Map();
|
|
75
|
+
for (const agent of demoAgents) {
|
|
76
|
+
handles.set(agent.id, await startAgent(adapter, agent));
|
|
77
|
+
}
|
|
78
|
+
return handles;
|
|
79
|
+
};
|
|
80
|
+
const stopAll = async (handles) => {
|
|
81
|
+
await Promise.all([...handles.values()].map((handle) => handle.stop()));
|
|
82
|
+
};
|
|
83
|
+
const wake = async (handle, event, options = {}) => {
|
|
84
|
+
if (options.assertNoMarkerLeak) {
|
|
85
|
+
assertCurrentPromptDoesNotLeakMarkers(event);
|
|
86
|
+
}
|
|
87
|
+
const result = await handle.wake(event);
|
|
88
|
+
console.log(`[${event.id}] ${result.agentId}: ${result.text}`);
|
|
89
|
+
return result;
|
|
90
|
+
};
|
|
91
|
+
const seedPrivateMemories = async (handles) => {
|
|
92
|
+
console.log("\n== Private seed phase ==");
|
|
93
|
+
for (const agent of demoAgents) {
|
|
94
|
+
const result = await handles.get(agent.id)?.wake({
|
|
95
|
+
id: `seed-${agent.id}`,
|
|
96
|
+
kind: "manual",
|
|
97
|
+
text: [
|
|
98
|
+
"Private memory seed.",
|
|
99
|
+
`Remember this exact marker token for later recall: ${agent.marker}`,
|
|
100
|
+
"Do not write files. Reply with exactly: stored"
|
|
101
|
+
].join("\n")
|
|
102
|
+
});
|
|
103
|
+
console.log(`[seed-${agent.id}] ${agent.id}: ${result?.text ?? ""}`);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const runRoomConversation = async (handles) => {
|
|
107
|
+
console.log("\n== Room recall phase ==");
|
|
108
|
+
const transcript = [];
|
|
109
|
+
const atlas = await wake(handles.get("atlas"), {
|
|
110
|
+
id: "room-atlas-1",
|
|
111
|
+
kind: "manual",
|
|
112
|
+
context: roomContext,
|
|
113
|
+
text: [
|
|
114
|
+
"Moltnet room simulation. Visible room transcript so far:",
|
|
115
|
+
transcript.join("\n") || "(empty)",
|
|
116
|
+
"Recall your private marker token from Daimon memory.",
|
|
117
|
+
"Reply in one line: @oracle atlas recalls <exact token>",
|
|
118
|
+
"Do not invent markers for other agents."
|
|
119
|
+
].join("\n")
|
|
120
|
+
}, { assertNoMarkerLeak: true });
|
|
121
|
+
assertIncludes("atlas room reply", atlas.text, "ATLAS_BLUE_17");
|
|
122
|
+
transcript.push(`atlas: ${atlas.text}`);
|
|
123
|
+
const oracle = await wake(handles.get("oracle"), {
|
|
124
|
+
id: "room-oracle-1",
|
|
125
|
+
kind: "manual",
|
|
126
|
+
context: roomContext,
|
|
127
|
+
text: [
|
|
128
|
+
"Moltnet room simulation. Visible room transcript so far:",
|
|
129
|
+
transcript.join("\n"),
|
|
130
|
+
"Recall your private marker token from Daimon memory and acknowledge Atlas from the transcript.",
|
|
131
|
+
"Reply in one line: @keeper oracle recalls <exact token>; observed atlas=<atlas token>"
|
|
132
|
+
].join("\n")
|
|
133
|
+
});
|
|
134
|
+
assertIncludes("oracle room reply", oracle.text, "ORACLE_GOLD_23");
|
|
135
|
+
assertIncludes("oracle room reply", oracle.text, "ATLAS_BLUE_17");
|
|
136
|
+
transcript.push(`oracle: ${oracle.text}`);
|
|
137
|
+
const keeper = await wake(handles.get("keeper"), {
|
|
138
|
+
id: "room-keeper-1",
|
|
139
|
+
kind: "manual",
|
|
140
|
+
context: roomContext,
|
|
141
|
+
text: [
|
|
142
|
+
"Moltnet room simulation. Visible room transcript so far:",
|
|
143
|
+
transcript.join("\n"),
|
|
144
|
+
"Recall your private marker token from Daimon memory and acknowledge Atlas and Oracle from the transcript.",
|
|
145
|
+
"Reply in one line: keeper recalls <exact token>; observed atlas=<atlas token> oracle=<oracle token>"
|
|
146
|
+
].join("\n")
|
|
147
|
+
});
|
|
148
|
+
assertIncludes("keeper room reply", keeper.text, "KEEPER_GREEN_31");
|
|
149
|
+
assertIncludes("keeper room reply", keeper.text, "ATLAS_BLUE_17");
|
|
150
|
+
assertIncludes("keeper room reply", keeper.text, "ORACLE_GOLD_23");
|
|
151
|
+
transcript.push(`keeper: ${keeper.text}`);
|
|
152
|
+
console.log("\nRoom transcript:");
|
|
153
|
+
for (const line of transcript) {
|
|
154
|
+
console.log(line);
|
|
155
|
+
}
|
|
156
|
+
return transcript;
|
|
157
|
+
};
|
|
158
|
+
const verifyFreshSessionRecall = async (adapter, previousKeeper) => {
|
|
159
|
+
console.log("\n== Fresh session recall phase ==");
|
|
160
|
+
await previousKeeper.stop();
|
|
161
|
+
await resetPiSessionHistory("keeper");
|
|
162
|
+
const keeper = await startAgent(adapter, demoAgents.find((agent) => agent.id === "keeper"));
|
|
163
|
+
try {
|
|
164
|
+
const event = {
|
|
165
|
+
id: "room-keeper-2",
|
|
166
|
+
kind: "manual",
|
|
167
|
+
context: roomContext,
|
|
168
|
+
text: [
|
|
169
|
+
"Fresh session check. You do not get the room transcript in this wake.",
|
|
170
|
+
"Use only Daimon memory recalled into this turn.",
|
|
171
|
+
"Report the marker tokens for atlas, oracle, and keeper from your previous memory-lab room turn.",
|
|
172
|
+
"Reply in one line: final atlas=<token> oracle=<token> keeper=<token>"
|
|
173
|
+
].join("\n")
|
|
174
|
+
};
|
|
175
|
+
const result = await wake(keeper, event, { assertNoMarkerLeak: true });
|
|
176
|
+
assertIncludes("fresh keeper recall", result.text, "ATLAS_BLUE_17");
|
|
177
|
+
assertIncludes("fresh keeper recall", result.text, "ORACLE_GOLD_23");
|
|
178
|
+
assertIncludes("fresh keeper recall", result.text, "KEEPER_GREEN_31");
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
await keeper.stop();
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
const printMemoryCounts = async () => {
|
|
185
|
+
console.log("\nMemory event counts:");
|
|
186
|
+
for (const agent of demoAgents) {
|
|
187
|
+
const events = await new JsonlMemoryStore(agentRuntimeHome(agent.id)).read();
|
|
188
|
+
const counts = events.reduce((memo, event) => {
|
|
189
|
+
memo[event.type] = (memo[event.type] ?? 0) + 1;
|
|
190
|
+
return memo;
|
|
191
|
+
}, {});
|
|
192
|
+
console.log(`${agent.id}: ${JSON.stringify(counts)}`);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
const run = async () => {
|
|
196
|
+
await setupRuntime();
|
|
197
|
+
const adapter = new PiHarnessAdapter({
|
|
198
|
+
authPath: piAuthPath,
|
|
199
|
+
model: {
|
|
200
|
+
provider: "openai-codex",
|
|
201
|
+
name: process.env.HARNESS_PI_MODEL ?? "gpt-5.4-mini"
|
|
202
|
+
},
|
|
203
|
+
memory: {
|
|
204
|
+
tokenBudget: 1800
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
const seedHandles = await startAllAgents(adapter);
|
|
208
|
+
await seedPrivateMemories(seedHandles);
|
|
209
|
+
await stopAll(seedHandles);
|
|
210
|
+
await Promise.all(demoAgents.map((agent) => resetPiSessionHistory(agent.id)));
|
|
211
|
+
const roomHandles = await startAllAgents(adapter);
|
|
212
|
+
try {
|
|
213
|
+
await runRoomConversation(roomHandles);
|
|
214
|
+
await verifyFreshSessionRecall(adapter, roomHandles.get("keeper"));
|
|
215
|
+
await roomHandles.get("atlas")?.stop();
|
|
216
|
+
await roomHandles.get("oracle")?.stop();
|
|
217
|
+
await printMemoryCounts();
|
|
218
|
+
console.log("\ne2e:pi-memory-org ok");
|
|
219
|
+
}
|
|
220
|
+
finally {
|
|
221
|
+
await Promise.all([
|
|
222
|
+
roomHandles.get("atlas")?.stop(),
|
|
223
|
+
roomHandles.get("oracle")?.stop()
|
|
224
|
+
]);
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
run().catch((error) => {
|
|
228
|
+
console.error(error instanceof Error ? error.stack ?? error.message : String(error));
|
|
229
|
+
process.exitCode = 1;
|
|
230
|
+
});
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/observability/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./orgObserver.js";
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { MemoryRecallAudit } from "@noopolis/mneme";
|
|
2
|
+
export interface WakeBenchRow {
|
|
3
|
+
agent: string;
|
|
4
|
+
engine: string;
|
|
5
|
+
event: string;
|
|
6
|
+
totalMs: number;
|
|
7
|
+
memoryPrepareMs: number;
|
|
8
|
+
engineMs: number;
|
|
9
|
+
memoryRecordMs: number;
|
|
10
|
+
promptChars: number;
|
|
11
|
+
outputChars: number;
|
|
12
|
+
recallCandidates: number;
|
|
13
|
+
recallSelected: number;
|
|
14
|
+
}
|
|
15
|
+
export interface TurnObservation extends WakeBenchRow {
|
|
16
|
+
mentions: string[];
|
|
17
|
+
outputText: string;
|
|
18
|
+
recall: Array<{
|
|
19
|
+
decision: string;
|
|
20
|
+
eventId: string;
|
|
21
|
+
representation: string;
|
|
22
|
+
scope: string;
|
|
23
|
+
}>;
|
|
24
|
+
signalsMentioned: string[];
|
|
25
|
+
signalsInWakeText: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface SignalObservation {
|
|
28
|
+
agent: string;
|
|
29
|
+
engine: string;
|
|
30
|
+
signal: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ConsultationObservation {
|
|
33
|
+
event: string;
|
|
34
|
+
from: string;
|
|
35
|
+
observed: boolean;
|
|
36
|
+
outputText: string;
|
|
37
|
+
to: string;
|
|
38
|
+
}
|
|
39
|
+
export interface BehaviorAssertion {
|
|
40
|
+
detail: string;
|
|
41
|
+
event: string;
|
|
42
|
+
kind: "consultation" | "no-leak" | "recall";
|
|
43
|
+
passed: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface OrgObserverOptions {
|
|
46
|
+
orgId: string;
|
|
47
|
+
runId: string;
|
|
48
|
+
}
|
|
49
|
+
export declare const mentionsFrom: (text: string) => string[];
|
|
50
|
+
export declare class OrgObserver {
|
|
51
|
+
readonly options: OrgObserverOptions;
|
|
52
|
+
readonly assertions: BehaviorAssertion[];
|
|
53
|
+
readonly consultations: ConsultationObservation[];
|
|
54
|
+
readonly signals: SignalObservation[];
|
|
55
|
+
readonly turns: TurnObservation[];
|
|
56
|
+
constructor(options: OrgObserverOptions);
|
|
57
|
+
knownSignals(): string[];
|
|
58
|
+
recordAssertion(assertion: BehaviorAssertion): void;
|
|
59
|
+
recordSignal(input: SignalObservation): void;
|
|
60
|
+
recordTurn(input: {
|
|
61
|
+
agent: string;
|
|
62
|
+
engine: string;
|
|
63
|
+
engineMs: number;
|
|
64
|
+
event: string;
|
|
65
|
+
eventText: string;
|
|
66
|
+
memoryPrepareMs: number;
|
|
67
|
+
memoryRecordMs: number;
|
|
68
|
+
outputChars: number;
|
|
69
|
+
outputText: string;
|
|
70
|
+
promptChars: number;
|
|
71
|
+
recall: MemoryRecallAudit;
|
|
72
|
+
totalMs: number;
|
|
73
|
+
}): void;
|
|
74
|
+
recordConsultation(input: {
|
|
75
|
+
event: string;
|
|
76
|
+
from: string;
|
|
77
|
+
outputText: string;
|
|
78
|
+
to: string;
|
|
79
|
+
}): ConsultationObservation;
|
|
80
|
+
benchRows(): WakeBenchRow[];
|
|
81
|
+
summary(): Record<string, {
|
|
82
|
+
count: number;
|
|
83
|
+
engineMs: number;
|
|
84
|
+
promptChars: number;
|
|
85
|
+
totalMs: number;
|
|
86
|
+
}>;
|
|
87
|
+
behaviorSummary(): {
|
|
88
|
+
assertionPassRate: number;
|
|
89
|
+
consultationObservedRate: number;
|
|
90
|
+
signalsGenerated: number;
|
|
91
|
+
totalRecallSelected: number;
|
|
92
|
+
totalTurns: number;
|
|
93
|
+
};
|
|
94
|
+
tracePayload(): object;
|
|
95
|
+
write(runtimeRoot: string): Promise<void>;
|
|
96
|
+
toMarkdown(): string;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=orgObserver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orgObserver.d.ts","sourceRoot":"","sources":["../../src/observability/orgObserver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const maxExcerptChars = 280;
|
|
4
|
+
const excerpt = (text) => text.length <= maxExcerptChars ? text : `${text.slice(0, maxExcerptChars).trim()}...`;
|
|
5
|
+
export const mentionsFrom = (text) => [...new Set([...text.matchAll(/@([a-z0-9-]+)/gi)].map((match) => match[1].toLowerCase()))];
|
|
6
|
+
export class OrgObserver {
|
|
7
|
+
options;
|
|
8
|
+
assertions = [];
|
|
9
|
+
consultations = [];
|
|
10
|
+
signals = [];
|
|
11
|
+
turns = [];
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.options = options;
|
|
14
|
+
}
|
|
15
|
+
knownSignals() {
|
|
16
|
+
return this.signals.map((signal) => signal.signal);
|
|
17
|
+
}
|
|
18
|
+
recordAssertion(assertion) {
|
|
19
|
+
this.assertions.push(assertion);
|
|
20
|
+
}
|
|
21
|
+
recordSignal(input) {
|
|
22
|
+
this.signals.push(input);
|
|
23
|
+
}
|
|
24
|
+
recordTurn(input) {
|
|
25
|
+
this.turns.push({
|
|
26
|
+
agent: input.agent,
|
|
27
|
+
engine: input.engine,
|
|
28
|
+
event: input.event,
|
|
29
|
+
totalMs: input.totalMs,
|
|
30
|
+
memoryPrepareMs: input.memoryPrepareMs,
|
|
31
|
+
engineMs: input.engineMs,
|
|
32
|
+
memoryRecordMs: input.memoryRecordMs,
|
|
33
|
+
promptChars: input.promptChars,
|
|
34
|
+
outputChars: input.outputChars,
|
|
35
|
+
recallCandidates: input.recall.totalCandidates,
|
|
36
|
+
recallSelected: input.recall.selectedEventIds.length,
|
|
37
|
+
mentions: mentionsFrom(input.outputText),
|
|
38
|
+
outputText: input.outputText,
|
|
39
|
+
recall: (input.recall.selected ?? []).map((selected) => ({
|
|
40
|
+
decision: selected.decision,
|
|
41
|
+
eventId: selected.eventId,
|
|
42
|
+
representation: excerpt(selected.representation),
|
|
43
|
+
scope: selected.scope
|
|
44
|
+
})),
|
|
45
|
+
signalsMentioned: this.knownSignals().filter((signal) => input.outputText.includes(signal)),
|
|
46
|
+
signalsInWakeText: this.knownSignals().filter((signal) => input.eventText.includes(signal))
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
recordConsultation(input) {
|
|
50
|
+
const observed = mentionsFrom(input.outputText).includes(input.to);
|
|
51
|
+
const edge = { ...input, observed };
|
|
52
|
+
this.consultations.push(edge);
|
|
53
|
+
this.recordAssertion({
|
|
54
|
+
detail: `${input.from} should mention @${input.to}`,
|
|
55
|
+
event: input.event,
|
|
56
|
+
kind: "consultation",
|
|
57
|
+
passed: observed
|
|
58
|
+
});
|
|
59
|
+
return edge;
|
|
60
|
+
}
|
|
61
|
+
benchRows() {
|
|
62
|
+
return this.turns.map((turn) => ({
|
|
63
|
+
agent: turn.agent,
|
|
64
|
+
engine: turn.engine,
|
|
65
|
+
event: turn.event,
|
|
66
|
+
totalMs: turn.totalMs,
|
|
67
|
+
memoryPrepareMs: turn.memoryPrepareMs,
|
|
68
|
+
engineMs: turn.engineMs,
|
|
69
|
+
memoryRecordMs: turn.memoryRecordMs,
|
|
70
|
+
promptChars: turn.promptChars,
|
|
71
|
+
outputChars: turn.outputChars,
|
|
72
|
+
recallCandidates: turn.recallCandidates,
|
|
73
|
+
recallSelected: turn.recallSelected
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
summary() {
|
|
77
|
+
return this.turns.reduce((memo, turn) => {
|
|
78
|
+
const value = memo[turn.engine] ?? { count: 0, engineMs: 0, promptChars: 0, totalMs: 0 };
|
|
79
|
+
value.count += 1;
|
|
80
|
+
value.engineMs += turn.engineMs;
|
|
81
|
+
value.promptChars += turn.promptChars;
|
|
82
|
+
value.totalMs += turn.totalMs;
|
|
83
|
+
memo[turn.engine] = value;
|
|
84
|
+
return memo;
|
|
85
|
+
}, {});
|
|
86
|
+
}
|
|
87
|
+
behaviorSummary() {
|
|
88
|
+
const passedAssertions = this.assertions.filter((assertion) => assertion.passed).length;
|
|
89
|
+
const observedConsultations = this.consultations.filter((edge) => edge.observed).length;
|
|
90
|
+
const rate = (part, total) => total === 0 ? 1 : part / total;
|
|
91
|
+
return {
|
|
92
|
+
assertionPassRate: rate(passedAssertions, this.assertions.length),
|
|
93
|
+
consultationObservedRate: rate(observedConsultations, this.consultations.length),
|
|
94
|
+
signalsGenerated: this.signals.length,
|
|
95
|
+
totalRecallSelected: this.turns.reduce((total, turn) => total + turn.recallSelected, 0),
|
|
96
|
+
totalTurns: this.turns.length
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
tracePayload() {
|
|
100
|
+
return {
|
|
101
|
+
assertions: this.assertions,
|
|
102
|
+
behavior: this.behaviorSummary(),
|
|
103
|
+
consultations: this.consultations,
|
|
104
|
+
org_id: this.options.orgId,
|
|
105
|
+
run_id: this.options.runId,
|
|
106
|
+
schema: "daimon.org.telemetry/v1",
|
|
107
|
+
signals: this.signals,
|
|
108
|
+
summary: this.summary(),
|
|
109
|
+
turns: this.turns
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
async write(runtimeRoot) {
|
|
113
|
+
const telemetryDir = path.join(runtimeRoot, "telemetry");
|
|
114
|
+
await mkdir(telemetryDir, { recursive: true });
|
|
115
|
+
const summaryRecord = {
|
|
116
|
+
assertions: this.assertions,
|
|
117
|
+
behavior: this.behaviorSummary(),
|
|
118
|
+
kind: "org.turn_summary",
|
|
119
|
+
org_id: this.options.orgId,
|
|
120
|
+
run_id: this.options.runId,
|
|
121
|
+
schema: "daimon.org.telemetry/v1",
|
|
122
|
+
summary: this.summary()
|
|
123
|
+
};
|
|
124
|
+
const turnRecords = this.turns.map((turn) => ({
|
|
125
|
+
kind: "org.turn",
|
|
126
|
+
org_id: this.options.orgId,
|
|
127
|
+
run_id: this.options.runId,
|
|
128
|
+
schema: "daimon.org.telemetry/v1",
|
|
129
|
+
turn
|
|
130
|
+
}));
|
|
131
|
+
const ndjson = [...turnRecords, summaryRecord]
|
|
132
|
+
.map((record) => JSON.stringify(record))
|
|
133
|
+
.join("\n");
|
|
134
|
+
await writeFile(path.join(runtimeRoot, "trace.json"), `${JSON.stringify(this.tracePayload(), null, 2)}\n`);
|
|
135
|
+
await writeFile(path.join(runtimeRoot, "trace.md"), this.toMarkdown());
|
|
136
|
+
await writeFile(path.join(runtimeRoot, "bench.json"), `${JSON.stringify({ rows: this.benchRows(), summary: this.summary() }, null, 2)}\n`);
|
|
137
|
+
await writeFile(path.join(telemetryDir, "events.ndjson"), `${ndjson}\n`);
|
|
138
|
+
await writeFile(path.join(telemetryDir, "summary.json"), `${JSON.stringify(summaryRecord, null, 2)}\n`);
|
|
139
|
+
}
|
|
140
|
+
toMarkdown() {
|
|
141
|
+
const lines = [
|
|
142
|
+
"# Mixed Engine Org Trace",
|
|
143
|
+
"",
|
|
144
|
+
`- org: ${this.options.orgId}`,
|
|
145
|
+
`- run: ${this.options.runId}`,
|
|
146
|
+
"",
|
|
147
|
+
"## Behavior",
|
|
148
|
+
"",
|
|
149
|
+
`- assertion_pass_rate: ${this.behaviorSummary().assertionPassRate}`,
|
|
150
|
+
`- consultation_observed_rate: ${this.behaviorSummary().consultationObservedRate}`,
|
|
151
|
+
`- total_recall_selected: ${this.behaviorSummary().totalRecallSelected}`,
|
|
152
|
+
"",
|
|
153
|
+
"## Signals",
|
|
154
|
+
"",
|
|
155
|
+
"| Agent | Engine | Signal |",
|
|
156
|
+
"| --- | --- | --- |",
|
|
157
|
+
...this.signals.map((signal) => `| ${signal.agent} | ${signal.engine} | ${signal.signal} |`),
|
|
158
|
+
"",
|
|
159
|
+
"## Consultations",
|
|
160
|
+
"",
|
|
161
|
+
"| Event | Edge | Observed |",
|
|
162
|
+
"| --- | --- | --- |",
|
|
163
|
+
...this.consultations.map((edge) => `| ${edge.event} | ${edge.from} -> ${edge.to} | ${edge.observed ? "yes" : "no"} |`),
|
|
164
|
+
"",
|
|
165
|
+
"## Turns",
|
|
166
|
+
""
|
|
167
|
+
];
|
|
168
|
+
for (const turn of this.turns) {
|
|
169
|
+
lines.push(`### ${turn.event}`, "", `- agent: ${turn.agent}`, `- engine: ${turn.engine}`, `- total_ms: ${turn.totalMs}`, `- engine_ms: ${turn.engineMs}`, `- memory_prepare_ms: ${turn.memoryPrepareMs}`, `- memory_record_ms: ${turn.memoryRecordMs}`, `- prompt_chars: ${turn.promptChars}`, `- recall: ${turn.recallSelected}/${turn.recallCandidates}`, `- mentions: ${turn.mentions.join(", ") || "(none)"}`, `- signals_mentioned: ${turn.signalsMentioned.join(", ") || "(none)"}`, "", "Output:", "", `> ${turn.outputText}`, "");
|
|
170
|
+
if (turn.recall.length > 0) {
|
|
171
|
+
lines.push("Recalled memory:", "");
|
|
172
|
+
for (const recall of turn.recall) {
|
|
173
|
+
lines.push(`- ${recall.eventId} [${recall.decision}] ${recall.representation}`);
|
|
174
|
+
}
|
|
175
|
+
lines.push("");
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
lines.push("## Assertions", "", "| Event | Kind | Passed | Detail |", "| --- | --- | --- | --- |", ...this.assertions.map((assertion) => `| ${assertion.event} | ${assertion.kind} | ${assertion.passed ? "yes" : "no"} | ${assertion.detail} |`), "");
|
|
179
|
+
return lines.join("\n");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pi/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC"}
|
package/dist/pi/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { MemoryRuntime, MemoryToolExecutionContext } from "@noopolis/mneme";
|
|
3
|
+
export interface PiMemoryToolContextRef {
|
|
4
|
+
current?: MemoryToolExecutionContext;
|
|
5
|
+
}
|
|
6
|
+
interface PiMemoryToolInput {
|
|
7
|
+
agentId: string;
|
|
8
|
+
memory: MemoryRuntime;
|
|
9
|
+
contextRef: PiMemoryToolContextRef;
|
|
10
|
+
}
|
|
11
|
+
type PiMemoryTool = ToolDefinition<any, unknown>;
|
|
12
|
+
export declare const createPiMemoryTools: (input: PiMemoryToolInput) => PiMemoryTool[];
|
|
13
|
+
export declare const piMemoryToolNames: (tools: PiMemoryTool[]) => string[];
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=memoryTools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryTools.d.ts","sourceRoot":"","sources":["../../src/pi/memoryTools.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAGlF,OAAO,KAAK,EAAE,aAAa,EAAE,0BAA0B,EAAoB,MAAM,iBAAiB,CAAC;AAEnG,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,0BAA0B,CAAC;CACtC;AAED,UAAU,iBAAiB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,sBAAsB,CAAC;CACpC;AAED,KAAK,YAAY,GAAG,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AA4DjD,eAAO,MAAM,mBAAmB,GAAI,OAAO,iBAAiB,KAAG,YAAY,EAiBxE,CAAC;AAEJ,eAAO,MAAM,iBAAiB,GAAI,OAAO,YAAY,EAAE,KAAG,MAAM,EAChC,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Type } from "@earendil-works/pi-ai";
|
|
2
|
+
import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { createMemoryToolDescriptors } from "@noopolis/mneme";
|
|
4
|
+
const fallbackContext = (agentId) => ({
|
|
5
|
+
wakeId: "manual",
|
|
6
|
+
threadId: "manual",
|
|
7
|
+
principal: { agentId, scope: "global" },
|
|
8
|
+
conversationScope: "global",
|
|
9
|
+
audienceKey: agentId,
|
|
10
|
+
transport: "in_process"
|
|
11
|
+
});
|
|
12
|
+
const textContent = (result) => ({
|
|
13
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
14
|
+
details: result
|
|
15
|
+
});
|
|
16
|
+
const contentSchema = Type.Object({
|
|
17
|
+
kind: Type.String({ description: "Memory content kind: text, claim, decision, artifact, or relationship." })
|
|
18
|
+
}, { additionalProperties: true });
|
|
19
|
+
const schemaFor = (name) => {
|
|
20
|
+
if (name === "memory_search") {
|
|
21
|
+
return Type.Object({
|
|
22
|
+
scope: Type.String({ description: "Scope alias or canonical scope id. Use current, global, or all when appropriate." }),
|
|
23
|
+
query: Type.String({ description: "Search query." }),
|
|
24
|
+
limit: Type.Optional(Type.Number({ description: "Maximum result count." }))
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
if (name === "memory_locate") {
|
|
28
|
+
return Type.Object({
|
|
29
|
+
query: Type.String({ description: "What to locate in memory." }),
|
|
30
|
+
limit: Type.Optional(Type.Number({ description: "Maximum candidate count." })),
|
|
31
|
+
active_scope: Type.Optional(Type.String({ description: "Optional active scope hint." }))
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (name === "memory_register") {
|
|
35
|
+
return Type.Object({
|
|
36
|
+
scope: Type.String({ description: "Scope alias or canonical scope id where the memory belongs." }),
|
|
37
|
+
kind: Type.String({ description: "Memory content kind." }),
|
|
38
|
+
content: contentSchema,
|
|
39
|
+
visibility: Type.String({ description: "private, pair, team, room, global, public, or sealed." }),
|
|
40
|
+
sensitivity: Type.String({ description: "normal, sensitive, or secret." }),
|
|
41
|
+
evidence_event_ids: Type.Array(Type.String(), { description: "Event ids that justify the memory." }),
|
|
42
|
+
source_type: Type.String({ description: "Source label for the registered memory." }),
|
|
43
|
+
confidence: Type.Optional(Type.Number({ description: "Confidence from 0 to 1." }))
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (name === "memory_summarize") {
|
|
47
|
+
return Type.Object({
|
|
48
|
+
scope: Type.String({ description: "Scope alias or canonical scope id to summarize." }),
|
|
49
|
+
horizon: Type.Optional(Type.Number({ description: "Approximate number of recent memories to include." }))
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return Type.Object({
|
|
53
|
+
scope: Type.String({ description: "Scope alias or canonical scope id for the tombstone." }),
|
|
54
|
+
event_ids: Type.Array(Type.String(), { description: "Memory event ids to tombstone." }),
|
|
55
|
+
reason: Type.Optional(Type.String({ description: "Why these memories should be forgotten." }))
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
export const createPiMemoryTools = (input) => createMemoryToolDescriptors(input.memory.kernel).map((descriptor) => defineTool({
|
|
59
|
+
name: descriptor.modelName,
|
|
60
|
+
label: descriptor.label,
|
|
61
|
+
description: descriptor.description,
|
|
62
|
+
promptSnippet: descriptor.promptSnippet,
|
|
63
|
+
promptGuidelines: descriptor.promptGuidelines,
|
|
64
|
+
parameters: schemaFor(descriptor.modelName),
|
|
65
|
+
async execute(_toolCallId, params) {
|
|
66
|
+
const result = await descriptor.invoke(params, input.contextRef.current ?? fallbackContext(input.agentId));
|
|
67
|
+
return textContent(result);
|
|
68
|
+
}
|
|
69
|
+
}));
|
|
70
|
+
export const piMemoryToolNames = (tools) => tools.map((tool) => tool.name);
|