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
@@ -8,6 +8,7 @@ const promises_1 = require("node:fs/promises");
8
8
  const node_os_1 = require("node:os");
9
9
  const node_path_1 = require("node:path");
10
10
  const agent_1 = require("../../agent");
11
+ const agent_2 = require("../../agent");
11
12
  const attachments_1 = require("../../attachments");
12
13
  const plugin_1 = require("../../plugin");
13
14
  const cdp_client_1 = require("./cdp-client");
@@ -16,9 +17,9 @@ const session_history_1 = require("./session-history");
16
17
  const desktop_launch_1 = require("../desktop-launch");
17
18
  const desktop_launch_2 = require("./desktop-launch");
18
19
  exports.workbuddyManifest = {
19
- id: "workbuddy", version: "1.1.32", displayName: "WorkBuddy", type: "agent",
20
+ id: "workbuddy", version: "1.1.35", displayName: "WorkBuddy", type: "agent",
20
21
  entry: "dist/index.js", apiVersion: "1", process: "in-process",
21
- capabilities: ["chat", "health"], configSchema: "config.schema.json",
22
+ capabilities: ["chat", "health", "model-provider"], configSchema: "config.schema.json",
22
23
  };
23
24
  function extractExpertQuery(task) {
24
25
  const text = task.normalize("NFKC");
@@ -40,13 +41,19 @@ function findExecutable(configured) {
40
41
  class WorkbuddyPlugin {
41
42
  options;
42
43
  manifest = exports.workbuddyManifest;
44
+ get modelProvider() {
45
+ if (this.transport === "cli" || (this.transport !== "cdp" && this.cliPath) || !this.client?.createTask || !this.client.complete)
46
+ return undefined;
47
+ return { complete: (request) => this.completeModelProvider(request) };
48
+ }
43
49
  client;
44
50
  process;
45
51
  reconnect;
46
52
  cliPath;
47
53
  model;
48
54
  transport = "auto";
49
- timeoutMs = 3_600_000;
55
+ replyTimeoutLimitMs;
56
+ timeoutMs = cdp_client_1.WORKBUDDY_MAX_WAIT_MS;
50
57
  queue = Promise.resolve();
51
58
  pending = 0;
52
59
  activeSessionId;
@@ -70,6 +77,7 @@ class WorkbuddyPlugin {
70
77
  sessionHistory;
71
78
  constructor(options = {}) {
72
79
  this.options = options;
80
+ this.replyTimeoutLimitMs = options.replyTimeoutLimitMs ?? cdp_client_1.WORKBUDDY_MAX_WAIT_MS;
73
81
  }
74
82
  get attachmentInput() { return Boolean(this.client?.attachmentInput && this.client.complete && this.transport !== "cli" && (!this.cliPath || this.transport === "cdp")); }
75
83
  async activate(context) {
@@ -77,7 +85,7 @@ class WorkbuddyPlugin {
77
85
  if (config.transport !== undefined && !["auto", "cli", "cdp"].includes(String(config.transport)))
78
86
  throw new Error("transport 只能是 auto、cli 或 cdp");
79
87
  this.transport = config.transport ?? "auto";
80
- this.timeoutMs = typeof config.timeoutMs === "number" && config.timeoutMs > 0 ? config.timeoutMs : 3_600_000;
88
+ this.timeoutMs = Math.min(typeof config.timeoutMs === "number" && config.timeoutMs > 0 ? config.timeoutMs : 3_600_000, this.replyTimeoutLimitMs);
81
89
  this.model = typeof config.model === "string" && config.model.trim() ? config.model : undefined;
82
90
  this.cliPath = (0, cli_client_1.findCli)(typeof config.cliPath === "string" ? config.cliPath : undefined);
83
91
  this.failure = undefined;
@@ -231,31 +239,92 @@ class WorkbuddyPlugin {
231
239
  return { status: "ready", details: { transport: "cdp" } };
232
240
  if (this.transport !== "cdp" && this.cliPath && (0, node_fs_1.existsSync)(this.cliPath))
233
241
  return { status: "ready", details: { transport: "cli" } };
234
- return { status: "failed", message: this.failure ?? "WorkBuddy 未连接", details: { transport: this.transport } };
242
+ return { status: "failed", message: this.failure ?? "WorkBuddy CDP 未连接;桌面升级后请在后台使用“重启桌面”恢复连接", details: { transport: this.transport } };
235
243
  }
236
244
  async handle(request) {
237
245
  if (!request.task.trim())
238
246
  throw new Error("消息内容不能为空");
239
247
  (0, attachments_1.validateAttachments)(request.attachments);
240
248
  const run = this.enqueue(async () => {
249
+ request.signal?.throwIfAborted();
241
250
  try {
242
- return await this.complete(request);
251
+ const response = await this.complete(request);
252
+ await this.synchronizeSession();
253
+ return response;
243
254
  }
244
- finally {
245
- if (this.activeSessionId && this.desktopSessionValid && this.client?.conversationId) {
246
- try {
247
- this.activeDesktopConversationId = await this.client.conversationId();
248
- await this.persistKnownSessions();
249
- }
250
- catch (error) {
251
- this.dailyPointsLogger?.warn("WorkBuddy 会话状态同步失败,已保留本轮回复", { stage: "完成后读取会话标识或保存映射", error: error instanceof Error ? error.message : String(error) });
252
- }
253
- }
255
+ catch (error) {
256
+ // 失败时桌面可能已切换,保留原绑定并要求重新校验或恢复。
257
+ this.desktopSessionValid = false;
258
+ throw error;
254
259
  }
255
260
  });
256
261
  const response = await run;
257
262
  return { ...response, sessionId: request.sessionId ?? response.sessionId };
258
263
  }
264
+ async synchronizeSession() {
265
+ if (this.activeSessionId && this.desktopSessionValid && this.client?.conversationId) {
266
+ try {
267
+ const conversationId = await this.client.conversationId();
268
+ if (this.activeDesktopConversationId && conversationId !== this.activeDesktopConversationId) {
269
+ this.desktopSessionValid = false;
270
+ throw new Error("WorkBuddy 桌面任务已切换,已保留原会话绑定");
271
+ }
272
+ this.activeDesktopConversationId = conversationId;
273
+ if (this.activeDesktopConversationId)
274
+ this.sessionBindings.set(this.activeSessionId, { conversationId: this.activeDesktopConversationId, expert: this.activeExpert });
275
+ await this.persistKnownSessions();
276
+ }
277
+ catch (error) {
278
+ this.dailyPointsLogger?.warn("WorkBuddy 会话状态同步失败,已保留本轮回复", { stage: "完成后读取会话标识或保存映射", error: error instanceof Error ? error.message : String(error) });
279
+ }
280
+ }
281
+ }
282
+ async completeModelProvider(request) {
283
+ let stage = "WorkBuddy 模型排队(queue)";
284
+ try {
285
+ request.signal.throwIfAborted();
286
+ const run = this.enqueue(async () => {
287
+ request.signal.throwIfAborted();
288
+ const client = this.client;
289
+ if (!client?.connected() || !client.complete)
290
+ throw new Error("WorkBuddy CDP 未连接,模型请求不会启动或重启桌面");
291
+ const availability = await client.historyAvailability?.();
292
+ if (availability?.waiting || availability?.generating || availability?.draft)
293
+ throw new Error("WorkBuddy 当前有用户草稿、待确认操作或正在生成回复,模型请求未切换会话");
294
+ stage = "连接 WorkBuddy 模型(connect)";
295
+ const previous = { sessionId: this.activeSessionId, conversationId: await client.conversationId?.(), expert: this.activeExpert, expertSession: this.expertSession, valid: this.desktopSessionValid };
296
+ try {
297
+ stage = "等待 WorkBuddy 模型生成(generate)";
298
+ const response = await this.complete({ task: request.prompt, sessionId: request.sessionId, timeoutMs: request.timeoutMs, signal: request.signal }, true);
299
+ return { text: response.text };
300
+ }
301
+ finally {
302
+ await this.synchronizeSession();
303
+ if (client.connected()) {
304
+ if (previous.conversationId) {
305
+ if (!client.activateConversation)
306
+ throw new Error("WorkBuddy 无法恢复用户原会话");
307
+ await client.activateConversation(previous.conversationId, true);
308
+ }
309
+ else if (client.conversationId)
310
+ await client.createTask();
311
+ }
312
+ this.activeSessionId = previous.sessionId;
313
+ this.activeDesktopConversationId = previous.conversationId;
314
+ this.activeExpert = previous.expert;
315
+ this.expertSession = previous.expertSession;
316
+ this.desktopSessionValid = previous.valid;
317
+ await this.persistKnownSessions();
318
+ }
319
+ });
320
+ return await (0, agent_1.abortable)(run, request.signal);
321
+ }
322
+ catch (error) {
323
+ if (error instanceof agent_2.AgentOperationError)
324
+ throw error;
325
+ throw new agent_2.AgentOperationError("WORKBUDDY_MODEL_FAILED", stage, error);
326
+ }
327
+ }
259
328
  async controlSession(request) {
260
329
  if (this.pending)
261
330
  throw new Error("WorkBuddy 当前忙,无法创建新会话");
@@ -277,17 +346,20 @@ class WorkbuddyPlugin {
277
346
  return { text: "WorkBuddy 已创建新会话", sessionId };
278
347
  });
279
348
  }
280
- async complete(request) {
349
+ async complete(request, modelRequest = false) {
281
350
  let stage = "连接 WorkBuddy 桌面";
282
351
  try {
283
- const timeout = request.timeoutMs ?? this.timeoutMs;
284
- const expert = extractExpertQuery(request.task);
352
+ const timeout = Math.min(request.timeoutMs ?? this.timeoutMs, this.replyTimeoutLimitMs);
353
+ const expert = modelRequest || this.options.expertSelection === false ? undefined : extractExpertQuery(request.task);
285
354
  const usesCli = Boolean(this.cliPath && this.transport !== "cdp" && !expert);
286
355
  const hasAttachments = Array.isArray(request.attachments) && request.attachments.length > 0;
287
356
  if (hasAttachments && !this.attachmentInput)
288
357
  throw new Error("WorkBuddy 当前传输不支持附件输入");
289
- if (!usesCli && !this.client?.connected())
358
+ if (!usesCli && !this.client?.connected()) {
359
+ if (modelRequest)
360
+ throw new Error("WorkBuddy CDP 已断开,模型请求不会启动或重启桌面");
290
361
  await this.reconnect?.();
362
+ }
291
363
  const pendingInteractionSessionId = this.client?.pendingInteractionSessionId?.();
292
364
  if (!usesCli && pendingInteractionSessionId && pendingInteractionSessionId !== request.sessionId)
293
365
  throw new Error("WorkBuddy 正在等待另一个会话的选择");
@@ -299,7 +371,7 @@ class WorkbuddyPlugin {
299
371
  throw new Error("WorkBuddy 桌面任务状态未知,请先创建新会话");
300
372
  stage = "准备或恢复 WorkBuddy 会话";
301
373
  if (!usesCli)
302
- await this.ensureSession(request.sessionId);
374
+ await this.ensureSession(request.sessionId, modelRequest);
303
375
  stage = "执行 WorkBuddy 桌面任务";
304
376
  if (expert) {
305
377
  if (!this.client?.connected())
@@ -312,7 +384,7 @@ class WorkbuddyPlugin {
312
384
  this.expertSession = true;
313
385
  try {
314
386
  if (this.client.complete)
315
- return await this.client.complete({ ...request, timeoutMs: timeout }, select, false);
387
+ return await this.client.complete({ ...request, timeoutMs: timeout }, select, false, request.sessionId ? this.activeDesktopConversationId ?? null : undefined);
316
388
  return { text: await this.client.direct(request.task, timeout, select) };
317
389
  }
318
390
  catch (error) {
@@ -332,7 +404,7 @@ class WorkbuddyPlugin {
332
404
  this.activeExpert = null;
333
405
  try {
334
406
  if (this.client.complete)
335
- return await this.client.complete({ ...request, timeoutMs: timeout }, undefined, reset);
407
+ return await this.client.complete({ ...request, timeoutMs: timeout }, undefined, reset, request.sessionId ? this.activeDesktopConversationId ?? null : undefined);
336
408
  return { text: await this.client.direct(request.task, timeout, undefined, reset) };
337
409
  }
338
410
  catch (error) {
@@ -342,12 +414,12 @@ class WorkbuddyPlugin {
342
414
  }
343
415
  }
344
416
  catch (error) {
345
- if (error instanceof agent_1.AgentOperationError || error?.stage)
417
+ if (error instanceof agent_2.AgentOperationError || error?.stage)
346
418
  throw error;
347
- throw new agent_1.AgentOperationError("WORKBUDDY_TASK_FAILED", stage, error);
419
+ throw new agent_2.AgentOperationError("WORKBUDDY_TASK_FAILED", stage, error);
348
420
  }
349
421
  }
350
- async ensureSession(sessionId) {
422
+ async ensureSession(sessionId, modelRequest = false) {
351
423
  if (!sessionId)
352
424
  return;
353
425
  if (!this.client?.connected())
@@ -370,7 +442,7 @@ class WorkbuddyPlugin {
370
442
  }
371
443
  if (!this.client.activateConversation)
372
444
  throw new Error("WorkBuddy 不支持恢复旧 WorkBuddy 会话");
373
- await this.client.activateConversation(conversationId);
445
+ await this.client.activateConversation(conversationId, modelRequest);
374
446
  this.activeSessionId = sessionId;
375
447
  this.activeDesktopConversationId = conversationId;
376
448
  this.activeExpert = binding?.expert;
@@ -462,22 +534,33 @@ class WorkbuddyPlugin {
462
534
  const profile = (0, node_path_1.join)(dataDir ?? (0, node_path_1.join)((0, node_os_1.homedir)(), ".agent-bridge", "workbuddy"), "desktop");
463
535
  const launch = (file, args) => (0, desktop_launch_2.launchWorkbuddyDesktop)(file, args, profile, port);
464
536
  const timeoutMs = typeof config.startupTimeoutMs === "number" ? config.startupTimeoutMs : 30_000;
537
+ const connectOrLaunch = async () => {
538
+ try {
539
+ await this.client.connect();
540
+ return;
541
+ }
542
+ catch (first) {
543
+ if (config.autoStart === false || this.options.client)
544
+ throw first;
545
+ if (!executable)
546
+ throw new Error("未找到 WorkBuddy.exe,请配置 executablePath");
547
+ logger.info(`WorkBuddy CDP ${port} 不可用,启动带调试参数的桥接实例`);
548
+ await (0, desktop_launch_1.launchManagedAndWait)(executable, [`--remote-debugging-port=${port}`], profile, () => this.client.connect(), timeoutMs, child => { this.process = child; }, launch);
549
+ }
550
+ };
465
551
  this.reconnect = async () => {
466
- // 请求恢复只重连 socket,页面错误不能触发桌面进程重启。
467
- await this.client.connect();
552
+ try {
553
+ await this.client.connect();
554
+ }
555
+ catch (error) {
556
+ const failure = error;
557
+ // 只有调试端口拒绝连接才重新启动;页面或协议错误不得触碰桌面进程。
558
+ if (failure.code !== "ECONNREFUSED" && failure.cause?.code !== "ECONNREFUSED")
559
+ throw error;
560
+ await connectOrLaunch();
561
+ }
468
562
  };
469
- try {
470
- await this.client.connect();
471
- return;
472
- }
473
- catch (first) {
474
- if (config.autoStart === false || this.options.client)
475
- throw first;
476
- if (!executable)
477
- throw new Error("未找到 WorkBuddy.exe,请配置 executablePath");
478
- logger.info(`WorkBuddy 已启动,等待 CDP ${port}`);
479
- await (0, desktop_launch_1.launchManagedAndWait)(executable, [`--remote-debugging-port=${port}`], profile, () => this.client.connect(), timeoutMs, child => { this.process = child; }, launch);
480
- }
563
+ await connectOrLaunch();
481
564
  }
482
565
  }
483
566
  exports.WorkbuddyPlugin = WorkbuddyPlugin;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-bridge-workbuddy",
3
- "version": "1.1.32",
3
+ "version": "1.1.35",
4
4
  "description": "mu-agent-bridge 的 WorkBuddy 桌面端插件。",
5
5
  "keywords": [
6
6
  "mu-agent-bridge-plugin",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "workbuddy",
3
- "version": "1.1.32",
3
+ "version": "1.1.35",
4
4
  "type": "agent",
5
5
  "displayName": "WorkBuddy",
6
6
  "entry": "dist/src-ts/plugins/workbuddy/index.js",
@@ -8,7 +8,8 @@
8
8
  "process": "in-process",
9
9
  "capabilities": [
10
10
  "chat",
11
- "health"
11
+ "health",
12
+ "model-provider"
12
13
  ],
13
14
  "configSchema": "config.schema.json",
14
15
  "clientDownloadUrl": "https://www.workbuddy.ai/"
@@ -0,0 +1,13 @@
1
+ {
2
+ "type": "object",
3
+ "properties": {
4
+ "aid": { "type": "string", "description": "关联的 AID" },
5
+ "autoStart": { "type": "boolean", "default": true, "description": "CDP 端口拒绝连接时自动发现并启动 ZCode" },
6
+ "executablePath": { "type": "string", "description": "可选的 ZCode.exe 路径,留空时从注册表、开始菜单和安装目录自动发现" },
7
+ "startupArgs": { "type": "array", "items": { "type": "string" }, "default": [], "description": "附加启动参数;CDP 地址和端口由插件自动传入" },
8
+ "startupTimeoutMs": { "type": "integer", "minimum": 1, "default": 30000, "description": "启动后等待 CDP 就绪的时间(毫秒)" },
9
+ "cdpPort": { "type": "integer", "minimum": 1, "maximum": 65535, "default": 9231, "description": "ZCode CDP 端口" },
10
+ "timeoutMs": { "type": "integer", "minimum": 1, "default": 3600000, "description": "单次回复等待时间(毫秒)" }
11
+ },
12
+ "additionalProperties": false
13
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgentOperationError = exports.AgentError = void 0;
4
+ exports.abortable = abortable;
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
+ }
40
+ class AgentError extends Error {
41
+ constructor(message, options) {
42
+ super(message, options);
43
+ this.name = "AgentError";
44
+ }
45
+ }
46
+ exports.AgentError = AgentError;
47
+ /** 保留底层错误码,避免只留下 fetch failed 或超时这类表层提示。 */
48
+ function errorDetails(error) {
49
+ const parts = [];
50
+ const seen = new Set();
51
+ for (let current = error; current && !seen.has(current) && seen.size < 5;) {
52
+ seen.add(current);
53
+ const value = current;
54
+ const message = typeof value.message === "string" ? value.message : String(current);
55
+ parts.push(`${message}${value.code ? `(${String(value.code)})` : ""}`);
56
+ current = value.cause;
57
+ }
58
+ return parts.join(";原因:") || String(error);
59
+ }
60
+ class AgentOperationError extends AgentError {
61
+ code;
62
+ stage;
63
+ constructor(code, stage, cause) {
64
+ super(`${code}:${stage}失败:${errorDetails(cause)}`, { cause });
65
+ this.code = code;
66
+ this.stage = stage;
67
+ }
68
+ }
69
+ exports.AgentOperationError = AgentOperationError;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_TOTAL_ATTACHMENT_BYTES = exports.MAX_ATTACHMENTS = exports.MAX_ATTACHMENT_BYTES = void 0;
4
+ exports.detectImageContentType = detectImageContentType;
5
+ exports.attachmentFilename = attachmentFilename;
6
+ exports.validateAttachment = validateAttachment;
7
+ exports.validateAttachments = validateAttachments;
8
+ exports.asAttachments = asAttachments;
9
+ exports.MAX_ATTACHMENT_BYTES = 32 * 1024 * 1024;
10
+ exports.MAX_ATTACHMENTS = 8;
11
+ exports.MAX_TOTAL_ATTACHMENT_BYTES = 64 * 1024 * 1024;
12
+ function detectImageContentType(data) {
13
+ if (data.length >= 8 && data.slice(0, 8).every((value, index) => value === [137, 80, 78, 71, 13, 10, 26, 10][index]))
14
+ return "image/png";
15
+ if (data.length >= 3 && data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff)
16
+ return "image/jpeg";
17
+ if (data.length >= 12 && String.fromCharCode(...data.slice(0, 4)) === "RIFF" && String.fromCharCode(...data.slice(8, 12)) === "WEBP")
18
+ return "image/webp";
19
+ return undefined;
20
+ }
21
+ function attachmentFilename(filename) {
22
+ if (typeof filename !== "string" || /[\u0000-\u001f\u007f]/.test(filename))
23
+ throw new Error("附件文件名无效");
24
+ const name = filename.split(/[\\/]/).pop() ?? "";
25
+ if (!name.trim() || name === "." || name === "..")
26
+ throw new Error("附件文件名无效");
27
+ return name;
28
+ }
29
+ function validateAttachment(item) {
30
+ if (!item || !(item.data instanceof Uint8Array) || item.data.byteLength === 0)
31
+ throw new Error("附件内容不能为空");
32
+ if (item.data.byteLength > exports.MAX_ATTACHMENT_BYTES)
33
+ throw new Error("单个附件不能超过 32 MiB");
34
+ attachmentFilename(item.filename);
35
+ if (item.kind !== "image" && item.kind !== "file")
36
+ throw new Error("附件类型无效");
37
+ if (typeof item.contentType !== "string" || !/^[A-Za-z0-9!#$&^_.+-]+\/[A-Za-z0-9!#$&^_.+-]+$/.test(item.contentType))
38
+ throw new Error("附件 MIME 类型无效");
39
+ if (item.kind === "image") {
40
+ const detected = detectImageContentType(item.data);
41
+ if (!detected || detected !== item.contentType.toLowerCase())
42
+ throw new Error("图片内容与 MIME 类型不一致");
43
+ }
44
+ }
45
+ function validateAttachments(items) {
46
+ if (!items)
47
+ return;
48
+ if (!Array.isArray(items))
49
+ throw new Error("附件列表无效");
50
+ if (items.length > exports.MAX_ATTACHMENTS)
51
+ throw new Error("单条消息最多包含 8 个附件");
52
+ let total = 0;
53
+ for (const item of items) {
54
+ validateAttachment(item);
55
+ total += item.data.byteLength;
56
+ }
57
+ if (total > exports.MAX_TOTAL_ATTACHMENT_BYTES)
58
+ throw new Error("单条消息附件总大小不能超过 64 MiB");
59
+ }
60
+ function asAttachments(images) {
61
+ return (images ?? []).map((image) => ({ ...image, kind: "image" }));
62
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveRuntimePort = resolveRuntimePort;
4
+ function resolveRuntimePort(config, runtime, pluginId, envName, fallback) {
5
+ const injected = runtime?.ports?.[pluginId];
6
+ if (typeof injected === "number" && Number.isInteger(injected) && injected > 0)
7
+ return injected;
8
+ const configured = config.cdpPort;
9
+ if (typeof configured === "number" && Number.isInteger(configured) && configured > 0)
10
+ return configured;
11
+ const environment = Number(process.env[envName] ?? "");
12
+ return Number.isInteger(environment) && environment > 0 ? environment : fallback;
13
+ }