mu-agent-bridge 1.0.73 → 1.0.78

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.
Files changed (152) hide show
  1. package/README.md +12 -8
  2. package/dist/src-ts/cli.js +67 -37
  3. package/dist/src-ts/control-server.js +7 -28
  4. package/dist/src-ts/core-updater.js +141 -33
  5. package/dist/src-ts/daemon-process.js +2 -1
  6. package/dist/src-ts/dsh-agent.js +7 -2
  7. package/dist/src-ts/http-agent.js +36 -0
  8. package/dist/src-ts/plugin-manager.js +185 -58
  9. package/dist/src-ts/plugins/abweb/index.js +1 -1
  10. package/dist/src-ts/plugins/abweb/public/app.js +8 -6
  11. package/dist/src-ts/plugins/abweb/public/index.html +3 -3
  12. package/dist/src-ts/plugins/aun/attachments.js +3 -21
  13. package/dist/src-ts/plugins/aun/index.js +89 -11
  14. package/dist/src-ts/plugins/aun/messages.js +1 -1
  15. package/dist/src-ts/plugins/aun/public/app.js +2 -1
  16. package/dist/src-ts/plugins/aun/public/index.html +1 -1
  17. package/dist/src-ts/plugins/cdp-draft.js +5 -2
  18. package/dist/src-ts/plugins/chatgpt/index.js +3 -2
  19. package/dist/src-ts/plugins/claude-cli/index.js +1 -1
  20. package/dist/src-ts/plugins/desktop-launch.js +44 -3
  21. package/dist/src-ts/plugins/doubao/cdp-client.js +231 -45
  22. package/dist/src-ts/plugins/doubao/index.js +119 -7
  23. package/dist/src-ts/plugins/doubao/native-task.js +134 -0
  24. package/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
  25. package/dist/src-ts/plugins/dsh/index.js +102 -23
  26. package/dist/src-ts/plugins/dsh/session-history.js +31 -3
  27. package/dist/src-ts/plugins/feishu/index.js +1 -1
  28. package/dist/src-ts/plugins/personal-assistant/index.js +29 -8
  29. package/dist/src-ts/plugins/personal-assistant/model-client.js +20 -6
  30. package/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
  31. package/dist/src-ts/plugins/personal-assistant/tools.js +4 -3
  32. package/dist/src-ts/plugins/qwenwork/cdp-client.js +43 -7
  33. package/dist/src-ts/plugins/qwenwork/index.js +52 -18
  34. package/dist/src-ts/plugins/workbuddy/cdp-client.js +349 -83
  35. package/dist/src-ts/plugins/workbuddy/index.js +24 -12
  36. package/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
  37. package/dist/src-ts/plugins/zcode/index.js +97 -0
  38. package/dist/src-ts/session-management.js +27 -8
  39. package/dist/src-ts/version-manager.js +6 -3
  40. package/dist/tests-ts/abweb-model-config.test.js +44 -41
  41. package/dist/tests-ts/aun-attachments.test.js +19 -17
  42. package/dist/tests-ts/aun-default-owner-page.test.js +2 -1
  43. package/dist/tests-ts/aun-messages.test.js +14 -0
  44. package/dist/tests-ts/aun-plugin.test.js +207 -19
  45. package/dist/tests-ts/bundled-package.test.js +1 -1
  46. package/dist/tests-ts/cdp-draft-recovery.test.js +182 -3
  47. package/dist/tests-ts/chatgpt-plugin.test.js +19 -0
  48. package/dist/tests-ts/control-server.test.js +20 -0
  49. package/dist/tests-ts/core-updater.test.js +215 -46
  50. package/dist/tests-ts/daemon-process.test.js +126 -1
  51. package/dist/tests-ts/desktop-launch.test.js +73 -0
  52. package/dist/tests-ts/doubao-native-task.test.js +237 -0
  53. package/dist/tests-ts/doubao-plugin.test.js +688 -19
  54. package/dist/tests-ts/dsh-agent.test.js +91 -19
  55. package/dist/tests-ts/dsh-cdp.test.js +148 -0
  56. package/dist/tests-ts/dsh-history.test.js +37 -0
  57. package/dist/tests-ts/feishu-plugin.test.js +1 -1
  58. package/dist/tests-ts/http-agent.test.js +18 -0
  59. package/dist/tests-ts/local-cli.test.js +29 -2
  60. package/dist/tests-ts/model-provider-cancellation.test.js +2 -0
  61. package/dist/tests-ts/native-session-management.test.js +8 -7
  62. package/dist/tests-ts/personal-assistant-coordination.test.js +16 -0
  63. package/dist/tests-ts/personal-assistant-extensions.test.js +7 -1
  64. package/dist/tests-ts/personal-assistant-memory.test.js +117 -0
  65. package/dist/tests-ts/personal-assistant.test.js +277 -3
  66. package/dist/tests-ts/platform-integration.test.js +60 -1
  67. package/dist/tests-ts/plugin-manager.test.js +78 -6
  68. package/dist/tests-ts/plugin-upgrade-deadline.test.js +354 -0
  69. package/dist/tests-ts/publish-packages.test.js +1 -1
  70. package/dist/tests-ts/qwenwork-plugin.test.js +30 -0
  71. package/dist/tests-ts/qwenwork-reconnect.test.js +195 -0
  72. package/dist/tests-ts/qwenwork-sse.test.js +33 -0
  73. package/dist/tests-ts/session-access-defaults.test.js +112 -0
  74. package/dist/tests-ts/session-management.test.js +8 -8
  75. package/dist/tests-ts/version-manager.test.js +40 -0
  76. package/dist/tests-ts/workbuddy-cdp-recovery.test.js +311 -0
  77. package/dist/tests-ts/workbuddy-plugin.test.js +356 -13
  78. package/dist/tests-ts/zcode-cdp.test.js +894 -0
  79. package/dist/tests-ts/zcode-plugin.test.js +396 -0
  80. package/package.json +1 -1
  81. package/plugins/abweb/dist/src-ts/plugins/abweb/index.js +1 -1
  82. package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.js +8 -6
  83. package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.ts +7 -5
  84. package/plugins/abweb/dist/src-ts/plugins/abweb/public/index.html +3 -3
  85. package/plugins/abweb/package.json +1 -1
  86. package/plugins/abweb/plugin.json +1 -1
  87. package/plugins/aun/config.schema.json +1 -1
  88. package/plugins/aun/dist/src-ts/plugins/aun/attachments.js +3 -21
  89. package/plugins/aun/dist/src-ts/plugins/aun/index.js +89 -11
  90. package/plugins/aun/dist/src-ts/plugins/aun/messages.js +1 -1
  91. package/plugins/aun/dist/src-ts/plugins/aun/public/app.js +2 -1
  92. package/plugins/aun/dist/src-ts/plugins/aun/public/index.html +1 -1
  93. package/plugins/aun/package.json +1 -1
  94. package/plugins/aun/plugin.json +1 -1
  95. package/plugins/chatgpt/dist/src-ts/plugins/cdp-draft.js +5 -2
  96. package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/index.js +3 -2
  97. package/plugins/chatgpt/dist/src-ts/plugins/desktop-launch.js +44 -3
  98. package/plugins/claude-cli/dist/src-ts/plugins/claude-cli/index.js +1 -1
  99. package/plugins/claude-cli/package.json +1 -1
  100. package/plugins/claude-cli/plugin.json +1 -1
  101. package/plugins/doubao/config.schema.json +2 -1
  102. package/plugins/doubao/dist/src-ts/plugins/desktop-launch.js +44 -3
  103. package/plugins/doubao/dist/src-ts/plugins/doubao/cdp-client.js +231 -45
  104. package/plugins/doubao/dist/src-ts/plugins/doubao/index.js +119 -7
  105. package/plugins/doubao/dist/src-ts/plugins/doubao/native-task.js +134 -0
  106. package/plugins/doubao/package.json +1 -1
  107. package/plugins/doubao/plugin.json +1 -1
  108. package/plugins/dsh/config.schema.json +5 -2
  109. package/plugins/dsh/dist/src-ts/dsh-agent.js +7 -2
  110. package/plugins/dsh/dist/src-ts/plugins/desktop-launch.js +44 -3
  111. package/plugins/dsh/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
  112. package/plugins/dsh/dist/src-ts/plugins/dsh/index.js +102 -23
  113. package/plugins/dsh/dist/src-ts/plugins/dsh/session-history.js +31 -3
  114. package/plugins/dsh/package.json +1 -1
  115. package/plugins/dsh/plugin.json +1 -1
  116. package/plugins/feishu/dist/src-ts/plugins/feishu/index.js +1 -1
  117. package/plugins/feishu/package.json +1 -1
  118. package/plugins/feishu/plugin.json +1 -1
  119. package/plugins/personal-assistant/config.schema.json +3 -2
  120. package/plugins/personal-assistant/dist/src-ts/attachments.js +62 -0
  121. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/index.js +29 -8
  122. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/model-client.js +20 -6
  123. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
  124. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/tools.js +4 -3
  125. package/plugins/personal-assistant/package.json +2 -2
  126. package/plugins/personal-assistant/plugin.json +1 -1
  127. package/plugins/qwenwork/dist/src-ts/plugins/cdp-draft.js +5 -2
  128. package/plugins/qwenwork/dist/src-ts/plugins/desktop-launch.js +44 -3
  129. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/cdp-client.js +43 -7
  130. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/index.js +52 -18
  131. package/plugins/qwenwork/package.json +1 -1
  132. package/plugins/qwenwork/plugin.json +1 -1
  133. package/plugins/workbuddy/config.schema.json +1 -1
  134. package/plugins/workbuddy/dist/src-ts/plugins/desktop-launch.js +44 -3
  135. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cdp-client.js +349 -83
  136. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/index.js +24 -12
  137. package/plugins/workbuddy/package.json +1 -1
  138. package/plugins/workbuddy/plugin.json +1 -1
  139. package/plugins/zcode/config.schema.json +13 -0
  140. package/plugins/zcode/dist/src-ts/agent.js +69 -0
  141. package/plugins/zcode/dist/src-ts/attachments.js +62 -0
  142. package/plugins/zcode/dist/src-ts/plugin.js +13 -0
  143. package/plugins/zcode/dist/src-ts/plugins/desktop-launch.js +238 -0
  144. package/plugins/zcode/dist/src-ts/plugins/workbuddy/cdp-client.js +896 -0
  145. package/plugins/zcode/dist/src-ts/plugins/workbuddy/cli-client.js +39 -0
  146. package/plugins/zcode/dist/src-ts/plugins/workbuddy/desktop-launch.js +10 -0
  147. package/plugins/zcode/dist/src-ts/plugins/workbuddy/index.js +567 -0
  148. package/plugins/zcode/dist/src-ts/plugins/workbuddy/session-history.js +121 -0
  149. package/plugins/zcode/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
  150. package/plugins/zcode/dist/src-ts/plugins/zcode/index.js +97 -0
  151. package/plugins/zcode/package.json +16 -0
  152. package/plugins/zcode/plugin.json +11 -0
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const strict_1 = __importDefault(require("node:assert/strict"));
7
+ const node_test_1 = require("node:test");
8
+ const promises_1 = require("node:fs/promises");
9
+ const node_os_1 = require("node:os");
10
+ const node_path_1 = require("node:path");
11
+ const session_memory_1 = require("../src-ts/plugins/personal-assistant/session-memory");
12
+ const turn = (content) => [{ role: "user", content }, { role: "assistant", content: `回答:${content}` }];
13
+ const toolTurn = [
14
+ { role: "user", content: "调用 WorkBuddy 记住 PA_TOOL" },
15
+ { role: "assistant", content: null, tool_calls: [{ id: "call-1", type: "function", function: { name: "agents_call", arguments: '{"id":"workbuddy","task":"记住 PA_TOOL"}' } }] },
16
+ { role: "tool", tool_call_id: "call-1", name: "agents_call", content: '{"text":"已记住 PA_TOOL"}' },
17
+ { role: "assistant", content: "WorkBuddy 已记住" },
18
+ ];
19
+ (0, node_test_1.test)("会话历史裁剪保留完整轮次和工具调用配对", async () => {
20
+ const dataDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "pa-memory-trim-"));
21
+ try {
22
+ const memory = new session_memory_1.PersonalAssistantSessionMemory(dataDir);
23
+ await memory.save("thread", [...toolTurn, ...Array.from({ length: 19 }, (_, i) => turn(String(i))).flat()]);
24
+ const result = await memory.load("thread");
25
+ strict_1.default.equal(result.length, 38);
26
+ strict_1.default.equal(result[0].role, "user");
27
+ strict_1.default.equal(result.some(message => message.role === "tool"), false);
28
+ await memory.save("tool-thread", toolTurn);
29
+ strict_1.default.deepEqual(await new session_memory_1.PersonalAssistantSessionMemory(dataDir).load("tool-thread"), toolTurn);
30
+ }
31
+ finally {
32
+ await (0, promises_1.rm)(dataDir, { recursive: true, force: true });
33
+ }
34
+ });
35
+ (0, node_test_1.test)("并发首次读取和保存不遗漏不同会话,文件保持私有", async () => {
36
+ const dataDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "pa-memory-concurrent-"));
37
+ try {
38
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dataDir, "model-sessions.json"), JSON.stringify({ old: turn("旧记录") }));
39
+ const memory = new session_memory_1.PersonalAssistantSessionMemory(dataDir);
40
+ strict_1.default.deepEqual(await Promise.all([memory.load("old"), memory.load("old")]), [turn("旧记录"), turn("旧记录")]);
41
+ await Promise.all(Array.from({ length: 10 }, (_, i) => memory.save(`thread-${i}`, turn(`内容-${i}`))));
42
+ const restored = new session_memory_1.PersonalAssistantSessionMemory(dataDir);
43
+ for (let i = 0; i < 10; i++)
44
+ strict_1.default.deepEqual(await restored.load(`thread-${i}`), turn(`内容-${i}`));
45
+ if (process.platform !== "win32")
46
+ strict_1.default.equal((await (0, promises_1.stat)((0, node_path_1.join)(dataDir, "model-sessions.json"))).mode & 0o777, 0o600);
47
+ }
48
+ finally {
49
+ await (0, promises_1.rm)(dataDir, { recursive: true, force: true });
50
+ }
51
+ });
52
+ (0, node_test_1.test)("损坏历史不回显正文或把多余字段带入模型", async () => {
53
+ const dataDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "pa-memory-invalid-"));
54
+ const warnings = [];
55
+ try {
56
+ const file = (0, node_path_1.join)(dataDir, "model-sessions.json");
57
+ await (0, promises_1.writeFile)(file, '{"private-token-secret-value": malformed');
58
+ const memory = new session_memory_1.PersonalAssistantSessionMemory(dataDir, (...args) => warnings.push(args));
59
+ strict_1.default.deepEqual(await memory.load("old"), []);
60
+ strict_1.default.equal(warnings.length, 1);
61
+ strict_1.default.doesNotMatch(JSON.stringify(warnings), /private-token-secret-value/);
62
+ await (0, promises_1.writeFile)(file, JSON.stringify({ good: turn("可用"), bad: [{ role: "user", content: "测试", secret: "private-token-secret-value" }, { role: "tool", content: "孤立工具结果", tool_call_id: "missing" }] }));
63
+ const restored = new session_memory_1.PersonalAssistantSessionMemory(dataDir);
64
+ strict_1.default.deepEqual(await restored.load("good"), turn("可用"));
65
+ strict_1.default.deepEqual(await restored.load("bad"), []);
66
+ }
67
+ finally {
68
+ await (0, promises_1.rm)(dataDir, { recursive: true, force: true });
69
+ }
70
+ });
71
+ (0, node_test_1.test)("历史条数与字符数超限时丢弃完整旧轮次,容量超限淘汰最旧会话", async () => {
72
+ const dataDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "pa-memory-limit-"));
73
+ try {
74
+ const memory = new session_memory_1.PersonalAssistantSessionMemory(dataDir);
75
+ await memory.save("large", turn("字".repeat(121_000)));
76
+ strict_1.default.ok(JSON.stringify(await memory.load("large")).length <= 120_000);
77
+ for (let i = 0; i < 130; i++)
78
+ await memory.save(`s-${i}`, turn(String(i)));
79
+ const raw = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(dataDir, "model-sessions.json"), "utf8"));
80
+ strict_1.default.equal(Object.keys(raw).length, 128);
81
+ strict_1.default.deepEqual(await memory.load("s-0"), []);
82
+ strict_1.default.deepEqual(await memory.load("s-129"), turn("129"));
83
+ }
84
+ finally {
85
+ await (0, promises_1.rm)(dataDir, { recursive: true, force: true });
86
+ }
87
+ });
88
+ (0, node_test_1.test)("历史写盘失败保留内存上下文并记录安全提示", async () => {
89
+ const dataDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "pa-memory-write-failure-"));
90
+ const warnings = [];
91
+ try {
92
+ const blocked = (0, node_path_1.join)(dataDir, "不可写目录");
93
+ await (0, promises_1.writeFile)(blocked, "阻挡目录创建");
94
+ const memory = new session_memory_1.PersonalAssistantSessionMemory(blocked, (...args) => warnings.push(args));
95
+ await memory.save("thread", turn("有效回复"));
96
+ strict_1.default.deepEqual(await memory.load("thread"), turn("有效回复"));
97
+ strict_1.default.ok(JSON.stringify(warnings).includes("保存失败"));
98
+ strict_1.default.doesNotMatch(JSON.stringify(warnings), /有效回复|不可写目录/);
99
+ }
100
+ finally {
101
+ await (0, promises_1.rm)(dataDir, { recursive: true, force: true });
102
+ }
103
+ });
104
+ (0, node_test_1.test)("格式错误的新历史不会删除先前可用的内存记录", async () => {
105
+ const dataDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "pa-memory-invalid-save-"));
106
+ const warnings = [];
107
+ try {
108
+ const memory = new session_memory_1.PersonalAssistantSessionMemory(dataDir, (...args) => warnings.push(args));
109
+ await memory.save("thread", turn("先前回复"));
110
+ await memory.save("thread", [{ role: "tool", content: "孤立结果", tool_call_id: "missing" }]);
111
+ strict_1.default.deepEqual(await memory.load("thread"), turn("先前回复"));
112
+ strict_1.default.ok(JSON.stringify(warnings).includes("格式无效"));
113
+ }
114
+ finally {
115
+ await (0, promises_1.rm)(dataDir, { recursive: true, force: true });
116
+ }
117
+ });
@@ -1,10 +1,47 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
39
  const strict_1 = __importDefault(require("node:assert/strict"));
