Files
boss/tests/master-agent-chat-controls.test.ts

958 lines
33 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import os from "node:os";
import path from "node:path";
import { mkdtemp, rm, writeFile } from "node:fs/promises";
import { execFile as execFileCallback } from "node:child_process";
import { promisify } from "node:util";
import { NextRequest } from "next/server";
let runtimeRoot = "";
let readState: (typeof import("../src/lib/boss-data"))["readState"];
let writeState: (typeof import("../src/lib/boss-data"))["writeState"];
let updateProjectAgentControls: (typeof import("../src/lib/boss-data"))["updateProjectAgentControls"];
let getProjectAgentControls: (typeof import("../src/lib/boss-data"))["getProjectAgentControls"];
let getProjectDetailView: (typeof import("../src/lib/boss-projections"))["getProjectDetailView"];
let getProjectRoute: (typeof import("../src/app/api/v1/projects/[projectId]/route"))["GET"];
let getAgentControlsRoute: (typeof import("../src/app/api/v1/projects/[projectId]/agent-controls/route"))["GET"];
let postAgentControlsRoute: (typeof import("../src/app/api/v1/projects/[projectId]/agent-controls/route"))["POST"];
let createAuthSession: (typeof import("../src/lib/boss-data"))["createAuthSession"];
let AUTH_SESSION_COOKIE = "";
const execFile = promisify(execFileCallback);
async function setup() {
if (runtimeRoot) return;
runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-master-agent-controls-"));
process.env.BOSS_RUNTIME_ROOT = runtimeRoot;
process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json");
const [data, projections, projectRouteModule, agentControlsRouteModule, auth] = await Promise.all([
import("../src/lib/boss-data.ts"),
import("../src/lib/boss-projections.ts"),
import("../src/app/api/v1/projects/[projectId]/route.ts"),
import("../src/app/api/v1/projects/[projectId]/agent-controls/route.ts"),
import("../src/lib/boss-auth.ts"),
]);
readState = data.readState;
writeState = data.writeState;
updateProjectAgentControls = data.updateProjectAgentControls;
getProjectAgentControls = data.getProjectAgentControls;
getProjectDetailView = projections.getProjectDetailView;
getProjectRoute = projectRouteModule.GET;
getAgentControlsRoute = agentControlsRouteModule.GET;
postAgentControlsRoute = agentControlsRouteModule.POST;
createAuthSession = data.createAuthSession;
AUTH_SESSION_COOKIE = auth.AUTH_SESSION_COOKIE;
}
async function resetMasterAgentControls() {
await setup();
const state = await readState();
const project = state.projects.find((item) => item.id === "master-agent");
assert.ok(project, "expected seeded master-agent project");
delete project.agentControls;
state.userProjectAgentControls = state.userProjectAgentControls.filter(
(item) => item.projectId !== "master-agent",
);
await writeState(state);
}
test.beforeEach(async () => {
await resetMasterAgentControls();
});
test.after(async () => {
if (runtimeRoot) {
await rm(runtimeRoot, { recursive: true, force: true });
}
});
test("master-agent 会话可保存并读取模型与推理强度覆盖", async () => {
await setup();
await updateProjectAgentControls("master-agent", {
modelOverride: "gpt-5.4",
reasoningEffortOverride: "high",
});
const controls = await getProjectAgentControls("master-agent");
assert.equal(controls?.modelOverride, "gpt-5.4");
assert.equal(controls?.reasoningEffortOverride, "high");
const state = await readState();
const project = state.projects.find((item) => item.id === "master-agent");
assert.equal(project?.agentControls?.modelOverride, "gpt-5.4");
assert.equal(project?.agentControls?.reasoningEffortOverride, "high");
const detail = getProjectDetailView(state, "master-agent");
assert.equal(detail?.agentControls?.modelOverride, "gpt-5.4");
assert.equal(detail?.agentControls?.reasoningEffortOverride, "high");
});
test("master-agent 对话控制路由可读写并回显到项目详情", async () => {
await setup();
const tempDir = await mkdtemp(path.join(os.tmpdir(), "boss-claw-agent-controls-"));
const scriptPath = path.join(tempDir, "claw-runtime.mjs");
await writeFile(scriptPath, "console.log('ok');\n", "utf8");
const previousEnv = {
BOSS_CLAW_ENABLED: process.env.BOSS_CLAW_ENABLED,
BOSS_CLAW_COMMAND: process.env.BOSS_CLAW_COMMAND,
BOSS_CLAW_ARGS: process.env.BOSS_CLAW_ARGS,
BOSS_CLAW_WORKDIR: process.env.BOSS_CLAW_WORKDIR,
};
process.env.BOSS_CLAW_ENABLED = "true";
process.env.BOSS_CLAW_COMMAND = process.execPath;
process.env.BOSS_CLAW_ARGS = scriptPath;
process.env.BOSS_CLAW_WORKDIR = tempDir;
try {
const session = await createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
const headers = {
"content-type": "application/json",
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
};
const postResponse = await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers,
body: JSON.stringify({
modelOverride: "gpt-5.4",
reasoningEffortOverride: "medium",
backendOverride: "claw-runtime",
}),
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(postResponse.status, 200);
const postPayload = (await postResponse.json()) as {
ok: boolean;
controls: {
modelOverride?: string;
reasoningEffortOverride?: string;
backendOverride?: string;
updatedAt: string;
} | null;
};
assert.equal(postPayload.ok, true);
assert.equal(postPayload.controls?.modelOverride, "gpt-5.4");
assert.equal(postPayload.controls?.reasoningEffortOverride, "medium");
assert.equal(postPayload.controls?.backendOverride, "claw-runtime");
const getResponse = await getAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "GET",
headers,
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(getResponse.status, 200);
const getPayload = (await getResponse.json()) as {
ok: boolean;
controls: {
modelOverride?: string;
reasoningEffortOverride?: string;
backendOverride?: string;
updatedAt: string;
} | null;
};
assert.equal(getPayload.ok, true);
assert.equal(getPayload.controls?.modelOverride, "gpt-5.4");
assert.equal(getPayload.controls?.reasoningEffortOverride, "medium");
assert.equal(getPayload.controls?.backendOverride, "claw-runtime");
const projectResponse = await getProjectRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent", {
method: "GET",
headers,
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(projectResponse.status, 200);
const projectPayload = (await projectResponse.json()) as {
ok: boolean;
agentControls: {
modelOverride?: string;
reasoningEffortOverride?: string;
backendOverride?: string;
updatedAt: string;
} | null;
};
assert.equal(projectPayload.ok, true);
assert.equal(projectPayload.agentControls?.modelOverride, "gpt-5.4");
assert.equal(projectPayload.agentControls?.reasoningEffortOverride, "medium");
assert.equal(projectPayload.agentControls?.backendOverride, "claw-runtime");
} finally {
if (previousEnv.BOSS_CLAW_ENABLED === undefined) delete process.env.BOSS_CLAW_ENABLED;
else process.env.BOSS_CLAW_ENABLED = previousEnv.BOSS_CLAW_ENABLED;
if (previousEnv.BOSS_CLAW_COMMAND === undefined) delete process.env.BOSS_CLAW_COMMAND;
else process.env.BOSS_CLAW_COMMAND = previousEnv.BOSS_CLAW_COMMAND;
if (previousEnv.BOSS_CLAW_ARGS === undefined) delete process.env.BOSS_CLAW_ARGS;
else process.env.BOSS_CLAW_ARGS = previousEnv.BOSS_CLAW_ARGS;
if (previousEnv.BOSS_CLAW_WORKDIR === undefined) delete process.env.BOSS_CLAW_WORKDIR;
else process.env.BOSS_CLAW_WORKDIR = previousEnv.BOSS_CLAW_WORKDIR;
await rm(tempDir, { recursive: true, force: true });
}
});
test("master-agent 对话控制按当前账号隔离,不会串到其他用户", async () => {
await setup();
const adminSession = await createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
const memberSession = await createAuthSession({
account: "18800001111",
role: "member",
displayName: "普通成员",
loginMethod: "password",
});
const adminHeaders = {
"content-type": "application/json",
cookie: `${AUTH_SESSION_COOKIE}=${adminSession.sessionToken}`,
};
const memberHeaders = {
"content-type": "application/json",
cookie: `${AUTH_SESSION_COOKIE}=${memberSession.sessionToken}`,
};
await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers: adminHeaders,
body: JSON.stringify({
modelOverride: "gpt-5.4",
reasoningEffortOverride: "high",
}),
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
const adminGet = await getAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "GET",
headers: adminHeaders,
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
const memberGet = await getAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "GET",
headers: memberHeaders,
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
const adminPayload = (await adminGet.json()) as { controls: { modelOverride?: string; reasoningEffortOverride?: string } | null };
const memberPayload = (await memberGet.json()) as { controls: { modelOverride?: string; reasoningEffortOverride?: string } | null };
assert.equal(adminPayload.controls?.modelOverride, "gpt-5.4");
assert.equal(adminPayload.controls?.reasoningEffortOverride, "high");
assert.equal(memberPayload.controls, null);
});
test("master-agent 对话控制路由单字段更新不会清掉另一字段", async () => {
await setup();
const session = await createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
const headers = {
"content-type": "application/json",
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
};
await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers,
body: JSON.stringify({
modelOverride: "gpt-5.4",
reasoningEffortOverride: "high",
}),
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
const response = await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers,
body: JSON.stringify({
reasoningEffortOverride: "low",
}),
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
controls: {
modelOverride?: string;
reasoningEffortOverride?: string;
} | null;
};
assert.equal(payload.ok, true);
assert.equal(payload.controls?.modelOverride, "gpt-5.4");
assert.equal(payload.controls?.reasoningEffortOverride, "low");
});
test("master-agent 对话控制 POST 清空后仍稳定回传 controls null", async () => {
await setup();
const session = await createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
const headers = {
"content-type": "application/json",
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
};
await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers,
body: JSON.stringify({
modelOverride: "gpt-5.4",
reasoningEffortOverride: "high",
}),
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
const clearResponse = await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers,
body: JSON.stringify({
modelOverride: null,
reasoningEffortOverride: null,
}),
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(clearResponse.status, 200);
const clearPayload = (await clearResponse.json()) as {
ok: boolean;
controls: unknown;
};
assert.equal(clearPayload.ok, true);
assert.equal(Object.prototype.hasOwnProperty.call(clearPayload, "controls"), true);
assert.equal(clearPayload.controls, null);
});
test("非 master-agent 项目详情不应回传 agentControls 字段", async () => {
await setup();
const session = await createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
const response = await getProjectRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/boss-console", {
method: "GET",
headers: {
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
},
}),
{ params: Promise.resolve({ projectId: "boss-console" }) },
);
assert.equal(response.status, 200);
const payload = (await response.json()) as Record<string, unknown>;
assert.equal(payload.ok, true);
assert.equal(Object.prototype.hasOwnProperty.call(payload, "agentControls"), false);
});
test("master-agent 对话控制 POST 允许当前用户修改自己的 master-agent 会话配置", async () => {
await setup();
const session = await createAuthSession({
account: "viewer-0001",
role: "member",
displayName: "普通成员",
loginMethod: "password",
});
const response = await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers: {
"content-type": "application/json",
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
},
body: JSON.stringify({
modelOverride: "gpt-5.4",
reasoningEffortOverride: "low",
}),
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
controls: { modelOverride?: string; reasoningEffortOverride?: string } | null;
};
assert.equal(payload.ok, true);
assert.equal(payload.controls?.modelOverride, "gpt-5.4");
assert.equal(payload.controls?.reasoningEffortOverride, "low");
const controls = await getProjectAgentControls("master-agent", "viewer-0001");
assert.equal(controls?.modelOverride, "gpt-5.4");
assert.equal(controls?.reasoningEffortOverride, "low");
});
test("master-agent 对话控制 POST 会稳定拒绝非法 modelOverride", async () => {
await setup();
const session = await createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
const response = await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers: {
"content-type": "application/json",
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
},
body: JSON.stringify({
modelOverride: 123,
}),
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(response.status, 400);
const payload = (await response.json()) as { ok: boolean; message: string };
assert.equal(payload.ok, false);
assert.equal(payload.message, "INVALID_MODEL_OVERRIDE");
const controls = await getProjectAgentControls("master-agent");
assert.equal(controls, null);
});
test("master-agent 对话控制 POST 会稳定拒绝 malformed JSON 和空对象", async () => {
await setup();
const session = await createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
const headers = {
"content-type": "application/json",
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
};
const beforeState = await readState();
const beforeProject = beforeState.projects.find((item) => item.id === "master-agent");
assert.ok(beforeProject, "expected seeded master-agent project");
const beforeUpdatedAt = beforeProject.updatedAt;
const beforeThreadMetaUpdatedAt = beforeProject.threadMeta.updatedAt;
const malformedResponse = await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers,
body: "{",
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(malformedResponse.status, 400);
assert.equal((await malformedResponse.json()).message, "INVALID_JSON_PAYLOAD");
const emptyObjectResponse = await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers,
body: JSON.stringify({}),
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(emptyObjectResponse.status, 400);
assert.equal((await emptyObjectResponse.json()).message, "INVALID_AGENT_CONTROLS_PAYLOAD");
const nullResponse = await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers,
body: "null",
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(nullResponse.status, 400);
assert.equal((await nullResponse.json()).message, "INVALID_AGENT_CONTROLS_PAYLOAD");
const arrayResponse = await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers,
body: "[]",
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(arrayResponse.status, 400);
assert.equal((await arrayResponse.json()).message, "INVALID_AGENT_CONTROLS_PAYLOAD");
const primitiveResponse = await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers,
body: "1",
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(primitiveResponse.status, 400);
assert.equal((await primitiveResponse.json()).message, "INVALID_AGENT_CONTROLS_PAYLOAD");
const controls = await getProjectAgentControls("master-agent");
assert.equal(controls, null);
const state = await readState();
const project = state.projects.find((item) => item.id === "master-agent");
assert.equal(project?.agentControls, undefined);
assert.equal(project?.updatedAt, beforeUpdatedAt);
assert.equal(project?.threadMeta.updatedAt, beforeThreadMetaUpdatedAt);
});
test("master-agent 对话控制 helper 会安全忽略非法 modelOverride 输入", async () => {
await setup();
await updateProjectAgentControls("master-agent", {
modelOverride: "gpt-5.4",
reasoningEffortOverride: "high",
});
const beforeState = await readState();
const beforeProject = beforeState.projects.find((item) => item.id === "master-agent");
assert.ok(beforeProject, "expected seeded master-agent project");
const beforeUpdatedAt = beforeProject.updatedAt;
const beforeThreadMetaUpdatedAt = beforeProject.threadMeta.updatedAt;
await assert.rejects(
() =>
updateProjectAgentControls("master-agent", {
modelOverride: { bad: true } as never,
reasoningEffortOverride: "medium",
}),
/INVALID_MODEL_OVERRIDE/,
);
const controls = await getProjectAgentControls("master-agent");
assert.equal(controls?.modelOverride, "gpt-5.4");
assert.equal(controls?.reasoningEffortOverride, "high");
const afterState = await readState();
const afterProject = afterState.projects.find((item) => item.id === "master-agent");
assert.equal(afterProject?.updatedAt, beforeUpdatedAt);
assert.equal(afterProject?.threadMeta.updatedAt, beforeThreadMetaUpdatedAt);
});
test("master-agent 对话控制 helper 重复提交或重复清空不应刷新更新时间", async () => {
await setup();
await updateProjectAgentControls("master-agent", {
modelOverride: "gpt-5.4",
reasoningEffortOverride: "high",
});
const beforeRepeatState = await readState();
const beforeRepeatProject = beforeRepeatState.projects.find((item) => item.id === "master-agent");
assert.ok(beforeRepeatProject, "expected seeded master-agent project");
const beforeRepeatUpdatedAt = beforeRepeatProject.updatedAt;
const beforeRepeatThreadMetaUpdatedAt = beforeRepeatProject.threadMeta.updatedAt;
await updateProjectAgentControls("master-agent", {
modelOverride: "gpt-5.4",
reasoningEffortOverride: "high",
});
const afterRepeatState = await readState();
const afterRepeatProject = afterRepeatState.projects.find((item) => item.id === "master-agent");
assert.equal(afterRepeatProject?.updatedAt, beforeRepeatUpdatedAt);
assert.equal(afterRepeatProject?.threadMeta.updatedAt, beforeRepeatThreadMetaUpdatedAt);
await updateProjectAgentControls("master-agent", {
modelOverride: undefined,
reasoningEffortOverride: undefined,
});
const afterClearState = await readState();
const afterClearProject = afterClearState.projects.find((item) => item.id === "master-agent");
const clearedUpdatedAt = afterClearProject?.updatedAt;
const clearedThreadMetaUpdatedAt = afterClearProject?.threadMeta.updatedAt;
await updateProjectAgentControls("master-agent", {
modelOverride: undefined,
reasoningEffortOverride: undefined,
});
const afterRepeatClearState = await readState();
const afterRepeatClearProject = afterRepeatClearState.projects.find((item) => item.id === "master-agent");
assert.equal(afterRepeatClearProject?.updatedAt, clearedUpdatedAt);
assert.equal(afterRepeatClearProject?.threadMeta.updatedAt, clearedThreadMetaUpdatedAt);
assert.equal(await getProjectAgentControls("master-agent"), null);
});
test("master-agent 对话控制 helper 单字段更新不会清掉另一字段", async () => {
await setup();
await updateProjectAgentControls("master-agent", {
modelOverride: "gpt-5.4",
reasoningEffortOverride: "high",
});
await updateProjectAgentControls("master-agent", {
reasoningEffortOverride: "low",
});
const controls = await getProjectAgentControls("master-agent");
assert.equal(controls?.modelOverride, "gpt-5.4");
assert.equal(controls?.reasoningEffortOverride, "low");
});
test("master-agent 对话控制可清空为未覆盖状态", async () => {
await setup();
await updateProjectAgentControls("master-agent", {
modelOverride: "gpt-5.4",
reasoningEffortOverride: "high",
});
await updateProjectAgentControls("master-agent", {
modelOverride: undefined,
reasoningEffortOverride: undefined,
});
const controls = await getProjectAgentControls("master-agent");
assert.equal(controls, null);
const state = await readState();
const project = state.projects.find((item) => item.id === "master-agent");
assert.equal(project?.agentControls, undefined);
const detail = getProjectDetailView(state, "master-agent");
assert.equal(detail?.agentControls, null);
});
test("GET /agent-controls returns 404 for missing project", async () => {
await setup();
const session = await createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
const response = await getAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/missing-project/agent-controls", {
method: "GET",
headers: {
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
},
}),
{ params: Promise.resolve({ projectId: "missing-project" }) },
);
assert.equal(response.status, 404);
assert.equal((await response.json()).message, "PROJECT_NOT_FOUND");
});
test(
"GET /agent-controls returns 404 when master-agent record is missing from state",
{ concurrency: false },
async () => {
await setup();
const script = String.raw`
import { mkdtemp, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { NextRequest } from "next/server";
(async () => {
const runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-master-agent-missing-"));
process.env.BOSS_RUNTIME_ROOT = runtimeRoot;
process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json");
const dataModule = await import("./src/lib/boss-data.ts");
const authModule = await import("./src/lib/boss-auth.ts");
const routeModule = await import("./src/app/api/v1/projects/[projectId]/agent-controls/route.ts");
const data = dataModule.default ?? dataModule;
const auth = authModule.default ?? authModule;
const route = routeModule.default ?? routeModule;
const session = await data.createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
const state = await data.readState();
state.projects = state.projects.filter((item) => item.id !== "master-agent");
await writeFile(process.env.BOSS_STATE_FILE!, JSON.stringify(state, null, 2), "utf8");
if (await data.hasPersistedProject("master-agent")) {
throw new Error("expected raw state to miss master-agent");
}
const response = await route.GET(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "GET",
headers: {
cookie: auth.AUTH_SESSION_COOKIE + "=" + session.sessionToken,
},
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
const text = await response.text();
if (response.status !== 404) {
throw new Error("expected 404, got " + response.status + ": " + text);
}
if (!text.includes("PROJECT_NOT_FOUND")) {
throw new Error("expected PROJECT_NOT_FOUND, got " + text);
}
console.log(text);
})().catch((error) => {
console.error(error);
process.exit(1);
});
`;
const tsxBin = path.resolve("node_modules/.bin/tsx");
const { stdout } = await execFile(tsxBin, ["--eval", script], {
cwd: process.cwd(),
env: { ...process.env },
encoding: "utf8",
maxBuffer: 1024 * 1024,
});
assert.match(stdout, /PROJECT_NOT_FOUND/);
},
);
test("GET /agent-controls 在未显式设置 BOSS_STATE_FILE 时仍可正常读取 controls", async () => {
const runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-master-agent-default-state-"));
const childEnv = { ...process.env };
delete childEnv.BOSS_STATE_FILE;
const script = String.raw`
import { NextRequest } from "next/server";
(async () => {
const runtimeRoot = process.env.BOSS_RUNTIME_ROOT;
if (!runtimeRoot) {
throw new Error("missing BOSS_RUNTIME_ROOT");
}
delete process.env.BOSS_STATE_FILE;
const dataModule = await import("./src/lib/boss-data.ts");
const authModule = await import("./src/lib/boss-auth.ts");
const routeModule = await import("./src/app/api/v1/projects/[projectId]/agent-controls/route.ts");
const data = dataModule.default ?? dataModule;
const auth = authModule.default ?? authModule;
const route = routeModule.default ?? routeModule;
await data.updateProjectAgentControls("master-agent", {
modelOverride: "gpt-5.4",
reasoningEffortOverride: "medium",
});
const session = await data.createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
const response = await route.GET(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "GET",
headers: {
cookie: auth.AUTH_SESSION_COOKIE + "=" + session.sessionToken,
},
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
const payload = await response.json();
if (response.status !== 200) {
throw new Error("expected 200, got " + response.status + ": " + JSON.stringify(payload));
}
if (!payload.ok || payload.controls?.modelOverride !== "gpt-5.4" || payload.controls?.reasoningEffortOverride !== "medium") {
throw new Error("unexpected payload: " + JSON.stringify(payload));
}
console.log("OK");
})().catch((error) => {
console.error(error);
process.exit(1);
});
`;
const tsxBin = path.resolve("node_modules/.bin/tsx");
const { stdout } = await execFile(tsxBin, ["--eval", script], {
cwd: process.cwd(),
env: { ...childEnv, BOSS_RUNTIME_ROOT: runtimeRoot },
encoding: "utf8",
maxBuffer: 1024 * 1024,
});
assert.match(stdout, /OK/);
});
test("GET /agent-controls rejects ordinary projects", async () => {
await setup();
const session = await createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
const response = await getAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/boss-console/agent-controls", {
method: "GET",
headers: {
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
},
}),
{ params: Promise.resolve({ projectId: "boss-console" }) },
);
assert.equal(response.status, 404);
assert.equal((await response.json()).message, "PROJECT_NOT_FOUND");
});
test("POST /agent-controls rejects unknown-key payload and preserves controls", async () => {
await setup();
const session = await createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
await updateProjectAgentControls("master-agent", {
modelOverride: "gpt-5.4",
reasoningEffortOverride: "high",
});
const beforeState = await readState();
const beforeProject = beforeState.projects.find((item) => item.id === "master-agent");
assert.ok(beforeProject, "expected seeded master-agent project");
const beforeUpdatedAt = beforeProject.updatedAt;
const response = await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers: {
"content-type": "application/json",
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
},
body: JSON.stringify({
unexpectedKey: "value",
}),
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(response.status, 400);
assert.equal((await response.json()).message, "INVALID_AGENT_CONTROLS_PAYLOAD");
const controls = await getProjectAgentControls("master-agent");
assert.equal(controls?.modelOverride, "gpt-5.4");
assert.equal(controls?.reasoningEffortOverride, "high");
const afterState = await readState();
const afterProject = afterState.projects.find((item) => item.id === "master-agent");
assert.equal(afterProject?.updatedAt, beforeUpdatedAt);
});
test("master-agent 对话控制 POST 会稳定拒绝非法 backendOverride", async () => {
await setup();
const session = await createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
const response = await postAgentControlsRoute(
new NextRequest("http://127.0.0.1:3000/api/v1/projects/master-agent/agent-controls", {
method: "POST",
headers: {
"content-type": "application/json",
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
},
body: JSON.stringify({
backendOverride: "bad-backend",
}),
}),
{ params: Promise.resolve({ projectId: "master-agent" }) },
);
assert.equal(response.status, 400);
const payload = (await response.json()) as { ok: boolean; message?: string };
assert.equal(payload.ok, false);
assert.equal(payload.message, "INVALID_BACKEND_OVERRIDE");
});
test("master-agent controls helper 不会写入普通项目", async () => {
await setup();
await assert.rejects(
() =>
updateProjectAgentControls("boss-console", {
modelOverride: "gpt-5.4",
reasoningEffortOverride: "low",
}),
/MASTER_AGENT_CONTROLS_SCOPE_RESTRICTED/,
);
const state = await readState();
const project = state.projects.find((item) => item.id === "boss-console");
assert.equal(project?.agentControls, undefined);
assert.equal(await getProjectAgentControls("boss-console"), null);
});