evolcore 0.0.31 → 0.0.33
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 +35 -0
- package/bin/install-codex-managed-hooks.mjs +124 -37
- package/dist/agents/claude-runner.js +29 -2
- package/dist/agents/codex/app-server-client.js +3 -0
- package/dist/agents/codex/diagnostics.js +76 -44
- package/dist/agents/codex-runner.js +51 -24
- package/dist/agents/ecagent-runner.js +9 -13
- package/dist/agents/gemini-runner.js +4 -0
- package/dist/aun/aid/store.js +0 -81
- package/dist/aun/group/fs-download.js +1 -10
- package/dist/aun/group/operations.js +0 -1
- package/dist/aun/msg/history.js +1 -0
- package/dist/aun/msg/managed-operation.js +130 -32
- package/dist/aun/msg/p2p.js +0 -1
- package/dist/aun/outbox.js +50 -1
- package/dist/aun/service-proxy.js +12 -18
- package/dist/aun/storage/index.js +29 -0
- package/dist/channels/aun.js +38 -137
- package/dist/channels/daemon.js +257 -2
- package/dist/cli/agent-command.js +64 -31
- package/dist/cli/agent-create.js +43 -24
- package/dist/cli/agent.js +16 -70
- package/dist/cli/aun-commands.js +512 -32
- package/dist/cli/contact.js +8 -2
- package/dist/cli/ctl-command.js +1 -2
- package/dist/cli/daemon-commands.js +82 -13
- package/dist/cli/debug-mode.js +154 -0
- package/dist/cli/diag.js +2 -2
- package/dist/cli/handoff-command.js +18 -5
- package/dist/cli/index.js +81 -64
- package/dist/cli/init.js +2 -2
- package/dist/cli/managed-command-guard.js +5 -0
- package/dist/cli/memory-command.js +93 -12
- package/dist/cli/model.js +14 -138
- package/dist/cli/queue-command.js +51 -0
- package/dist/cli/response.js +5 -54
- package/dist/cli/session-command.js +194 -0
- package/dist/cli/skill-command.js +85 -3
- package/dist/cli/stats.js +10 -4
- package/dist/cli/task-command.js +1 -0
- package/dist/cli/task-context.js +16 -0
- package/dist/cli/thread-command.js +620 -0
- package/dist/cli/trigger-command.js +76 -50
- package/dist/config/builtin-roles.js +9 -7
- package/dist/config/config-field-policy.js +2 -3
- package/dist/config/config-manager.js +7 -2
- package/dist/config/resolved-config-op.js +3 -0
- package/dist/config-store.js +15 -0
- package/dist/core/agent-ipc-registration.js +65 -22
- package/dist/core/auth/agent-delegation.js +42 -2
- package/dist/core/auth/debug-context.js +139 -0
- package/dist/core/auth/delegation-authorization.js +1 -0
- package/dist/core/auth/operation-authorizer.js +24 -1
- package/dist/core/auth/operation-catalog.js +44 -3
- package/dist/core/background-session/session-cleanup.js +212 -0
- package/dist/core/background-session/types.js +10 -0
- package/dist/core/bootstrap-messages.js +1 -1
- package/dist/core/bootstrap-service.js +6 -3
- package/dist/core/command/command-handler.js +224 -45
- package/dist/core/command/diag-service.js +5 -1
- package/dist/core/command/memory-slash.js +6 -2
- package/dist/core/command/menu-catalog.js +48 -1
- package/dist/core/command/menu-handler.js +92 -16
- package/dist/core/command/menu-protocol.js +24 -1
- package/dist/core/command/skill-slash.js +322 -0
- package/dist/core/command/slash-gate.js +6 -4
- package/dist/core/command/slash-handler.js +193 -13
- package/dist/core/command/topic-slash.js +528 -0
- package/dist/core/evolagent-registry.js +20 -5
- package/dist/core/handoff/ipc-registration.js +38 -0
- package/dist/core/handoff/runtime.js +5 -11
- package/dist/core/handoff/store.js +5 -0
- package/dist/core/ipc-registration.js +210 -9
- package/dist/core/memory/consolidation-context.js +49 -16
- package/dist/core/memory/consolidation-ops-records.js +35 -0
- package/dist/core/memory/consolidation-queue-format.js +21 -0
- package/dist/core/memory/consolidation.js +174 -180
- package/dist/core/message/aun-ipc-sender.js +207 -8
- package/dist/core/message/im-renderer.js +149 -6
- package/dist/core/message/message-bridge.js +13 -3
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-queue.js +131 -3
- package/dist/core/message/peer-mode.js +6 -1
- package/dist/core/message/response-engine.js +379 -69
- package/dist/core/message/subtask-tool-projection.js +140 -0
- package/dist/core/model/catalog-service.js +17 -12
- package/dist/core/permission/ec-command-parser.js +126 -7
- package/dist/core/permission/sandbox-runtime.js +14 -1
- package/dist/core/session/session-idle-monitor.js +249 -22
- package/dist/core/session/session-manager.js +54 -9
- package/dist/core/skill/command-parser.js +13 -0
- package/dist/core/skill/index-generator.js +4 -1
- package/dist/core/skill/startup.js +41 -0
- package/dist/core/skill/switch-resolver.js +55 -29
- package/dist/core/task/task-recovery-service.js +2 -0
- package/dist/core/task/task-resume-operation.js +11 -0
- package/dist/core/thread/command-parser.js +125 -0
- package/dist/core/thread/index.js +1 -0
- package/dist/core/thread/ipc-operation.js +95 -0
- package/dist/core/thread/thread-context-storage.js +131 -0
- package/dist/core/thread/thread-operation.js +258 -0
- package/dist/core/thread/thread-route.js +33 -0
- package/dist/core/thread/thread-service.js +777 -0
- package/dist/core/thread/types.js +1 -0
- package/dist/eck/message-renderer.js +35 -0
- package/dist/index.js +10 -7
- package/dist/ipc.js +234 -17
- package/dist/paths.js +23 -0
- package/dist/response-system/engines/v1/proactive-flow.js +169 -80
- package/dist/trigger/authorization.js +59 -29
- package/dist/trigger/feedback.js +7 -1
- package/dist/trigger/ipc-service.js +49 -35
- package/dist/trigger/parser.js +63 -1
- package/dist/trigger/script-sandbox.js +58 -77
- package/dist/trigger/validation.js +14 -0
- package/dist/utils/error-utils.js +22 -1
- package/kits/docs/AUTHORING.md +1 -1
- package/kits/docs/channels/aun.md +8 -0
- package/kits/docs/context-assembly.md +1 -0
- package/kits/docs/evolcore/INDEX.md +3 -2
- package/kits/docs/evolcore/agent-create.md +39 -28
- package/kits/docs/evolcore/agent.md +19 -4
- package/kits/docs/evolcore/ec-capabilities.md +4 -0
- package/kits/docs/evolcore/group-collaboration.md +3 -5
- package/kits/docs/evolcore/group.md +3 -4
- package/kits/docs/evolcore/memory-consolidation.md +1 -1
- package/kits/docs/evolcore/menu-exec-schema-commands.md +2 -2
- package/kits/docs/evolcore/menu-protocol.md +7 -0
- package/kits/docs/evolcore/msg.md +5 -8
- package/kits/docs/evolcore/task.md +2 -0
- package/kits/docs/evolcore/thread-chain.md +267 -0
- package/kits/docs/evolcore/trigger.md +2 -2
- package/kits/docs/prompt-loading-architecture.md +1 -0
- package/kits/eck_manifest.json +61 -26
- package/kits/eck_message_manifest.json +169 -10
- package/kits/rules/01-overview.md +0 -9
- package/kits/rules/05-venue.md +1 -1
- package/kits/rules/06-channel.md +7 -1
- package/kits/rules/07-memory-and-thread.md +202 -0
- package/kits/schemas/relation-config.schema.9.json +18 -3
- package/kits/schemas/role-config.schema.1.json +6 -6
- package/kits/schemas/single-session.schema.1.json +6 -6
- package/kits/schemas/single-session.schema.2.json +6 -6
- package/kits/schemas/single-session.schema.3.json +6 -6
- package/kits/skills/.switches.json +12 -1
- package/kits/skills/ec-group/SKILL.md +234 -0
- package/kits/skills/ec-skill/SKILL.md +10 -1
- package/kits/skills/ec-skill/scripts/cli.mjs +15 -1
- package/kits/skills/scrapling-article-fetch/SKILL.md +128 -0
- package/kits/skills/scrapling-article-fetch/scripts/check_python_env.py +54 -0
- package/kits/skills/scrapling-article-fetch/scripts/render_markdown_reply.py +35 -0
- package/kits/skills/scrapling-article-fetch/scripts/run_pipeline.sh +16 -0
- package/kits/skills/scrapling-article-fetch/scripts/scrapling_fetch.py +344 -0
- package/kits/skills/thread-ops/SKILL.md +492 -0
- package/kits/skills/wechat-article-media-download/SKILL.md +65 -0
- package/kits/skills/wechat-article-media-download/scripts/download.py +163 -0
- package/kits/skills/wechat-article-reader/SKILL.md +97 -0
- package/kits/skills/wechat-article-reader/scripts/fetch.mjs +256 -0
- package/kits/templates/bootstrap-welcome.md +7 -7
- package/kits/templates/memory-consolidation/forget.md +5 -0
- package/kits/templates/memory-consolidation/generalize.md +5 -0
- package/kits/templates/memory-consolidation/profile.md +5 -0
- package/kits/templates/memory-consolidation/promote.md +5 -0
- package/kits/templates/message-fragments/item.md +2 -1
- package/kits/templates/message-fragments/thread-context.md +6 -0
- package/kits/templates/message-fragments/trigger-session.md +2 -0
- package/kits/templates/message-fragments/trigger-thread-check.md +2 -0
- package/kits/templates/roles/member.json +2 -0
- package/kits/templates/roles/visitor.json +2 -0
- package/kits/templates/system-fragments/bootstrap.md +66 -72
- package/kits/templates/system-fragments/channel.md +3 -6
- package/kits/templates/system-fragments/commands.md +2 -1
- package/kits/templates/system-fragments/managed-runtime.md +15 -0
- package/kits/templates/system-fragments/reply.md +3 -2
- package/kits/templates/system-fragments/session.md +5 -14
- package/package.json +3 -1
- package/kits/docs/evolcore/group-fs.md +0 -17
- package/kits/docs/venues/aun-group.md +0 -45
- package/kits/docs/venues/group.md +0 -43
|
@@ -12,9 +12,7 @@ import fs from 'fs';
|
|
|
12
12
|
import path from 'path';
|
|
13
13
|
import { agentDir, resolveRoot } from '../../paths.js';
|
|
14
14
|
import { serializeConsolidationContext } from './consolidation-context.js';
|
|
15
|
-
import { normalizeTriggerDefinition } from '../../trigger/validation.js';
|
|
16
15
|
import { formatChannelKey } from '../channel-loader.js';
|
|
17
|
-
import { formatPeerKey } from '../relation/peer-identity.js';
|
|
18
16
|
import { logger } from '../../utils/logger.js';
|
|
19
17
|
import { appendOpsRecord } from './consolidation-ops-records.js';
|
|
20
18
|
import { checkConsolidationCandidates, shouldUseMetaIndex } from './consolidation-trigger.js';
|
|
@@ -50,47 +48,6 @@ function cleanupPreviousConsolidationBatches(selfAid) {
|
|
|
50
48
|
logger.warn(`[Memory] 清理整理批次时出错: ${e?.message}`);
|
|
51
49
|
}
|
|
52
50
|
}
|
|
53
|
-
export function buildDebugTaskContext(input) {
|
|
54
|
-
const { session } = input;
|
|
55
|
-
const meta = (session.metadata ?? {});
|
|
56
|
-
const sessionType = session.sessionType ?? meta.sessionType ?? 'main';
|
|
57
|
-
let channel = session.channelType || session.channel;
|
|
58
|
-
let chatType = session.chatType || 'private';
|
|
59
|
-
let peerId = meta.peerId;
|
|
60
|
-
let peerKeyId = chatType === 'group'
|
|
61
|
-
? (meta.groupId || session.channelId)
|
|
62
|
-
: (meta.peerId || session.channelId);
|
|
63
|
-
let threadId = session.threadId || undefined;
|
|
64
|
-
if (session.channelId?.startsWith('trigger:') && session.selfAID && input.getTrigger) {
|
|
65
|
-
const triggerId = session.channelId.slice('trigger:'.length);
|
|
66
|
-
const origin = input.getTrigger(session.selfAID, triggerId)?.origin;
|
|
67
|
-
if (origin?.channelType) {
|
|
68
|
-
channel = origin.channelType;
|
|
69
|
-
chatType = origin.delivery?.chatType ?? 'private';
|
|
70
|
-
peerId = origin.peerId;
|
|
71
|
-
peerKeyId = chatType === 'group' ? origin.channelId : (origin.peerId ?? origin.channelId);
|
|
72
|
-
threadId = origin.threadId;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return {
|
|
76
|
-
sessionId: session.id,
|
|
77
|
-
baseagent: session.baseagent,
|
|
78
|
-
channel,
|
|
79
|
-
channelId: session.channelId,
|
|
80
|
-
chatType,
|
|
81
|
-
selfAid: session.selfAID,
|
|
82
|
-
peerId,
|
|
83
|
-
peerKey: channel && peerKeyId ? formatPeerKey(channel, peerKeyId) : undefined,
|
|
84
|
-
peerName: meta.peerName,
|
|
85
|
-
peerType: meta.peerType,
|
|
86
|
-
threadId,
|
|
87
|
-
sessionType,
|
|
88
|
-
memoryMode: meta.memoryMode,
|
|
89
|
-
memoryScope: meta.memoryScope,
|
|
90
|
-
consolidationBatchDir: meta.consolidationBatchDir ?? meta.consolidationLogBase,
|
|
91
|
-
sessionRuntimeDir: input.sessionRuntimeDir,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
51
|
/**
|
|
95
52
|
* 序列化上下文并直接创建整理会话。
|
|
96
53
|
* 失败抛错,调用方负责决定是否记录诊断或回传错误。
|
|
@@ -107,6 +64,7 @@ export async function launchConsolidation(channel, params) {
|
|
|
107
64
|
cleanupPreviousConsolidationBatches(selfAid);
|
|
108
65
|
// notes 模式:pending/ → processing/ 快照迁移(在序列化上下文之前执行,声明认领)
|
|
109
66
|
let memoryDir;
|
|
67
|
+
let claimedProcessing = false;
|
|
110
68
|
if (mode === 'notes') {
|
|
111
69
|
memoryDir = effectiveCtx.peerKey
|
|
112
70
|
? path.join(resolveRoot(), 'agents', selfAid, 'relations', effectiveCtx.peerKey, 'memory')
|
|
@@ -114,13 +72,13 @@ export async function launchConsolidation(channel, params) {
|
|
|
114
72
|
const pendingDir = path.join(memoryDir, 'pending');
|
|
115
73
|
const processingDir = path.join(memoryDir, 'processing');
|
|
116
74
|
if (fs.existsSync(processingDir)) {
|
|
117
|
-
|
|
118
|
-
logger.warn(`[Memory] processing/ 已存在,跳过本次迁移(上一批未收尾): ${processingDir}`);
|
|
75
|
+
throw new Error(`上一批整理尚未收尾,不能重新认领 processing: ${processingDir}`);
|
|
119
76
|
}
|
|
120
77
|
else if (fs.existsSync(pendingDir)) {
|
|
121
78
|
try {
|
|
122
79
|
const count = fs.readdirSync(pendingDir).filter(f => f.endsWith('.md')).length;
|
|
123
80
|
fs.renameSync(pendingDir, processingDir);
|
|
81
|
+
claimedProcessing = true;
|
|
124
82
|
// 立即重建空 pending 目录,供主会话后续写 note
|
|
125
83
|
fs.mkdirSync(pendingDir, { recursive: true });
|
|
126
84
|
logger.info(`[Memory] pending → processing 快照完成(${count} 条 note): ${processingDir}`);
|
|
@@ -131,20 +89,29 @@ export async function launchConsolidation(channel, params) {
|
|
|
131
89
|
}
|
|
132
90
|
}
|
|
133
91
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
92
|
+
let ctxFile;
|
|
93
|
+
try {
|
|
94
|
+
ctxFile = serializeConsolidationContext({
|
|
95
|
+
mode,
|
|
96
|
+
triggeredBy,
|
|
97
|
+
taskCtx: effectiveCtx,
|
|
98
|
+
ownerAid,
|
|
99
|
+
sessionRuntimeDir: effectiveCtx.sessionRuntimeDir,
|
|
100
|
+
ownerInvolved: params.ownerInvolved,
|
|
101
|
+
forgetAfterDays: params.forgetAfterDays,
|
|
102
|
+
scopeOverride: params.scopeOverride,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (claimedProcessing && memoryDir)
|
|
107
|
+
restorePendingNotes(memoryDir);
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
144
110
|
const baseagent = effectiveCtx.baseagent ?? 'claude';
|
|
145
111
|
const now = Date.now();
|
|
146
112
|
const scopeTag = params.scopeOverride ? `-${params.scopeOverride}` : '';
|
|
147
|
-
const
|
|
113
|
+
const kind = `memory-consolidate-${mode}${scopeTag}`;
|
|
114
|
+
const triggerId = `${kind}-${now.toString(36)}`;
|
|
148
115
|
// 整理会话的渠道信息(origin):发起时抓取,供反馈时直接投递到原会话渠道。
|
|
149
116
|
// 用 channelId/peerId/threadId 三要素——不依赖 evolcore sessionId,renew/`/new` 换会话也不影响送达。
|
|
150
117
|
const feedbackOrigin = effectiveCtx.channel && effectiveCtx.peerId ? {
|
|
@@ -156,109 +123,73 @@ export async function launchConsolidation(channel, params) {
|
|
|
156
123
|
...(effectiveCtx.threadId ? { threadId: effectiveCtx.threadId } : {}),
|
|
157
124
|
delivery: { chatType: effectiveCtx.chatType ?? 'private' },
|
|
158
125
|
} : undefined;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
'',
|
|
179
|
-
'请先读取上述上下文文件,再按照注入的整理规范完成本次整理。',
|
|
180
|
-
].join('\n'),
|
|
126
|
+
const projectPath = params.projectPath ?? path.join(resolveRoot(), 'agents', selfAid);
|
|
127
|
+
const prompt = [
|
|
128
|
+
'你正在执行记忆整理任务。',
|
|
129
|
+
`本次整理模式:${mode}`,
|
|
130
|
+
`整理上下文文件路径:${ctxFile.filePath}`,
|
|
131
|
+
'',
|
|
132
|
+
'请先读取上述上下文文件,再按照注入的整理规范完成本次整理。',
|
|
133
|
+
].join('\n');
|
|
134
|
+
// 通过 BackgroundSessionLauncher 拉起独立会话。
|
|
135
|
+
// 不再构造 TriggerDefinition——与 trigger 调度系统完全解耦。
|
|
136
|
+
// on_next_launch 默认策略由 launchBackgroundSession() 负责清理 evolcore session chat 目录;
|
|
137
|
+
// cleanupPreviousConsolidationLogs()(上方已调用)负责清理 memory/consolidation-logs/ 日志目录。
|
|
138
|
+
// 两者清理的是不同的数据,互不重复。
|
|
139
|
+
// 详见 docs/background-session/background-session-launcher.md
|
|
140
|
+
let handle;
|
|
141
|
+
try {
|
|
142
|
+
handle = await channel.launch({
|
|
143
|
+
kind,
|
|
144
|
+
instanceId: now.toString(36),
|
|
181
145
|
baseagent,
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// normalizeTriggerDefinition 只保留白名单字段,自定义字段在其后补挂。
|
|
202
|
-
// 反馈目标(发起时渠道三元组)与触发方式,收尾流程据此投递 / 判断是否反馈。
|
|
203
|
-
if (feedbackOrigin) {
|
|
204
|
-
triggerDef.execution.feedbackOrigin = feedbackOrigin;
|
|
146
|
+
agentAid: selfAid,
|
|
147
|
+
projectPath,
|
|
148
|
+
prompt,
|
|
149
|
+
metadata: {
|
|
150
|
+
sessionType: 'memory',
|
|
151
|
+
memoryMode: mode,
|
|
152
|
+
...(params.scopeOverride ? { memoryScope: params.scopeOverride } : {}),
|
|
153
|
+
// 透传到 session.metadata,供 ipc.ts 写 ops 流水、收尾流程读取
|
|
154
|
+
consolidationBatchDir: ctxFile.batchDir,
|
|
155
|
+
...(ctxFile.chatDir ? { consolidationChatDir: ctxFile.chatDir } : {}),
|
|
156
|
+
...(claimedProcessing && memoryDir ? { consolidationMemoryDir: memoryDir } : {}),
|
|
157
|
+
consolidationUsedThreadSnapshots: !!ctxFile.threadFiles?.length,
|
|
158
|
+
...(ctxFile.snapshotThroughTs ? { consolidationSnapshotThroughTs: ctxFile.snapshotThroughTs } : {}),
|
|
159
|
+
...(effectiveCtx.peerKey ? { peerKey: effectiveCtx.peerKey } : {}),
|
|
160
|
+
...(feedbackOrigin ? { feedbackOrigin } : {}),
|
|
161
|
+
consolidationTriggeredBy: triggeredBy,
|
|
162
|
+
},
|
|
163
|
+
// cleanupPolicy 用默认 on_next_launch:清 evolcore session 记录;日志目录由 cleanupPreviousConsolidationLogs() 负责
|
|
164
|
+
});
|
|
205
165
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
baseagent,
|
|
220
|
-
session,
|
|
221
|
-
causation: undefined,
|
|
222
|
-
}).catch((e) => {
|
|
223
|
-
logger.warn(`[Memory] 整理会话执行失败(mode=${mode},session=${session.id}): ${e?.message}`);
|
|
166
|
+
catch (error) {
|
|
167
|
+
if (claimedProcessing && memoryDir)
|
|
168
|
+
restorePendingNotes(memoryDir);
|
|
169
|
+
recordConsolidationOutcome(ctxFile.contextFilePath, `启动失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
// launch() 在会话创建后即返回,sessionId 立即可用;不等会话结束。
|
|
173
|
+
// 收尾由 bg-session:completed/error/interrupted 事件驱动,这里只记录异常结局。
|
|
174
|
+
const executionSessionId = handle.sessionId;
|
|
175
|
+
void handle.result.then(r => {
|
|
176
|
+
if (r.outcome !== 'completed') {
|
|
177
|
+
logger.warn(`[Memory] 整理会话未正常结束(mode=${mode},outcome=${r.outcome}): ${r.error ?? ''}`);
|
|
178
|
+
}
|
|
224
179
|
});
|
|
225
180
|
logger.info(`[Memory] 已拉起整理会话(mode=${mode},triggeredBy=${triggeredBy},` +
|
|
226
|
-
`selfAid=${selfAid}${effectiveCtx.peerKey ? `,peerKey=${effectiveCtx.peerKey}` : ''}
|
|
227
|
-
|
|
181
|
+
`selfAid=${selfAid}${effectiveCtx.peerKey ? `,peerKey=${effectiveCtx.peerKey}` : ''}` +
|
|
182
|
+
`${executionSessionId ? `,session=${executionSessionId}` : ''})`);
|
|
228
183
|
return {
|
|
229
184
|
triggerId,
|
|
230
185
|
contextFile: ctxFile.filePath,
|
|
231
186
|
contextFilePath: ctxFile.contextFilePath,
|
|
232
187
|
logFile: ctxFile.contextFilePath,
|
|
233
188
|
batchDir: ctxFile.batchDir,
|
|
234
|
-
executionSessionId
|
|
189
|
+
executionSessionId,
|
|
190
|
+
waitForAgentSessionId: handle.waitForAgentSessionId,
|
|
235
191
|
};
|
|
236
192
|
}
|
|
237
|
-
/**
|
|
238
|
-
* 手动 consolidate 用:在超时内轮询等 runner 分配 agentSessionId。
|
|
239
|
-
* 拿到立即返回;超时返回已拿到的部分,不抛错。
|
|
240
|
-
*
|
|
241
|
-
* 会话创建后 executionSessionId 立刻可用,但 agentSessionId 要等 runner 初始化
|
|
242
|
-
* 并开始第一轮才写入 session 记录,所以这里必须轮询等待。
|
|
243
|
-
*/
|
|
244
|
-
export async function waitForConsolidationSession(opts) {
|
|
245
|
-
const executionSessionId = opts.executionSessionId;
|
|
246
|
-
if (!executionSessionId)
|
|
247
|
-
return {};
|
|
248
|
-
const deadline = Date.now() + (opts.timeoutMs ?? 10_000);
|
|
249
|
-
const interval = opts.intervalMs ?? 250;
|
|
250
|
-
while (true) {
|
|
251
|
-
try {
|
|
252
|
-
const agentSessionId = await opts.readAgentSessionId(executionSessionId);
|
|
253
|
-
if (agentSessionId)
|
|
254
|
-
return { executionSessionId, agentSessionId };
|
|
255
|
-
}
|
|
256
|
-
catch { /* 会话记录写到一半,下一轮再读 */ }
|
|
257
|
-
if (Date.now() >= deadline)
|
|
258
|
-
return { executionSessionId };
|
|
259
|
-
await new Promise(r => setTimeout(r, interval));
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
193
|
/** 把 entry 移进 destDir;重名时加时间戳后缀,不覆盖已有文件。 */
|
|
263
194
|
function moveIntoDir(srcPath, destDir, stamp) {
|
|
264
195
|
const name = path.basename(srcPath);
|
|
@@ -276,6 +207,17 @@ function moveIntoDir(srcPath, destDir, stamp) {
|
|
|
276
207
|
}
|
|
277
208
|
fs.renameSync(srcPath, dest);
|
|
278
209
|
}
|
|
210
|
+
function restorePendingNotes(memoryDir) {
|
|
211
|
+
const processingDir = path.join(memoryDir, 'processing');
|
|
212
|
+
if (!fs.existsSync(processingDir))
|
|
213
|
+
return;
|
|
214
|
+
const pendingDir = path.join(memoryDir, 'pending');
|
|
215
|
+
fs.mkdirSync(pendingDir, { recursive: true });
|
|
216
|
+
const stamp = Date.now().toString(36);
|
|
217
|
+
for (const entry of fs.readdirSync(processingDir))
|
|
218
|
+
moveIntoDir(path.join(processingDir, entry), pendingDir, stamp);
|
|
219
|
+
fs.rmdirSync(processingDir);
|
|
220
|
+
}
|
|
279
221
|
/**
|
|
280
222
|
* 整理会话结束后的收尾,task:completed / task:error / task:interrupted 都走这里。
|
|
281
223
|
* - processing/ 里的 note:成功 → archive/notes/,失败 → 归还 pending/(下次重试)
|
|
@@ -306,9 +248,10 @@ export async function onConsolidationComplete(params) {
|
|
|
306
248
|
result.movedTo = noteDest;
|
|
307
249
|
}
|
|
308
250
|
}
|
|
309
|
-
|
|
251
|
+
// C3: update mode-specific checkpoint only when thread snapshots were used
|
|
252
|
+
if (params.success && params.chatDir && params.mode && params.usedThreadSnapshots) {
|
|
310
253
|
const { writeCheckpoint } = await import('./consolidation-context.js');
|
|
311
|
-
writeCheckpoint(params.chatDir, now);
|
|
254
|
+
writeCheckpoint(params.chatDir, params.snapshotThroughTs ?? now, params.mode, params.scopeOverride);
|
|
312
255
|
result.checkpointWritten = true;
|
|
313
256
|
}
|
|
314
257
|
const { summarizeOpsRecords, appendOpsRecord } = await import('./consolidation-ops-records.js');
|
|
@@ -396,6 +339,7 @@ export async function rollbackConsolidation(batchDir, selfAid) {
|
|
|
396
339
|
}
|
|
397
340
|
const MAX_CONCURRENT_CONSOLIDATION = 5;
|
|
398
341
|
export function createConsolidationSessionFinalizer({ sessionManager, getAgent, agentMap, releaseSlot, enqueueConsolidation, sendFeedback, }) {
|
|
342
|
+
const finalizedSessions = new Set();
|
|
399
343
|
return async (sessionId, success) => {
|
|
400
344
|
let releaseAid;
|
|
401
345
|
try {
|
|
@@ -408,6 +352,9 @@ export function createConsolidationSessionFinalizer({ sessionManager, getAgent,
|
|
|
408
352
|
const batchDir = (meta.consolidationBatchDir ?? meta.consolidationLogBase);
|
|
409
353
|
if (!batchDir)
|
|
410
354
|
return;
|
|
355
|
+
if (finalizedSessions.has(sessionId))
|
|
356
|
+
return;
|
|
357
|
+
finalizedSessions.add(sessionId);
|
|
411
358
|
releaseAid = session.selfAID;
|
|
412
359
|
const { summarizeOpsRecords, collectAffectedScopes } = await import('./consolidation-ops-records.js');
|
|
413
360
|
if (!success) {
|
|
@@ -418,6 +365,10 @@ export function createConsolidationSessionFinalizer({ sessionManager, getAgent,
|
|
|
418
365
|
batchDir,
|
|
419
366
|
chatDir: meta.consolidationChatDir,
|
|
420
367
|
memoryDir: meta.consolidationMemoryDir,
|
|
368
|
+
mode: meta.memoryMode,
|
|
369
|
+
scopeOverride: meta.memoryScope,
|
|
370
|
+
usedThreadSnapshots: meta.consolidationUsedThreadSnapshots === true,
|
|
371
|
+
snapshotThroughTs: meta.consolidationSnapshotThroughTs,
|
|
421
372
|
});
|
|
422
373
|
try {
|
|
423
374
|
const affectedScopes = collectAffectedScopes(batchDir);
|
|
@@ -537,8 +488,8 @@ export function createConsolidationSessionFinalizer({ sessionManager, getAgent,
|
|
|
537
488
|
logger.warn(`[Memory] 整理收尾失败(session=${sessionId}): ${error?.message}`);
|
|
538
489
|
}
|
|
539
490
|
finally {
|
|
540
|
-
if (releaseAid)
|
|
541
|
-
releaseSlot(releaseAid);
|
|
491
|
+
if (releaseAid && sessionId)
|
|
492
|
+
releaseSlot(releaseAid, sessionId);
|
|
542
493
|
}
|
|
543
494
|
};
|
|
544
495
|
}
|
|
@@ -583,28 +534,43 @@ export function registerConsolidationSessionEvents({ eventBus, permissionGateway
|
|
|
583
534
|
if ('sessionId' in event && event.sessionId) {
|
|
584
535
|
permissionGateway.cancelAll(event.sessionId, event.reason || 'interrupted');
|
|
585
536
|
}
|
|
586
|
-
void finalize(event.sessionId, false);
|
|
587
537
|
});
|
|
588
538
|
eventBus.subscribe('task:error', event => {
|
|
589
539
|
if ('sessionId' in event && event.sessionId) {
|
|
590
540
|
permissionGateway.cancelAll(event.sessionId, 'task_error', false);
|
|
591
541
|
}
|
|
592
|
-
void finalize(event.sessionId, false);
|
|
593
542
|
});
|
|
594
543
|
eventBus.subscribe('task:completed', event => {
|
|
595
544
|
if ('sessionId' in event && event.sessionId) {
|
|
596
545
|
permissionGateway.cancelAll(event.sessionId, 'task_completed', false);
|
|
597
546
|
}
|
|
598
|
-
|
|
547
|
+
});
|
|
548
|
+
eventBus.subscribe('bg-session:completed', event => {
|
|
549
|
+
if (event.type === 'bg-session:completed')
|
|
550
|
+
void finalize(event.sessionId, true);
|
|
551
|
+
});
|
|
552
|
+
eventBus.subscribe('bg-session:error', event => {
|
|
553
|
+
if (event.type === 'bg-session:error')
|
|
554
|
+
void finalize(event.sessionId, false);
|
|
555
|
+
});
|
|
556
|
+
eventBus.subscribe('bg-session:interrupted', event => {
|
|
557
|
+
if (event.type === 'bg-session:interrupted')
|
|
558
|
+
void finalize(event.sessionId, false);
|
|
599
559
|
});
|
|
600
560
|
}
|
|
601
561
|
export class ConsolidationQueue {
|
|
602
562
|
daemonChannel;
|
|
603
563
|
activeAgents = new Set();
|
|
604
564
|
queues = new Map();
|
|
565
|
+
activeSessions = new Map();
|
|
566
|
+
timers = new Map();
|
|
567
|
+
finalizer;
|
|
605
568
|
constructor(daemonChannel) {
|
|
606
569
|
this.daemonChannel = daemonChannel;
|
|
607
570
|
}
|
|
571
|
+
setFinalizer(finalizer) {
|
|
572
|
+
this.finalizer = finalizer;
|
|
573
|
+
}
|
|
608
574
|
async enqueue(params) {
|
|
609
575
|
const aid = params.taskCtx.selfAid;
|
|
610
576
|
if (!aid)
|
|
@@ -619,9 +585,30 @@ export class ConsolidationQueue {
|
|
|
619
585
|
this.queues.set(aid, queue);
|
|
620
586
|
logger.info(`[Memory] 整理请求入队(aid=${aid},mode=${params.mode},` +
|
|
621
587
|
`队列长度=${queue.length},全局活跃=${this.activeAgents.size})`);
|
|
622
|
-
return
|
|
588
|
+
return {
|
|
589
|
+
triggerId: '',
|
|
590
|
+
contextFile: '',
|
|
591
|
+
contextFilePath: '',
|
|
592
|
+
batchDir: '',
|
|
593
|
+
queued: {
|
|
594
|
+
position: queue.length,
|
|
595
|
+
agentQueueLength: queue.length,
|
|
596
|
+
agentBusy,
|
|
597
|
+
activeCount: this.activeAgents.size,
|
|
598
|
+
maxConcurrent: MAX_CONCURRENT_CONSOLIDATION,
|
|
599
|
+
totalQueued: [...this.queues.values()].reduce((total, pending) => total + pending.length, 0),
|
|
600
|
+
},
|
|
601
|
+
};
|
|
623
602
|
}
|
|
624
|
-
release(aid) {
|
|
603
|
+
release(aid, sessionId) {
|
|
604
|
+
const activeSessionId = this.activeSessions.get(aid);
|
|
605
|
+
if (sessionId && activeSessionId !== undefined && activeSessionId !== sessionId)
|
|
606
|
+
return;
|
|
607
|
+
const timer = this.timers.get(aid);
|
|
608
|
+
if (timer)
|
|
609
|
+
clearTimeout(timer);
|
|
610
|
+
this.timers.delete(aid);
|
|
611
|
+
this.activeSessions.delete(aid);
|
|
625
612
|
this.activeAgents.delete(aid);
|
|
626
613
|
void this.drain();
|
|
627
614
|
}
|
|
@@ -631,7 +618,30 @@ export class ConsolidationQueue {
|
|
|
631
618
|
return null;
|
|
632
619
|
this.activeAgents.add(aid);
|
|
633
620
|
try {
|
|
634
|
-
|
|
621
|
+
const launched = await launchConsolidation(this.daemonChannel, params);
|
|
622
|
+
if (launched.executionSessionId) {
|
|
623
|
+
const sessionId = launched.executionSessionId;
|
|
624
|
+
this.activeSessions.set(aid, sessionId);
|
|
625
|
+
const timer = setTimeout(() => {
|
|
626
|
+
if (this.activeSessions.get(aid) !== sessionId)
|
|
627
|
+
return;
|
|
628
|
+
logger.warn(`[Memory] 整理会话超时收尾(aid=${aid},session=${sessionId})`);
|
|
629
|
+
if (this.finalizer)
|
|
630
|
+
void this.finalizer(sessionId, false).finally(() => this.release(aid, sessionId));
|
|
631
|
+
else
|
|
632
|
+
this.release(aid, sessionId);
|
|
633
|
+
}, 15 * 60_000);
|
|
634
|
+
timer.unref?.();
|
|
635
|
+
this.timers.set(aid, timer);
|
|
636
|
+
}
|
|
637
|
+
appendOpsRecord(launched.batchDir, {
|
|
638
|
+
ts: new Date().toISOString(),
|
|
639
|
+
op: 'session-start',
|
|
640
|
+
sessionId: launched.executionSessionId ?? launched.triggerId,
|
|
641
|
+
mode: params.mode,
|
|
642
|
+
triggeredBy: params.triggeredBy,
|
|
643
|
+
});
|
|
644
|
+
return launched;
|
|
635
645
|
}
|
|
636
646
|
catch (error) {
|
|
637
647
|
logger.warn(`[Memory] 拉起整理会话失败(aid=${aid},mode=${params.mode}): ${error?.message}`);
|
|
@@ -659,33 +669,17 @@ export class ConsolidationQueue {
|
|
|
659
669
|
}
|
|
660
670
|
}
|
|
661
671
|
}
|
|
662
|
-
export function registerConsolidationLaunchExecutor({ ipcServer,
|
|
672
|
+
export function registerConsolidationLaunchExecutor({ ipcServer, enqueueConsolidation, }) {
|
|
663
673
|
ipcServer.setConsolidationLaunchExecutor(async (params) => {
|
|
664
674
|
if (!params.taskCtx.selfAid)
|
|
665
675
|
throw new Error('无法确定当前 agent AID(selfAid 为空)');
|
|
666
676
|
const launched = await enqueueConsolidation(params);
|
|
667
|
-
if (!launched)
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
batchDir: '',
|
|
674
|
-
queued: true,
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
appendOpsRecord(launched.batchDir, {
|
|
678
|
-
ts: new Date().toISOString(),
|
|
679
|
-
op: 'session-start',
|
|
680
|
-
sessionId: launched.triggerId,
|
|
681
|
-
mode: params.mode,
|
|
682
|
-
triggeredBy: params.triggeredBy,
|
|
683
|
-
});
|
|
684
|
-
const ids = await waitForConsolidationSession({
|
|
685
|
-
executionSessionId: launched.executionSessionId,
|
|
686
|
-
readAgentSessionId: async (id) => (await sessionManager.getSessionById(id))?.agentSessionId,
|
|
687
|
-
});
|
|
688
|
-
return { ...launched, ...ids };
|
|
677
|
+
if (!launched)
|
|
678
|
+
throw new Error('拉起整理会话失败,详见 daemon 日志');
|
|
679
|
+
if (launched.queued)
|
|
680
|
+
return launched;
|
|
681
|
+
const { waitForAgentSessionId, ...result } = launched;
|
|
682
|
+
return result;
|
|
689
683
|
});
|
|
690
684
|
}
|
|
691
685
|
export function registerConsolidationCheckExecutor({ ipcServer, agentRegistry, enqueueConsolidation, }) {
|