feat: expose master agent evolution dashboard
This commit is contained in:
@@ -34,6 +34,7 @@ test("master agent settings pages refresh when master agent config changes", asy
|
||||
for (const relativePath of [
|
||||
"src/app/me/master-agent/page.tsx",
|
||||
"src/app/me/master-agent/takeover/page.tsx",
|
||||
"src/app/me/master-agent/evolution/page.tsx",
|
||||
]) {
|
||||
const source = await readSource(relativePath);
|
||||
assert.match(source, /import \{ RealtimeRefresh \}/, `expected ${relativePath} to import RealtimeRefresh`);
|
||||
@@ -45,3 +46,9 @@ test("master agent settings pages refresh when master agent config changes", asy
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("me page exposes master agent evolution entry", async () => {
|
||||
const source = await readSource("src/app/me/page.tsx");
|
||||
assert.match(source, /href="\/me\/master-agent\/evolution"/, "expected me page to link evolution page");
|
||||
assert.match(source, /title="主 Agent 自动进化"/, "expected me page to show evolution menu title");
|
||||
});
|
||||
|
||||
@@ -2,18 +2,19 @@ import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { getMasterAgentChatMenuItems } from "../src/lib/master-agent-chat-menu";
|
||||
|
||||
test("master-agent 聊天页菜单包含全局接管、提示词、模型、推理强度、记忆和刷新", () => {
|
||||
test("master-agent 聊天页菜单包含全局接管、进化、提示词、模型、推理强度、记忆和刷新", () => {
|
||||
const items = getMasterAgentChatMenuItems("master-agent");
|
||||
assert.deepEqual(
|
||||
items.map((item) => item.key),
|
||||
["model", "reasoning_effort", "takeover", "prompt", "memory", "refresh"],
|
||||
["model", "reasoning_effort", "takeover", "evolution", "prompt", "memory", "refresh"],
|
||||
);
|
||||
assert.equal(items[0]?.href, "/me/master-agent#model-section");
|
||||
assert.equal(items[1]?.href, "/me/master-agent#reasoning-effort-section");
|
||||
assert.equal(items[2]?.href, "/me/master-agent/takeover");
|
||||
assert.equal(items[3]?.href, "/me/master-agent#prompt-section");
|
||||
assert.equal(items[4]?.href, "/me/master-agent#memory-section");
|
||||
assert.equal(items[5]?.action, "refresh");
|
||||
assert.equal(items[3]?.href, "/me/master-agent/evolution");
|
||||
assert.equal(items[4]?.href, "/me/master-agent#prompt-section");
|
||||
assert.equal(items[5]?.href, "/me/master-agent#memory-section");
|
||||
assert.equal(items[6]?.action, "refresh");
|
||||
});
|
||||
|
||||
test("普通会话不返回主 Agent 专属菜单", () => {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { mkdir, mkdtemp, rm } from "node:fs/promises";
|
||||
|
||||
let runtimeRoot = "";
|
||||
let readState: (typeof import("../src/lib/boss-data"))["readState"];
|
||||
let getProjectAgentControls: (typeof import("../src/lib/boss-data"))["getProjectAgentControls"];
|
||||
let recordMasterAgentEvolutionSignal: (typeof import("../src/lib/master-agent-evolution"))["recordMasterAgentEvolutionSignal"];
|
||||
let listMasterAgentEvolutionProposals: (typeof import("../src/lib/master-agent-evolution"))["listMasterAgentEvolutionProposals"];
|
||||
let setMasterAgentEvolutionMode: (typeof import("../src/lib/master-agent-evolution"))["setMasterAgentEvolutionMode"];
|
||||
@@ -22,6 +23,7 @@ async function setup() {
|
||||
import("../src/lib/master-agent-evolution.ts"),
|
||||
]);
|
||||
readState = data.readState;
|
||||
getProjectAgentControls = data.getProjectAgentControls;
|
||||
recordMasterAgentEvolutionSignal = evolution.recordMasterAgentEvolutionSignal;
|
||||
listMasterAgentEvolutionProposals = evolution.listMasterAgentEvolutionProposals;
|
||||
setMasterAgentEvolutionMode = evolution.setMasterAgentEvolutionMode;
|
||||
@@ -73,3 +75,25 @@ test("autonomous mode auto applies low risk fast path proposals as evolution rul
|
||||
assert.equal(state.masterAgentEvolutionRules.length, 1);
|
||||
assert.equal(state.masterAgentEvolutionRules[0]?.ruleType, "fast_path_rule");
|
||||
});
|
||||
|
||||
test("autonomous mode auto applies backend fallback proposals into master-agent backend override", async () => {
|
||||
await setMasterAgentEvolutionMode("autonomous");
|
||||
|
||||
const result = await recordMasterAgentEvolutionSignal({
|
||||
kind: "backend_fallback",
|
||||
projectId: "master-agent",
|
||||
account: "17600003315",
|
||||
requestText: "Hermes 不可用时自动回退到 Claw",
|
||||
metadataJson: {
|
||||
failedBackendId: "hermes-runtime",
|
||||
fallbackToBackendId: "claw-runtime",
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.proposal?.status, "auto_applied");
|
||||
const state = await readState();
|
||||
const controls = await getProjectAgentControls("master-agent", "17600003315");
|
||||
assert.equal(state.masterAgentEvolutionRules.length, 1);
|
||||
assert.equal(state.masterAgentEvolutionRules[0]?.ruleType, "routing_preference_patch");
|
||||
assert.equal(controls?.backendOverride ?? null, "claw-runtime");
|
||||
});
|
||||
|
||||
@@ -359,6 +359,43 @@ test("master-agent 查询当前后端时直接走 fast path 返回后端摘要",
|
||||
assert.equal(reply?.senderLabel ?? "", "主Agent·gpt-5.4");
|
||||
});
|
||||
|
||||
test("master-agent 重复追问状态类问题时会记录 repeated_question 进化信号", async () => {
|
||||
await saveAiAccount({
|
||||
accountId: "openai-repeat-status",
|
||||
label: "OpenAI 主模型",
|
||||
role: "primary",
|
||||
provider: "openai_api",
|
||||
displayName: "OpenAI 主模型",
|
||||
model: "gpt-5.4",
|
||||
apiKey: "sk-openai-repeat-status",
|
||||
enabled: true,
|
||||
setActive: true,
|
||||
loginStatusNote: "用于重复状态问题测试。",
|
||||
});
|
||||
|
||||
const firstResponse = await POST(
|
||||
await createAuthedRequest("master-agent", {
|
||||
body: "当前主节点在线吗",
|
||||
}),
|
||||
{ params: Promise.resolve({ projectId: "master-agent" }) },
|
||||
);
|
||||
assert.equal(firstResponse.status, 200);
|
||||
|
||||
const secondResponse = await POST(
|
||||
await createAuthedRequest("master-agent", {
|
||||
body: "现在主节点在线吗",
|
||||
}),
|
||||
{ params: Promise.resolve({ projectId: "master-agent" }) },
|
||||
);
|
||||
assert.equal(secondResponse.status, 200);
|
||||
|
||||
const state = await readState();
|
||||
assert.ok(
|
||||
state.masterAgentEvolutionSignals.some((signal) => signal.kind === "repeated_question"),
|
||||
"expected at least one repeated_question signal",
|
||||
);
|
||||
});
|
||||
|
||||
test("master-agent 查询全局接管状态时直接走 fast path 返回当前状态", async () => {
|
||||
await saveAiAccount({
|
||||
accountId: "openai-takeover-status",
|
||||
|
||||
Reference in New Issue
Block a user