agent-bridge-aun 1.0.11 → 1.0.12

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
@@ -6,4 +6,4 @@
6
6
 
7
7
  该插件依赖 `@agentunion/fastaun`,要求 Node.js 22.16 或更高版本。
8
8
 
9
- ABWeb 的 AUN 设置展示本机 AID 和已连接 AID,不再依赖 `ec` 命令。"本机 AID"来自插件密钥库(`store.list()`),`ec stop` 后仍然可见;"本工程 · 已连接"是插件当前保持连接的身份。列表先显示已关联 Agent 的身份,各组按最近成功关联的时间倒序排列,时间相同或旧记录没有时间时按 AID 名称排序。关联时间保存在插件配置的 `binding_times` 中,刷新或重启后保留;旧记录不补造时间,再次关联成功后开始记录。关联时只要求 AID 在本地密钥库中,由插件直接建立连接,不再执行 `ec agent set/reload` 配置 EvolCore 路由。
9
+ ABWeb 的 AUN 设置只展示已连接 AID,并按来源分组。插件通过 SDK 密钥库枚举 AID,再逐个建立连接;只有连接成功的身份才会显示。EvolCore 来源身份只用于连接状态检测,不订阅消息,避免重复收信;本工程创建的身份负责消息收发。连接状态检测不调用 `ec agent list/show`。将 EvolCore 身份关联到 Agent 时仍使用既有 `ec agent set/reload` 路由配置,该配置不参与连接状态检测。列表先显示已关联 Agent 的身份,各组按最近成功关联的时间倒序排列,时间相同或旧记录没有时间时按 AID 名称排序。关联时间保存在插件配置的 `binding_times` 中,刷新或重启后保留;旧记录不补造时间,再次关联成功后开始记录。
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveRuntimePort = resolveRuntimePort;
4
+ function resolveRuntimePort(config, runtime, pluginId, envName, fallback) {
5
+ const injected = runtime?.ports?.[pluginId];
6
+ if (typeof injected === "number" && Number.isInteger(injected) && injected > 0)
7
+ return injected;
8
+ const configured = config.cdpPort;
9
+ if (typeof configured === "number" && Number.isInteger(configured) && configured > 0)
10
+ return configured;
11
+ const environment = Number(process.env[envName] ?? "");
12
+ return Number.isInteger(environment) && environment > 0 ? environment : fallback;
13
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runEc = runEc;
4
+ exports.configureAidForPlugin = configureAidForPlugin;
5
+ const node_child_process_1 = require("node:child_process");
6
+ const node_util_1 = require("node:util");
7
+ const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
8
+ async function runEc(args) {
9
+ try {
10
+ const { stdout } = await execFileAsync("ec", args, { shell: process.platform === "win32", timeout: 15_000, maxBuffer: 1024 * 1024 });
11
+ return JSON.parse(stdout);
12
+ }
13
+ catch (error) {
14
+ const stdout = error.stdout;
15
+ if (stdout) {
16
+ try {
17
+ return JSON.parse(stdout);
18
+ }
19
+ catch { /* 保留原始命令错误 */ }
20
+ }
21
+ throw error;
22
+ }
23
+ }
24
+ async function configureAidForPlugin(pluginId, aid, port, run = runEc) {
25
+ if (!aid)
26
+ return;
27
+ if (!/^[a-z0-9_-]+$/.test(pluginId))
28
+ throw new Error("插件 ID 格式无效");
29
+ const path = pluginId === "dsh" ? "/dsh/v1" : pluginId === "qwenwork" ? "/v1" : `/api/agents/${pluginId}/v1`;
30
+ for (const [key, value] of [
31
+ ["baseagents.ecagent.baseUrl", `http://127.0.0.1:${port}${path}`],
32
+ ["baseagents.ecagent.apiKey", "mab-local"],
33
+ ["baseagents.ecagent.model", pluginId],
34
+ ["active_baseagent", "ecagent"],
35
+ ]) {
36
+ const result = await run(["agent", "set", aid, key, value, "--format", "json"]);
37
+ if (!result?.ok)
38
+ throw new Error(`配置 AID ${aid} 失败:${key};${result?.code ?? ""} ${result?.error ?? "未知错误"}`);
39
+ }
40
+ const result = await run(["agent", "reload", aid, "--format", "json"]);
41
+ if (!result?.ok)
42
+ throw new Error(`重载 AID ${aid} 失败:${result?.code ?? ""} ${result?.error ?? "未知错误"}`);
43
+ }
@@ -8,8 +8,9 @@ const node_path_1 = require("node:path");
8
8
  const node_os_1 = require("node:os");
9
9
  const node_url_1 = require("node:url");
10
10
  const messages_1 = require("./messages");
11
+ const evolcore_1 = require("./evolcore");
11
12
  const manifest = {
12
- id: "aun", version: "1.0.11", type: "channel", displayName: "AUN 通道",
13
+ id: "aun", version: "1.0.12", type: "channel", displayName: "AUN 通道",
13
14
  entry: "dist/src-ts/plugins/aun/index.js", apiVersion: "1", process: "in-process",
14
15
  capabilities: ["channel", "channel.identity.create", "channel.receive", "channel.send", "health"],
15
16
  configSchema: "config.schema.json",
@@ -38,6 +39,7 @@ class AunPlugin {
38
39
  store;
39
40
  clients = new Map();
40
41
  identities = new Set();
42
+ legacyCreatedAids = new Set();
41
43
  bindings = {};
42
44
  bindingTimes = {};
43
45
  creating = false;
@@ -55,13 +57,11 @@ class AunPlugin {
55
57
  }
56
58
  identity = {
57
59
  list: async () => {
58
- // 不再依赖 ec 命令:本地密钥库的 AID 全部列出,本工程连接的 AID 以 clients 为准
59
- const local = this.listStoreAids();
60
+ const connected = [...this.clients.keys()];
60
61
  return {
61
- evolcore: [],
62
- muAgentBridge: [...this.clients.keys()].sort(),
62
+ evolcore: connected.filter((aid) => !this.identities.has(aid) && !this.legacyCreatedAids.has(aid)).sort(),
63
+ muAgentBridge: connected.filter((aid) => this.identities.has(aid) || this.legacyCreatedAids.has(aid)).sort(),
63
64
  localMuAgentBridge: [...this.identities].filter((aid) => !this.clients.has(aid)).sort(),
64
- local,
65
65
  };
66
66
  },
67
67
  create: async (aid, owner) => {
@@ -96,7 +96,7 @@ class AunPlugin {
96
96
  this.creating = false;
97
97
  }
98
98
  },
99
- bind: async (pluginId, aid, _port) => {
99
+ bind: async (pluginId, aid, port) => {
100
100
  if (pluginId === "aun" || pluginId === "abweb")
101
101
  throw new Error("只能关联 Agent 插件");
102
102
  const previous = this.bindings;
@@ -109,7 +109,7 @@ class AunPlugin {
109
109
  throw new Error("AID 格式无效");
110
110
  if (this.context?.pluginStatus(pluginId) !== "ready")
111
111
  throw new Error("目标 Agent 插件未启动");
112
- if (this.identities.has(aid)) {
112
+ if (this.identities.has(aid) || this.legacyCreatedAids.has(aid)) {
113
113
  if (!this.clients.has(aid))
114
114
  await this.connectAid(aid);
115
115
  if (!this.clients.has(aid))
@@ -122,20 +122,15 @@ class AunPlugin {
122
122
  this.bindings[aid] = pluginId;
123
123
  }
124
124
  else {
125
- // 不再调用 ec:只要 AID 在本地密钥库中就直接连接并绑定
126
- const loaded = this.store.load(aid);
127
- if (!loaded.ok || !loaded.data)
128
- throw new Error("AID 不在本地密钥库中,无法关联");
129
- await this.connectAid(aid);
130
- if (!this.clients.has(aid))
125
+ const connected = await this.identity.list();
126
+ if (![...connected.evolcore, ...connected.muAgentBridge].includes(aid))
131
127
  throw new Error("AID 当前未连接");
128
+ await (0, evolcore_1.configureAidForPlugin)(pluginId, aid, port);
132
129
  for (const [identity, target] of Object.entries(this.bindings))
133
130
  if (target === pluginId) {
134
131
  delete this.bindings[identity];
135
132
  delete this.bindingTimes[identity];
136
133
  }
137
- this.bindings[aid] = pluginId;
138
- this.identities.add(aid);
139
134
  }
140
135
  }
141
136
  else {
@@ -169,6 +164,18 @@ class AunPlugin {
169
164
  async activate(context) {
170
165
  this.context = context;
171
166
  this.config = { ...context.config };
167
+ this.legacyCreatedAids.clear();
168
+ try {
169
+ const created = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(context.dataDir, "..", "created-aids.json"), "utf8"));
170
+ if (Array.isArray(created))
171
+ for (const aid of created)
172
+ if (typeof aid === "string" && aidPattern.test(aid))
173
+ this.legacyCreatedAids.add(aid);
174
+ }
175
+ catch (error) {
176
+ if (error.code !== "ENOENT")
177
+ context.logger.warn("读取旧版身份创建记录失败", { error: safeError(error) });
178
+ }
172
179
  for (const key of ["aid", "owner_aid", "aun_path", "encryption_seed", "root_ca_path", "allow_from", "agent_plugin"]) {
173
180
  if (this.config[key] !== undefined && typeof this.config[key] !== "string")
174
181
  throw new Error(`${key} 必须是字符串`);
@@ -209,12 +216,10 @@ class AunPlugin {
209
216
  this.identities.add(this.aid);
210
217
  for (const aid of this.identities)
211
218
  await this.connectAid(aid);
212
- // 密钥库中的其余 AID 也自动连接:不再依赖 ec 或 EvolCore 进程
213
- for (const aid of this.listStoreAids()) {
214
- this.identities.add(aid);
219
+ // AUN 插件直接连接本地密钥库中的所有 AID,不依赖 ec 进程或 CLI。
220
+ for (const aid of this.listStoreAids())
215
221
  if (!this.clients.has(aid))
216
222
  await this.connectAid(aid);
217
- }
218
223
  }
219
224
  async connectAid(aid) {
220
225
  try {
@@ -222,12 +227,14 @@ class AunPlugin {
222
227
  if (!loaded.ok || !loaded.data)
223
228
  throw new Error(loaded.error?.message ?? "本地密钥库中不存在该 AID");
224
229
  const client = new this.sdk.AUNClient(loaded.data.aid);
225
- const subscription = client.on("message.received", (payload) => this.onMessage(payload, aid));
230
+ const subscription = this.identities.has(aid) || this.legacyCreatedAids.has(aid)
231
+ ? client.on("message.received", (payload) => this.onMessage(payload, aid))
232
+ : undefined;
226
233
  try {
227
234
  await client.connect();
228
235
  }
229
236
  catch (error) {
230
- subscription.unsubscribe();
237
+ subscription?.unsubscribe();
231
238
  await client.close();
232
239
  throw error;
233
240
  }
@@ -244,7 +251,7 @@ class AunPlugin {
244
251
  async deactivate(_reason) {
245
252
  this.status = "degraded";
246
253
  for (const { client, subscription } of this.clients.values()) {
247
- subscription.unsubscribe();
254
+ subscription?.unsubscribe();
248
255
  await client.close();
249
256
  }
250
257
  this.clients.clear();
@@ -261,11 +268,11 @@ class AunPlugin {
261
268
  async handle(_request) { throw new Error("AUN 是入站通道插件"); }
262
269
  path() {
263
270
  const configured = this.config.aun_path;
264
- // 默认与 EvolCore 共用同一密钥库目录,保证已注册的 AID 直接可用
265
- return typeof configured === "string" && configured.trim() ? configured : (0, node_path_1.resolve)(process.env.AUN_HOME ?? process.env.EVOLCORE_HOME ?? (0, node_path_1.join)((0, node_os_1.homedir)(), ".evolcore"));
271
+ if (typeof configured === "string" && configured.trim())
272
+ return configured;
273
+ return (0, node_path_1.resolve)(process.env.AUN_HOME ?? process.env.EVOLCORE_HOME ?? (0, node_path_1.join)((0, node_os_1.homedir)(), ".evolcore"));
266
274
  }
267
275
  newStore() {
268
- // 与 EvolCore 共用密钥库时沿用其固定 seed 和 CA 证书路径
269
276
  const rootCaPath = typeof this.config.root_ca_path === "string" && this.config.root_ca_path ? this.config.root_ca_path : (0, node_path_1.join)(this.path(), "CA", "root", "root.crt");
270
277
  return new this.sdk.AIDStore({ aunPath: this.path(), encryptionSeed: typeof this.config.encryption_seed === "string" && this.config.encryption_seed ? this.config.encryption_seed : "evol", verifySsl: typeof this.config.verify_ssl === "boolean" ? this.config.verify_ssl : true, rootCaPath: (0, node_fs_1.existsSync)(rootCaPath) ? rootCaPath : undefined });
271
278
  }
@@ -312,8 +319,8 @@ class AunPlugin {
312
319
  }
313
320
  listIdentities = async (_request, response) => {
314
321
  const groups = await this.identity.list();
315
- const connected = new Set([...groups.evolcore, ...groups.muAgentBridge, ...groups.localMuAgentBridge ?? []]);
316
- const localAids = (groups.local ?? []).filter((aid) => !connected.has(aid));
322
+ const connected = new Set([...groups.evolcore, ...groups.muAgentBridge]);
323
+ const localAids = this.listStoreAids().filter((aid) => !connected.has(aid));
317
324
  this.json(response, 200, { groups, localAids, bindings: this.bindings, bindingTimes: this.bindingTimes });
318
325
  };
319
326
  saveSettings = async (request, response) => {
@@ -31,8 +31,15 @@
31
31
  configForm.elements.encryption_seed.value = "";
32
32
  }
33
33
  list.replaceChildren();
34
- const entries = [["本工程 · 已连接", identities.groups.muAgentBridge || []], ["本机 AID", identities.groups.local || []], ["本工程 · 未连接", identities.groups.localMuAgentBridge || []]]
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 })));
34
+ const entries = [];
35
+ const seen = new Set();
36
+ for (const [group, label, values] of [[0, "本工程 · 已连接", identities.groups.muAgentBridge || []], [1, "EvolCore · 已连接", identities.groups.evolcore || []]]) {
37
+ for (const aid of values) {
38
+ if (seen.has(aid)) continue;
39
+ seen.add(aid);
40
+ entries.push({ aid, label, group, bound: identities.bindings?.[aid] || agents.find((agent) => agent.id && agent.configAid === aid)?.id || "", time: Date.parse(identities.bindingTimes?.[aid] || "") || 0 });
41
+ }
42
+ }
36
43
  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
44
  for (const { aid, label, bound } of entries) {
38
45
  const row = document.createElement("tr");
@@ -42,8 +49,8 @@
42
49
  select.value = bound; select.onchange = () => { if (select.value) void bind(aid, select.value); };
43
50
  cell.append(select); row.append(cell); list.append(row);
44
51
  }
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`);
52
+ 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); }
53
+ show(`${entries.length} 个已连接 AID`);
47
54
  } catch (error) { show(String(error), true); }
48
55
  finally { loading = false; }
49
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-bridge-aun",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "mu-agent-bridge 的 AUN 通道插件。",
5
5
  "keywords": [
6
6
  "mu-agent-bridge-plugin",
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "aun",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "type": "channel",
5
5
  "displayName": "AUN 通道",
6
6
  "entry": "dist/src-ts/plugins/aun/index.js",