akemon 0.3.6 → 0.3.7
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/DATA_POLICY.md +11 -3
- package/README.md +133 -21
- package/dist/akemon-home.js +56 -0
- package/dist/akemon-message.js +107 -0
- package/dist/best-effort.js +8 -0
- package/dist/cli.js +1188 -100
- package/dist/cognitive-artifact-store.js +101 -0
- package/dist/cognitive-event-log.js +47 -0
- package/dist/config.js +45 -9
- package/dist/context.js +27 -6
- package/dist/core/contracts/layers.js +1 -0
- package/dist/core/contracts/permission.js +1 -0
- package/dist/core/contracts/workspace.js +1 -0
- package/dist/core-cognitive-module.js +768 -0
- package/dist/engine-peripheral.js +127 -26
- package/dist/engine-routing.js +58 -17
- package/dist/interactive-session.js +361 -0
- package/dist/local-interconnect.js +156 -0
- package/dist/local-registry.js +178 -0
- package/dist/mcp-server.js +4 -1
- package/dist/memory-proposal.js +379 -0
- package/dist/memory-recorder.js +368 -0
- package/dist/orphan-scan.js +36 -24
- package/dist/passive-reflection-cognitive-module.js +172 -0
- package/dist/peripheral-registry.js +235 -0
- package/dist/permission-audit.js +132 -0
- package/dist/relay-client.js +68 -9
- package/dist/relay-mode.js +34 -0
- package/dist/relay-peripheral.js +139 -49
- package/dist/runtime-platform.js +122 -0
- package/dist/secretariat/client.js +87 -0
- package/dist/self.js +15 -6
- package/dist/server.js +3675 -512
- package/dist/social-discovery.js +231 -0
- package/dist/software-agent-peripheral.js +185 -244
- package/dist/software-agent-transport.js +177 -0
- package/dist/task-module.js +243 -0
- package/dist/task-registry.js +756 -0
- package/dist/vendor/xterm/addon-fit.js +2 -0
- package/dist/vendor/xterm/addon-search.js +2 -0
- package/dist/vendor/xterm/addon-web-links.js +2 -0
- package/dist/vendor/xterm/xterm.css +285 -0
- package/dist/vendor/xterm/xterm.js +2 -0
- package/dist/work-memory.js +59 -15
- package/dist/workbench-peripheral-guide.js +79 -0
- package/dist/workbench-session.js +1074 -0
- package/dist/workbench.html +4011 -0
- package/package.json +8 -3
- package/scripts/build.cjs +24 -0
- package/scripts/check-architecture-baseline.cjs +68 -0
- package/scripts/test.cjs +38 -0
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
const BUILTIN_MEMORY_RECORDERS = [
|
|
2
|
+
{
|
|
3
|
+
id: "agent-home-initialization",
|
|
4
|
+
title: "Agent home and self-memory initialization",
|
|
5
|
+
source: "builtin",
|
|
6
|
+
owner: "self",
|
|
7
|
+
trigger: {
|
|
8
|
+
event: "agent:first-use",
|
|
9
|
+
description: "Creates the per-agent home, config, self directories, world guide, identity seed, and bio-state.",
|
|
10
|
+
},
|
|
11
|
+
destinations: [
|
|
12
|
+
destination("config", "~/.akemon/agents/{agent}/config.json", "json", "create", "Per-agent runtime configuration."),
|
|
13
|
+
destination("self", "~/.akemon/agents/{agent}/self/world.md", "markdown", "create", "World and network orientation."),
|
|
14
|
+
destination("self", "~/.akemon/agents/{agent}/self/identity.jsonl", "jsonl", "create", "Initial identity snapshot."),
|
|
15
|
+
destination("self", "~/.akemon/agents/{agent}/self/bio-state.json", "json", "create", "Initial bio-state."),
|
|
16
|
+
destination("self", "~/.akemon/agents/{agent}/self/guide.md", "markdown", "create", "Relay/network operating guide when relay is enabled."),
|
|
17
|
+
],
|
|
18
|
+
privacy: privacy(false, false, false),
|
|
19
|
+
enabled: true,
|
|
20
|
+
sourceFiles: ["src/self.ts", "src/akemon-home.ts"],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "conversation-transcript",
|
|
24
|
+
title: "Conversation transcript",
|
|
25
|
+
source: "builtin",
|
|
26
|
+
owner: "context",
|
|
27
|
+
trigger: {
|
|
28
|
+
event: "conversation:message",
|
|
29
|
+
description: "Appends owner/agent chat and order rounds to a local markdown conversation transcript.",
|
|
30
|
+
},
|
|
31
|
+
destinations: [
|
|
32
|
+
destination("conversation", "{workdir}/.akemon/agents/{agent}/conversations/{conversation}.md", "markdown", "append", "Conversation summary and recent rounds."),
|
|
33
|
+
],
|
|
34
|
+
privacy: privacy(false, true, false),
|
|
35
|
+
enabled: true,
|
|
36
|
+
sourceFiles: ["src/context.ts", "src/mcp-server.ts", "src/task-module.ts"],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "product-context-log",
|
|
40
|
+
title: "Product interaction context",
|
|
41
|
+
source: "builtin",
|
|
42
|
+
owner: "context",
|
|
43
|
+
trigger: {
|
|
44
|
+
event: "product:interaction",
|
|
45
|
+
description: "Records product purchase requests/responses and creates product notes for service improvement.",
|
|
46
|
+
},
|
|
47
|
+
destinations: [
|
|
48
|
+
destination("product", "{workdir}/.akemon/products/{product}/history.log", "log", "append", "Product interaction request/response excerpts."),
|
|
49
|
+
destination("product", "{workdir}/.akemon/products/{product}/notes.md", "markdown", "create", "Editable product context notes."),
|
|
50
|
+
],
|
|
51
|
+
privacy: privacy(false, true, false),
|
|
52
|
+
enabled: true,
|
|
53
|
+
sourceFiles: ["src/context.ts", "src/mcp-server.ts"],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: "task-history",
|
|
57
|
+
title: "Task execution history",
|
|
58
|
+
source: "builtin",
|
|
59
|
+
owner: "task",
|
|
60
|
+
trigger: {
|
|
61
|
+
event: "task:completed",
|
|
62
|
+
description: "Records concise task/order execution outcome summaries.",
|
|
63
|
+
},
|
|
64
|
+
destinations: [
|
|
65
|
+
destination("self", "~/.akemon/agents/{agent}/self/task-history.jsonl", "jsonl", "append", "Recent task outcome ledger."),
|
|
66
|
+
destination("self", "~/.akemon/agents/{agent}/self/task-runs.json", "json", "overwrite", "Due-task run timestamps."),
|
|
67
|
+
],
|
|
68
|
+
privacy: privacy(false, true, false),
|
|
69
|
+
enabled: true,
|
|
70
|
+
sourceFiles: ["src/self.ts", "src/task-module.ts"],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: "subjective-impressions",
|
|
74
|
+
title: "Subjective impressions",
|
|
75
|
+
source: "module",
|
|
76
|
+
owner: "memory",
|
|
77
|
+
trigger: {
|
|
78
|
+
event: "impression:new",
|
|
79
|
+
description: "Records subjective observations, decisions, activity notes, and errors for later digestion.",
|
|
80
|
+
},
|
|
81
|
+
destinations: [
|
|
82
|
+
destination("self", "~/.akemon/agents/{agent}/self/impressions.jsonl", "jsonl", "append", "Subjective impression records; digestion can compress or mark entries."),
|
|
83
|
+
],
|
|
84
|
+
privacy: privacy(false, true, false),
|
|
85
|
+
enabled: true,
|
|
86
|
+
sourceFiles: ["src/self.ts", "src/memory-module.ts", "src/script-module.ts", "src/task-module.ts"],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: "identity-and-summary",
|
|
90
|
+
title: "Identity snapshots and summary",
|
|
91
|
+
source: "module",
|
|
92
|
+
owner: "memory",
|
|
93
|
+
trigger: {
|
|
94
|
+
event: "digestion:complete",
|
|
95
|
+
description: "Writes identity snapshots and compressed identity summary from self-cycle digestion.",
|
|
96
|
+
},
|
|
97
|
+
destinations: [
|
|
98
|
+
destination("self", "~/.akemon/agents/{agent}/self/identity.jsonl", "jsonl", "append", "Five-question identity snapshots."),
|
|
99
|
+
destination("self", "~/.akemon/agents/{agent}/self/identity-summary.json", "json", "overwrite", "Compressed identity summary."),
|
|
100
|
+
],
|
|
101
|
+
privacy: privacy(false, true, false),
|
|
102
|
+
enabled: true,
|
|
103
|
+
sourceFiles: ["src/self.ts", "src/memory-module.ts"],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: "structured-self-memory",
|
|
107
|
+
title: "Structured self-memory stores",
|
|
108
|
+
source: "module",
|
|
109
|
+
owner: "memory",
|
|
110
|
+
trigger: {
|
|
111
|
+
event: "digestion:complete",
|
|
112
|
+
description: "Updates projects, relationships, discoveries, and canvas entries from digestion/reflection modules.",
|
|
113
|
+
},
|
|
114
|
+
destinations: [
|
|
115
|
+
destination("self", "~/.akemon/agents/{agent}/self/projects.jsonl", "jsonl", "overwrite", "Long-term project records."),
|
|
116
|
+
destination("self", "~/.akemon/agents/{agent}/self/relationships.jsonl", "jsonl", "overwrite", "Social relationship records."),
|
|
117
|
+
destination("self", "~/.akemon/agents/{agent}/self/discoveries.jsonl", "jsonl", "overwrite", "Lessons and capability discoveries."),
|
|
118
|
+
destination("self", "~/.akemon/agents/{agent}/self/canvas/{timestamp}.md", "markdown", "create", "Creative inner-canvas entries."),
|
|
119
|
+
],
|
|
120
|
+
privacy: privacy(false, true, false),
|
|
121
|
+
enabled: true,
|
|
122
|
+
sourceFiles: ["src/self.ts", "src/memory-module.ts", "src/social-module.ts", "src/longterm-module.ts", "src/reflection-module.ts"],
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: "bio-state-and-events",
|
|
126
|
+
title: "Bio-state and bio events",
|
|
127
|
+
source: "module",
|
|
128
|
+
owner: "biostate",
|
|
129
|
+
trigger: {
|
|
130
|
+
event: "bio:update",
|
|
131
|
+
description: "Updates bio-state and appends bounded bio event records from tasks, token usage, digestion, and shop actions.",
|
|
132
|
+
},
|
|
133
|
+
destinations: [
|
|
134
|
+
destination("self", "~/.akemon/agents/{agent}/self/bio-state.json", "json", "overwrite", "Current hunger, mood, energy, boredom, fear, and personality state."),
|
|
135
|
+
destination("self", "~/.akemon/agents/{agent}/self/bio-events.jsonl", "jsonl", "append", "Recent bio event ledger."),
|
|
136
|
+
],
|
|
137
|
+
privacy: privacy(false, false, false),
|
|
138
|
+
enabled: true,
|
|
139
|
+
sourceFiles: ["src/self.ts", "src/bio-module.ts", "src/task-module.ts", "src/mcp-server.ts"],
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: "role-playbook-product-files",
|
|
143
|
+
title: "Role, playbook, and product files",
|
|
144
|
+
source: "builtin",
|
|
145
|
+
owner: "role",
|
|
146
|
+
trigger: {
|
|
147
|
+
event: "role-or-product:update",
|
|
148
|
+
description: "Creates and updates role, playbook, and product markdown files; reflection may append playbook experience.",
|
|
149
|
+
},
|
|
150
|
+
destinations: [
|
|
151
|
+
destination("self", "~/.akemon/agents/{agent}/self/roles/{name}.md", "markdown", "create", "Role definitions and context boundaries."),
|
|
152
|
+
destination("self", "~/.akemon/agents/{agent}/self/playbooks/{name}.md", "markdown", "append", "Reusable domain playbooks and experience notes."),
|
|
153
|
+
destination("self", "~/.akemon/agents/{agent}/self/products/{name}.md", "markdown", "create", "Product-to-playbook mappings."),
|
|
154
|
+
],
|
|
155
|
+
privacy: privacy(false, true, false),
|
|
156
|
+
enabled: true,
|
|
157
|
+
sourceFiles: ["src/role-module.ts", "src/reflection-module.ts"],
|
|
158
|
+
notes: "Natural-language reusable rules should eventually consolidate into relevant skill/playbook files through proposals and conflict review.",
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: "work-memory-note",
|
|
162
|
+
title: "Work memory notes",
|
|
163
|
+
source: "builtin",
|
|
164
|
+
owner: "work-memory",
|
|
165
|
+
trigger: {
|
|
166
|
+
event: "work-memory:note",
|
|
167
|
+
description: "Appends user or software-agent work notes to project or global work memory.",
|
|
168
|
+
},
|
|
169
|
+
destinations: [
|
|
170
|
+
destination("work", "{workdir}/.akemon/work/inbox.md", "markdown", "append", "Project-scoped work memory inbox."),
|
|
171
|
+
destination("work", "~/.akemon/agents/{agent}/work/inbox.md", "markdown", "append", "Global per-agent work memory inbox."),
|
|
172
|
+
],
|
|
173
|
+
privacy: privacy(true, true, false),
|
|
174
|
+
enabled: true,
|
|
175
|
+
sourceFiles: ["src/work-memory.ts", "src/cli.ts"],
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "software-agent-ledger",
|
|
179
|
+
title: "Software-agent task ledger and context sessions",
|
|
180
|
+
source: "builtin",
|
|
181
|
+
owner: "software-agent",
|
|
182
|
+
trigger: {
|
|
183
|
+
event: "software-agent:task",
|
|
184
|
+
description: "Records Codex software-agent task envelopes, summaries, environment audit, context packets, and session state.",
|
|
185
|
+
},
|
|
186
|
+
destinations: [
|
|
187
|
+
destination("software-agent", "{workdir}/.akemon/agents/{agent}/software-agent/tasks/{taskId}.json", "json", "overwrite", "Per-task software-agent ledger record."),
|
|
188
|
+
destination("software-agent", "{workdir}/.akemon/agents/{agent}/software-agent/sessions/{session}/TASK_CONTEXT.md", "markdown", "overwrite", "Akemon-generated context packet."),
|
|
189
|
+
destination("software-agent", "{workdir}/.akemon/agents/{agent}/software-agent/sessions/{session}/SESSION.json", "json", "overwrite", "Akemon-side software-agent session state."),
|
|
190
|
+
],
|
|
191
|
+
privacy: privacy(true, true, false),
|
|
192
|
+
enabled: true,
|
|
193
|
+
sourceFiles: ["src/software-agent-peripheral.ts", "src/software-agent-transport.ts", "src/software-agent-memory.ts", "src/server.ts"],
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
id: "local-peer-contact",
|
|
197
|
+
title: "Local peer contact metadata",
|
|
198
|
+
source: "builtin",
|
|
199
|
+
owner: "local-interconnect",
|
|
200
|
+
trigger: {
|
|
201
|
+
event: "akemon.message",
|
|
202
|
+
description: "Records sent/received local Akemon peer contact metadata without merging self memory.",
|
|
203
|
+
},
|
|
204
|
+
destinations: [
|
|
205
|
+
destination("contacts", "~/.akemon/agents/{agent}/contacts/local-peers.jsonl", "jsonl", "append", "Local peer message metadata."),
|
|
206
|
+
],
|
|
207
|
+
privacy: privacy(false, false, false),
|
|
208
|
+
enabled: true,
|
|
209
|
+
sourceFiles: ["src/local-interconnect.ts", "src/server.ts", "src/cli.ts"],
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
id: "accepted-social-contact",
|
|
213
|
+
title: "Accepted social contact metadata",
|
|
214
|
+
source: "builtin",
|
|
215
|
+
owner: "social-discovery",
|
|
216
|
+
trigger: {
|
|
217
|
+
event: "akemon.intro.response",
|
|
218
|
+
description: "Records accepted relay/local social introductions as contact metadata.",
|
|
219
|
+
},
|
|
220
|
+
destinations: [
|
|
221
|
+
destination("contacts", "~/.akemon/agents/{agent}/contacts/accepted-social-contacts.jsonl", "jsonl", "append", "Accepted social relationship metadata."),
|
|
222
|
+
],
|
|
223
|
+
privacy: privacy(false, false, false),
|
|
224
|
+
enabled: true,
|
|
225
|
+
sourceFiles: ["src/social-discovery.ts"],
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
id: "persistent-event-log",
|
|
229
|
+
title: "Persistent event log",
|
|
230
|
+
source: "builtin",
|
|
231
|
+
owner: "event-bus",
|
|
232
|
+
trigger: {
|
|
233
|
+
event: "*",
|
|
234
|
+
description: "Appends emitted core/module/peripheral signals for recovery and later audit.",
|
|
235
|
+
},
|
|
236
|
+
destinations: [
|
|
237
|
+
destination("events", "{workdir}/.akemon/agents/{agent}/events/events.jsonl", "jsonl", "append", "Append-only event stream."),
|
|
238
|
+
],
|
|
239
|
+
privacy: privacy(true, true, false),
|
|
240
|
+
enabled: true,
|
|
241
|
+
sourceFiles: ["src/event-bus.ts", "src/server.ts"],
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: "relay-staged-artifact-imports",
|
|
245
|
+
title: "Relay-staged artifact imports",
|
|
246
|
+
source: "builtin",
|
|
247
|
+
owner: "relay",
|
|
248
|
+
trigger: {
|
|
249
|
+
event: "relay:pull",
|
|
250
|
+
description: "Stages relay-hosted games, notes, and pages as external import candidates.",
|
|
251
|
+
},
|
|
252
|
+
destinations: [
|
|
253
|
+
destination("inbox", "~/.akemon/agents/{agent}/inbox/relay-imports/games/{slug}.html", "html", "create", "Relay-hosted game import candidates."),
|
|
254
|
+
destination("inbox", "~/.akemon/agents/{agent}/inbox/relay-imports/notes/{slug}.md", "markdown", "create", "Relay-hosted note import candidates."),
|
|
255
|
+
destination("inbox", "~/.akemon/agents/{agent}/inbox/relay-imports/pages/{slug}.html", "html", "create", "Relay-hosted page import candidates."),
|
|
256
|
+
destination("inbox", "~/.akemon/agents/{agent}/inbox/relay-imports/{kind}/{slug}.{ext}.relay-import.json", "json", "create", "Sidecar source and authority metadata."),
|
|
257
|
+
],
|
|
258
|
+
privacy: privacy(false, false, true),
|
|
259
|
+
enabled: true,
|
|
260
|
+
sourceFiles: ["src/relay-peripheral.ts", "src/server.ts"],
|
|
261
|
+
notes: "Relay data is an external source. Staging does not make it canonical self memory; owner-approved import is required before writing self.",
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
id: "local-instance-registry",
|
|
265
|
+
title: "Local runtime instance registry",
|
|
266
|
+
source: "builtin",
|
|
267
|
+
owner: "local-registry",
|
|
268
|
+
trigger: {
|
|
269
|
+
event: "agent:start",
|
|
270
|
+
description: "Tracks running local Akemon instances so CLI commands can select by name.",
|
|
271
|
+
},
|
|
272
|
+
destinations: [
|
|
273
|
+
destination("runtime", "~/.akemon/runtime/instances.json", "json", "overwrite", "Running local instance registry."),
|
|
274
|
+
],
|
|
275
|
+
privacy: privacy(false, false, false),
|
|
276
|
+
enabled: true,
|
|
277
|
+
sourceFiles: ["src/local-registry.ts", "src/server.ts"],
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
id: "peripheral-registry",
|
|
281
|
+
title: "Peripheral configuration registry",
|
|
282
|
+
source: "builtin",
|
|
283
|
+
owner: "peripheral-registry",
|
|
284
|
+
trigger: {
|
|
285
|
+
event: "peripheral:registered",
|
|
286
|
+
description: "Records configured and runtime-discovered peripheral descriptors for routing and exploration.",
|
|
287
|
+
},
|
|
288
|
+
destinations: [
|
|
289
|
+
destination("config", "~/.akemon/agents/{agent}/peripherals/registry.json", "json", "overwrite", "Configured peripheral records with capabilities, risk, allowed actions, and explore behavior."),
|
|
290
|
+
],
|
|
291
|
+
privacy: privacy(true, false, false),
|
|
292
|
+
enabled: true,
|
|
293
|
+
sourceFiles: ["src/peripheral-registry.ts", "src/server.ts", "src/cli.ts"],
|
|
294
|
+
notes: "This registry stores peripheral descriptors and should not treat peripheral state or explore output as canonical self memory.",
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
id: "permission-audit-log",
|
|
298
|
+
title: "Permission and action audit log",
|
|
299
|
+
source: "builtin",
|
|
300
|
+
owner: "permission-audit",
|
|
301
|
+
trigger: {
|
|
302
|
+
event: "permission:audit",
|
|
303
|
+
description: "Appends inspectable records for risk-relevant actions and permission decisions.",
|
|
304
|
+
},
|
|
305
|
+
destinations: [
|
|
306
|
+
destination("audit", "~/.akemon/agents/{agent}/audit/actions.jsonl", "jsonl", "append", "Action audit records for software-agent tasks, inter-Akemon messages, relay publication, and work-memory writes."),
|
|
307
|
+
],
|
|
308
|
+
privacy: privacy(true, true, false),
|
|
309
|
+
enabled: true,
|
|
310
|
+
sourceFiles: [
|
|
311
|
+
"src/permission-audit.ts",
|
|
312
|
+
"src/software-agent-peripheral.ts",
|
|
313
|
+
"src/server.ts",
|
|
314
|
+
"src/relay-peripheral.ts",
|
|
315
|
+
"src/work-memory.ts",
|
|
316
|
+
],
|
|
317
|
+
notes: "This is an audit trail for later approval UI and policy work. It records decisions and boundaries, not a full RBAC system.",
|
|
318
|
+
},
|
|
319
|
+
];
|
|
320
|
+
export function listMemoryRecorders(options = {}) {
|
|
321
|
+
return BUILTIN_MEMORY_RECORDERS
|
|
322
|
+
.filter((recorder) => options.enabled === undefined || recorder.enabled === options.enabled)
|
|
323
|
+
.filter((recorder) => !options.source || recorder.source === options.source)
|
|
324
|
+
.filter((recorder) => !options.scope || recorder.destinations.some((dest) => dest.scope === options.scope))
|
|
325
|
+
.map(cloneRecorder);
|
|
326
|
+
}
|
|
327
|
+
export function getMemoryRecorder(id) {
|
|
328
|
+
const normalized = id.trim();
|
|
329
|
+
const recorder = BUILTIN_MEMORY_RECORDERS.find((item) => item.id === normalized);
|
|
330
|
+
return recorder ? cloneRecorder(recorder) : null;
|
|
331
|
+
}
|
|
332
|
+
export function createMemoryWriteProposal(input) {
|
|
333
|
+
const recorder = getMemoryRecorder(input.recorderId);
|
|
334
|
+
if (!recorder)
|
|
335
|
+
throw new Error(`Unknown memory recorder: ${input.recorderId}`);
|
|
336
|
+
const destination = input.destinationPath
|
|
337
|
+
? recorder.destinations.find((dest) => dest.path === input.destinationPath)
|
|
338
|
+
: recorder.destinations[0];
|
|
339
|
+
if (!destination)
|
|
340
|
+
throw new Error(`Unknown memory recorder destination: ${input.destinationPath}`);
|
|
341
|
+
const reason = input.reason.trim();
|
|
342
|
+
if (!reason)
|
|
343
|
+
throw new Error("Memory write proposal reason is required");
|
|
344
|
+
return {
|
|
345
|
+
recorderId: recorder.id,
|
|
346
|
+
...(input.eventId ? { eventId: input.eventId } : {}),
|
|
347
|
+
destination,
|
|
348
|
+
record: input.record,
|
|
349
|
+
reason,
|
|
350
|
+
risk: input.risk || "low",
|
|
351
|
+
createdAt: input.createdAt || new Date().toISOString(),
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
function destination(scope, path, format, writeMode, description) {
|
|
355
|
+
return { scope, path, format, writeMode, description };
|
|
356
|
+
}
|
|
357
|
+
function privacy(redactsSecrets, includesOwnerMemory, approvalRequired) {
|
|
358
|
+
return { redactsSecrets, includesOwnerMemory, approvalRequired };
|
|
359
|
+
}
|
|
360
|
+
function cloneRecorder(recorder) {
|
|
361
|
+
return {
|
|
362
|
+
...recorder,
|
|
363
|
+
trigger: { ...recorder.trigger },
|
|
364
|
+
destinations: recorder.destinations.map((dest) => ({ ...dest })),
|
|
365
|
+
privacy: { ...recorder.privacy },
|
|
366
|
+
sourceFiles: [...recorder.sourceFiles],
|
|
367
|
+
};
|
|
368
|
+
}
|
package/dist/orphan-scan.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* processes that happen to have a matching command name.
|
|
11
11
|
*/
|
|
12
12
|
import { execFile } from "child_process";
|
|
13
|
+
import { getRuntimePlatform } from "./runtime-platform.js";
|
|
13
14
|
// ---------------------------------------------------------------------------
|
|
14
15
|
// Patterns — agent-mode invocations only (not install/update/etc.)
|
|
15
16
|
// ---------------------------------------------------------------------------
|
|
@@ -48,32 +49,43 @@ export function parseProcessList(psOutput) {
|
|
|
48
49
|
// Runtime — scan ps output and kill matched orphans
|
|
49
50
|
// ---------------------------------------------------------------------------
|
|
50
51
|
export async function scanAndKillOrphans() {
|
|
52
|
+
const runtime = getRuntimePlatform();
|
|
53
|
+
if (!runtime.capabilities.canScanOrphanProcesses) {
|
|
54
|
+
console.log(`[orphan] scan unsupported on platform=${runtime.platform}`);
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
51
57
|
return new Promise((resolve) => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
let killed = 0;
|
|
65
|
-
for (const { pid, command } of orphans) {
|
|
66
|
-
console.log(`[orphan] killing pid=${pid} cmd="${command.slice(0, 80)}"`);
|
|
67
|
-
try {
|
|
68
|
-
process.kill(pid, "SIGKILL");
|
|
69
|
-
killed++;
|
|
58
|
+
try {
|
|
59
|
+
execFile("ps", ["-eo", "pid,ppid,command"], (err, stdout) => {
|
|
60
|
+
if (err) {
|
|
61
|
+
console.log(`[orphan] ps failed: ${err.message}`);
|
|
62
|
+
resolve(0);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const orphans = parseProcessList(stdout);
|
|
66
|
+
if (orphans.length === 0) {
|
|
67
|
+
console.log("[orphan] none found");
|
|
68
|
+
resolve(0);
|
|
69
|
+
return;
|
|
70
70
|
}
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
let killed = 0;
|
|
72
|
+
for (const { pid, command } of orphans) {
|
|
73
|
+
console.log(`[orphan] killing pid=${pid} cmd="${command.slice(0, 80)}"`);
|
|
74
|
+
try {
|
|
75
|
+
process.kill(pid, "SIGKILL");
|
|
76
|
+
killed++;
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
console.log(`[orphan] failed to kill pid=${pid}: ${e.message}`);
|
|
80
|
+
}
|
|
73
81
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
82
|
+
console.log(`[orphan] killed ${killed} process${killed !== 1 ? "es" : ""}`);
|
|
83
|
+
resolve(killed);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
console.log(`[orphan] ps failed: ${err.message || String(err)}`);
|
|
88
|
+
resolve(0);
|
|
89
|
+
}
|
|
78
90
|
});
|
|
79
91
|
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { appendCognitiveArtifact, } from "./cognitive-artifact-store.js";
|
|
2
|
+
import { readCognitiveEvents, } from "./cognitive-event-log.js";
|
|
3
|
+
const MIN_REFLECTION_VALUE_SCORE = 0.65;
|
|
4
|
+
const MAX_EVENT_TEXT_LENGTH = 900;
|
|
5
|
+
export function shouldRunPassiveReflection(input) {
|
|
6
|
+
if (!input.conversationId)
|
|
7
|
+
return false;
|
|
8
|
+
return (input.eventIds.peripheral?.length || 0) > 0
|
|
9
|
+
|| (input.eventIds.cm?.length || 0) > 0;
|
|
10
|
+
}
|
|
11
|
+
export async function runPassiveReflectionOnce(input) {
|
|
12
|
+
if (!shouldRunPassiveReflection(input))
|
|
13
|
+
return null;
|
|
14
|
+
const events = await collectRecentEvents({
|
|
15
|
+
workdir: input.workdir,
|
|
16
|
+
agentName: input.agentName,
|
|
17
|
+
conversationId: input.conversationId,
|
|
18
|
+
});
|
|
19
|
+
if (!events.length)
|
|
20
|
+
return null;
|
|
21
|
+
const result = await input.requestCompute({
|
|
22
|
+
taskId: `reflection:${input.conversationId || "unknown"}`,
|
|
23
|
+
taskKind: "reflection_passive",
|
|
24
|
+
purpose: "Reflection CM reviews recent chat, peripheral, and CM events for one high-value passive reflection.",
|
|
25
|
+
priority: "low",
|
|
26
|
+
origin: "reflection",
|
|
27
|
+
engineHints: {
|
|
28
|
+
requiredCapabilities: ["chat", "json", "reflection"],
|
|
29
|
+
maxCost: "medium",
|
|
30
|
+
maxLatency: "medium",
|
|
31
|
+
},
|
|
32
|
+
context: [
|
|
33
|
+
"[Akemon Reflection CM]",
|
|
34
|
+
`Agent: ${input.agentName}`,
|
|
35
|
+
"",
|
|
36
|
+
"You are a passive reflection sidecar for Akemon.",
|
|
37
|
+
"Review recent main chat, peripheral observations, and CM events.",
|
|
38
|
+
"Write one high-value reflection only when there is a non-obvious lesson, risk, recurring pattern, or useful next question.",
|
|
39
|
+
"Do not write memory. Do not ask the owner anything directly. Do not summarize routine actions.",
|
|
40
|
+
"",
|
|
41
|
+
"Return strict JSON only.",
|
|
42
|
+
"Use this schema:",
|
|
43
|
+
"{\"kind\":\"none\",\"reason\":\"...\"}",
|
|
44
|
+
"or",
|
|
45
|
+
"{\"kind\":\"reflection\",\"insight\":\"...\",\"reasoning\":\"...\",\"suggestedAction\":\"...\",\"valueScore\":0.0,\"confidence\":\"low|medium|high\",\"tags\":[\"...\"]}",
|
|
46
|
+
].join("\n"),
|
|
47
|
+
question: [
|
|
48
|
+
"Recent event buffer:",
|
|
49
|
+
formatEventsForReflection(events),
|
|
50
|
+
"",
|
|
51
|
+
"Decide whether there is one valuable passive reflection to store.",
|
|
52
|
+
].join("\n"),
|
|
53
|
+
});
|
|
54
|
+
if (!result.success || !result.response)
|
|
55
|
+
return null;
|
|
56
|
+
const decision = parseReflectionDecision(result.response);
|
|
57
|
+
if (!decision || decision.kind === "none")
|
|
58
|
+
return null;
|
|
59
|
+
const valueScore = clampScore(decision.valueScore);
|
|
60
|
+
if (valueScore < MIN_REFLECTION_VALUE_SCORE)
|
|
61
|
+
return null;
|
|
62
|
+
return appendCognitiveArtifact({
|
|
63
|
+
workdir: input.workdir,
|
|
64
|
+
agentName: input.agentName,
|
|
65
|
+
record: {
|
|
66
|
+
kind: "reflection",
|
|
67
|
+
refs: [createReflectionRef(input)],
|
|
68
|
+
tags: normalizeTags(["reflection", "passive", ...normalizeTags(decision.tags)]),
|
|
69
|
+
insight: decision.insight.trim(),
|
|
70
|
+
reasoning: decision.reasoning.trim(),
|
|
71
|
+
...(decision.suggestedAction?.trim() ? { suggestedAction: decision.suggestedAction.trim() } : {}),
|
|
72
|
+
valueScore,
|
|
73
|
+
confidence: normalizeConfidence(decision.confidence),
|
|
74
|
+
surfaced: false,
|
|
75
|
+
outcome: "unknown",
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async function collectRecentEvents(input) {
|
|
80
|
+
const [mainChat, peripheral, cm, task] = await Promise.all([
|
|
81
|
+
readCognitiveEvents({ workdir: input.workdir, agentName: input.agentName, stream: "main_chat", limit: 12 }),
|
|
82
|
+
readCognitiveEvents({ workdir: input.workdir, agentName: input.agentName, stream: "peripheral", limit: 8 }),
|
|
83
|
+
readCognitiveEvents({ workdir: input.workdir, agentName: input.agentName, stream: "cm", limit: 8 }),
|
|
84
|
+
readCognitiveEvents({ workdir: input.workdir, agentName: input.agentName, stream: "task", limit: 8 }),
|
|
85
|
+
]);
|
|
86
|
+
return [...mainChat, ...peripheral, ...cm, ...task]
|
|
87
|
+
.filter((event) => !input.conversationId || event.conversationId === input.conversationId)
|
|
88
|
+
.sort((a, b) => a.createdAt.localeCompare(b.createdAt))
|
|
89
|
+
.slice(-16);
|
|
90
|
+
}
|
|
91
|
+
function createReflectionRef(input) {
|
|
92
|
+
return {
|
|
93
|
+
conversationId: input.conversationId,
|
|
94
|
+
eventIds: [
|
|
95
|
+
...(input.eventIds.mainChat || []),
|
|
96
|
+
...(input.eventIds.peripheral || []),
|
|
97
|
+
...(input.eventIds.cm || []),
|
|
98
|
+
...(input.eventIds.task || []),
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function formatEventsForReflection(events) {
|
|
103
|
+
return events.map((event) => {
|
|
104
|
+
const prefix = `[${event.createdAt}] ${event.stream}:${event.id}`;
|
|
105
|
+
if (event.stream === "main_chat") {
|
|
106
|
+
return `${prefix} ${event.role}: ${truncate(event.text)}`;
|
|
107
|
+
}
|
|
108
|
+
if (event.stream === "peripheral") {
|
|
109
|
+
return `${prefix} ${event.peripheral}.${event.capability} ok=${event.ok}: ${truncate(event.summary)}`;
|
|
110
|
+
}
|
|
111
|
+
if (event.stream === "cm") {
|
|
112
|
+
return `${prefix} ${event.cm}.${event.itemType} status=${event.status || "info"}: ${truncate(event.summary)}`;
|
|
113
|
+
}
|
|
114
|
+
if (event.stream === "task") {
|
|
115
|
+
return `${prefix} task ${event.taskId} ${event.phase}/${event.status}: ${truncate(event.summary)}`;
|
|
116
|
+
}
|
|
117
|
+
return `${prefix} compute ${event.taskKind || "unknown"} success=${event.success}: ${event.inputChars} input chars`;
|
|
118
|
+
}).join("\n");
|
|
119
|
+
}
|
|
120
|
+
function parseReflectionDecision(raw) {
|
|
121
|
+
const json = extractJsonObject(raw.trim());
|
|
122
|
+
if (!json)
|
|
123
|
+
return null;
|
|
124
|
+
try {
|
|
125
|
+
const value = JSON.parse(json);
|
|
126
|
+
if (value.kind === "none")
|
|
127
|
+
return { kind: "none", reason: String(value.reason || "") };
|
|
128
|
+
if (value.kind !== "reflection")
|
|
129
|
+
return null;
|
|
130
|
+
const insight = typeof value.insight === "string" ? value.insight.trim() : "";
|
|
131
|
+
const reasoning = typeof value.reasoning === "string" ? value.reasoning.trim() : "";
|
|
132
|
+
if (!insight || !reasoning)
|
|
133
|
+
return null;
|
|
134
|
+
return {
|
|
135
|
+
kind: "reflection",
|
|
136
|
+
insight,
|
|
137
|
+
reasoning,
|
|
138
|
+
suggestedAction: typeof value.suggestedAction === "string" ? value.suggestedAction : undefined,
|
|
139
|
+
valueScore: typeof value.valueScore === "number" ? value.valueScore : undefined,
|
|
140
|
+
confidence: normalizeConfidence(value.confidence),
|
|
141
|
+
tags: normalizeTags(value.tags),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function extractJsonObject(raw) {
|
|
149
|
+
if (raw.startsWith("{") && raw.endsWith("}"))
|
|
150
|
+
return raw;
|
|
151
|
+
const start = raw.indexOf("{");
|
|
152
|
+
const end = raw.lastIndexOf("}");
|
|
153
|
+
if (start < 0 || end <= start)
|
|
154
|
+
return null;
|
|
155
|
+
return raw.slice(start, end + 1);
|
|
156
|
+
}
|
|
157
|
+
function normalizeConfidence(value) {
|
|
158
|
+
return value === "low" || value === "medium" || value === "high" ? value : "medium";
|
|
159
|
+
}
|
|
160
|
+
function normalizeTags(value) {
|
|
161
|
+
if (!Array.isArray(value))
|
|
162
|
+
return [];
|
|
163
|
+
return [...new Set(value.map((tag) => String(tag).trim()).filter(Boolean))];
|
|
164
|
+
}
|
|
165
|
+
function clampScore(value) {
|
|
166
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
167
|
+
return 0;
|
|
168
|
+
return Math.max(0, Math.min(1, value));
|
|
169
|
+
}
|
|
170
|
+
function truncate(text) {
|
|
171
|
+
return text.length <= MAX_EVENT_TEXT_LENGTH ? text : `${text.slice(0, MAX_EVENT_TEXT_LENGTH)}...`;
|
|
172
|
+
}
|