mu-agent-bridge 1.0.71 → 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 (195) hide show
  1. package/README.md +17 -10
  2. package/dist/src-ts/agent.js +35 -0
  3. package/dist/src-ts/channel-sessions.js +3 -2
  4. package/dist/src-ts/cli.js +67 -37
  5. package/dist/src-ts/control-server.js +12 -30
  6. package/dist/src-ts/core-updater.js +141 -33
  7. package/dist/src-ts/daemon-process.js +2 -1
  8. package/dist/src-ts/dsh-agent.js +31 -13
  9. package/dist/src-ts/http-agent.js +36 -0
  10. package/dist/src-ts/plugin-catalog.js +11 -2
  11. package/dist/src-ts/plugin-manager.js +351 -50
  12. package/dist/src-ts/plugins/abweb/index.js +1 -1
  13. package/dist/src-ts/plugins/abweb/public/app.js +73 -5
  14. package/dist/src-ts/plugins/abweb/public/index.html +15 -0
  15. package/dist/src-ts/plugins/abweb/public/style.css +4 -0
  16. package/dist/src-ts/plugins/aun/attachments.js +3 -21
  17. package/dist/src-ts/plugins/aun/index.js +155 -21
  18. package/dist/src-ts/plugins/aun/messages.js +4 -1
  19. package/dist/src-ts/plugins/aun/public/app.js +2 -1
  20. package/dist/src-ts/plugins/aun/public/index.html +1 -1
  21. package/dist/src-ts/plugins/cdp-draft.js +5 -2
  22. package/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
  23. package/dist/src-ts/plugins/chatgpt/index.js +80 -19
  24. package/dist/src-ts/plugins/claude-cli/index.js +19 -2
  25. package/dist/src-ts/plugins/codex-cli/index.js +19 -2
  26. package/dist/src-ts/plugins/desktop-launch.js +44 -3
  27. package/dist/src-ts/plugins/doubao/cdp-client.js +234 -45
  28. package/dist/src-ts/plugins/doubao/index.js +152 -8
  29. package/dist/src-ts/plugins/doubao/native-task.js +134 -0
  30. package/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
  31. package/dist/src-ts/plugins/dsh/index.js +172 -21
  32. package/dist/src-ts/plugins/dsh/session-history.js +31 -3
  33. package/dist/src-ts/plugins/feishu/index.js +1 -1
  34. package/dist/src-ts/plugins/local-cli/agent.js +74 -9
  35. package/dist/src-ts/plugins/personal-assistant/claude-cli-model.js +30 -0
  36. package/dist/src-ts/plugins/personal-assistant/coordination.js +57 -0
  37. package/dist/src-ts/plugins/personal-assistant/index.js +263 -0
  38. package/dist/src-ts/plugins/personal-assistant/model-client.js +181 -0
  39. package/dist/src-ts/plugins/personal-assistant/owner-context.js +56 -0
  40. package/dist/src-ts/plugins/personal-assistant/remote-ability.js +176 -0
  41. package/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
  42. package/dist/src-ts/plugins/personal-assistant/tools.js +167 -0
  43. package/dist/src-ts/plugins/qwenwork/cdp-client.js +90 -18
  44. package/dist/src-ts/plugins/qwenwork/index.js +139 -24
  45. package/dist/src-ts/plugins/workbuddy/cdp-client.js +353 -82
  46. package/dist/src-ts/plugins/workbuddy/index.js +124 -41
  47. package/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
  48. package/dist/src-ts/plugins/zcode/index.js +97 -0
  49. package/dist/src-ts/session-management.js +132 -14
  50. package/dist/src-ts/version-manager.js +6 -3
  51. package/dist/tests-ts/abweb-cli.test.js +10 -2
  52. package/dist/tests-ts/abweb-model-config.test.js +73 -0
  53. package/dist/tests-ts/agent.test.js +27 -0
  54. package/dist/tests-ts/aun-attachments.test.js +19 -17
  55. package/dist/tests-ts/aun-default-owner-page.test.js +2 -1
  56. package/dist/tests-ts/aun-messages.test.js +20 -0
  57. package/dist/tests-ts/aun-plugin.test.js +292 -19
  58. package/dist/tests-ts/bundled-package.test.js +12 -2
  59. package/dist/tests-ts/cdp-draft-recovery.test.js +182 -3
  60. package/dist/tests-ts/channel-sessions.test.js +27 -0
  61. package/dist/tests-ts/chatgpt-plugin.test.js +118 -0
  62. package/dist/tests-ts/control-server.test.js +56 -0
  63. package/dist/tests-ts/core-updater.test.js +215 -46
  64. package/dist/tests-ts/daemon-process.test.js +126 -1
  65. package/dist/tests-ts/desktop-launch.test.js +73 -0
  66. package/dist/tests-ts/doubao-native-task.test.js +237 -0
  67. package/dist/tests-ts/doubao-plugin.test.js +773 -12
  68. package/dist/tests-ts/dsh-agent.test.js +157 -8
  69. package/dist/tests-ts/dsh-cdp.test.js +148 -0
  70. package/dist/tests-ts/dsh-history.test.js +37 -0
  71. package/dist/tests-ts/feishu-plugin.test.js +1 -1
  72. package/dist/tests-ts/http-agent.test.js +18 -0
  73. package/dist/tests-ts/installer-assets.test.js +1 -1
  74. package/dist/tests-ts/local-cli.test.js +146 -1
  75. package/dist/tests-ts/model-provider-cancellation.test.js +152 -0
  76. package/dist/tests-ts/native-session-management.test.js +8 -7
  77. package/dist/tests-ts/personal-assistant-coordination.test.js +92 -0
  78. package/dist/tests-ts/personal-assistant-extensions.test.js +35 -0
  79. package/dist/tests-ts/personal-assistant-memory.test.js +117 -0
  80. package/dist/tests-ts/personal-assistant-owner-context.test.js +107 -0
  81. package/dist/tests-ts/personal-assistant-remote-ability.test.js +123 -0
  82. package/dist/tests-ts/personal-assistant.test.js +663 -0
  83. package/dist/tests-ts/platform-integration.test.js +183 -1
  84. package/dist/tests-ts/plugin-catalog.test.js +12 -2
  85. package/dist/tests-ts/plugin-manager.test.js +356 -4
  86. package/dist/tests-ts/plugin-upgrade-deadline.test.js +354 -0
  87. package/dist/tests-ts/publish-packages.test.js +42 -0
  88. package/dist/tests-ts/qwenwork-plugin.test.js +135 -1
  89. package/dist/tests-ts/qwenwork-reconnect.test.js +195 -0
  90. package/dist/tests-ts/qwenwork-sse.test.js +33 -0
  91. package/dist/tests-ts/session-access-defaults.test.js +112 -0
  92. package/dist/tests-ts/session-management.test.js +159 -4
  93. package/dist/tests-ts/version-manager.test.js +40 -0
  94. package/dist/tests-ts/workbuddy-cdp-recovery.test.js +311 -0
  95. package/dist/tests-ts/workbuddy-plugin.test.js +499 -4
  96. package/dist/tests-ts/zcode-cdp.test.js +894 -0
  97. package/dist/tests-ts/zcode-plugin.test.js +396 -0
  98. package/package.json +1 -1
  99. package/plugins/abweb/dist/src-ts/agent.js +35 -0
  100. package/plugins/abweb/dist/src-ts/plugins/abweb/index.js +1 -1
  101. package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.js +73 -5
  102. package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.ts +57 -5
  103. package/plugins/abweb/dist/src-ts/plugins/abweb/public/index.html +15 -0
  104. package/plugins/abweb/dist/src-ts/plugins/abweb/public/style.css +4 -0
  105. package/plugins/abweb/package.json +1 -1
  106. package/plugins/abweb/plugin.json +1 -1
  107. package/plugins/aun/config.schema.json +1 -1
  108. package/plugins/aun/dist/src-ts/agent.js +35 -0
  109. package/plugins/aun/dist/src-ts/plugins/aun/attachments.js +3 -21
  110. package/plugins/aun/dist/src-ts/plugins/aun/index.js +155 -21
  111. package/plugins/aun/dist/src-ts/plugins/aun/messages.js +4 -1
  112. package/plugins/aun/dist/src-ts/plugins/aun/public/app.js +2 -1
  113. package/plugins/aun/dist/src-ts/plugins/aun/public/index.html +1 -1
  114. package/plugins/aun/package.json +1 -1
  115. package/plugins/aun/plugin.json +1 -1
  116. package/plugins/chatgpt/dist/src-ts/agent.js +35 -0
  117. package/plugins/chatgpt/dist/src-ts/plugins/cdp-draft.js +5 -2
  118. package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
  119. package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/index.js +80 -19
  120. package/plugins/chatgpt/dist/src-ts/plugins/desktop-launch.js +44 -3
  121. package/plugins/chatgpt/package.json +1 -1
  122. package/plugins/chatgpt/plugin.json +1 -1
  123. package/plugins/claude-cli/dist/src-ts/agent.js +35 -0
  124. package/plugins/claude-cli/dist/src-ts/plugins/claude-cli/index.js +19 -2
  125. package/plugins/claude-cli/dist/src-ts/plugins/local-cli/agent.js +74 -9
  126. package/plugins/claude-cli/package.json +1 -1
  127. package/plugins/claude-cli/plugin.json +3 -2
  128. package/plugins/codex-cli/dist/src-ts/agent.js +35 -0
  129. package/plugins/codex-cli/dist/src-ts/plugins/codex-cli/index.js +19 -2
  130. package/plugins/codex-cli/dist/src-ts/plugins/local-cli/agent.js +74 -9
  131. package/plugins/codex-cli/package.json +1 -1
  132. package/plugins/codex-cli/plugin.json +3 -2
  133. package/plugins/doubao/config.schema.json +2 -1
  134. package/plugins/doubao/dist/src-ts/agent.js +35 -0
  135. package/plugins/doubao/dist/src-ts/plugins/desktop-launch.js +44 -3
  136. package/plugins/doubao/dist/src-ts/plugins/doubao/cdp-client.js +234 -45
  137. package/plugins/doubao/dist/src-ts/plugins/doubao/index.js +152 -8
  138. package/plugins/doubao/dist/src-ts/plugins/doubao/native-task.js +134 -0
  139. package/plugins/doubao/package.json +1 -1
  140. package/plugins/doubao/plugin.json +3 -2
  141. package/plugins/dsh/config.schema.json +5 -2
  142. package/plugins/dsh/dist/src-ts/agent.js +35 -0
  143. package/plugins/dsh/dist/src-ts/dsh-agent.js +31 -13
  144. package/plugins/dsh/dist/src-ts/plugins/desktop-launch.js +44 -3
  145. package/plugins/dsh/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
  146. package/plugins/dsh/dist/src-ts/plugins/dsh/index.js +172 -21
  147. package/plugins/dsh/dist/src-ts/plugins/dsh/session-history.js +31 -3
  148. package/plugins/dsh/package.json +1 -1
  149. package/plugins/dsh/plugin.json +3 -2
  150. package/plugins/feishu/dist/src-ts/agent.js +35 -0
  151. package/plugins/feishu/dist/src-ts/plugins/feishu/index.js +1 -1
  152. package/plugins/feishu/package.json +1 -1
  153. package/plugins/feishu/plugin.json +1 -1
  154. package/plugins/personal-assistant/config.schema.json +23 -0
  155. package/plugins/personal-assistant/dist/src-ts/agent.js +69 -0
  156. package/plugins/personal-assistant/dist/src-ts/attachments.js +62 -0
  157. package/plugins/personal-assistant/dist/src-ts/plugin.js +13 -0
  158. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/claude-cli-model.js +30 -0
  159. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/coordination.js +57 -0
  160. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/index.js +263 -0
  161. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/model-client.js +181 -0
  162. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/owner-context.js +56 -0
  163. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/remote-ability.js +176 -0
  164. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
  165. package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/tools.js +167 -0
  166. package/plugins/personal-assistant/package.json +39 -0
  167. package/plugins/personal-assistant/plugin.json +15 -0
  168. package/plugins/qwenwork/dist/src-ts/agent.js +35 -0
  169. package/plugins/qwenwork/dist/src-ts/plugins/cdp-draft.js +5 -2
  170. package/plugins/qwenwork/dist/src-ts/plugins/desktop-launch.js +44 -3
  171. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/cdp-client.js +90 -18
  172. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/index.js +139 -24
  173. package/plugins/qwenwork/package.json +1 -1
  174. package/plugins/qwenwork/plugin.json +3 -2
  175. package/plugins/workbuddy/config.schema.json +1 -1
  176. package/plugins/workbuddy/dist/src-ts/agent.js +35 -0
  177. package/plugins/workbuddy/dist/src-ts/plugins/desktop-launch.js +44 -3
  178. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cdp-client.js +353 -82
  179. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/index.js +124 -41
  180. package/plugins/workbuddy/package.json +1 -1
  181. package/plugins/workbuddy/plugin.json +3 -2
  182. package/plugins/zcode/config.schema.json +13 -0
  183. package/plugins/zcode/dist/src-ts/agent.js +69 -0
  184. package/plugins/zcode/dist/src-ts/attachments.js +62 -0
  185. package/plugins/zcode/dist/src-ts/plugin.js +13 -0
  186. package/plugins/zcode/dist/src-ts/plugins/desktop-launch.js +238 -0
  187. package/plugins/zcode/dist/src-ts/plugins/workbuddy/cdp-client.js +896 -0
  188. package/plugins/zcode/dist/src-ts/plugins/workbuddy/cli-client.js +39 -0
  189. package/plugins/zcode/dist/src-ts/plugins/workbuddy/desktop-launch.js +10 -0
  190. package/plugins/zcode/dist/src-ts/plugins/workbuddy/index.js +567 -0
  191. package/plugins/zcode/dist/src-ts/plugins/workbuddy/session-history.js +121 -0
  192. package/plugins/zcode/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
  193. package/plugins/zcode/dist/src-ts/plugins/zcode/index.js +97 -0
  194. package/plugins/zcode/package.json +16 -0
  195. package/plugins/zcode/plugin.json +11 -0
