evolcore 0.0.27 → 0.0.29-test.0
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/CHANGELOG.md +38 -15
- package/bin/ec-safe-output.js +270 -54
- package/dist/agents/baseagent-availability.js +37 -1
- package/dist/agents/baseagent.js +29 -14
- package/dist/agents/claude-runner.js +171 -13
- package/dist/agents/codex/app-server-client.js +13 -2
- package/dist/agents/codex/catalog.js +7 -1
- package/dist/agents/codex/diagnostics.js +4 -3
- package/dist/agents/codex-runner.js +444 -106
- package/dist/agents/gemini-runner.js +35 -17
- package/dist/aun/group/history.js +130 -90
- package/dist/aun/group/operations.js +1 -3
- package/dist/aun/menu/client.js +1 -0
- package/dist/aun/menu/transport.js +5 -3
- package/dist/aun/msg/managed-operation.js +70 -0
- package/dist/aun/msg/p2p.js +1 -3
- package/dist/aun/msg/upload.js +2 -2
- package/dist/aun/outbox.js +1 -37
- package/dist/channels/aun.js +262 -86
- package/dist/channels/daemon.js +18 -1
- package/dist/channels/feishu.js +1 -2
- package/dist/cli/agent-command.js +23 -3
- package/dist/cli/agent-create.js +68 -2
- package/dist/cli/agent.js +12 -2
- package/dist/cli/aun-commands.js +87 -13
- package/dist/cli/cli-argv.js +26 -0
- package/dist/cli/daemon-commands.js +116 -149
- package/dist/cli/data-command.js +4 -4
- package/dist/cli/diag.js +1 -1
- package/dist/cli/handoff-command.js +2 -0
- package/dist/cli/index.js +18 -1
- package/dist/cli/managed-command-guard.js +10 -0
- package/dist/cli/memory-command.js +441 -0
- package/dist/cli/menu-client.js +4 -0
- package/dist/cli/restart-monitor.js +127 -23
- package/dist/cli/skill-command.js +41 -0
- package/dist/cli/task-context.js +2 -23
- package/dist/cli/trigger-command.js +9 -1
- package/dist/cli/watch-msg-diag.js +209 -0
- package/dist/config/config-field-policy.js +52 -3
- package/dist/config/config-manager.js +17 -4
- package/dist/config/contact-book-store.js +2 -2
- package/dist/config/mention-mode.js +7 -2
- package/dist/config/merge.js +28 -9
- package/dist/config/resolved-config-op.js +1 -1
- package/dist/config/runtime-env.js +137 -0
- package/dist/config/schema-registry.js +11 -1
- package/dist/config-store.js +10 -10
- package/dist/core/audit/event-key.js +3 -1
- package/dist/core/audit/log-integrity.js +4 -0
- package/dist/core/auth/agent-delegation.js +2 -1
- package/dist/core/auth/auth-gateway.js +13 -6
- package/dist/core/auth/authorization-audit.js +54 -19
- package/dist/core/auth/operation-authorizer.js +17 -0
- package/dist/core/auth/operation-catalog.js +9 -0
- package/dist/core/causation/context.js +5 -1
- package/dist/core/command/agent-control.js +1 -2
- package/dist/core/command/command-handler.js +80 -24
- package/dist/core/command/diag-service.js +292 -27
- package/dist/core/command/memory-slash.js +270 -0
- package/dist/core/command/menu-catalog.js +1 -0
- package/dist/core/command/menu-handler.js +331 -79
- package/dist/core/command/menu-protocol.js +45 -4
- package/dist/core/command/slash-gate.js +10 -10
- package/dist/core/command/slash-handler.js +230 -79
- package/dist/core/data-migration.js +282 -505
- package/dist/core/event-catalog.js +26 -0
- package/dist/core/evolagent-registry.js +6 -0
- package/dist/core/evolagent.js +0 -10
- package/dist/core/handoff/store.js +1 -20
- package/dist/core/inference/text-inference.js +57 -1
- package/dist/core/memory/consolidation-context.js +505 -0
- package/dist/core/memory/consolidation-ops-records.js +124 -0
- package/dist/core/memory/consolidation-trigger.js +394 -0
- package/dist/core/memory/index-manager.js +308 -0
- package/dist/core/memory/launch-consolidation.js +395 -0
- package/dist/core/memory/memory-admin.js +234 -0
- package/dist/core/memory/memory-document.js +100 -0
- package/dist/core/memory/memory-session-policy.js +41 -0
- package/dist/core/memory/memory-signature.js +257 -0
- package/dist/core/memory/memory-writer.js +432 -0
- package/dist/core/memory/staleness.js +117 -0
- package/dist/core/message/auto-mention-gate.js +454 -0
- package/dist/core/message/im-renderer.js +90 -20
- package/dist/core/message/message-bridge.js +333 -23
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-queue.js +114 -27
- package/dist/core/message/pending-hints.js +329 -161
- package/dist/core/message/response-engine.js +596 -90
- package/dist/core/permission/ec-command-parser.js +1044 -87
- package/dist/core/permission/protected-paths.js +376 -126
- package/dist/core/permission/sandbox-runtime.js +40 -12
- package/dist/core/permission/tool-error-code.js +96 -13
- package/dist/core/permission/tool-policy.js +277 -24
- package/dist/core/role/runtime-policy.js +3 -7
- package/dist/core/session/{runner-task-history.js → runner-event-summary.js} +1 -1
- package/dist/core/session/session-fs-store.js +0 -76
- package/dist/core/session/session-idle-monitor.js +355 -0
- package/dist/core/session/session-manager.js +482 -17
- package/dist/core/session/session-mapper.js +33 -16
- package/dist/core/session/session-renew.js +217 -155
- package/dist/core/session/{session-turns.js → session-transcript.js} +35 -6
- package/dist/core/skill/global-watcher.js +282 -0
- package/dist/core/skill/index-generator.js +84 -0
- package/dist/core/skill/startup.js +73 -0
- package/dist/core/skill/switch-resolver.js +115 -0
- package/dist/core/task/task-activity-store.js +219 -0
- package/dist/eck/kit-renderer.js +30 -3
- package/dist/eck/manifest-engine.js +26 -4
- package/dist/index.js +722 -171
- package/dist/ipc.js +564 -2
- package/dist/paths.js +30 -9
- package/dist/product.js +1 -0
- package/dist/response-system/engines/v1/proactive-flow.js +116 -15
- package/dist/response-system/modes/single-session/index.js +3 -0
- package/dist/trigger/feedback.js +1 -0
- package/dist/trigger/manager.js +0 -10
- package/dist/trigger/scheduler.js +11 -0
- package/dist/trigger/validation.js +22 -0
- package/dist/utils/atomic-write.js +98 -0
- package/dist/utils/avatar-upload.js +59 -18
- package/dist/utils/cross-platform.js +87 -16
- package/dist/utils/error-dict.json +6 -3
- package/dist/utils/error-utils.js +27 -0
- package/dist/utils/logger.js +32 -10
- package/dist/utils/media-cache.js +84 -0
- package/dist/utils/msg-diag.js +97 -0
- package/dist/utils/npm-ops.js +119 -4
- package/dist/utils/package-version-info.js +244 -0
- package/dist/utils/welcome.js +37 -8
- package/dist/utils/windows-shell-trust.js +37 -0
- package/kits/docs/AUTHORING.md +314 -0
- package/kits/docs/GUIDE.md +2 -0
- package/kits/docs/INDEX.md +2 -0
- package/kits/docs/aun/CHEATSHEET.md +4 -0
- package/kits/docs/aun/SDK.md +60 -0
- package/kits/docs/channels/aun.md +8 -0
- package/kits/docs/context-assembly.md +10 -6
- package/kits/docs/evolcore/INDEX.md +17 -3
- package/kits/docs/evolcore/agent-create.md +24 -0
- package/kits/docs/evolcore/agent.md +5 -2
- package/kits/docs/evolcore/config.md +1 -1
- package/kits/docs/evolcore/ec-capabilities.md +364 -0
- package/kits/docs/evolcore/group.md +34 -18
- package/kits/docs/evolcore/memory-architecture.md +78 -0
- package/kits/docs/evolcore/memory-consolidation-batches.md +133 -0
- package/kits/docs/evolcore/memory-consolidation.md +263 -0
- package/kits/docs/evolcore/memory-tags.md +63 -0
- package/kits/docs/evolcore/memory.md +110 -0
- package/kits/docs/evolcore/menu-client.md +27 -11
- package/kits/{schemas → docs/evolcore}/menu-exec-schema-commands.md +12 -6
- package/kits/docs/evolcore/menu-protocol.md +213 -0
- package/kits/docs/evolcore/msg.md +2 -0
- package/kits/docs/evolcore/trigger.md +7 -5
- package/kits/docs/path-registry.md +6 -8
- package/kits/docs/prompt-loading-architecture.md +5 -3
- package/kits/docs/venues/group.md +5 -4
- package/kits/eck_manifest.json +294 -88
- package/kits/eck_manifest.memory.json +257 -0
- package/kits/rules/03-identity.md +8 -8
- package/kits/rules/05-venue.md +4 -2
- package/kits/rules/06-channel.md +1 -1
- package/kits/schemas/_meta.json +276 -47
- package/kits/schemas/agent-config.schema.12.json +38 -2
- package/kits/schemas/agent-config.schema.13.json +591 -0
- package/kits/schemas/daemon.schema.6.json +9 -9
- package/kits/schemas/defaults.schema.5.json +29 -0
- package/kits/schemas/relation-config.schema.8.json +14 -1
- package/kits/schemas/relation-config.schema.9.json +129 -0
- package/kits/schemas/role-config.schema.1.json +3 -3
- package/kits/skills/.switches.json +3 -0
- package/kits/skills/ec-skill/SKILL.md +217 -0
- package/kits/skills/ec-skill/scripts/cli.mjs +128 -0
- package/kits/skills/ec-skill/scripts/deps.mjs +107 -0
- package/kits/skills/ec-skill/scripts/frontmatter.mjs +104 -0
- package/kits/skills/ec-skill/scripts/skill.mjs +629 -0
- package/kits/skills/ec-skill/scripts/template/SKILL.md.tmpl +30 -0
- package/kits/templates/decision/auto-mention.md +25 -0
- package/kits/templates/decision/session-renew.md +22 -0
- package/kits/templates/memory-consolidation/forget.md +104 -0
- package/kits/templates/memory-consolidation/generalize.md +76 -0
- package/kits/templates/memory-consolidation/notes.md +133 -0
- package/kits/templates/memory-consolidation/profile.md +58 -0
- package/kits/templates/memory-consolidation/promote.md +72 -0
- package/kits/templates/memory-consolidation/workflow.md +75 -0
- package/kits/templates/system-fragments/bootstrap.md +14 -5
- package/kits/templates/system-fragments/commands.md +1 -0
- package/kits/templates/system-fragments/group-history.md +6 -0
- package/kits/templates/system-fragments/identity.md +0 -3
- package/kits/templates/system-fragments/memory.md +79 -0
- package/kits/templates/system-fragments/reply.md +1 -0
- package/kits/templates/system-fragments/venue.md +1 -1
- package/package.json +4 -6
- package/dist/trigger/legacy-session-history.js +0 -19
- package/kits/templates/system-fragments/group-unread-history.md +0 -7
package/dist/ipc.js
CHANGED
|
@@ -16,10 +16,11 @@ import { getPackageRoot, getWindowsInstanceSocketPathCandidates, normalizeIpcEnd
|
|
|
16
16
|
import { getProcessStartTime, isSameOrOlderProcess } from './utils/process-introspect.js';
|
|
17
17
|
import { classifyProcessTree, ProcessTreeSampler, readProcessMetrics } from './utils/process-tree-stats.js';
|
|
18
18
|
import { readSystemMemoryUsage } from './utils/system-memory.js';
|
|
19
|
-
import { hashCurrentDelegatedCommand } from './core/auth/agent-delegation.js';
|
|
19
|
+
import { hashCurrentDelegatedCommand, hashDelegatedCommandArgv } from './core/auth/agent-delegation.js';
|
|
20
20
|
import { normalizeAunMentionEntries } from './aun/msg/mention-schema.js';
|
|
21
21
|
import { remoteAccessService } from './core/auth/remote-access-store.js';
|
|
22
22
|
import { setModelCatalogDaemonOwner } from './core/model/model-catalog.js';
|
|
23
|
+
import { RUNTIME_ENVIRONMENT_NAMES, setRuntimeEnvironmentOverride } from './config/runtime-env.js';
|
|
23
24
|
const isWindows = process.platform === 'win32';
|
|
24
25
|
const isNamedPipe = (p) => isWindows && p.toLowerCase().startsWith('\\\\.\\pipe\\');
|
|
25
26
|
const CPU_SAMPLE_INTERVAL_MS = 1000;
|
|
@@ -30,6 +31,22 @@ const EVENT_LOOP_LAG_WARN_MS = 100;
|
|
|
30
31
|
const SAMPLE_WARN_LOG_INTERVAL_MS = 60_000;
|
|
31
32
|
const PROCESS_TREE_WORKER_REQUEST_TIMEOUT_MS = 15_000;
|
|
32
33
|
const finiteTimestamp = (value) => (typeof value === 'number' && Number.isFinite(value) ? value : undefined);
|
|
34
|
+
function parseRuntimeEnvironmentInput(value) {
|
|
35
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
36
|
+
return { ok: false, error: 'runtimeEnv must be an object' };
|
|
37
|
+
}
|
|
38
|
+
const values = {};
|
|
39
|
+
for (const name of RUNTIME_ENVIRONMENT_NAMES) {
|
|
40
|
+
if (!Object.prototype.hasOwnProperty.call(value, name))
|
|
41
|
+
continue;
|
|
42
|
+
const item = value[name];
|
|
43
|
+
if (item !== null && item !== undefined && typeof item !== 'string') {
|
|
44
|
+
return { ok: false, error: `${name} must be a string or null` };
|
|
45
|
+
}
|
|
46
|
+
values[name] = item;
|
|
47
|
+
}
|
|
48
|
+
return { ok: true, values };
|
|
49
|
+
}
|
|
33
50
|
const LOCAL_CONTROL_COMMANDS = new Set([
|
|
34
51
|
'bind.begin',
|
|
35
52
|
'bind.status',
|
|
@@ -40,6 +57,7 @@ const LOCAL_CONTROL_COMMANDS = new Set([
|
|
|
40
57
|
'wecom.contact-bind.register',
|
|
41
58
|
'wechat.contact-bind.register',
|
|
42
59
|
'queue-snapshot',
|
|
60
|
+
'memory.check-consolidation',
|
|
43
61
|
'aun-aid-stats-record-outbound',
|
|
44
62
|
'evolagent.list',
|
|
45
63
|
'evolagent.show',
|
|
@@ -146,10 +164,13 @@ export class IpcServer {
|
|
|
146
164
|
storageAuthorizationExecutor;
|
|
147
165
|
storageUploadExecutor;
|
|
148
166
|
triggerExecutor;
|
|
167
|
+
consolidationLaunchExecutor;
|
|
168
|
+
consolidationCheckExecutor;
|
|
149
169
|
bootstrapCompleteExecutor;
|
|
150
170
|
agentReloadExecutor;
|
|
151
171
|
shutdownExecutor;
|
|
152
172
|
taskRuntimeContextProvider;
|
|
173
|
+
debugTaskRuntimeContextProvider;
|
|
153
174
|
taskRuntimeContextAuthorizer;
|
|
154
175
|
codexPreToolUseExecutor;
|
|
155
176
|
aunMsgSender;
|
|
@@ -407,6 +428,14 @@ export class IpcServer {
|
|
|
407
428
|
setTriggerExecutor(executor) {
|
|
408
429
|
this.triggerExecutor = executor;
|
|
409
430
|
}
|
|
431
|
+
/** Inject daemon-level consolidation launcher that uses the real trigger scheduler. */
|
|
432
|
+
setConsolidationLaunchExecutor(executor) {
|
|
433
|
+
this.consolidationLaunchExecutor = executor;
|
|
434
|
+
}
|
|
435
|
+
/** 注入定时检查 executor:跑候选检查并入队(整理队列在 index.ts)。 */
|
|
436
|
+
setConsolidationCheckExecutor(executor) {
|
|
437
|
+
this.consolidationCheckExecutor = executor;
|
|
438
|
+
}
|
|
410
439
|
/** Complete an agent bootstrap in the daemon so disk and runtime state change together. */
|
|
411
440
|
setBootstrapCompleteExecutor(executor) {
|
|
412
441
|
this.bootstrapCompleteExecutor = executor;
|
|
@@ -415,6 +444,20 @@ export class IpcServer {
|
|
|
415
444
|
setTaskRuntimeContextProvider(provider) {
|
|
416
445
|
this.taskRuntimeContextProvider = provider;
|
|
417
446
|
}
|
|
447
|
+
/** 仅开发仓(npm link)安装注册;正式安装不调用,debug 请求一律走正常路径。 */
|
|
448
|
+
setDebugTaskRuntimeContextProvider(provider) {
|
|
449
|
+
this.debugTaskRuntimeContextProvider = provider;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* memory 命令取运行时上下文:先查正在运行的任务;没有且请求带 debug 时,
|
|
453
|
+
* 再由开发仓专用的 provider 从会话文件重建。
|
|
454
|
+
*/
|
|
455
|
+
async resolveMemoryTaskCtx(sessionId, debug) {
|
|
456
|
+
const active = this.taskRuntimeContextProvider?.({ sessionId });
|
|
457
|
+
if (active || !debug || !this.debugTaskRuntimeContextProvider)
|
|
458
|
+
return active;
|
|
459
|
+
return this.debugTaskRuntimeContextProvider({ sessionId });
|
|
460
|
+
}
|
|
418
461
|
setTaskRuntimeContextAuthorizer(authorizer) {
|
|
419
462
|
this.taskRuntimeContextAuthorizer = authorizer;
|
|
420
463
|
}
|
|
@@ -1406,6 +1449,330 @@ export class IpcServer {
|
|
|
1406
1449
|
return { ok: false, error: 'missing cmd or sessionId' };
|
|
1407
1450
|
return await this.commandExecutor(slashCmd, sessionId, typeof cmd.delegationToken === 'string' ? cmd.delegationToken : undefined, typeof cmd.delegationCommandHash === 'string' ? cmd.delegationCommandHash : undefined);
|
|
1408
1451
|
}
|
|
1452
|
+
case 'memory.note': {
|
|
1453
|
+
const { sessionId, slug, content, tags, speakers } = cmd;
|
|
1454
|
+
if (!sessionId)
|
|
1455
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing sessionId' };
|
|
1456
|
+
if (typeof slug !== 'string' || !slug)
|
|
1457
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing slug' };
|
|
1458
|
+
if (typeof content !== 'string' || !content)
|
|
1459
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing content' };
|
|
1460
|
+
try {
|
|
1461
|
+
const taskCtx = await this.resolveMemoryTaskCtx(sessionId, cmd.debug === true);
|
|
1462
|
+
if (!taskCtx)
|
|
1463
|
+
return { ok: false, code: 'SESSION_NOT_FOUND', error: `未找到会话 ${sessionId} 的运行时上下文` };
|
|
1464
|
+
const memoryConfig = taskCtx.selfAid
|
|
1465
|
+
? this.agentRegistry?.get(taskCtx.selfAid)?.config?.memory
|
|
1466
|
+
: undefined;
|
|
1467
|
+
const { writeMemoryNote } = await import('./core/memory/memory-writer.js');
|
|
1468
|
+
return await writeMemoryNote({
|
|
1469
|
+
content, slug,
|
|
1470
|
+
tags: Array.isArray(tags) ? tags : undefined,
|
|
1471
|
+
speakers: Array.isArray(speakers) ? speakers : undefined,
|
|
1472
|
+
taskCtx, memoryConfig,
|
|
1473
|
+
});
|
|
1474
|
+
}
|
|
1475
|
+
catch (e) {
|
|
1476
|
+
return { ok: false, error: e?.message || String(e) };
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
case 'memory.note.update': {
|
|
1480
|
+
const { sessionId, slug, newSlug, tags, tagsProvided, content } = cmd;
|
|
1481
|
+
if (!sessionId)
|
|
1482
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing sessionId' };
|
|
1483
|
+
try {
|
|
1484
|
+
const taskCtx = await this.resolveMemoryTaskCtx(sessionId, cmd.debug === true);
|
|
1485
|
+
if (!taskCtx)
|
|
1486
|
+
return { ok: false, code: 'SESSION_NOT_FOUND', error: `未找到会话 ${sessionId} 的运行时上下文` };
|
|
1487
|
+
const memoryConfig = taskCtx.selfAid
|
|
1488
|
+
? this.agentRegistry?.get(taskCtx.selfAid)?.config?.memory
|
|
1489
|
+
: undefined;
|
|
1490
|
+
const { updateMemoryNote } = await import('./core/memory/memory-writer.js');
|
|
1491
|
+
return await updateMemoryNote({
|
|
1492
|
+
taskCtx, target: slug, newSlug,
|
|
1493
|
+
tags: tagsProvided ? (Array.isArray(tags) ? tags : []) : undefined,
|
|
1494
|
+
content, memoryConfig,
|
|
1495
|
+
});
|
|
1496
|
+
}
|
|
1497
|
+
catch (e) {
|
|
1498
|
+
return { ok: false, error: e?.message || String(e) };
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
case 'memory.note.drop': {
|
|
1502
|
+
const { sessionId, slug } = cmd;
|
|
1503
|
+
if (!sessionId)
|
|
1504
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing sessionId' };
|
|
1505
|
+
try {
|
|
1506
|
+
const taskCtx = await this.resolveMemoryTaskCtx(sessionId, cmd.debug === true);
|
|
1507
|
+
if (!taskCtx)
|
|
1508
|
+
return { ok: false, code: 'SESSION_NOT_FOUND', error: `未找到会话 ${sessionId} 的运行时上下文` };
|
|
1509
|
+
const memoryConfig = taskCtx.selfAid
|
|
1510
|
+
? this.agentRegistry?.get(taskCtx.selfAid)?.config?.memory
|
|
1511
|
+
: undefined;
|
|
1512
|
+
const { dropMemoryNote } = await import('./core/memory/memory-writer.js');
|
|
1513
|
+
return await dropMemoryNote({ taskCtx, target: slug, memoryConfig });
|
|
1514
|
+
}
|
|
1515
|
+
catch (e) {
|
|
1516
|
+
return { ok: false, error: e?.message || String(e) };
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
case 'memory.note.list': {
|
|
1520
|
+
const { sessionId } = cmd;
|
|
1521
|
+
if (!sessionId)
|
|
1522
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing sessionId' };
|
|
1523
|
+
try {
|
|
1524
|
+
const taskCtx = await this.resolveMemoryTaskCtx(sessionId, cmd.debug === true);
|
|
1525
|
+
if (!taskCtx)
|
|
1526
|
+
return { ok: false, code: 'SESSION_NOT_FOUND', error: `未找到会话 ${sessionId} 的运行时上下文` };
|
|
1527
|
+
const memoryConfig = taskCtx.selfAid
|
|
1528
|
+
? this.agentRegistry?.get(taskCtx.selfAid)?.config?.memory
|
|
1529
|
+
: undefined;
|
|
1530
|
+
const { listMemoryNotes } = await import('./core/memory/memory-writer.js');
|
|
1531
|
+
return await listMemoryNotes({ taskCtx, memoryConfig });
|
|
1532
|
+
}
|
|
1533
|
+
catch (e) {
|
|
1534
|
+
return { ok: false, error: e?.message || String(e) };
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
case 'memory.consolidate': {
|
|
1538
|
+
const { sessionId, mode } = cmd;
|
|
1539
|
+
if (!sessionId)
|
|
1540
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing sessionId' };
|
|
1541
|
+
if (!this.taskRuntimeContextProvider)
|
|
1542
|
+
return { ok: false, code: 'NOT_CONFIGURED', error: 'task runtime context not configured' };
|
|
1543
|
+
try {
|
|
1544
|
+
const { CONSOLIDATION_MODES } = await import('./core/memory/consolidation-context.js');
|
|
1545
|
+
const effectiveMode = (mode ?? 'notes');
|
|
1546
|
+
if (!CONSOLIDATION_MODES.includes(effectiveMode)) {
|
|
1547
|
+
return { ok: false, code: 'INVALID_REQUEST', error: `mode must be one of ${CONSOLIDATION_MODES.join(' / ')}` };
|
|
1548
|
+
}
|
|
1549
|
+
const taskCtx = await this.resolveMemoryTaskCtx(sessionId, cmd.debug === true);
|
|
1550
|
+
if (!taskCtx)
|
|
1551
|
+
return { ok: false, code: 'SESSION_NOT_FOUND', error: `未找到会话 ${sessionId} 的运行时上下文` };
|
|
1552
|
+
const mc = this.agentRegistry?.get(taskCtx.selfAid ?? '')?.config?.memory;
|
|
1553
|
+
const disabled = this.checkMemoryEnabled(mc, effectiveMode, taskCtx);
|
|
1554
|
+
if (disabled)
|
|
1555
|
+
return disabled;
|
|
1556
|
+
const ownerAid = taskCtx.selfAid
|
|
1557
|
+
? this.agentRegistry?.get(taskCtx.selfAid)?.config?.owners?.[0]
|
|
1558
|
+
: undefined;
|
|
1559
|
+
const { launchConsolidation } = await import('./core/memory/launch-consolidation.js');
|
|
1560
|
+
if (!this.consolidationLaunchExecutor) {
|
|
1561
|
+
// daemon 未注入 launcher —— 无法直接创建整理会话,明确报错而不是静默失败
|
|
1562
|
+
return { ok: false, code: 'NOT_CONFIGURED', error: 'daemon 未注入整理会话 launcher' };
|
|
1563
|
+
}
|
|
1564
|
+
const r = await this.consolidationLaunchExecutor({
|
|
1565
|
+
taskCtx,
|
|
1566
|
+
mode: effectiveMode,
|
|
1567
|
+
triggeredBy: 'manual',
|
|
1568
|
+
ownerAid,
|
|
1569
|
+
forgetAfterDays: mc?.forgetAfterDays,
|
|
1570
|
+
});
|
|
1571
|
+
return {
|
|
1572
|
+
ok: true,
|
|
1573
|
+
triggerId: r.triggerId,
|
|
1574
|
+
executionSessionId: r.executionSessionId,
|
|
1575
|
+
agentSessionId: r.agentSessionId,
|
|
1576
|
+
contextFile: r.contextFile,
|
|
1577
|
+
contextFilePath: r.contextFilePath,
|
|
1578
|
+
...(r.logFile ? { logFile: r.logFile } : {}),
|
|
1579
|
+
mode: effectiveMode,
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
catch (e) {
|
|
1583
|
+
return { ok: false, error: e?.message || String(e) };
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
case 'memory.create': {
|
|
1587
|
+
const { sessionId, scope, slug, description, content, tags, keywords, replaces, targetPeerKey, generalizedFrom, promotedFrom } = cmd;
|
|
1588
|
+
if (!sessionId)
|
|
1589
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing sessionId' };
|
|
1590
|
+
try {
|
|
1591
|
+
const guard = await this.assertMemoryWriteSession(sessionId, scope, 'create', replaces, cmd.debug === true);
|
|
1592
|
+
if ('error' in guard)
|
|
1593
|
+
return guard.error;
|
|
1594
|
+
const { createMemory } = await import('./core/memory/memory-writer.js');
|
|
1595
|
+
const { appendOpsRecord } = await import('./core/memory/consolidation-ops-records.js');
|
|
1596
|
+
let createResult;
|
|
1597
|
+
try {
|
|
1598
|
+
createResult = await createMemory({
|
|
1599
|
+
taskCtx: guard.taskCtx,
|
|
1600
|
+
scope: scope,
|
|
1601
|
+
ownerAid: guard.ownerAid,
|
|
1602
|
+
slug, description, content,
|
|
1603
|
+
tags: Array.isArray(tags) ? tags : [],
|
|
1604
|
+
keywords: Array.isArray(keywords) ? keywords : undefined,
|
|
1605
|
+
replaces: Array.isArray(replaces) ? replaces : undefined,
|
|
1606
|
+
targetPeerKey: typeof targetPeerKey === 'string' ? targetPeerKey : undefined,
|
|
1607
|
+
generalizedFrom: typeof generalizedFrom === 'string' ? generalizedFrom : undefined,
|
|
1608
|
+
promotedFrom: typeof promotedFrom === 'string' ? promotedFrom : undefined,
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1611
|
+
catch (e) {
|
|
1612
|
+
const batchDir = guard.taskCtx.consolidationBatchDir;
|
|
1613
|
+
if (batchDir)
|
|
1614
|
+
appendOpsRecord(batchDir, { ts: new Date().toISOString(), op: 'create', scope: scope ?? '', target: slug ?? '', ok: false, error: e?.message });
|
|
1615
|
+
throw e;
|
|
1616
|
+
}
|
|
1617
|
+
const batchDir = guard.taskCtx.consolidationBatchDir;
|
|
1618
|
+
if (batchDir)
|
|
1619
|
+
appendOpsRecord(batchDir, { ts: new Date().toISOString(), op: 'create', scope: scope ?? '', target: slug ?? '', filePath: createResult.filePath, archivedFiles: createResult.archived.map((dest, i) => ({ source: (Array.isArray(replaces) ? replaces : [])[i] ?? dest, archivedTo: dest })), tags: Array.isArray(tags) ? tags : [], memoryDir: createResult.scopeDirs.memoryDir, ok: true });
|
|
1620
|
+
return { ok: true, filePath: createResult.filePath, archived: createResult.archived };
|
|
1621
|
+
}
|
|
1622
|
+
catch (e) {
|
|
1623
|
+
return { ok: false, error: e?.message || String(e) };
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
case 'memory.update': {
|
|
1627
|
+
const { sessionId, filePath, tags, touch } = cmd;
|
|
1628
|
+
if (!sessionId)
|
|
1629
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing sessionId' };
|
|
1630
|
+
try {
|
|
1631
|
+
const guard = await this.assertMemoryWriteSession(sessionId, undefined, 'update', undefined, cmd.debug === true);
|
|
1632
|
+
if ('error' in guard)
|
|
1633
|
+
return guard.error;
|
|
1634
|
+
const { updateMemory } = await import('./core/memory/memory-writer.js');
|
|
1635
|
+
const { appendOpsRecord } = await import('./core/memory/consolidation-ops-records.js');
|
|
1636
|
+
let updateResult;
|
|
1637
|
+
try {
|
|
1638
|
+
updateResult = await updateMemory({
|
|
1639
|
+
taskCtx: guard.taskCtx,
|
|
1640
|
+
scope: guard.writeScope,
|
|
1641
|
+
ownerAid: guard.ownerAid,
|
|
1642
|
+
target: filePath,
|
|
1643
|
+
tags: Array.isArray(tags) ? tags : undefined,
|
|
1644
|
+
touch: !!touch,
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
catch (e) {
|
|
1648
|
+
const batchDir = guard.taskCtx.consolidationBatchDir;
|
|
1649
|
+
if (batchDir)
|
|
1650
|
+
appendOpsRecord(batchDir, { ts: new Date().toISOString(), op: 'update', scope: guard.writeScope, target: filePath ?? '', ok: false, error: e?.message });
|
|
1651
|
+
throw e;
|
|
1652
|
+
}
|
|
1653
|
+
const batchDirU = guard.taskCtx.consolidationBatchDir;
|
|
1654
|
+
if (batchDirU)
|
|
1655
|
+
appendOpsRecord(batchDirU, { ts: new Date().toISOString(), op: 'update', scope: guard.writeScope, target: filePath ?? '', tags: Array.isArray(tags) ? tags : undefined, prevTags: updateResult.prevTags, memoryDir: updateResult.scopeDirs.memoryDir, ok: true });
|
|
1656
|
+
return { ok: true, filePath: updateResult.filePath };
|
|
1657
|
+
}
|
|
1658
|
+
catch (e) {
|
|
1659
|
+
return { ok: false, error: e?.message || String(e) };
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
case 'memory.archive': {
|
|
1663
|
+
const { sessionId, filePaths } = cmd;
|
|
1664
|
+
if (!sessionId)
|
|
1665
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing sessionId' };
|
|
1666
|
+
try {
|
|
1667
|
+
const guard = await this.assertMemoryWriteSession(sessionId, undefined, 'archive', undefined, cmd.debug === true);
|
|
1668
|
+
if ('error' in guard)
|
|
1669
|
+
return guard.error;
|
|
1670
|
+
const { archiveMemory } = await import('./core/memory/memory-writer.js');
|
|
1671
|
+
const { appendOpsRecord } = await import('./core/memory/consolidation-ops-records.js');
|
|
1672
|
+
let archiveResult;
|
|
1673
|
+
try {
|
|
1674
|
+
archiveResult = await archiveMemory({
|
|
1675
|
+
taskCtx: guard.taskCtx,
|
|
1676
|
+
scope: guard.writeScope,
|
|
1677
|
+
ownerAid: guard.ownerAid,
|
|
1678
|
+
targets: Array.isArray(filePaths) ? filePaths : [],
|
|
1679
|
+
});
|
|
1680
|
+
}
|
|
1681
|
+
catch (e) {
|
|
1682
|
+
const batchDir = guard.taskCtx.consolidationBatchDir;
|
|
1683
|
+
if (batchDir)
|
|
1684
|
+
appendOpsRecord(batchDir, { ts: new Date().toISOString(), op: 'archive', scope: guard.writeScope, target: (Array.isArray(filePaths) ? filePaths : []).join(', '), ok: false, error: e?.message });
|
|
1685
|
+
throw e;
|
|
1686
|
+
}
|
|
1687
|
+
const batchDirA = guard.taskCtx.consolidationBatchDir;
|
|
1688
|
+
if (batchDirA) {
|
|
1689
|
+
for (let i = 0; i < archiveResult.archived.length; i++) {
|
|
1690
|
+
const archivedTo = archiveResult.archived[i];
|
|
1691
|
+
const sourceFile = (Array.isArray(filePaths) ? filePaths : [])[i] ?? archivedTo;
|
|
1692
|
+
appendOpsRecord(batchDirA, { ts: new Date().toISOString(), op: 'archive', scope: guard.writeScope, target: archivedTo, sourceFile, archivedTo, memoryDir: archiveResult.scopeDirs.memoryDir, ok: true });
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
return { ok: true, archived: archiveResult.archived };
|
|
1696
|
+
}
|
|
1697
|
+
catch (e) {
|
|
1698
|
+
return { ok: false, error: e?.message || String(e) };
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
case 'memory.demote': {
|
|
1702
|
+
const { sessionId, slug, scope } = cmd;
|
|
1703
|
+
if (!sessionId)
|
|
1704
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing sessionId' };
|
|
1705
|
+
try {
|
|
1706
|
+
const taskCtx = await this.resolveMemoryTaskCtx(sessionId, cmd.debug === true);
|
|
1707
|
+
if (!taskCtx)
|
|
1708
|
+
return { ok: false, code: 'SESSION_NOT_FOUND', error: `未找到会话 ${sessionId} 的运行时上下文` };
|
|
1709
|
+
if (scope !== 'agent' && scope !== 'owner') {
|
|
1710
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'scope 必须是 agent 或 owner' };
|
|
1711
|
+
}
|
|
1712
|
+
const { demoteMemory } = await import('./core/memory/memory-writer.js');
|
|
1713
|
+
const ownerAid = taskCtx.ownerAid;
|
|
1714
|
+
const result = await demoteMemory({ taskCtx, slug, scope: scope, ownerAid });
|
|
1715
|
+
await this.rebuildMemoryIndexFor(taskCtx, result.srcScopeDirs, ownerAid);
|
|
1716
|
+
// 重建目标层索引:从 destMemoryDir 推导出 consolidatedDir 和 memoryDir
|
|
1717
|
+
const destConsolidatedDir = path.join(result.destMemoryDir, 'consolidated');
|
|
1718
|
+
await this.rebuildMemoryIndexFor(taskCtx, { memoryDir: result.destMemoryDir, consolidatedDir: destConsolidatedDir }, ownerAid);
|
|
1719
|
+
return {
|
|
1720
|
+
ok: true,
|
|
1721
|
+
destPath: result.destPath,
|
|
1722
|
+
...(result.conflictArchived ? { conflictArchived: result.conflictArchived, note: '目标层已有同名文件,当前记忆已归档' } : {}),
|
|
1723
|
+
};
|
|
1724
|
+
}
|
|
1725
|
+
catch (e) {
|
|
1726
|
+
return { ok: false, error: e?.message || String(e) };
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
case 'memory.check-consolidation': {
|
|
1730
|
+
const { selfAid } = cmd;
|
|
1731
|
+
if (typeof selfAid !== 'string' || !selfAid) {
|
|
1732
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing selfAid' };
|
|
1733
|
+
}
|
|
1734
|
+
if (!this.consolidationCheckExecutor) {
|
|
1735
|
+
return { ok: false, code: 'NOT_CONFIGURED', error: 'daemon 未注入整理检查 executor' };
|
|
1736
|
+
}
|
|
1737
|
+
try {
|
|
1738
|
+
const result = await this.consolidationCheckExecutor({ selfAid });
|
|
1739
|
+
return { ok: true, ...result };
|
|
1740
|
+
}
|
|
1741
|
+
catch (e) {
|
|
1742
|
+
return { ok: false, error: e?.message || String(e) };
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
case 'memory.feedback': {
|
|
1746
|
+
const { sessionId, text } = cmd;
|
|
1747
|
+
if (!sessionId)
|
|
1748
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing sessionId' };
|
|
1749
|
+
if (typeof text !== 'string' || !text.trim()) {
|
|
1750
|
+
return { ok: false, code: 'INVALID_REQUEST', error: 'missing feedback text' };
|
|
1751
|
+
}
|
|
1752
|
+
try {
|
|
1753
|
+
const taskCtx = await this.resolveMemoryTaskCtx(sessionId, cmd.debug === true);
|
|
1754
|
+
if (!taskCtx)
|
|
1755
|
+
return { ok: false, code: 'SESSION_NOT_FOUND', error: `未找到会话 ${sessionId} 的运行时上下文` };
|
|
1756
|
+
// 只有整理会话可以记录反馈
|
|
1757
|
+
if (taskCtx.sessionType !== 'memory') {
|
|
1758
|
+
return { ok: false, code: 'NOT_MEMORY_SESSION', error: '`ec memory feedback` 只能在整理会话内调用' };
|
|
1759
|
+
}
|
|
1760
|
+
const batchDir = taskCtx.consolidationBatchDir;
|
|
1761
|
+
if (!batchDir) {
|
|
1762
|
+
return { ok: false, code: 'BATCH_DIR_NOT_FOUND', error: '整理会话缺少 consolidationBatchDir' };
|
|
1763
|
+
}
|
|
1764
|
+
const { appendOpsRecord } = await import('./core/memory/consolidation-ops-records.js');
|
|
1765
|
+
appendOpsRecord(batchDir, {
|
|
1766
|
+
ts: new Date().toISOString(),
|
|
1767
|
+
op: 'feedback-set',
|
|
1768
|
+
text,
|
|
1769
|
+
});
|
|
1770
|
+
return { ok: true };
|
|
1771
|
+
}
|
|
1772
|
+
catch (e) {
|
|
1773
|
+
return { ok: false, error: e?.message || String(e) };
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1409
1776
|
case 'config.op': {
|
|
1410
1777
|
if (!this.configOperationExecutor)
|
|
1411
1778
|
return { ok: false, code: 'NOT_CONFIGURED', error: 'config.op not configured' };
|
|
@@ -1568,6 +1935,12 @@ export class IpcServer {
|
|
|
1568
1935
|
const name = cmd.name;
|
|
1569
1936
|
if (!name || typeof name !== 'string')
|
|
1570
1937
|
return { ok: false, error: 'missing name' };
|
|
1938
|
+
const runtimeEnv = cmd.runtimeEnv === undefined ? undefined : parseRuntimeEnvironmentInput(cmd.runtimeEnv);
|
|
1939
|
+
if (runtimeEnv && !runtimeEnv.ok)
|
|
1940
|
+
return { ok: false, code: 'INVALID_REQUEST', error: runtimeEnv.error };
|
|
1941
|
+
const target = this.agentRegistry?.get(name);
|
|
1942
|
+
if (runtimeEnv?.ok && target)
|
|
1943
|
+
setRuntimeEnvironmentOverride(target.aid, runtimeEnv.values);
|
|
1571
1944
|
if (this.agentApplicationService) {
|
|
1572
1945
|
const result = await this.agentApplicationService.reload(name, { force: cmd.force === true });
|
|
1573
1946
|
if (!result.ok) {
|
|
@@ -1622,6 +1995,15 @@ export class IpcServer {
|
|
|
1622
1995
|
}
|
|
1623
1996
|
}
|
|
1624
1997
|
case 'evolagent.resync': {
|
|
1998
|
+
const runtimeEnv = cmd.runtimeEnv === undefined ? undefined : parseRuntimeEnvironmentInput(cmd.runtimeEnv);
|
|
1999
|
+
if (runtimeEnv && !runtimeEnv.ok)
|
|
2000
|
+
return { ok: false, code: 'INVALID_REQUEST', error: runtimeEnv.error };
|
|
2001
|
+
if (runtimeEnv?.ok) {
|
|
2002
|
+
setRuntimeEnvironmentOverride(undefined, runtimeEnv.values);
|
|
2003
|
+
for (const agent of this.agentRegistry?.list() ?? []) {
|
|
2004
|
+
setRuntimeEnvironmentOverride(agent.aid, runtimeEnv.values);
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
1625
2007
|
if (this.agentApplicationService) {
|
|
1626
2008
|
const result = await this.agentApplicationService.resync();
|
|
1627
2009
|
return result.ok
|
|
@@ -1663,6 +2045,15 @@ export class IpcServer {
|
|
|
1663
2045
|
const actorAid = typeof suppliedAuth?.actorAid === 'string' && suppliedAuth.actorAid.trim()
|
|
1664
2046
|
? suppliedAuth.actorAid.trim()
|
|
1665
2047
|
: null;
|
|
2048
|
+
const ecwebRequestId = typeof suppliedAuth?.ecwebRequestId === 'string' && suppliedAuth.ecwebRequestId.trim()
|
|
2049
|
+
? suppliedAuth.ecwebRequestId.trim()
|
|
2050
|
+
: undefined;
|
|
2051
|
+
const endpoint = typeof suppliedAuth?.endpoint === 'string' && suppliedAuth.endpoint.trim()
|
|
2052
|
+
? suppliedAuth.endpoint.trim()
|
|
2053
|
+
: undefined;
|
|
2054
|
+
const logicalToolName = typeof suppliedAuth?.logicalToolName === 'string' && suppliedAuth.logicalToolName.trim()
|
|
2055
|
+
? suppliedAuth.logicalToolName.trim()
|
|
2056
|
+
: undefined;
|
|
1666
2057
|
const response = await this.menuExecutor(cmd.payload, {
|
|
1667
2058
|
source: 'ecweb',
|
|
1668
2059
|
// The ECWeb process resolved this actor from its bearer token. The
|
|
@@ -1670,6 +2061,9 @@ export class IpcServer {
|
|
|
1670
2061
|
// menu handler still checks that actorAid remains a configured owner.
|
|
1671
2062
|
actorAid,
|
|
1672
2063
|
localDirect: suppliedAuth?.localDirect === true,
|
|
2064
|
+
ecwebRequestId,
|
|
2065
|
+
endpoint,
|
|
2066
|
+
logicalToolName,
|
|
1673
2067
|
// Reaching this handler means the control token gate succeeded.
|
|
1674
2068
|
// Never trust an authenticated flag supplied by the caller.
|
|
1675
2069
|
authenticated: true,
|
|
@@ -1712,6 +2106,164 @@ export class IpcServer {
|
|
|
1712
2106
|
return { error: `unknown command: ${cmd.type}` };
|
|
1713
2107
|
}
|
|
1714
2108
|
}
|
|
2109
|
+
// ── 记忆整理辅助 ──────────────────────────────────────────────────────────
|
|
2110
|
+
/**
|
|
2111
|
+
* 检查记忆开关。relation 是总开关:它关闭则整个记忆系统停用。
|
|
2112
|
+
* 返回 null 表示可用,否则返回错误响应。
|
|
2113
|
+
*/
|
|
2114
|
+
checkMemoryEnabled(mc, mode, taskCtx) {
|
|
2115
|
+
if (mc?.enableRelation === false) {
|
|
2116
|
+
return { ok: false, code: 'SCOPE_DISABLED', error: '记忆系统已停用(memory.enableRelation=false)' };
|
|
2117
|
+
}
|
|
2118
|
+
if (mode === 'generalize' && mc?.enableAgent === false) {
|
|
2119
|
+
return { ok: false, code: 'SCOPE_DISABLED', error: '泛化模式已停用(memory.enableAgent=false)' };
|
|
2120
|
+
}
|
|
2121
|
+
if (mode === 'promote' && mc?.enableOwner === false) {
|
|
2122
|
+
return { ok: false, code: 'SCOPE_DISABLED', error: '提升模式已停用(memory.enableOwner=false)' };
|
|
2123
|
+
}
|
|
2124
|
+
if (mode === 'promote' && !taskCtx.selfAid) {
|
|
2125
|
+
return { ok: false, code: 'INVALID_REQUEST', error: '无法确定当前 agent AID' };
|
|
2126
|
+
}
|
|
2127
|
+
return null;
|
|
2128
|
+
}
|
|
2129
|
+
/**
|
|
2130
|
+
* 写正式记忆前的会话校验:必须是整理会话(sessionType=memory),
|
|
2131
|
+
* 且模式与作用域匹配。返回授权后的上下文。
|
|
2132
|
+
*/
|
|
2133
|
+
async assertMemoryWriteSession(sessionId, requestedScope, op, replaces, debug = false) {
|
|
2134
|
+
if (!this.taskRuntimeContextProvider) {
|
|
2135
|
+
return { error: { ok: false, code: 'NOT_CONFIGURED', error: 'task runtime context not configured' } };
|
|
2136
|
+
}
|
|
2137
|
+
const taskCtx = await this.resolveMemoryTaskCtx(sessionId, debug);
|
|
2138
|
+
if (!taskCtx) {
|
|
2139
|
+
return { error: { ok: false, code: 'SESSION_NOT_FOUND', error: `未找到会话 ${sessionId} 的运行时上下文` } };
|
|
2140
|
+
}
|
|
2141
|
+
// 只有整理会话能写正式记忆
|
|
2142
|
+
const sessionType = taskCtx?.sessionType;
|
|
2143
|
+
if (sessionType !== 'memory') {
|
|
2144
|
+
return {
|
|
2145
|
+
error: {
|
|
2146
|
+
ok: false, code: 'ROLE_ACCESS_DENIED',
|
|
2147
|
+
error: `${op} 只能由整理会话(sessionType=memory)调用;主会话请用 \`ec memory note\``,
|
|
2148
|
+
},
|
|
2149
|
+
};
|
|
2150
|
+
}
|
|
2151
|
+
const mode = taskCtx?.memoryMode;
|
|
2152
|
+
const { MODE_SCOPE, CONSOLIDATION_MODES } = await import('./core/memory/consolidation-context.js');
|
|
2153
|
+
if (!mode || !CONSOLIDATION_MODES.includes(mode)) {
|
|
2154
|
+
return { error: { ok: false, code: 'INVALID_REQUEST', error: '当前会话没有有效的 memoryMode' } };
|
|
2155
|
+
}
|
|
2156
|
+
// forget 是分层审查:一次会话只审一层,允许写哪个作用域取决于会话带下来的
|
|
2157
|
+
// memoryScope(关系级索引重建 → relation;agent 级 → agent;owner 级 → owner)。
|
|
2158
|
+
// 其余四种模式由 MODE_SCOPE 唯一决定。
|
|
2159
|
+
const sessionScope = taskCtx?.memoryScope;
|
|
2160
|
+
const allowed = mode === 'forget' ? sessionScope : MODE_SCOPE[mode];
|
|
2161
|
+
if (!allowed) {
|
|
2162
|
+
return {
|
|
2163
|
+
error: {
|
|
2164
|
+
ok: false, code: 'INVALID_REQUEST',
|
|
2165
|
+
error: mode === 'forget'
|
|
2166
|
+
? 'forget 会话缺少 memoryScope,无法确定该写哪个作用域'
|
|
2167
|
+
: `${mode} 模式没有可写作用域`,
|
|
2168
|
+
},
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
if (op === 'create' && requestedScope !== allowed) {
|
|
2172
|
+
return {
|
|
2173
|
+
error: {
|
|
2174
|
+
ok: false, code: 'ROLE_ACCESS_DENIED',
|
|
2175
|
+
error: `${mode} 模式只能写 --scope ${allowed},收到 ${requestedScope ?? '(空)'}`,
|
|
2176
|
+
},
|
|
2177
|
+
};
|
|
2178
|
+
}
|
|
2179
|
+
// 二次查开关
|
|
2180
|
+
const mc = this.agentRegistry?.get(taskCtx.selfAid ?? '')?.config?.memory;
|
|
2181
|
+
const disabled = this.checkMemoryEnabled(mc, mode, taskCtx);
|
|
2182
|
+
if (disabled)
|
|
2183
|
+
return { error: disabled };
|
|
2184
|
+
const ownerAid = taskCtx.selfAid
|
|
2185
|
+
? this.agentRegistry?.get(taskCtx.selfAid)?.config?.owners?.[0]
|
|
2186
|
+
: undefined;
|
|
2187
|
+
if (allowed === 'owner' && !ownerAid) {
|
|
2188
|
+
return { error: { ok: false, code: 'INVALID_REQUEST', error: '当前 agent 未配置 owner' } };
|
|
2189
|
+
}
|
|
2190
|
+
return { taskCtx, writeScope: allowed, ownerAid };
|
|
2191
|
+
}
|
|
2192
|
+
/** 保存成功后重建对应作用域的索引。失败不影响写入结果。 */
|
|
2193
|
+
async rebuildMemoryIndexFor(taskCtx, dirs, ownerAid) {
|
|
2194
|
+
try {
|
|
2195
|
+
// owner: .../memory/owner/<ownerAid> → dirname 的 basename 是 'owner'
|
|
2196
|
+
// relation: .../relations/<peerKey>/memory → dirname 的 basename 是 peerKey,不是 'relations'
|
|
2197
|
+
// 用路径段列表判断,比看直接父目录名可靠。
|
|
2198
|
+
const memParts = dirs.memoryDir.split(path.sep);
|
|
2199
|
+
const scope = path.basename(path.dirname(dirs.memoryDir)) === 'owner'
|
|
2200
|
+
? 'owner'
|
|
2201
|
+
: memParts.includes('relations')
|
|
2202
|
+
? 'relation'
|
|
2203
|
+
: 'agent';
|
|
2204
|
+
const { rebuildIndex } = await import('./core/memory/index-manager.js');
|
|
2205
|
+
const mc = this.agentRegistry?.get(taskCtx.selfAid ?? '')?.config?.memory;
|
|
2206
|
+
const maxBytes = mc?.indexMaxBytes ?? 5 * 1024;
|
|
2207
|
+
const buildResult = await rebuildIndex(dirs.consolidatedDir, path.join(dirs.memoryDir, 'MEMORY.md'), scope, path.join(dirs.memoryDir, 'archive', 'invalid'), undefined, // 验签门控尚未开启,不传 verifyFn
|
|
2208
|
+
maxBytes);
|
|
2209
|
+
// 索引重建后顺手检查这一层有没有超期记忆 —— 有则建触发器拉一个独立的遗忘会话。
|
|
2210
|
+
await this.maybeTriggerForget(taskCtx, scope, dirs.consolidatedDir, mc, buildResult.verifiedFiles);
|
|
2211
|
+
}
|
|
2212
|
+
catch { /* 索引重建失败下次整理时会补上 */ }
|
|
2213
|
+
}
|
|
2214
|
+
/**
|
|
2215
|
+
* 重建索引后检查超期记忆;有到期的就建触发器拉起遗忘会话。
|
|
2216
|
+
*
|
|
2217
|
+
* 判据与定时检查共用 staleness.ts:mtime 决定进不进候选,
|
|
2218
|
+
* updatedAt 决定是否真的交给模型审查。未到期的长期记忆在这里被刷新 mtime(减速)。
|
|
2219
|
+
*/
|
|
2220
|
+
async maybeTriggerForget(taskCtx, scope, consolidatedDir, mc,
|
|
2221
|
+
/** 本次索引重建中验签通过的文件名;其余文件不做审查 */
|
|
2222
|
+
verifiedFiles) {
|
|
2223
|
+
const selfAid = taskCtx.selfAid;
|
|
2224
|
+
if (!selfAid)
|
|
2225
|
+
return;
|
|
2226
|
+
const { collectCandidates, isDueForReview, deferCandidate } = await import('./core/memory/staleness.js');
|
|
2227
|
+
const thresholds = { forgetAfterDays: mc?.forgetAfterDays ?? 3 };
|
|
2228
|
+
const now = Date.now();
|
|
2229
|
+
const verified = new Set(verifiedFiles);
|
|
2230
|
+
let due = 0;
|
|
2231
|
+
try {
|
|
2232
|
+
for (const info of collectCandidates(consolidatedDir, thresholds, now)) {
|
|
2233
|
+
// 验签失败的记忆不审查、不减速、也不进候选
|
|
2234
|
+
if (!verified.has(info.name))
|
|
2235
|
+
continue;
|
|
2236
|
+
if (isDueForReview(info, thresholds, now))
|
|
2237
|
+
due++;
|
|
2238
|
+
else {
|
|
2239
|
+
try {
|
|
2240
|
+
deferCandidate(info.filePath, now);
|
|
2241
|
+
}
|
|
2242
|
+
catch { /* ignore */ }
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
catch {
|
|
2247
|
+
return;
|
|
2248
|
+
}
|
|
2249
|
+
if (due === 0)
|
|
2250
|
+
return;
|
|
2251
|
+
// 该层有超期记忆 → 经统一队列拉独立遗忘会话
|
|
2252
|
+
try {
|
|
2253
|
+
if (!this.consolidationLaunchExecutor)
|
|
2254
|
+
return;
|
|
2255
|
+
const ownerAid = this.agentRegistry?.get(selfAid)?.config?.owners?.[0];
|
|
2256
|
+
await this.consolidationLaunchExecutor({
|
|
2257
|
+
taskCtx,
|
|
2258
|
+
mode: 'forget',
|
|
2259
|
+
triggeredBy: 'manual',
|
|
2260
|
+
ownerAid,
|
|
2261
|
+
forgetAfterDays: mc?.forgetAfterDays,
|
|
2262
|
+
scopeOverride: scope,
|
|
2263
|
+
});
|
|
2264
|
+
}
|
|
2265
|
+
catch { /* 触发失败不影响本次写入结果 */ }
|
|
2266
|
+
}
|
|
1715
2267
|
hasValidControlToken(value) {
|
|
1716
2268
|
if (!this.controlToken || typeof value !== 'string')
|
|
1717
2269
|
return false;
|
|
@@ -1789,9 +2341,19 @@ function ipcQueryOnce(socketPath, cmd, timeoutMs = 3000) {
|
|
|
1789
2341
|
}
|
|
1790
2342
|
catch { }
|
|
1791
2343
|
}
|
|
2344
|
+
const requestArgv = Array.isArray(authenticatedCmd.argv)
|
|
2345
|
+
&& authenticatedCmd.argv.every((value) => typeof value === 'string')
|
|
2346
|
+
? [
|
|
2347
|
+
'ec',
|
|
2348
|
+
...(authenticatedCmd.type === 'menu-client.request' ? ['menu-client'] : []),
|
|
2349
|
+
...authenticatedCmd.argv,
|
|
2350
|
+
]
|
|
2351
|
+
: undefined;
|
|
1792
2352
|
const delegationCommandHash = typeof authenticatedCmd.delegationToken === 'string'
|
|
1793
2353
|
&& typeof authenticatedCmd.delegationCommandHash !== 'string'
|
|
1794
|
-
?
|
|
2354
|
+
? requestArgv
|
|
2355
|
+
? hashDelegatedCommandArgv(requestArgv)
|
|
2356
|
+
: hashCurrentDelegatedCommand()
|
|
1795
2357
|
: undefined;
|
|
1796
2358
|
const request = {
|
|
1797
2359
|
...(delegationCommandHash ? { ...authenticatedCmd, delegationCommandHash } : authenticatedCmd),
|