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
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.QwenworkPlugin = exports.qwenworkManifest = void 0;
4
4
  exports.createQwenworkPlugin = createQwenworkPlugin;
5
+ const promises_1 = require("node:fs/promises");
6
+ const node_path_1 = require("node:path");
5
7
  const agent_1 = require("../../agent");
6
8
  const openai_adapter_1 = require("./openai-adapter");
7
9
  const cdp_client_1 = require("./cdp-client");
@@ -10,21 +12,29 @@ const desktop_launch_1 = require("../desktop-launch");
10
12
  const session_history_1 = require("./session-history");
11
13
  exports.qwenworkManifest = {
12
14
  id: "qwenwork",
13
- version: "1.0.24",
15
+ version: "1.0.28",
14
16
  displayName: "千问办公",
15
17
  entry: "dist/index.js",
16
18
  apiVersion: "1",
17
19
  process: "in-process",
18
- capabilities: ["chat", "openai-compatible", "health"],
20
+ capabilities: ["chat", "openai-compatible", "health", "model-provider"],
19
21
  configSchema: "config.schema.json",
20
22
  defaults: { cdpPort: 9228, httpPort: 17893 },
21
23
  };
22
24
  function asNumber(value, fallback) {
23
25
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
24
26
  }
27
+ function validModelSessionId(value) {
28
+ return typeof value === "string" && Boolean(value.trim()) && value.length <= 512 && !/[\u0000-\u001f]/.test(value);
29
+ }
25
30
  /** 千问插件由后台守护,所有通道共用请求队列和恢复流程。 */
