aws-runtime-bridge 1.9.33 → 1.9.40
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 +35 -1
- package/dist/adapter/AcodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/AcodeSdkAdapter.js +417 -40
- package/dist/adapter/ClaudeSdkAdapter.d.ts +6 -0
- package/dist/adapter/ClaudeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/ClaudeSdkAdapter.js +23 -1
- package/dist/adapter/idle-poll-loop.d.ts +2 -1
- package/dist/adapter/idle-poll-loop.d.ts.map +1 -1
- package/dist/adapter/types.d.ts +65 -3
- package/dist/adapter/types.d.ts.map +1 -1
- package/dist/adapter/types.js +5 -4
- package/dist/index.js +4 -0
- package/dist/routes/acode-todos.d.ts +11 -0
- package/dist/routes/acode-todos.d.ts.map +1 -0
- package/dist/routes/acode-todos.js +75 -0
- package/dist/routes/memory.d.ts +1 -1
- package/dist/routes/memory.d.ts.map +1 -1
- package/dist/routes/memory.js +3 -3
- package/dist/routes/pty.d.ts.map +1 -1
- package/dist/routes/pty.js +9 -0
- package/dist/routes/sub-agents.d.ts +14 -0
- package/dist/routes/sub-agents.d.ts.map +1 -0
- package/dist/routes/sub-agents.js +253 -0
- package/dist/routes/terminal.d.ts +9 -1
- package/dist/routes/terminal.d.ts.map +1 -1
- package/dist/routes/terminal.js +207 -22
- package/dist/services/agent-event-store.d.ts +1 -0
- package/dist/services/agent-event-store.d.ts.map +1 -1
- package/dist/services/event-delta-pusher.js +4 -4
- package/dist/services/session-output.d.ts +3 -0
- package/dist/services/session-output.d.ts.map +1 -1
- package/dist/services/session-output.js +38 -2
- package/dist/services/sub-agent-manager-instance.d.ts +4 -0
- package/dist/services/sub-agent-manager-instance.d.ts.map +1 -0
- package/dist/services/sub-agent-manager-instance.js +12 -0
- package/dist/services/workspace-files.d.ts +1 -0
- package/dist/services/workspace-files.d.ts.map +1 -1
- package/dist/services/workspace-files.js +57 -1
- package/package/acode/dist/ask-user-question-tool.d.ts +47 -0
- package/package/acode/dist/ask-user-question-tool.d.ts.map +1 -0
- package/package/acode/dist/ask-user-question-tool.js +233 -0
- package/package/acode/dist/built-in-file-tools.d.ts +2 -0
- package/package/acode/dist/built-in-file-tools.d.ts.map +1 -1
- package/package/acode/dist/compaction.d.ts +206 -0
- package/package/acode/dist/compaction.d.ts.map +1 -0
- package/package/acode/dist/compaction.js +664 -0
- package/package/acode/dist/config.d.ts +6 -1
- package/package/acode/dist/config.d.ts.map +1 -1
- package/package/acode/dist/config.js +27 -2
- package/package/acode/dist/index.d.ts +4 -0
- package/package/acode/dist/index.d.ts.map +1 -1
- package/package/acode/dist/index.js +4 -0
- package/package/acode/dist/runtime.d.ts +137 -0
- package/package/acode/dist/runtime.d.ts.map +1 -1
- package/package/acode/dist/runtime.js +974 -172
- package/package/acode/dist/skill-tool.d.ts +30 -0
- package/package/acode/dist/skill-tool.d.ts.map +1 -0
- package/package/acode/dist/skill-tool.js +174 -0
- package/package/acode/dist/sub-agent-manager.d.ts +169 -0
- package/package/acode/dist/sub-agent-manager.d.ts.map +1 -0
- package/package/acode/dist/sub-agent-manager.js +535 -0
- package/package/acode/dist/sub-agent-store.d.ts +33 -0
- package/package/acode/dist/sub-agent-store.d.ts.map +1 -0
- package/package/acode/dist/sub-agent-store.js +109 -0
- package/package/acode/dist/sub-agent-tools.d.ts +72 -0
- package/package/acode/dist/sub-agent-tools.d.ts.map +1 -0
- package/package/acode/dist/sub-agent-tools.js +429 -0
- package/package/acode/dist/sub-agent-types.d.ts +81 -0
- package/package/acode/dist/sub-agent-types.d.ts.map +1 -0
- package/package/acode/dist/sub-agent-types.js +8 -0
- package/package/acode/dist/todo-store.d.ts +42 -0
- package/package/acode/dist/todo-store.d.ts.map +1 -0
- package/package/acode/dist/todo-store.js +68 -0
- package/package/acode/dist/todo-tool.d.ts +6 -0
- package/package/acode/dist/todo-tool.d.ts.map +1 -0
- package/package/acode/dist/todo-tool.js +138 -0
- package/package/acode/dist/types.d.ts +22 -1
- package/package/acode/dist/types.d.ts.map +1 -1
- package/package/acode/package.json +13 -2
- package/package/aws-client-agent-mcp/dist/context-manager.test.js +0 -3
- 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 +83 -50
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.js +451 -346
- package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +259 -241
- 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 +1 -19
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +4 -77
- package/package/aws-client-agent-mcp/dist/mcp-tools.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/memory-store.d.ts +17 -40
- package/package/aws-client-agent-mcp/dist/memory-store.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/memory-store.js +62 -149
- package/package/aws-client-agent-mcp/dist/memory-store.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/memory-store.test.js +175 -164
- 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 +3 -9
- package/package/aws-client-agent-mcp/dist/memory-tools.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/memory-tools.js +28 -55
- package/package/aws-client-agent-mcp/dist/memory-tools.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/message-buffer.d.ts +27 -9
- package/package/aws-client-agent-mcp/dist/message-buffer.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/message-buffer.js +100 -23
- package/package/aws-client-agent-mcp/dist/message-buffer.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts +1 -14
- 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 +7 -18
- 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 +8 -5
- package/package/aws-client-agent-mcp/dist/status-reporter.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/status-reporter.test.js +93 -0
- package/package/aws-client-agent-mcp/dist/status-reporter.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +3 -25
- package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
- package/package.json +17 -7
- package/dist/adapter/AcodeSdkAdapter.test.d.ts +0 -2
- package/dist/adapter/AcodeSdkAdapter.test.d.ts.map +0 -1
- package/dist/adapter/AcodeSdkAdapter.test.js +0 -2000
- package/dist/adapter/AdapterRegistry.test.d.ts +0 -5
- package/dist/adapter/AdapterRegistry.test.d.ts.map +0 -1
- package/dist/adapter/AdapterRegistry.test.js +0 -118
- package/dist/adapter/ClaudeSdkAdapter.test.d.ts +0 -2
- package/dist/adapter/ClaudeSdkAdapter.test.d.ts.map +0 -1
- package/dist/adapter/ClaudeSdkAdapter.test.js +0 -311
- package/dist/adapter/CodexSdkAdapter.test.d.ts +0 -2
- package/dist/adapter/CodexSdkAdapter.test.d.ts.map +0 -1
- package/dist/adapter/CodexSdkAdapter.test.js +0 -270
- package/dist/adapter/OpencodeSdkAdapter.test.d.ts +0 -2
- package/dist/adapter/OpencodeSdkAdapter.test.d.ts.map +0 -1
- package/dist/adapter/OpencodeSdkAdapter.test.js +0 -158
- package/dist/adapter/acode-tool-names.test.d.ts +0 -2
- package/dist/adapter/acode-tool-names.test.d.ts.map +0 -1
- package/dist/adapter/acode-tool-names.test.js +0 -28
- package/dist/adapter/adapter.test.d.ts +0 -5
- package/dist/adapter/adapter.test.d.ts.map +0 -1
- package/dist/adapter/adapter.test.js +0 -180
- package/dist/adapter/idle-poll-loop.test.d.ts +0 -2
- package/dist/adapter/idle-poll-loop.test.d.ts.map +0 -1
- package/dist/adapter/idle-poll-loop.test.js +0 -85
- package/dist/adapter/types.test.d.ts +0 -2
- package/dist/adapter/types.test.d.ts.map +0 -1
- package/dist/adapter/types.test.js +0 -50
- package/dist/adapters/cc-switch/mcp-acode.test.d.ts +0 -2
- package/dist/adapters/cc-switch/mcp-acode.test.d.ts.map +0 -1
- package/dist/adapters/cc-switch/mcp-acode.test.js +0 -80
- package/dist/adapters/cc-switch/mcp-claudecode.test.d.ts +0 -2
- package/dist/adapters/cc-switch/mcp-claudecode.test.d.ts.map +0 -1
- package/dist/adapters/cc-switch/mcp-claudecode.test.js +0 -75
- package/dist/adapters/cc-switch/mcp-codex.test.d.ts +0 -2
- package/dist/adapters/cc-switch/mcp-codex.test.d.ts.map +0 -1
- package/dist/adapters/cc-switch/mcp-codex.test.js +0 -126
- package/dist/adapters/cc-switch/mcp-opencode.test.d.ts +0 -2
- package/dist/adapters/cc-switch/mcp-opencode.test.d.ts.map +0 -1
- package/dist/adapters/cc-switch/mcp-opencode.test.js +0 -62
- package/dist/adapters/cc-switch/skill-directory.test.d.ts +0 -2
- package/dist/adapters/cc-switch/skill-directory.test.d.ts.map +0 -1
- package/dist/adapters/cc-switch/skill-directory.test.js +0 -74
- package/dist/config.test.d.ts +0 -2
- package/dist/config.test.d.ts.map +0 -1
- package/dist/config.test.js +0 -107
- package/dist/routes/ai-sources.test.d.ts +0 -2
- package/dist/routes/ai-sources.test.d.ts.map +0 -1
- package/dist/routes/ai-sources.test.js +0 -169
- package/dist/routes/file-browser.test.d.ts +0 -5
- package/dist/routes/file-browser.test.d.ts.map +0 -1
- package/dist/routes/file-browser.test.js +0 -155
- package/dist/routes/git.test.d.ts +0 -2
- package/dist/routes/git.test.d.ts.map +0 -1
- package/dist/routes/git.test.js +0 -330
- package/dist/routes/instance.test.d.ts +0 -5
- package/dist/routes/instance.test.d.ts.map +0 -1
- package/dist/routes/instance.test.js +0 -389
- package/dist/routes/mcp.test.d.ts +0 -5
- package/dist/routes/mcp.test.d.ts.map +0 -1
- package/dist/routes/mcp.test.js +0 -92
- package/dist/routes/memory-route-wiring.test.d.ts +0 -2
- package/dist/routes/memory-route-wiring.test.d.ts.map +0 -1
- package/dist/routes/memory-route-wiring.test.js +0 -15
- package/dist/routes/memory.test.d.ts +0 -2
- package/dist/routes/memory.test.d.ts.map +0 -1
- package/dist/routes/memory.test.js +0 -177
- package/dist/routes/properties.test.d.ts +0 -5
- package/dist/routes/properties.test.d.ts.map +0 -1
- package/dist/routes/properties.test.js +0 -72
- package/dist/routes/pty.test.d.ts +0 -2
- package/dist/routes/pty.test.d.ts.map +0 -1
- package/dist/routes/pty.test.js +0 -82
- package/dist/routes/runtime-binding.test.d.ts +0 -2
- package/dist/routes/runtime-binding.test.d.ts.map +0 -1
- package/dist/routes/runtime-binding.test.js +0 -32
- package/dist/routes/sessions.test.d.ts +0 -5
- package/dist/routes/sessions.test.d.ts.map +0 -1
- package/dist/routes/sessions.test.js +0 -86
- package/dist/routes/skills.test.d.ts +0 -5
- package/dist/routes/skills.test.d.ts.map +0 -1
- package/dist/routes/skills.test.js +0 -50
- package/dist/routes/system-metrics.test.d.ts +0 -2
- package/dist/routes/system-metrics.test.d.ts.map +0 -1
- package/dist/routes/system-metrics.test.js +0 -16
- package/dist/routes/terminal.stop-options.test.d.ts +0 -2
- package/dist/routes/terminal.stop-options.test.d.ts.map +0 -1
- package/dist/routes/terminal.stop-options.test.js +0 -39
- package/dist/routes/terminal.test.d.ts +0 -2
- package/dist/routes/terminal.test.d.ts.map +0 -1
- package/dist/routes/terminal.test.js +0 -746
- package/dist/routes/yml.test.d.ts +0 -5
- package/dist/routes/yml.test.d.ts.map +0 -1
- package/dist/routes/yml.test.js +0 -58
- package/dist/services/ai-source-apply.test.d.ts +0 -2
- package/dist/services/ai-source-apply.test.d.ts.map +0 -1
- package/dist/services/ai-source-apply.test.js +0 -138
- package/dist/services/auto-register.test.d.ts +0 -2
- package/dist/services/auto-register.test.d.ts.map +0 -1
- package/dist/services/auto-register.test.js +0 -184
- package/dist/services/aws-client-agent-mcp.test.d.ts +0 -2
- package/dist/services/aws-client-agent-mcp.test.d.ts.map +0 -1
- package/dist/services/aws-client-agent-mcp.test.js +0 -242
- package/dist/services/bridge-package-publish-hooks.test.d.ts +0 -2
- package/dist/services/bridge-package-publish-hooks.test.d.ts.map +0 -1
- package/dist/services/bridge-package-publish-hooks.test.js +0 -136
- package/dist/services/cc-switch-discovery.test.d.ts +0 -2
- package/dist/services/cc-switch-discovery.test.d.ts.map +0 -1
- package/dist/services/cc-switch-discovery.test.js +0 -56
- package/dist/services/cli-commands.test.d.ts +0 -2
- package/dist/services/cli-commands.test.d.ts.map +0 -1
- package/dist/services/cli-commands.test.js +0 -230
- package/dist/services/instance-init-service.test.d.ts +0 -2
- package/dist/services/instance-init-service.test.d.ts.map +0 -1
- package/dist/services/instance-init-service.test.js +0 -140
- package/dist/services/instance-state.test.d.ts +0 -2
- package/dist/services/instance-state.test.d.ts.map +0 -1
- package/dist/services/instance-state.test.js +0 -245
- package/dist/services/mcp-launch-binding-queue.test.d.ts +0 -2
- package/dist/services/mcp-launch-binding-queue.test.d.ts.map +0 -1
- package/dist/services/mcp-launch-binding-queue.test.js +0 -181
- package/dist/services/runtime-binding.test.d.ts +0 -2
- package/dist/services/runtime-binding.test.d.ts.map +0 -1
- package/dist/services/runtime-binding.test.js +0 -78
- package/dist/services/runtime-lifecycle-policy.test.d.ts +0 -2
- package/dist/services/runtime-lifecycle-policy.test.d.ts.map +0 -1
- package/dist/services/runtime-lifecycle-policy.test.js +0 -41
- package/dist/services/session-output.test.d.ts +0 -5
- package/dist/services/session-output.test.d.ts.map +0 -1
- package/dist/services/session-output.test.js +0 -177
- package/dist/services/startup-config-wizard.test.d.ts +0 -2
- package/dist/services/startup-config-wizard.test.d.ts.map +0 -1
- package/dist/services/startup-config-wizard.test.js +0 -184
- package/dist/services/terminal-persistence.test.d.ts +0 -5
- package/dist/services/terminal-persistence.test.d.ts.map +0 -1
- package/dist/services/terminal-persistence.test.js +0 -159
- package/dist/services/tool-installer.test.d.ts +0 -2
- package/dist/services/tool-installer.test.d.ts.map +0 -1
- package/dist/services/tool-installer.test.js +0 -225
- package/dist/services/workspace-files.test.d.ts +0 -2
- package/dist/services/workspace-files.test.d.ts.map +0 -1
- package/dist/services/workspace-files.test.js +0 -648
- package/dist/services/workspace-watch.test.d.ts +0 -2
- package/dist/services/workspace-watch.test.d.ts.map +0 -1
- package/dist/services/workspace-watch.test.js +0 -38
- package/dist/utils/file-utils.test.d.ts +0 -2
- package/dist/utils/file-utils.test.d.ts.map +0 -1
- package/dist/utils/file-utils.test.js +0 -244
- package/dist/utils/logger.test.d.ts +0 -2
- package/dist/utils/logger.test.d.ts.map +0 -1
- package/dist/utils/logger.test.js +0 -93
- package/dist/utils/sdk-package-loader.test.d.ts +0 -2
- package/dist/utils/sdk-package-loader.test.d.ts.map +0 -1
- package/dist/utils/sdk-package-loader.test.js +0 -84
- package/dist/utils/validation.test.d.ts +0 -2
- package/dist/utils/validation.test.d.ts.map +0 -1
- package/dist/utils/validation.test.js +0 -88
- package/dist/utils/yaml-utils.test.d.ts +0 -2
- package/dist/utils/yaml-utils.test.d.ts.map +0 -1
- package/dist/utils/yaml-utils.test.js +0 -363
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { describe, it } from "node:test";
|
|
6
6
|
import { AgentClient } from "./agent-client.js";
|
|
7
7
|
import { McpServer } from "./mcp-server.js";
|
|
8
8
|
import { MCP_TOOLS } from "./mcp-tools.js";
|
|
9
|
-
import {
|
|
9
|
+
import { MemoryStore, } from "./memory-store.js";
|
|
10
10
|
import { MessageBuffer } from "./message-buffer.js";
|
|
11
11
|
function createServerWithUnread(unreadMessages, overrides = {}) {
|
|
12
12
|
const server = new McpServer();
|
|
@@ -150,52 +150,40 @@ describe("McpServer unread backlog hydration", () => {
|
|
|
150
150
|
});
|
|
151
151
|
});
|
|
152
152
|
it("poll_message should keep blocking through empty polls until messages arrive", async () => {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
assert.equal(fetchOptions[1].blockIfEmpty, true);
|
|
188
|
-
assert.ok(typeof fetchOptions[1].blockTimeoutMs === "number");
|
|
189
|
-
assert.equal(fetchOptions[1].blockTimeoutMs, 20);
|
|
190
|
-
}
|
|
191
|
-
finally {
|
|
192
|
-
if (previousBlockWait === undefined) {
|
|
193
|
-
delete process.env.AWS_POLL_MESSAGE_BLOCK_WAIT_MS;
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
process.env.AWS_POLL_MESSAGE_BLOCK_WAIT_MS = previousBlockWait;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
153
|
+
const directMessage = {
|
|
154
|
+
msgId: "dm-delayed-1",
|
|
155
|
+
senderId: "agent-delayed",
|
|
156
|
+
senderName: "Agent Delayed",
|
|
157
|
+
content: "delayed dm",
|
|
158
|
+
requireReply: false,
|
|
159
|
+
timestamp: new Date().toISOString(),
|
|
160
|
+
};
|
|
161
|
+
const fetchOptions = [];
|
|
162
|
+
const server = createServerWithUnread({ directMessages: [], groupMessages: [] }, {
|
|
163
|
+
fetchUnreadMessages: async (options) => {
|
|
164
|
+
fetchOptions.push(options ?? {});
|
|
165
|
+
return { directMessages: [], groupMessages: [] };
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
// Simulate a WebSocket message arriving after hydration returns empty.
|
|
169
|
+
// poll_message must keep blocking on the local buffer until the message arrives.
|
|
170
|
+
const buffer = Reflect.get(server, "messageBuffer");
|
|
171
|
+
setTimeout(() => {
|
|
172
|
+
buffer.push(directMessage);
|
|
173
|
+
}, 50);
|
|
174
|
+
const handleToolCall = getHandleToolCall(server);
|
|
175
|
+
const result = await handleToolCall.call(server, "poll_message", {});
|
|
176
|
+
assert.deepEqual(result, {
|
|
177
|
+
directMessages: [directMessage],
|
|
178
|
+
groupMessages: [],
|
|
179
|
+
fromBuffer: true,
|
|
180
|
+
systemMessages: [],
|
|
181
|
+
});
|
|
182
|
+
// fetchUnreadMessages should only be called once (the initial non-blocking hydrate).
|
|
183
|
+
// The message must arrive via the local buffer (WebSocket push), not a second blocking fetch.
|
|
184
|
+
assert.equal(fetchOptions.length, 1);
|
|
185
|
+
assert.equal(fetchOptions[0].blockIfEmpty, false);
|
|
186
|
+
assert.equal(fetchOptions[0].includePipelineTasks, false);
|
|
199
187
|
});
|
|
200
188
|
it("poll_message should handle hydration error gracefully and receive WebSocket messages", async () => {
|
|
201
189
|
const directMessage = {
|
|
@@ -210,10 +198,7 @@ describe("McpServer unread backlog hydration", () => {
|
|
|
210
198
|
const server = createServerWithUnread({ directMessages: [], groupMessages: [] }, {
|
|
211
199
|
fetchUnreadMessages: async () => {
|
|
212
200
|
fetchCount += 1;
|
|
213
|
-
|
|
214
|
-
throw new Error("MCP tool poll_message timed out after 120000ms");
|
|
215
|
-
}
|
|
216
|
-
return { directMessages: [], groupMessages: [] };
|
|
201
|
+
throw new Error("MCP tool poll_message timed out after 120000ms");
|
|
217
202
|
},
|
|
218
203
|
});
|
|
219
204
|
// Simulate WebSocket message arriving after hydration fails
|
|
@@ -229,7 +214,10 @@ describe("McpServer unread backlog hydration", () => {
|
|
|
229
214
|
fromBuffer: true,
|
|
230
215
|
systemMessages: [],
|
|
231
216
|
});
|
|
232
|
-
|
|
217
|
+
// fetchUnreadMessages should only be called once (the initial hydrate, which throws).
|
|
218
|
+
// hydrateUnreadMessagesFromServer catches the error, and poll_message falls back to
|
|
219
|
+
// blocking on the local buffer until the WebSocket message arrives.
|
|
220
|
+
assert.equal(fetchCount, 1);
|
|
233
221
|
});
|
|
234
222
|
it("get_message should still hydrate unread group messages after profile push is received", async () => {
|
|
235
223
|
const groupMessage = {
|
|
@@ -519,54 +507,13 @@ describe("McpServer unread backlog hydration", () => {
|
|
|
519
507
|
}, 50);
|
|
520
508
|
const handleToolCall = getHandleToolCall(server);
|
|
521
509
|
const result = (await handleToolCall.call(server, "poll_message", {}));
|
|
522
|
-
|
|
510
|
+
// Only the initial non-blocking hydrate should call fetchUnreadMessages.
|
|
511
|
+
// The message must arrive via the local buffer (WebSocket push).
|
|
512
|
+
assert.equal(fetchCalls, 1);
|
|
523
513
|
assert.deepEqual(result.directMessages, [delayedMessage]);
|
|
524
514
|
assert.deepEqual(result.groupMessages, []);
|
|
525
515
|
assert.equal(result.fromBuffer, true);
|
|
526
516
|
});
|
|
527
|
-
it("poll_message should clamp block wait below HTTP request timeout", async () => {
|
|
528
|
-
const previousBlockWait = process.env.AWS_POLL_MESSAGE_BLOCK_WAIT_MS;
|
|
529
|
-
process.env.AWS_POLL_MESSAGE_BLOCK_WAIT_MS = "120000";
|
|
530
|
-
try {
|
|
531
|
-
const delayedMessage = {
|
|
532
|
-
msgId: "dm-after-clamped-poll",
|
|
533
|
-
senderId: "agent-later",
|
|
534
|
-
senderName: "Later Agent",
|
|
535
|
-
receiverId: "agent-self",
|
|
536
|
-
content: "arrived after clamped backend poll",
|
|
537
|
-
requireReply: false,
|
|
538
|
-
timestamp: new Date().toISOString(),
|
|
539
|
-
};
|
|
540
|
-
const fetchOptions = [];
|
|
541
|
-
const server = createServerWithUnread({
|
|
542
|
-
directMessages: [],
|
|
543
|
-
groupMessages: [],
|
|
544
|
-
}, {
|
|
545
|
-
fetchUnreadMessages: async (options) => {
|
|
546
|
-
fetchOptions.push(options ?? {});
|
|
547
|
-
return fetchOptions.length === 1
|
|
548
|
-
? { directMessages: [], groupMessages: [] }
|
|
549
|
-
: fetchOptions.length === 2
|
|
550
|
-
? { directMessages: [delayedMessage], groupMessages: [] }
|
|
551
|
-
: { directMessages: [], groupMessages: [] };
|
|
552
|
-
},
|
|
553
|
-
});
|
|
554
|
-
const handleToolCall = getHandleToolCall(server);
|
|
555
|
-
const result = (await handleToolCall.call(server, "poll_message", {}));
|
|
556
|
-
assert.deepEqual(result.directMessages, [delayedMessage]);
|
|
557
|
-
assert.equal(fetchOptions[0].blockIfEmpty, false);
|
|
558
|
-
assert.equal(fetchOptions[1].blockIfEmpty, true);
|
|
559
|
-
assert.equal(fetchOptions[1].blockTimeoutMs, 120000);
|
|
560
|
-
}
|
|
561
|
-
finally {
|
|
562
|
-
if (previousBlockWait === undefined) {
|
|
563
|
-
delete process.env.AWS_POLL_MESSAGE_BLOCK_WAIT_MS;
|
|
564
|
-
}
|
|
565
|
-
else {
|
|
566
|
-
process.env.AWS_POLL_MESSAGE_BLOCK_WAIT_MS = previousBlockWait;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
});
|
|
570
517
|
it("poll_message should restore waiting status when task notification is returned", async () => {
|
|
571
518
|
const statusEvents = [];
|
|
572
519
|
const server = createServerWithUnread({
|
|
@@ -768,7 +715,6 @@ describe("McpServer memory tools", () => {
|
|
|
768
715
|
assert.ok(toolNames.includes("search_memory"));
|
|
769
716
|
assert.ok(toolNames.includes("list_memories"));
|
|
770
717
|
assert.ok(toolNames.includes("get_memory_stats"));
|
|
771
|
-
assert.ok(toolNames.includes("archive_recently_memory"));
|
|
772
718
|
// Memory 近期记忆过期与回忆工具 (v1.11.0)
|
|
773
719
|
assert.ok(toolNames.includes("memory_recurrence"));
|
|
774
720
|
assert.ok(toolNames.includes("memory_recurrence_complete"));
|
|
@@ -777,7 +723,7 @@ describe("McpServer memory tools", () => {
|
|
|
777
723
|
await withMemoryServer(async (server) => {
|
|
778
724
|
const handleToolCall = getHandleToolCall(server);
|
|
779
725
|
const created = await handleToolCall.call(server, "create_memory", {
|
|
780
|
-
memory_type: "
|
|
726
|
+
memory_type: "project_memory",
|
|
781
727
|
uri: "Core://Agent/Profile/",
|
|
782
728
|
content: "prefers concise backend summaries",
|
|
783
729
|
});
|
|
@@ -785,12 +731,12 @@ describe("McpServer memory tools", () => {
|
|
|
785
731
|
assert.equal(created.content, undefined);
|
|
786
732
|
const read = await handleToolCall.call(server, "read_memory", {
|
|
787
733
|
uri: "core://Agent/Profile",
|
|
788
|
-
memory_type: "
|
|
734
|
+
memory_type: "project_memory",
|
|
789
735
|
});
|
|
790
736
|
assert.equal(read.content, "prefers concise backend summaries");
|
|
791
737
|
const updated = await handleToolCall.call(server, "update_memory", {
|
|
792
738
|
uri: "core://Agent/Profile",
|
|
793
|
-
memory_type: "
|
|
739
|
+
memory_type: "project_memory",
|
|
794
740
|
old_string: "concise",
|
|
795
741
|
new_string: "structured",
|
|
796
742
|
append: "\nuses MCP memory tools",
|
|
@@ -799,7 +745,7 @@ describe("McpServer memory tools", () => {
|
|
|
799
745
|
assert.equal(updated.version, 2);
|
|
800
746
|
const readUpdated = await handleToolCall.call(server, "read_memory", {
|
|
801
747
|
uri: "core://Agent/Profile",
|
|
802
|
-
memory_type: "
|
|
748
|
+
memory_type: "project_memory",
|
|
803
749
|
});
|
|
804
750
|
assert.match(readUpdated.content, /structured backend/);
|
|
805
751
|
assert.match(readUpdated.content, /MCP memory tools/);
|
|
@@ -810,7 +756,7 @@ describe("McpServer memory tools", () => {
|
|
|
810
756
|
assert.equal(searchResult.results.length, 1);
|
|
811
757
|
const deleted = await handleToolCall.call(server, "delete_memory", {
|
|
812
758
|
uri: "core://Agent/Profile",
|
|
813
|
-
memory_type: "
|
|
759
|
+
memory_type: "project_memory",
|
|
814
760
|
});
|
|
815
761
|
assert.deepEqual(deleted, { deleted: true });
|
|
816
762
|
});
|
|
@@ -819,25 +765,25 @@ describe("McpServer memory tools", () => {
|
|
|
819
765
|
await withMemoryServer(async (server) => {
|
|
820
766
|
const handleToolCall = getHandleToolCall(server);
|
|
821
767
|
await handleToolCall.call(server, "create_memory", {
|
|
822
|
-
memory_type: "
|
|
768
|
+
memory_type: "recently_memory",
|
|
823
769
|
uri: "task://todo/current",
|
|
824
770
|
content: "finish memory endpoint tests",
|
|
825
771
|
});
|
|
826
772
|
await handleToolCall.call(server, "create_memory", {
|
|
827
|
-
memory_type: "
|
|
773
|
+
memory_type: "agent_memory",
|
|
828
774
|
uri: "recent://discussion/memory-tools",
|
|
829
775
|
content: "memory tools should stay local for now",
|
|
830
776
|
});
|
|
831
777
|
const taskList = await handleToolCall.call(server, "list_memories", {
|
|
832
|
-
memory_type: "
|
|
778
|
+
memory_type: "recently_memory",
|
|
833
779
|
});
|
|
834
780
|
assert.equal(taskList.length, 1);
|
|
835
781
|
const recentList = await handleToolCall.call(server, "list_memories", {
|
|
836
|
-
memory_type: "
|
|
782
|
+
memory_type: "agent_memory",
|
|
837
783
|
});
|
|
838
784
|
assert.equal(recentList.length, 1);
|
|
839
785
|
await assert.rejects(() => handleToolCall.call(server, "list_memories", {
|
|
840
|
-
memory_type: "
|
|
786
|
+
memory_type: "project_memory",
|
|
841
787
|
}), /Invalid memory_type/);
|
|
842
788
|
});
|
|
843
789
|
});
|
|
@@ -846,76 +792,42 @@ describe("McpServer memory tools", () => {
|
|
|
846
792
|
const firstHandleToolCall = getHandleToolCall(firstServer);
|
|
847
793
|
const secondHandleToolCall = getHandleToolCall(secondServer);
|
|
848
794
|
await firstHandleToolCall.call(firstServer, "create_memory", {
|
|
849
|
-
memory_type: "
|
|
795
|
+
memory_type: "project_memory",
|
|
850
796
|
uri: "core://role/shared-profile",
|
|
851
797
|
content: "shared role knowledge",
|
|
852
798
|
});
|
|
853
799
|
await firstHandleToolCall.call(firstServer, "create_memory", {
|
|
854
|
-
memory_type: "
|
|
800
|
+
memory_type: "agent_memory",
|
|
855
801
|
uri: "recent://instance/private-context",
|
|
856
802
|
content: "agent one private context",
|
|
857
803
|
});
|
|
858
804
|
const roleMemory = await secondHandleToolCall.call(secondServer, "read_memory", {
|
|
859
805
|
uri: "core://role/shared-profile",
|
|
860
|
-
memory_type: "
|
|
806
|
+
memory_type: "project_memory",
|
|
861
807
|
});
|
|
862
808
|
const recentMemory = await secondHandleToolCall.call(secondServer, "read_memory", {
|
|
863
809
|
uri: "recent://instance/private-context",
|
|
864
|
-
memory_type: "
|
|
810
|
+
memory_type: "agent_memory",
|
|
865
811
|
});
|
|
866
812
|
assert.equal(roleMemory.content, "shared role knowledge");
|
|
867
813
|
assert.equal(recentMemory, null);
|
|
868
814
|
});
|
|
869
815
|
});
|
|
870
|
-
it("supports task-list removal and recent-memory archive semantics", async () => {
|
|
871
|
-
await withMemoryServer(async (server) => {
|
|
872
|
-
const handleToolCall = getHandleToolCall(server);
|
|
873
|
-
await handleToolCall.call(server, "create_memory", {
|
|
874
|
-
memory_type: "task_list",
|
|
875
|
-
uri: "task://todo/remove-me",
|
|
876
|
-
content: "temporary task",
|
|
877
|
-
});
|
|
878
|
-
await handleToolCall.call(server, "create_memory", {
|
|
879
|
-
memory_type: "recently_memory",
|
|
880
|
-
uri: "recent://note/archive-me",
|
|
881
|
-
content: "hot context",
|
|
882
|
-
});
|
|
883
|
-
const deleted = await handleToolCall.call(server, "delete_memory", {
|
|
884
|
-
uri: "task://todo/remove-me",
|
|
885
|
-
memory_type: "task_list",
|
|
886
|
-
});
|
|
887
|
-
assert.deepEqual(deleted, { deleted: true });
|
|
888
|
-
const archived = await handleToolCall.call(server, "archive_recently_memory", {
|
|
889
|
-
uri: "recent://note/archive-me",
|
|
890
|
-
});
|
|
891
|
-
assert.equal(archived.memory_type, "memory");
|
|
892
|
-
const archivedInRoleScope = await handleToolCall.call(server, "read_memory", {
|
|
893
|
-
uri: "recent://note/archive-me",
|
|
894
|
-
memory_type: "memory",
|
|
895
|
-
});
|
|
896
|
-
const removedFromInstanceScope = await handleToolCall.call(server, "read_memory", {
|
|
897
|
-
uri: "recent://note/archive-me",
|
|
898
|
-
memory_type: "recently_memory",
|
|
899
|
-
});
|
|
900
|
-
assert.equal(archivedInRoleScope.content, "hot context");
|
|
901
|
-
assert.equal(removedFromInstanceScope, null);
|
|
902
|
-
});
|
|
903
|
-
});
|
|
904
816
|
it("returns memory stats through MCP dispatch", async () => {
|
|
905
817
|
await withMemoryServer(async (server) => {
|
|
906
818
|
const handleToolCall = getHandleToolCall(server);
|
|
907
819
|
await handleToolCall.call(server, "create_memory", {
|
|
908
|
-
memory_type: "
|
|
820
|
+
memory_type: "recently_memory",
|
|
909
821
|
uri: "task://todo/stats",
|
|
910
822
|
content: "temporary task",
|
|
911
823
|
});
|
|
912
824
|
await handleToolCall.call(server, "create_memory", {
|
|
913
|
-
memory_type: "
|
|
825
|
+
memory_type: "agent_memory",
|
|
914
826
|
uri: "recent://note/stats",
|
|
915
827
|
content: "hot context",
|
|
916
828
|
});
|
|
917
829
|
await handleToolCall.call(server, "create_memory", {
|
|
918
|
-
memory_type: "
|
|
830
|
+
memory_type: "project_memory",
|
|
919
831
|
uri: "core://agent/profile",
|
|
920
832
|
content: "long-term profile",
|
|
921
833
|
});
|
|
@@ -929,15 +841,15 @@ describe("McpServer memory tools", () => {
|
|
|
929
841
|
exceeded: false,
|
|
930
842
|
hardExceeded: false,
|
|
931
843
|
});
|
|
932
|
-
assert.equal(typedStats.by_type.task_list.count, 1);
|
|
933
|
-
assert.equal(typedStats.by_type.task_list.domainCount, 1);
|
|
934
|
-
assert.equal(typedStats.by_type.task_list.by_domain.task?.count, 1);
|
|
935
844
|
assert.equal(typedStats.by_type.recently_memory.count, 1);
|
|
936
845
|
assert.equal(typedStats.by_type.recently_memory.domainCount, 1);
|
|
937
|
-
assert.equal(typedStats.by_type.recently_memory.by_domain.
|
|
938
|
-
assert.equal(typedStats.by_type.
|
|
939
|
-
assert.equal(typedStats.by_type.
|
|
940
|
-
assert.equal(typedStats.by_type.
|
|
846
|
+
assert.equal(typedStats.by_type.recently_memory.by_domain.task?.count, 1);
|
|
847
|
+
assert.equal(typedStats.by_type.agent_memory.count, 1);
|
|
848
|
+
assert.equal(typedStats.by_type.agent_memory.domainCount, 1);
|
|
849
|
+
assert.equal(typedStats.by_type.agent_memory.by_domain.recent?.count, 1);
|
|
850
|
+
assert.equal(typedStats.by_type.project_memory.count, 1);
|
|
851
|
+
assert.equal(typedStats.by_type.project_memory.domainCount, 1);
|
|
852
|
+
assert.equal(typedStats.by_type.project_memory.by_domain.core?.count, 1);
|
|
941
853
|
});
|
|
942
854
|
});
|
|
943
855
|
it("reports combined memory stats after long-term memory changes", async () => {
|
|
@@ -946,32 +858,13 @@ describe("McpServer memory tools", () => {
|
|
|
946
858
|
const reportedStats = [];
|
|
947
859
|
attachMemoryStatsReporter(server, reportedStats);
|
|
948
860
|
await handleToolCall.call(server, "create_memory", {
|
|
949
|
-
memory_type: "
|
|
861
|
+
memory_type: "project_memory",
|
|
950
862
|
uri: "project://test-aws/permanent-memory-check",
|
|
951
863
|
content: "dashboard should see this permanent memory count",
|
|
952
864
|
});
|
|
953
865
|
assert.equal(reportedStats.length, 1);
|
|
954
|
-
assert.equal(reportedStats[0]?.by_type.
|
|
955
|
-
assert.equal(reportedStats[0]?.by_type.
|
|
956
|
-
});
|
|
957
|
-
});
|
|
958
|
-
it("reports combined memory stats after archiving recent memory", async () => {
|
|
959
|
-
await withMemoryServer(async (server) => {
|
|
960
|
-
const handleToolCall = getHandleToolCall(server);
|
|
961
|
-
const reportedStats = [];
|
|
962
|
-
attachMemoryStatsReporter(server, reportedStats);
|
|
963
|
-
await handleToolCall.call(server, "create_memory", {
|
|
964
|
-
memory_type: "recently_memory",
|
|
965
|
-
uri: "project://test-aws/hot-note",
|
|
966
|
-
content: "hot note that will become permanent",
|
|
967
|
-
});
|
|
968
|
-
await handleToolCall.call(server, "archive_recently_memory", {
|
|
969
|
-
uri: "project://test-aws/hot-note",
|
|
970
|
-
});
|
|
971
|
-
const latestStats = reportedStats.at(-1);
|
|
972
|
-
assert.equal(latestStats?.by_type.recently_memory.count, 0);
|
|
973
|
-
assert.equal(latestStats?.by_type.memory.count, 1);
|
|
974
|
-
assert.equal(latestStats?.by_type.memory.by_domain.project?.count, 1);
|
|
866
|
+
assert.equal(reportedStats[0]?.by_type.project_memory.count, 1);
|
|
867
|
+
assert.equal(reportedStats[0]?.by_type.project_memory.by_domain.project?.count, 1);
|
|
975
868
|
});
|
|
976
869
|
});
|
|
977
870
|
it("reports existing combined memory stats after auto registration", async () => {
|
|
@@ -979,7 +872,7 @@ describe("McpServer memory tools", () => {
|
|
|
979
872
|
const reportedStats = [];
|
|
980
873
|
const roleMemoryStore = Reflect.get(server, "roleMemoryStore");
|
|
981
874
|
await roleMemoryStore.createMemory({
|
|
982
|
-
memory_type: "
|
|
875
|
+
memory_type: "project_memory",
|
|
983
876
|
uri: "project://test-aws/existing-permanent-memory",
|
|
984
877
|
content: "existing role memory should be visible on dashboard startup",
|
|
985
878
|
});
|
|
@@ -999,75 +892,55 @@ describe("McpServer memory tools", () => {
|
|
|
999
892
|
const autoRegister = Reflect.get(server, "autoRegister");
|
|
1000
893
|
await autoRegister.call(server);
|
|
1001
894
|
assert.equal(reportedStats.length, 1);
|
|
1002
|
-
assert.equal(reportedStats[0]?.by_type.
|
|
1003
|
-
assert.equal(reportedStats[0]?.by_type.
|
|
895
|
+
assert.equal(reportedStats[0]?.by_type.project_memory.count, 1);
|
|
896
|
+
assert.equal(reportedStats[0]?.by_type.project_memory.by_domain.project?.count, 1);
|
|
1004
897
|
});
|
|
1005
898
|
});
|
|
1006
899
|
it("returns memory stats for one requested memory type", async () => {
|
|
1007
900
|
await withMemoryServer(async (server) => {
|
|
1008
901
|
const handleToolCall = getHandleToolCall(server);
|
|
1009
902
|
await handleToolCall.call(server, "create_memory", {
|
|
1010
|
-
memory_type: "
|
|
903
|
+
memory_type: "recently_memory",
|
|
1011
904
|
uri: "task://todo/stats",
|
|
1012
905
|
content: "temporary task",
|
|
1013
906
|
});
|
|
1014
907
|
await handleToolCall.call(server, "create_memory", {
|
|
1015
|
-
memory_type: "
|
|
908
|
+
memory_type: "agent_memory",
|
|
1016
909
|
uri: "recent://note/stats",
|
|
1017
910
|
content: "hot context",
|
|
1018
911
|
});
|
|
1019
912
|
await handleToolCall.call(server, "create_memory", {
|
|
1020
|
-
memory_type: "
|
|
913
|
+
memory_type: "project_memory",
|
|
1021
914
|
uri: "core://agent/profile",
|
|
1022
915
|
content: "long-term profile",
|
|
1023
916
|
});
|
|
1024
917
|
const stats = (await handleToolCall.call(server, "get_memory_stats", {
|
|
1025
|
-
memory_type: "
|
|
918
|
+
memory_type: "agent_memory",
|
|
1026
919
|
}));
|
|
1027
|
-
assert.equal(stats.memory_type, "
|
|
920
|
+
assert.equal(stats.memory_type, "agent_memory");
|
|
1028
921
|
assert.equal(stats.total, 1);
|
|
1029
|
-
assert.deepEqual(Object.keys(stats.by_type), ["
|
|
1030
|
-
assert.equal(stats.by_type.
|
|
1031
|
-
assert.equal(stats.by_type.
|
|
1032
|
-
const memoryStats = (await handleToolCall.call(server, "get_memory_stats", { memory_type: "
|
|
1033
|
-
assert.equal(memoryStats.memory_type, "
|
|
922
|
+
assert.deepEqual(Object.keys(stats.by_type), ["agent_memory"]);
|
|
923
|
+
assert.equal(stats.by_type.agent_memory?.domainCount, 1);
|
|
924
|
+
assert.equal(stats.by_type.agent_memory?.by_domain.recent?.count, 1);
|
|
925
|
+
const memoryStats = (await handleToolCall.call(server, "get_memory_stats", { memory_type: "project_memory" }));
|
|
926
|
+
assert.equal(memoryStats.memory_type, "project_memory");
|
|
1034
927
|
assert.equal(memoryStats.total, 1);
|
|
1035
|
-
assert.deepEqual(Object.keys(memoryStats.by_type), ["
|
|
1036
|
-
assert.equal(memoryStats.by_type.
|
|
1037
|
-
assert.equal(memoryStats.by_type.
|
|
1038
|
-
});
|
|
1039
|
-
});
|
|
1040
|
-
it("keeps structured details on memory capacity errors", async () => {
|
|
1041
|
-
await withMemoryServer(async (server) => {
|
|
1042
|
-
const handleToolCall = getHandleToolCall(server);
|
|
1043
|
-
for (let index = 0; index < 64; index += 1) {
|
|
1044
|
-
await handleToolCall.call(server, "create_memory", {
|
|
1045
|
-
memory_type: "recently_memory",
|
|
1046
|
-
uri: `recent://capacity/${index}`,
|
|
1047
|
-
content: `recent ${index}`,
|
|
1048
|
-
});
|
|
1049
|
-
}
|
|
1050
|
-
await assert.rejects(async () => {
|
|
1051
|
-
await handleToolCall.call(server, "create_memory", {
|
|
1052
|
-
memory_type: "recently_memory",
|
|
1053
|
-
uri: "recent://capacity/overflow",
|
|
1054
|
-
content: "overflow",
|
|
1055
|
-
});
|
|
1056
|
-
}, (error) => {
|
|
1057
|
-
assert.ok(error instanceof MemoryCapacityError);
|
|
1058
|
-
assert.equal(error.details.code, "MEMORY_TYPE_LIMIT_REACHED");
|
|
1059
|
-
assert.equal(error.details.memory_type, "recently_memory");
|
|
1060
|
-
assert.equal(error.details.domain, "recent");
|
|
1061
|
-
assert.equal(error.details.current, 64);
|
|
1062
|
-
assert.equal(error.details.limit, 64);
|
|
1063
|
-
assert.ok(error.details.recommended_actions.includes("archive_recently_memory({ uri })"));
|
|
1064
|
-
return true;
|
|
1065
|
-
});
|
|
928
|
+
assert.deepEqual(Object.keys(memoryStats.by_type), ["project_memory"]);
|
|
929
|
+
assert.equal(memoryStats.by_type.project_memory?.domainCount, 1);
|
|
930
|
+
assert.equal(memoryStats.by_type.project_memory?.by_domain.core?.count, 1);
|
|
1066
931
|
});
|
|
1067
932
|
});
|
|
1068
933
|
it("poll_message injects a cleanup notice when listable memory exceeds soft limits", async () => {
|
|
1069
934
|
await withMemoryServer(async (server) => {
|
|
1070
935
|
const handleToolCall = getHandleToolCall(server);
|
|
936
|
+
const directMessage = {
|
|
937
|
+
msgId: "dm-trigger-cleanup",
|
|
938
|
+
senderId: "agent-trigger",
|
|
939
|
+
senderName: "Trigger Agent",
|
|
940
|
+
content: "trigger cleanup notice",
|
|
941
|
+
requireReply: false,
|
|
942
|
+
timestamp: new Date().toISOString(),
|
|
943
|
+
};
|
|
1071
944
|
Reflect.set(server, "agentClient", {
|
|
1072
945
|
fetchUnreadMessages: async () => ({
|
|
1073
946
|
directMessages: [],
|
|
@@ -1078,21 +951,29 @@ describe("McpServer memory tools", () => {
|
|
|
1078
951
|
});
|
|
1079
952
|
for (let index = 0; index < 33; index += 1) {
|
|
1080
953
|
await handleToolCall.call(server, "create_memory", {
|
|
1081
|
-
memory_type: "
|
|
954
|
+
memory_type: "agent_memory",
|
|
1082
955
|
uri: `recent://cleanup/${index}`,
|
|
1083
956
|
content: `recent ${index}`,
|
|
1084
957
|
});
|
|
1085
958
|
}
|
|
959
|
+
// poll_message blocks until a real message arrives; cleanup notice is prepended.
|
|
960
|
+
const buffer = Reflect.get(server, "messageBuffer");
|
|
961
|
+
setTimeout(() => {
|
|
962
|
+
buffer.push(directMessage);
|
|
963
|
+
}, 50);
|
|
1086
964
|
const result = (await handleToolCall.call(server, "poll_message", {}));
|
|
1087
965
|
assert.equal(result.groupMessages.length, 0);
|
|
1088
|
-
|
|
966
|
+
// cleanup notice prepended before the real message
|
|
967
|
+
assert.equal(result.directMessages.length, 2);
|
|
1089
968
|
assert.match(result.directMessages[0]?.msgId, /^memory-cleanup-/);
|
|
1090
969
|
assert.equal(result.directMessages[0]?.senderId, "MCP-System");
|
|
1091
970
|
assert.equal(result.directMessages[0]?.receiverId, "agent-self");
|
|
1092
971
|
assert.match(result.directMessages[0]?.content ?? "", /本地 memory 已超过建议容量/);
|
|
1093
|
-
assert.match(result.directMessages[0]?.content ?? "", /
|
|
972
|
+
assert.match(result.directMessages[0]?.content ?? "", /agent_memory\/recent 类型下当前 33 条 memory/);
|
|
1094
973
|
assert.match(result.directMessages[0]?.content ?? "", /get_memory_stats/);
|
|
1095
974
|
assert.match(result.directMessages[0]?.prompt ?? "", /无需持久化/);
|
|
975
|
+
// real message follows the cleanup notice
|
|
976
|
+
assert.equal(result.directMessages[1]?.msgId, directMessage.msgId);
|
|
1096
977
|
});
|
|
1097
978
|
});
|
|
1098
979
|
it("poll_message should claim backend tasks before returning a cleanup notice", async () => {
|
|
@@ -1121,7 +1002,7 @@ describe("McpServer memory tools", () => {
|
|
|
1121
1002
|
});
|
|
1122
1003
|
for (let index = 0; index < 33; index += 1) {
|
|
1123
1004
|
await handleToolCall.call(server, "create_memory", {
|
|
1124
|
-
memory_type: "
|
|
1005
|
+
memory_type: "agent_memory",
|
|
1125
1006
|
uri: `recent://cleanup-claim/${index}`,
|
|
1126
1007
|
content: `recent ${index}`,
|
|
1127
1008
|
});
|
|
@@ -1149,7 +1030,7 @@ describe("McpServer memory tools", () => {
|
|
|
1149
1030
|
});
|
|
1150
1031
|
for (let index = 0; index < 33; index += 1) {
|
|
1151
1032
|
await handleToolCall.call(server, "create_memory", {
|
|
1152
|
-
memory_type: "
|
|
1033
|
+
memory_type: "agent_memory",
|
|
1153
1034
|
uri: `recent://cleanup-get/${index}`,
|
|
1154
1035
|
content: `recent ${index}`,
|
|
1155
1036
|
});
|
|
@@ -1162,7 +1043,7 @@ describe("McpServer memory tools", () => {
|
|
|
1162
1043
|
assert.equal(result.directMessages[0]?.senderId, "MCP-System");
|
|
1163
1044
|
assert.equal(result.directMessages[0]?.receiverId, "agent-self");
|
|
1164
1045
|
assert.match(result.directMessages[0]?.content ?? "", /本地 memory 已超过建议容量/);
|
|
1165
|
-
assert.match(result.directMessages[0]?.content ?? "", /
|
|
1046
|
+
assert.match(result.directMessages[0]?.content ?? "", /agent_memory\/recent 类型下当前 33 条 memory/);
|
|
1166
1047
|
assert.match(result.directMessages[0]?.prompt ?? "", /无需持久化/);
|
|
1167
1048
|
});
|
|
1168
1049
|
});
|
|
@@ -1170,7 +1051,7 @@ describe("McpServer memory tools", () => {
|
|
|
1170
1051
|
await withMemoryServer(async (server) => {
|
|
1171
1052
|
const handleToolCall = getHandleToolCall(server);
|
|
1172
1053
|
await handleToolCall.call(server, "create_memory", {
|
|
1173
|
-
memory_type: "
|
|
1054
|
+
memory_type: "project_memory",
|
|
1174
1055
|
uri: "core://agent/incomplete-update",
|
|
1175
1056
|
content: "original",
|
|
1176
1057
|
});
|
|
@@ -1196,7 +1077,7 @@ describe("McpServer memory tools", () => {
|
|
|
1196
1077
|
});
|
|
1197
1078
|
const handleToolCall = getHandleToolCall(server);
|
|
1198
1079
|
await handleToolCall.call(server, "create_memory", {
|
|
1199
|
-
memory_type: "
|
|
1080
|
+
memory_type: "project_memory",
|
|
1200
1081
|
uri: "core://agent/private",
|
|
1201
1082
|
content: "secret local memory content",
|
|
1202
1083
|
});
|
|
@@ -1212,7 +1093,7 @@ describe("McpServer memory tools", () => {
|
|
|
1212
1093
|
});
|
|
1213
1094
|
assert.deepEqual(reported[0], {
|
|
1214
1095
|
name: "create_memory",
|
|
1215
|
-
args: { uri: "core://agent/private", memory_type: "
|
|
1096
|
+
args: { uri: "core://agent/private", memory_type: "project_memory" },
|
|
1216
1097
|
});
|
|
1217
1098
|
assert.deepEqual(reported[1], {
|
|
1218
1099
|
name: "update_memory",
|
|
@@ -1268,12 +1149,12 @@ describe("McpServer memory tools", () => {
|
|
|
1268
1149
|
await withMemoryServer(async (server) => {
|
|
1269
1150
|
const handleToolCall = getHandleToolCall(server);
|
|
1270
1151
|
await handleToolCall.call(server, "create_memory", {
|
|
1271
|
-
memory_type: "
|
|
1152
|
+
memory_type: "project_memory",
|
|
1272
1153
|
uri: "core://agent/duplicate",
|
|
1273
1154
|
content: "first",
|
|
1274
1155
|
});
|
|
1275
1156
|
await assert.rejects(() => handleToolCall.call(server, "create_memory", {
|
|
1276
|
-
memory_type: "
|
|
1157
|
+
memory_type: "project_memory",
|
|
1277
1158
|
uri: "core://agent/duplicate",
|
|
1278
1159
|
content: "second",
|
|
1279
1160
|
}), /Memory already exists/);
|
|
@@ -1287,7 +1168,7 @@ describe("McpServer memory tools", () => {
|
|
|
1287
1168
|
await withMemoryServer(async (server) => {
|
|
1288
1169
|
const handleToolCall = getHandleToolCall(server);
|
|
1289
1170
|
await handleToolCall.call(server, "create_memory", {
|
|
1290
|
-
memory_type: "
|
|
1171
|
+
memory_type: "project_memory",
|
|
1291
1172
|
uri: "core://agent/noop",
|
|
1292
1173
|
content: "original",
|
|
1293
1174
|
});
|
|
@@ -1301,7 +1182,7 @@ describe("McpServer memory tools", () => {
|
|
|
1301
1182
|
await withMemoryServer(async (server) => {
|
|
1302
1183
|
const handleToolCall = getHandleToolCall(server);
|
|
1303
1184
|
await assert.rejects(() => handleToolCall.call(server, "create_memory", {
|
|
1304
|
-
memory_type: "
|
|
1185
|
+
memory_type: "project_memory",
|
|
1305
1186
|
uri: "core://agent/missing-bound-file",
|
|
1306
1187
|
content: "memory with non-existent bound file",
|
|
1307
1188
|
bound_files: ["./non-existent-file.ts"],
|
|
@@ -1312,13 +1193,13 @@ describe("McpServer memory tools", () => {
|
|
|
1312
1193
|
await withMemoryServer(async (server) => {
|
|
1313
1194
|
const handleToolCall = getHandleToolCall(server);
|
|
1314
1195
|
await handleToolCall.call(server, "create_memory", {
|
|
1315
|
-
memory_type: "
|
|
1196
|
+
memory_type: "project_memory",
|
|
1316
1197
|
uri: "core://agent/update-with-missing-bound-file",
|
|
1317
1198
|
content: "original content",
|
|
1318
1199
|
});
|
|
1319
1200
|
await assert.rejects(() => handleToolCall.call(server, "update_memory", {
|
|
1320
1201
|
uri: "core://agent/update-with-missing-bound-file",
|
|
1321
|
-
memory_type: "
|
|
1202
|
+
memory_type: "project_memory",
|
|
1322
1203
|
old_string: "original",
|
|
1323
1204
|
new_string: "updated",
|
|
1324
1205
|
bound_files: ["./non-existent-file.ts"],
|
|
@@ -1335,7 +1216,7 @@ describe("McpServer memory tools", () => {
|
|
|
1335
1216
|
await withMemoryServer(async (server) => {
|
|
1336
1217
|
const handleToolCall = getHandleToolCall(server);
|
|
1337
1218
|
const created = await handleToolCall.call(server, "create_memory", {
|
|
1338
|
-
memory_type: "
|
|
1219
|
+
memory_type: "project_memory",
|
|
1339
1220
|
uri: "core://agent/valid-bound-file",
|
|
1340
1221
|
content: "memory with valid bound file",
|
|
1341
1222
|
bound_files: ["./existing-file.ts"],
|
|
@@ -1364,7 +1245,7 @@ describe("McpServer memory tools", () => {
|
|
|
1364
1245
|
await withMemoryServer(async (server) => {
|
|
1365
1246
|
const handleToolCall = getHandleToolCall(server);
|
|
1366
1247
|
await assert.rejects(() => handleToolCall.call(server, "create_memory", {
|
|
1367
|
-
memory_type: "
|
|
1248
|
+
memory_type: "project_memory",
|
|
1368
1249
|
uri: "core://agent/mixed-bound-file",
|
|
1369
1250
|
content: "memory with mixed bound files",
|
|
1370
1251
|
bound_files: ["./existing-file.ts", "./non-existent-file.ts"],
|
|
@@ -1385,14 +1266,14 @@ describe("McpServer memory tools", () => {
|
|
|
1385
1266
|
await withMemoryServer(async (server) => {
|
|
1386
1267
|
const handleToolCall = getHandleToolCall(server);
|
|
1387
1268
|
await handleToolCall.call(server, "create_memory", {
|
|
1388
|
-
memory_type: "
|
|
1269
|
+
memory_type: "project_memory",
|
|
1389
1270
|
uri: "core://agent/update-without-bound-files",
|
|
1390
1271
|
content: "original content",
|
|
1391
1272
|
});
|
|
1392
1273
|
// Update without bound_files should succeed even if existing bound files are invalid
|
|
1393
1274
|
const updated = await handleToolCall.call(server, "update_memory", {
|
|
1394
1275
|
uri: "core://agent/update-without-bound-files",
|
|
1395
|
-
memory_type: "
|
|
1276
|
+
memory_type: "project_memory",
|
|
1396
1277
|
old_string: "original",
|
|
1397
1278
|
new_string: "updated",
|
|
1398
1279
|
});
|
|
@@ -1882,4 +1763,141 @@ describe("AgentClient group room aggregation", () => {
|
|
|
1882
1763
|
assert.equal(result.count, 2);
|
|
1883
1764
|
});
|
|
1884
1765
|
});
|
|
1766
|
+
describe("McpServer todo reminder on poll_message", () => {
|
|
1767
|
+
// 使用唯一 agentId 避免污染开发者真实 todo 文件;每次测试写入并清理
|
|
1768
|
+
const testAgentId = `test-todo-reminder-${process.pid}-${Date.now()}`;
|
|
1769
|
+
const todoDir = path.join(os.homedir(), ".acode", "todos");
|
|
1770
|
+
const todoPath = path.join(todoDir, `${testAgentId}.json`);
|
|
1771
|
+
async function writeTodoFile(todos) {
|
|
1772
|
+
await mkdir(todoDir, { recursive: true });
|
|
1773
|
+
await writeFile(todoPath, JSON.stringify({
|
|
1774
|
+
agentId: testAgentId,
|
|
1775
|
+
updatedAt: new Date().toISOString(),
|
|
1776
|
+
background: "test background",
|
|
1777
|
+
todos,
|
|
1778
|
+
}), "utf-8");
|
|
1779
|
+
}
|
|
1780
|
+
async function cleanupTodoFile() {
|
|
1781
|
+
try {
|
|
1782
|
+
await rm(todoPath, { force: true });
|
|
1783
|
+
}
|
|
1784
|
+
catch {
|
|
1785
|
+
// 忽略清理失败
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
function createServerForTodo() {
|
|
1789
|
+
return createServerWithUnread({ directMessages: [], groupMessages: [] }, {
|
|
1790
|
+
getState: () => ({ agentId: testAgentId }),
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
function makeDirectMessage(msgId) {
|
|
1794
|
+
return {
|
|
1795
|
+
msgId,
|
|
1796
|
+
senderId: "agent-wake",
|
|
1797
|
+
senderName: "Wake Agent",
|
|
1798
|
+
content: `wake message ${msgId}`,
|
|
1799
|
+
requireReply: false,
|
|
1800
|
+
timestamp: new Date().toISOString(),
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1803
|
+
it("injects todo reminder when incomplete todos exist", async () => {
|
|
1804
|
+
await writeTodoFile([
|
|
1805
|
+
{ content: "任务A", status: "pending", priority: "high" },
|
|
1806
|
+
{ content: "任务B", status: "completed", priority: "low" },
|
|
1807
|
+
]);
|
|
1808
|
+
try {
|
|
1809
|
+
const server = createServerForTodo();
|
|
1810
|
+
const handleToolCall = getHandleToolCall(server);
|
|
1811
|
+
const result = (await handleToolCall.call(server, "poll_message", {}));
|
|
1812
|
+
assert.equal(result.directMessages.length, 1);
|
|
1813
|
+
const notice = result.directMessages[0];
|
|
1814
|
+
assert.equal(notice.senderId, "MCP-System");
|
|
1815
|
+
assert.equal(notice.senderName, "系统");
|
|
1816
|
+
assert.match(notice.content, /Todo 列表存在 1 项未完成/);
|
|
1817
|
+
}
|
|
1818
|
+
finally {
|
|
1819
|
+
await cleanupTodoFile();
|
|
1820
|
+
}
|
|
1821
|
+
});
|
|
1822
|
+
it("does not inject todo reminder when all todos are completed", async () => {
|
|
1823
|
+
await writeTodoFile([
|
|
1824
|
+
{ content: "任务A", status: "completed", priority: "high" },
|
|
1825
|
+
]);
|
|
1826
|
+
try {
|
|
1827
|
+
const server = createServerForTodo();
|
|
1828
|
+
const buffer = Reflect.get(server, "messageBuffer");
|
|
1829
|
+
const wake = makeDirectMessage("wake-completed");
|
|
1830
|
+
setTimeout(() => buffer.push(wake), 50);
|
|
1831
|
+
const handleToolCall = getHandleToolCall(server);
|
|
1832
|
+
const result = (await handleToolCall.call(server, "poll_message", {}));
|
|
1833
|
+
// 全完成时不应注入 todo 通知,仅返回 push 的唤醒消息
|
|
1834
|
+
assert.equal(result.directMessages.length, 1);
|
|
1835
|
+
assert.equal(result.directMessages[0].msgId, "wake-completed");
|
|
1836
|
+
}
|
|
1837
|
+
finally {
|
|
1838
|
+
await cleanupTodoFile();
|
|
1839
|
+
}
|
|
1840
|
+
});
|
|
1841
|
+
it("does not repeat todo reminder when fingerprint unchanged", async () => {
|
|
1842
|
+
await writeTodoFile([
|
|
1843
|
+
{ content: "任务A", status: "pending", priority: "high" },
|
|
1844
|
+
]);
|
|
1845
|
+
try {
|
|
1846
|
+
const server = createServerForTodo();
|
|
1847
|
+
const handleToolCall = getHandleToolCall(server);
|
|
1848
|
+
// 第一次:应返回 todo 通知
|
|
1849
|
+
const result1 = (await handleToolCall.call(server, "poll_message", {}));
|
|
1850
|
+
assert.equal(result1.directMessages.length, 1);
|
|
1851
|
+
assert.match(result1.directMessages[0].content, /Todo 列表存在/);
|
|
1852
|
+
// 第二次:指纹未变,应进入阻塞等待。push 一条消息让 poll 返回
|
|
1853
|
+
const buffer = Reflect.get(server, "messageBuffer");
|
|
1854
|
+
const wake = makeDirectMessage("wake-unchanged");
|
|
1855
|
+
setTimeout(() => buffer.push(wake), 50);
|
|
1856
|
+
const result2 = (await handleToolCall.call(server, "poll_message", {}));
|
|
1857
|
+
// 第二次不应再注入 todo 通知,仅返回 push 的唤醒消息
|
|
1858
|
+
assert.equal(result2.directMessages.length, 1);
|
|
1859
|
+
assert.equal(result2.directMessages[0].msgId, "wake-unchanged");
|
|
1860
|
+
}
|
|
1861
|
+
finally {
|
|
1862
|
+
await cleanupTodoFile();
|
|
1863
|
+
}
|
|
1864
|
+
});
|
|
1865
|
+
it("re-injects todo reminder when todos change after being notified", async () => {
|
|
1866
|
+
await writeTodoFile([
|
|
1867
|
+
{ content: "任务A", status: "pending", priority: "high" },
|
|
1868
|
+
]);
|
|
1869
|
+
try {
|
|
1870
|
+
const server = createServerForTodo();
|
|
1871
|
+
const handleToolCall = getHandleToolCall(server);
|
|
1872
|
+
// 第一次:返回 todo 通知(1 项未完成)
|
|
1873
|
+
const result1 = (await handleToolCall.call(server, "poll_message", {}));
|
|
1874
|
+
assert.match(result1.directMessages[0].content, /Todo 列表存在 1 项未完成/);
|
|
1875
|
+
// 修改 todo:新增一项未完成(指纹变化)
|
|
1876
|
+
await writeTodoFile([
|
|
1877
|
+
{ content: "任务A", status: "pending", priority: "high" },
|
|
1878
|
+
{ content: "任务B", status: "in_progress", priority: "medium" },
|
|
1879
|
+
]);
|
|
1880
|
+
// 第二次:指纹变化,应再次返回 todo 通知(2 项未完成)
|
|
1881
|
+
const result2 = (await handleToolCall.call(server, "poll_message", {}));
|
|
1882
|
+
assert.equal(result2.directMessages.length, 1);
|
|
1883
|
+
assert.match(result2.directMessages[0].content, /Todo 列表存在 2 项未完成/);
|
|
1884
|
+
}
|
|
1885
|
+
finally {
|
|
1886
|
+
await cleanupTodoFile();
|
|
1887
|
+
}
|
|
1888
|
+
});
|
|
1889
|
+
it("does not inject todo reminder when todo file is absent", async () => {
|
|
1890
|
+
// 确保文件不存在
|
|
1891
|
+
await cleanupTodoFile();
|
|
1892
|
+
const server = createServerForTodo();
|
|
1893
|
+
const buffer = Reflect.get(server, "messageBuffer");
|
|
1894
|
+
const wake = makeDirectMessage("wake-no-file");
|
|
1895
|
+
setTimeout(() => buffer.push(wake), 50);
|
|
1896
|
+
const handleToolCall = getHandleToolCall(server);
|
|
1897
|
+
const result = (await handleToolCall.call(server, "poll_message", {}));
|
|
1898
|
+
// 无 todo 文件不应注入通知,仅返回 push 的唤醒消息
|
|
1899
|
+
assert.equal(result.directMessages.length, 1);
|
|
1900
|
+
assert.equal(result.directMessages[0].msgId, "wake-no-file");
|
|
1901
|
+
});
|
|
1902
|
+
});
|
|
1885
1903
|
//# sourceMappingURL=mcp-server.test.js.map
|