akemon 0.3.4 → 0.3.6
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 +120 -0
- package/README.md +43 -0
- package/TRADEMARK.md +74 -0
- package/dist/cli.js +311 -71
- package/dist/engine-peripheral.js +5 -4
- package/dist/engine-routing.js +99 -0
- package/dist/event-bus.js +63 -17
- package/dist/privacy-filter.js +269 -0
- package/dist/redaction.js +159 -0
- package/dist/relay-client.js +39 -2
- package/dist/server.js +181 -103
- package/dist/software-agent-memory.js +9 -11
- package/dist/software-agent-peripheral.js +453 -22
- package/dist/software-agent-result-cli.js +69 -0
- package/dist/software-agent-stream-cli.js +124 -0
- package/dist/work-memory.js +295 -0
- package/package.json +5 -3
package/dist/server.js
CHANGED
|
@@ -2,6 +2,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
2
2
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
3
3
|
import { exec } from "child_process";
|
|
4
4
|
import { scanAndKillOrphans } from "./orphan-scan.js";
|
|
5
|
+
import { timingSafeEqual } from "node:crypto";
|
|
5
6
|
import { createServer } from "http";
|
|
6
7
|
import { createInterface } from "readline";
|
|
7
8
|
import { mkdir } from "fs/promises";
|
|
@@ -86,8 +87,35 @@ function bearerToken(req) {
|
|
|
86
87
|
}
|
|
87
88
|
function isOwnerRequest(req, options) {
|
|
88
89
|
const token = bearerToken(req);
|
|
89
|
-
const validTokens = [options.secretKey, options.key]
|
|
90
|
-
|
|
90
|
+
const validTokens = [options.secretKey, options.key]
|
|
91
|
+
.filter((validToken) => typeof validToken === "string" && validToken.length > 0);
|
|
92
|
+
return !!token && validTokens.some((validToken) => constantTimeTokenEqual(token, validToken));
|
|
93
|
+
}
|
|
94
|
+
function constantTimeTokenEqual(left, right) {
|
|
95
|
+
const leftBuffer = Buffer.from(left);
|
|
96
|
+
const rightBuffer = Buffer.from(right);
|
|
97
|
+
const length = Math.max(leftBuffer.length, rightBuffer.length, 1);
|
|
98
|
+
const leftPadded = Buffer.alloc(length);
|
|
99
|
+
const rightPadded = Buffer.alloc(length);
|
|
100
|
+
leftBuffer.copy(leftPadded);
|
|
101
|
+
rightBuffer.copy(rightPadded);
|
|
102
|
+
return timingSafeEqual(leftPadded, rightPadded) && leftBuffer.length === rightBuffer.length;
|
|
103
|
+
}
|
|
104
|
+
function writeJsonResponse(res, statusCode, body, pretty = false) {
|
|
105
|
+
res.writeHead(statusCode, { "Content-Type": "application/json" })
|
|
106
|
+
.end(JSON.stringify(body, null, pretty ? 2 : 0));
|
|
107
|
+
}
|
|
108
|
+
function requireOwnerRequest(req, res, options) {
|
|
109
|
+
if (isOwnerRequest(req, options))
|
|
110
|
+
return true;
|
|
111
|
+
writeJsonResponse(res, 401, { error: "Owner token required" });
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
function requireSoftwareAgent(res, softwareAgent) {
|
|
115
|
+
if (softwareAgent)
|
|
116
|
+
return softwareAgent;
|
|
117
|
+
writeJsonResponse(res, 503, { error: "Software agent peripheral not ready" });
|
|
118
|
+
return null;
|
|
91
119
|
}
|
|
92
120
|
function readJsonBody(req, maxBytes = 256 * 1024) {
|
|
93
121
|
return new Promise((resolve, reject) => {
|
|
@@ -118,87 +146,67 @@ function readJsonBody(req, maxBytes = 256 * 1024) {
|
|
|
118
146
|
req.on("error", reject);
|
|
119
147
|
});
|
|
120
148
|
}
|
|
121
|
-
|
|
122
|
-
if (!isOwnerRequest(req, deps.options)) {
|
|
123
|
-
res.writeHead(401, { "Content-Type": "application/json" })
|
|
124
|
-
.end(JSON.stringify({ error: "Owner token required" }));
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
if (!deps.softwareAgent) {
|
|
128
|
-
res.writeHead(503, { "Content-Type": "application/json" })
|
|
129
|
-
.end(JSON.stringify({ error: "Software agent peripheral not ready" }));
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
149
|
+
async function readOwnerSoftwareAgentEnvelope(req, res, deps) {
|
|
132
150
|
let body;
|
|
133
151
|
try {
|
|
134
152
|
body = await readJsonBody(req);
|
|
135
153
|
}
|
|
136
154
|
catch (err) {
|
|
137
|
-
res
|
|
138
|
-
|
|
139
|
-
return;
|
|
155
|
+
writeJsonResponse(res, 400, { error: err.message || "Invalid request body" });
|
|
156
|
+
return null;
|
|
140
157
|
}
|
|
141
|
-
let envelope;
|
|
142
158
|
try {
|
|
143
|
-
envelope = createOwnerTaskEnvelope(body, deps.workdir);
|
|
159
|
+
const envelope = createOwnerTaskEnvelope(body, deps.workdir);
|
|
144
160
|
envelope.memorySummary = await buildSoftwareAgentMemorySummary({
|
|
145
161
|
workdir: deps.workdir,
|
|
146
162
|
agentName: deps.agentName,
|
|
147
163
|
envelope,
|
|
148
164
|
request: body,
|
|
149
165
|
});
|
|
166
|
+
if (readOptionalBooleanBody(body?.includeWorkMemoryContext, "includeWorkMemoryContext")) {
|
|
167
|
+
const workContext = await buildWorkMemoryContext({
|
|
168
|
+
workdir: deps.workdir,
|
|
169
|
+
agentName: deps.agentName,
|
|
170
|
+
purpose: `software-agent task: ${envelope.goal}`,
|
|
171
|
+
budget: readOptionalPositiveIntBody(body?.workMemoryContextBudget, "workMemoryContextBudget"),
|
|
172
|
+
});
|
|
173
|
+
envelope.workMemoryDir = workContext.workMemoryDir;
|
|
174
|
+
envelope.workMemoryContext = workContext.text;
|
|
175
|
+
}
|
|
176
|
+
return envelope;
|
|
150
177
|
}
|
|
151
178
|
catch (err) {
|
|
152
|
-
res
|
|
153
|
-
|
|
154
|
-
return;
|
|
179
|
+
writeJsonResponse(res, 400, { error: err.message || "Invalid software-agent envelope" });
|
|
180
|
+
return null;
|
|
155
181
|
}
|
|
182
|
+
}
|
|
183
|
+
export async function handleSoftwareAgentRunHttp(req, res, deps) {
|
|
184
|
+
if (!requireOwnerRequest(req, res, deps.options))
|
|
185
|
+
return;
|
|
186
|
+
const softwareAgent = requireSoftwareAgent(res, deps.softwareAgent);
|
|
187
|
+
if (!softwareAgent)
|
|
188
|
+
return;
|
|
189
|
+
const envelope = await readOwnerSoftwareAgentEnvelope(req, res, deps);
|
|
190
|
+
if (!envelope)
|
|
191
|
+
return;
|
|
156
192
|
try {
|
|
157
|
-
const result = await
|
|
158
|
-
res
|
|
159
|
-
.end(JSON.stringify(result, null, 2));
|
|
193
|
+
const result = await softwareAgent.sendTask(envelope);
|
|
194
|
+
writeJsonResponse(res, 200, redactSecrets(result), true);
|
|
160
195
|
}
|
|
161
196
|
catch (err) {
|
|
162
197
|
const busy = String(err.message || "").includes("busy");
|
|
163
|
-
res
|
|
164
|
-
.end(JSON.stringify({ error: err.message || String(err) }));
|
|
198
|
+
writeJsonResponse(res, busy ? 409 : 500, { error: err.message || String(err) });
|
|
165
199
|
}
|
|
166
200
|
}
|
|
167
201
|
export async function handleSoftwareAgentRunStreamHttp(req, res, deps) {
|
|
168
|
-
if (!
|
|
169
|
-
res.writeHead(401, { "Content-Type": "application/json" })
|
|
170
|
-
.end(JSON.stringify({ error: "Owner token required" }));
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
if (!deps.softwareAgent) {
|
|
174
|
-
res.writeHead(503, { "Content-Type": "application/json" })
|
|
175
|
-
.end(JSON.stringify({ error: "Software agent peripheral not ready" }));
|
|
202
|
+
if (!requireOwnerRequest(req, res, deps.options))
|
|
176
203
|
return;
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
try {
|
|
180
|
-
body = await readJsonBody(req);
|
|
181
|
-
}
|
|
182
|
-
catch (err) {
|
|
183
|
-
res.writeHead(400, { "Content-Type": "application/json" })
|
|
184
|
-
.end(JSON.stringify({ error: err.message || "Invalid request body" }));
|
|
204
|
+
const softwareAgent = requireSoftwareAgent(res, deps.softwareAgent);
|
|
205
|
+
if (!softwareAgent)
|
|
185
206
|
return;
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
try {
|
|
189
|
-
envelope = createOwnerTaskEnvelope(body, deps.workdir);
|
|
190
|
-
envelope.memorySummary = await buildSoftwareAgentMemorySummary({
|
|
191
|
-
workdir: deps.workdir,
|
|
192
|
-
agentName: deps.agentName,
|
|
193
|
-
envelope,
|
|
194
|
-
request: body,
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
catch (err) {
|
|
198
|
-
res.writeHead(400, { "Content-Type": "application/json" })
|
|
199
|
-
.end(JSON.stringify({ error: err.message || "Invalid software-agent envelope" }));
|
|
207
|
+
const envelope = await readOwnerSoftwareAgentEnvelope(req, res, deps);
|
|
208
|
+
if (!envelope)
|
|
200
209
|
return;
|
|
201
|
-
}
|
|
202
210
|
const abortController = new AbortController();
|
|
203
211
|
let responseFinished = false;
|
|
204
212
|
let streamStarted = false;
|
|
@@ -218,7 +226,7 @@ export async function handleSoftwareAgentRunStreamHttp(req, res, deps) {
|
|
|
218
226
|
res.flushHeaders?.();
|
|
219
227
|
};
|
|
220
228
|
try {
|
|
221
|
-
await
|
|
229
|
+
await softwareAgent.sendTask(envelope, {
|
|
222
230
|
signal: abortController.signal,
|
|
223
231
|
observer: {
|
|
224
232
|
onStart(event) {
|
|
@@ -227,6 +235,9 @@ export async function handleSoftwareAgentRunStreamHttp(req, res, deps) {
|
|
|
227
235
|
type: "start",
|
|
228
236
|
taskId: event.taskId,
|
|
229
237
|
commandLine: event.commandLine,
|
|
238
|
+
contextSessionId: event.contextSessionId,
|
|
239
|
+
contextPacketPath: event.contextPacketPath,
|
|
240
|
+
workMemoryDir: event.workMemoryDir,
|
|
230
241
|
});
|
|
231
242
|
},
|
|
232
243
|
onStream(event) {
|
|
@@ -242,7 +253,12 @@ export async function handleSoftwareAgentRunStreamHttp(req, res, deps) {
|
|
|
242
253
|
writeSoftwareAgentStreamEvent(res, {
|
|
243
254
|
type: "end",
|
|
244
255
|
taskId: event.taskId,
|
|
256
|
+
exitCode: event.exitCode,
|
|
257
|
+
durationMs: event.durationMs,
|
|
245
258
|
result: event.result,
|
|
259
|
+
contextSessionId: event.contextSessionId,
|
|
260
|
+
contextPacketPath: event.contextPacketPath,
|
|
261
|
+
workMemoryDir: event.workMemoryDir,
|
|
246
262
|
});
|
|
247
263
|
},
|
|
248
264
|
},
|
|
@@ -251,8 +267,7 @@ export async function handleSoftwareAgentRunStreamHttp(req, res, deps) {
|
|
|
251
267
|
catch (err) {
|
|
252
268
|
if (!streamStarted) {
|
|
253
269
|
const busy = String(err.message || "").includes("busy");
|
|
254
|
-
res
|
|
255
|
-
.end(JSON.stringify({ error: err.message || String(err) }));
|
|
270
|
+
writeJsonResponse(res, busy ? 409 : 500, { error: err.message || String(err) });
|
|
256
271
|
responseFinished = true;
|
|
257
272
|
return;
|
|
258
273
|
}
|
|
@@ -268,58 +283,95 @@ export async function handleSoftwareAgentRunStreamHttp(req, res, deps) {
|
|
|
268
283
|
}
|
|
269
284
|
}
|
|
270
285
|
export async function handleSoftwareAgentStatusHttp(req, res, deps) {
|
|
271
|
-
if (!
|
|
272
|
-
res.writeHead(401, { "Content-Type": "application/json" })
|
|
273
|
-
.end(JSON.stringify({ error: "Owner token required" }));
|
|
286
|
+
if (!requireOwnerRequest(req, res, deps.options))
|
|
274
287
|
return;
|
|
275
|
-
|
|
276
|
-
if (!
|
|
277
|
-
res.writeHead(503, { "Content-Type": "application/json" })
|
|
278
|
-
.end(JSON.stringify({ error: "Software agent peripheral not ready" }));
|
|
288
|
+
const softwareAgent = requireSoftwareAgent(res, deps.softwareAgent);
|
|
289
|
+
if (!softwareAgent)
|
|
279
290
|
return;
|
|
280
|
-
|
|
281
|
-
res.writeHead(200, { "Content-Type": "application/json" })
|
|
282
|
-
.end(JSON.stringify(deps.softwareAgent.getState(), null, 2));
|
|
291
|
+
writeJsonResponse(res, 200, softwareAgent.getState(), true);
|
|
283
292
|
}
|
|
284
293
|
export async function handleSoftwareAgentTasksHttp(req, res, deps) {
|
|
285
|
-
if (!
|
|
286
|
-
res.writeHead(401, { "Content-Type": "application/json" })
|
|
287
|
-
.end(JSON.stringify({ error: "Owner token required" }));
|
|
294
|
+
if (!requireOwnerRequest(req, res, deps.options))
|
|
288
295
|
return;
|
|
289
|
-
}
|
|
290
296
|
const url = new URL(req.url || "/", "http://127.0.0.1");
|
|
291
297
|
const basePath = "/self/software-agent/tasks";
|
|
292
298
|
const taskLedgerDir = softwareAgentTaskLedgerDir(deps.workdir, deps.agentName);
|
|
293
299
|
if (url.pathname === basePath) {
|
|
294
300
|
const limit = readPositiveIntQuery(url.searchParams.get("limit"), 20, 100);
|
|
295
|
-
const tasks = listSoftwareAgentTaskRecords(taskLedgerDir, limit
|
|
296
|
-
|
|
297
|
-
|
|
301
|
+
const tasks = listSoftwareAgentTaskRecords(taskLedgerDir, limit, {
|
|
302
|
+
contextSessionId: url.searchParams.get("session") || undefined,
|
|
303
|
+
});
|
|
304
|
+
writeJsonResponse(res, 200, { tasks }, true);
|
|
298
305
|
return;
|
|
299
306
|
}
|
|
300
307
|
if (url.pathname.startsWith(`${basePath}/`)) {
|
|
301
308
|
const taskId = decodeURIComponent(url.pathname.slice(basePath.length + 1));
|
|
302
309
|
if (!taskId || taskId.includes("/")) {
|
|
303
|
-
res
|
|
304
|
-
.end(JSON.stringify({ error: "Invalid software-agent task id" }));
|
|
310
|
+
writeJsonResponse(res, 400, { error: "Invalid software-agent task id" });
|
|
305
311
|
return;
|
|
306
312
|
}
|
|
307
313
|
const task = readSoftwareAgentTaskRecord(taskLedgerDir, taskId);
|
|
308
314
|
if (!task) {
|
|
309
|
-
res
|
|
310
|
-
|
|
315
|
+
writeJsonResponse(res, 404, { error: "Software-agent task not found" });
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
let contextSession;
|
|
319
|
+
if (readBooleanQuery(url.searchParams.get("includeContext")) && task.contextSession?.sessionId) {
|
|
320
|
+
try {
|
|
321
|
+
contextSession = readSoftwareAgentContextSession(softwareAgentContextSessionDir(deps.workdir, deps.agentName), task.contextSession.sessionId, { includeContextPacket: true });
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
contextSession = null;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
writeJsonResponse(res, 200, { task, ...(contextSession ? { contextSession } : {}) }, true);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
writeJsonResponse(res, 404, { error: "Software-agent task endpoint not found" });
|
|
331
|
+
}
|
|
332
|
+
export async function handleSoftwareAgentContextSessionsHttp(req, res, deps) {
|
|
333
|
+
if (!requireOwnerRequest(req, res, deps.options))
|
|
334
|
+
return;
|
|
335
|
+
const url = new URL(req.url || "/", "http://127.0.0.1");
|
|
336
|
+
const basePath = "/self/software-agent/sessions";
|
|
337
|
+
const contextSessionDir = softwareAgentContextSessionDir(deps.workdir, deps.agentName);
|
|
338
|
+
if (url.pathname === basePath) {
|
|
339
|
+
const limit = readPositiveIntQuery(url.searchParams.get("limit"), 20, 100);
|
|
340
|
+
const sessions = listSoftwareAgentContextSessions(contextSessionDir, limit);
|
|
341
|
+
writeJsonResponse(res, 200, { sessions }, true);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (url.pathname.startsWith(`${basePath}/`)) {
|
|
345
|
+
const sessionId = decodeURIComponent(url.pathname.slice(basePath.length + 1));
|
|
346
|
+
if (!sessionId || sessionId.includes("/")) {
|
|
347
|
+
writeJsonResponse(res, 400, { error: "Invalid software-agent context session id" });
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
let session;
|
|
351
|
+
try {
|
|
352
|
+
session = readSoftwareAgentContextSession(contextSessionDir, sessionId, {
|
|
353
|
+
includeContextPacket: readBooleanQuery(url.searchParams.get("includeContext")),
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
catch (err) {
|
|
357
|
+
writeJsonResponse(res, 400, { error: err.message || "Invalid software-agent context session id" });
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
if (!session) {
|
|
361
|
+
writeJsonResponse(res, 404, { error: "Software-agent context session not found" });
|
|
311
362
|
return;
|
|
312
363
|
}
|
|
313
|
-
res
|
|
314
|
-
.end(JSON.stringify({ task }, null, 2));
|
|
364
|
+
writeJsonResponse(res, 200, { session }, true);
|
|
315
365
|
return;
|
|
316
366
|
}
|
|
317
|
-
res
|
|
318
|
-
.end(JSON.stringify({ error: "Software-agent task endpoint not found" }));
|
|
367
|
+
writeJsonResponse(res, 404, { error: "Software-agent context session endpoint not found" });
|
|
319
368
|
}
|
|
320
369
|
function softwareAgentTaskLedgerDir(workdir, agentName) {
|
|
321
370
|
return join(workdir, ".akemon", "agents", agentName, "software-agent", "tasks");
|
|
322
371
|
}
|
|
372
|
+
function softwareAgentContextSessionDir(workdir, agentName) {
|
|
373
|
+
return join(workdir, ".akemon", "agents", agentName, "software-agent", "sessions");
|
|
374
|
+
}
|
|
323
375
|
function readPositiveIntQuery(value, fallback, max) {
|
|
324
376
|
if (!value)
|
|
325
377
|
return fallback;
|
|
@@ -328,30 +380,41 @@ function readPositiveIntQuery(value, fallback, max) {
|
|
|
328
380
|
return fallback;
|
|
329
381
|
return Math.min(parsed, max);
|
|
330
382
|
}
|
|
383
|
+
function readBooleanQuery(value) {
|
|
384
|
+
return value === "1" || value === "true" || value === "yes";
|
|
385
|
+
}
|
|
386
|
+
function readOptionalBooleanBody(value, field) {
|
|
387
|
+
if (value === undefined || value === null)
|
|
388
|
+
return false;
|
|
389
|
+
if (typeof value !== "boolean")
|
|
390
|
+
throw new Error(`Invalid ${field}: expected boolean`);
|
|
391
|
+
return value;
|
|
392
|
+
}
|
|
393
|
+
function readOptionalPositiveIntBody(value, field) {
|
|
394
|
+
if (value === undefined || value === null)
|
|
395
|
+
return undefined;
|
|
396
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
397
|
+
throw new Error(`Invalid ${field}: expected positive integer`);
|
|
398
|
+
}
|
|
399
|
+
return value;
|
|
400
|
+
}
|
|
331
401
|
function writeSoftwareAgentStreamEvent(res, event) {
|
|
332
402
|
if (res.destroyed)
|
|
333
403
|
return;
|
|
334
|
-
res.write(`${JSON.stringify(event)}\n`);
|
|
404
|
+
res.write(`${JSON.stringify(redactSecrets(event))}\n`);
|
|
335
405
|
}
|
|
336
406
|
export async function handleSoftwareAgentResetHttp(req, res, deps) {
|
|
337
|
-
if (!
|
|
338
|
-
res.writeHead(401, { "Content-Type": "application/json" })
|
|
339
|
-
.end(JSON.stringify({ error: "Owner token required" }));
|
|
407
|
+
if (!requireOwnerRequest(req, res, deps.options))
|
|
340
408
|
return;
|
|
341
|
-
|
|
342
|
-
if (!
|
|
343
|
-
res.writeHead(503, { "Content-Type": "application/json" })
|
|
344
|
-
.end(JSON.stringify({ error: "Software agent peripheral not ready" }));
|
|
409
|
+
const softwareAgent = requireSoftwareAgent(res, deps.softwareAgent);
|
|
410
|
+
if (!softwareAgent)
|
|
345
411
|
return;
|
|
346
|
-
}
|
|
347
412
|
try {
|
|
348
|
-
await
|
|
349
|
-
res
|
|
350
|
-
.end(JSON.stringify({ ok: true, state: deps.softwareAgent.getState() }, null, 2));
|
|
413
|
+
await softwareAgent.resetSession();
|
|
414
|
+
writeJsonResponse(res, 200, { ok: true, state: softwareAgent.getState() }, true);
|
|
351
415
|
}
|
|
352
416
|
catch (err) {
|
|
353
|
-
res
|
|
354
|
-
.end(JSON.stringify({ error: err.message || String(err) }));
|
|
417
|
+
writeJsonResponse(res, 500, { error: err.message || String(err) });
|
|
355
418
|
}
|
|
356
419
|
}
|
|
357
420
|
import { RelayPeripheral } from "./relay-peripheral.js";
|
|
@@ -366,10 +429,12 @@ import { LongTermModule } from "./longterm-module.js";
|
|
|
366
429
|
import { ReflectionModule } from "./reflection-module.js";
|
|
367
430
|
import { ScriptModule } from "./script-module.js";
|
|
368
431
|
import { FileEventLog, PersistentEventBus } from "./event-bus.js";
|
|
369
|
-
import { CodexSoftwareAgentPeripheral, createOwnerTaskEnvelope, listSoftwareAgentTaskRecords, readSoftwareAgentTaskRecord, } from "./software-agent-peripheral.js";
|
|
432
|
+
import { CodexSoftwareAgentPeripheral, createOwnerTaskEnvelope, listSoftwareAgentContextSessions, listSoftwareAgentTaskRecords, readSoftwareAgentContextSession, readSoftwareAgentTaskRecord, } from "./software-agent-peripheral.js";
|
|
370
433
|
import { buildSoftwareAgentMemorySummary } from "./software-agent-memory.js";
|
|
434
|
+
import { buildWorkMemoryContext, workMemoryDir } from "./work-memory.js";
|
|
371
435
|
import { SIG, sig } from "./types.js";
|
|
372
436
|
import { loadConversation, listConversations, buildLLMContext } from "./context.js";
|
|
437
|
+
import { redactSecrets } from "./redaction.js";
|
|
373
438
|
import { createMcpServer, initMcpProxy, createMcpProxyServer } from "./mcp-server.js";
|
|
374
439
|
import { autoRoute, runCollaborativeQuery } from "./agent-utils.js";
|
|
375
440
|
// createMcpServer, initMcpProxy, createMcpProxyServer → see mcp-server.ts
|
|
@@ -378,11 +443,11 @@ const LLM_ENGINES = LLM_ENGINES_SET;
|
|
|
378
443
|
// Engine execution — delegates to EnginePeripheral (V2 Step 3)
|
|
379
444
|
// ---------------------------------------------------------------------------
|
|
380
445
|
/** Unified engine runner — delegates to EnginePeripheral */
|
|
381
|
-
function runEngine(engine, model, allowAll, task, workdir, extraAllowedTools, relay, signal, origin, routing, taskId) {
|
|
446
|
+
function runEngine(engine, model, allowAll, task, workdir, extraAllowedTools, relay, signal, origin, routing, taskId, routeRequest) {
|
|
382
447
|
if (!_engineP) {
|
|
383
448
|
throw new Error("Engine peripheral not initialized");
|
|
384
449
|
}
|
|
385
|
-
const result = _engineP.runEngine(task, allowAll, extraAllowedTools, signal, origin, routing, taskId);
|
|
450
|
+
const result = _engineP.runEngine(task, allowAll, extraAllowedTools, signal, origin, routing, taskId, routeRequest);
|
|
386
451
|
// Sync trace back to module-level for reporting
|
|
387
452
|
result.then(() => { lastEngineTrace = _engineP.lastTrace; }).catch(() => { lastEngineTrace = _engineP.lastTrace; });
|
|
388
453
|
return result;
|
|
@@ -476,6 +541,15 @@ export async function serve(options) {
|
|
|
476
541
|
return;
|
|
477
542
|
}
|
|
478
543
|
const requestPath = req.url?.split("?")[0] || "";
|
|
544
|
+
if (req.method === "GET"
|
|
545
|
+
&& (requestPath === "/self/software-agent/sessions" || requestPath.startsWith("/self/software-agent/sessions/"))) {
|
|
546
|
+
await handleSoftwareAgentContextSessionsHttp(req, res, {
|
|
547
|
+
options,
|
|
548
|
+
workdir,
|
|
549
|
+
agentName: options.agentName,
|
|
550
|
+
});
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
479
553
|
if (req.method === "GET"
|
|
480
554
|
&& (requestPath === "/self/software-agent/tasks" || requestPath.startsWith("/self/software-agent/tasks/"))) {
|
|
481
555
|
await handleSoftwareAgentTasksHttp(req, res, {
|
|
@@ -681,6 +755,10 @@ export async function serve(options) {
|
|
|
681
755
|
model: process.env.AKEMON_CODEX_MODEL,
|
|
682
756
|
sandbox: "workspace-write",
|
|
683
757
|
taskLedgerDir: softwareAgentTaskLedgerDir(workdir, options.agentName),
|
|
758
|
+
contextSessionDir: softwareAgentContextSessionDir(workdir, options.agentName),
|
|
759
|
+
workMemoryDir: workMemoryDir(workdir, options.agentName),
|
|
760
|
+
envPolicy: options.softwareAgentEnvPolicy,
|
|
761
|
+
envAllowlist: options.softwareAgentEnvAllowlist,
|
|
684
762
|
});
|
|
685
763
|
// Peripheral registry — Core routes by capability
|
|
686
764
|
const peripherals = [relay, engineP, codexSoftwareAgent];
|
|
@@ -718,7 +796,7 @@ export async function serve(options) {
|
|
|
718
796
|
const abortController = new AbortController();
|
|
719
797
|
const timer = setTimeout(() => abortController.abort(), ENGINE_EXEC_TIMEOUT_MS);
|
|
720
798
|
try {
|
|
721
|
-
const response = await runEngine(options.engine || "claude", options.model, options.allowAll, prompt, workdir, req.tools, req.relay, abortController.signal, req.origin, routing, req.taskId);
|
|
799
|
+
const response = await runEngine(options.engine || "claude", options.model, options.allowAll, prompt, workdir, req.tools, req.relay, abortController.signal, req.origin, routing, req.taskId, req.engineHints);
|
|
722
800
|
emitTokenUsage(prompt.length, response.length);
|
|
723
801
|
return { success: true, response };
|
|
724
802
|
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { buildLLMContext, loadConversation } from "./context.js";
|
|
2
2
|
import { buildRoleContext, loadRoles, resolveRoles } from "./role-module.js";
|
|
3
3
|
const DEFAULT_CONTEXT_BUDGET = 6000;
|
|
4
|
+
const OWNER_MEMORY_EXCLUDE_TERMS = [
|
|
5
|
+
"owner",
|
|
6
|
+
"private",
|
|
7
|
+
"personal",
|
|
8
|
+
"note",
|
|
9
|
+
"diary",
|
|
10
|
+
"bio",
|
|
11
|
+
];
|
|
4
12
|
export async function buildSoftwareAgentMemorySummary(opts) {
|
|
5
13
|
const budget = opts.contextBudget ?? DEFAULT_CONTEXT_BUDGET;
|
|
6
14
|
const parts = [
|
|
@@ -103,17 +111,7 @@ async function resolveRoleMemoryPolicy(workdir, agentName, roleTrigger) {
|
|
|
103
111
|
function roleExcludesOwnerMemory(policy) {
|
|
104
112
|
return policy.exclude.some((item) => {
|
|
105
113
|
const normalized = item.toLowerCase();
|
|
106
|
-
return normalized.includes(
|
|
107
|
-
|| normalized.includes("private")
|
|
108
|
-
|| normalized.includes("personal")
|
|
109
|
-
|| normalized.includes("note")
|
|
110
|
-
|| normalized.includes("diary")
|
|
111
|
-
|| normalized.includes("bio")
|
|
112
|
-
|| normalized.includes("全部记忆")
|
|
113
|
-
|| normalized.includes("个人")
|
|
114
|
-
|| normalized.includes("笔记")
|
|
115
|
-
|| normalized.includes("日记")
|
|
116
|
-
|| normalized.includes("状态");
|
|
114
|
+
return OWNER_MEMORY_EXCLUDE_TERMS.some((term) => normalized.includes(term));
|
|
117
115
|
});
|
|
118
116
|
}
|
|
119
117
|
function normalizeRequest(value) {
|