@@ -0,0 +1,176 @@
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
+ exports.RemoteAbilityClient = void 0;
7
+ exports.createRemoteAbilityClient = createRemoteAbilityClient;
8
+ const node_child_process_1 = require("node:child_process");
9
+ const node_util_1 = require("node:util");
10
+ const ajv_1 = __importDefault(require("ajv"));
11
+ const node_crypto_1 = require("node:crypto");
12
+ const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
13
+ const aidPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{2,255}$/;
14
+ const idPattern = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/;
15
+ const ajv = new ajv_1.default({ allErrors: true, strict: false });
16
+ class RemoteAbilityClient {
17
+ cache = new Map();
18
+ selfAid;
19
+ ecPath;
20
+ timeoutMs;
21
+ constructor(options) {
22
+ if (!validAid(options.selfAid))
23
+ throw new Error("selfAid AID 无效");
24
+ this.selfAid = options.selfAid;
25
+ this.ecPath = options.ecPath?.trim() || "ec";
26
+ this.timeoutMs = options.timeoutMs && Number.isInteger(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : 30_000;
27
+ }
28
+ async discover(providerAid) {
29
+ validProvider(providerAid);
30
+ const index = await this.readCat(["fs", "cat", `${providerAid}:/ability/index.json`], "能力索引");
31
+ const entries = Array.isArray(index.abilities) ? index.abilities : Array.isArray(index) ? index : undefined;
32
+ if (!entries)
33
+ throw new Error("能力索引缺少 abilities 列表");
34
+ const valid = [];
35
+ for (const value of entries) {
36
+ const entry = validateEntry(value);
37
+ if (!entry)
38
+ continue;
39
+ const detailPath = detailPathFor(providerAid, entry.detail_ref);
40
+ const detail = await this.readCat(["fs", "cat", `${providerAid}:${detailPath}`], "能力契约");
41
+ if (!sameContract(entry, detail))
42
+ continue;
43
+ this.cache.set(`${providerAid}\n${entry.path}`, { entry, detail: detail });
44
+ valid.push(entry);
45
+ }
46
+ return valid;
47
+ }
48
+ async call(providerAid, path, params) {
49
+ validProvider(providerAid);
50
+ if (!validPath(path))
51
+ throw new Error("能力路径无效");
52
+ let contract = this.cache.get(`${providerAid}\n${path}`);
53
+ if (!contract) {
54
+ await this.discover(providerAid);
55
+ contract = this.cache.get(`${providerAid}\n${path}`);
56
+ }
57
+ if (!contract)
58
+ throw new Error("能力索引或 L3 契约中不存在该精确路径");
59
+ const { entry, detail } = contract;
60
+ if (!sameContract(entry, detail))
61
+ throw new Error("L1 与 L3 能力契约不一致");
62
+ ensureReadOnly(entry);
63
+ const validateParams = ajv.compile(entry.params_schema);
64
+ if (!validateParams(params))
65
+ throw new Error(`参数不符合 schema:${ajv.errorsText(validateParams.errors)}`);
66
+ const callId = `c-${(0, node_crypto_1.randomUUID)()}`;
67
+ const operationId = `op-${(0, node_crypto_1.randomUUID)()}`;
68
+ const payload = {
69
+ type: "ability", role: "call", call_id: callId, operation_id: operationId,
70
+ ability_path: entry.path, definition_id: entry.definition_id, params, ttl: 30, async: false,
71
+ };
72
+ const receipt = object(await this.ec(["msg", "send", this.selfAid, providerAid, "--payload", JSON.stringify(payload), "--return", "required", "--timeout", "30s", "--format", "json"]), "发送回执");
73
+ return this.readReceipt(receipt, entry, callId, operationId);
74
+ }
75
+ async getRequest(providerAid, requestId) {
76
+ validProvider(providerAid);
77
+ if (!validId(requestId))
78
+ throw new Error("request_id 无效");
79
+ const receipt = object(await this.ec(["msg", "request", "get", this.selfAid, requestId, "--format", "json"]), "请求查询回执");
80
+ const request = object(receipt.request, "请求状态");
81
+ const status = normalizeState(request.state);
82
+ if (status !== "completed")
83
+ return { status, requestId };
84
+ const response = object(request.responsePayload, "Ability 响应");
85
+ const expected = this.findCallById(requestId);
86
+ if (!expected)
87
+ throw new Error("本地没有该请求对应的 Ability 契约;拒绝解释远端响应");
88
+ return this.validateResponse(response, expected.entry, requestId, expected.callId, expected.operationId);
89
+ }
90
+ async ec(args) {
91
+ const { stdout } = await execFileAsync(this.ecPath, args, { timeout: this.timeoutMs, maxBuffer: 1024 * 1024, encoding: "utf8", windowsHide: true });
92
+ try {
93
+ return JSON.parse(stdout);
94
+ }
95
+ catch {
96
+ throw new Error("ec 返回了无效 JSON");
97
+ }
98
+ }
99
+ async readCat(args, label) {
100
+ const value = object(await this.ec([...args, "--format", "json"]), label);
101
+ if (value.command !== "cat")
102
+ return value;
103
+ if (value.binary === true || typeof value.text !== "string")
104
+ throw new Error(`${label}不是 UTF-8 文本`);
105
+ try {
106
+ return object(JSON.parse(value.text), label);
107
+ }
108
+ catch {
109
+ throw new Error(`${label}不是有效 JSON`);
110
+ }
111
+ }
112
+ pending = new Map();
113
+ readReceipt(receipt, entry, callId, operationId) {
114
+ const requestId = typeof receipt.request_id === "string" ? receipt.request_id : callId;
115
+ if (receipt.request_state === "completed" && receipt.response && typeof receipt.response === "object") {
116
+ return this.validateResponse(receipt.response, entry, requestId, callId, operationId);
117
+ }
118
+ const status = normalizeState(receipt.request_state ?? receipt.status);
119
+ if (status === "pending" || status === "sent" || status === "unknown")
120
+ this.pending.set(requestId, { entry, callId, operationId });
121
+ return { status, requestId };
122
+ }
123
+ validateResponse(response, entry, requestId, callId, operationId) {
124
+ if (response.type !== "ability" || response.role !== "result" || response.call_id !== callId || response.operation_id !== operationId || response.ability_path !== entry.path || response.definition_id !== entry.definition_id)
125
+ throw new Error("Ability 响应关联字段不匹配");
126
+ if (response.ok !== true)
127
+ return { status: "failed", requestId, response, error: response.error };
128
+ if (response.execution_state !== "completed")
129
+ return { status: normalizeState(response.execution_state), requestId, response };
130
+ const validateResult = ajv.compile(entry.result_schema);
131
+ if (!validateResult(response.result))
132
+ throw new Error(`结果不符合 schema:${ajv.errorsText(validateResult.errors)}`);
133
+ return { status: "completed", requestId, response, result: response.result };
134
+ }
135
+ findCallById(requestId) {
136
+ return this.pending.get(requestId);
137
+ }
138
+ }
139
+ exports.RemoteAbilityClient = RemoteAbilityClient;
140
+ function createRemoteAbilityClient(options) { return new RemoteAbilityClient(options); }
141
+ function validAid(value) { return typeof value === "string" && aidPattern.test(value); }
142
+ function validProvider(value) { if (!validAid(value))
143
+ throw new Error("Provider AID 无效"); }
144
+ function validId(value) { return idPattern.test(value); }
145
+ function validPath(value) { return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._/-]{0,255}$/.test(value) && !value.includes("..") && !value.startsWith("/"); }
146
+ function detailPathFor(providerAid, ref) {
147
+ const prefix = `${providerAid}:/`;
148
+ const path = ref.startsWith(prefix) ? ref.slice(prefix.length) : ref.replace(/^\/+/, "");
149
+ if (!validPath(path))
150
+ throw new Error("detail_ref 路径无效或越界");
151
+ return `/${path}`;
152
+ }
153
+ function object(value, label) { if (!value || typeof value !== "object" || Array.isArray(value))
154
+ throw new Error(`${label}必须是 JSON 对象`); return value; }
155
+ function validateEntry(value) {
156
+ try {
157
+ const entry = object(value, "能力条目");
158
+ if (!validPath(entry.path) || !validId(String(entry.definition_id ?? "")) || typeof entry.detail_ref !== "string" || !entry.params_schema || typeof entry.params_schema !== "object" || !entry.result_schema || typeof entry.result_schema !== "object")
159
+ return undefined;
160
+ ajv.compile(entry.params_schema);
161
+ ajv.compile(entry.result_schema);
162
+ return entry;
163
+ }
164
+ catch {
165
+ return undefined;
166
+ }
167
+ }
168
+ function sameContract(entry, detail) {
169
+ return detail.path === entry.path && detail.definition_id === entry.definition_id && JSON.stringify(detail.params_schema) === JSON.stringify(entry.params_schema) && JSON.stringify(detail.result_schema) === JSON.stringify(entry.result_schema) && JSON.stringify(detail.effects) === JSON.stringify(entry.effects) && detail.auth_required === entry.auth_required && detail.require_confirm === entry.require_confirm;
170
+ }
171
+ function ensureReadOnly(entry) {
172
+ const effects = entry.effects;
173
+ if (!(effects === "read" || Array.isArray(effects) && effects.length > 0 && effects.every((effect) => effect === "read")) || entry.auth_required !== false || entry.require_confirm !== false)
174
+ throw new Error("能力契约不是无需认证和确认的纯只读调用");
175
+ }
176
+ function normalizeState(value) { return value === "completed" ? "completed" : value === "pending" ? "pending" : value === "sent" ? "sent" : value === "failed" ? "failed" : "unknown"; }
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PersonalAssistantSessionMemory = void 0;
4
+ const promises_1 = require("node:fs/promises");
5
+ const node_path_1 = require("node:path");
6
+ const node_crypto_1 = require("node:crypto");
7
+ const MAX_SESSIONS = 128;
8
+ const MAX_MESSAGES = 40;
9
+ const MAX_CHARS = 120_000;
10
+ class PersonalAssistantSessionMemory {
11
+ dataDir;
12
+ warn;
13
+ sessions = new Map();
14
+ loaded;
15
+ writes = Promise.resolve();
16
+ file;
17
+ constructor(dataDir, warn) {
18
+ this.dataDir = dataDir;
19
+ this.warn = warn;
20
+ this.file = (0, node_path_1.join)(dataDir, "model-sessions.json");
21
+ }
22
+ async load(sessionId) {
23
+ await this.ensureLoaded();
24
+ await this.writes;
25
+ return structuredClone(this.sessions.get(sessionId) ?? []);
26
+ }
27
+ async save(sessionId, messages) {
28
+ await this.ensureLoaded();
29
+ const task = this.writes.then(async () => {
30
+ const trimmed = trimMessages(messages);
31
+ this.sessions.delete(sessionId);
32
+ this.sessions.set(sessionId, trimmed);
33
+ while (this.sessions.size > MAX_SESSIONS)
34
+ this.sessions.delete(this.sessions.keys().next().value);
35
+ const temporary = `${this.file}.${process.pid}.${(0, node_crypto_1.randomUUID)()}.tmp`;
36
+ try {
37
+ await (0, promises_1.mkdir)(this.dataDir, { recursive: true, mode: 0o700 });
38
+ await (0, promises_1.writeFile)(temporary, `${JSON.stringify(Object.fromEntries(this.sessions))}\n`, { mode: 0o600, flag: "wx" });
39
+ await (0, promises_1.rename)(temporary, this.file);
40
+ await (0, promises_1.chmod)(this.file, 0o600);
41
+ }
42
+ catch {
43
+ this.warn?.("个人助理会话历史保存失败,本次回复仍有效;重载前可继续使用内存历史");
44
+ }
45
+ finally {
46
+ await (0, promises_1.rm)(temporary, { force: true }).catch(() => { });
47
+ }
48
+ });
49
+ this.writes = task.catch(() => { this.warn?.("个人助理会话历史格式无效,本轮未保存"); });
50
+ await this.writes;
51
+ }
52
+ ensureLoaded() {
53
+ this.loaded ??= (async () => {
54
+ try {
55
+ if ((await (0, promises_1.stat)(this.file)).size > MAX_SESSIONS * MAX_CHARS * 4)
56
+ throw new Error("历史文件超过限制");
57
+ const raw = JSON.parse(await (0, promises_1.readFile)(this.file, "utf8"));
58
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
59
+ throw new Error("历史文件格式无效");
60
+ for (const [id, value] of Object.entries(raw).slice(-MAX_SESSIONS)) {
61
+ if (!id || id.length > 128 || !Array.isArray(value))
62
+ continue;
63
+ try {
64
+ this.sessions.set(id, trimMessages(value));
65
+ }
66
+ catch {
67
+ this.warn?.("个人助理丢弃了一条格式无效的会话历史");
68
+ }
69
+ }
70
+ }
71
+ catch (error) {
72
+ if (error.code !== "ENOENT")
73
+ this.warn?.("个人助理会话历史读取失败,已使用空历史");
74
+ }
75
+ })();
76
+ return this.loaded;
77
+ }
78
+ }
79
+ exports.PersonalAssistantSessionMemory = PersonalAssistantSessionMemory;
80
+ function trimMessages(messages) {
81
+ const result = [];
82
+ const pending = new Set();
83
+ let next = "user";
84
+ for (const value of messages) {
85
+ if (!value || typeof value !== "object")
86
+ throw new Error("会话消息无效");
87
+ const m = value;
88
+ if (m.role !== next || (m.content !== undefined && m.content !== null && typeof m.content !== "string"))
89
+ throw new Error("会话消息顺序无效");
90
+ if (m.role === "assistant" && m.tool_calls?.length) {
91
+ if (!Array.isArray(m.tool_calls) || m.tool_calls.length > 8)
92
+ throw new Error("工具调用无效");
93
+ const calls = m.tool_calls.map(call => {
94
+ if (typeof call?.id !== "string" || !call.id || pending.has(call.id) || call.type !== "function" || typeof call.function?.name !== "string" || typeof call.function.arguments !== "string")
95
+ throw new Error("工具调用无效");
96
+ pending.add(call.id);
97
+ return { id: call.id, type: "function", function: { name: call.function.name, arguments: call.function.arguments } };
98
+ });
99
+ result.push({ role: "assistant", content: m.content ?? null, tool_calls: calls });
100
+ next = "tool";
101
+ }
102
+ else if (m.role === "tool") {
103
+ if (typeof m.content !== "string" || !m.tool_call_id || !pending.delete(m.tool_call_id))
104
+ throw new Error("工具结果无效");
105
+ result.push({ role: "tool", content: m.content, tool_call_id: m.tool_call_id, ...(typeof m.name === "string" ? { name: m.name } : {}) });
106
+ if (!pending.size)
107
+ next = "assistant";
108
+ }
109
+ else {
110
+ if (typeof m.content !== "string")
111
+ throw new Error("会话正文无效");
112
+ result.push({ role: m.role, content: m.content });
113
+ next = m.role === "user" ? "assistant" : "user";
114
+ }
115
+ }
116
+ if (next !== "user")
117
+ throw new Error("会话轮次未完成");
118
+ // 以整轮用户消息裁剪,避免留下缺少工具调用的孤立 tool 消息。
119
+ while (result.length > MAX_MESSAGES || JSON.stringify(result).length > MAX_CHARS) {
120
+ const end = result.findIndex((message, index) => index > 0 && message.role === "user");
121
+ result.splice(0, end < 0 ? result.length : end);
122
+ }
123
+ return result;
124
+ }
@@ -0,0 +1,167 @@
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
+ exports.TOOL_NAMES = void 0;
7
+ exports.toolDefinitions = toolDefinitions;
8
+ exports.parseToolArguments = parseToolArguments;
9
+ exports.executeTool = executeTool;
10
+ exports.parseExplicitCommand = parseExplicitCommand;
11
+ exports.stringifyToolResult = stringifyToolResult;
12
+ const ajv_1 = __importDefault(require("ajv"));
13
+ const coordination_1 = require("./coordination");
14
+ exports.TOOL_NAMES = ["agents_list", "agents_call", "aun_identity_list", "sessions_command", "sessions_today", "self_status", "ability_discover", "ability_call", "ability_request_get", "coordination_dispatch", "coordination_status", "owner_context_read"];
15
+ const ajv = new ajv_1.default({ allErrors: false, strict: false });
16
+ const schemas = {
17
+ agents_list: ajv.compile({ type: "object", additionalProperties: false, properties: {} }),
18
+ agents_call: ajv.compile({ type: "object", additionalProperties: false, required: ["id", "task"], properties: { id: { type: "string", minLength: 1, maxLength: 128 }, task: { type: "string", minLength: 1, maxLength: 20_000 } } }),
19
+ aun_identity_list: ajv.compile({ type: "object", additionalProperties: false, properties: {} }),
20
+ sessions_command: ajv.compile({ type: "object", additionalProperties: false, required: ["command"], properties: { command: { type: "string", minLength: 1, maxLength: 512 } } }),
21
+ sessions_today: ajv.compile({ type: "object", additionalProperties: false, properties: {} }),
22
+ self_status: ajv.compile({ type: "object", additionalProperties: false, properties: {} }),
23
+ ability_discover: ajv.compile({ type: "object", additionalProperties: false, required: ["providerAid"], properties: { providerAid: { type: "string", minLength: 3, maxLength: 256 } } }),
24
+ ability_call: ajv.compile({ type: "object", additionalProperties: false, required: ["providerAid", "path", "params"], properties: { providerAid: { type: "string", minLength: 3, maxLength: 256 }, path: { type: "string", minLength: 1, maxLength: 256 }, params: { type: "object" } } }),
25
+ ability_request_get: ajv.compile({ type: "object", additionalProperties: false, required: ["providerAid", "requestId"], properties: { providerAid: { type: "string", minLength: 3, maxLength: 256 }, requestId: { type: "string", minLength: 1, maxLength: 256 } } }),
26
+ coordination_dispatch: ajv.compile({ type: "object", additionalProperties: false, required: ["agentId", "aid", "task"], properties: { agentId: { type: "string", minLength: 1, maxLength: 64 }, aid: { type: "string", minLength: 3, maxLength: 256 }, task: { type: "string", minLength: 1, maxLength: 20000 } } }),
27
+ coordination_status: ajv.compile({ type: "object", additionalProperties: false, required: ["aid", "threadId"], properties: { aid: { type: "string", minLength: 3, maxLength: 256 }, threadId: { type: "string", minLength: 1, maxLength: 256 } } }),
28
+ owner_context_read: ajv.compile({ type: "object", additionalProperties: false, properties: {} }),
29
+ };
30
+ const toolDescriptions = {
31
+ agents_list: { name: "agents_list", description: "列出当前可调用的 Agent 及其 AID。", parameters: { type: "object", additionalProperties: false, properties: {} } },
32
+ agents_call: { name: "agents_call", description: "向白名单中的 Agent 发送一项独立任务。", parameters: { type: "object", additionalProperties: false, required: ["id", "task"], properties: { id: { type: "string", minLength: 1, maxLength: 128 }, task: { type: "string", minLength: 1, maxLength: 20_000 } } } },
33
+ aun_identity_list: { name: "aun_identity_list", description: "列出本机已知 AUN 身份及绑定状态。", parameters: { type: "object", additionalProperties: false, properties: {} } },
34
+ sessions_command: { name: "sessions_command", description: "执行只读的 /sessions 管理命令。", parameters: { type: "object", additionalProperties: false, required: ["command"], properties: { command: { type: "string", minLength: 1, maxLength: 512 } } } },
35
+ sessions_today: { name: "sessions_today", description: "生成今天工作的小结。", parameters: { type: "object", additionalProperties: false, properties: {} } },
36
+ self_status: { name: "self_status", description: "报告个人助理自身状态。", parameters: { type: "object", additionalProperties: false, properties: {} } },
37
+ ability_discover: { name: "ability_discover", description: "发现已配置 Provider 的只读 AUN Ability。", parameters: { type: "object", additionalProperties: false, required: ["providerAid"], properties: { providerAid: { type: "string", minLength: 3, maxLength: 256 } } } },
38
+ ability_call: { name: "ability_call", description: "调用无需认证和确认的纯只读 AUN Ability。", parameters: { type: "object", additionalProperties: false, required: ["providerAid", "path", "params"], properties: { providerAid: { type: "string", minLength: 3, maxLength: 256 }, path: { type: "string", minLength: 1, maxLength: 256 }, params: { type: "object" } } } },
39
+ ability_request_get: { name: "ability_request_get", description: "查询已发送 AUN Ability 的请求状态,不重新发送。", parameters: { type: "object", additionalProperties: false, required: ["providerAid", "requestId"], properties: { providerAid: { type: "string", minLength: 3, maxLength: 256 }, requestId: { type: "string", minLength: 1, maxLength: 256 } } } },
40
+ coordination_dispatch: { name: "coordination_dispatch", description: "显式向白名单 Agent 派发任务并创建独立 thread。", parameters: { type: "object", additionalProperties: false, required: ["agentId", "aid", "task"], properties: { agentId: { type: "string", minLength: 1, maxLength: 64 }, aid: { type: "string", minLength: 3, maxLength: 256 }, task: { type: "string", minLength: 1, maxLength: 20000 } } } },
41
+ coordination_status: { name: "coordination_status", description: "读取派发任务对应 thread 的当前状态和历史。", parameters: { type: "object", additionalProperties: false, required: ["aid", "threadId"], properties: { aid: { type: "string", minLength: 3, maxLength: 256 }, threadId: { type: "string", minLength: 1, maxLength: 256 } } } },
42
+ owner_context_read: { name: "owner_context_read", description: "读取管理员配置的 Owner 共享资料,仅作为参考。", parameters: { type: "object", additionalProperties: false, properties: {} } },
43
+ };
44
+ function toolDefinitions() {
45
+ return exports.TOOL_NAMES.map((name) => ({ type: "function", function: { ...toolDescriptions[name], parameters: { ...toolDescriptions[name].parameters } } }));
46
+ }
47
+ function parseToolArguments(name, raw) {
48
+ if (!exports.TOOL_NAMES.includes(name))
49
+ throw new Error("未知的管理工具");
50
+ let value;
51
+ try {
52
+ value = JSON.parse(raw);
53
+ }
54
+ catch {
55
+ throw new Error("管理工具参数不是有效 JSON");
56
+ }
57
+ const validate = schemas[name];
58
+ if (!validate(value))
59
+ throw new Error("管理工具参数不符合要求");
60
+ return value;
61
+ }
62
+ async function executeTool(name, args, management, allowedAgents, runtime = {}) {
63
+ if (!exports.TOOL_NAMES.includes(name))
64
+ throw new Error("未知的管理工具");
65
+ if (!schemas[name](args))
66
+ throw new Error("管理工具参数不符合要求");
67
+ switch (name) {
68
+ case "agents_list": {
69
+ const agents = await management.listAgents();
70
+ return allowedAgents?.length && !allowedAgents.includes("*") ? agents.map((agent) => allowedAgents.includes(agent.id) ? agent : { ...agent, callable: false, reason: "未加入个人助理 Agent 白名单" }) : agents;
71
+ }
72
+ case "agents_call": {
73
+ if (allowedAgents?.length && !allowedAgents.includes("*") && !allowedAgents.includes(String(args.id)))
74
+ throw new Error("目标 Agent 未加入个人助理白名单");
75
+ const result = await management.callAgent(String(args.id), String(args.task));
76
+ return {
77
+ text: result.text,
78
+ ...((result.attachments?.length || result.images?.length) ? { attachments: (result.attachments?.length ? result.attachments : result.images).map(({ filename, contentType }) => ({ filename, contentType })), attachmentDelivery: "附件将随最终回复自动回传,由通道确认发送结果,无需模型另行读取或发送。" } : {}),
79
+ ...(result.sessionId ? { sessionId: result.sessionId } : {}),
80
+ };
81
+ }
82
+ case "aun_identity_list": return management.listAunIdentities();
83
+ case "sessions_command": {
84
+ const command = String(args.command).trim();
85
+ if (!/^\/sessions(?:\s|$)/.test(command) || /[\r\n]/.test(command))
86
+ throw new Error("只支持单行 /sessions 只读命令");
87
+ return management.runSessionCommand(command);
88
+ }
89
+ case "sessions_today": return management.summarizeToday();
90
+ case "self_status": return { status: "ready", capabilities: exports.TOOL_NAMES };
91
+ case "ability_discover": {
92
+ const providerAid = String(args.providerAid);
93
+ if (!runtime.allowedProviders?.includes(providerAid) || !runtime.remoteAbility)
94
+ throw new Error("Provider 未加入远程 Ability 白名单");
95
+ return runtime.remoteAbility.discover(providerAid);
96
+ }
97
+ case "ability_call": {
98
+ const providerAid = String(args.providerAid);
99
+ if (!runtime.allowedProviders?.includes(providerAid) || !runtime.remoteAbility)
100
+ throw new Error("Provider 未加入远程 Ability 白名单");
101
+ return runtime.remoteAbility.call(providerAid, String(args.path), args.params);
102
+ }
103
+ case "ability_request_get": {
104
+ const providerAid = String(args.providerAid);
105
+ if (!runtime.allowedProviders?.includes(providerAid) || !runtime.remoteAbility)
106
+ throw new Error("Provider 未加入远程 Ability 白名单");
107
+ return runtime.remoteAbility.getRequest(providerAid, String(args.requestId));
108
+ }
109
+ case "coordination_dispatch": {
110
+ if (!allowedAgents || (allowedAgents.length > 0 && !allowedAgents.includes("*") && !allowedAgents.includes(String(args.agentId))) || !runtime.selfAid)
111
+ throw new Error("目标 Agent 未加入个人助理白名单");
112
+ const abilities = await management.listAgents();
113
+ const agent = abilities.find((item) => item.id === args.agentId && item.callable && item.aids.includes(String(args.aid)));
114
+ if (!agent)
115
+ throw new Error("目标 Agent/AID 当前不可派活");
116
+ const coordinator = (0, coordination_1.createCoordinator)({ selfAid: runtime.selfAid, ecPath: runtime.ecPath, allowedAgents: [{ id: agent.id, aids: agent.aids }] });
117
+ const result = await coordinator.dispatch({ agentId: agent.id, aid: String(args.aid), task: String(args.task) });
118
+ if (runtime.threads && runtime.threads.size >= 128)
119
+ runtime.threads.delete(runtime.threads.keys().next().value);
120
+ runtime.threads?.set(result.threadId, result.aid);
121
+ return result;
122
+ }
123
+ case "coordination_status": {
124
+ if (!runtime.selfAid)
125
+ throw new Error("个人助理 AID 未配置");
126
+ if (runtime.threads?.get(String(args.threadId)) !== String(args.aid))
127
+ throw new Error("thread 不属于本个人助理已派发的任务");
128
+ const coordinator = (0, coordination_1.createCoordinator)({ selfAid: runtime.selfAid, ecPath: runtime.ecPath, allowedAgents: [] });
129
+ return coordinator.getStatus({ aid: String(args.aid), threadId: String(args.threadId) });
130
+ }
131
+ case "owner_context_read": {
132
+ if (!runtime.ownerContext)
133
+ throw new Error("Owner 共享上下文尚未配置");
134
+ return runtime.ownerContext.get();
135
+ }
136
+ }
137
+ }
138
+ function parseExplicitCommand(task) {
139
+ if (!task.startsWith("/assistant ") && !task.startsWith("/sessions"))
140
+ return undefined;
141
+ if (/[\r\n]/.test(task))
142
+ return { kind: "invalid" };
143
+ if (task.startsWith("/sessions"))
144
+ return /^\/sessions(?:\s|$)/.test(task) ? { kind: "sessions", command: task } : { kind: "invalid" };
145
+ if (task === "/assistant context refresh")
146
+ return { kind: "context-refresh" };
147
+ const agentCall = task.match(/^\/assistant agent call ([a-z0-9][a-z0-9-]{0,63}) ([\s\S]{1,20000})$/);
148
+ if (agentCall)
149
+ return { kind: "agent-call", agentId: agentCall[1], task: agentCall[2] };
150
+ const create = task.match(/^\/assistant aid create ([A-Za-z0-9][A-Za-z0-9._-]{2,255})(?: --owner ([A-Za-z0-9][A-Za-z0-9._-]{2,255}))?$/);
151
+ if (create)
152
+ return { kind: "create", aid: create[1], ...(create[2] ? { ownerAid: create[2] } : {}) };
153
+ const bind = task.match(/^\/assistant aid bind ([A-Za-z0-9][A-Za-z0-9._-]{2,255}) ([A-Za-z0-9][A-Za-z0-9._-]{0,127})( --replace)?$/);
154
+ if (bind)
155
+ return { kind: "bind", aid: bind[1], agentId: bind[2], replace: Boolean(bind[3]) };
156
+ return { kind: "invalid" };
157
+ }
158
+ function stringifyToolResult(value) {
159
+ let text;
160
+ try {
161
+ text = typeof value === "string" ? value : JSON.stringify(value);
162
+ }
163
+ catch {
164
+ text = "工具返回结果不可序列化";
165
+ }
166
+ return text.length > 64_000 ? `${text.slice(0, 64_000)}\n[结果已截断]` : text;
167
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "agent-bridge-pa",
3
+ "version": "1.0.7",
4
+ "description": "mu-agent-bridge 的个人助理管理 Agent 插件。",
5
+ "keywords": [
6
+ "mu-agent-bridge-plugin",
7
+ "mu-agent-bridge-agent"
8
+ ],
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://codeup.aliyun.com/6808da56fb3da14b899afd54/agent_bridge.git",
12
+ "directory": "packages/personal-assistant"
13
+ },
14
+ "main": "dist/src-ts/plugins/personal-assistant/index.js",
15
+ "files": [
16
+ "dist/",
17
+ "plugin.json",
18
+ "config.schema.json",
19
+ "README.md"
20
+ ],
21
+ "agentBridge": {
22
+ "id": "personal-assistant",
23
+ "plugin": "./plugin.json",
24
+ "type": "agent",
25
+ "requires": {
26
+ "mu-agent-bridge": ">=1.0.78"
27
+ }
28
+ },
29
+ "publishConfig": {
30
+ "access": "public",
31
+ "registry": "https://registry.npmjs.org"
32
+ },
33
+ "engines": {
34
+ "node": ">=22.16.0"
35
+ },
36
+ "dependencies": {
37
+ "ajv": "^8.20.0"
38
+ }
39
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "personal-assistant",
3
+ "version": "1.0.7",
4
+ "type": "agent",
5
+ "displayName": "个人助理",
6
+ "entry": "dist/src-ts/plugins/personal-assistant/index.js",
7
+ "apiVersion": "1",
8
+ "process": "in-process",
9
+ "capabilities": [
10
+ "chat",
11
+ "management",
12
+ "health"
13
+ ],
14
+ "configSchema": "config.schema.json"
15
+ }
@@ -1,7 +1,42 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AgentOperationError = exports.AgentError = void 0;
4
+ exports.abortable = abortable;
4
5
  exports.errorDetails = errorDetails;
