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.
- package/README.md +17 -10
- package/dist/src-ts/agent.js +35 -0
- package/dist/src-ts/channel-sessions.js +3 -2
- package/dist/src-ts/cli.js +67 -37
- package/dist/src-ts/control-server.js +12 -30
- package/dist/src-ts/core-updater.js +141 -33
- package/dist/src-ts/daemon-process.js +2 -1
- package/dist/src-ts/dsh-agent.js +31 -13
- package/dist/src-ts/http-agent.js +36 -0
- package/dist/src-ts/plugin-catalog.js +11 -2
- package/dist/src-ts/plugin-manager.js +351 -50
- package/dist/src-ts/plugins/abweb/index.js +1 -1
- package/dist/src-ts/plugins/abweb/public/app.js +73 -5
- package/dist/src-ts/plugins/abweb/public/index.html +15 -0
- package/dist/src-ts/plugins/abweb/public/style.css +4 -0
- package/dist/src-ts/plugins/aun/attachments.js +3 -21
- package/dist/src-ts/plugins/aun/index.js +155 -21
- package/dist/src-ts/plugins/aun/messages.js +4 -1
- package/dist/src-ts/plugins/aun/public/app.js +2 -1
- package/dist/src-ts/plugins/aun/public/index.html +1 -1
- package/dist/src-ts/plugins/cdp-draft.js +5 -2
- package/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
- package/dist/src-ts/plugins/chatgpt/index.js +80 -19
- package/dist/src-ts/plugins/claude-cli/index.js +19 -2
- package/dist/src-ts/plugins/codex-cli/index.js +19 -2
- package/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/dist/src-ts/plugins/doubao/cdp-client.js +234 -45
- package/dist/src-ts/plugins/doubao/index.js +152 -8
- package/dist/src-ts/plugins/doubao/native-task.js +134 -0
- package/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
- package/dist/src-ts/plugins/dsh/index.js +172 -21
- package/dist/src-ts/plugins/dsh/session-history.js +31 -3
- package/dist/src-ts/plugins/feishu/index.js +1 -1
- package/dist/src-ts/plugins/local-cli/agent.js +74 -9
- package/dist/src-ts/plugins/personal-assistant/claude-cli-model.js +30 -0
- package/dist/src-ts/plugins/personal-assistant/coordination.js +57 -0
- package/dist/src-ts/plugins/personal-assistant/index.js +263 -0
- package/dist/src-ts/plugins/personal-assistant/model-client.js +181 -0
- package/dist/src-ts/plugins/personal-assistant/owner-context.js +56 -0
- package/dist/src-ts/plugins/personal-assistant/remote-ability.js +176 -0
- package/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
- package/dist/src-ts/plugins/personal-assistant/tools.js +167 -0
- package/dist/src-ts/plugins/qwenwork/cdp-client.js +90 -18
- package/dist/src-ts/plugins/qwenwork/index.js +139 -24
- package/dist/src-ts/plugins/workbuddy/cdp-client.js +353 -82
- package/dist/src-ts/plugins/workbuddy/index.js +124 -41
- package/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
- package/dist/src-ts/plugins/zcode/index.js +97 -0
- package/dist/src-ts/session-management.js +132 -14
- package/dist/src-ts/version-manager.js +6 -3
- package/dist/tests-ts/abweb-cli.test.js +10 -2
- package/dist/tests-ts/abweb-model-config.test.js +73 -0
- package/dist/tests-ts/agent.test.js +27 -0
- package/dist/tests-ts/aun-attachments.test.js +19 -17
- package/dist/tests-ts/aun-default-owner-page.test.js +2 -1
- package/dist/tests-ts/aun-messages.test.js +20 -0
- package/dist/tests-ts/aun-plugin.test.js +292 -19
- package/dist/tests-ts/bundled-package.test.js +12 -2
- package/dist/tests-ts/cdp-draft-recovery.test.js +182 -3
- package/dist/tests-ts/channel-sessions.test.js +27 -0
- package/dist/tests-ts/chatgpt-plugin.test.js +118 -0
- package/dist/tests-ts/control-server.test.js +56 -0
- package/dist/tests-ts/core-updater.test.js +215 -46
- package/dist/tests-ts/daemon-process.test.js +126 -1
- package/dist/tests-ts/desktop-launch.test.js +73 -0
- package/dist/tests-ts/doubao-native-task.test.js +237 -0
- package/dist/tests-ts/doubao-plugin.test.js +773 -12
- package/dist/tests-ts/dsh-agent.test.js +157 -8
- package/dist/tests-ts/dsh-cdp.test.js +148 -0
- package/dist/tests-ts/dsh-history.test.js +37 -0
- package/dist/tests-ts/feishu-plugin.test.js +1 -1
- package/dist/tests-ts/http-agent.test.js +18 -0
- package/dist/tests-ts/installer-assets.test.js +1 -1
- package/dist/tests-ts/local-cli.test.js +146 -1
- package/dist/tests-ts/model-provider-cancellation.test.js +152 -0
- package/dist/tests-ts/native-session-management.test.js +8 -7
- package/dist/tests-ts/personal-assistant-coordination.test.js +92 -0
- package/dist/tests-ts/personal-assistant-extensions.test.js +35 -0
- package/dist/tests-ts/personal-assistant-memory.test.js +117 -0
- package/dist/tests-ts/personal-assistant-owner-context.test.js +107 -0
- package/dist/tests-ts/personal-assistant-remote-ability.test.js +123 -0
- package/dist/tests-ts/personal-assistant.test.js +663 -0
- package/dist/tests-ts/platform-integration.test.js +183 -1
- package/dist/tests-ts/plugin-catalog.test.js +12 -2
- package/dist/tests-ts/plugin-manager.test.js +356 -4
- package/dist/tests-ts/plugin-upgrade-deadline.test.js +354 -0
- package/dist/tests-ts/publish-packages.test.js +42 -0
- package/dist/tests-ts/qwenwork-plugin.test.js +135 -1
- package/dist/tests-ts/qwenwork-reconnect.test.js +195 -0
- package/dist/tests-ts/qwenwork-sse.test.js +33 -0
- package/dist/tests-ts/session-access-defaults.test.js +112 -0
- package/dist/tests-ts/session-management.test.js +159 -4
- package/dist/tests-ts/version-manager.test.js +40 -0
- package/dist/tests-ts/workbuddy-cdp-recovery.test.js +311 -0
- package/dist/tests-ts/workbuddy-plugin.test.js +499 -4
- package/dist/tests-ts/zcode-cdp.test.js +894 -0
- package/dist/tests-ts/zcode-plugin.test.js +396 -0
- package/package.json +1 -1
- package/plugins/abweb/dist/src-ts/agent.js +35 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/index.js +1 -1
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.js +73 -5
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.ts +57 -5
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/index.html +15 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/style.css +4 -0
- package/plugins/abweb/package.json +1 -1
- package/plugins/abweb/plugin.json +1 -1
- package/plugins/aun/config.schema.json +1 -1
- package/plugins/aun/dist/src-ts/agent.js +35 -0
- package/plugins/aun/dist/src-ts/plugins/aun/attachments.js +3 -21
- package/plugins/aun/dist/src-ts/plugins/aun/index.js +155 -21
- package/plugins/aun/dist/src-ts/plugins/aun/messages.js +4 -1
- package/plugins/aun/dist/src-ts/plugins/aun/public/app.js +2 -1
- package/plugins/aun/dist/src-ts/plugins/aun/public/index.html +1 -1
- package/plugins/aun/package.json +1 -1
- package/plugins/aun/plugin.json +1 -1
- package/plugins/chatgpt/dist/src-ts/agent.js +35 -0
- package/plugins/chatgpt/dist/src-ts/plugins/cdp-draft.js +5 -2
- package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
- package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/index.js +80 -19
- package/plugins/chatgpt/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/chatgpt/package.json +1 -1
- package/plugins/chatgpt/plugin.json +1 -1
- package/plugins/claude-cli/dist/src-ts/agent.js +35 -0
- package/plugins/claude-cli/dist/src-ts/plugins/claude-cli/index.js +19 -2
- package/plugins/claude-cli/dist/src-ts/plugins/local-cli/agent.js +74 -9
- package/plugins/claude-cli/package.json +1 -1
- package/plugins/claude-cli/plugin.json +3 -2
- package/plugins/codex-cli/dist/src-ts/agent.js +35 -0
- package/plugins/codex-cli/dist/src-ts/plugins/codex-cli/index.js +19 -2
- package/plugins/codex-cli/dist/src-ts/plugins/local-cli/agent.js +74 -9
- package/plugins/codex-cli/package.json +1 -1
- package/plugins/codex-cli/plugin.json +3 -2
- package/plugins/doubao/config.schema.json +2 -1
- package/plugins/doubao/dist/src-ts/agent.js +35 -0
- package/plugins/doubao/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/doubao/dist/src-ts/plugins/doubao/cdp-client.js +234 -45
- package/plugins/doubao/dist/src-ts/plugins/doubao/index.js +152 -8
- package/plugins/doubao/dist/src-ts/plugins/doubao/native-task.js +134 -0
- package/plugins/doubao/package.json +1 -1
- package/plugins/doubao/plugin.json +3 -2
- package/plugins/dsh/config.schema.json +5 -2
- package/plugins/dsh/dist/src-ts/agent.js +35 -0
- package/plugins/dsh/dist/src-ts/dsh-agent.js +31 -13
- package/plugins/dsh/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/dsh/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
- package/plugins/dsh/dist/src-ts/plugins/dsh/index.js +172 -21
- package/plugins/dsh/dist/src-ts/plugins/dsh/session-history.js +31 -3
- package/plugins/dsh/package.json +1 -1
- package/plugins/dsh/plugin.json +3 -2
- package/plugins/feishu/dist/src-ts/agent.js +35 -0
- package/plugins/feishu/dist/src-ts/plugins/feishu/index.js +1 -1
- package/plugins/feishu/package.json +1 -1
- package/plugins/feishu/plugin.json +1 -1
- package/plugins/personal-assistant/config.schema.json +23 -0
- package/plugins/personal-assistant/dist/src-ts/agent.js +69 -0
- package/plugins/personal-assistant/dist/src-ts/attachments.js +62 -0
- package/plugins/personal-assistant/dist/src-ts/plugin.js +13 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/claude-cli-model.js +30 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/coordination.js +57 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/index.js +263 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/model-client.js +181 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/owner-context.js +56 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/remote-ability.js +176 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/tools.js +167 -0
- package/plugins/personal-assistant/package.json +39 -0
- package/plugins/personal-assistant/plugin.json +15 -0
- package/plugins/qwenwork/dist/src-ts/agent.js +35 -0
- package/plugins/qwenwork/dist/src-ts/plugins/cdp-draft.js +5 -2
- package/plugins/qwenwork/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/cdp-client.js +90 -18
- package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/index.js +139 -24
- package/plugins/qwenwork/package.json +1 -1
- package/plugins/qwenwork/plugin.json +3 -2
- package/plugins/workbuddy/config.schema.json +1 -1
- package/plugins/workbuddy/dist/src-ts/agent.js +35 -0
- package/plugins/workbuddy/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cdp-client.js +353 -82
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/index.js +124 -41
- package/plugins/workbuddy/package.json +1 -1
- package/plugins/workbuddy/plugin.json +3 -2
- package/plugins/zcode/config.schema.json +13 -0
- package/plugins/zcode/dist/src-ts/agent.js +69 -0
- package/plugins/zcode/dist/src-ts/attachments.js +62 -0
- package/plugins/zcode/dist/src-ts/plugin.js +13 -0
- package/plugins/zcode/dist/src-ts/plugins/desktop-launch.js +238 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/cdp-client.js +896 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/cli-client.js +39 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/desktop-launch.js +10 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/index.js +567 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/session-history.js +121 -0
- package/plugins/zcode/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
- package/plugins/zcode/dist/src-ts/plugins/zcode/index.js +97 -0
- package/plugins/zcode/package.json +16 -0
- 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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
251
|
+
const response = await this.complete(request);
|
|
252
|
+
await this.synchronizeSession();
|
|
253
|
+
return response;
|
|
243
254
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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
|
|
417
|
+
if (error instanceof agent_2.AgentOperationError || error?.stage)
|
|
346
418
|
throw error;
|
|
347
|
-
throw new
|
|
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
|
-
|
|
467
|
-
|
|
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
|
-
|
|
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
|
"id": "workbuddy",
|
|
3
|
-
"version": "1.1.
|
|
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
|
+
}
|