7
40
  const node_test_1 = require("node:test");
41
+ const promises_1 = require("node:fs/promises");
42
+ const node_os_1 = require("node:os");
43
+ const node_path_1 = require("node:path");
44
+ const channel_sessions_1 = require("../src-ts/channel-sessions");
8
45
  const agent_1 = require("../src-ts/agent");
9
46
  const personal_assistant_1 = require("../src-ts/plugins/personal-assistant");
10
47
  const tools_1 = require("../src-ts/plugins/personal-assistant/tools");
@@ -17,6 +54,135 @@ const management = {
17
54
  runSessionCommand: async (command) => `执行:${command}`,
18
55
  summarizeToday: async () => ({ supported: true, text: "今天完成了任务。", sources: [], complete: true }),
19
56
  };
57
+ (0, node_test_1.test)("个人助理 Agent 通配符贯通模型工具,不把全部允许误判为名单外", async () => {
58
+ let round = 0;
59
+ let listed = false;
60
+ let called = false;
61
+ const plugin = new personal_assistant_1.PersonalAssistantPlugin({ fetch: async (_input, init) => {
62
+ const messages = JSON.parse(String(init?.body)).messages;
63
+ if (round++) {
64
+ listed = messages.some((message) => message.role === "tool" && message.content.includes('"callable":true'));
65
+ called = messages.some((message) => message.role === "tool" && message.content.includes("已处理:通配任务"));
66
+ }
67
+ return new Response(JSON.stringify({ choices: [{ message: round === 1 ? { role: "assistant", tool_calls: [
68
+ { id: "list", type: "function", function: { name: "agents_list", arguments: "{}" } },
69
+ { id: "call", type: "function", function: { name: "agents_call", arguments: JSON.stringify({ id: "qwenwork", task: "通配任务" }) } },
70
+ ] } : { role: "assistant", content: "已完成" } }] }));
71
+ } });
72
+ try {
73
+ await plugin.activate({ config: { endpoint: "https://example.test/v1/chat/completions", model: "test", allowedPeers: ["*"], allowedAgents: ["*"] } });
74
+ strict_1.default.equal((await plugin.health()).status, "ready");
75
+ strict_1.default.equal((await plugin.handle({ task: "调用千问", management })).text, "已完成");
76
+ strict_1.default.ok(listed && called);
77
+ }
78
+ finally {
79
+ await plugin.deactivate("stop");
80
+ }
81
+ });
82
+ (0, node_test_1.test)("个人助理经真实通道会话入口执行 /new 并隔离旧上下文", async () => {
83
+ const dataDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "pa-channel-new-"));
84
+ const prompts = [];
85
+ const plugin = new personal_assistant_1.PersonalAssistantPlugin({ fetch: async (_input, init) => {
86
+ prompts.push(JSON.parse(String(init?.body)).messages);
87
+ return new Response(JSON.stringify({ choices: [{ message: { role: "assistant", content: "已处理" } }] }));
88
+ } });
89
+ try {
90
+ await plugin.activate({ dataDir, config: { endpoint: "https://example.test/v1/chat/completions", model: "test", allowedPeers: ["*"], allowedAgents: [] } });
91
+ const p = plugin;
92
+ strict_1.default.ok(p.sessionOperations?.includes("new"));
93
+ const sessions = new channel_sessions_1.ChannelSessions(dataDir);
94
+ const send = (text) => sessions.run({ channel: "aun", recipientId: "pa.agentid.cn", peerId: "devproj.agentid.cn", text, reply: async () => { } }, "personal-assistant", (sessionId, newSession) => plugin.handle({ task: text, sessionId, newSession, management }), request => p.controlSession(request));
95
+ const first = await send("旧记号");
96
+ strict_1.default.match((await send("/new")).text, /新会话/);
97
+ const second = await send("新消息");
98
+ strict_1.default.notEqual(first.logicalSessionId, second.logicalSessionId);
99
+ strict_1.default.equal(prompts[1].length, 2);
100
+ strict_1.default.doesNotMatch(JSON.stringify(prompts[1]), /旧记号/);
101
+ }
102
+ finally {
103
+ await plugin.deactivate("stop");
104
+ await (0, promises_1.rm)(dataDir, { recursive: true, force: true });
105
+ }
106
+ });
107
+ (0, node_test_1.test)("后续模型请求保留上轮管理工具调用及结果且失败轮次不写入历史", async () => {
108
+ const dataDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "pa-tool-continuity-"));
109
+ const prompts = [];
110
+ let fail = false;
111
+ const plugin = new personal_assistant_1.PersonalAssistantPlugin({ fetch: async (_input, init) => {
112
+ prompts.push(JSON.parse(String(init?.body)).messages);
113
+ if (fail)
114
+ throw new Error("请求失败");
115
+ const message = prompts.length === 1
116
+ ? { role: "assistant", content: null, tool_calls: [{ id: "call-1", type: "function", function: { name: "agents_call", arguments: '{"id":"workbuddy","task":"记住 PA_TOOL"}' } }] }
117
+ : { role: "assistant", content: "已完成" };
118
+ return new Response(JSON.stringify({ choices: [{ message }] }));
119
+ } });
120
+ try {
121
+ await plugin.activate({ dataDir, config: { endpoint: "https://example.test/v1/chat/completions", model: "test", allowedPeers: ["*"], allowedAgents: ["workbuddy"] } });
122
+ await plugin.handle({ task: "调用 WorkBuddy 记住 PA_TOOL", sessionId: "one", management });
123
+ await plugin.handle({ task: "接着做", sessionId: "one", management });
124
+ strict_1.default.deepEqual(prompts[2].map((m) => m.role), ["system", "user", "assistant", "tool", "assistant", "user"]);
125
+ strict_1.default.match(prompts[2][3].content, /PA_TOOL/);
126
+ fail = true;
127
+ await plugin.handle({ task: "失败输入", sessionId: "one", management });
128
+ fail = false;
129
+ await plugin.handle({ task: "再次续聊", sessionId: "one", management });
130
+ strict_1.default.doesNotMatch(JSON.stringify(prompts.at(-1)), /失败输入/);
131
+ }
132
+ finally {
133
+ await plugin.deactivate("stop");
134
+ await (0, promises_1.rm)(dataDir, { recursive: true, force: true });
135
+ }
136
+ });
137
+ (0, node_test_1.test)("Claude 临时模型调用沿用个人助理历史,不依赖 CLI 持久会话", async () => {
138
+ const dataDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "pa-claude-continuity-"));
139
+ const prompts = [];
140
+ const plugin = new personal_assistant_1.PersonalAssistantPlugin();
141
+ try {
142
+ await plugin.activate({ dataDir, config: { modelProvider: "claude-cli", allowedPeers: ["*"], allowedAgents: [] }, modelInputGuard: true, callPlugin: async (_id, request) => {
143
+ prompts.push(JSON.parse(request.task).messages);
144
+ return { text: JSON.stringify({ role: "assistant", content: "记号 PA_CLAUDE", tool_calls: [] }) };
145
+ } });
146
+ await plugin.handle({ task: "记住 PA_CLAUDE", sessionId: "one", management });
147
+ await plugin.handle({ task: "继续", sessionId: "one", management });
148
+ strict_1.default.deepEqual(prompts[1].map((m) => m.role), ["system", "user", "assistant", "user"]);
149
+ strict_1.default.equal(prompts[1][1].content, "记住 PA_CLAUDE");
150
+ await plugin.handle({ task: "另一位 Peer", sessionId: "two", management });
151
+ strict_1.default.equal(prompts[2].length, 2);
152
+ }
153
+ finally {
154
+ await plugin.deactivate("stop");
155
+ await (0, promises_1.rm)(dataDir, { recursive: true, force: true });
156
+ }
157
+ });
158
+ (0, node_test_1.test)("个人助理在同一 AUN 会话中恢复模型历史并隔离新会话", async () => {
159
+ const dataDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "pa-session-memory-"));
160
+ const requests = [];
161
+ let answer = 0;
162
+ const fetcher = async (_input, init) => {
163
+ const body = JSON.parse(String(init?.body));
164
+ requests.push(body);
165
+ answer++;
166
+ return new Response(JSON.stringify({ choices: [{ message: { role: "assistant", content: answer === 1 ? "第一条记号 PA_FIRST" : answer === 2 ? "第二条已记住 PA_FIRST" : "新会话没有旧记号", tool_calls: [] } }] }), { status: 200 });
167
+ };
168
+ const context = { dataDir, config: { endpoint: "https://example.test/v1/chat/completions", model: "test", allowedPeers: [], allowedAgents: [] }, logger: { info() { }, warn() { }, error() { } }, http: { register: () => undefined, unregister() { } }, callPlugin: async () => ({ text: "" }), pluginStatus: () => "ready" };
169
+ try {
170
+ const first = new personal_assistant_1.PersonalAssistantPlugin({ fetch: fetcher });
171
+ await first.activate(context);
172
+ strict_1.default.equal((await first.handle({ task: "记住 PA_FIRST", sessionId: "peer-thread", management })).text, "第一条记号 PA_FIRST");
173
+ await first.deactivate("reload");
174
+ const resumed = new personal_assistant_1.PersonalAssistantPlugin({ fetch: fetcher });
175
+ await resumed.activate(context);
176
+ strict_1.default.equal((await resumed.handle({ task: "请引用刚才的记号", sessionId: "peer-thread", management })).text, "第二条已记住 PA_FIRST");
177
+ strict_1.default.deepEqual(requests[1].messages.slice(-3).map(message => [message.role, message.content]), [["user", "记住 PA_FIRST"], ["assistant", "第一条记号 PA_FIRST"], ["user", "请引用刚才的记号"]]);
178
+ strict_1.default.equal((await resumed.handle({ task: "新会话测试", sessionId: "peer-thread-new", management })).text, "新会话没有旧记号");
179
+ strict_1.default.deepEqual(requests[2].messages.slice(-2).map(message => [message.role, message.content]), [["system", requests[2].messages[0].content], ["user", "新会话测试"]]);
180
+ await resumed.deactivate("stop");
181
+ }
182
+ finally {
183
+ await (0, promises_1.rm)(dataDir, { recursive: true, force: true });
184
+ }
185
+ });
20
186
  (0, node_test_1.test)("个人助理保留工具调用历史并返回最终文本", async () => {
21
187
  const requests = [];
22
188
  const fetcher = async (_input, init) => {
@@ -72,11 +238,40 @@ const management = {
72
238
  strict_1.default.equal(result.text, "来自千问的模型回复");
73
239
  strict_1.default.equal(calls.length, 1);
74
240
  strict_1.default.equal(calls[0].id, "qwenwork");
241
+ const firstPrompt = JSON.parse(calls[0].request.prompt);
75
242
  strict_1.default.equal(calls[0].request.prompt.includes("agents_call"), true);
243
+ strict_1.default.match(firstPrompt.instructions, /只决定 content/);
244
+ strict_1.default.match(firstPrompt.instructions, /responseSchema/);
76
245
  strict_1.default.match(calls[0].request.sessionId, /^[a-f0-9]{64}$/);
246
+ strict_1.default.equal(firstPrompt.responseSchema.required.includes("tool_calls"), true);
247
+ strict_1.default.equal(firstPrompt.messages.at(-1).content, "只回答测试");
77
248
  strict_1.default.equal("management" in calls[0].request, false);
78
249
  strict_1.default.equal("onMessage" in calls[0].request, false);
79
250
  });
251
+ (0, node_test_1.test)("通用模型来源返回纯文本时作为最终回复,不执行管理工具", async () => {
252
+ const plugin = new personal_assistant_1.PersonalAssistantPlugin();
253
+ let executed = 0;
254
+ await plugin.activate({ config: { modelProvider: "plugin", modelPlugin: "workbuddy", allowedPeers: [], allowedAgents: [] }, callModelProvider: async () => ({ text: "桌面模型的普通回答" }) });
255
+ const result = await plugin.handle({ task: "只回答测试", management: { ...management, listAgents: async () => { executed++; return []; } } });
256
+ strict_1.default.equal(result.text, "桌面模型的普通回答");
257
+ strict_1.default.equal(executed, 0);
258
+ });
259
+ (0, node_test_1.test)("CLI 模型请求格式失败在回复和日志中说明具体原因", async () => {
260
+ for (const provider of ["claude-cli", "codex-cli"]) {
261
+ const reason = `${provider === "claude-cli" ? "Claude" : "Codex"} CLI 模型请求必须是包含 responseSchema 的 JSON 对象`;
262
+ const logs = [];
263
+ const plugin = new personal_assistant_1.PersonalAssistantPlugin();
264
+ await plugin.activate({ config: { modelProvider: "plugin", modelPlugin: provider, allowedPeers: [], allowedAgents: [] }, logger: { info() { }, warn: (_message, fields) => logs.push(fields), error() { } }, callModelProvider: async () => { throw new Error(reason); } });
265
+ try {
266
+ const result = await plugin.handle({ task: "测试", management });
267
+ strict_1.default.ok(result.text.includes(reason));
268
+ strict_1.default.ok(JSON.stringify(logs).includes(reason));
269
+ }
270
+ finally {
271
+ await plugin.deactivate("stop");
272
+ }
273
+ }
274
+ });
80
275
  (0, node_test_1.test)("本机 OpenAI 兼容模型允许无密钥调用", async () => {
81
276
  let authorization = "未检查";
82
277
  const plugin = new personal_assistant_1.PersonalAssistantPlugin({ fetch: async (_input, init) => {
@@ -108,9 +303,9 @@ const management = {
108
303
  await plugin.deactivate("stop");
109
304
  }
110
305
  });
111
- (0, node_test_1.test)("插件模型的坏 JSON 和无效决策在执行任一工具前被拒绝", async () => {
306
+ (0, node_test_1.test)("插件模型的无效 JSON 决策在执行任一工具前被拒绝", async () => {
112
307
  let executed = 0;
113
- for (const raw of ["不是 JSON", JSON.stringify({ role: "assistant", content: {}, tool_calls: [] }), JSON.stringify({ role: "assistant", content: null, tool_calls: [
308
+ for (const raw of [JSON.stringify({ role: "assistant", content: {}, tool_calls: [] }), JSON.stringify({ role: "assistant", content: null, tool_calls: [
114
309
  { id: "good", type: "function", function: { name: "agents_list", arguments: "{}" } },
115
310
  { id: "bad", type: "function", function: { name: "agents_list", arguments: "{bad" } },
116
311
  ] })]) {
@@ -362,7 +557,7 @@ const management = {
362
557
  const definition = (0, tools_1.toolDefinitions)().find((tool) => tool.function.name === "agents_call");
363
558
  strict_1.default.equal(definition.function.parameters.properties.task.maxLength, 20_000);
364
559
  const result = await (0, tools_1.executeTool)("agents_call", { id: "qwenwork", task: "处理任务" }, { ...management, callAgent: async () => ({ text: "完成", sessionId: "session-1", attachments: [{ data: new Uint8Array([1, 2, 3]), filename: "secret.txt", contentType: "text/plain", kind: "file" }], images: [{ data: new Uint8Array([4, 5]), filename: "image.png", contentType: "image/png" }] }) }, ["qwenwork"]);
365
- strict_1.default.deepEqual(result, { text: "完成", sessionId: "session-1" });
560
+ strict_1.default.deepEqual(result, { text: "完成", sessionId: "session-1", attachments: [{ filename: "secret.txt", contentType: "text/plain" }], attachmentDelivery: "附件将随最终回复自动回传,由通道确认发送结果,无需模型另行读取或发送。" });
366
561
  });
367
562
  (0, node_test_1.test)("上游小于一秒的超时仍会中止请求", async () => {
368
563
  const plugin = new personal_assistant_1.PersonalAssistantPlugin({ fetch: async (_input, init) => new Promise((_resolve, reject) => {
@@ -387,3 +582,82 @@ const management = {
387
582
  strict_1.default.equal(logs.length, 1);
388
583
  strict_1.default.doesNotMatch(JSON.stringify(logs), /secret-value|arbitrary-provider-error/);
389
584
  });
585
+ (0, node_test_1.test)("个人助理显式调用保留目标图片且不替换助理会话", async () => {
586
+ const plugin = new personal_assistant_1.PersonalAssistantPlugin();
587
+ const images = [{ data: new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]), filename: "画像.png", contentType: "image/png" }];
588
+ const result = await plugin.handle({ task: "/assistant agent call workbuddy 生成人像", sessionId: "助理会话", management: { ...management, callAgent: async () => ({ text: "完成", sessionId: "目标会话", images }) } });
589
+ strict_1.default.deepEqual(result.images, images);
590
+ strict_1.default.notEqual(result.sessionId, "目标会话");
591
+ });
592
+ (0, node_test_1.test)("个人助理自然语言调用回传真实附件,模型只接收附件信息且后续请求不复用附件", async () => {
593
+ const inputs = [];
594
+ const plugin = new personal_assistant_1.PersonalAssistantPlugin({ fetch: async (_url, init) => {
595
+ inputs.push(JSON.parse(String(init?.body)));
596
+ const message = inputs.length === 1
597
+ ? { role: "assistant", tool_calls: [{ id: "图片调用", type: "function", function: { name: "agents_call", arguments: '{"id":"workbuddy","task":"生成画像"}' } }] }
598
+ : { role: "assistant", content: "完成" };
599
+ return new Response(JSON.stringify({ choices: [{ message }] }));
600
+ } });
601
+ await plugin.activate({ config: { endpoint: "https://example.test/v1/chat/completions", model: "test", apiKey: "secret", allowedPeers: ["*"], allowedAgents: ["workbuddy"] } });
602
+ strict_1.default.equal((await plugin.health()).status, "ready");
603
+ const attachments = [{ kind: "file", data: new TextEncoder().encode("仅回传给通道的文件正文"), filename: "结果.txt", contentType: "text/plain" }];
604
+ const mg = { ...management, callAgent: async () => ({ text: "已生成", attachments }) };
605
+ const result = await plugin.handle({ task: "调用 WorkBuddy", sessionId: "原会话", management: mg });
606
+ strict_1.default.deepEqual(result.attachments, attachments);
607
+ strict_1.default.match(inputs[1].messages.at(-1).content, /结果.txt/);
608
+ strict_1.default.match(inputs[1].messages.at(-1).content, /附件将随最终回复自动回传/);
609
+ strict_1.default.match(inputs[0].messages[0].content, /不能读取附件字节不代表不能回传/);
610
+ strict_1.default.doesNotMatch(JSON.stringify(inputs), /仅回传给通道的文件正文|\"data\"/);
611
+ const next = await plugin.handle({ task: "谢谢", sessionId: "原会话", management: mg });
612
+ strict_1.default.equal(next.attachments, undefined);
613
+ });
614
+ (0, node_test_1.test)("个人助理保存同会话上下文,隔离其他会话并在重载后保留", async (t) => {
615
+ const dataDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "pa-context-reload-"));
616
+ const inputs = [];
617
+ const plugin = new personal_assistant_1.PersonalAssistantPlugin({ fetch: async (_url, init) => {
618
+ inputs.push(JSON.parse(String(init?.body)));
619
+ return new Response(JSON.stringify({ choices: [{ message: { role: "assistant", content: "已收到" } }] }));
620
+ } });
621
+ t.after(async () => { await plugin.deactivate("stop"); await (0, promises_1.rm)(dataDir, { recursive: true, force: true }); });
622
+ const ctx = { dataDir, config: { endpoint: "https://example.test/v1/chat/completions", model: "test", apiKey: "secret", allowedPeers: [], allowedAgents: [] } };
623
+ await plugin.activate(ctx);
624
+ await plugin.handle({ task: "画一位成年人", sessionId: "甲", management: management });
625
+ await plugin.handle({ task: "风格要古装西域", sessionId: "甲", management: management });
626
+ strict_1.default.deepEqual(inputs[1].messages.slice(1).map((m) => m.content), ["画一位成年人", "已收到", "风格要古装西域"]);
627
+ await plugin.handle({ task: "另一个用户", sessionId: "乙", management: management });
628
+ strict_1.default.equal(inputs[2].messages.length, 2);
629
+ await plugin.deactivate("reload");
630
+ await plugin.activate(ctx);
631
+ await plugin.handle({ task: "重载后", sessionId: "甲", management: management });
632
+ strict_1.default.deepEqual(inputs[3].messages.slice(1).map((m) => m.content), ["画一位成年人", "已收到", "风格要古装西域", "已收到", "重载后"]);
633
+ });
634
+ (0, node_test_1.test)("个人助理的通配来源配置通过 Schema,未知通配形式仍拒绝", async () => {
635
+ const { readFile } = await Promise.resolve().then(() => __importStar(require("node:fs/promises")));
636
+ const schema = JSON.parse(await readFile("plugins/personal-assistant/config.schema.json", "utf8"));
637
+ const pattern = new RegExp(schema.properties.allowedPeers.items.pattern);
638
+ strict_1.default.equal(pattern.test("*"), true);
639
+ strict_1.default.equal(pattern.test("owner.agentid.cn"), true);
640
+ strict_1.default.equal(pattern.test("*.agentid.cn"), false);
641
+ });
642
+ (0, node_test_1.test)("个人助理持久上下文按整轮裁剪并限制会话数量", async (t) => {
643
+ const dataDir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "pa-context-limits-"));
644
+ const inputs = [];
645
+ const plugin = new personal_assistant_1.PersonalAssistantPlugin({ fetch: async (_url, init) => {
646
+ inputs.push(JSON.parse(String(init?.body)));
647
+ return new Response(JSON.stringify({ choices: [{ message: { role: "assistant", content: "收到" } }] }));
648
+ } });
649
+ t.after(async () => { await plugin.deactivate("stop"); await (0, promises_1.rm)(dataDir, { recursive: true, force: true }); });
650
+ await plugin.activate({ dataDir, config: { endpoint: "https://example.test/v1/chat/completions", model: "test", apiKey: "secret", allowedPeers: [], allowedAgents: [] } });
651
+ const send = (sessionId, task) => plugin.handle({ sessionId, task, management: management });
652
+ for (let i = 0; i < 22; i++)
653
+ await send("连续", String(i));
654
+ strict_1.default.equal(inputs.at(-1).messages.length, 42);
655
+ strict_1.default.equal(inputs.at(-1).messages[1].content, "1");
656
+ await send("连续", "长".repeat(120_000));
657
+ await send("连续", "边界");
658
+ strict_1.default.equal(inputs.at(-1).messages.length, 2);
659
+ for (let i = 0; i < 129; i++)
660
+ await send(String(i), "独立会话");
661
+ await send("0", "已淘汰");
662
+ strict_1.default.equal(inputs.at(-1).messages.length, 2);
663
+ });
@@ -18,7 +18,7 @@ const qwenwork_1 = require("../src-ts/plugins/qwenwork");
18
18
  const state = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-platform-"));
19
19
  const manager = new plugin_manager_1.PluginManager({ pluginsDir: (0, node_path_1.resolve)(process.cwd(), "plugins"), stateDir: state });
20
20
  const records = await manager.discover();
21
- strict_1.default.deepEqual(records.map((record) => record.id).sort(), ["abweb", "aun", "chatgpt", "claude-cli", "codex-cli", "doubao", "dsh", "feishu", "personal-assistant", "qwenwork", "workbuddy"]);
21
+ strict_1.default.deepEqual(records.map((record) => record.id).sort(), ["abweb", "aun", "chatgpt", "claude-cli", "codex-cli", "doubao", "dsh", "feishu", "personal-assistant", "qwenwork", "workbuddy", "zcode"]);
22
22
  strict_1.default.equal(records.find((record) => record.id === "aun")?.type, "channel");
23
23
  const server = new control_server_1.ControlServer({ manager, host: "127.0.0.1", port: 0 });
24
24
  const address = await server.start();
@@ -171,6 +171,65 @@ const qwenwork_1 = require("../src-ts/plugins/qwenwork");
171
171
  await (0, promises_1.rm)(state, { recursive: true, force: true });
172
172
  }
173
173
  });
174
+ (0, node_test_1.default)("个人助理默认白名单允许任意 AUN Peer 调用所有 Agent,显式限制优先", async () => {
175
+ const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-assistant-defaults-"));
176
+ const pluginsDir = (0, node_path_1.join)(root, "plugins");
177
+ const stateDir = (0, node_path_1.join)(root, "state");
178
+ const desktops = ["workbuddy", "qwenwork", "doubao", "dsh", "chatgpt"];
179
+ const manager = new plugin_manager_1.PluginManager({ pluginsDir, stateDir });
180
+ try {
181
+ await (0, promises_1.mkdir)(pluginsDir, { recursive: true });
182
+ await (0, promises_1.cp)((0, node_path_1.join)(process.cwd(), "plugins", "personal-assistant"), (0, node_path_1.join)(pluginsDir, "personal-assistant"), { recursive: true });
183
+ await (0, promises_1.symlink)((0, node_path_1.resolve)(process.cwd(), "node_modules"), (0, node_path_1.join)(root, "node_modules"), "dir");
184
+ const addPlugin = async (id) => {
185
+ const dir = (0, node_path_1.join)(pluginsDir, id);
186
+ await (0, promises_1.mkdir)(dir);
187
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "plugin.json"), JSON.stringify({ id, version: "1.0.0", type: id === "aun" ? "channel" : "agent", entry: "index.js", apiVersion: "1", capabilities: id === "aun" ? ["channel"] : ["chat"] }));
188
+ await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "index.js"), "module.exports=class{async activate(c){this.ingress=c.ingress}async deactivate(){}async health(){return {status:'ready'}}async handle(r){return {text:'目标已处理:'+r.task}}async publish(m){return this.ingress.publish(m)}};");
189
+ };
190
+ for (const id of [...desktops, "codex-cli", "aun"])
191
+ await addPlugin(id);
192
+ await manager.discover();
193
+ strict_1.default.deepEqual((await manager.config("personal-assistant")).allowedPeers, []);
194
+ strict_1.default.deepEqual((await manager.config("personal-assistant")).allowedAgents, []);
195
+ await manager.start("personal-assistant");
196
+ strict_1.default.equal((await manager.health("personal-assistant")).status, "ready");
197
+ for (const id of [...desktops, "codex-cli"]) {
198
+ await manager.saveConfig(id, { executablePath: process.execPath });
199
+ await manager.start(id);
200
+ }
201
+ await manager.start("aun");
202
+ const channel = manager.get("aun").instance;
203
+ const send = async (peerId, id) => {
204
+ let reply = "";
205
+ await channel.publish({ channel: "aun", peerId, agentPlugin: "personal-assistant", text: `/assistant agent call ${id} 默认测试`, reply: async (text) => { reply = text; } });
206
+ return reply;
207
+ };
208
+ for (const id of desktops)
209
+ strict_1.default.equal(await send(`${id}.agentid.cn`, id), "目标已处理:默认测试");
210
+ strict_1.default.equal(await send("any.agentid.cn", "codex-cli"), "目标已处理:默认测试");
211
+ await addPlugin("new-agent");
212
+ await manager.discover();
213
+ await manager.start("new-agent");
214
+ strict_1.default.equal(await send("newpeer.agentid.cn", "new-agent"), "目标已处理:默认测试");
215
+ await manager.saveConfig("personal-assistant", { allowedPeers: ["owner.agentid.cn"], allowedAgents: ["workbuddy"] });
216
+ strict_1.default.match(await send("any.agentid.cn", "workbuddy"), /授权的 AUN/);
217
+ strict_1.default.equal(await send("owner.agentid.cn", "workbuddy"), "目标已处理:默认测试");
218
+ strict_1.default.match(await send("owner.agentid.cn", "dsh"), /白名单/);
219
+ await manager.saveConfig("personal-assistant", { allowedPeers: [], allowedAgents: [] });
220
+ strict_1.default.equal(await send("owner.agentid.cn", "workbuddy"), "目标已处理:默认测试");
221
+ strict_1.default.equal(await send("new-peer.agentid.cn", "dsh"), "目标已处理:默认测试");
222
+ strict_1.default.deepEqual((await manager.config("personal-assistant")).allowedPeers, []);
223
+ strict_1.default.deepEqual((await manager.config("personal-assistant")).allowedAgents, []);
224
+ }
225
+ finally {
226
+ for (const record of manager.list())
227
+ if (manager.get(record.id)?.instance)
228
+ await manager.stop(record.id);
229
+ await manager.logs.flush();
230
+ await (0, promises_1.rm)(root, { recursive: true, force: true });
231
+ }
232
+ });
174
233
  (0, node_test_1.default)("model manifests keep the platform defaults and explicit doubao degraded adapter", async () => {
175
234
  strict_1.default.equal(qwenwork_1.qwenworkManifest.defaults.cdpPort, 9228);
176
235
  strict_1.default.equal(qwenwork_1.qwenworkManifest.defaults.httpPort, 17893);