aws-runtime-bridge 1.9.21 → 1.9.30
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/dist/adapter/AcodeSdkAdapter.d.ts +3 -0
- package/dist/adapter/AcodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/AcodeSdkAdapter.js +9 -0
- package/dist/adapter/OpencodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/OpencodeSdkAdapter.js +11 -3
- package/dist/adapter/types.d.ts +6 -0
- package/dist/adapter/types.d.ts.map +1 -1
- package/dist/routes/git.d.ts +42 -2
- package/dist/routes/git.d.ts.map +1 -1
- package/dist/routes/git.js +580 -61
- package/dist/routes/git.test.js +171 -6
- package/dist/routes/terminal.d.ts.map +1 -1
- package/dist/routes/terminal.js +175 -0
- package/package/acode/dist/runtime.d.ts.map +1 -1
- package/package/acode/dist/runtime.js +19 -5
- package/package/acode/dist/types.d.ts +6 -0
- package/package/acode/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +6 -0
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.js +15 -0
- package/package/aws-client-agent-mcp/dist/agent-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/context-manager.test.js +4 -1
- package/package/aws-client-agent-mcp/dist/context-manager.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +69 -6
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.js +374 -105
- package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +12 -3
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +17 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +44 -8
- package/package/aws-client-agent-mcp/dist/mcp-tools.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/memory-store.d.ts +49 -2
- package/package/aws-client-agent-mcp/dist/memory-store.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/memory-store.js +116 -14
- package/package/aws-client-agent-mcp/dist/memory-store.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/memory-store.test.js +82 -5
- package/package/aws-client-agent-mcp/dist/memory-store.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/memory-tools.d.ts +11 -1
- package/package/aws-client-agent-mcp/dist/memory-tools.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/memory-tools.js +37 -11
- package/package/aws-client-agent-mcp/dist/memory-tools.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts +10 -1
- package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/server-memory-store.js +16 -4
- package/package/aws-client-agent-mcp/dist/server-memory-store.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/status-reporter.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/status-reporter.js +0 -1
- package/package/aws-client-agent-mcp/dist/status-reporter.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +9 -0
- package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -30,6 +30,13 @@ const DEFAULT_POLL_MESSAGE_BLOCK_WAIT_MS = 240_000;
|
|
|
30
30
|
const POLL_MESSAGE_LONGPOLL_HTTP_TIMEOUT_MS = 600_000;
|
|
31
31
|
const DEFAULT_MCP_HTTP_REQUEST_TIMEOUT_MS = 120_000;
|
|
32
32
|
const POLL_MESSAGE_HTTP_TIMEOUT_BUFFER_MS = 1_000;
|
|
33
|
+
/**
|
|
34
|
+
* poll_message 内部轮询间隔:每 30 秒在永久阻塞的 poll_message 中醒来一次,
|
|
35
|
+
* 检查 WebSocket 缓冲区、Memory 通知(文件变更/TODO/容量等)。
|
|
36
|
+
* 能主动通知的消息(WebSocket)实时响应,无法主动通知的状态变化最长 30s 延迟。
|
|
37
|
+
* poll_message 永不超时返回空,只在有消息可返回时才退出。
|
|
38
|
+
*/
|
|
39
|
+
const POLL_MESSAGE_INTERNAL_POLL_INTERVAL_MS = 30_000;
|
|
33
40
|
const DEFAULT_MEMORY_FILE_CHECK_INTERVAL_MS = 5_000;
|
|
34
41
|
const PATH_UNSAFE_CHARACTERS = new Set([
|
|
35
42
|
"<",
|
|
@@ -51,6 +58,8 @@ export class McpServer {
|
|
|
51
58
|
sessionContextMemoryStore;
|
|
52
59
|
memoryStoresShareFile;
|
|
53
60
|
initialRoleName = "";
|
|
61
|
+
/** 是否有真实的角色名(非 env 空值 fallback "default-role") */
|
|
62
|
+
hasRoleName = false;
|
|
54
63
|
/** 上下文管理器 (v1.8.0) */
|
|
55
64
|
contextManager;
|
|
56
65
|
/**
|
|
@@ -68,6 +77,16 @@ export class McpServer {
|
|
|
68
77
|
listableMd5Cache = new Map();
|
|
69
78
|
/** 后台 Memory 文件变更检测定时器 (v1.9.0) */
|
|
70
79
|
memoryFileCheckInterval = null;
|
|
80
|
+
/**
|
|
81
|
+
* Memory 通知 null 结果缓存:key → expiresAt 时间戳。
|
|
82
|
+
* 仅缓存 null(无通知)结果,避免 while(true) 每 30s 重复读盘。
|
|
83
|
+
* 有通知时立即投递并清除缓存,不缓存非 null 结果。
|
|
84
|
+
*/
|
|
85
|
+
memoryNotificationNullCache = new Map();
|
|
86
|
+
static MEMORY_NOTIFICATION_NULL_TTL_MS = 60_000;
|
|
87
|
+
// 系统提示词由 runtime adapter(ACode/OpenCode/Codex/Claude)在会话创建时注入,
|
|
88
|
+
// 无需通过 MCP 工具返回。三方 runtime(OpenCode/Claude)将三层提示词合并为一条 system prompt,
|
|
89
|
+
// ACode 则直接注入为前三条 system role 消息。
|
|
71
90
|
/**
|
|
72
91
|
* 收到 Profile 后同步角色存储路径。
|
|
73
92
|
* 当服务端返回的 roleName 与进程初始化时不一致时,重建 roleMemoryStore 指向正确的目录。
|
|
@@ -77,6 +96,7 @@ export class McpServer {
|
|
|
77
96
|
return;
|
|
78
97
|
}
|
|
79
98
|
const expectedRoleDir = McpServer.sanitizeRoleDirectoryName(profile.roleName);
|
|
99
|
+
this.hasRoleName = true; // Profile 确认了角色名
|
|
80
100
|
if (expectedRoleDir === this.initialRoleName) {
|
|
81
101
|
return;
|
|
82
102
|
}
|
|
@@ -182,6 +202,7 @@ export class McpServer {
|
|
|
182
202
|
this.agentClient = new AgentClient();
|
|
183
203
|
this.messageBuffer = new MessageBuffer();
|
|
184
204
|
this.initialRoleName = McpServer.resolveRoleMemoryDirectoryName();
|
|
205
|
+
this.hasRoleName = !!process.env.AWS_ROLE_NAME; // 只有明确设置了 env 才认为有角色名
|
|
185
206
|
const memoryStorePaths = McpServer.resolveMemoryStorePaths();
|
|
186
207
|
this.memoryStore = new ServerMemoryStore(this.agentClient);
|
|
187
208
|
this.roleMemoryStore = new MemoryStore(memoryStorePaths.rolePath);
|
|
@@ -322,8 +343,6 @@ export class McpServer {
|
|
|
322
343
|
return await this.handleListMemories(args);
|
|
323
344
|
case "get_memory_stats":
|
|
324
345
|
return await this.handleGetMemoryStats(args);
|
|
325
|
-
case "remove_task_list_memory":
|
|
326
|
-
return await this.handleRemoveTaskListMemory(args);
|
|
327
346
|
case "archive_recently_memory":
|
|
328
347
|
return await this.handleArchiveRecentlyMemory(args);
|
|
329
348
|
// Memory 增强功能工具 (v1.6.0)
|
|
@@ -331,6 +350,11 @@ export class McpServer {
|
|
|
331
350
|
return await this.handleListMemoriesByFile(args);
|
|
332
351
|
case "abandon_memory_update":
|
|
333
352
|
return await this.handleAbandonMemoryUpdate(args);
|
|
353
|
+
// Memory 近期记忆过期与回忆工具 (v1.11.0)
|
|
354
|
+
case "memory_recurrence":
|
|
355
|
+
return await this.handleMemoryRecurrence();
|
|
356
|
+
case "memory_recurrence_complete":
|
|
357
|
+
return await this.handleMemoryRecurrenceComplete();
|
|
334
358
|
// 上下文压缩工具 (v1.8.0)
|
|
335
359
|
case "get_context_stats":
|
|
336
360
|
return await this.handleGetContextStats(args);
|
|
@@ -355,11 +379,13 @@ export class McpServer {
|
|
|
355
379
|
"search_memory",
|
|
356
380
|
"list_memories",
|
|
357
381
|
"get_memory_stats",
|
|
358
|
-
"remove_task_list_memory",
|
|
359
382
|
"archive_recently_memory",
|
|
360
383
|
// Memory 增强功能工具 (v1.6.0)
|
|
361
384
|
"list_memories_by_file",
|
|
362
385
|
"abandon_memory_update",
|
|
386
|
+
// Memory 近期记忆过期与回忆工具 (v1.11.0)
|
|
387
|
+
"memory_recurrence",
|
|
388
|
+
"memory_recurrence_complete",
|
|
363
389
|
]);
|
|
364
390
|
/**
|
|
365
391
|
* 从 startPath 向上逐级查找 .agentswork 目录。
|
|
@@ -468,8 +494,17 @@ export class McpServer {
|
|
|
468
494
|
* 按记忆生命周期选择存储作用域。
|
|
469
495
|
* 主流程:长期 memory 走角色级 store;task_list/recently_memory 走当前 Agent 实例级 store。
|
|
470
496
|
*/
|
|
497
|
+
/**
|
|
498
|
+
* 按记忆生命周期选择存储作用域。
|
|
499
|
+
* 主流程:永久记忆(memory)仅在 hasRoleName 为 true 时走角色级 store,
|
|
500
|
+
* 否则回退到实例级 server store(避免空角色名下所有实例共享 default-role 目录导致跨角色污染)。
|
|
501
|
+
* task_list/recently_memory/session_context 始终走实例级 store。
|
|
502
|
+
*/
|
|
471
503
|
getMemoryStoreForType(memoryType) {
|
|
472
|
-
|
|
504
|
+
if (memoryType === "memory" && this.hasRoleName) {
|
|
505
|
+
return this.roleMemoryStore;
|
|
506
|
+
}
|
|
507
|
+
return this.memoryStore;
|
|
473
508
|
}
|
|
474
509
|
/**
|
|
475
510
|
* 在未显式指定类型时按两个作用域读取。
|
|
@@ -482,12 +517,15 @@ export class McpServer {
|
|
|
482
517
|
if (input.memory_type) {
|
|
483
518
|
return await this.getMemoryStoreForType(input.memory_type).readMemory(input);
|
|
484
519
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
520
|
+
// hasRoleName 为 false 时不查 roleMemoryStore,避免空角色名共享 default-role 目录
|
|
521
|
+
if (this.hasRoleName) {
|
|
522
|
+
const longTermRecord = await this.roleMemoryStore.readMemory({
|
|
523
|
+
...input,
|
|
524
|
+
memory_type: "memory",
|
|
525
|
+
});
|
|
526
|
+
if (longTermRecord) {
|
|
527
|
+
return longTermRecord;
|
|
528
|
+
}
|
|
491
529
|
}
|
|
492
530
|
return await this.memoryStore.readMemory(input);
|
|
493
531
|
}
|
|
@@ -505,12 +543,14 @@ export class McpServer {
|
|
|
505
543
|
memory_type: input.memory_type,
|
|
506
544
|
};
|
|
507
545
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
546
|
+
if (this.hasRoleName) {
|
|
547
|
+
const longTermRecord = await this.roleMemoryStore.readMemory({
|
|
548
|
+
uri: input.uri,
|
|
549
|
+
memory_type: "memory",
|
|
550
|
+
});
|
|
551
|
+
if (longTermRecord) {
|
|
552
|
+
return { store: this.roleMemoryStore, memory_type: "memory" };
|
|
553
|
+
}
|
|
514
554
|
}
|
|
515
555
|
return { store: this.memoryStore };
|
|
516
556
|
}
|
|
@@ -522,15 +562,23 @@ export class McpServer {
|
|
|
522
562
|
if (this.memoryStoresShareFile) {
|
|
523
563
|
return instanceStats;
|
|
524
564
|
}
|
|
565
|
+
// 服务端 now 也按角色级返回永久记忆统计(同角色实例共享),
|
|
566
|
+
// 本地 roleMemoryStore 也可能有尚未同步到服务端的记录。
|
|
567
|
+
// permanentCount 取两者的较大值作为保守估计(下界)。
|
|
568
|
+
// 注意: 当 instance 和 role 分别有对方没有的唯一 URI 时,实际并集 > Math.max,
|
|
569
|
+
// 但此处只有 count 无 URI 列表,无法精确计算并集,使用下界避免面板显示虚高。
|
|
570
|
+
const permanentCount = Math.max(instanceStats.by_type.memory.count, roleStats.by_type.memory.count);
|
|
571
|
+
// total 同样保守估算:用 server 非 memory count + permanentCount 下界
|
|
572
|
+
const serverNonMemoryTotal = instanceStats.total - instanceStats.by_type.memory.count;
|
|
525
573
|
return {
|
|
526
|
-
total:
|
|
574
|
+
total: serverNonMemoryTotal + permanentCount,
|
|
527
575
|
listable: instanceStats.listable,
|
|
528
576
|
by_type: {
|
|
529
577
|
task_list: instanceStats.by_type.task_list,
|
|
530
578
|
recently_memory: instanceStats.by_type.recently_memory,
|
|
531
579
|
memory: {
|
|
532
580
|
...roleStats.by_type.memory,
|
|
533
|
-
count:
|
|
581
|
+
count: permanentCount,
|
|
534
582
|
},
|
|
535
583
|
session_context: instanceStats.by_type.session_context,
|
|
536
584
|
},
|
|
@@ -541,12 +589,12 @@ export class McpServer {
|
|
|
541
589
|
* 主流程:读取实例级与角色级统计 -> 合并长期 memory count -> 通过 server 广播给 Dashboard。
|
|
542
590
|
*/
|
|
543
591
|
async reportCombinedMemoryStats() {
|
|
544
|
-
const
|
|
545
|
-
|
|
546
|
-
this.roleMemoryStore.getStats()
|
|
547
|
-
|
|
592
|
+
const instanceStats = await this.memoryStore.getStats();
|
|
593
|
+
const mergedStats = this.hasRoleName
|
|
594
|
+
? this.combineMemoryStats(instanceStats, await this.roleMemoryStore.getStats())
|
|
595
|
+
: instanceStats;
|
|
548
596
|
try {
|
|
549
|
-
await this.agentClient.reportMemoryStats(
|
|
597
|
+
await this.agentClient.reportMemoryStats(mergedStats);
|
|
550
598
|
}
|
|
551
599
|
catch (error) {
|
|
552
600
|
logger.warn("[McpServer] 上报合并 memory 统计失败,已保留本地记忆写入结果:", error);
|
|
@@ -557,6 +605,8 @@ export class McpServer {
|
|
|
557
605
|
* 主流程:读取本地 roleMemoryStore 中所有 memory 类型记录 -> 逐条写入服务端 memoryStore -> 已存在的记录静默跳过。
|
|
558
606
|
*/
|
|
559
607
|
async syncLocalPermanentMemoryToServer() {
|
|
608
|
+
if (!this.hasRoleName)
|
|
609
|
+
return;
|
|
560
610
|
try {
|
|
561
611
|
const memories = await this.roleMemoryStore.listByType("memory");
|
|
562
612
|
if (memories.length === 0)
|
|
@@ -588,6 +638,14 @@ export class McpServer {
|
|
|
588
638
|
logger.error("[McpServer] Failed to sync permanent memories to server:", error);
|
|
589
639
|
}
|
|
590
640
|
}
|
|
641
|
+
/**
|
|
642
|
+
* 系统提示词由 runtime adapter 在会话创建时注入,MCP 层面不再负责返回。
|
|
643
|
+
* 详见 startListeningInternal -> profileHandler 中的合并注入逻辑。
|
|
644
|
+
*
|
|
645
|
+
* @deprecated 启动记忆不再通过 MCP 的 systemMessages 返回。
|
|
646
|
+
* 三方 runtime(OpenCode/Claude)在 adapter 层将三层提示词合并为一条 system prompt;
|
|
647
|
+
* ACode 则直接注入为前三条 system role 消息。
|
|
648
|
+
*/
|
|
591
649
|
/**
|
|
592
650
|
* 生成安全的工具状态上报参数。
|
|
593
651
|
* 主流程:memory 工具只上报元数据,避免 content/query/old_string/new_string/append 离开本地记忆边界。
|
|
@@ -657,6 +715,8 @@ export class McpServer {
|
|
|
657
715
|
logger.warn("[McpServer] Failed to sync permanent memory to server:", e);
|
|
658
716
|
}
|
|
659
717
|
}
|
|
718
|
+
// v1.13.0: recently_memory 过期判定、task_list todo 状态由服务端 memory_status 字段管理,
|
|
719
|
+
// 无需 TS 侧本地缓存。服务端默认按类型填充正确状态(recently_memory='normal', task_list='pending')。
|
|
660
720
|
return this.toMemoryWriteResult(created);
|
|
661
721
|
}
|
|
662
722
|
/**
|
|
@@ -743,6 +803,12 @@ export class McpServer {
|
|
|
743
803
|
logger.warn("[McpServer] Failed to sync permanent memory update to server:", e);
|
|
744
804
|
}
|
|
745
805
|
}
|
|
806
|
+
// v1.13.0: task_list TODO 状态、recently_memory 过期与回忆状态均由服务端 memory_status 字段管理。
|
|
807
|
+
// 显式传入的 todo_status / recall_status / memory_status 已在 updateMemory 内部透传到服务端。
|
|
808
|
+
// 服务端会自动处理"所有 TODO 已完成时清理全部已完成项"的逻辑(见 AgentMemoryService.updateMemory)。
|
|
809
|
+
// 内容变更对 recently_memory 的"续期"语义现在由过期判定基于 created_at 决定,
|
|
810
|
+
// update_memory 内容变更不会重置 created_at,因此"续期"实际对应"修改 created_at" — 当前不提供该能力,
|
|
811
|
+
// 如需续期建议使用 archive_recently_memory 归档或重新 createMemory 替代。
|
|
746
812
|
return this.toMemoryWriteResult(updated);
|
|
747
813
|
}
|
|
748
814
|
/**
|
|
@@ -755,14 +821,17 @@ export class McpServer {
|
|
|
755
821
|
memory_type: this.getOptionalMemoryType(args),
|
|
756
822
|
};
|
|
757
823
|
const target = await this.findMemoryStoreForMutation(input);
|
|
824
|
+
const effectiveType = target.memory_type ?? input.memory_type;
|
|
758
825
|
const deleted = await target.store.deleteMemory({
|
|
759
826
|
...input,
|
|
760
|
-
memory_type:
|
|
827
|
+
memory_type: effectiveType,
|
|
761
828
|
});
|
|
762
829
|
if (deleted) {
|
|
763
830
|
await this.reportCombinedMemoryStats();
|
|
831
|
+
// v1.13.0: 服务端 deleteMemory 内部已处理"task_list 删除后清空 completed 残留"逻辑,
|
|
832
|
+
// TS 侧无需任何本地元数据清理。
|
|
764
833
|
// Dual-write permanent memory delete to server
|
|
765
|
-
if (
|
|
834
|
+
if (effectiveType === "memory") {
|
|
766
835
|
try {
|
|
767
836
|
await this.memoryStore
|
|
768
837
|
.deleteMemory({ uri: input.uri, memory_type: "memory" })
|
|
@@ -821,6 +890,10 @@ export class McpServer {
|
|
|
821
890
|
if (this.memoryStoresShareFile) {
|
|
822
891
|
return await this.memoryStore.searchMemory(input);
|
|
823
892
|
}
|
|
893
|
+
// 无角色名时不查询 roleMemoryStore(避免 default-role 共享目录导致跨角色污染)
|
|
894
|
+
if (!this.hasRoleName) {
|
|
895
|
+
return await this.memoryStore.searchMemory(input);
|
|
896
|
+
}
|
|
824
897
|
const [roleResult, instanceResult] = await Promise.all([
|
|
825
898
|
this.roleMemoryStore.searchMemory({ ...input, memory_type: "memory" }),
|
|
826
899
|
this.memoryStore.searchMemory(input),
|
|
@@ -872,11 +945,10 @@ export class McpServer {
|
|
|
872
945
|
* 主流程:读取 MemoryStore 统计结果,供 Agent 在创建前判断 listable/type 容量。
|
|
873
946
|
*/
|
|
874
947
|
async handleGetMemoryStats(args) {
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
this.roleMemoryStore.getStats()
|
|
878
|
-
|
|
879
|
-
const stats = this.combineMemoryStats(instanceStats, roleStats);
|
|
948
|
+
const instanceStats = await this.memoryStore.getStats();
|
|
949
|
+
const stats = this.hasRoleName
|
|
950
|
+
? this.combineMemoryStats(instanceStats, await this.roleMemoryStore.getStats())
|
|
951
|
+
: instanceStats;
|
|
880
952
|
const memoryType = this.getOptionalMemoryType(args);
|
|
881
953
|
if (!memoryType) {
|
|
882
954
|
return stats;
|
|
@@ -889,14 +961,6 @@ export class McpServer {
|
|
|
889
961
|
},
|
|
890
962
|
};
|
|
891
963
|
}
|
|
892
|
-
/**
|
|
893
|
-
* 移除任务清单记忆。
|
|
894
|
-
* 主流程:按 uri 读取并校验 task_list 类型后删除,避免误删长期记忆。
|
|
895
|
-
*/
|
|
896
|
-
async handleRemoveTaskListMemory(args) {
|
|
897
|
-
const removed = await this.memoryStore.removeTaskListMemory(this.getRequiredString(args, "uri"));
|
|
898
|
-
return { removed };
|
|
899
|
-
}
|
|
900
964
|
/**
|
|
901
965
|
* 归档近期记忆。
|
|
902
966
|
* 主流程:将 recently_memory 原地转换为长期 memory,并递增版本号。
|
|
@@ -913,7 +977,7 @@ export class McpServer {
|
|
|
913
977
|
if (!record) {
|
|
914
978
|
throw new Error(`Memory not found: ${uri}`);
|
|
915
979
|
}
|
|
916
|
-
const archived = await this.
|
|
980
|
+
const archived = await this.getMemoryStoreForType("memory").createMemory({
|
|
917
981
|
memory_type: "memory",
|
|
918
982
|
uri: record.uri,
|
|
919
983
|
title: record.title,
|
|
@@ -993,8 +1057,8 @@ export class McpServer {
|
|
|
993
1057
|
memory_type: memoryType,
|
|
994
1058
|
});
|
|
995
1059
|
let localResult = [];
|
|
996
|
-
// 补充查询本地永久记忆(server
|
|
997
|
-
if (!memoryType || memoryType === "memory") {
|
|
1060
|
+
// 补充查询本地永久记忆(server 可能未同步);无角色名时跳过(避免 default-role 跨角色污染)
|
|
1061
|
+
if (this.hasRoleName && (!memoryType || memoryType === "memory")) {
|
|
998
1062
|
localResult = await this.roleMemoryStore.listByFile(filePath, "memory");
|
|
999
1063
|
}
|
|
1000
1064
|
// 去重合并
|
|
@@ -1031,6 +1095,74 @@ export class McpServer {
|
|
|
1031
1095
|
message: "Memory 更新状态已清除",
|
|
1032
1096
|
};
|
|
1033
1097
|
}
|
|
1098
|
+
// ============ Memory 近期记忆过期与回忆工具处理 (v1.11.0 / v1.13.0) ============
|
|
1099
|
+
// v1.13.0: 过期判定与 recalling 状态标记已统一迁移到服务端 memory_status 字段,
|
|
1100
|
+
// 下方两个工具方法直接调用服务端接口,不再依赖任何本地元数据。
|
|
1101
|
+
/**
|
|
1102
|
+
* 处理 memory_recurrence 工具调用。
|
|
1103
|
+
* 主流程:调用服务端 list_expired_memories 拉取已过期 recently_memory ->
|
|
1104
|
+
* 批量调用 mark_expired_memories_recalling 把这些记录标记为「回忆中」状态 -> 返回过期记忆列表。
|
|
1105
|
+
*/
|
|
1106
|
+
async handleMemoryRecurrence() {
|
|
1107
|
+
// v1.13.0: 过期判定与 recalling 状态全部由服务端管理
|
|
1108
|
+
const expiredMemories = await this.memoryStore.listExpiredRecentlyMemories();
|
|
1109
|
+
if (expiredMemories.length === 0) {
|
|
1110
|
+
return {
|
|
1111
|
+
memories: [],
|
|
1112
|
+
count: 0,
|
|
1113
|
+
message: "没有待回忆的即将遗忘记忆。",
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
// 标记所有过期记忆为 recalling 状态(服务端)
|
|
1117
|
+
try {
|
|
1118
|
+
await this.memoryStore.markExpiredMemoriesRecalling();
|
|
1119
|
+
}
|
|
1120
|
+
catch (e) {
|
|
1121
|
+
logger.warn("[McpServer] 标记过期记忆为 recalling 失败:", e);
|
|
1122
|
+
}
|
|
1123
|
+
// 返回过期记忆的摘要(不含完整 content 以减少上下文占用)
|
|
1124
|
+
const memorySummaries = expiredMemories.map(m => ({
|
|
1125
|
+
uri: m.uri,
|
|
1126
|
+
title: m.title,
|
|
1127
|
+
domain: m.domain,
|
|
1128
|
+
path: m.path,
|
|
1129
|
+
recall_status: 'recalling',
|
|
1130
|
+
memory_status: 'recalling',
|
|
1131
|
+
contentPreview: m.content && m.content.length > 200 ? m.content.substring(0, 200) + '...' : m.content,
|
|
1132
|
+
createdAt: m.createdAt,
|
|
1133
|
+
updatedAt: m.updatedAt,
|
|
1134
|
+
}));
|
|
1135
|
+
return {
|
|
1136
|
+
memories: memorySummaries,
|
|
1137
|
+
count: expiredMemories.length,
|
|
1138
|
+
message: `发现 ${expiredMemories.length} 条即将遗忘的近期记忆。请审查后决定:\n` +
|
|
1139
|
+
`1) 使用 archive_recently_memory 归档为长期记忆\n` +
|
|
1140
|
+
`2) 完成审查后调用 memory_recurrence_complete 进行清理`,
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* 处理 memory_recurrence_complete 工具调用。
|
|
1145
|
+
* 主流程:调用服务端 clear_recalling_expired_memories 删除所有「recalling + 已过期」记录。
|
|
1146
|
+
*/
|
|
1147
|
+
async handleMemoryRecurrenceComplete() {
|
|
1148
|
+
// v1.13.0: 删除操作由服务端完成
|
|
1149
|
+
let result = { deleted: 0, uris: [] };
|
|
1150
|
+
try {
|
|
1151
|
+
result = await this.memoryStore.clearRecallingExpiredMemories();
|
|
1152
|
+
}
|
|
1153
|
+
catch (e) {
|
|
1154
|
+
logger.warn("[McpServer] 清理回忆中记忆失败:", e);
|
|
1155
|
+
}
|
|
1156
|
+
await this.reportCombinedMemoryStats();
|
|
1157
|
+
const deletedCount = result.deleted ?? 0;
|
|
1158
|
+
return {
|
|
1159
|
+
deleted: deletedCount,
|
|
1160
|
+
uris: result.uris ?? [],
|
|
1161
|
+
message: deletedCount === 0
|
|
1162
|
+
? "没有待疏理的回忆中记忆。"
|
|
1163
|
+
: `已清理 ${deletedCount} 条已过期近期记忆。`,
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
1034
1166
|
// ============ 上下文压缩工具处理 (v1.8.0) ============
|
|
1035
1167
|
/**
|
|
1036
1168
|
* 获取当前会话的上下文统计。
|
|
@@ -1189,78 +1321,118 @@ export class McpServer {
|
|
|
1189
1321
|
content,
|
|
1190
1322
|
});
|
|
1191
1323
|
}
|
|
1324
|
+
/**
|
|
1325
|
+
* 构建内存通知并前置到消息列表。
|
|
1326
|
+
* @returns 若生成了通知并已前置,返回 true;否则返回 false。
|
|
1327
|
+
*/
|
|
1328
|
+
async prependMemoryNotification(messages, buildFn) {
|
|
1329
|
+
const notification = await buildFn();
|
|
1330
|
+
if (notification) {
|
|
1331
|
+
messages.directMessages.unshift(notification);
|
|
1332
|
+
return true;
|
|
1333
|
+
}
|
|
1334
|
+
return false;
|
|
1335
|
+
}
|
|
1336
|
+
/**
|
|
1337
|
+
* 带 null 结果缓存的 Memory 通知构建。
|
|
1338
|
+
* 主流程:查缓存 → 命中且未过期则返回 null → 未命中则调 buildFn →
|
|
1339
|
+
* 结果为 null 则写入缓存(TTL 60s)→ 结果非 null 则清除缓存并返回。
|
|
1340
|
+
* 目的:while(true) 每 30s 轮询时避免重复读盘,有通知时立即投递不受缓存影响。
|
|
1341
|
+
*/
|
|
1342
|
+
async getCachedMemoryNotification(key, buildFn) {
|
|
1343
|
+
const expiresAt = this.memoryNotificationNullCache.get(key);
|
|
1344
|
+
if (expiresAt !== undefined && expiresAt > Date.now()) {
|
|
1345
|
+
return null;
|
|
1346
|
+
}
|
|
1347
|
+
const result = await buildFn();
|
|
1348
|
+
if (result === null) {
|
|
1349
|
+
this.memoryNotificationNullCache.set(key, Date.now() + McpServer.MEMORY_NOTIFICATION_NULL_TTL_MS);
|
|
1350
|
+
}
|
|
1351
|
+
else {
|
|
1352
|
+
this.memoryNotificationNullCache.delete(key);
|
|
1353
|
+
}
|
|
1354
|
+
return result;
|
|
1355
|
+
}
|
|
1192
1356
|
async handlePollMessage() {
|
|
1193
|
-
//
|
|
1194
|
-
// 避免进入服务端 MVC 异步线程池排队(poll_message 始终走异步池),
|
|
1195
|
-
// 确保快速返回,不影响后续 waitForMessagesWithPoll 的 resolver 注册。
|
|
1196
|
-
// 流程线任务由后续的 waitForMessagesWithPoll → 后台长轮询负责补拉。
|
|
1357
|
+
// 首次非阻塞预取:先拉一次已有消息填充缓冲区
|
|
1197
1358
|
await this.hydrateUnreadMessagesFromServer({
|
|
1198
1359
|
blockIfEmpty: false,
|
|
1199
1360
|
includePipelineTasks: false,
|
|
1200
1361
|
});
|
|
1201
|
-
|
|
1202
|
-
//
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
groupMessages: messages.groupMessages,
|
|
1211
|
-
fromBuffer: true,
|
|
1212
|
-
};
|
|
1362
|
+
let backendPollStarted = false;
|
|
1363
|
+
// poll_message 永不超时返回空:while(true) 内部每 30s 轮询一次
|
|
1364
|
+
// WebSocket 消息(主动通知)→ 实时响应
|
|
1365
|
+
// Memory 状态变化(无法主动通知)→ 最长 30s 延迟
|
|
1366
|
+
while (true) {
|
|
1367
|
+
// 1. 检查 WebSocket 缓冲区(来自 push + 后台补拉)
|
|
1368
|
+
const buffered = this.messageBuffer.get();
|
|
1369
|
+
if (buffered.directMessages.length > 0 || buffered.groupMessages.length > 0) {
|
|
1370
|
+
return await this.finalizeWithMemoryNotifications(buffered);
|
|
1213
1371
|
}
|
|
1372
|
+
// 2. 检查 Memory 通知(缓冲区无消息时直接返回)
|
|
1373
|
+
if (!this.memoryFileCheckInterval) {
|
|
1374
|
+
const fileChange = await this.buildMemoryFileChangeNotification();
|
|
1375
|
+
if (fileChange) {
|
|
1376
|
+
return this.buildPollResult({ directMessages: [fileChange], groupMessages: [] });
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
const recurrence = await this.getCachedMemoryNotification('recurrence', () => this.buildMemoryRecurrenceNotification());
|
|
1380
|
+
if (recurrence) {
|
|
1381
|
+
return this.buildPollResult({ directMessages: [recurrence], groupMessages: [] });
|
|
1382
|
+
}
|
|
1383
|
+
const todo = await this.getCachedMemoryNotification('todo', () => this.buildMemoryTodoNotification());
|
|
1384
|
+
if (todo) {
|
|
1385
|
+
return this.buildPollResult({ directMessages: [todo], groupMessages: [] });
|
|
1386
|
+
}
|
|
1387
|
+
const cleanup = await this.getCachedMemoryNotification('cleanup', () => this.buildMemoryCleanupNotification());
|
|
1388
|
+
if (cleanup) {
|
|
1389
|
+
return this.buildPollResult({ directMessages: [cleanup], groupMessages: [] });
|
|
1390
|
+
}
|
|
1391
|
+
// 3. 首次循环:触发后台 HTTP 长轮询(仅一次,后续循环复用)
|
|
1392
|
+
if (!backendPollStarted) {
|
|
1393
|
+
backendPollStarted = true;
|
|
1394
|
+
const blockTimeoutMs = this.resolvePollMessageBlockWaitMs();
|
|
1395
|
+
this.hydrateUnreadMessagesIfNeeded({
|
|
1396
|
+
blockIfEmpty: true,
|
|
1397
|
+
blockTimeoutMs,
|
|
1398
|
+
includePipelineTasks: true,
|
|
1399
|
+
}).catch((error) => {
|
|
1400
|
+
logger.warn("[McpServer] 后台 HTTP 长轮询补拉失败:", error);
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
// 4. 带超时等 WebSocket 消息(内部轮询周期)
|
|
1404
|
+
// poll() 一旦返回就已消费 buffer,不可 `continue` 回 get()(空)
|
|
1405
|
+
const polled = await this.messageBuffer.poll(POLL_MESSAGE_INTERNAL_POLL_INTERVAL_MS);
|
|
1406
|
+
if (polled.directMessages.length > 0 || polled.groupMessages.length > 0) {
|
|
1407
|
+
return await this.finalizeWithMemoryNotifications(polled);
|
|
1408
|
+
}
|
|
1409
|
+
// 超时 → 继续循环,重新检查 Memory 和缓冲区
|
|
1214
1410
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
groupMessages: messages.groupMessages,
|
|
1222
|
-
fromBuffer: true,
|
|
1223
|
-
};
|
|
1224
|
-
}
|
|
1225
|
-
const messages = await this.waitForMessagesWithPoll();
|
|
1226
|
-
// 后台定时器启用时跳过,避免与定时器推送重复
|
|
1411
|
+
}
|
|
1412
|
+
/**
|
|
1413
|
+
* 后检 Memory 通知并注入到待返回的消息中。按优先级从高到低注入:
|
|
1414
|
+
* 文件变更(始终注入)→ 近期记忆过期回忆(触发即返回)→ TODO(触发即返回)→ 容量整理(始终注入)
|
|
1415
|
+
*/
|
|
1416
|
+
async finalizeWithMemoryNotifications(messages) {
|
|
1227
1417
|
if (!this.memoryFileCheckInterval) {
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1418
|
+
await this.prependMemoryNotification(messages, () => this.buildMemoryFileChangeNotification());
|
|
1419
|
+
}
|
|
1420
|
+
if (await this.prependMemoryNotification(messages, () => this.getCachedMemoryNotification('recurrence', () => this.buildMemoryRecurrenceNotification()))) {
|
|
1421
|
+
return this.buildPollResult(messages);
|
|
1232
1422
|
}
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
messages.directMessages.unshift(memoryNotification);
|
|
1423
|
+
if (await this.prependMemoryNotification(messages, () => this.getCachedMemoryNotification('todo', () => this.buildMemoryTodoNotification()))) {
|
|
1424
|
+
return this.buildPollResult(messages);
|
|
1236
1425
|
}
|
|
1426
|
+
await this.prependMemoryNotification(messages, () => this.getCachedMemoryNotification('cleanup', () => this.buildMemoryCleanupNotification()));
|
|
1427
|
+
return this.buildPollResult(messages);
|
|
1428
|
+
}
|
|
1429
|
+
buildPollResult(messages) {
|
|
1237
1430
|
return {
|
|
1238
1431
|
directMessages: messages.directMessages,
|
|
1239
1432
|
groupMessages: messages.groupMessages,
|
|
1240
1433
|
fromBuffer: true,
|
|
1241
1434
|
};
|
|
1242
1435
|
}
|
|
1243
|
-
async waitForMessagesWithPoll() {
|
|
1244
|
-
// 如果缓冲区已有消息(来自上层的非阻塞补拉),立即返回
|
|
1245
|
-
const buffered = this.messageBuffer.get();
|
|
1246
|
-
if (buffered.directMessages.length > 0 || buffered.groupMessages.length > 0) {
|
|
1247
|
-
return buffered;
|
|
1248
|
-
}
|
|
1249
|
-
// 后台长轮询补拉:作为 WebSocket 之外的第二消息通道,不阻塞 poll 的 resolver 注册
|
|
1250
|
-
// 长轮询返回的消息会入 buffer → tryDispatch(),若 poll 已注册 resolver 则被立即唤醒
|
|
1251
|
-
const blockTimeoutMs = this.resolvePollMessageBlockWaitMs();
|
|
1252
|
-
this.hydrateUnreadMessagesIfNeeded({
|
|
1253
|
-
blockIfEmpty: true,
|
|
1254
|
-
blockTimeoutMs,
|
|
1255
|
-
includePipelineTasks: true,
|
|
1256
|
-
}).catch((error) => {
|
|
1257
|
-
logger.warn("[McpServer] 后台 HTTP 长轮询补拉失败:", error);
|
|
1258
|
-
});
|
|
1259
|
-
// 永久阻塞等待 WebSocket 推送的消息
|
|
1260
|
-
// WebSocket 消息到达时,push() → tryDispatch() 会解析此 Promise
|
|
1261
|
-
// 不传递超时参数,确保不会因超时返回空消息而重试
|
|
1262
|
-
return await this.messageBuffer.poll();
|
|
1263
|
-
}
|
|
1264
1436
|
resolvePollMessageBlockWaitMs() {
|
|
1265
1437
|
const blockWaitMs = this.parsePositiveIntegerEnv("AWS_POLL_MESSAGE_BLOCK_WAIT_MS", DEFAULT_POLL_MESSAGE_BLOCK_WAIT_MS);
|
|
1266
1438
|
// poll_message 走 callToolOnce 专用通道,HTTP 超时使用 POLL_MESSAGE_LONGPOLL_HTTP_TIMEOUT_MS
|
|
@@ -1339,6 +1511,62 @@ export class McpServer {
|
|
|
1339
1511
|
return null;
|
|
1340
1512
|
}
|
|
1341
1513
|
}
|
|
1514
|
+
/**
|
|
1515
|
+
* 构建近期记忆过期回忆通知(有即将遗忘的记忆需要整理)。
|
|
1516
|
+
* Memory 近期记忆过期 (v1.11.0) / v1.13.0 改用服务端 memory_status 字段
|
|
1517
|
+
*
|
|
1518
|
+
* 通知策略(基于服务端 memory_status):
|
|
1519
|
+
* 1. 有过期 recently_memory 且 memory_status='recalling'(回忆中但未完成疏理):
|
|
1520
|
+
* 通知 "存在待疏理的即将遗忘记忆,请通过 memory_recurrence 获取进行整理"
|
|
1521
|
+
* 2. 有过期 recently_memory 且 memory_status='normal'(尚未开始回忆):
|
|
1522
|
+
* 通知 "有即将遗忘记忆得整理,请通过 memory_recurrence 进行回忆"
|
|
1523
|
+
*/
|
|
1524
|
+
async buildMemoryRecurrenceNotification() {
|
|
1525
|
+
try {
|
|
1526
|
+
// v1.13.0: 改为调用服务端 list_expired_memories,返回的记录带 memory_status
|
|
1527
|
+
const expiredMemories = await this.memoryStore.listExpiredRecentlyMemories();
|
|
1528
|
+
if (expiredMemories.length === 0)
|
|
1529
|
+
return null;
|
|
1530
|
+
const agentId = this.getCurrentAgentId();
|
|
1531
|
+
if (!agentId)
|
|
1532
|
+
return null;
|
|
1533
|
+
const recallingExpired = expiredMemories.filter(m => m.recall_status === 'recalling' || m.memory_status === 'recalling');
|
|
1534
|
+
const normalExpired = expiredMemories.filter(m => !recallingExpired.includes(m));
|
|
1535
|
+
// 场景1: 有 recalling 状态的过期记忆(Agent 未完成疏理)
|
|
1536
|
+
if (recallingExpired.length > 0) {
|
|
1537
|
+
const memoryList = recallingExpired.slice(0, 5).map(m => m.uri).join('\n');
|
|
1538
|
+
return {
|
|
1539
|
+
msgId: `memory-recurrence-pending-${Date.now()}`,
|
|
1540
|
+
senderId: "MCP-System",
|
|
1541
|
+
senderName: "系统",
|
|
1542
|
+
receiverId: agentId,
|
|
1543
|
+
content: `存在待疏理的即将遗忘记忆,请通过 memory_recurrence 获取进行整理。\n\n待疏理记忆:\n${memoryList}${recallingExpired.length > 5 ? `\n ...及其他 ${recallingExpired.length - 5} 条` : ''}`,
|
|
1544
|
+
requireReply: false,
|
|
1545
|
+
prompt: "memory_recurrence 取回的记忆仍在回忆中,请通过 memory_recurrence_complete 完成疏理,或继续归档/续期。",
|
|
1546
|
+
timestamp: new Date().toISOString(),
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1549
|
+
// 场景2: 有待回忆的过期记忆
|
|
1550
|
+
if (normalExpired.length > 0) {
|
|
1551
|
+
const memoryList = normalExpired.slice(0, 5).map(m => m.uri).join('\n');
|
|
1552
|
+
return {
|
|
1553
|
+
msgId: `memory-recurrence-${Date.now()}`,
|
|
1554
|
+
senderId: "MCP-System",
|
|
1555
|
+
senderName: "系统",
|
|
1556
|
+
receiverId: agentId,
|
|
1557
|
+
content: `有即将遗忘记忆得整理,请通过 memory_recurrence 进行回忆,若有必要存留请通过创建永久记忆/归档/更新近期记忆时间的方式保留在近期记忆里的时长。\n\n即将遗忘的记忆:\n${memoryList}${normalExpired.length > 5 ? `\n ...及其他 ${normalExpired.length - 5} 条` : ''}`,
|
|
1558
|
+
requireReply: false,
|
|
1559
|
+
prompt: "这是一条近期记忆过期提醒,请调用 memory_recurrence 获取即将遗忘的记忆并决定处理方式。",
|
|
1560
|
+
timestamp: new Date().toISOString(),
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
return null;
|
|
1564
|
+
}
|
|
1565
|
+
catch (error) {
|
|
1566
|
+
logger.warn("[McpServer] 构建近期记忆过期回忆通知失败:", error);
|
|
1567
|
+
return null;
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1342
1570
|
/**
|
|
1343
1571
|
* 构建 Memory 文件变更检测通知。
|
|
1344
1572
|
* Memory 增强功能 (v1.6.0)
|
|
@@ -1349,6 +1577,9 @@ export class McpServer {
|
|
|
1349
1577
|
* 3. 如果没有变更,检查永久记忆的文件变更,标记最多 5 个为 updating
|
|
1350
1578
|
*/
|
|
1351
1579
|
async buildMemoryFileChangeNotification() {
|
|
1580
|
+
// 无角色名时不检测本地永久记忆文件变更(避免 default-role 跨角色污染)
|
|
1581
|
+
if (!this.hasRoleName)
|
|
1582
|
+
return null;
|
|
1352
1583
|
try {
|
|
1353
1584
|
const agentId = this.getCurrentAgentId();
|
|
1354
1585
|
if (!agentId) {
|
|
@@ -1585,15 +1816,16 @@ export class McpServer {
|
|
|
1585
1816
|
async handleGetMessage() {
|
|
1586
1817
|
await this.hydrateUnreadMessagesIfNeeded();
|
|
1587
1818
|
const messages = this.messageBuffer.get();
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
messages.directMessages.unshift(memoryNotification);
|
|
1819
|
+
if (await this.prependMemoryNotification(messages, () => this.buildMemoryRecurrenceNotification())) {
|
|
1820
|
+
return this.buildPollResult(messages);
|
|
1591
1821
|
}
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1822
|
+
if (await this.prependMemoryNotification(messages, () => this.buildMemoryTodoNotification())) {
|
|
1823
|
+
return this.buildPollResult(messages);
|
|
1824
|
+
}
|
|
1825
|
+
if (await this.prependMemoryNotification(messages, () => this.buildMemoryCleanupNotification())) {
|
|
1826
|
+
return this.buildPollResult(messages);
|
|
1827
|
+
}
|
|
1828
|
+
return this.buildPollResult(messages);
|
|
1597
1829
|
}
|
|
1598
1830
|
/**
|
|
1599
1831
|
* 在本地缓冲区为空时,从服务端补拉离线期间积累的未读消息。
|
|
@@ -1786,6 +2018,7 @@ export class McpServer {
|
|
|
1786
2018
|
if (DEGRADED_MODE_ENABLED) {
|
|
1787
2019
|
logger.info(`[McpServer] 降级模式已启用,注册失败时将以离线模式继续运行`);
|
|
1788
2020
|
}
|
|
2021
|
+
// v1.13.0: 不再加载本地元数据缓存,过期/TODO/回忆状态统一由服务端 memory_status 字段管理
|
|
1789
2022
|
// 后台注册:不阻塞 MCP 工具暴露,Agent 可立即接收工具调用
|
|
1790
2023
|
this.autoRegisterInBackground();
|
|
1791
2024
|
// 启动后台 Memory 文件变更检测
|
|
@@ -1826,6 +2059,37 @@ export class McpServer {
|
|
|
1826
2059
|
}, intervalMs);
|
|
1827
2060
|
logger.info(`[McpServer] 后台文件变更检测已启动,间隔: ${intervalMs}ms(可通过 AWS_MEMORY_FILE_CHECK_INTERVAL_MS 环境变量调整,设为 0 禁用)`);
|
|
1828
2061
|
}
|
|
2062
|
+
/**
|
|
2063
|
+
* 构建短期记忆 TODO 通知。
|
|
2064
|
+
* 主流程:调用服务端 list_by_todo_status({ todo_status: 'pending' }) 获取 pending 待办 -> 注入提醒。
|
|
2065
|
+
* v1.13.0: 由服务端 memory_status 字段管理 todo 状态,TS 侧不再维护本地缓存。
|
|
2066
|
+
*/
|
|
2067
|
+
async buildMemoryTodoNotification() {
|
|
2068
|
+
try {
|
|
2069
|
+
const pendingTodos = await this.memoryStore.listByTodoStatus('pending');
|
|
2070
|
+
if (pendingTodos.length === 0)
|
|
2071
|
+
return null;
|
|
2072
|
+
const agentId = this.getCurrentAgentId();
|
|
2073
|
+
if (!agentId)
|
|
2074
|
+
return null;
|
|
2075
|
+
const pendingCount = pendingTodos.length;
|
|
2076
|
+
const pendingList = pendingTodos.slice(0, 5).map(m => `- ${m.uri}`).join('\n');
|
|
2077
|
+
return {
|
|
2078
|
+
msgId: `memory-todo-${Date.now()}`,
|
|
2079
|
+
senderId: "MCP-System",
|
|
2080
|
+
senderName: "系统",
|
|
2081
|
+
receiverId: agentId,
|
|
2082
|
+
content: `当前有 ${pendingCount} 个 todo 项未完成,请获取短期记忆(todo 列表),且已经完成请移除标注为已完成状态。\n\n待办项:\n${pendingList}${pendingCount > 5 ? `\n ...及其他 ${pendingCount - 5} 条` : ''}`,
|
|
2083
|
+
requireReply: false,
|
|
2084
|
+
prompt: "这是一条短期记忆 TODO 提醒,请调用 list_memories({ memory_type: 'task_list' }) 查看待办列表,完成后通过 update_memory({ todo_status: 'completed' }) 标注为已完成,或通过 delete_memory 移除已完成项。",
|
|
2085
|
+
timestamp: new Date().toISOString(),
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
2088
|
+
catch (error) {
|
|
2089
|
+
logger.warn("[McpServer] 构建短期记忆 TODO 提醒失败:", error);
|
|
2090
|
+
return null;
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
1829
2093
|
/**
|
|
1830
2094
|
* 停止后台 Memory 文件变更检测定时器。
|
|
1831
2095
|
*/
|
|
@@ -1836,6 +2100,11 @@ export class McpServer {
|
|
|
1836
2100
|
logger.info("[McpServer] 后台文件变更检测已停止");
|
|
1837
2101
|
}
|
|
1838
2102
|
}
|
|
2103
|
+
// ============ 记忆统一状态字段 (v1.13.0) ============
|
|
2104
|
+
// v1.13.0 改用服务端 memory_status 字段管理 task_list todo 状态与 recently_memory 过期/回忆状态,
|
|
2105
|
+
// 下方 4 个工具直接调用服务端接口,本地不再维护元数据缓存。
|
|
2106
|
+
// buildMemoryRecurrenceNotification / buildMemoryTodoNotification / handleMemoryRecurrence / handleMemoryRecurrenceComplete
|
|
2107
|
+
// 已在文件其他位置实现(直接使用 this.memoryStore.listExpiredRecentlyMemories / listByTodoStatus / markExpiredMemoriesRecalling / clearRecallingExpiredMemories)。
|
|
1839
2108
|
async autoRegister() {
|
|
1840
2109
|
const agentConfig = this.agentClient.getAgentConfig();
|
|
1841
2110
|
logger.info(`[McpServer] 角色: "${agentConfig.roleName}"`);
|