Files
boss/tests/master-agent-openai-fallback.test.ts

103 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import test from "node:test";
import assert from "node:assert/strict";
import os from "node:os";
import path from "node:path";
import { mkdtemp, rm } from "node:fs/promises";
let runtimeRoot = "";
let replyToMasterAgentUserMessage: (typeof import("../src/lib/boss-master-agent"))["replyToMasterAgentUserMessage"];
let saveAiAccount: (typeof import("../src/lib/boss-data"))["saveAiAccount"];
let readState: (typeof import("../src/lib/boss-data"))["readState"];
async function setup() {
if (runtimeRoot) return;
runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-master-agent-fallback-"));
process.env.BOSS_RUNTIME_ROOT = runtimeRoot;
process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json");
const [masterAgent, data] = await Promise.all([
import("../src/lib/boss-master-agent.ts"),
import("../src/lib/boss-data.ts"),
]);
replyToMasterAgentUserMessage = masterAgent.replyToMasterAgentUserMessage;
saveAiAccount = data.saveAiAccount;
readState = data.readState;
}
test.after(async () => {
if (runtimeRoot) {
await rm(runtimeRoot, { recursive: true, force: true });
}
});
test("replyToMasterAgentUserMessage falls back to a runnable OpenAI API account when the master node is offline", async () => {
await setup();
await saveAiAccount({
accountId: "master-codex-primary",
label: "主 GPT",
role: "primary",
provider: "master_codex_node",
displayName: "Mac 上的 Master Codex Node",
nodeId: "offline-node",
nodeLabel: "离线节点",
model: "gpt-5.4",
enabled: true,
setActive: true,
loginStatusNote: "通过绑定的 Master Codex Node 对话。",
});
await saveAiAccount({
accountId: "openai-backup",
label: "备用 GPT",
role: "backup",
provider: "openai_api",
displayName: "OpenAI API 备用账号",
accountIdentifier: "sk-demo",
model: "gpt-5.4",
apiKey: "sk-live-demo-123456",
enabled: true,
setActive: false,
loginStatusNote: "备用 API 账号。",
});
const originalFetch = globalThis.fetch;
globalThis.fetch = (async (input) => {
if (typeof input === "string" && input === "https://api.openai.com/v1/responses") {
return new Response(JSON.stringify({ output_text: "主Agent链路正常。" }), {
status: 200,
headers: {
"content-type": "application/json",
"x-request-id": "req-master-fallback",
},
});
}
throw new Error(`unexpected fetch: ${String(input)}`);
}) as typeof fetch;
try {
const result = await replyToMasterAgentUserMessage({
requestMessageId: "msg-master-fallback",
requestText: "请只回复主Agent链路正常。",
requestedBy: "Boss 超级管理员",
requestedByAccount: "17600003315",
});
assert.equal(result.ok, true);
assert.equal(result.accountId, "openai-backup");
assert.equal(result.requestId, "req-master-fallback");
const state = await readState();
const masterProject = state.projects.find((project) => project.id === "master-agent");
const reply = masterProject?.messages.at(-1);
assert.ok(reply, "expected a master-agent reply to be appended");
assert.equal(reply?.sender, "master");
assert.equal(reply?.senderLabel, "主 Agent · 备用 GPT");
assert.match(reply?.body ?? "", /主Agent链路正常/);
} finally {
globalThis.fetch = originalFetch;
}
});