mu-agent-bridge 1.0.14 → 1.0.16
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 +15 -8
- package/dist/src-ts/cli.js +47 -1
- package/dist/src-ts/control-server.js +7 -0
- package/dist/src-ts/local-aids.js +2 -2
- package/dist/src-ts/plugin-manifest.js +4 -1
- package/dist/src-ts/plugins/abweb/public/app.js +10 -0
- package/dist/src-ts/plugins/aun/evolcore.js +0 -11
- package/dist/src-ts/plugins/aun/index.js +30 -16
- package/dist/src-ts/plugins/qwenwork/cdp-client.js +8 -1
- package/dist/tests-ts/aun-plugin.test.js +65 -4
- package/dist/tests-ts/bundled-package.test.js +24 -0
- package/dist/tests-ts/control-server.test.js +24 -49
- package/dist/tests-ts/plugin-manager.test.js +39 -0
- package/dist/tests-ts/qwenwork-plugin.test.js +38 -0
- package/package.json +6 -6
- package/plugins/abweb/dist/src-ts/agent.js +10 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/control-client.js +91 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/index.js +132 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.js +366 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.ts +227 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/index.html +25 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/style.css +55 -0
- package/plugins/abweb/plugin.json +7 -3
- package/plugins/aun/config.schema.json +18 -0
- package/plugins/aun/dist/src-ts/agent.js +10 -0
- package/plugins/aun/dist/src-ts/plugins/aun/evolcore.js +43 -0
- package/plugins/aun/dist/src-ts/plugins/aun/index.js +434 -0
- package/plugins/aun/dist/src-ts/plugins/aun/messages.js +45 -0
- package/plugins/aun/dist/src-ts/plugins/aun/public/app.js +66 -0
- package/plugins/aun/dist/src-ts/plugins/aun/public/index.html +14 -0
- package/plugins/aun/dist/src-ts/plugins/aun/public/style.css +21 -0
- package/plugins/aun/plugin.json +18 -0
- package/plugins/doubao/config.schema.json +13 -0
- package/plugins/doubao/dist/src-ts/agent.js +10 -0
- package/plugins/doubao/dist/src-ts/plugins/doubao/cdp-client.js +94 -0
- package/plugins/doubao/dist/src-ts/plugins/doubao/index.js +84 -0
- package/plugins/doubao/plugin.json +15 -0
- package/plugins/dsh/config.schema.json +8 -0
- package/plugins/dsh/dist/src-ts/agent.js +10 -0
- package/plugins/dsh/dist/src-ts/dsh-agent.js +70 -0
- package/plugins/dsh/dist/src-ts/dsh-paths.js +15 -0
- package/plugins/dsh/dist/src-ts/headless-account.patch.yml +5 -0
- package/plugins/dsh/dist/src-ts/plugins/dsh/index.js +61 -0
- package/plugins/dsh/dist/src-ts/plugins/qwenwork/openai-adapter.js +146 -0
- package/plugins/dsh/plugin.json +14 -0
- package/plugins/feishu/config.schema.json +68 -0
- package/plugins/feishu/dist/src-ts/agent.js +10 -0
- package/plugins/feishu/dist/src-ts/channel.js +2 -0
- package/plugins/feishu/dist/src-ts/plugins/feishu/client.js +133 -0
- package/plugins/feishu/dist/src-ts/plugins/feishu/index.js +257 -0
- package/plugins/feishu/dist/src-ts/plugins/feishu/public/app.js +147 -0
- package/plugins/feishu/dist/src-ts/plugins/feishu/public/index.html +17 -0
- package/plugins/feishu/dist/src-ts/plugins/feishu/public/style.css +30 -0
- package/plugins/feishu/plugin.json +18 -0
- package/plugins/qwenwork/dist/src-ts/agent.js +10 -0
- package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/cdp-client.js +172 -0
- package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/index.js +148 -0
- package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/openai-adapter.js +146 -0
- package/plugins/qwenwork/plugin.json +8 -4
- package/plugins/workbuddy/config.schema.json +15 -0
- package/plugins/workbuddy/dist/src-ts/agent.js +10 -0
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cdp-client.js +118 -0
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cli-client.js +39 -0
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/index.js +139 -0
- package/plugins/workbuddy/plugin.json +15 -0
package/README.md
CHANGED
|
@@ -20,13 +20,10 @@ OpenAI 兼容 API 为 `/v1/models` 和 `/v1/chat/completions`。管理页面位
|
|
|
20
20
|
安装后使用 `mab start` 启动。旧桥仍可使用 `17893`,不会与管理页面冲突。局域网访问时设置
|
|
21
21
|
`AGENT_BRIDGE_HOST=0.0.0.0` 和 `AGENT_BRIDGE_TOKEN`,然后访问
|
|
22
22
|
`http://<Windows 主机 IP>:26107/abweb/`。页面使用一次性配置码配对后管理插件;请只在可信网络使用。
|
|
23
|
-
已有 AID 的连接状态由 AUN
|
|
24
|
-
|
|
23
|
+
已有 AID 的连接状态由 AUN 插件自己建立和查询,只有当前已连接的身份才能关联 Agent。
|
|
24
|
+
AUN 插件通过 SDK 枚举 EvolCore 的本地 AID,并逐个建立连接;ABWeb 只展示已连接 AID,并按 EvolCore 与 mu-agent-bridge 分组,未连接身份不显示。状态检测不调用 `ec agent list/show`。
|
|
25
25
|
创建新 AID 必须填写 Owner AID,并安装、启动 AUN 插件;创建与通信由该插件完成。
|
|
26
|
-
|
|
27
|
-
关联 EvolCore 身份到 DSH 或千问办公时,AUN 插件会将所选身份的执行基座分别配置为本机
|
|
28
|
-
`/dsh/v1` 或 `/v1` OpenAI 接口,然后重载该 Agent;AUN 入站消息由 EvolCore 转给插件,
|
|
29
|
-
回复仍由 EvolCore 经 AUN 发送。该操作会覆盖所选 AID 当前的执行基座。
|
|
26
|
+
本工程创建的身份由 AUN 插件保持连接并收发消息;EvolCore 来源身份只用于连接状态检测,不订阅消息,避免重复收信。将 EvolCore 身份关联到 Agent 时,AUN 插件仍执行既有 `ec agent set/reload` 路由配置;该命令不用于检测连接状态。
|
|
30
27
|
其他 Agent 插件可关联 AUN 插件自己创建的身份,由通道直接转发来信和回复。
|
|
31
28
|
Windows 可运行 `start-mab.ps1` 注册并启动登录时自动运行的计划任务;令牌保存在
|
|
32
29
|
`%USERPROFILE%\.mab\token.txt`,页面输入该令牌即可使用管理 API。
|
|
@@ -43,7 +40,14 @@ abweb 的“配置码”栏;配对码 10 分钟有效,只能使用一次,
|
|
|
43
40
|
|
|
44
41
|
## npm 插件
|
|
45
42
|
|
|
46
|
-
默认包 `mu-agent-bridge`
|
|
43
|
+
默认包 `mu-agent-bridge` 已内置 abweb、AUN、千问办公、DSH、豆包、飞书和 WorkBuddy 七个插件,直接安装即可使用:
|
|
44
|
+
|
|
45
|
+
```powershell
|
|
46
|
+
npm install -g mu-agent-bridge@latest
|
|
47
|
+
mab start
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
七个插件会从核心包的 `plugins/` 目录自动发现。插件仍分别发布为独立 npm 包,可用于单独测试、升级或替换版本。安装与发布说明见
|
|
47
51
|
[`docs/npm-publishing.md`](docs/npm-publishing.md)。
|
|
48
52
|
|
|
49
53
|
`mab start` 启动时会查询核心包和托管插件的 npm 最新版本,检查状态保存于 mab 状态目录的
|
|
@@ -51,6 +55,9 @@ abweb 的“配置码”栏;配对码 10 分钟有效,只能使用一次,
|
|
|
51
55
|
升级失败会恢复旧插件并继续启动。Windows 的 `start-mab.ps1` 登录计划任务会在启动 daemon 前
|
|
52
56
|
更新全局核心包,健康检查失败时恢复备份。全局单独安装的插件及 Linux 核心自动升级暂不受管理。
|
|
53
57
|
|
|
58
|
+
可用 `mab status` 查看后台、插件以及 AUN 已连接 AID 和关联 Agent 的状态。AUN 插件自己加载本地
|
|
59
|
+
`~/.evolcore/AIDs` 并建立连接,不要求先启动 `ec start`,也不调用 `ec agent list/show`。
|
|
60
|
+
|
|
54
61
|
插件更新策略可在 ABWeb 的“版本管理”中选择:默认“自动下载并安装”;“自动下载,手动安装”会把新版本缓存到状态目录并等待页面操作;“手动下载和安装”只检查版本。策略保存在 `state/update-policy.json`,插件下载缓存位于 `state/downloads`。
|
|
55
62
|
|
|
56
63
|
运行时会发现核心包依赖和 `AGENT_BRIDGE_PLUGIN_PACKAGES` 中声明的 npm 包。插件包在自己的
|
|
@@ -65,7 +72,7 @@ abweb 插件目录从 npm 搜索带 `mu-agent-bridge-plugin` 关键词的包,
|
|
|
65
72
|
插件仍在 daemon 的同一个 Node.js 进程内运行。修改插件入口依赖后应重启 daemon,避免模块缓存
|
|
66
73
|
影响新代码。
|
|
67
74
|
|
|
68
|
-
npm
|
|
75
|
+
npm 尚未发布时,核心包内置的七个默认插件仍会出现在插件列表。abweb 的“安装本地插件”
|
|
69
76
|
可填写 **Windows 主机上**包含 `plugin.json` 的目录路径,例如编译后的
|
|
70
77
|
`C:\path\to\agent_bridge\packages\dsh`;安装后可在下拉框中启动。已内置的千问办公无需再次安装。
|
|
71
78
|
“安装 npm 插件”只适用于包已经公开发布的情况。npm 发布令牌仅供发布脚本向 npm 官网认证,
|
package/dist/src-ts/cli.js
CHANGED
|
@@ -109,6 +109,50 @@ async function update() {
|
|
|
109
109
|
console.log("核心已更新,已请求 mab 计划任务重新启动");
|
|
110
110
|
return 0;
|
|
111
111
|
}
|
|
112
|
+
async function status() {
|
|
113
|
+
const port = Number(process.env.AGENT_BRIDGE_PORT ?? "26107");
|
|
114
|
+
const get = (path) => new Promise((resolve, reject) => {
|
|
115
|
+
const req = (0, node_http_1.request)({ host: "127.0.0.1", port, path, method: "GET" }, (res) => {
|
|
116
|
+
let body = "";
|
|
117
|
+
res.setEncoding("utf8");
|
|
118
|
+
res.on("data", (chunk) => body += chunk);
|
|
119
|
+
res.on("end", () => {
|
|
120
|
+
try {
|
|
121
|
+
const value = JSON.parse(body);
|
|
122
|
+
if ((res.statusCode ?? 500) >= 400)
|
|
123
|
+
reject(new Error(value.error ?? `HTTP ${res.statusCode}`));
|
|
124
|
+
else
|
|
125
|
+
resolve(value);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
reject(new Error("后台响应格式错误"));
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
req.setTimeout(5000, () => req.destroy(new Error("连接后台超时")));
|
|
133
|
+
req.on("error", reject);
|
|
134
|
+
req.end();
|
|
135
|
+
});
|
|
136
|
+
try {
|
|
137
|
+
const [plugins, health, aids] = await Promise.all([get("/api/plugins"), get("/api/health"), get("/api/plugins/aun/identities")]);
|
|
138
|
+
console.log(`后台:运行中(端口 ${port})`);
|
|
139
|
+
console.log(`插件:${health.plugins ?? plugins.plugins?.length ?? 0} 个`);
|
|
140
|
+
for (const plugin of plugins.plugins ?? [])
|
|
141
|
+
console.log(` ${plugin.id} ${plugin.version}:${plugin.status}`);
|
|
142
|
+
const groups = aids.groups ?? { muAgentBridge: [], evolcore: [] };
|
|
143
|
+
const all = aids.aids ?? [...(groups.muAgentBridge ?? []), ...(groups.evolcore ?? [])];
|
|
144
|
+
console.log(`AUN 已连接 AID:${all.length} 个`);
|
|
145
|
+
for (const aid of groups.muAgentBridge ?? [])
|
|
146
|
+
console.log(` ${aid}:本工程${aids.bindings?.[aid] ? ` → ${aids.bindings[aid]}` : ""}`);
|
|
147
|
+
for (const aid of groups.evolcore ?? [])
|
|
148
|
+
console.log(` ${aid}:EvolCore${aids.bindings?.[aid] ? ` → ${aids.bindings[aid]}` : ""}`);
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
console.error(`后台未运行或无法访问:${error instanceof Error ? error.message : String(error)}`);
|
|
153
|
+
return 1;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
112
156
|
async function serve() {
|
|
113
157
|
const manager = new plugin_manager_1.PluginManager({
|
|
114
158
|
pluginsDir: (0, node_path_1.resolve)(process.env.AGENT_BRIDGE_PLUGINS_DIR ?? (0, node_path_1.resolve)(__dirname, "..", "..", "plugins")),
|
|
@@ -201,6 +245,8 @@ async function main() {
|
|
|
201
245
|
const args = process.argv.slice(2);
|
|
202
246
|
if (args.includes("pair"))
|
|
203
247
|
return pair();
|
|
248
|
+
if (args[0] === "status")
|
|
249
|
+
return status();
|
|
204
250
|
if (args[0] === "update")
|
|
205
251
|
return update();
|
|
206
252
|
const selfTestIndex = args.indexOf("--self-test");
|
|
@@ -208,7 +254,7 @@ async function main() {
|
|
|
208
254
|
return selfTest(args[selfTestIndex + 1] ?? "hi");
|
|
209
255
|
if (args.includes("--serve") || args.includes("start"))
|
|
210
256
|
return serve();
|
|
211
|
-
console.error("用法:mab start | mab --self-test <任务>");
|
|
257
|
+
console.error("用法:mab start | mab status | mab --self-test <任务>");
|
|
212
258
|
return 2;
|
|
213
259
|
}
|
|
214
260
|
main().then((code) => { process.exitCode = code; }).catch((error) => {
|
|
@@ -189,6 +189,13 @@ class ControlServer {
|
|
|
189
189
|
}
|
|
190
190
|
if (await this.options.manager.dispatchHttp(req, res))
|
|
191
191
|
return;
|
|
192
|
+
// 根路径直接进入 abweb 管理页面,避免用户手敲 /abweb/
|
|
193
|
+
if (method === "GET" && (url.pathname === "/" || url.pathname === "")) {
|
|
194
|
+
res.statusCode = 302;
|
|
195
|
+
res.setHeader("location", "/abweb/");
|
|
196
|
+
res.end();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
192
199
|
return this.json(res, 404, { error: "not found" });
|
|
193
200
|
}
|
|
194
201
|
catch (error) {
|
|
@@ -4,8 +4,8 @@ exports.listExistingAids = listExistingAids;
|
|
|
4
4
|
const promises_1 = require("node:fs/promises");
|
|
5
5
|
const node_os_1 = require("node:os");
|
|
6
6
|
const node_path_1 = require("node:path");
|
|
7
|
-
async function listExistingAids() {
|
|
8
|
-
const root = (0, node_path_1.resolve)(process.env.EVOLCORE_HOME ?? (0, node_path_1.join)((0, node_os_1.homedir)(), ".evolcore"), "AIDs");
|
|
7
|
+
async function listExistingAids(aunRoot) {
|
|
8
|
+
const root = (0, node_path_1.resolve)(aunRoot ?? process.env.EVOLCORE_HOME ?? (0, node_path_1.join)((0, node_os_1.homedir)(), ".evolcore"), "AIDs");
|
|
9
9
|
let names;
|
|
10
10
|
try {
|
|
11
11
|
names = await (0, promises_1.readdir)(root);
|
|
@@ -4,6 +4,7 @@ exports.validateManifest = validateManifest;
|
|
|
4
4
|
const node_path_1 = require("node:path");
|
|
5
5
|
const agent_1 = require("./agent");
|
|
6
6
|
const semver = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
7
|
+
const httpUrl = /^https?:\/\/.+$/;
|
|
7
8
|
function validateManifest(value, baseDir) {
|
|
8
9
|
if (!value || typeof value !== "object")
|
|
9
10
|
throw new agent_1.AgentError("invalid plugin manifest");
|
|
@@ -27,6 +28,8 @@ function validateManifest(value, baseDir) {
|
|
|
27
28
|
throw new agent_1.AgentError("invalid plugin process");
|
|
28
29
|
if (m.managementPage !== undefined && ((m.type ?? inferredType) !== "channel" || m.managementPage !== `/abweb/channels/${m.id}`))
|
|
29
30
|
throw new agent_1.AgentError("插件管理页面路径无效");
|
|
31
|
+
if (m.clientDownloadUrl !== undefined && (typeof m.clientDownloadUrl !== "string" || !httpUrl.test(m.clientDownloadUrl)))
|
|
32
|
+
throw new agent_1.AgentError("客户端下载地址必须是 http(s) URL");
|
|
30
33
|
if (m.dependencies && (!m.dependencies || typeof m.dependencies !== "object" || Array.isArray(m.dependencies) || Object.entries(m.dependencies).some(([id, range]) => !/^[a-z][a-z0-9-]{1,63}$/.test(id) || typeof range !== "string" || !range.trim())))
|
|
31
34
|
throw new agent_1.AgentError("插件依赖声明无效");
|
|
32
35
|
if (baseDir) {
|
|
@@ -36,5 +39,5 @@ function validateManifest(value, baseDir) {
|
|
|
36
39
|
if ((0, node_path_1.isAbsolute)(m.entry) || rel.startsWith(`..${node_path_1.sep}`) || rel === "..")
|
|
37
40
|
throw new agent_1.AgentError("plugin entry path escapes plugin directory");
|
|
38
41
|
}
|
|
39
|
-
return { id: m.id, version: m.version, displayName: m.displayName ?? m.id, type: m.type ?? inferredType, entry: m.entry, apiVersion: m.apiVersion, process: m.process ?? "in-process", capabilities: [...m.capabilities], configSchema: m.configSchema, routes: m.routes, ...(m.dependencies ? { dependencies: { ...m.dependencies } } : {}), ...(m.managementPage ? { managementPage: m.managementPage } : {}) };
|
|
42
|
+
return { id: m.id, version: m.version, displayName: m.displayName ?? m.id, type: m.type ?? inferredType, entry: m.entry, apiVersion: m.apiVersion, process: m.process ?? "in-process", capabilities: [...m.capabilities], configSchema: m.configSchema, routes: m.routes, ...(m.dependencies ? { dependencies: { ...m.dependencies } } : {}), ...(m.managementPage ? { managementPage: m.managementPage } : {}), ...(m.clientDownloadUrl ? { clientDownloadUrl: m.clientDownloadUrl } : {}) };
|
|
40
43
|
}
|
|
@@ -239,6 +239,16 @@
|
|
|
239
239
|
detail.textContent = `依赖:${plugin.dependencyStatus.join(";")}`;
|
|
240
240
|
state.append(detail);
|
|
241
241
|
}
|
|
242
|
+
// 插件未就绪且声明了客户端下载地址时,给出获取桌面客户端的入口
|
|
243
|
+
if (plugin.manifest?.clientDownloadUrl && plugin.status !== "ready") {
|
|
244
|
+
const link = document.createElement("a");
|
|
245
|
+
link.className = "plugin-id";
|
|
246
|
+
link.href = plugin.manifest.clientDownloadUrl;
|
|
247
|
+
link.target = "_blank";
|
|
248
|
+
link.rel = "noreferrer noopener";
|
|
249
|
+
link.textContent = "下载客户端";
|
|
250
|
+
state.append(link);
|
|
251
|
+
}
|
|
242
252
|
const controls = document.createElement("td");
|
|
243
253
|
controls.className = "controls";
|
|
244
254
|
if (pluginVersions[plugin.id]?.state === "update-available" && plugin.path.includes("node_modules")) {
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.runEc = runEc;
|
|
4
4
|
exports.configureAidForPlugin = configureAidForPlugin;
|
|
5
|
-
exports.listConnectedAids = listConnectedAids;
|
|
6
5
|
const node_child_process_1 = require("node:child_process");
|
|
7
6
|
const node_util_1 = require("node:util");
|
|
8
|
-
const local_aids_1 = require("../../local-aids");
|
|
9
7
|
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
10
8
|
async function runEc(args) {
|
|
11
9
|
try {
|
|
@@ -43,12 +41,3 @@ async function configureAidForPlugin(pluginId, aid, port, run = runEc) {
|
|
|
43
41
|
if (!result?.ok)
|
|
44
42
|
throw new Error(`重载 AID ${aid} 失败:${result?.code ?? ""} ${result?.error ?? "未知错误"}`);
|
|
45
43
|
}
|
|
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
|
-
}
|
|
@@ -2,14 +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");
|
|
9
11
|
const evolcore_1 = require("./evolcore");
|
|
10
|
-
const local_aids_1 = require("../../local-aids");
|
|
11
12
|
const manifest = {
|
|
12
|
-
id: "aun", version: "1.0.
|
|
13
|
+
id: "aun", version: "1.0.10", 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",
|
|
@@ -56,13 +57,10 @@ class AunPlugin {
|
|
|
56
57
|
}
|
|
57
58
|
identity = {
|
|
58
59
|
list: async () => {
|
|
59
|
-
const connected =
|
|
60
|
-
this.context?.logger.warn("查询 EvolCore 已连接身份失败", { error: safeError(error) });
|
|
61
|
-
return [];
|
|
62
|
-
});
|
|
60
|
+
const connected = [...this.clients.keys()];
|
|
63
61
|
return {
|
|
64
|
-
evolcore: connected.filter((aid) => !this.identities.has(aid) && !this.legacyCreatedAids.has(aid)),
|
|
65
|
-
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(),
|
|
66
64
|
localMuAgentBridge: [...this.identities].filter((aid) => !this.clients.has(aid)).sort(),
|
|
67
65
|
};
|
|
68
66
|
},
|
|
@@ -111,7 +109,7 @@ class AunPlugin {
|
|
|
111
109
|
throw new Error("AID 格式无效");
|
|
112
110
|
if (this.context?.pluginStatus(pluginId) !== "ready")
|
|
113
111
|
throw new Error("目标 Agent 插件未启动");
|
|
114
|
-
if (this.identities.has(aid)) {
|
|
112
|
+
if (this.identities.has(aid) || this.legacyCreatedAids.has(aid)) {
|
|
115
113
|
if (!this.clients.has(aid))
|
|
116
114
|
await this.connectAid(aid);
|
|
117
115
|
if (!this.clients.has(aid))
|
|
@@ -124,7 +122,8 @@ class AunPlugin {
|
|
|
124
122
|
this.bindings[aid] = pluginId;
|
|
125
123
|
}
|
|
126
124
|
else {
|
|
127
|
-
|
|
125
|
+
const connected = await this.identity.list();
|
|
126
|
+
if (![...connected.evolcore, ...connected.muAgentBridge].includes(aid))
|
|
128
127
|
throw new Error("AID 当前未连接");
|
|
129
128
|
await (0, evolcore_1.configureAidForPlugin)(pluginId, aid, port);
|
|
130
129
|
for (const [identity, target] of Object.entries(this.bindings))
|
|
@@ -217,6 +216,10 @@ class AunPlugin {
|
|
|
217
216
|
this.identities.add(this.aid);
|
|
218
217
|
for (const aid of this.identities)
|
|
219
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);
|
|
220
223
|
}
|
|
221
224
|
async connectAid(aid) {
|
|
222
225
|
try {
|
|
@@ -224,12 +227,14 @@ class AunPlugin {
|
|
|
224
227
|
if (!loaded.ok || !loaded.data)
|
|
225
228
|
throw new Error(loaded.error?.message ?? "本地密钥库中不存在该 AID");
|
|
226
229
|
const client = new this.sdk.AUNClient(loaded.data.aid);
|
|
227
|
-
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;
|
|
228
233
|
try {
|
|
229
234
|
await client.connect();
|
|
230
235
|
}
|
|
231
236
|
catch (error) {
|
|
232
|
-
subscription
|
|
237
|
+
subscription?.unsubscribe();
|
|
233
238
|
await client.close();
|
|
234
239
|
throw error;
|
|
235
240
|
}
|
|
@@ -246,7 +251,7 @@ class AunPlugin {
|
|
|
246
251
|
async deactivate(_reason) {
|
|
247
252
|
this.status = "degraded";
|
|
248
253
|
for (const { client, subscription } of this.clients.values()) {
|
|
249
|
-
subscription
|
|
254
|
+
subscription?.unsubscribe();
|
|
250
255
|
await client.close();
|
|
251
256
|
}
|
|
252
257
|
this.clients.clear();
|
|
@@ -263,10 +268,13 @@ class AunPlugin {
|
|
|
263
268
|
async handle(_request) { throw new Error("AUN 是入站通道插件"); }
|
|
264
269
|
path() {
|
|
265
270
|
const configured = this.config.aun_path;
|
|
266
|
-
|
|
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"));
|
|
267
274
|
}
|
|
268
275
|
newStore() {
|
|
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");
|
|
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 });
|
|
270
278
|
}
|
|
271
279
|
createAid = async (request, response) => {
|
|
272
280
|
let input;
|
|
@@ -303,10 +311,16 @@ class AunPlugin {
|
|
|
303
311
|
return this.json(response, 502, { error: safeError(error) });
|
|
304
312
|
}
|
|
305
313
|
};
|
|
314
|
+
listStoreAids() {
|
|
315
|
+
const result = this.store?.list();
|
|
316
|
+
if (!result?.ok || !Array.isArray(result.data?.identities))
|
|
317
|
+
return [];
|
|
318
|
+
return [...new Set(result.data.identities.filter((item) => item && typeof item.aid === "string" && aidPattern.test(item.aid)).map((item) => item.aid))].sort();
|
|
319
|
+
}
|
|
306
320
|
listIdentities = async (_request, response) => {
|
|
307
321
|
const groups = await this.identity.list();
|
|
308
322
|
const connected = new Set([...groups.evolcore, ...groups.muAgentBridge]);
|
|
309
|
-
const localAids =
|
|
323
|
+
const localAids = this.listStoreAids().filter((aid) => !connected.has(aid));
|
|
310
324
|
this.json(response, 200, { groups, localAids, bindings: this.bindings, bindingTimes: this.bindingTimes });
|
|
311
325
|
};
|
|
312
326
|
saveSettings = async (request, response) => {
|
|
@@ -40,7 +40,14 @@ class QwenCdpClient {
|
|
|
40
40
|
if (this.socket)
|
|
41
41
|
return;
|
|
42
42
|
const fetchImpl = this.options.fetchImpl ?? fetch;
|
|
43
|
-
|
|
43
|
+
let response;
|
|
44
|
+
try {
|
|
45
|
+
response = await fetchImpl(`http://127.0.0.1:${this.options.port}/json`);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
const code = error?.cause?.code ?? String(error);
|
|
49
|
+
throw new Error(`无法连接千问办公 CDP 端口 ${this.options.port}(请先以 --remote-debugging-port=${this.options.port} 启动千问办公客户端): ${code}`);
|
|
50
|
+
}
|
|
44
51
|
if (!response.ok)
|
|
45
52
|
throw new Error(`CDP /json HTTP ${response.status}`);
|
|
46
53
|
const targets = await response.json();
|
|
@@ -28,13 +28,59 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
28
28
|
await new Promise((resolve) => setImmediate(resolve));
|
|
29
29
|
strict_1.default.deepEqual(elements.get("#identities").children.map((row) => row.children[0].textContent), ["new.agentid.cn", "old.agentid.cn", "unknown.agentid.cn", "external.agentid.cn", "offline-order.agentid.cn"]);
|
|
30
30
|
});
|
|
31
|
+
(0, node_test_1.default)("AUN 插件直接从本地 keystore 连接 AID,不调用 EvolCore CLI", async () => {
|
|
32
|
+
const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "aun-local-connect-"));
|
|
33
|
+
const dataDir = (0, node_path_1.join)(root, "state", "aun");
|
|
34
|
+
const aunPath = (0, node_path_1.join)(root, "evolcore");
|
|
35
|
+
const before = process.env.EVOLCORE_HOME;
|
|
36
|
+
const connects = [];
|
|
37
|
+
const subscriptions = [];
|
|
38
|
+
const sdk = {
|
|
39
|
+
AIDStore: class {
|
|
40
|
+
list() { return { ok: true, data: { identities: [{ aid: "existing.agentid.cn" }] } }; }
|
|
41
|
+
load(aid) { return { ok: true, data: { aid } }; }
|
|
42
|
+
close() { }
|
|
43
|
+
},
|
|
44
|
+
AUNClient: class {
|
|
45
|
+
aid;
|
|
46
|
+
constructor(aid) {
|
|
47
|
+
this.aid = aid;
|
|
48
|
+
}
|
|
49
|
+
on() { subscriptions.push(this.aid); return { unsubscribe() { } }; }
|
|
50
|
+
async connect() { connects.push(this.aid); }
|
|
51
|
+
async close() { }
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
const plugin = new aun_1.AunPlugin({ sdk, ingress: { publish: async () => undefined } });
|
|
55
|
+
try {
|
|
56
|
+
process.env.EVOLCORE_HOME = aunPath;
|
|
57
|
+
await plugin.activate({ dataDir, config: {}, logger: { info() { }, warn() { }, error() { } }, callPlugin: async () => ({ text: "" }), pluginStatus: () => "ready", http: { register() { }, unregister() { } } });
|
|
58
|
+
strict_1.default.deepEqual(connects, ["existing.agentid.cn"]);
|
|
59
|
+
strict_1.default.deepEqual(subscriptions, []);
|
|
60
|
+
strict_1.default.deepEqual(await plugin.identity.list(), { evolcore: ["existing.agentid.cn"], muAgentBridge: [], localMuAgentBridge: [] });
|
|
61
|
+
await plugin.deactivate("stop");
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
if (before === undefined)
|
|
65
|
+
delete process.env.EVOLCORE_HOME;
|
|
66
|
+
else
|
|
67
|
+
process.env.EVOLCORE_HOME = before;
|
|
68
|
+
await (0, promises_1.rm)(root, { recursive: true, force: true });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
31
71
|
(0, node_test_1.default)("AUN 设置页及身份接口由插件注册并随停用注销", async () => {
|
|
32
72
|
const root = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "aun-management-"));
|
|
33
73
|
const routes = new Map();
|
|
34
74
|
const sdk = { AIDStore: class {
|
|
75
|
+
list() { return { ok: true, data: { identities: [{ aid: "external.agentid.cn" }] } }; }
|
|
76
|
+
load(aid) { return { ok: true, data: { aid } }; }
|
|
35
77
|
close() { }
|
|
78
|
+
}, AUNClient: class {
|
|
79
|
+
on() { throw new Error("不应订阅 EvolCore 身份"); }
|
|
80
|
+
async connect() { }
|
|
81
|
+
async close() { }
|
|
36
82
|
} };
|
|
37
|
-
const plugin = new aun_1.AunPlugin({ sdk,
|
|
83
|
+
const plugin = new aun_1.AunPlugin({ sdk, ingress: { publish: async () => undefined } });
|
|
38
84
|
try {
|
|
39
85
|
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
86
|
register(route) { routes.set(`${route.method} ${route.path}`, route.handler); return () => routes.delete(`${route.method} ${route.path}`); }, unregister() { },
|
|
@@ -67,10 +113,17 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
67
113
|
const dataDir = (0, node_path_1.join)(root, "aun");
|
|
68
114
|
await (0, promises_1.mkdir)(dataDir);
|
|
69
115
|
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"]));
|
|
116
|
+
const storeIds = ["doubao-lih.agentid.cn", "dshlihui.agentid.cn", "external.agentid.cn"];
|
|
70
117
|
const sdk = { AIDStore: class {
|
|
118
|
+
list() { return { ok: true, data: { identities: storeIds.map((aid) => ({ aid })) } }; }
|
|
119
|
+
load(aid) { return { ok: true, data: { aid } }; }
|
|
71
120
|
close() { }
|
|
121
|
+
}, AUNClient: class {
|
|
122
|
+
on() { return { unsubscribe() { } }; }
|
|
123
|
+
async connect() { }
|
|
124
|
+
async close() { }
|
|
72
125
|
} };
|
|
73
|
-
const plugin = new aun_1.AunPlugin({ sdk,
|
|
126
|
+
const plugin = new aun_1.AunPlugin({ sdk, ingress: { publish: async () => undefined } });
|
|
74
127
|
try {
|
|
75
128
|
await plugin.activate({ dataDir, config: {}, logger: { info() { }, warn() { }, error() { } }, callPlugin: async () => ({ text: "" }), pluginStatus: () => "ready", http: { register() { }, unregister() { } } });
|
|
76
129
|
strict_1.default.deepEqual(await plugin.identity.list(), { evolcore: ["external.agentid.cn"], muAgentBridge: ["doubao-lih.agentid.cn", "dshlihui.agentid.cn"], localMuAgentBridge: [] });
|
|
@@ -84,11 +137,14 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
84
137
|
const calls = [];
|
|
85
138
|
let registration = { ok: true, data: {} };
|
|
86
139
|
let loadOk = true;
|
|
140
|
+
let loadFailAid = "";
|
|
87
141
|
const clients = [];
|
|
88
142
|
const sdk = {
|
|
89
143
|
AIDStore: class {
|
|
90
|
-
|
|
91
|
-
|
|
144
|
+
registered = [];
|
|
145
|
+
async register(input) { calls.push(`register:${input.aid}:${input.owner}`); this.registered.push(input.aid); return registration; }
|
|
146
|
+
load(aid) { return !loadOk || aid === loadFailAid ? { ok: false, error: { message: "本地身份不存在" } } : { ok: true, data: { aid } }; }
|
|
147
|
+
list() { return { ok: true, data: { identities: this.registered.map((aid) => ({ aid })) } }; }
|
|
92
148
|
close() { calls.push("store.close"); }
|
|
93
149
|
},
|
|
94
150
|
AUNClient: class {
|
|
@@ -118,6 +174,7 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
118
174
|
await route.handler(second, response);
|
|
119
175
|
strict_1.default.equal(response.statusCode, 201);
|
|
120
176
|
strict_1.default.equal(clients.length, 2);
|
|
177
|
+
// 本工程身份由 AUN 插件直接关联和收发。
|
|
121
178
|
await plugin.identity.bind("dsh", "bridge.agentid.pub", 26107);
|
|
122
179
|
const boundAt = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(root, "config.json"), "utf8")).binding_times["bridge.agentid.pub"];
|
|
123
180
|
strict_1.default.ok(Number.isFinite(Date.parse(boundAt)));
|
|
@@ -150,6 +207,10 @@ const aun_1 = require("../src-ts/plugins/aun");
|
|
|
150
207
|
registration = { ok: true, data: {} };
|
|
151
208
|
loadOk = false;
|
|
152
209
|
await strict_1.default.rejects(plugin.identity.create("missing.agentid.pub", "owner.agentid.pub"), /本地身份不存在/);
|
|
210
|
+
// 断开的 AID 不能关联。
|
|
211
|
+
loadFailAid = "not-in-store.agentid.cn";
|
|
212
|
+
await strict_1.default.rejects(plugin.identity.bind("dsh", "not-in-store.agentid.cn", 26107), /当前未连接/);
|
|
213
|
+
loadFailAid = "";
|
|
153
214
|
await plugin.deactivate("stop");
|
|
154
215
|
}
|
|
155
216
|
finally {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
10
|
+
const ids = ["abweb", "aun", "doubao", "dsh", "feishu", "qwenwork", "workbuddy"];
|
|
11
|
+
(0, node_test_1.default)("核心插件目录包含全部默认插件及其可加载入口", async () => {
|
|
12
|
+
const packageJson = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(process.cwd(), "package.json"), "utf8"));
|
|
13
|
+
strict_1.default.ok(packageJson.files?.includes("plugins/"));
|
|
14
|
+
for (const id of ids) {
|
|
15
|
+
const directory = (0, node_path_1.join)(process.cwd(), "plugins", id);
|
|
16
|
+
const manifest = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(directory, "plugin.json"), "utf8"));
|
|
17
|
+
strict_1.default.equal(manifest.id, id);
|
|
18
|
+
const packageManifest = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(process.cwd(), "packages", id, "plugin.json"), "utf8"));
|
|
19
|
+
strict_1.default.deepEqual(manifest, packageManifest);
|
|
20
|
+
await (0, promises_1.access)((0, node_path_1.join)(directory, "config.schema.json"));
|
|
21
|
+
await (0, promises_1.access)((0, node_path_1.join)(directory, manifest.entry));
|
|
22
|
+
await strict_1.default.rejects((0, promises_1.access)((0, node_path_1.join)(directory, "package.json")));
|
|
23
|
+
}
|
|
24
|
+
});
|
|
@@ -11,11 +11,17 @@ const promises_1 = require("node:fs/promises");
|
|
|
11
11
|
const node_os_1 = require("node:os");
|
|
12
12
|
const node_path_1 = require("node:path");
|
|
13
13
|
const plugin_manager_1 = require("../src-ts/plugin-manager");
|
|
14
|
-
(0, node_test_1.default)("
|
|
14
|
+
(0, node_test_1.default)("关联 EvolCore AID 时配置相应的 Agent 路由", async () => {
|
|
15
15
|
const calls = [];
|
|
16
|
-
await (0, evolcore_1.configureAidForPlugin)("
|
|
17
|
-
strict_1.default.
|
|
18
|
-
|
|
16
|
+
await (0, evolcore_1.configureAidForPlugin)("dsh", "test.agentid.cn", 26107, async (args) => { calls.push(args); return { ok: true }; });
|
|
17
|
+
strict_1.default.deepEqual(calls.map((args) => args.slice(0, 4)), [
|
|
18
|
+
["agent", "set", "test.agentid.cn", "baseagents.ecagent.baseUrl"],
|
|
19
|
+
["agent", "set", "test.agentid.cn", "baseagents.ecagent.apiKey"],
|
|
20
|
+
["agent", "set", "test.agentid.cn", "baseagents.ecagent.model"],
|
|
21
|
+
["agent", "set", "test.agentid.cn", "active_baseagent"],
|
|
22
|
+
["agent", "reload", "test.agentid.cn", "--format"],
|
|
23
|
+
]);
|
|
24
|
+
strict_1.default.equal(calls[0][4], "http://127.0.0.1:26107/dsh/v1");
|
|
19
25
|
});
|
|
20
26
|
(0, node_test_1.default)("通用 Agent 路由调用插件且关联失败进入日志", async () => {
|
|
21
27
|
const logs = [];
|
|
@@ -114,51 +120,6 @@ const plugin_manager_1 = require("../src-ts/plugin-manager");
|
|
|
114
120
|
await (0, promises_1.rm)(root, { recursive: true, force: true });
|
|
115
121
|
}
|
|
116
122
|
});
|
|
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
123
|
(0, node_test_1.default)("creating an AID requires both identity and owner AID", async () => {
|
|
163
124
|
const manager = { list: () => [] };
|
|
164
125
|
const server = new control_server_1.ControlServer({ manager, host: "127.0.0.1", port: 0 });
|
|
@@ -287,3 +248,17 @@ const plugin_manager_1 = require("../src-ts/plugin-manager");
|
|
|
287
248
|
await server.stop();
|
|
288
249
|
}
|
|
289
250
|
});
|
|
251
|
+
(0, node_test_1.default)("根路径 302 跳转到 abweb 管理页面", async () => {
|
|
252
|
+
const manager = { list: () => [], dispatchHttp: async () => false };
|
|
253
|
+
const server = new control_server_1.ControlServer({ manager, host: "127.0.0.1", port: 0 });
|
|
254
|
+
const address = await server.start();
|
|
255
|
+
try {
|
|
256
|
+
const response = await fetch(`http://127.0.0.1:${address.port}/`, { redirect: "manual" });
|
|
257
|
+
strict_1.default.equal(response.status, 302);
|
|
258
|
+
strict_1.default.equal(response.headers.get("location"), "/abweb/");
|
|
259
|
+
strict_1.default.equal((await fetch(`http://127.0.0.1:${address.port}/api/health`)).status, 200);
|
|
260
|
+
}
|
|
261
|
+
finally {
|
|
262
|
+
await server.stop();
|
|
263
|
+
}
|
|
264
|
+
});
|