agent-bridge-aun 1.0.10 → 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
|
|
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
|
+
}
|
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AunPlugin = void 0;
|
|
4
4
|
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
5
6
|
const node_module_1 = require("node:module");
|
|
6
7
|
const node_path_1 = require("node:path");
|
|
8
|
+
const node_os_1 = require("node:os");
|
|
7
9
|
const node_url_1 = require("node:url");
|
|
8
10
|
const messages_1 = require("./messages");
|
|
11
|
+
const evolcore_1 = require("./evolcore");
|
|
9
12
|
const manifest = {
|
|
10
|
-
id: "aun", version: "1.0.
|
|
13
|
+
id: "aun", version: "1.0.12", type: "channel", displayName: "AUN 通道",
|
|
11
14
|
entry: "dist/src-ts/plugins/aun/index.js", apiVersion: "1", process: "in-process",
|
|
12
15
|
capabilities: ["channel", "channel.identity.create", "channel.receive", "channel.send", "health"],
|
|
13
16
|
configSchema: "config.schema.json",
|
|
@@ -36,6 +39,7 @@ class AunPlugin {
|
|
|
36
39
|
store;
|
|
37
40
|
clients = new Map();
|
|
38
41
|
identities = new Set();
|
|
42
|
+
legacyCreatedAids = new Set();
|
|
39
43
|
bindings = {};
|
|
40
44
|
bindingTimes = {};
|
|
41
45
|
creating = false;
|
|
@@ -53,13 +57,11 @@ class AunPlugin {
|
|
|
53
57
|
}
|
|
54
58
|
identity = {
|
|
55
59
|
list: async () => {
|
|
56
|
-
|
|
57
|
-
const local = this.listStoreAids();
|
|
60
|
+
const connected = [...this.clients.keys()];
|
|
58
61
|
return {
|
|
59
|
-
evolcore:
|
|
60
|
-
muAgentBridge:
|
|
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(),
|
|
61
64
|
localMuAgentBridge: [...this.identities].filter((aid) => !this.clients.has(aid)).sort(),
|
|
62
|
-
local,
|
|
63
65
|
};
|
|
64
66
|
},
|
|
65
67
|
create: async (aid, owner) => {
|
|
@@ -94,7 +96,7 @@ class AunPlugin {
|
|
|
94
96
|
this.creating = false;
|
|
95
97
|
}
|
|
96
98
|
},
|
|
97
|
-
bind: async (pluginId, aid,
|
|
99
|
+
bind: async (pluginId, aid, port) => {
|
|
98
100
|
if (pluginId === "aun" || pluginId === "abweb")
|
|
99
101
|
throw new Error("只能关联 Agent 插件");
|
|
100
102
|
const previous = this.bindings;
|
|
@@ -107,7 +109,7 @@ class AunPlugin {
|
|
|
107
109
|
throw new Error("AID 格式无效");
|
|
108
110
|
if (this.context?.pluginStatus(pluginId) !== "ready")
|
|
109
111
|
throw new Error("目标 Agent 插件未启动");
|
|
110
|
-
if (this.identities.has(aid)) {
|
|
112
|
+
if (this.identities.has(aid) || this.legacyCreatedAids.has(aid)) {
|
|
111
113
|
if (!this.clients.has(aid))
|
|
112
114
|
await this.connectAid(aid);
|
|
113
115
|
if (!this.clients.has(aid))
|
|
@@ -120,20 +122,15 @@ class AunPlugin {
|
|
|
120
122
|
this.bindings[aid] = pluginId;
|
|
121
123
|
}
|
|
122
124
|
else {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (!loaded.ok || !loaded.data)
|
|
126
|
-
throw new Error("AID 不在本地密钥库中,无法关联");
|
|
127
|
-
await this.connectAid(aid);
|
|
128
|
-
if (!this.clients.has(aid))
|
|
125
|
+
const connected = await this.identity.list();
|
|
126
|
+
if (![...connected.evolcore, ...connected.muAgentBridge].includes(aid))
|
|
129
127
|
throw new Error("AID 当前未连接");
|
|
128
|
+
await (0, evolcore_1.configureAidForPlugin)(pluginId, aid, port);
|
|
130
129
|
for (const [identity, target] of Object.entries(this.bindings))
|
|
131
130
|
if (target === pluginId) {
|
|
132
131
|
delete this.bindings[identity];
|
|
133
132
|
delete this.bindingTimes[identity];
|
|
134
133
|
}
|
|
135
|
-
this.bindings[aid] = pluginId;
|
|
136
|
-
this.identities.add(aid);
|
|
137
134
|
}
|
|
138
135
|
}
|
|
139
136
|
else {
|
|
@@ -167,6 +164,18 @@ class AunPlugin {
|
|
|
167
164
|
async activate(context) {
|
|
168
165
|
this.context = context;
|
|
169
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
|
+
}
|
|
170
179
|
for (const key of ["aid", "owner_aid", "aun_path", "encryption_seed", "root_ca_path", "allow_from", "agent_plugin"]) {
|
|
171
180
|
if (this.config[key] !== undefined && typeof this.config[key] !== "string")
|
|
172
181
|
throw new Error(`${key} 必须是字符串`);
|
|
@@ -207,6 +216,10 @@ class AunPlugin {
|
|
|
207
216
|
this.identities.add(this.aid);
|
|
208
217
|
for (const aid of this.identities)
|
|
209
218
|
await this.connectAid(aid);
|
|
219
|
+
// AUN 插件直接连接本地密钥库中的所有 AID,不依赖 ec 进程或 CLI。
|
|
220
|
+
for (const aid of this.listStoreAids())
|
|
221
|
+
if (!this.clients.has(aid))
|
|
222
|
+
await this.connectAid(aid);
|
|
210
223
|
}
|
|
211
224
|
async connectAid(aid) {
|
|
212
225
|
try {
|
|
@@ -214,12 +227,14 @@ class AunPlugin {
|
|
|
214
227
|
if (!loaded.ok || !loaded.data)
|
|
215
228
|
throw new Error(loaded.error?.message ?? "本地密钥库中不存在该 AID");
|
|
216
229
|
const client = new this.sdk.AUNClient(loaded.data.aid);
|
|
217
|
-
const subscription =
|
|
230
|
+
const subscription = this.identities.has(aid) || this.legacyCreatedAids.has(aid)
|
|
231
|
+
? client.on("message.received", (payload) => this.onMessage(payload, aid))
|
|
232
|
+
: undefined;
|
|
218
233
|
try {
|
|
219
234
|
await client.connect();
|
|
220
235
|
}
|
|
221
236
|
catch (error) {
|
|
222
|
-
subscription
|
|
237
|
+
subscription?.unsubscribe();
|
|
223
238
|
await client.close();
|
|
224
239
|
throw error;
|
|
225
240
|
}
|
|
@@ -236,7 +251,7 @@ class AunPlugin {
|
|
|
236
251
|
async deactivate(_reason) {
|
|
237
252
|
this.status = "degraded";
|
|
238
253
|
for (const { client, subscription } of this.clients.values()) {
|
|
239
|
-
subscription
|
|
254
|
+
subscription?.unsubscribe();
|
|
240
255
|
await client.close();
|
|
241
256
|
}
|
|
242
257
|
this.clients.clear();
|
|
@@ -253,10 +268,13 @@ class AunPlugin {
|
|
|
253
268
|
async handle(_request) { throw new Error("AUN 是入站通道插件"); }
|
|
254
269
|
path() {
|
|
255
270
|
const configured = this.config.aun_path;
|
|
256
|
-
|
|
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"));
|
|
257
274
|
}
|
|
258
275
|
newStore() {
|
|
259
|
-
|
|
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");
|
|
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 });
|
|
260
278
|
}
|
|
261
279
|
createAid = async (request, response) => {
|
|
262
280
|
let input;
|
|
@@ -301,8 +319,8 @@ class AunPlugin {
|
|
|
301
319
|
}
|
|
302
320
|
listIdentities = async (_request, response) => {
|
|
303
321
|
const groups = await this.identity.list();
|
|
304
|
-
const connected = new Set([...groups.evolcore, ...groups.muAgentBridge
|
|
305
|
-
const localAids = (
|
|
322
|
+
const connected = new Set([...groups.evolcore, ...groups.muAgentBridge]);
|
|
323
|
+
const localAids = this.listStoreAids().filter((aid) => !connected.has(aid));
|
|
306
324
|
this.json(response, 200, { groups, localAids, bindings: this.bindings, bindingTimes: this.bindingTimes });
|
|
307
325
|
};
|
|
308
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 = [
|
|
35
|
-
|
|
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 = "
|
|
46
|
-
show(`${
|
|
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