mu-agent-bridge 1.0.13 → 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 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
- 核心可以只读扫描 EvolCore 本地身份;ABWeb 只展示已连接 AID,并按 EvolCore 与 mu-agent-bridge 分组,未连接身份不显示。
24
+ 本机 AID 来自 AUN 插件自身的密钥库,不依赖 `ec` 命令,`ec stop` 后仍会显示。
25
25
  创建新 AID 必须填写 Owner AID,并安装、启动 AUN 插件;创建与通信由该插件完成。
26
- 已连接身份按来源分为 EvolCore 和 mu-agent-bridge 两组;后者保存在 AUN 插件自身的密钥库和配置中。
27
- 关联 EvolCore 身份到 DSH 或千问办公时,AUN 插件会将所选身份的执行基座分别配置为本机
28
- `/dsh/v1` 或 `/v1` OpenAI 接口,然后重载该 Agent;AUN 入站消息由 EvolCore 转给插件,
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 local_aids_2 = require("./local-aids");
10
- Object.defineProperty(exports, "listExistingAids", { enumerable: true, get: function () { return local_aids_2.listExistingAids; } });
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
- const aids = [...new Set([...groups.evolcore, ...groups.muAgentBridge])];
107
- return this.json(res, 200, { aids, groups, localAids: (await (0, local_aids_1.listExistingAids)()).filter((aid) => !aids.includes(aid)), canCreate: Boolean(identity), message: identity ? "" : "请先安装并启动 AUN 插件,才能创建或关联 AID" });
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);
@@ -5,7 +5,7 @@ const node_fs_1 = require("node:fs");
5
5
  const node_path_1 = require("node:path");
6
6
  const MANIFEST = {
7
7
  id: "abweb",
8
- version: "1.0.4",
8
+ version: "1.0.5",
9
9
  displayName: "Agent Bridge Web",
10
10
  entry: "dist/index.js",
11
11
  apiVersion: "1",
@@ -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.4", type: "channel", displayName: "AUN 通道",
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
- const connected = await (this.options.connectedAids ?? evolcore_1.listConnectedAids)().catch((error) => {
60
- this.context?.logger.warn("查询 EvolCore 已连接身份失败", { error: safeError(error) });
61
- return [];
62
- });
56
+ // 不再依赖 ec 命令:本地密钥库的 AID 全部列出,本工程连接的 AID 以 clients 为准
57
+ const local = this.listStoreAids();
63
58
  return {
64
- evolcore: connected.filter((aid) => !this.identities.has(aid) && !this.legacyCreatedAids.has(aid)),
65
- muAgentBridge: [...new Set([...this.clients.keys(), ...connected.filter((aid) => this.legacyCreatedAids.has(aid))])].sort(),
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, port) => {
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
- if (!(await (0, evolcore_1.listConnectedAids)()).includes(aid))
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 = (await (0, local_aids_1.listExistingAids)()).filter((aid) => !connected.has(aid));
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 || []], ["EvolCore · 已连接", identities.groups.evolcore || []]]
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 = "暂无已连接 AID"; row.append(cell); list.append(row); }
46
- show(`${(identities.groups.evolcore || []).length + (identities.groups.muAgentBridge || []).length} 个已连接 AID`);
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
  }
@@ -4,7 +4,7 @@ exports.DoubaoPlugin = exports.doubaoManifest = void 0;
4
4
  const cdp_client_1 = require("./cdp-client");
5
5
  exports.doubaoManifest = {
6
6
  id: "doubao",
7
- version: "1.0.3",
7
+ version: "1.0.4",
8
8
  displayName: "豆包",
9
9
  entry: "dist/index.js",
10
10
  apiVersion: "1",
@@ -6,7 +6,7 @@ const dsh_agent_1 = require("../../dsh-agent");
6
6
  const openai_adapter_1 = require("../qwenwork/openai-adapter");
7
7
  exports.dshManifest = {
8
8
  id: "dsh",
9
- version: "1.0.1",
9
+ version: "1.0.2",
10
10
  displayName: "DeepSeek Harness",
11
11
  entry: "dist/index.js",
12
12
  apiVersion: "1",
@@ -5,7 +5,7 @@ const promises_1 = require("node:fs/promises");
5
5
  const node_path_1 = require("node:path");
6
6
  const qrcode_1 = require("qrcode");
7
7
  const client_1 = require("./client");
8
- const manifest = { id: "feishu", version: "1.0.3", type: "channel", displayName: "飞书通道", entry: "dist/src-ts/plugins/feishu/index.js", apiVersion: "1", process: "in-process", capabilities: ["channel", "channel.bot.setup", "channel.receive", "channel.send", "health"], configSchema: "config.schema.json", managementPage: "/abweb/channels/feishu" };
8
+ const manifest = { id: "feishu", version: "1.0.4", type: "channel", displayName: "飞书通道", entry: "dist/src-ts/plugins/feishu/index.js", apiVersion: "1", process: "in-process", capabilities: ["channel", "channel.bot.setup", "channel.receive", "channel.send", "health"], configSchema: "config.schema.json", managementPage: "/abweb/channels/feishu" };
9
9
  class FeishuPlugin {
10
10
  options;
11
11
  manifest = manifest;
@@ -6,7 +6,7 @@ const openai_adapter_1 = require("./openai-adapter");
6
6
  const cdp_client_1 = require("./cdp-client");
7
7
  exports.qwenworkManifest = {
8
8
  id: "qwenwork",
9
- version: "1.0.1",
9
+ version: "1.0.2",
10
10
  displayName: "千问办公",
11
11
  entry: "dist/index.js",
12
12
  apiVersion: "1",
@@ -9,7 +9,7 @@ const node_path_1 = require("node:path");
9
9
  const cdp_client_1 = require("./cdp-client");
10
10
  const cli_client_1 = require("./cli-client");
11
11
  exports.workbuddyManifest = {
12
- id: "workbuddy", version: "1.1.0", displayName: "WorkBuddy", type: "agent",
12
+ id: "workbuddy", version: "1.1.1", displayName: "WorkBuddy", type: "agent",
13
13
  entry: "dist/index.js", apiVersion: "1", process: "in-process",
14
14
  capabilities: ["chat", "health"], configSchema: "config.schema.json",
15
15
  };
@@ -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"], evolcore: ["external.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, connectedAids: async () => ["external.agentid.cn"], ingress: { publish: async () => undefined } });
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.evolcore, ["external.agentid.cn"]);
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)("旧版创建身份按来源归入本工程且只显示已连接身份", async () => {
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, connectedAids: async () => ["doubao-lih.agentid.cn", "dshlihui.agentid.cn", "external.agentid.cn"], ingress: { publish: async () => undefined } });
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: ["external.agentid.cn"], muAgentBridge: ["doubao-lih.agentid.cn", "dshlihui.agentid.cn"], localMuAgentBridge: [] });
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
- async register(input) { calls.push(`register:${input.aid}:${input.owner}`); return registration; }
91
- load(aid) { return loadOk ? { ok: true, data: { aid } } : { ok: false, error: { message: "本地身份不存在" } }; }
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, 2);
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,6 +1,6 @@
1
1
  {
2
2
  "name": "mu-agent-bridge",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "将 AUN Agent 连接到本地桌面 AI 客户端的插件平台。",
5
5
  "main": "dist/src-ts/cli.js",
6
6
  "bin": {
@@ -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
- }