chore: retire openhub and pi ts runtime

This commit is contained in:
Agent Board
2026-07-12 14:18:26 +08:00
parent 62959b0c4d
commit 2f5902e3e7
45 changed files with 367 additions and 925 deletions
+104 -44
View File
@@ -97,8 +97,8 @@ async function main() {
const openHubLink = page.locator('a[href="/page-ai/openhub/admin"]');
assert(
await openHubLink.count() >= 1,
"OpenHub Admin 独立入口必须保留",
await openHubLink.count() === 0,
"OpenHub Admin 独立入口必须从当前 AI 管理页移除",
);
await page.getByRole("link", { name: "模型配置" }).click();
@@ -122,27 +122,37 @@ async function main() {
await page.getByRole("button", { name: "保存策略" }).click();
await page.locator("[data-ai-admin-tools-save-status]").filter({ hasText: /已保存/ }).waitFor();
await page.getByRole("link", { name: "技能 / MCP" }).click();
await page.getByRole("link", { name: "Skills" }).click();
await page.locator("#ai-admin-skills.is-active").waitFor();
await page.getByRole("button", { name: "+ 添加 Skill" }).click();
const skillRow = page.locator(".mnote-ai-admin-skill-row").last();
await skillRow.locator('[name="skillName"]').fill(skillName);
await skillRow.locator('[name="skillDescription"]').fill("浏览器验收技能");
await skillRow.locator('[name="skillEnabled"]').check();
const skillsPanel = page.locator("#ai-admin-skills");
await skillsPanel.getByRole("button", { name: "保存 Skills" }).click();
await assertEventually(
async () => (await skillsPanel.locator("[data-ai-admin-skills-save-status]").textContent()) || "",
(text) => text.includes("已保存"),
"Skills 配置保存状态未变为已保存",
);
await page.getByRole("link", { name: "MCP" }).click();
await page.locator("#ai-admin-mcp.is-active").waitFor();
await page.getByRole("button", { name: "+ 添加 MCP" }).click();
const mcpRow = page.locator("[data-mcp-idx]").last();
await mcpRow.locator("summary").click();
await mcpRow.locator('[name="mcpName"]').fill(mcpName);
await mcpRow.locator('[name="mcpTransport"]').selectOption("stdio");
await mcpRow.locator('[name="mcpCommand"]').fill("scripts/lightrag-native-mcp.sh");
await mcpRow.locator('[name="mcpSecretRefs"]').fill("env://LIGHTRAG_API_KEY");
await mcpRow.locator('[name="mcpEnabled"]').check();
const skillsPanel = page.locator("#ai-admin-skills");
await skillsPanel.getByRole("button", { name: "保存配置" }).click();
const mcpPanel = page.locator("#ai-admin-mcp");
await mcpPanel.getByRole("button", { name: "保存 MCP" }).click();
await assertEventually(
async () => (await skillsPanel.locator("[data-ai-admin-skills-save-status]").textContent()) || "",
async () => (await mcpPanel.locator("[data-ai-admin-mcp-save-status]").textContent()) || "",
(text) => text.includes("已保存"),
"技能/MCP 配置保存状态未变为已保存",
"MCP 配置保存状态未变为已保存",
);
await page.screenshot({
path: path.join(OUTPUT_DIR, "skills-mcp.png"),
@@ -155,19 +165,55 @@ async function main() {
await targetUser.waitFor();
await targetUser.click();
await page.locator('[data-ai-admin-user-settings] h3', { hasText: "ai-user" }).waitFor();
await page.locator('[data-user-model="omniroute/freefirst-fast"]').evaluate((input) => {
input.checked = false;
input.dispatchEvent(new Event("change", { bubbles: true }));
const disabledModelId = await page.locator("[data-user-model]").evaluateAll((inputs) => {
const checked = inputs
.filter((input) => input.checked)
.map((input) => input.getAttribute("data-user-model") || "")
.filter(Boolean);
return checked.length > 1 ? (checked.find((id) => id !== "omniroute/freefirst") || checked[1]) : "";
});
await page.locator('[data-action="save-user-settings"]').click();
await page.locator("[data-ai-admin-user-save-status]").filter({ hasText: /已保存/ }).waitFor();
if (disabledModelId) {
await page.locator(`[data-user-model="${disabledModelId}"]`).evaluate((input) => {
input.checked = false;
input.dispatchEvent(new Event("change", { bubbles: true }));
});
const saveModelOverride = await Promise.all([
page.waitForResponse((response) =>
response.url().includes("/api/ai-admin/users/ai-user/settings") &&
response.request().method() === "PUT"
),
page.locator('[data-action="save-user-settings"]').click(),
]).then(([response]) => response);
assert(
saveModelOverride.ok(),
`模型降权保存失败: ${saveModelOverride.status()} ${await saveModelOverride.text()}`,
);
}
await page.locator('[data-user-tab="skills"]').click();
await page.locator(`[data-user-skill="${skillName}"]`).evaluate((input) => {
input.checked = false;
input.dispatchEvent(new Event("change", { bubbles: true }));
const disabledSkillId = await page.locator("[data-user-skill]").evaluateAll((inputs) => {
const checked = inputs
.filter((input) => input.checked)
.map((input) => input.getAttribute("data-user-skill") || "")
.filter(Boolean);
return checked[0] || "";
});
await page.locator('[data-action="save-user-settings"]').click();
await page.locator("[data-ai-admin-user-save-status]").filter({ hasText: /已保存/ }).waitFor();
if (disabledSkillId) {
await page.locator(`[data-user-skill="${disabledSkillId}"]`).evaluate((input) => {
input.checked = false;
input.dispatchEvent(new Event("change", { bubbles: true }));
});
const saveSkillOverride = await Promise.all([
page.waitForResponse((response) =>
response.url().includes("/api/ai-admin/users/ai-user/settings") &&
response.request().method() === "PUT"
),
page.locator('[data-action="save-user-settings"]').click(),
]).then(([response]) => response);
assert(
saveSkillOverride.ok(),
`Skill 降权保存失败: ${saveSkillOverride.status()} ${await saveSkillOverride.text()}`,
);
}
await page.screenshot({
path: path.join(OUTPUT_DIR, "users.png"),
fullPage: false,
@@ -178,17 +224,23 @@ async function main() {
const drawer = document.querySelector("[data-ai-admin-user-drawer]");
return !drawer || !drawer.classList.contains("is-open");
});
await page.getByRole("link", { name: "技能 / MCP" }).click();
await page.getByRole("link", { name: "Skills" }).click();
await page.reload({ waitUntil: "commit" });
await page.locator("#ai-admin-skills.is-active").waitFor();
assert.equal(
await page.locator(`[name="skillName"][value="${skillName}"]`).count(),
1,
await assertEventually(
async () => page.locator('[name="skillName"]').evaluateAll((inputs) =>
inputs.map((input) => input.value || ""),
),
(values) => values.includes(skillName),
"Skill 保存后刷新必须仍存在",
);
assert.equal(
await page.locator(`[name="mcpName"][value="${mcpName}"]`).count(),
1,
await page.getByRole("link", { name: "MCP" }).click();
await page.locator("#ai-admin-mcp.is-active").waitFor();
await assertEventually(
async () => page.locator('[name="mcpName"]').evaluateAll((inputs) =>
inputs.map((input) => input.value || ""),
),
(values) => values.includes(mcpName),
"MCP 保存后刷新必须仍存在",
);
@@ -213,16 +265,20 @@ async function main() {
const response = await fetch("/api/ai-admin/users/ai-user/settings", { credentials: "include" });
return response.json();
});
assert.equal(
(userSettings.allowedModels || []).some((model) => model.id === "omniroute/freefirst-fast"),
false,
"ai-user 刷新后不应包含被禁用模型",
);
assert.equal(
(userSettings.skills || []).find((skill) => skill.id === skillName)?.enabled,
false,
"ai-user 刷新后应保留 Skill 禁用覆盖",
);
if (disabledModelId) {
assert.equal(
(userSettings.allowedModels || []).some((model) => model.id === disabledModelId),
false,
`ai-user 刷新后不应包含被禁用模型 ${disabledModelId}`,
);
}
if (disabledSkillId) {
assert.equal(
(userSettings.skills || []).find((skill) => skill.id === disabledSkillId)?.enabled,
false,
`ai-user 刷新后应保留 Skill 禁用覆盖 ${disabledSkillId}`,
);
}
const userContext = await browser.newContext({ viewport: { width: 1280, height: 800 } });
const userResponse = await userContext.request.post(`${BASE}/api/auth`, {
@@ -244,16 +300,20 @@ async function main() {
const userEffectiveResponse = await userContext.request.get(`${BASE}/api/ai-settings/effective`);
assert(userEffectiveResponse.ok(), `ai-user effective 读取失败: ${userEffectiveResponse.status()}`);
const userEffective = await userEffectiveResponse.json();
assert.equal(
(userEffective.models || []).some((model) => model.id === "omniroute/freefirst-fast"),
false,
"ai-user effective 不应包含被管理员取消的模型",
);
assert.equal(
(userEffective.skills || []).some((skill) => skill.name === skillName),
false,
"ai-user effective 不应包含被禁用 Skill",
);
if (disabledModelId) {
assert.equal(
(userEffective.models || []).some((model) => model.id === disabledModelId),
false,
`ai-user effective 不应包含被管理员取消的模型 ${disabledModelId}`,
);
}
if (disabledSkillId) {
assert.equal(
(userEffective.skills || []).some((skill) => skill.id === disabledSkillId || skill.name === disabledSkillId),
false,
`ai-user effective 不应包含被禁用 Skill ${disabledSkillId}`,
);
}
await userContext.close();
console.log(JSON.stringify({