26
31
  class QwenworkPlugin {
27
32
  manifest = exports.qwenworkManifest;
33
+ get modelProvider() {
34
+ if (this.relayTarget || !this.client?.complete || !this.client.createSession || !this.client.activateSession)
35
+ return undefined;
36
+ return { complete: (request) => this.completeModelProvider(request) };
37
+ }
28
38
  sessionHistory;
29
39
  get attachmentInput() { return Boolean(this.relayTarget || this.client?.attachmentInput); }
30
40
  sessionOperations = [];
@@ -42,6 +52,7 @@ class QwenworkPlugin {
42
52
  state = "stopped";
43
53
  message = "";
44
54
  healthIntervalMs;
55
+ restartDesktopHook;
45
56
  healthTimer;
46
57
  recovery;
47
58
  context;
@@ -53,11 +64,14 @@ class QwenworkPlugin {
53
64
  busy = false;
54
65
  taskCount = 0;
55
66
  stopped = true;
67
+ modelSessions = new Map();
68
+ modelSessionsPath;
56
69
  constructor(options = {}) {
57
70
  this.injectedClient = options.client;
58
71
  this.configuredCdpPort = options.cdpPort;
59
72
  this.configuredHttpPort = options.httpPort;
60
73
  this.healthIntervalMs = options.healthIntervalMs ?? 30_000;
74
+ this.restartDesktopHook = options.restartDesktop;
61
75
  }
62
76
  async activate(context) {
63
77
  if (this.state === "ready")
@@ -68,6 +82,21 @@ class QwenworkPlugin {
68
82
  this.lastHeartbeat = undefined;
69
83
  this.context = context;
70
84
  try {
85
+ this.modelSessions.clear();
86
+ this.modelSessionsPath = typeof context.dataDir === "string" && context.dataDir ? (0, node_path_1.join)(context.dataDir, "model-provider-sessions.json") : undefined;
87
+ try {
88
+ if (!this.modelSessionsPath)
89
+ throw Object.assign(new Error("无持久化目录"), { code: "ENOENT" });
90
+ const saved = JSON.parse(await (0, promises_1.readFile)(this.modelSessionsPath, "utf8"));
91
+ if (!saved || typeof saved !== "object" || Array.isArray(saved) || Object.entries(saved).some(([key, value]) => !validModelSessionId(key) || !validModelSessionId(value)))
92
+ throw new Error("千问个人助理模型会话记录无效");
93
+ for (const [key, value] of Object.entries(saved))
94
+ this.modelSessions.set(key, value);
95
+ }
96
+ catch (error) {
97
+ if (error.code !== "ENOENT")
98
+ throw error;
99
+ }
71
100
  const config = context.config;
72
101
  const relayTarget = config.relayTarget;
73
102
  if (relayTarget !== undefined && relayTarget !== "dsh")
@@ -106,6 +135,7 @@ class QwenworkPlugin {
106
135
  if (!executable)
107
136
  throw new Error("未找到 QwenWorkCN.exe,请配置 executablePath");
108
137
  context.logger?.info(`正在启动千问办公,等待 CDP ${this.activeCdpPort}`, { executablePath: executable });
138
+ await this.restartDesktopProcess(executable);
109
139
  try {
110
140
  await (0, desktop_launch_1.launchAndWait)(executable, [`--remote-debugging-port=${this.activeCdpPort}`], () => client.connect(), typeof config.startupTimeoutMs === "number" ? config.startupTimeoutMs : 30_000);
111
141
  }
@@ -140,8 +170,15 @@ class QwenworkPlugin {
140
170
  throw error;
141
171
  }
142
172
  }
143
- async deactivate(_reason) {
173
+ async deactivate(reason, options) {
174
+ const reloadDesktop = !options?.preserveDesktop && reason === "reload" && Boolean(this.client) && !this.relayTarget;
144
175
  await this.cleanup();
176
+ if (reloadDesktop) {
177
+ if (this.restartDesktopHook)
178
+ await this.restartDesktopHook();
179
+ else if (!this.injectedClient && process.platform === "win32")
180
+ await this.restartDesktopProcess();
181
+ }
145
182
  this.state = "stopped";
146
183
  this.stopped = true;
147
184
  }
@@ -154,8 +191,6 @@ class QwenworkPlugin {
154
191
  return { status: this.state, ...(this.message ? { message: this.message } : {}), details };
155
192
  }
156
193
  async handle(request) {
157
- if (this.recovery)
158
- await this.recovery;
159
194
  if (this.state === "stopped" || (!this.relayTarget && !this.client))
160
195
  throw new Error("qwenwork 插件未就绪");
161
196
  return this.enqueueTask(() => this.completeRequest(request));
@@ -170,9 +205,8 @@ class QwenworkPlugin {
170
205
  throw new Error("千问办公当前忙,无法创建新会话");
171
206
  if (!this.client?.createSession)
172
207
  throw new Error("千问办公当前传输不支持新建会话");
173
- if (!this.client.connected())
174
- throw new Error("千问办公 CDP 未连接");
175
208
  return this.enqueueTask(async () => {
209
+ await this.ensureConnected();
176
210
  await this.client.createSession(request.name);
177
211
  return { text: "千问办公已创建新会话", sessionId };
178
212
  });
@@ -185,8 +219,7 @@ class QwenworkPlugin {
185
219
  if (!this.client)
186
220
  throw new Error("qwenwork 插件未就绪");
187
221
  try {
188
- if (!this.client.connected())
189
- throw new Error("千问 CDP 已断开,等待空闲后自动恢复");
222
+ await this.ensureConnected(signal);
190
223
  const reply = this.client.complete ? (await this.client.complete(prompt, timeoutMs, signal, undefined, undefined, onMessage)).text : await this.client.direct(prompt, timeoutMs, signal);
191
224
  if ((0, cdp_client_1.isQwenApiUnavailableReply)(reply))
192
225
  throw new agent_1.AgentOperationError("QWEN_REMOTE_ERROR", "等待千问办公回复", new Error("千问生成接口不可用;桌面未提供具体服务端错误码,CDP 仍连接,未重启或重新提交任务"));
@@ -196,7 +229,7 @@ class QwenworkPlugin {
196
229
  return reply;
197
230
  }
198
231
  catch (error) {
199
- if (!signal?.aborted) {
232
+ if (!this.stopped && !signal?.aborted) {
200
233
  this.message = error instanceof Error ? error.message : String(error);
201
234
  this.failures = this.client.connected() ? 0 : 2;
202
235
  this.state = "degraded";
@@ -204,21 +237,23 @@ class QwenworkPlugin {
204
237
  throw error;
205
238
  }
206
239
  }
207
- async completeRequest(request) {
240
+ async completeRequest(request, modelRequest = false) {
208
241
  if (this.relayTarget) {
209
242
  return this.callPlugin(this.relayTarget, request);
210
243
  }
211
244
  if (!this.client)
212
245
  throw new Error("qwenwork 插件未就绪");
213
246
  try {
214
- if (!this.client.connected())
215
- throw new Error("千问 CDP 已断开,等待空闲后自动恢复");
247
+ if (modelRequest && !this.client.connected())
248
+ throw new Error("千问 CDP 已断开,模型请求不会启动或重启桌面");
249
+ if (!modelRequest)
250
+ await this.ensureConnected(request.signal);
216
251
  if (request.attachments?.length && (!this.client.attachmentInput || !this.client.complete))
217
252
  throw new Error("千问当前客户端不支持附件输入");
218
253
  const timeoutMs = request.timeoutMs ?? asNumber(this.context?.config.timeoutMs, 240_000);
219
254
  const response = this.client.complete
220
- ? await this.client.complete(request.task, timeoutMs, undefined, undefined, request.attachments, request.onMessage)
221
- : { text: await this.complete(request.task, timeoutMs) };
255
+ ? await this.client.complete(request.task, timeoutMs, request.signal, undefined, request.attachments, request.onMessage, modelRequest)
256
+ : { text: await this.complete(request.task, timeoutMs, request.signal) };
222
257
  if ((0, cdp_client_1.isQwenApiUnavailableReply)(response.text))
223
258
  throw new agent_1.AgentOperationError("QWEN_REMOTE_ERROR", "等待千问办公回复", new Error("千问生成接口不可用;桌面未提供具体服务端错误码,CDP 仍连接,未重启或重新提交任务"));
224
259
  this.failures = 0;
@@ -227,12 +262,66 @@ class QwenworkPlugin {
227
262
  return response;
228
263
  }
229
264
  catch (error) {
230
- this.message = error instanceof Error ? error.message : String(error);
231
- this.failures = this.client.connected() ? 0 : 2;
232
- this.state = "degraded";
265
+ if (!this.stopped && !request.signal?.aborted && !modelRequest) {
266
+ this.message = error instanceof Error ? error.message : String(error);
267
+ this.failures = this.client.connected() ? 0 : 2;
268
+ this.state = "degraded";
269
+ }
233
270
  throw error;
234
271
  }
235
272
  }
273
+ async completeModelProvider(request) {
274
+ let stage = "千问办公模型排队(queue)";
275
+ try {
276
+ request.signal.throwIfAborted();
277
+ const run = this.enqueueTask(async () => {
278
+ request.signal.throwIfAborted();
279
+ stage = "连接千问办公模型(connect)";
280
+ const client = this.client;
281
+ if (this.state !== "ready" || !client?.connected() || !client.createSession || !client.activateSession || !client.complete)
282
+ throw new Error("千问办公未连接或不支持隔离模型会话,模型请求不会启动或重启桌面");
283
+ const previousSessionId = await client.currentSessionId?.();
284
+ try {
285
+ stage = "准备千问办公模型会话(submit)";
286
+ const desktopSessionId = this.modelSessions.get(request.sessionId);
287
+ if (desktopSessionId)
288
+ await client.activateSession(desktopSessionId);
289
+ else
290
+ await client.createSession(undefined, true, true);
291
+ request.signal.throwIfAborted();
292
+ stage = "等待千问办公模型生成(generate)";
293
+ const response = await this.completeRequest({ task: request.prompt, sessionId: request.sessionId, timeoutMs: request.timeoutMs, signal: request.signal }, true);
294
+ const actualSessionId = response.sessionId ?? await client.currentSessionId?.();
295
+ if (!validModelSessionId(actualSessionId))
296
+ throw new Error("千问未返回可恢复的个人助理模型会话标识");
297
+ if (actualSessionId !== desktopSessionId) {
298
+ this.modelSessions.set(request.sessionId, actualSessionId);
299
+ const path = this.modelSessionsPath;
300
+ if (path) {
301
+ await (0, promises_1.mkdir)(this.context.dataDir ?? ".", { recursive: true });
302
+ await (0, promises_1.writeFile)(`${path}.tmp`, JSON.stringify(Object.fromEntries(this.modelSessions)), { mode: 0o600 });
303
+ await (0, promises_1.rename)(`${path}.tmp`, path);
304
+ }
305
+ }
306
+ return { text: response.text };
307
+ }
308
+ finally {
309
+ if (client.connected()) {
310
+ if (previousSessionId)
311
+ await client.activateSession(previousSessionId);
312
+ else
313
+ await client.createSession(undefined, false, true);
314
+ }
315
+ }
316
+ });
317
+ return await (0, agent_1.abortable)(run, request.signal);
318
+ }
319
+ catch (error) {
320
+ if (error instanceof agent_1.AgentOperationError)
321
+ throw error;
322
+ throw new agent_1.AgentOperationError("QWEN_MODEL_FAILED", stage, error);
323
+ }
324
+ }
236
325
  registerRoutes(http) {
237
326
  if (!this.adapter)
238
327
  return;
@@ -262,6 +351,14 @@ class QwenworkPlugin {
262
351
  this.callPlugin = undefined;
263
352
  this.pluginStatus = undefined;
264
353
  }
354
+ async restartDesktopProcess(configuredExecutable) {
355
+ const config = this.context?.config;
356
+ const executable = configuredExecutable ?? await (0, desktop_launch_1.findWindowsExecutable)("QwenWorkCN.exe", typeof config?.executablePath === "string" ? config.executablePath : undefined);
357
+ if (!executable)
358
+ throw new Error("未找到 QwenWorkCN.exe,请配置 executablePath");
359
+ const processIds = await (0, desktop_launch_1.terminateWindowsDesktop)(executable);
360
+ this.context?.logger?.info("千问办公重载前已清理旧进程,将以 CDP 模式启动", { processIds, executable });
361
+ }
265
362
  startHealthWatch() {
266
363
  if (this.relayTarget || !this.client || this.healthTimer)
267
364
  return;
@@ -284,9 +381,26 @@ class QwenworkPlugin {
284
381
  });
285
382
  }
286
383
  async recover() {
384
+ if (this.stopped || this.busy)
385
+ return;
386
+ try {
387
+ await this.reconnect();
388
+ }
389
+ catch { /* 失败已记录,留待下次空闲检查。 */ }
390
+ }
391
+ async ensureConnected(signal) {
392
+ signal?.throwIfAborted();
393
+ if (this.stopped || !this.client)
394
+ throw new Error("qwenwork 插件未就绪");
395
+ await this.reconnect();
396
+ signal?.throwIfAborted();
397
+ if (this.stopped)
398
+ throw new Error("qwenwork 插件未就绪");
399
+ }
400
+ async reconnect() {
287
401
  if (this.recovery)
288
402
  return this.recovery;
289
- if (this.stopped || this.busy)
403
+ if (this.stopped)
290
404
  return;
291
405
  const client = this.client;
292
406
  if (!client || client.connected())
@@ -307,11 +421,12 @@ class QwenworkPlugin {
307
421
  this.restarts += 1;
308
422
  this.context?.logger?.info("千问 CDP 自动重连成功", { restarts: this.restarts });
309
423
  })().catch((error) => {
310
- if (this.stopped)
311
- return;
312
- this.state = "failed";
313
- this.message = error instanceof Error ? error.message : String(error);
314
- this.context?.logger?.error(`千问 CDP 重连失败,桌面未重启,下次空闲检查重试:${this.message}`);
424
+ if (!this.stopped) {
425
+ this.state = "failed";
426
+ this.message = error instanceof Error ? error.message : String(error);
427
+ this.context?.logger?.error(`千问 CDP 重连失败,桌面未重启,下次空闲检查重试:${this.message}`);
428
+ }
429
+ throw error;
315
430
  }).finally(() => { this.recovery = undefined; });
316
431
  return this.recovery;
317
432
  }