mu-agent-bridge 1.0.71 → 1.0.73
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 +9 -6
- package/dist/src-ts/agent.js +35 -0
- package/dist/src-ts/channel-sessions.js +3 -2
- package/dist/src-ts/control-server.js +5 -2
- package/dist/src-ts/dsh-agent.js +25 -12
- package/dist/src-ts/plugin-catalog.js +11 -2
- package/dist/src-ts/plugin-manager.js +183 -9
- package/dist/src-ts/plugins/abweb/index.js +1 -1
- package/dist/src-ts/plugins/abweb/public/app.js +68 -2
- 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/index.js +66 -10
- package/dist/src-ts/plugins/aun/messages.js +3 -0
- package/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
- package/dist/src-ts/plugins/chatgpt/index.js +77 -17
- 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/doubao/cdp-client.js +5 -2
- package/dist/src-ts/plugins/doubao/index.js +36 -4
- package/dist/src-ts/plugins/dsh/index.js +78 -6
- 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 +242 -0
- package/dist/src-ts/plugins/personal-assistant/model-client.js +167 -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/tools.js +166 -0
- package/dist/src-ts/plugins/qwenwork/cdp-client.js +47 -11
- package/dist/src-ts/plugins/qwenwork/index.js +89 -8
- package/dist/src-ts/plugins/workbuddy/cdp-client.js +9 -4
- package/dist/src-ts/plugins/workbuddy/index.js +104 -33
- package/dist/src-ts/session-management.js +105 -6
- package/dist/tests-ts/abweb-cli.test.js +10 -2
- package/dist/tests-ts/abweb-model-config.test.js +70 -0
- package/dist/tests-ts/agent.test.js +27 -0
- package/dist/tests-ts/aun-messages.test.js +6 -0
- package/dist/tests-ts/aun-plugin.test.js +85 -0
- package/dist/tests-ts/bundled-package.test.js +12 -2
- package/dist/tests-ts/channel-sessions.test.js +27 -0
- package/dist/tests-ts/chatgpt-plugin.test.js +99 -0
- package/dist/tests-ts/control-server.test.js +36 -0
- package/dist/tests-ts/doubao-plugin.test.js +92 -0
- package/dist/tests-ts/dsh-agent.test.js +77 -0
- package/dist/tests-ts/feishu-plugin.test.js +1 -1
- package/dist/tests-ts/installer-assets.test.js +1 -1
- package/dist/tests-ts/local-cli.test.js +119 -1
- package/dist/tests-ts/model-provider-cancellation.test.js +150 -0
- package/dist/tests-ts/personal-assistant-coordination.test.js +76 -0
- package/dist/tests-ts/personal-assistant-extensions.test.js +29 -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 +389 -0
- package/dist/tests-ts/platform-integration.test.js +124 -1
- package/dist/tests-ts/plugin-catalog.test.js +12 -2
- package/dist/tests-ts/plugin-manager.test.js +280 -0
- package/dist/tests-ts/publish-packages.test.js +42 -0
- package/dist/tests-ts/qwenwork-plugin.test.js +105 -1
- package/dist/tests-ts/session-management.test.js +155 -0
- package/dist/tests-ts/workbuddy-plugin.test.js +154 -2
- 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 +68 -2
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.ts +53 -3
- 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/dist/src-ts/agent.js +35 -0
- package/plugins/aun/dist/src-ts/plugins/aun/index.js +66 -10
- package/plugins/aun/dist/src-ts/plugins/aun/messages.js +3 -0
- package/plugins/chatgpt/dist/src-ts/agent.js +35 -0
- package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
- package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/index.js +77 -17
- 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/dist/src-ts/agent.js +35 -0
- package/plugins/doubao/dist/src-ts/plugins/doubao/cdp-client.js +5 -2
- package/plugins/doubao/dist/src-ts/plugins/doubao/index.js +36 -4
- package/plugins/doubao/package.json +1 -1
- package/plugins/doubao/plugin.json +3 -2
- package/plugins/dsh/dist/src-ts/agent.js +35 -0
- package/plugins/dsh/dist/src-ts/dsh-agent.js +25 -12
- package/plugins/dsh/dist/src-ts/plugins/dsh/index.js +78 -6
- 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/personal-assistant/config.schema.json +22 -0
- package/plugins/personal-assistant/dist/src-ts/agent.js +69 -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 +242 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/model-client.js +167 -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/tools.js +166 -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/qwenwork/cdp-client.js +47 -11
- package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/index.js +89 -8
- package/plugins/qwenwork/package.json +1 -1
- package/plugins/qwenwork/plugin.json +3 -2
- package/plugins/workbuddy/dist/src-ts/agent.js +35 -0
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cdp-client.js +9 -4
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/index.js +104 -33
- package/plugins/workbuddy/package.json +1 -1
- package/plugins/workbuddy/plugin.json +3 -2
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
let logHasNext = false;
|
|
35
35
|
let loading = false;
|
|
36
36
|
const installingPackages = new Set();
|
|
37
|
+
let assistantOriginal = {};
|
|
37
38
|
function error(message) { errorNode.textContent = message; errorNode.hidden = !message; }
|
|
38
39
|
function showResult(title, message, failed) {
|
|
39
40
|
node("#operation-result-title").textContent = title;
|
|
@@ -76,7 +77,7 @@
|
|
|
76
77
|
head.append(headRow);
|
|
77
78
|
const body = document.createElement("tbody");
|
|
78
79
|
for (const plugin of items) {
|
|
79
|
-
const installed = plugins.find((item) => item.id === plugin.name.replace(/^agent-bridge-/, ""));
|
|
80
|
+
const installed = plugins.find((item) => item.id === (plugin.id ?? plugin.name.replace(/^agent-bridge-/, "")));
|
|
80
81
|
const versionStatus = installed ? pluginVersions[installed.id] : undefined;
|
|
81
82
|
const isUpgrade = Boolean(installed && versionStatus?.packageName === plugin.name && newerVersion(plugin.version, installed.version));
|
|
82
83
|
const row = document.createElement("tr");
|
|
@@ -309,7 +310,7 @@
|
|
|
309
310
|
status.className = `status status-${plugin.status}`;
|
|
310
311
|
status.textContent = plugin.status;
|
|
311
312
|
if (plugin.type === "agent")
|
|
312
|
-
type.textContent +=
|
|
313
|
+
type.textContent += plugin.manifest?.executionMode === "cli" ? " · CLI" : " · 桌面";
|
|
313
314
|
const dependencies = Object.entries(plugin.manifest?.dependencies ?? {});
|
|
314
315
|
if (dependencies.length) {
|
|
315
316
|
const detail = document.createElement("small");
|
|
@@ -344,6 +345,8 @@
|
|
|
344
345
|
controls.className = "controls";
|
|
345
346
|
if (plugin.manifest?.executionMode === "cli")
|
|
346
347
|
controls.append(button("配置", `配置 ${plugin.id}`, () => configureCli(plugin)));
|
|
348
|
+
if (plugin.id === "personal-assistant")
|
|
349
|
+
controls.append(button("配置模型", "配置个人助理模型来源", () => configureAssistant(plugin)));
|
|
347
350
|
if (pluginVersions[plugin.id]?.state === "update-available" && plugin.path.includes("node_modules")) {
|
|
348
351
|
controlsUpgrade(plugin.id);
|
|
349
352
|
controls.append(button("下载", `下载 ${plugin.id}`, async () => { await request(`/api/plugins/${encodeURIComponent(plugin.id)}/download`, "POST", { packageName: plugin.packageName, version: pluginVersions[plugin.id]?.latestVersion }); await load(); }));
|
|
@@ -401,6 +404,69 @@
|
|
|
401
404
|
detail.hidden = false;
|
|
402
405
|
}).finally(() => { save.disabled = false; });
|
|
403
406
|
};
|
|
407
|
+
node("#assistant-config-cancel").onclick = () => node("#assistant-config-dialog").close();
|
|
408
|
+
async function configureAssistant(plugin) {
|
|
409
|
+
const [config, sourceResult] = await Promise.all([
|
|
410
|
+
request(`/api/plugins/${encodeURIComponent(plugin.id)}/config`),
|
|
411
|
+
request("/api/model-providers"),
|
|
412
|
+
]);
|
|
413
|
+
assistantOriginal = config;
|
|
414
|
+
const select = node("#assistant-model-provider");
|
|
415
|
+
select.replaceChildren();
|
|
416
|
+
const add = (value, label, disabled = false) => { const option = document.createElement("option"); option.value = value; option.textContent = label; option.disabled = disabled; select.append(option); };
|
|
417
|
+
add("openai", "OpenAI 兼容接口");
|
|
418
|
+
if (config.modelProvider === "claude-cli")
|
|
419
|
+
add("claude-cli", "Claude CLI(原有配置,用户默认模型)");
|
|
420
|
+
for (const provider of sourceResult.providers ?? [])
|
|
421
|
+
add(`plugin:${provider.id}`, `${provider.displayName || provider.id}${provider.available ? "" : `(不可用:${provider.reason || provider.status})`}`, !provider.available);
|
|
422
|
+
if (config.modelProvider === "plugin" && config.modelPlugin && !(sourceResult.providers ?? []).some((item) => item.id === config.modelPlugin))
|
|
423
|
+
add(`plugin:${config.modelPlugin}`, `${config.modelPlugin}(未安装或未声明模型来源)`, true);
|
|
424
|
+
select.value = config.modelProvider === "plugin" && config.modelPlugin ? `plugin:${config.modelPlugin}` : config.modelProvider ?? "openai";
|
|
425
|
+
node("#assistant-model").value = config.model ?? "";
|
|
426
|
+
node("#assistant-endpoint").value = config.endpoint ?? "";
|
|
427
|
+
node("#assistant-api-key").value = "";
|
|
428
|
+
node("#assistant-api-key").placeholder = config.apiKey ? "已配置,留空保留" : "可选,本地免认证服务可留空";
|
|
429
|
+
node("#assistant-timeout").value = String(config.timeoutMs ?? 120000);
|
|
430
|
+
node("#assistant-allowed-peers").value = (config.allowedPeers ?? []).join("\n");
|
|
431
|
+
node("#assistant-allowed-agents").value = (config.allowedAgents ?? []).join("\n");
|
|
432
|
+
node("#assistant-config-error").hidden = true;
|
|
433
|
+
node("#assistant-config-dialog").showModal();
|
|
434
|
+
}
|
|
435
|
+
node("#assistant-config-form").onsubmit = event => {
|
|
436
|
+
event.preventDefault();
|
|
437
|
+
const save = node("#assistant-config-save");
|
|
438
|
+
save.disabled = true;
|
|
439
|
+
const source = node("#assistant-model-provider").value;
|
|
440
|
+
const provider = source.startsWith("plugin:") ? "plugin" : source;
|
|
441
|
+
const modelPlugin = source.startsWith("plugin:") ? source.slice("plugin:".length) : undefined;
|
|
442
|
+
const body = {};
|
|
443
|
+
if (provider !== (assistantOriginal.modelProvider ?? "openai"))
|
|
444
|
+
body.modelProvider = provider;
|
|
445
|
+
if (provider === "plugin" && modelPlugin !== assistantOriginal.modelPlugin)
|
|
446
|
+
body.modelPlugin = modelPlugin;
|
|
447
|
+
const model = node("#assistant-model").value.trim();
|
|
448
|
+
const endpoint = node("#assistant-endpoint").value.trim();
|
|
449
|
+
const apiKey = node("#assistant-api-key").value;
|
|
450
|
+
if (model && model !== String(assistantOriginal.model ?? ""))
|
|
451
|
+
body.model = model;
|
|
452
|
+
if (endpoint && endpoint !== String(assistantOriginal.endpoint ?? ""))
|
|
453
|
+
body.endpoint = endpoint;
|
|
454
|
+
if (apiKey.trim())
|
|
455
|
+
body.apiKey = apiKey.trim();
|
|
456
|
+
const timeoutMs = Number(node("#assistant-timeout").value);
|
|
457
|
+
if (timeoutMs !== Number(assistantOriginal.timeoutMs ?? 120000))
|
|
458
|
+
body.timeoutMs = timeoutMs;
|
|
459
|
+
for (const [field, selector] of [["allowedPeers", "#assistant-allowed-peers"], ["allowedAgents", "#assistant-allowed-agents"]]) {
|
|
460
|
+
const values = [...new Set(node(selector).value.split(/[\s,,]+/).filter(Boolean))];
|
|
461
|
+
if (JSON.stringify(values) !== JSON.stringify(assistantOriginal[field]))
|
|
462
|
+
body[field] = values;
|
|
463
|
+
}
|
|
464
|
+
void request("/api/plugins/personal-assistant/config", "PATCH", body).then(result => {
|
|
465
|
+
node("#assistant-config-dialog").close();
|
|
466
|
+
showResult("个人助理配置已保存", result.restartRequired || result.action === "restart" ? "配置已保存,需要重启后台后生效。" : "模型来源配置已更新。", false);
|
|
467
|
+
return load(false);
|
|
468
|
+
}).catch(cause => { const detail = node("#assistant-config-error"); detail.textContent = String(cause); detail.hidden = false; }).finally(() => { save.disabled = false; });
|
|
469
|
+
};
|
|
404
470
|
function renderMessages(messages) {
|
|
405
471
|
messagesNode.replaceChildren();
|
|
406
472
|
messagesEmpty.hidden = messages.length > 0;
|
|
@@ -31,6 +31,21 @@
|
|
|
31
31
|
<div><button id="cli-config-save" type="submit">保存配置</button><button id="cli-config-cancel" type="button">取消</button></div>
|
|
32
32
|
</form>
|
|
33
33
|
</dialog>
|
|
34
|
+
<dialog id="assistant-config-dialog" aria-labelledby="assistant-config-title">
|
|
35
|
+
<h2 id="assistant-config-title">个人助理模型配置</h2>
|
|
36
|
+
<form id="assistant-config-form">
|
|
37
|
+
<label for="assistant-model-provider">模型来源</label><select id="assistant-model-provider" required></select>
|
|
38
|
+
<label for="assistant-model">OpenAI 兼容模型名称</label><input id="assistant-model" placeholder="仅 HTTP 来源需要">
|
|
39
|
+
<label for="assistant-endpoint">OpenAI 兼容地址</label><input id="assistant-endpoint" type="url" placeholder="http://127.0.0.1:11434/v1/chat/completions">
|
|
40
|
+
<label for="assistant-api-key">API 密钥(留空保留已有密钥)</label><input id="assistant-api-key" type="password" autocomplete="new-password">
|
|
41
|
+
<label for="assistant-timeout">模型超时(毫秒)</label><input id="assistant-timeout" type="number" min="1000" max="120000" required>
|
|
42
|
+
<label for="assistant-allowed-peers">允许使用助理的 Peer AID(每行一个)</label><textarea id="assistant-allowed-peers" rows="3" placeholder="example.agentid.cn"></textarea>
|
|
43
|
+
<label for="assistant-allowed-agents">允许调用的 Agent 插件 ID(每行一个)</label><textarea id="assistant-allowed-agents" rows="3" placeholder="workbuddy dsh"></textarea>
|
|
44
|
+
<p class="muted">插件来源沿用客户端登录及当前模型;留空白名单表示不授权。AID 关联请在 Channel 设置中完成。</p>
|
|
45
|
+
<p id="assistant-config-error" class="error" role="alert" hidden></p>
|
|
46
|
+
<div><button id="assistant-config-save" type="submit">保存配置</button><button id="assistant-config-cancel" type="button">取消</button></div>
|
|
47
|
+
</form>
|
|
48
|
+
</dialog>
|
|
34
49
|
<dialog id="operation-result" aria-labelledby="operation-result-title" aria-describedby="operation-result-message">
|
|
35
50
|
<h2 id="operation-result-title">操作结果</h2><p id="operation-result-message"></p><button id="operation-result-close" type="button" autofocus>确定</button>
|
|
36
51
|
</dialog>
|
|
@@ -63,3 +63,7 @@ th:nth-child(1) { width: 145px; } th:nth-child(2) { width: 100px; } th:nth-child
|
|
|
63
63
|
|
|
64
64
|
#cli-config-form { display: grid; min-width: min(70vw, 480px); }
|
|
65
65
|
#cli-config-form input { width: 100%; }
|
|
66
|
+
#assistant-config-form { display: grid; min-width: min(70vw, 480px); }
|
|
67
|
+
#assistant-config-form input, #assistant-config-form select, #assistant-config-form textarea { width: 100%; }
|
|
68
|
+
#assistant-config-dialog { max-height: 90vh; overflow: auto; }
|
|
69
|
+
#assistant-config-form textarea { font: inherit; padding: 6px 9px; border: 1px solid #bfc9c5; border-radius: 5px; }
|
|
@@ -81,6 +81,60 @@ class AunPlugin {
|
|
|
81
81
|
this.sdk = options.sdk;
|
|
82
82
|
this.ingress = options.ingress;
|
|
83
83
|
}
|
|
84
|
+
aunManagement = {
|
|
85
|
+
list: async () => {
|
|
86
|
+
const groups = await this.identity.list();
|
|
87
|
+
const aids = [...new Set([...groups.evolcore, ...groups.muAgentBridge, ...(groups.localMuAgentBridge ?? []), ...this.listStoreAids()])]
|
|
88
|
+
.filter((aid) => aidPattern.test(aid)).sort();
|
|
89
|
+
const bindings = Object.fromEntries(Object.entries(this.bindings)
|
|
90
|
+
.filter(([aid, agentId]) => aidPattern.test(aid) && /^[a-z][a-z0-9-]{1,63}$/.test(agentId) && agentId !== "aun" && agentId !== "abweb")
|
|
91
|
+
.sort(([left], [right]) => left.localeCompare(right)));
|
|
92
|
+
return { aids, bindings };
|
|
93
|
+
},
|
|
94
|
+
create: async ({ aid, ownerAid }) => {
|
|
95
|
+
if (typeof aid !== "string" || !aidPattern.test(aid.trim()))
|
|
96
|
+
throw new AunCommandError("AID 格式无效");
|
|
97
|
+
const validAid = aid.trim();
|
|
98
|
+
const owner = typeof ownerAid === "string" && ownerAid.trim()
|
|
99
|
+
? ownerAid.trim()
|
|
100
|
+
: typeof this.config.owner_aid === "string" ? this.config.owner_aid.trim() : "";
|
|
101
|
+
if (!owner)
|
|
102
|
+
throw new AunCommandError("未提供 Owner AID,且未配置默认 Owner");
|
|
103
|
+
if (!aidPattern.test(owner))
|
|
104
|
+
throw new AunCommandError("Owner AID 格式无效");
|
|
105
|
+
const result = await this.createIdentity(validAid, owner);
|
|
106
|
+
const connection = result.connection === "ready" ? "ready" : "degraded";
|
|
107
|
+
if (connection !== "ready")
|
|
108
|
+
throw new AunCommandError("AID 已创建但连接失败,请先查询 AID 列表确认状态,不要重试创建", 502, { created: true, aid: validAid, connection });
|
|
109
|
+
return { aid: validAid, status: result.status, connection };
|
|
110
|
+
},
|
|
111
|
+
bind: async ({ aid, agentId, replace }) => {
|
|
112
|
+
if (typeof aid !== "string" || !aidPattern.test(aid.trim()))
|
|
113
|
+
throw new AunCommandError("AID 格式无效");
|
|
114
|
+
if (typeof agentId !== "string" || !/^[a-z][a-z0-9-]{1,63}$/.test(agentId) || agentId === "aun" || agentId === "abweb")
|
|
115
|
+
throw new AunCommandError("Agent 插件 ID 无效");
|
|
116
|
+
if (typeof replace !== "boolean")
|
|
117
|
+
throw new AunCommandError("必须明确指定是否替换现有绑定");
|
|
118
|
+
const validAid = aid.trim();
|
|
119
|
+
const previousAgent = this.bindings[validAid];
|
|
120
|
+
const existing = Object.entries(this.bindings)
|
|
121
|
+
.filter(([, target]) => target === agentId)
|
|
122
|
+
.map(([boundAid]) => boundAid)
|
|
123
|
+
.filter((previousAid) => previousAid !== validAid)
|
|
124
|
+
.sort();
|
|
125
|
+
if (previousAgent && previousAgent !== agentId)
|
|
126
|
+
throw new AunCommandError("该 AID 已绑定到其他 Agent,不能通过替换转移");
|
|
127
|
+
if (existing.length && !replace)
|
|
128
|
+
throw new AunCommandError("目标 Agent 已有其他 AID 绑定;如需替换请明确设置 replace");
|
|
129
|
+
try {
|
|
130
|
+
await this.patchAgentAid(agentId, validAid);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
throw new AunCommandError("AUN 身份关联失败", 502);
|
|
134
|
+
}
|
|
135
|
+
return { aid: validAid, agent: agentId, replacedAids: existing };
|
|
136
|
+
},
|
|
137
|
+
};
|
|
84
138
|
identity = {
|
|
85
139
|
list: async () => {
|
|
86
140
|
const own = new Set([...this.createdAids, ...this.legacyCreatedAids]);
|
|
@@ -672,16 +726,7 @@ class AunPlugin {
|
|
|
672
726
|
this.validatePluginId(agent);
|
|
673
727
|
await this.requireAgent(agent);
|
|
674
728
|
}
|
|
675
|
-
|
|
676
|
-
try {
|
|
677
|
-
created = await this.identity.create(aid, owner);
|
|
678
|
-
}
|
|
679
|
-
catch (error) {
|
|
680
|
-
const exists = this.identities.has(aid) || this.listStoreAids().includes(aid);
|
|
681
|
-
if (exists)
|
|
682
|
-
throw new AunCommandError("AID 可能已创建,但后续连接或保存失败;请先执行 mab aun list 确认,不要重试创建", 502, { created: true, aid });
|
|
683
|
-
throw new AunCommandError(`AID 创建失败:${safeError(error).replaceAll(owner, "[已隐藏]")}`, 502);
|
|
684
|
-
}
|
|
729
|
+
const created = await this.createIdentity(aid, owner);
|
|
685
730
|
const data = { created: true, aid, connection: created.connection ?? "ready" };
|
|
686
731
|
if (created.connection !== "ready")
|
|
687
732
|
throw new AunCommandError("AID 已创建,但连接失败;请先执行 mab aun list 确认,不要重试创建", 502, { ...data, connectionError: created.connectionError });
|
|
@@ -699,6 +744,17 @@ class AunPlugin {
|
|
|
699
744
|
data: { ...data, ...(agent ? { agent } : {}) },
|
|
700
745
|
};
|
|
701
746
|
}
|
|
747
|
+
async createIdentity(aid, owner) {
|
|
748
|
+
try {
|
|
749
|
+
return await this.identity.create(aid, owner);
|
|
750
|
+
}
|
|
751
|
+
catch (error) {
|
|
752
|
+
if (this.identities.has(aid) || this.listStoreAids().includes(aid)) {
|
|
753
|
+
throw new AunCommandError("AID 可能已创建,但后续连接或保存失败;请先执行 mab aun list 确认,不要重试创建", 502, { created: true, aid });
|
|
754
|
+
}
|
|
755
|
+
throw new AunCommandError(`AID 创建失败:${safeError(error).replaceAll(owner, "[已隐藏]")}`, 502);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
702
758
|
async agents(readyOnly = true) {
|
|
703
759
|
const payload = await this.controlRequest("/api/plugins");
|
|
704
760
|
if (!Array.isArray(payload.plugins))
|
|
@@ -13,6 +13,9 @@ function normalizeAunMessage(payload, selfAid, allowFrom) {
|
|
|
13
13
|
if (!peerId || peerId === selfAid || (rules.length > 0 && !rules.includes(peerId)))
|
|
14
14
|
return undefined;
|
|
15
15
|
const body = data.payload && typeof data.payload === "object" ? data.payload : {};
|
|
16
|
+
// 对端的系统事件只作通知,转为任务回复会导致两个 Agent 循环互答。
|
|
17
|
+
if (body.type === "error" || body.type === "notice")
|
|
18
|
+
return undefined;
|
|
16
19
|
const text = typeof data.payload === "string" ? data.payload : typeof body.text === "string" ? body.text : "";
|
|
17
20
|
let attachments = [];
|
|
18
21
|
let attachmentError;
|
|
@@ -170,9 +170,11 @@ class ChatgptCdpClient {
|
|
|
170
170
|
missingReasons.push("仅包含当前页面已加载的可验证正文,页面虚拟化或未加载历史导致完整性无法确认");
|
|
171
171
|
return { supported: true, turns: result.turns, complete: false, missingReasons };
|
|
172
172
|
}
|
|
173
|
-
async switchSession(session) {
|
|
174
|
-
|
|
175
|
-
|
|
173
|
+
async switchSession(session, preserveDraft = false) {
|
|
174
|
+
if (!preserveDraft) {
|
|
175
|
+
await this.waitForGeneration();
|
|
176
|
+
await this.recoverDraft();
|
|
177
|
+
}
|
|
176
178
|
const locate = `[...document.querySelectorAll(${JSON.stringify(sidebarSelector)})].find(item =>
|
|
177
179
|
item.getAttribute('data-app-action-sidebar-thread-id') === ${JSON.stringify(session.id)}
|
|
178
180
|
&& item.getAttribute('data-app-action-sidebar-thread-host-id') === ${JSON.stringify(session.host)})`;
|
|
@@ -194,15 +196,18 @@ class ChatgptCdpClient {
|
|
|
194
196
|
&& Boolean(document.querySelector(${JSON.stringify(exports.editorSelector)}));
|
|
195
197
|
})()`, "ChatGPT 会话切换未确认,未发送消息");
|
|
196
198
|
}
|
|
197
|
-
async createSession(_name) {
|
|
198
|
-
|
|
199
|
-
|
|
199
|
+
async createSession(_name, preserveDraft = false) {
|
|
200
|
+
if (!preserveDraft) {
|
|
201
|
+
await this.waitForGeneration();
|
|
202
|
+
await this.recoverDraft();
|
|
203
|
+
}
|
|
200
204
|
const before = await this.activeSession();
|
|
201
205
|
const state = await this.evaluate(`JSON.stringify({ editor: document.querySelector(${JSON.stringify(exports.editorSelector)})?.innerText ?? null, turns: document.querySelectorAll(${JSON.stringify(exports.turnSelector)}).length, generating: Boolean(document.querySelector(${JSON.stringify(stopButtonSelector)})) })`);
|
|
202
206
|
const initial = JSON.parse(String(state));
|
|
203
207
|
if (initial.editor?.trim() || initial.generating)
|
|
204
208
|
throw new Error("ChatGPT 当前有未发送内容或正在生成回复,不能新建会话");
|
|
205
209
|
const clicked = await this.evaluate(`(() => {
|
|
210
|
+
if (document.querySelector(${JSON.stringify(exports.editorSelector)})?.innerText.trim() || document.querySelector(${JSON.stringify(stopButtonSelector)})) throw new Error('ChatGPT 当前有未发送内容或正在生成回复,不能新建会话');
|
|
206
211
|
const labels = /^(?:新聊天|新对话|new chat|new conversation)$/i;
|
|
207
212
|
const item = [...document.querySelectorAll(${JSON.stringify(newSessionSelector)})].find((node) => {
|
|
208
213
|
const label = [node.getAttribute('aria-label'), node.getAttribute('title'), node.textContent].filter(Boolean).join(' ').trim();
|
|
@@ -304,7 +309,7 @@ class ChatgptCdpClient {
|
|
|
304
309
|
this.tunnel = undefined;
|
|
305
310
|
this.rejectPending(new Error("ChatGPT CDP 已关闭"));
|
|
306
311
|
}
|
|
307
|
-
async direct(text, timeoutMs = 240_000, attachments) {
|
|
312
|
+
async direct(text, timeoutMs = 240_000, attachments, signal, preserveDraft = false) {
|
|
308
313
|
(0, attachments_1.validateAttachments)(attachments);
|
|
309
314
|
const slot = `__agentBridgeChatgpt_${(0, node_crypto_1.randomUUID)().replaceAll("-", "")}`;
|
|
310
315
|
const outputDirectory = `agent-bridge-chatgpt-${(0, node_crypto_1.randomUUID)()}`;
|
|
@@ -312,7 +317,7 @@ class ChatgptCdpClient {
|
|
|
312
317
|
const instruction = `附件回传约定:如果本轮需要返回文件、图片或视频,请把要返回的文件副本写入本轮新建的临时目录(Linux/macOS:/tmp/${outputDirectory};Windows:C:/Users/<当前用户>/AppData/Local/Temp/${outputDirectory}),并在最终回复给出文件链接。仅需文字时无需创建目录。`;
|
|
313
318
|
let failure;
|
|
314
319
|
try {
|
|
315
|
-
return await this.directTurn(`${text} ${instruction}`, timeoutMs, attachments, slot, outputDirectory, startedAt);
|
|
320
|
+
return await this.directTurn(preserveDraft ? text : `${text} ${instruction}`, timeoutMs, attachments, slot, outputDirectory, startedAt, signal, preserveDraft);
|
|
316
321
|
}
|
|
317
322
|
catch (error) {
|
|
318
323
|
failure = error;
|
|
@@ -338,10 +343,12 @@ class ChatgptCdpClient {
|
|
|
338
343
|
}
|
|
339
344
|
}
|
|
340
345
|
}
|
|
341
|
-
async directTurn(text, timeoutMs, attachments, slot, outputDirectory, startedAt) {
|
|
346
|
+
async directTurn(text, timeoutMs, attachments, slot, outputDirectory, startedAt, signal, preserveDraft = false) {
|
|
342
347
|
await this.waitFor(`Boolean(document.querySelector(${JSON.stringify(exports.editorSelector)}))`, "ChatGPT 桌面端输入框未就绪");
|
|
343
|
-
|
|
344
|
-
|
|
348
|
+
if (!preserveDraft) {
|
|
349
|
+
await this.waitForGeneration();
|
|
350
|
+
await this.recoverDraft();
|
|
351
|
+
}
|
|
345
352
|
const beforeTurnsJson = await this.evaluate(`JSON.stringify([...document.querySelectorAll(${JSON.stringify(exports.turnSelector)})].map(turn => ({ id: turn.getAttribute(${JSON.stringify(turnIdAttribute)}), users: turn.querySelectorAll(${JSON.stringify(exports.userBubbleSelector)}).length })))`);
|
|
346
353
|
const beforeTurns = JSON.parse(String(beforeTurnsJson || "[]"));
|
|
347
354
|
const beforeAssistantCount = Number(await this.evaluate(`document.querySelectorAll(${JSON.stringify(assistantMessageSelector)}).length`));
|
|
@@ -393,7 +400,9 @@ class ChatgptCdpClient {
|
|
|
393
400
|
const deadline = Date.now() + timeoutMs;
|
|
394
401
|
let previous = "";
|
|
395
402
|
let stable = 0;
|
|
396
|
-
|
|
403
|
+
let seenActive = false;
|
|
404
|
+
let inactivePolls = 0;
|
|
405
|
+
while (Date.now() < deadline || signal?.aborted) {
|
|
397
406
|
await sleep(800);
|
|
398
407
|
const raw = await this.evaluate(`(() => {
|
|
399
408
|
const previous = new Set(${JSON.stringify(Array.isArray(beforeMessages) ? beforeMessages : [])}.map(item => JSON.stringify(item)));
|
|
@@ -439,6 +448,11 @@ class ChatgptCdpClient {
|
|
|
439
448
|
})()`);
|
|
440
449
|
const state = JSON.parse(String(raw));
|
|
441
450
|
const reply = state.reply.trim();
|
|
451
|
+
seenActive ||= state.active === true;
|
|
452
|
+
inactivePolls = seenActive && state.submitted === true && state.active === false ? inactivePolls + 1 : 0;
|
|
453
|
+
if (signal?.aborted && inactivePolls >= 2 && state.artifacts?.length && !reply && !state.hasArtifacts) {
|
|
454
|
+
throw new Error("ChatGPT 请求已取消,已确认本轮桌面生成结束,未返回正文或附件");
|
|
455
|
+
}
|
|
442
456
|
const signature = JSON.stringify([reply, state.artifacts, state.hasArtifacts]);
|
|
443
457
|
stable = (reply || state.hasArtifacts) && signature === previous ? stable + 1 : 0;
|
|
444
458
|
previous = signature;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ChatgptCdpClient = exports.ChatgptPlugin = exports.chatgptManifest = void 0;
|
|
4
|
+
const agent_1 = require("../../agent");
|
|
4
5
|
const node_crypto_1 = require("node:crypto");
|
|
5
6
|
const cdp_client_1 = require("./cdp-client");
|
|
6
7
|
const session_store_1 = require("./session-store");
|
|
@@ -9,13 +10,13 @@ const node_path_1 = require("node:path");
|
|
|
9
10
|
const node_os_1 = require("node:os");
|
|
10
11
|
exports.chatgptManifest = {
|
|
11
12
|
id: "chatgpt",
|
|
12
|
-
version: "1.0.
|
|
13
|
+
version: "1.0.12",
|
|
13
14
|
displayName: "ChatGPT(Codex)",
|
|
14
15
|
type: "agent",
|
|
15
16
|
entry: "dist/index.js",
|
|
16
17
|
apiVersion: "1",
|
|
17
18
|
process: "in-process",
|
|
18
|
-
capabilities: ["chat", "health"],
|
|
19
|
+
capabilities: ["chat", "health", "model-provider"],
|
|
19
20
|
configSchema: "config.schema.json",
|
|
20
21
|
};
|
|
21
22
|
function port(value, fallback) {
|
|
@@ -26,6 +27,11 @@ function port(value, fallback) {
|
|
|
26
27
|
class ChatgptPlugin {
|
|
27
28
|
options;
|
|
28
29
|
manifest = exports.chatgptManifest;
|
|
30
|
+
get modelProvider() {
|
|
31
|
+
if (!this.client?.createSession || !this.client.listSessions || !this.client.activeSession || !this.client.switchSession || !this.store)
|
|
32
|
+
return undefined;
|
|
33
|
+
return { complete: (request) => this.completeModelProvider(request) };
|
|
34
|
+
}
|
|
29
35
|
sessionOperations = [];
|
|
30
36
|
get attachmentInput() { return this.client?.attachmentInput === true; }
|
|
31
37
|
client;
|
|
@@ -156,6 +162,51 @@ class ChatgptPlugin {
|
|
|
156
162
|
const result = await run;
|
|
157
163
|
return { ...(typeof result === "string" ? { text: result } : result), sessionId: request.sessionId };
|
|
158
164
|
}
|
|
165
|
+
async completeModelProvider(request) {
|
|
166
|
+
let stage = "ChatGPT 模型排队(queue)";
|
|
167
|
+
try {
|
|
168
|
+
request.signal.throwIfAborted();
|
|
169
|
+
const run = this.enqueue(async () => {
|
|
170
|
+
request.signal.throwIfAborted();
|
|
171
|
+
stage = "连接 ChatGPT 模型(connect)";
|
|
172
|
+
const store = this.store;
|
|
173
|
+
const client = this.client;
|
|
174
|
+
if (!store || !client?.connected())
|
|
175
|
+
throw new Error("ChatGPT CDP 未连接,模型请求不会启动或重启桌面");
|
|
176
|
+
const previous = await client.activeSession();
|
|
177
|
+
try {
|
|
178
|
+
stage = "准备 ChatGPT 模型会话(submit)";
|
|
179
|
+
if (!store.bindings[request.sessionId]) {
|
|
180
|
+
const existing = new Set((await client.listSessions()).map(item => JSON.stringify([item.host, item.id])));
|
|
181
|
+
const created = await client.createSession(undefined, true);
|
|
182
|
+
if (created) {
|
|
183
|
+
store.remember(created, "", "");
|
|
184
|
+
store.bindings[request.sessionId] = created;
|
|
185
|
+
delete store.pendingBindings[request.sessionId];
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
store.pendingBindings[request.sessionId] = [...existing];
|
|
189
|
+
}
|
|
190
|
+
this.persist();
|
|
191
|
+
}
|
|
192
|
+
request.signal.throwIfAborted();
|
|
193
|
+
stage = "等待 ChatGPT 模型生成(generate)";
|
|
194
|
+
const result = await this.run({ task: request.prompt, sessionId: request.sessionId, timeoutMs: request.timeoutMs, signal: request.signal }, true);
|
|
195
|
+
return { text: typeof result === "string" ? result : result.text };
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
if (previous && client.connected())
|
|
199
|
+
await this.select(previous, true);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
return await (0, agent_1.abortable)(run, request.signal);
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
if (error instanceof agent_1.AgentOperationError)
|
|
206
|
+
throw error;
|
|
207
|
+
throw new agent_1.AgentOperationError("CHATGPT_MODEL_FAILED", stage, error);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
159
210
|
async controlSession(request) {
|
|
160
211
|
if (request.operation !== "new")
|
|
161
212
|
throw new Error(`ChatGPT 不支持会话操作:${String(request.operation)}`);
|
|
@@ -281,41 +332,47 @@ class ChatgptPlugin {
|
|
|
281
332
|
persist() {
|
|
282
333
|
void this.store.save().catch(error => this.logger?.warn("ChatGPT 会话缓存保存失败", { error: String(error) }));
|
|
283
334
|
}
|
|
284
|
-
async synchronize() {
|
|
285
|
-
if (!this.client.connected())
|
|
335
|
+
async synchronize(modelRequest = false) {
|
|
336
|
+
if (!this.client.connected()) {
|
|
337
|
+
if (modelRequest)
|
|
338
|
+
throw new Error("ChatGPT CDP 已断开,模型请求不会启动或重启桌面");
|
|
286
339
|
await (this.reconnect?.() ?? this.client.connect());
|
|
340
|
+
}
|
|
287
341
|
if (!this.client.listSessions)
|
|
288
342
|
throw new Error("当前 ChatGPT 客户端不支持会话列表");
|
|
289
343
|
this.store.synchronize(await this.client.listSessions());
|
|
290
344
|
this.persist();
|
|
291
345
|
}
|
|
292
|
-
async select(session) {
|
|
293
|
-
if (!this.client.connected())
|
|
346
|
+
async select(session, modelRequest = false) {
|
|
347
|
+
if (!this.client.connected()) {
|
|
348
|
+
if (modelRequest)
|
|
349
|
+
throw new Error("ChatGPT CDP 已断开,模型请求不会启动或重启桌面");
|
|
294
350
|
await (this.reconnect?.() ?? this.client.connect());
|
|
351
|
+
}
|
|
295
352
|
if (!this.client.switchSession)
|
|
296
353
|
throw new Error("当前 ChatGPT 客户端不支持会话切换");
|
|
297
354
|
const active = await this.client.activeSession?.();
|
|
298
355
|
if (active?.id === session.id && active.host === session.host)
|
|
299
356
|
return;
|
|
300
357
|
try {
|
|
301
|
-
await this.client.switchSession(session);
|
|
358
|
+
await this.client.switchSession(session, modelRequest);
|
|
302
359
|
}
|
|
303
360
|
catch (error) {
|
|
304
361
|
// 目标消失时只重新同步一次;不在其他会话中代替发送。
|
|
305
362
|
if (!String(error).includes("找不到目标会话"))
|
|
306
363
|
throw error;
|
|
307
|
-
await this.synchronize();
|
|
364
|
+
await this.synchronize(modelRequest);
|
|
308
365
|
const updated = this.store.sessions.find(item => item.id === session.id && item.host === session.host);
|
|
309
366
|
if (!updated)
|
|
310
367
|
throw new Error("ChatGPT 目标会话已删除或不在当前侧栏,请刷新最近任务");
|
|
311
|
-
await this.client.switchSession(updated);
|
|
368
|
+
await this.client.switchSession(updated, modelRequest);
|
|
312
369
|
}
|
|
313
370
|
}
|
|
314
|
-
async run(request) {
|
|
371
|
+
async run(request, modelRequest = false) {
|
|
315
372
|
const store = this.store;
|
|
316
373
|
const text = request.task.trim();
|
|
317
|
-
const refresh = /^(?:刷新最近任务|刷新任务列表|刷新最近会话)$/.test(text);
|
|
318
|
-
const listing = /^(?:最近任务|列出最近会话|有哪些已保存的 ChatGPT 任务)[??。]?$/.test(text);
|
|
374
|
+
const refresh = !modelRequest && /^(?:刷新最近任务|刷新任务列表|刷新最近会话)$/.test(text);
|
|
375
|
+
const listing = !modelRequest && /^(?:最近任务|列出最近会话|有哪些已保存的 ChatGPT 任务)[??。]?$/.test(text);
|
|
319
376
|
if (refresh || listing) {
|
|
320
377
|
if (refresh || !store.fresh()) {
|
|
321
378
|
try {
|
|
@@ -331,7 +388,7 @@ class ChatgptPlugin {
|
|
|
331
388
|
}
|
|
332
389
|
const explicit = text.match(/^切换会话\s*[::]\s*([^;;\n]+)(?:[;;\n]\s*([\s\S]+))?$/);
|
|
333
390
|
const natural = text.match(/^(?:继续处理|接着处理|继续任务|切换到)\s*(.+?)[。]?$/);
|
|
334
|
-
const query = explicit?.[1].trim() ?? natural?.[1].trim();
|
|
391
|
+
const query = modelRequest ? undefined : explicit?.[1].trim() ?? natural?.[1].trim();
|
|
335
392
|
let selected;
|
|
336
393
|
if (query) {
|
|
337
394
|
if (!store.fresh())
|
|
@@ -355,13 +412,16 @@ class ChatgptPlugin {
|
|
|
355
412
|
}
|
|
356
413
|
else if (request.sessionId && store.bindings[request.sessionId]) {
|
|
357
414
|
selected = store.bindings[request.sessionId];
|
|
358
|
-
await this.select(selected);
|
|
415
|
+
await this.select(selected, modelRequest);
|
|
359
416
|
}
|
|
360
|
-
if (!this.client.connected())
|
|
417
|
+
if (!this.client.connected()) {
|
|
418
|
+
if (modelRequest)
|
|
419
|
+
throw new Error("ChatGPT CDP 已断开,模型请求不会启动或重启桌面");
|
|
361
420
|
await (this.reconnect?.() ?? this.client.connect());
|
|
421
|
+
}
|
|
362
422
|
selected ??= await this.client.activeSession?.();
|
|
363
|
-
const message = explicit?.[2]?.trim() || request.task;
|
|
364
|
-
const reply = await this.client.direct(message, request.timeoutMs, request.attachments);
|
|
423
|
+
const message = (modelRequest ? undefined : explicit?.[2]?.trim()) || request.task;
|
|
424
|
+
const reply = await this.client.direct(message, request.timeoutMs, request.attachments, request.signal, modelRequest);
|
|
365
425
|
const baseline = request.sessionId ? store.pendingBindings[request.sessionId] : undefined;
|
|
366
426
|
if (baseline) {
|
|
367
427
|
try {
|
|
@@ -3,12 +3,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ClaudeCliPlugin = exports.manifest = void 0;
|
|
4
4
|
const agent_1 = require("../local-cli/agent");
|
|
5
5
|
exports.manifest = {
|
|
6
|
-
id: "claude-cli", version: "1.0.
|
|
6
|
+
id: "claude-cli", version: "1.0.2", displayName: "Claude Code CLI", type: "agent", executionMode: "cli",
|
|
7
7
|
entry: "dist/src-ts/plugins/claude-cli/index.js", apiVersion: "1", process: "in-process",
|
|
8
|
-
capabilities: ["chat", "health"], configSchema: "config.schema.json",
|
|
8
|
+
capabilities: ["chat", "health", "model-provider"], configSchema: "config.schema.json",
|
|
9
9
|
};
|
|
10
10
|
class ClaudeCliPlugin extends agent_1.LocalCliAgent {
|
|
11
11
|
constructor() { super(exports.manifest, "claude"); }
|
|
12
|
+
get modelProvider() {
|
|
13
|
+
if (!this.modelInput)
|
|
14
|
+
return undefined;
|
|
15
|
+
return { complete: (request) => this.completeModelProvider(request) };
|
|
16
|
+
}
|
|
17
|
+
async completeModelProvider(request) {
|
|
18
|
+
let responseSchema;
|
|
19
|
+
try {
|
|
20
|
+
responseSchema = JSON.parse(request.prompt)?.responseSchema;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new Error("Claude CLI 模型请求必须是包含 responseSchema 的 JSON 对象");
|
|
24
|
+
}
|
|
25
|
+
if (!responseSchema || typeof responseSchema !== "object" || Array.isArray(responseSchema))
|
|
26
|
+
throw new Error("Claude CLI 模型请求缺少有效 responseSchema");
|
|
27
|
+
return this.completeStructuredModel(request, responseSchema);
|
|
28
|
+
}
|
|
12
29
|
}
|
|
13
30
|
exports.ClaudeCliPlugin = ClaudeCliPlugin;
|
|
14
31
|
exports.default = ClaudeCliPlugin;
|
|
@@ -3,12 +3,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.CodexCliPlugin = exports.manifest = void 0;
|
|
4
4
|
const agent_1 = require("../local-cli/agent");
|
|
5
5
|
exports.manifest = {
|
|
6
|
-
id: "codex-cli", version: "1.0.
|
|
6
|
+
id: "codex-cli", version: "1.0.2", displayName: "Codex CLI", type: "agent", executionMode: "cli",
|
|
7
7
|
entry: "dist/src-ts/plugins/codex-cli/index.js", apiVersion: "1", process: "in-process",
|
|
8
|
-
capabilities: ["chat", "health"], configSchema: "config.schema.json",
|
|
8
|
+
capabilities: ["chat", "health", "model-provider"], configSchema: "config.schema.json",
|
|
9
9
|
};
|
|
10
10
|
class CodexCliPlugin extends agent_1.LocalCliAgent {
|
|
11
11
|
constructor() { super(exports.manifest, "codex"); }
|
|
12
|
+
get modelProvider() {
|
|
13
|
+
if (!this.modelInput)
|
|
14
|
+
return undefined;
|
|
15
|
+
return { complete: (request) => this.completeModelProvider(request) };
|
|
16
|
+
}
|
|
17
|
+
async completeModelProvider(request) {
|
|
18
|
+
let responseSchema;
|
|
19
|
+
try {
|
|
20
|
+
responseSchema = JSON.parse(request.prompt)?.responseSchema;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new Error("Codex CLI 模型请求必须是包含 responseSchema 的 JSON 对象");
|
|
24
|
+
}
|
|
25
|
+
if (!responseSchema || typeof responseSchema !== "object" || Array.isArray(responseSchema))
|
|
26
|
+
throw new Error("Codex CLI 模型请求缺少有效 responseSchema");
|
|
27
|
+
return this.completeStructuredModel(request, responseSchema);
|
|
28
|
+
}
|
|
12
29
|
}
|
|
13
30
|
exports.CodexCliPlugin = CodexCliPlugin;
|
|
14
31
|
exports.default = CodexCliPlugin;
|
|
@@ -355,8 +355,9 @@ class DoubaoCdpClient {
|
|
|
355
355
|
const uploaded = attachments?.length ? await this.uploadAttachments(attachments, requestSignal) : [];
|
|
356
356
|
await this.evaluate(buildInjection(requestBody(text, target, this.options.botId, this.options.pluginList, uploaded)));
|
|
357
357
|
const deadline = Date.now() + this.options.timeoutMs;
|
|
358
|
-
while (Date.now() < deadline) {
|
|
359
|
-
|
|
358
|
+
while (Date.now() < deadline || signal?.aborted) {
|
|
359
|
+
// 上游取消只结束等待,页面请求结束前继续占用原队列。
|
|
360
|
+
await sleep(1000, this.closeController.signal);
|
|
360
361
|
const result = await this.evaluate("window.__mab_doubao_result");
|
|
361
362
|
if (typeof result !== "string")
|
|
362
363
|
continue;
|
|
@@ -395,6 +396,8 @@ class DoubaoCdpClient {
|
|
|
395
396
|
this.conversationId = backendId;
|
|
396
397
|
return { text: reply || "附件已生成。", sessionId: backendId, ...(output.length ? { attachments: output } : {}), ...(images.length ? { images } : {}) };
|
|
397
398
|
}
|
|
399
|
+
if (signal?.aborted && parsed.pending !== true && !parsed.expectVideo)
|
|
400
|
+
throw new Error("豆包请求已取消,已确认本轮页面请求结束,未返回正文或附件");
|
|
398
401
|
}
|
|
399
402
|
throw new Error("等待豆包回复超时");
|
|
400
403
|
}
|