370 lines
11 KiB
TypeScript
370 lines
11 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 } from "node:fs/promises";
|
|
import { NextRequest } from "next/server";
|
|
|
|
let runtimeRoot = "";
|
|
let validateAiAccountConnection: (typeof import("../src/lib/boss-master-agent"))["validateAiAccountConnection"];
|
|
let readState: (typeof import("../src/lib/boss-data"))["readState"];
|
|
let deviceHeartbeatRoute: (typeof import("../src/app/api/device-heartbeat/route"))["POST"];
|
|
let saveAiAccount: (typeof import("../src/lib/boss-data"))["saveAiAccount"];
|
|
|
|
async function setup() {
|
|
if (runtimeRoot) return;
|
|
|
|
runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-ai-account-"));
|
|
process.env.BOSS_RUNTIME_ROOT = runtimeRoot;
|
|
process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json");
|
|
|
|
const [masterAgent, data, heartbeatModule] = await Promise.all([
|
|
import("../src/lib/boss-master-agent.ts"),
|
|
import("../src/lib/boss-data.ts"),
|
|
import("../src/app/api/device-heartbeat/route.ts"),
|
|
]);
|
|
|
|
validateAiAccountConnection = masterAgent.validateAiAccountConnection;
|
|
readState = data.readState;
|
|
saveAiAccount = data.saveAiAccount;
|
|
deviceHeartbeatRoute = heartbeatModule.POST;
|
|
}
|
|
|
|
test.after(async () => {
|
|
if (runtimeRoot) {
|
|
await rm(runtimeRoot, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("validateAiAccountConnection explains master node login happens on the bound device", async () => {
|
|
await setup();
|
|
|
|
const result = await validateAiAccountConnection("master-codex-primary");
|
|
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.status, "ready");
|
|
assert.match(result.message, /不在手机里直接登录/);
|
|
assert.match(result.message, /Mac Studio|本机 Codex/);
|
|
});
|
|
|
|
test("validateAiAccountConnection reports degraded when the bound master node device is offline", async () => {
|
|
await setup();
|
|
const state = await readState();
|
|
const device = state.devices.find((item) => item.id === "mac-studio");
|
|
assert.ok(device, "expected default mac-studio seed device");
|
|
|
|
const heartbeatResponse = await deviceHeartbeatRoute(
|
|
new NextRequest("http://127.0.0.1:3000/api/device-heartbeat", {
|
|
method: "POST",
|
|
headers: { "content-type": "application/json" },
|
|
body: JSON.stringify({
|
|
deviceId: device!.id,
|
|
token: device!.token,
|
|
name: device!.name,
|
|
avatar: device!.avatar,
|
|
account: device!.account,
|
|
status: "offline",
|
|
quota5h: device!.quota5h,
|
|
quota7d: device!.quota7d,
|
|
projects: device!.projects,
|
|
endpoint: device!.endpoint,
|
|
}),
|
|
}),
|
|
);
|
|
assert.equal(heartbeatResponse.status, 200);
|
|
|
|
const result = await validateAiAccountConnection("master-codex-primary");
|
|
|
|
assert.equal(result.ok, false);
|
|
assert.equal(result.status, "degraded");
|
|
assert.match(result.message, /当前不在线|不在线/);
|
|
});
|
|
|
|
test("validateAiAccountConnection probes aliyun qwen backup accounts through the compatible endpoint", async () => {
|
|
await setup();
|
|
|
|
await saveAiAccount({
|
|
accountId: "aliyun-qwen-backup",
|
|
label: "阿里备用",
|
|
role: "backup",
|
|
provider: "aliyun_qwen_api",
|
|
displayName: "阿里百炼备用账号",
|
|
accountIdentifier: "dashscope-demo",
|
|
model: "qwen3.5-plus",
|
|
apiKey: "sk-aliyun-demo-123456",
|
|
enabled: true,
|
|
});
|
|
|
|
const originalFetch = globalThis.fetch;
|
|
globalThis.fetch = (async (input) => {
|
|
if (typeof input === "string" && input === "https://dashscope.aliyuncs.com/compatible-mode/v1/responses") {
|
|
return new Response(JSON.stringify({ output_text: "连接正常" }), {
|
|
status: 200,
|
|
headers: {
|
|
"content-type": "application/json",
|
|
"x-request-id": "req-aliyun-validate",
|
|
},
|
|
});
|
|
}
|
|
throw new Error(`unexpected fetch: ${String(input)}`);
|
|
}) as typeof fetch;
|
|
|
|
try {
|
|
const result = await validateAiAccountConnection("aliyun-qwen-backup");
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.status, "ready");
|
|
assert.match(result.message, /连接正常/);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|
|
|
|
test("validateAiAccountConnection honors custom api base url overrides for OpenAI accounts", async () => {
|
|
await setup();
|
|
|
|
await saveAiAccount(Object.assign({
|
|
accountId: "openai-api-primary",
|
|
label: "主 GPT",
|
|
role: "primary" as const,
|
|
provider: "openai_api" as const,
|
|
displayName: "OpenAI 平台账号",
|
|
accountIdentifier: "openai-demo",
|
|
model: "gpt-5.4-mini",
|
|
apiKey: "sk-openai-demo-123456",
|
|
enabled: true,
|
|
}, {
|
|
apiBaseUrl: "https://gateway.example.com/openai/v1",
|
|
}));
|
|
|
|
const originalFetch = globalThis.fetch;
|
|
globalThis.fetch = (async (input) => {
|
|
if (typeof input === "string" && input === "https://gateway.example.com/openai/v1/responses") {
|
|
return new Response(JSON.stringify({ output_text: "连接正常" }), {
|
|
status: 200,
|
|
headers: {
|
|
"content-type": "application/json",
|
|
"x-request-id": "req-openai-custom-endpoint",
|
|
},
|
|
});
|
|
}
|
|
throw new Error(`unexpected fetch: ${String(input)}`);
|
|
}) as typeof fetch;
|
|
|
|
try {
|
|
const result = await validateAiAccountConnection("openai-api-primary");
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.status, "ready");
|
|
assert.match(result.message, /连接正常/);
|
|
assert.equal(result.requestId, "req-openai-custom-endpoint");
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|
|
|
|
test("validateAiAccountConnection uses the default 环宇智擎 endpoint for primary API accounts", async () => {
|
|
await setup();
|
|
|
|
await saveAiAccount({
|
|
accountId: "hyzq-primary",
|
|
label: "主 GPT",
|
|
role: "primary",
|
|
provider: "hyzq_api",
|
|
displayName: "环宇智擎主链路",
|
|
accountIdentifier: "hyzq-primary-demo",
|
|
model: "gpt-5.4-mini",
|
|
apiKey: "sk-hyzq-demo-123456",
|
|
enabled: true,
|
|
});
|
|
|
|
const originalFetch = globalThis.fetch;
|
|
globalThis.fetch = (async (input) => {
|
|
if (typeof input === "string" && input === "https://api.hyzq2046.com/v1/responses") {
|
|
return new Response(JSON.stringify({ output_text: "连接正常" }), {
|
|
status: 200,
|
|
headers: {
|
|
"content-type": "application/json",
|
|
"x-request-id": "req-hyzq-validate",
|
|
},
|
|
});
|
|
}
|
|
throw new Error(`unexpected fetch: ${String(input)}`);
|
|
}) as typeof fetch;
|
|
|
|
try {
|
|
const result = await validateAiAccountConnection("hyzq-primary");
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.status, "ready");
|
|
assert.equal(result.requestId, "req-hyzq-validate");
|
|
assert.match(result.message, /连接正常/);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|
|
|
|
test("validateAiAccountConnection probes GLM accounts through chat completions", async () => {
|
|
await setup();
|
|
|
|
await saveAiAccount({
|
|
accountId: "glm-backup",
|
|
label: "备用 GPT",
|
|
role: "backup",
|
|
provider: "glm_api",
|
|
displayName: "GLM 备用账号",
|
|
accountIdentifier: "glm-demo",
|
|
model: "glm-4.5",
|
|
apiKey: "sk-glm-demo-123456",
|
|
enabled: true,
|
|
});
|
|
|
|
const originalFetch = globalThis.fetch;
|
|
globalThis.fetch = (async (input) => {
|
|
if (typeof input === "string" && input === "https://open.bigmodel.cn/api/paas/v4/chat/completions") {
|
|
return new Response(JSON.stringify({
|
|
choices: [
|
|
{
|
|
message: {
|
|
content: "连接正常",
|
|
},
|
|
},
|
|
],
|
|
}), {
|
|
status: 200,
|
|
headers: {
|
|
"content-type": "application/json",
|
|
"x-request-id": "req-glm-validate",
|
|
},
|
|
});
|
|
}
|
|
throw new Error(`unexpected fetch: ${String(input)}`);
|
|
}) as typeof fetch;
|
|
|
|
try {
|
|
const result = await validateAiAccountConnection("glm-backup");
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.status, "ready");
|
|
assert.equal(result.requestId, "req-glm-validate");
|
|
assert.match(result.message, /连接正常/);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|
|
|
|
test("validateAiAccountConnection probes DeepSeek V4 accounts through chat completions", async () => {
|
|
await setup();
|
|
|
|
await saveAiAccount({
|
|
accountId: "deepseek-primary",
|
|
label: "主要API",
|
|
role: "primary",
|
|
provider: "deepseek_api",
|
|
displayName: "DeepSeek V4 主链路",
|
|
accountIdentifier: "deepseek-demo",
|
|
model: "deepseek-v4-pro",
|
|
apiKey: "sk-deepseek-demo-123456",
|
|
enabled: true,
|
|
});
|
|
|
|
const originalFetch = globalThis.fetch;
|
|
globalThis.fetch = (async (input) => {
|
|
if (typeof input === "string" && input === "https://api.deepseek.com/chat/completions") {
|
|
return new Response(JSON.stringify({
|
|
choices: [
|
|
{
|
|
message: {
|
|
content: "连接正常",
|
|
},
|
|
},
|
|
],
|
|
}), {
|
|
status: 200,
|
|
headers: {
|
|
"content-type": "application/json",
|
|
"x-request-id": "req-deepseek-validate",
|
|
},
|
|
});
|
|
}
|
|
if (typeof input === "string" && input === "https://api.deepseek.com/models") {
|
|
return new Response(JSON.stringify({
|
|
data: [
|
|
{ id: "deepseek-v4-pro" },
|
|
{ id: "deepseek-v4-flash" },
|
|
],
|
|
}), {
|
|
status: 200,
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
});
|
|
}
|
|
throw new Error(`unexpected fetch: ${String(input)}`);
|
|
}) as typeof fetch;
|
|
|
|
try {
|
|
const result = await validateAiAccountConnection("deepseek-primary");
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.status, "ready");
|
|
assert.equal(result.requestId, "req-deepseek-validate");
|
|
assert.match(result.message, /连接正常/);
|
|
assert.deepEqual(result.availableModels, ["deepseek-v4-pro", "deepseek-v4-flash"]);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|
|
|
|
test("validateAiAccountConnection falls back to generic models for custom api accounts", async () => {
|
|
await setup();
|
|
|
|
await saveAiAccount({
|
|
accountId: "custom-backup",
|
|
label: "备用 GPT",
|
|
role: "backup",
|
|
provider: "custom_api",
|
|
displayName: "自定义兼容 API",
|
|
accountIdentifier: "custom-demo",
|
|
model: "gpt-5.4",
|
|
apiBaseUrl: "https://gateway.example.com/v1",
|
|
apiKey: "sk-custom-demo-123456",
|
|
enabled: true,
|
|
});
|
|
|
|
const originalFetch = globalThis.fetch;
|
|
globalThis.fetch = (async (input) => {
|
|
if (typeof input === "string" && input === "https://gateway.example.com/v1/chat/completions") {
|
|
return new Response(JSON.stringify({
|
|
choices: [
|
|
{
|
|
message: {
|
|
content: "连接正常",
|
|
},
|
|
},
|
|
],
|
|
}), {
|
|
status: 200,
|
|
headers: {
|
|
"content-type": "application/json",
|
|
"x-request-id": "req-custom-validate",
|
|
},
|
|
});
|
|
}
|
|
if (typeof input === "string" && input === "https://gateway.example.com/v1/models") {
|
|
return new Response(JSON.stringify({ data: [] }), {
|
|
status: 200,
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
});
|
|
}
|
|
throw new Error(`unexpected fetch: ${String(input)}`);
|
|
}) as typeof fetch;
|
|
|
|
try {
|
|
const result = await validateAiAccountConnection("custom-backup");
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.status, "ready");
|
|
assert.match(result.message, /兜底/);
|
|
assert.deepEqual(result.availableModels, ["gpt-5.4", "gpt-5.4-mini", "gpt-5.1", "gpt-4.1"]);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|