6
+ async function abortable(promise, signal) {
7
+ if (!signal)
8
+ return promise;
9
+ if (signal.aborted) {
10
+ // promise 已在调用方启动,先观察其拒绝,避免预取消时产生未处理拒绝。
11
+ void promise.catch(() => undefined);
12
+ signal.throwIfAborted();
13
+ }
14
+ return new Promise((resolve, reject) => {
15
+ let settled = false;
16
+ const cleanup = () => signal.removeEventListener("abort", abort);
17
+ const abort = () => {
18
+ if (settled)
19
+ return;
20
+ settled = true;
21
+ cleanup();
22
+ reject(signal.reason);
23
+ };
24
+ signal.addEventListener("abort", abort, { once: true });
25
+ promise.then((value) => {
26
+ if (settled)
27
+ return;
28
+ settled = true;
29
+ cleanup();
30
+ resolve(value);
31
+ }, (error) => {
32
+ if (settled)
33
+ return;
34
+ settled = true;
35
+ cleanup();
36
+ reject(error);
37
+ });
38
+ });
39
+ }
5
40
  class AgentError extends Error {
6
41
  constructor(message, options) {
7
42
  super(message, options);
@@ -5,7 +5,7 @@ const promises_1 = require("node:fs/promises");
5
5
  const node_os_1 = require("node:os");
6
6
  const node_path_1 = require("node:path");
7
7
  /** 空闲时先备份旧草稿,再通过编辑器原生删除事件清理,避免只修改 DOM。 */
8
- async function recoverCdpDraft(evaluate, editorSelector, stopSelector, dataDir = (0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-draft-recovery")) {
8
+ async function recoverCdpDraft(evaluate, editorSelector, stopSelector, dataDir = (0, node_path_1.join)((0, node_os_1.tmpdir)(), "agent-bridge-draft-recovery"), expected) {
9
9
  const state = await evaluate(`(() => ({
10
10
  text: document.querySelector(${JSON.stringify(editorSelector)})?.innerText ?? null,
11
11
  generating: Boolean(document.querySelector(${JSON.stringify(stopSelector)})),
@@ -15,13 +15,16 @@ async function recoverCdpDraft(evaluate, editorSelector, stopSelector, dataDir =
15
15
  throw new Error("桌面端正在生成回复,不能清理输入或切换会话");
16
16
  if (state.text === null)
17
17
  throw new Error("桌面端输入框未就绪");
18
+ if (expected && (state.text !== expected.text || state.url !== expected.url))
19
+ return;
18
20
  if (!state.text?.trim())
19
21
  return;
20
22
  await (0, promises_1.mkdir)(dataDir, { recursive: true, mode: 0o700 });
21
23
  await (0, promises_1.appendFile)((0, node_path_1.join)(dataDir, "draft-recovery.jsonl"), JSON.stringify({ time: new Date().toISOString(), url: state.url, text: state.text }) + "\n", { encoding: "utf8", mode: 0o600 });
22
24
  const cleared = await evaluate(`(() => {
23
25
  const editor = document.querySelector(${JSON.stringify(editorSelector)});
24
- const unchanged = () => editor && editor.innerText === ${JSON.stringify(state.text)}
26
+ const unchanged = () => editor && document.querySelector(${JSON.stringify(editorSelector)}) === editor
27
+ && editor.innerText === ${JSON.stringify(state.text)} && (document.URL ?? '') === ${JSON.stringify(state.url)}
25
28
  && !document.querySelector(${JSON.stringify(stopSelector)});
26
29
  if (!unchanged()) return false;
27
30
  editor.focus();