mu-agent-bridge 1.0.14 → 1.0.15
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 +4 -5
- package/dist/src-ts/control-server.js +5 -5
- package/dist/src-ts/plugins/aun/index.js +23 -27
- package/dist/src-ts/plugins/aun/public/app.js +3 -3
- package/dist/tests-ts/aun-plugin.test.js +28 -11
- package/dist/tests-ts/control-server.test.js +0 -52
- package/package.json +1 -1
- package/dist/src-ts/plugins/aun/evolcore.js +0 -54
package/README.md
CHANGED
|
@@ -21,12 +21,11 @@ OpenAI 兼容 API 为 `/v1/models` 和 `/v1/chat/completions`。管理页面位
|
|
|
21
21
|
`AGENT_BRIDGE_HOST=0.0.0.0` 和 `AGENT_BRIDGE_TOKEN`,然后访问
|
|
22
22
|
`http://<Windows 主机 IP>:26107/abweb/`。页面使用一次性配置码配对后管理插件;请只在可信网络使用。
|
|
23
23
|
已有 AID 的连接状态由 AUN 插件查询,只有当前已连接的身份才能关联 Agent。
|
|
24
|
-
|
|
24
|
+
本机 AID 来自 AUN 插件自身的密钥库,不依赖 `ec` 命令,`ec stop` 后仍会显示。
|
|
25
25
|
创建新 AID 必须填写 Owner AID,并安装、启动 AUN 插件;创建与通信由该插件完成。
|
|
26
|
-
|
|
27
|
-
关联
|
|
28
|
-
|
|
29
|
-
回复仍由 EvolCore 经 AUN 发送。该操作会覆盖所选 AID 当前的执行基座。
|
|
26
|
+
已连接身份保存在 AUN 插件自身的密钥库和配置中。
|
|
27
|
+
关联 AID 到 DSH 或千问办公等 Agent 时,由 AUN 插件直接保持该身份连接并把来信转给
|
|
28
|
+
对应 Agent,回复经 AUN 发送;关联不再执行 `ec agent set/reload` 配置 EvolCore 路由。
|
|
30
29
|
其他 Agent 插件可关联 AUN 插件自己创建的身份,由通道直接转发来信和回复。
|
|
31
30
|
Windows 可运行 `start-mab.ps1` 注册并启动登录时自动运行的计划任务;令牌保存在
|
|
32
31
|
`%USERPROFILE%\.mab\token.txt`,页面输入该令牌即可使用管理 API。
|
|
@@ -4,10 +4,9 @@ exports.ControlServer = exports.listExistingAids = void 0;
|
|
|
4
4
|
const node_http_1 = require("node:http");
|
|
5
5
|
const node_child_process_1 = require("node:child_process");
|
|
6
6
|
const node_crypto_1 = require("node:crypto");
|
|
7
|
-
const local_aids_1 = require("./local-aids");
|
|
8
7
|
const openai_adapter_1 = require("./plugins/qwenwork/openai-adapter");
|
|
9
|
-
var
|
|
10
|
-
Object.defineProperty(exports, "listExistingAids", { enumerable: true, get: function () { return
|
|
8
|
+
var local_aids_1 = require("./local-aids");
|
|
9
|
+
Object.defineProperty(exports, "listExistingAids", { enumerable: true, get: function () { return local_aids_1.listExistingAids; } });
|
|
11
10
|
const AID_PATTERN = /^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?){2,}$/;
|
|
12
11
|
class ControlServer {
|
|
13
12
|
options;
|
|
@@ -103,8 +102,9 @@ class ControlServer {
|
|
|
103
102
|
if (method === "GET" && url.pathname === "/api/aids") {
|
|
104
103
|
const identity = this.identity();
|
|
105
104
|
const groups = identity ? await identity.list() : { evolcore: [], muAgentBridge: [] };
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
// 本地 AID 由 AUN 插件的密钥库提供(groups.local),不再依赖 ec 查询 EvolCore
|
|
106
|
+
const aids = [...new Set([...groups.evolcore, ...groups.muAgentBridge, ...groups.local ?? []])];
|
|
107
|
+
return this.json(res, 200, { aids, groups, localAids: [], canCreate: Boolean(identity), message: identity ? "" : "请先安装并启动 AUN 插件,才能创建或关联 AID" });
|
|
108
108
|
}
|
|
109
109
|
if (method === "POST" && url.pathname === "/api/aids") {
|
|
110
110
|
const body = await this.body(req);
|
|
@@ -6,10 +6,8 @@ const node_module_1 = require("node:module");
|
|
|
6
6
|
const node_path_1 = require("node:path");
|
|
7
7
|
const node_url_1 = require("node:url");
|
|
8
8
|
const messages_1 = require("./messages");
|
|
9
|
-
const evolcore_1 = require("./evolcore");
|
|
10
|
-
const local_aids_1 = require("../../local-aids");
|
|
11
9
|
const manifest = {
|
|
12
|
-
id: "aun", version: "1.0.
|
|
10
|
+
id: "aun", version: "1.0.6", type: "channel", displayName: "AUN 通道",
|
|
13
11
|
entry: "dist/src-ts/plugins/aun/index.js", apiVersion: "1", process: "in-process",
|
|
14
12
|
capabilities: ["channel", "channel.identity.create", "channel.receive", "channel.send", "health"],
|
|
15
13
|
configSchema: "config.schema.json",
|
|
@@ -38,7 +36,6 @@ class AunPlugin {
|
|
|
38
36
|
store;
|
|
39
37
|
clients = new Map();
|
|
40
38
|
identities = new Set();
|
|
41
|
-
legacyCreatedAids = new Set();
|
|
42
39
|
bindings = {};
|
|
43
40
|
bindingTimes = {};
|
|
44
41
|
creating = false;
|
|
@@ -56,14 +53,13 @@ class AunPlugin {
|
|
|
56
53
|
}
|
|
57
54
|
identity = {
|
|
58
55
|
list: async () => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return [];
|
|
62
|
-
});
|
|
56
|
+
// 不再依赖 ec 命令:本地密钥库的 AID 全部列出,本工程连接的 AID 以 clients 为准
|
|
57
|
+
const local = this.listStoreAids();
|
|
63
58
|
return {
|
|
64
|
-
evolcore:
|
|
65
|
-
muAgentBridge: [...
|
|
59
|
+
evolcore: [],
|
|
60
|
+
muAgentBridge: [...this.clients.keys()].sort(),
|
|
66
61
|
localMuAgentBridge: [...this.identities].filter((aid) => !this.clients.has(aid)).sort(),
|
|
62
|
+
local,
|
|
67
63
|
};
|
|
68
64
|
},
|
|
69
65
|
create: async (aid, owner) => {
|
|
@@ -98,7 +94,7 @@ class AunPlugin {
|
|
|
98
94
|
this.creating = false;
|
|
99
95
|
}
|
|
100
96
|
},
|
|
101
|
-
bind: async (pluginId, aid,
|
|
97
|
+
bind: async (pluginId, aid, _port) => {
|
|
102
98
|
if (pluginId === "aun" || pluginId === "abweb")
|
|
103
99
|
throw new Error("只能关联 Agent 插件");
|
|
104
100
|
const previous = this.bindings;
|
|
@@ -124,14 +120,20 @@ class AunPlugin {
|
|
|
124
120
|
this.bindings[aid] = pluginId;
|
|
125
121
|
}
|
|
126
122
|
else {
|
|
127
|
-
|
|
123
|
+
// 不再调用 ec:只要 AID 在本地密钥库中就直接连接并绑定
|
|
124
|
+
const loaded = this.store.load(aid);
|
|
125
|
+
if (!loaded.ok || !loaded.data)
|
|
126
|
+
throw new Error("AID 不在本地密钥库中,无法关联");
|
|
127
|
+
await this.connectAid(aid);
|
|
128
|
+
if (!this.clients.has(aid))
|
|
128
129
|
throw new Error("AID 当前未连接");
|
|
129
|
-
await (0, evolcore_1.configureAidForPlugin)(pluginId, aid, port);
|
|
130
130
|
for (const [identity, target] of Object.entries(this.bindings))
|
|
131
131
|
if (target === pluginId) {
|
|
132
132
|
delete this.bindings[identity];
|
|
133
133
|
delete this.bindingTimes[identity];
|
|
134
134
|
}
|
|
135
|
+
this.bindings[aid] = pluginId;
|
|
136
|
+
this.identities.add(aid);
|
|
135
137
|
}
|
|
136
138
|
}
|
|
137
139
|
else {
|
|
@@ -165,18 +167,6 @@ class AunPlugin {
|
|
|
165
167
|
async activate(context) {
|
|
166
168
|
this.context = context;
|
|
167
169
|
this.config = { ...context.config };
|
|
168
|
-
this.legacyCreatedAids.clear();
|
|
169
|
-
try {
|
|
170
|
-
const created = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(context.dataDir, "..", "created-aids.json"), "utf8"));
|
|
171
|
-
if (Array.isArray(created))
|
|
172
|
-
for (const aid of created)
|
|
173
|
-
if (typeof aid === "string" && aidPattern.test(aid))
|
|
174
|
-
this.legacyCreatedAids.add(aid);
|
|
175
|
-
}
|
|
176
|
-
catch (error) {
|
|
177
|
-
if (error.code !== "ENOENT")
|
|
178
|
-
context.logger.warn("读取旧版身份创建记录失败", { error: safeError(error) });
|
|
179
|
-
}
|
|
180
170
|
for (const key of ["aid", "owner_aid", "aun_path", "encryption_seed", "root_ca_path", "allow_from", "agent_plugin"]) {
|
|
181
171
|
if (this.config[key] !== undefined && typeof this.config[key] !== "string")
|
|
182
172
|
throw new Error(`${key} 必须是字符串`);
|
|
@@ -303,10 +293,16 @@ class AunPlugin {
|
|
|
303
293
|
return this.json(response, 502, { error: safeError(error) });
|
|
304
294
|
}
|
|
305
295
|
};
|
|
296
|
+
listStoreAids() {
|
|
297
|
+
const result = this.store?.list();
|
|
298
|
+
if (!result?.ok || !Array.isArray(result.data?.identities))
|
|
299
|
+
return [];
|
|
300
|
+
return [...new Set(result.data.identities.filter((item) => item && typeof item.aid === "string" && aidPattern.test(item.aid)).map((item) => item.aid))].sort();
|
|
301
|
+
}
|
|
306
302
|
listIdentities = async (_request, response) => {
|
|
307
303
|
const groups = await this.identity.list();
|
|
308
|
-
const connected = new Set([...groups.evolcore, ...groups.muAgentBridge]);
|
|
309
|
-
const localAids = (
|
|
304
|
+
const connected = new Set([...groups.evolcore, ...groups.muAgentBridge, ...groups.localMuAgentBridge ?? []]);
|
|
305
|
+
const localAids = (groups.local ?? []).filter((aid) => !connected.has(aid));
|
|
310
306
|
this.json(response, 200, { groups, localAids, bindings: this.bindings, bindingTimes: this.bindingTimes });
|
|
311
307
|
};
|
|
312
308
|
saveSettings = async (request, response) => {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
configForm.elements.encryption_seed.value = "";
|
|
32
32
|
}
|
|
33
33
|
list.replaceChildren();
|
|
34
|
-
const entries = [["本工程 · 已连接", identities.groups.muAgentBridge || []], ["
|
|
34
|
+
const entries = [["本工程 · 已连接", identities.groups.muAgentBridge || []], ["本机 AID", identities.groups.local || []], ["本工程 · 未连接", identities.groups.localMuAgentBridge || []]]
|
|
35
35
|
.flatMap(([label, values], group) => values.map((aid) => ({ aid, label, group, bound: identities.bindings?.[aid] || agents.find((agent) => agent.id && agent.configAid === aid)?.id || "", time: Date.parse(identities.bindingTimes?.[aid] || "") || 0 })));
|
|
36
36
|
entries.sort((a, b) => Number(Boolean(b.bound)) - Number(Boolean(a.bound)) || a.group - b.group || b.time - a.time || a.aid.localeCompare(b.aid));
|
|
37
37
|
for (const { aid, label, bound } of entries) {
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
select.value = bound; select.onchange = () => { if (select.value) void bind(aid, select.value); };
|
|
43
43
|
cell.append(select); row.append(cell); list.append(row);
|
|
44
44
|
}
|
|
45
|
-
if (!list.children.length) { const row = document.createElement("tr"); const cell = document.createElement("td"); cell.colSpan = 4; cell.textContent = "
|
|
46
|
-
show(`${(identities.groups.
|
|
45
|
+
if (!list.children.length) { const row = document.createElement("tr"); const cell = document.createElement("td"); cell.colSpan = 4; cell.textContent = "暂无 AID"; row.append(cell); list.append(row); }
|
|
46
|
+
show(`${(identities.groups.muAgentBridge || []).length} 个已连接,${(identities.groups.local || []).length} 个本机 AID`);
|
|
47
47
|
} catch (error) { show(String(error), true); }
|
|
48
48
|
finally { loading = false; }
|
|
49
49
|
}
|
|
@@ -14,7 +14,7 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
14
14
|
const node = () => ({ children: [], elements: new Proxy({}, { get: () => ({ value: "", replaceChildren() { } }) }), append(...items) { this.children.push(...items); }, replaceChildren(...items) { this.children = items; }, setAttribute() { } });
|
|
15
15
|
const elements = new Map();
|
|
16
16
|
const identities = {
|
|
17
|
-
groups: { muAgentBridge: ["offline-order.agentid.cn", "old.agentid.cn", "new.agentid.cn", "unknown.agentid.cn"],
|
|
17
|
+
groups: { muAgentBridge: ["offline-order.agentid.cn", "old.agentid.cn", "new.agentid.cn", "unknown.agentid.cn"], local: ["external.agentid.cn"] },
|
|
18
18
|
bindings: { "old.agentid.cn": "dsh", "new.agentid.cn": "doubao", "unknown.agentid.cn": "workbuddy" },
|
|
19
19
|
bindingTimes: { "old.agentid.cn": "2026-10-09T00:00:00.000Z", "new.agentid.cn": "2026-10-10T00:00:00.000Z", "external.agentid.cn": "2026-10-11T00:00:00.000Z" },
|
|
20
20
|
};
|
|
@@ -32,9 +32,10 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
32
32
|
const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "aun-management-"));
|
|
33
33
|
const routes = new Map();
|
|
34
34
|
const sdk = { AIDStore: class {
|
|
35
|
+
list() { return { ok: true, data: { identities: [{ aid: "external.agentid.cn" }] } }; }
|
|
35
36
|
close() { }
|
|
36
37
|
} };
|
|
37
|
-
const plugin = new aun_1.AunPlugin({ sdk,
|
|
38
|
+
const plugin = new aun_1.AunPlugin({ sdk, ingress: { publish: async () => undefined } });
|
|
38
39
|
try {
|
|
39
40
|
await plugin.activate({ dataDir: root, config: { owner_aid: "owner.agentid.cn", bindings: { "external.agentid.cn": "qwenwork" } }, logger: { info() { }, warn() { }, error() { } }, callPlugin: async () => ({ text: "" }), pluginStatus: () => "ready", http: {
|
|
40
41
|
register(route) { routes.set(`${route.method} ${route.path}`, route.handler); return () => routes.delete(`${route.method} ${route.path}`); }, unregister() { },
|
|
@@ -48,7 +49,8 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
48
49
|
strict_1.default.equal(response.statusCode, 200);
|
|
49
50
|
strict_1.default.match(String(response.body), /AUN 身份/);
|
|
50
51
|
await routes.get("GET /api/plugins/aun/identities")({}, response);
|
|
51
|
-
strict_1.default.deepEqual(JSON.parse(response.body).groups.
|
|
52
|
+
strict_1.default.deepEqual(JSON.parse(response.body).groups.local, ["external.agentid.cn"]);
|
|
53
|
+
strict_1.default.deepEqual(JSON.parse(response.body).groups.evolcore, []);
|
|
52
54
|
strict_1.default.deepEqual(JSON.parse(response.body).bindingTimes, {});
|
|
53
55
|
await routes.get("POST /api/plugins/aun/settings")((async function* () { yield Buffer.from(JSON.stringify({ agent_plugin: "dsh", allow_from: "peer.agentid.cn", aun_path: "" })); })(), response);
|
|
54
56
|
const saved = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(root, "config.json"), "utf8"));
|
|
@@ -62,18 +64,21 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
62
64
|
await (0, promises_1.rm)(root, { recursive: true, force: true });
|
|
63
65
|
}
|
|
64
66
|
});
|
|
65
|
-
(0, node_test_1.default)("
|
|
67
|
+
(0, node_test_1.default)("旧版创建身份按来源归入本工程且本地身份始终可见", async () => {
|
|
66
68
|
const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "aun-origin-"));
|
|
67
69
|
const dataDir = (0, node_path_1.join)(root, "aun");
|
|
68
70
|
await (0, promises_1.mkdir)(dataDir);
|
|
69
71
|
await (0, promises_1.writeFile)((0, node_path_1.join)(root, "created-aids.json"), JSON.stringify(["doubao-lih.agentid.cn", "dshlihui.agentid.cn", "offline.agentid.cn"]));
|
|
72
|
+
const storeIds = ["doubao-lih.agentid.cn", "dshlihui.agentid.cn", "external.agentid.cn"];
|
|
70
73
|
const sdk = { AIDStore: class {
|
|
74
|
+
list() { return { ok: true, data: { identities: storeIds.map((aid) => ({ aid })) } }; }
|
|
75
|
+
load(aid) { return { ok: true, data: { aid } }; }
|
|
71
76
|
close() { }
|
|
72
77
|
} };
|
|
73
|
-
const plugin = new aun_1.AunPlugin({ sdk,
|
|
78
|
+
const plugin = new aun_1.AunPlugin({ sdk, ingress: { publish: async () => undefined } });
|
|
74
79
|
try {
|
|
75
80
|
await plugin.activate({ dataDir, config: {}, logger: { info() { }, warn() { }, error() { } }, callPlugin: async () => ({ text: "" }), pluginStatus: () => "ready", http: { register() { }, unregister() { } } });
|
|
76
|
-
strict_1.default.deepEqual(await plugin.identity.list(), { evolcore: [
|
|
81
|
+
strict_1.default.deepEqual(await plugin.identity.list(), { evolcore: [], muAgentBridge: [], localMuAgentBridge: [], local: ["doubao-lih.agentid.cn", "dshlihui.agentid.cn", "external.agentid.cn"] });
|
|
77
82
|
await plugin.deactivate("stop");
|
|
78
83
|
}
|
|
79
84
|
finally {
|
|
@@ -84,11 +89,14 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
84
89
|
const calls = [];
|
|
85
90
|
let registration = { ok: true, data: {} };
|
|
86
91
|
let loadOk = true;
|
|
92
|
+
let loadFailAid = "";
|
|
87
93
|
const clients = [];
|
|
88
94
|
const sdk = {
|
|
89
95
|
AIDStore: class {
|
|
90
|
-
|
|
91
|
-
|
|
96
|
+
registered = [];
|
|
97
|
+
async register(input) { calls.push(`register:${input.aid}:${input.owner}`); this.registered.push(input.aid); return registration; }
|
|
98
|
+
load(aid) { return !loadOk || aid === loadFailAid ? { ok: false, error: { message: "本地身份不存在" } } : { ok: true, data: { aid } }; }
|
|
99
|
+
list() { return { ok: true, data: { identities: this.registered.concat(loadOk ? ["offline-store.agentid.cn"] : []).map((aid) => ({ aid })) } }; }
|
|
92
100
|
close() { calls.push("store.close"); }
|
|
93
101
|
},
|
|
94
102
|
AUNClient: class {
|
|
@@ -118,9 +126,14 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
118
126
|
await route.handler(second, response);
|
|
119
127
|
strict_1.default.equal(response.statusCode, 201);
|
|
120
128
|
strict_1.default.equal(clients.length, 2);
|
|
129
|
+
// 关联不再调用 ec:AID 在本地密钥库即可直接绑定
|
|
121
130
|
await plugin.identity.bind("dsh", "bridge.agentid.pub", 26107);
|
|
122
131
|
const boundAt = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(root, "config.json"), "utf8")).binding_times["bridge.agentid.pub"];
|
|
123
132
|
strict_1.default.ok(Number.isFinite(Date.parse(boundAt)));
|
|
133
|
+
// 本地密钥库存在但尚未连接的 AID 也可以关联(会先建立连接)
|
|
134
|
+
await plugin.identity.bind("doubao", "offline-store.agentid.cn", 26107);
|
|
135
|
+
strict_1.default.ok(JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(root, "config.json"), "utf8")).bindings["offline-store.agentid.cn"]);
|
|
136
|
+
strict_1.default.equal(clients.length, 3);
|
|
124
137
|
clients[0].emit({ from: "peer.agentid.pub", message_id: "m1", payload: { text: "你好" } });
|
|
125
138
|
strict_1.default.equal(received[0].agentPlugin, "dsh");
|
|
126
139
|
await received[0].reply("收到");
|
|
@@ -131,12 +144,12 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
131
144
|
clients[0].emit({ from: "peer.agentid.pub", message_id: "m1", payload: { text: "重复消息" } });
|
|
132
145
|
strict_1.default.equal(received.length, 3);
|
|
133
146
|
await plugin.deactivate("stop");
|
|
134
|
-
strict_1.default.equal(calls.filter((call) => call === "client.close").length,
|
|
147
|
+
strict_1.default.equal(calls.filter((call) => call === "client.close").length, 3);
|
|
135
148
|
strict_1.default.equal(calls.at(-1), "store.close");
|
|
136
149
|
await plugin.activate({ dataDir: root, config: JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(root, "config.json"), "utf8")), logger: { info() { }, warn() { }, error() { } }, callPlugin: async () => ({ text: "" }), pluginStatus: () => "ready", http: { register() { }, unregister() { } } });
|
|
137
150
|
const health = await plugin.health();
|
|
138
|
-
strict_1.default.deepEqual(health.details?.aids, ["bridge.agentid.pub", "second.agentid.pub"]);
|
|
139
|
-
strict_1.default.deepEqual(health.details?.bindings, { "bridge.agentid.pub": "dsh" });
|
|
151
|
+
strict_1.default.deepEqual(health.details?.aids, ["bridge.agentid.pub", "second.agentid.pub", "offline-store.agentid.cn"]);
|
|
152
|
+
strict_1.default.deepEqual(health.details?.bindings, { "bridge.agentid.pub": "dsh", "offline-store.agentid.cn": "doubao" });
|
|
140
153
|
await routes.find((entry) => entry.path === "/api/plugins/aun/identities").handler({}, response);
|
|
141
154
|
strict_1.default.equal(response.body.bindingTimes["bridge.agentid.pub"], boundAt);
|
|
142
155
|
await strict_1.default.rejects(plugin.identity.bind("dsh", "bad", 26107), /AID 格式无效/);
|
|
@@ -150,6 +163,10 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
150
163
|
registration = { ok: true, data: {} };
|
|
151
164
|
loadOk = false;
|
|
152
165
|
await strict_1.default.rejects(plugin.identity.create("missing.agentid.pub", "owner.agentid.pub"), /本地身份不存在/);
|
|
166
|
+
// 不在本地密钥库的 AID 无法关联(不再依赖 ec 查询)
|
|
167
|
+
loadFailAid = "not-in-store.agentid.cn";
|
|
168
|
+
await strict_1.default.rejects(plugin.identity.bind("dsh", "not-in-store.agentid.cn", 26107), /不在本地密钥库/);
|
|
169
|
+
loadFailAid = "";
|
|
153
170
|
await plugin.deactivate("stop");
|
|
154
171
|
}
|
|
155
172
|
finally {
|
|
@@ -6,17 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
7
|
const node_test_1 = __importDefault(require("node:test"));
|
|
8
8
|
const control_server_1 = require("../src-ts/control-server");
|
|
9
|
-
const evolcore_1 = require("../src-ts/plugins/aun/evolcore");
|
|
10
9
|
const promises_1 = require("node:fs/promises");
|
|
11
10
|
const node_os_1 = require("node:os");
|
|
12
11
|
const node_path_1 = require("node:path");
|
|
13
12
|
const plugin_manager_1 = require("../src-ts/plugin-manager");
|
|
14
|
-
(0, node_test_1.default)("豆包等 Agent 的 EvolCore 关联使用独立路由", async () => {
|
|
15
|
-
const calls = [];
|
|
16
|
-
await (0, evolcore_1.configureAidForPlugin)("doubao", "doubao-lih.agentid.cn", 26107, async (args) => { calls.push(args); return { ok: true }; });
|
|
17
|
-
strict_1.default.ok(calls.some((args) => args.includes("http://127.0.0.1:26107/api/agents/doubao/v1")));
|
|
18
|
-
await strict_1.default.rejects((0, evolcore_1.configureAidForPlugin)("doubao", "doubao-lih.agentid.cn", 26107, async (args) => args[1] === "reload" ? { ok: false, code: "AGENT_BUSY", error: "还有任务正在运行" } : { ok: true }), /AGENT_BUSY.*还有任务正在运行/);
|
|
19
|
-
});
|
|
20
13
|
(0, node_test_1.default)("通用 Agent 路由调用插件且关联失败进入日志", async () => {
|
|
21
14
|
const logs = [];
|
|
22
15
|
const recordMessage = () => undefined;
|
|
@@ -114,51 +107,6 @@ const plugin_manager_1 = require("../src-ts/plugin-manager");
|
|
|
114
107
|
await (0, promises_1.rm)(root, { recursive: true, force: true });
|
|
115
108
|
}
|
|
116
109
|
});
|
|
117
|
-
(0, node_test_1.default)("connected AID list excludes disabled and disconnected identities", async () => {
|
|
118
|
-
const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "mab-connected-aids-"));
|
|
119
|
-
const before = process.env.EVOLCORE_HOME;
|
|
120
|
-
try {
|
|
121
|
-
for (const aid of ["connected.agentid.cn", "offline.agentid.cn", "disabled.agentid.cn"]) {
|
|
122
|
-
const dir = (0, node_path_1.join)(root, "AIDs", aid, "private");
|
|
123
|
-
await (0, promises_1.mkdir)(dir, { recursive: true });
|
|
124
|
-
await (0, promises_1.writeFile)((0, node_path_1.join)(dir, "key.json"), "{}");
|
|
125
|
-
}
|
|
126
|
-
process.env.EVOLCORE_HOME = root;
|
|
127
|
-
const run = async (args) => args[1] === "list"
|
|
128
|
-
? { ok: true, agents: [
|
|
129
|
-
{ aid: "connected.agentid.cn", status: "running", channels: ["aun#connected.agentid.cn#main"] },
|
|
130
|
-
{ aid: "offline.agentid.cn", status: "running", channels: ["aun#offline.agentid.cn#main"] },
|
|
131
|
-
{ aid: "disabled.agentid.cn", status: "disabled", channels: ["aun#disabled.agentid.cn#main"] },
|
|
132
|
-
] }
|
|
133
|
-
: { ok: true, aid: args[2], status: "running", connection: { status: args[2] === "connected.agentid.cn" ? "connected" : "disconnected" } };
|
|
134
|
-
strict_1.default.deepEqual(await (0, evolcore_1.listConnectedAids)(run), ["connected.agentid.cn"]);
|
|
135
|
-
}
|
|
136
|
-
finally {
|
|
137
|
-
if (before === undefined)
|
|
138
|
-
delete process.env.EVOLCORE_HOME;
|
|
139
|
-
else
|
|
140
|
-
process.env.EVOLCORE_HOME = before;
|
|
141
|
-
await (0, promises_1.rm)(root, { recursive: true, force: true });
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
(0, node_test_1.default)("关联 DSH 时配置 EvolCore 路由并重载 AID", async () => {
|
|
145
|
-
const calls = [];
|
|
146
|
-
const run = async (args) => { calls.push(args); return { ok: true }; };
|
|
147
|
-
await (0, evolcore_1.configureAidForPlugin)("dsh", "test.agentid.cn", 26107, run);
|
|
148
|
-
strict_1.default.deepEqual(calls.map((args) => args.slice(0, 4)), [
|
|
149
|
-
["agent", "set", "test.agentid.cn", "baseagents.ecagent.baseUrl"],
|
|
150
|
-
["agent", "set", "test.agentid.cn", "baseagents.ecagent.apiKey"],
|
|
151
|
-
["agent", "set", "test.agentid.cn", "baseagents.ecagent.model"],
|
|
152
|
-
["agent", "set", "test.agentid.cn", "active_baseagent"],
|
|
153
|
-
["agent", "reload", "test.agentid.cn", "--format"],
|
|
154
|
-
]);
|
|
155
|
-
strict_1.default.equal(calls[0][4], "http://127.0.0.1:26107/dsh/v1");
|
|
156
|
-
strict_1.default.equal(calls[2][4], "dsh");
|
|
157
|
-
calls.length = 0;
|
|
158
|
-
await (0, evolcore_1.configureAidForPlugin)("qwenwork", "qwenbg.agentid.cn", 26107, run);
|
|
159
|
-
strict_1.default.equal(calls[0][4], "http://127.0.0.1:26107/v1");
|
|
160
|
-
strict_1.default.equal(calls[2][4], "qwenwork");
|
|
161
|
-
});
|
|
162
110
|
(0, node_test_1.default)("creating an AID requires both identity and owner AID", async () => {
|
|
163
111
|
const manager = { list: () => [] };
|
|
164
112
|
const server = new control_server_1.ControlServer({ manager, host: "127.0.0.1", port: 0 });
|
package/package.json
CHANGED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runEc = runEc;
|
|
4
|
-
exports.configureAidForPlugin = configureAidForPlugin;
|
|
5
|
-
exports.listConnectedAids = listConnectedAids;
|
|
6
|
-
const node_child_process_1 = require("node:child_process");
|
|
7
|
-
const node_util_1 = require("node:util");
|
|
8
|
-
const local_aids_1 = require("../../local-aids");
|
|
9
|
-
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
10
|
-
async function runEc(args) {
|
|
11
|
-
try {
|
|
12
|
-
const { stdout } = await execFileAsync("ec", args, { shell: process.platform === "win32", timeout: 15_000, maxBuffer: 1024 * 1024 });
|
|
13
|
-
return JSON.parse(stdout);
|
|
14
|
-
}
|
|
15
|
-
catch (error) {
|
|
16
|
-
const stdout = error.stdout;
|
|
17
|
-
if (stdout) {
|
|
18
|
-
try {
|
|
19
|
-
return JSON.parse(stdout);
|
|
20
|
-
}
|
|
21
|
-
catch { /* 保留原始命令错误 */ }
|
|
22
|
-
}
|
|
23
|
-
throw error;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
async function configureAidForPlugin(pluginId, aid, port, run = runEc) {
|
|
27
|
-
if (!aid)
|
|
28
|
-
return;
|
|
29
|
-
if (!/^[a-z0-9_-]+$/.test(pluginId))
|
|
30
|
-
throw new Error("插件 ID 格式无效");
|
|
31
|
-
const path = pluginId === "dsh" ? "/dsh/v1" : pluginId === "qwenwork" ? "/v1" : `/api/agents/${pluginId}/v1`;
|
|
32
|
-
for (const [key, value] of [
|
|
33
|
-
["baseagents.ecagent.baseUrl", `http://127.0.0.1:${port}${path}`],
|
|
34
|
-
["baseagents.ecagent.apiKey", "mab-local"],
|
|
35
|
-
["baseagents.ecagent.model", pluginId],
|
|
36
|
-
["active_baseagent", "ecagent"],
|
|
37
|
-
]) {
|
|
38
|
-
const result = await run(["agent", "set", aid, key, value, "--format", "json"]);
|
|
39
|
-
if (!result?.ok)
|
|
40
|
-
throw new Error(`配置 AID ${aid} 失败:${key};${result?.code ?? ""} ${result?.error ?? "未知错误"}`);
|
|
41
|
-
}
|
|
42
|
-
const result = await run(["agent", "reload", aid, "--format", "json"]);
|
|
43
|
-
if (!result?.ok)
|
|
44
|
-
throw new Error(`重载 AID ${aid} 失败:${result?.code ?? ""} ${result?.error ?? "未知错误"}`);
|
|
45
|
-
}
|
|
46
|
-
async function listConnectedAids(run = runEc) {
|
|
47
|
-
const result = await run(["agent", "list", "--format", "json"]);
|
|
48
|
-
if (!result.ok || !Array.isArray(result.agents))
|
|
49
|
-
throw new Error("读取 EvolCore Agent 列表失败");
|
|
50
|
-
const candidates = result.agents.filter((agent) => agent.status === "running" && typeof agent.aid === "string" && /^[a-zA-Z0-9.-]+$/.test(agent.aid) && agent.channels?.some((channel) => channel.startsWith("aun#")));
|
|
51
|
-
const details = await Promise.all(candidates.map((agent) => run(["agent", "show", agent.aid, "--format", "json"]).catch(() => null)));
|
|
52
|
-
const local = new Set(await (0, local_aids_1.listExistingAids)());
|
|
53
|
-
return details.filter((detail) => detail?.ok && detail.status === "running" && detail.connection?.status === "connected" && local.has(detail.aid)).map((detail) => detail.aid).sort();
|
|
54
|
-
}
|