diff --git a/android/app/src/main/java/com/hyzq/boss/AiAccountsActivity.java b/android/app/src/main/java/com/hyzq/boss/AiAccountsActivity.java
index 6fe2d07..95ab4f0 100644
--- a/android/app/src/main/java/com/hyzq/boss/AiAccountsActivity.java
+++ b/android/app/src/main/java/com/hyzq/boss/AiAccountsActivity.java
@@ -33,6 +33,7 @@ public class AiAccountsActivity extends BossScreenActivity {
private static final String PROVIDER_CHATGPT_OAUTH = "chatgpt_oauth";
private static final String PROVIDER_OPENAI_API = "openai_api";
private static final String PROVIDER_ALIYUN_QWEN_API = "aliyun_qwen_api";
+ private static final String PROVIDER_DEEPSEEK_API = "deepseek_api";
private static final String PROVIDER_MINIMAX_API = "minimax_api";
private static final String PROVIDER_GLM_API = "glm_api";
private static final String PROVIDER_HYZQ_API = "hyzq_api";
@@ -41,6 +42,7 @@ public class AiAccountsActivity extends BossScreenActivity {
private static final String DEFAULT_MASTER_MODEL = "gpt-5.4";
private static final String OPENAI_API_BASE_URL = "https://api.openai.com/v1";
private static final String ALIYUN_QWEN_API_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1";
+ private static final String DEEPSEEK_API_BASE_URL = "https://api.deepseek.com";
private static final String MINIMAX_API_BASE_URL = "https://api.minimaxi.com/v1";
private static final String GLM_API_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
private static final String HYZQ_API_BASE_URL = "https://api.hyzq2046.com/v1";
@@ -54,6 +56,7 @@ public class AiAccountsActivity extends BossScreenActivity {
private static final ProviderOption[] API_OPTIONS = new ProviderOption[] {
new ProviderOption(PROVIDER_ALIYUN_QWEN_API, "阿里", "阿里百炼 API", "自动填好百炼兼容地址,直接填写模型和 Key。"),
+ new ProviderOption(PROVIDER_DEEPSEEK_API, "DeepSeek", "DeepSeek API", "自动填好 DeepSeek 地址,可选择 V4 Pro / Flash。"),
new ProviderOption(PROVIDER_MINIMAX_API, "Minimax", "MiniMax API", "自动填好 MiniMax 地址,适合接成主链路或备用链路。"),
new ProviderOption(PROVIDER_GLM_API, "GLM", "智谱 GLM API", "自动填好 GLM 地址,直接复用通用 API 保存流程。"),
new ProviderOption(PROVIDER_HYZQ_API, "环宇智擎", "环宇智擎 API", "自动填好环宇智擎网关地址,直接填写模型和 Key。"),
@@ -466,7 +469,7 @@ public class AiAccountsActivity extends BossScreenActivity {
isPrimaryRole(targetRole)
? "主链路可直接接兼容 API。"
: "备用链路可接兼容 API 做兜底。",
- "支持阿里、Minimax、GLM、环宇智擎和自定义。",
+ "支持阿里、DeepSeek、Minimax、GLM、环宇智擎和自定义。",
null,
null
));
@@ -575,6 +578,7 @@ public class AiAccountsActivity extends BossScreenActivity {
private boolean isApiProvider(String provider) {
return PROVIDER_OPENAI_API.equals(provider)
|| PROVIDER_ALIYUN_QWEN_API.equals(provider)
+ || PROVIDER_DEEPSEEK_API.equals(provider)
|| PROVIDER_MINIMAX_API.equals(provider)
|| PROVIDER_GLM_API.equals(provider)
|| PROVIDER_HYZQ_API.equals(provider)
@@ -588,6 +592,9 @@ public class AiAccountsActivity extends BossScreenActivity {
if (PROVIDER_ALIYUN_QWEN_API.equals(provider)) {
return ALIYUN_QWEN_API_BASE_URL;
}
+ if (PROVIDER_DEEPSEEK_API.equals(provider)) {
+ return DEEPSEEK_API_BASE_URL;
+ }
if (PROVIDER_MINIMAX_API.equals(provider)) {
return MINIMAX_API_BASE_URL;
}
@@ -604,6 +611,9 @@ public class AiAccountsActivity extends BossScreenActivity {
if (PROVIDER_ALIYUN_QWEN_API.equals(provider)) {
return "qwen3.5-plus";
}
+ if (PROVIDER_DEEPSEEK_API.equals(provider)) {
+ return "deepseek-v4-pro";
+ }
if (PROVIDER_MINIMAX_API.equals(provider)) {
return "MiniMax-M1";
}
@@ -629,6 +639,9 @@ public class AiAccountsActivity extends BossScreenActivity {
if (PROVIDER_ALIYUN_QWEN_API.equals(provider)) {
return "阿里";
}
+ if (PROVIDER_DEEPSEEK_API.equals(provider)) {
+ return "DeepSeek";
+ }
if (PROVIDER_MINIMAX_API.equals(provider)) {
return "Minimax";
}
diff --git a/scripts/deploy-server.sh b/scripts/deploy-server.sh
index c6975ff..e88445a 100755
--- a/scripts/deploy-server.sh
+++ b/scripts/deploy-server.sh
@@ -6,7 +6,7 @@ REMOTE_USER="${BOSS_SERVER_USER:-ubuntu}"
REMOTE_HOSTNAME="${BOSS_SERVER_HOST:-106.53.170.158}"
REMOTE_HOST="${BOSS_REMOTE_HOST:-${REMOTE_USER}@${REMOTE_HOSTNAME}}"
REMOTE_DIR="${BOSS_REMOTE_DIR:-/opt/boss}"
-SSH_OPTS="-o StrictHostKeyChecking=no"
+SSH_OPTS="-o StrictHostKeyChecking=no -o PreferredAuthentications=password -o PubkeyAuthentication=no -o NumberOfPasswordPrompts=1"
KEYCHAIN_SERVICE="${BOSS_KEYCHAIN_SERVICE:-boss-server-debug-ssh}"
BUILD_MODE="${BOSS_DEPLOY_BUILD_MODE:-auto}"
diff --git a/src/app/api/v1/accounts/[accountId]/route.ts b/src/app/api/v1/accounts/[accountId]/route.ts
index 1eec0c5..7a3fbef 100644
--- a/src/app/api/v1/accounts/[accountId]/route.ts
+++ b/src/app/api/v1/accounts/[accountId]/route.ts
@@ -15,6 +15,7 @@ function isValidProvider(
| "chatgpt_oauth"
| "openai_api"
| "aliyun_qwen_api"
+ | "deepseek_api"
| "minimax_api"
| "glm_api"
| "hyzq_api"
@@ -25,6 +26,7 @@ function isValidProvider(
value === "chatgpt_oauth" ||
value === "openai_api" ||
value === "aliyun_qwen_api" ||
+ value === "deepseek_api" ||
value === "minimax_api" ||
value === "glm_api" ||
value === "hyzq_api" ||
diff --git a/src/app/api/v1/accounts/route.ts b/src/app/api/v1/accounts/route.ts
index 5bb6f2b..8c9e058 100644
--- a/src/app/api/v1/accounts/route.ts
+++ b/src/app/api/v1/accounts/route.ts
@@ -15,6 +15,7 @@ function isValidProvider(
| "chatgpt_oauth"
| "openai_api"
| "aliyun_qwen_api"
+ | "deepseek_api"
| "minimax_api"
| "glm_api"
| "hyzq_api"
@@ -25,6 +26,7 @@ function isValidProvider(
value === "chatgpt_oauth" ||
value === "openai_api" ||
value === "aliyun_qwen_api" ||
+ value === "deepseek_api" ||
value === "minimax_api" ||
value === "glm_api" ||
value === "hyzq_api" ||
diff --git a/src/app/api/v1/accounts/validate-draft/route.ts b/src/app/api/v1/accounts/validate-draft/route.ts
index 83ef7ae..1793936 100644
--- a/src/app/api/v1/accounts/validate-draft/route.ts
+++ b/src/app/api/v1/accounts/validate-draft/route.ts
@@ -7,6 +7,7 @@ function isValidProvider(
): value is
| "openai_api"
| "aliyun_qwen_api"
+ | "deepseek_api"
| "minimax_api"
| "glm_api"
| "hyzq_api"
@@ -14,6 +15,7 @@ function isValidProvider(
return (
value === "openai_api" ||
value === "aliyun_qwen_api" ||
+ value === "deepseek_api" ||
value === "minimax_api" ||
value === "glm_api" ||
value === "hyzq_api" ||
diff --git a/src/components/ai-accounts-client.tsx b/src/components/ai-accounts-client.tsx
index a3148c7..f6e2b4f 100644
--- a/src/components/ai-accounts-client.tsx
+++ b/src/components/ai-accounts-client.tsx
@@ -71,10 +71,27 @@ function providerOptions() {
return [
{ value: "openai_api", label: "OpenAI API" },
{ value: "aliyun_qwen_api", label: "阿里百炼 Qwen" },
+ { value: "deepseek_api", label: "DeepSeek API" },
+ { value: "minimax_api", label: "MiniMax API" },
+ { value: "glm_api", label: "GLM API" },
+ { value: "hyzq_api", label: "环宇智擎 API" },
+ { value: "custom_api", label: "自定义 API" },
{ value: "master_codex_node", label: "Master Codex Node / ChatGPT Plus 节点" },
] as const;
}
+function isApiKeyDraftProvider(provider: AiProvider) {
+ return (
+ provider === "openai_api" ||
+ provider === "aliyun_qwen_api" ||
+ provider === "deepseek_api" ||
+ provider === "minimax_api" ||
+ provider === "glm_api" ||
+ provider === "hyzq_api" ||
+ provider === "custom_api"
+ );
+}
+
function defaultOpenAiOnboardDraft(): OpenAiOnboardDraft {
return {
label: "主 GPT",
@@ -675,7 +692,7 @@ export function AiAccountsClient({
placeholder="例如:gpt-5.4"
/>
)}
- {draft.provider === "openai_api" || draft.provider === "aliyun_qwen_api" ? (
+ {isApiKeyDraftProvider(draft.provider) ? (
diff --git a/src/lib/boss-data.ts b/src/lib/boss-data.ts
index 6468dfd..1e04510 100644
--- a/src/lib/boss-data.ts
+++ b/src/lib/boss-data.ts
@@ -226,6 +226,7 @@ export type AiProvider =
| "chatgpt_oauth"
| "openai_api"
| "aliyun_qwen_api"
+ | "deepseek_api"
| "minimax_api"
| "glm_api"
| "hyzq_api"
@@ -3354,6 +3355,8 @@ export function aiProviderLabel(provider: AiProvider) {
return "OpenAI API";
case "aliyun_qwen_api":
return "阿里百炼 Qwen";
+ case "deepseek_api":
+ return "DeepSeek API";
case "minimax_api":
return "MiniMax API";
case "glm_api":
@@ -3373,6 +3376,8 @@ export function aiProviderDefaultApiBaseUrl(provider: AiProvider) {
return "https://api.openai.com/v1";
case "aliyun_qwen_api":
return "https://dashscope.aliyuncs.com/compatible-mode/v1";
+ case "deepseek_api":
+ return "https://api.deepseek.com";
case "minimax_api":
return "https://api.minimaxi.com/v1";
case "glm_api":
@@ -3390,6 +3395,8 @@ export function aiProviderDefaultModel(provider: AiProvider) {
return "gpt-5.4";
case "aliyun_qwen_api":
return "qwen3.5-plus";
+ case "deepseek_api":
+ return "deepseek-v4-pro";
case "minimax_api":
return "MiniMax-M1";
case "glm_api":
@@ -3434,6 +3441,7 @@ export function isApiKeyProvider(provider: AiProvider) {
return (
provider === "openai_api" ||
provider === "aliyun_qwen_api" ||
+ provider === "deepseek_api" ||
provider === "minimax_api" ||
provider === "glm_api" ||
provider === "hyzq_api" ||
diff --git a/src/lib/boss-master-agent.ts b/src/lib/boss-master-agent.ts
index 0387da0..b1e3598 100644
--- a/src/lib/boss-master-agent.ts
+++ b/src/lib/boss-master-agent.ts
@@ -1,7 +1,6 @@
import { randomBytes } from "node:crypto";
import {
AUTH_SESSION_TTL_MS,
- aiRoleLabel,
aiProviderLabel,
appendProjectMessage,
completeMasterAgentTask,
@@ -70,7 +69,7 @@ const CLAW_RUNTIME_DEVICE_ID = "master-agent-claw";
type ApiCompatibleProvider = Extract<
AiProvider,
- "openai_api" | "aliyun_qwen_api" | "minimax_api" | "glm_api" | "hyzq_api" | "custom_api"
+ "openai_api" | "aliyun_qwen_api" | "deepseek_api" | "minimax_api" | "glm_api" | "hyzq_api" | "custom_api"
>;
const API_PROVIDER_CONFIG: Record<
@@ -97,6 +96,13 @@ const API_PROVIDER_CONFIG: Record<
loginLabel: "阿里百炼 API Key",
protocol: "responses",
},
+ deepseek_api: {
+ label: "DeepSeek API",
+ defaultBaseUrl: "https://api.deepseek.com",
+ defaultModel: "deepseek-v4-pro",
+ loginLabel: "DeepSeek API Key",
+ protocol: "chat_completions",
+ },
minimax_api: {
label: "MiniMax API",
defaultBaseUrl: "https://api.minimaxi.com/v1",
@@ -130,6 +136,7 @@ const API_PROVIDER_CONFIG: Record<
const API_PROVIDER_MODEL_OPTIONS: Record
= {
openai_api: ["gpt-5.4-mini", "gpt-5.4", "gpt-5.1", "gpt-4.1"],
aliyun_qwen_api: ["qwen3.5-plus", "qwen3.5-flash"],
+ deepseek_api: ["deepseek-v4-pro", "deepseek-v4-flash"],
minimax_api: ["MiniMax-M1"],
glm_api: ["glm-4.5"],
hyzq_api: ["gpt-5.4-mini", "gpt-5.4"],
@@ -139,6 +146,7 @@ const API_PROVIDER_MODEL_OPTIONS: Record = {
const API_EXECUTION_PROVIDER_PRIORITY: ApiCompatibleProvider[] = [
"hyzq_api",
"openai_api",
+ "deepseek_api",
"aliyun_qwen_api",
"glm_api",
"minimax_api",
@@ -528,7 +536,7 @@ export async function resolveMasterAgentExecutionConfig(
const state = await readState();
const resolvedAccountId = accountId?.trim() || state.user.account || runtime.account.accountId;
const scopedAgentControls = await getProjectAgentControls(projectId, resolvedAccountId);
- const modeResolution = resolveMasterAgentExecutionMode(scopedAgentControls, requestText);
+ const modeResolution = resolveMasterAgentExecutionMode(scopedAgentControls, requestText, runtime.account);
const reasoningEffort =
modeResolution.effectiveReasoningEffort ||
(runtime.account as typeof runtime.account & { reasoningEffort?: ReasoningEffort }).reasoningEffort ||
@@ -584,12 +592,44 @@ function normalizeAgentControlText(value?: string | null) {
return trimmed ? trimmed : undefined;
}
-function resolveConfiguredFastModel(agentControls?: ProjectAgentControls | null) {
- return normalizeAgentControlText(agentControls?.fastModelOverride) || DEFAULT_FAST_MODEL;
+function isProviderCompatibleModel(model: string | undefined, account?: AiAccount | null) {
+ if (!model || !account || !isApiCompatibleProvider(account.provider)) {
+ return true;
+ }
+ if (account.provider !== "deepseek_api") {
+ return true;
+ }
+ const modelOptions = API_PROVIDER_MODEL_OPTIONS[account.provider];
+ return modelOptions.length === 0 || modelOptions.includes(model);
}
-function resolveConfiguredDeepModel(agentControls?: ProjectAgentControls | null) {
- return normalizeAgentControlText(agentControls?.deepModelOverride) || DEFAULT_DEEP_MODEL;
+function normalizeAgentControlModelForAccount(value?: string | null, account?: AiAccount | null) {
+ const model = normalizeAgentControlText(value);
+ return isProviderCompatibleModel(model, account) ? model : undefined;
+}
+
+function defaultFastModelForAccount(account?: AiAccount | null) {
+ if (account && isApiCompatibleProvider(account.provider)) {
+ if (account.provider === "deepseek_api") return "deepseek-v4-flash";
+ if (account.provider === "aliyun_qwen_api") return "qwen3.5-flash";
+ return apiProviderConfig(account.provider).defaultModel;
+ }
+ return DEFAULT_FAST_MODEL;
+}
+
+function defaultDeepModelForAccount(account?: AiAccount | null) {
+ if (account && isApiCompatibleProvider(account.provider)) {
+ return account.model || apiProviderConfig(account.provider).defaultModel;
+ }
+ return DEFAULT_DEEP_MODEL;
+}
+
+function resolveConfiguredFastModel(agentControls?: ProjectAgentControls | null, account?: AiAccount | null) {
+ return normalizeAgentControlModelForAccount(agentControls?.fastModelOverride, account) || defaultFastModelForAccount(account);
+}
+
+function resolveConfiguredDeepModel(agentControls?: ProjectAgentControls | null, account?: AiAccount | null) {
+ return normalizeAgentControlModelForAccount(agentControls?.deepModelOverride, account) || defaultDeepModelForAccount(account);
}
export function shouldAutoEscalateMasterAgentRequest(requestText?: string | null) {
@@ -623,12 +663,21 @@ export function shouldAutoEscalateMasterAgentRequest(requestText?: string | null
function resolveMasterAgentExecutionMode(
agentControls?: ProjectAgentControls | null,
requestText?: string | null,
+ account?: AiAccount | null,
): MasterAgentExecutionModeResolution {
const storedAgentControls = agentControls ?? null;
- const currentModelOverride = normalizeAgentControlText(agentControls?.modelOverride);
+ const currentModelOverride = normalizeAgentControlModelForAccount(agentControls?.modelOverride, account);
const currentReasoningEffort = agentControls?.reasoningEffortOverride;
- const fastModelOverride = resolveConfiguredFastModel(agentControls);
- const deepModelOverride = resolveConfiguredDeepModel(agentControls);
+ const fastModelOverride = resolveConfiguredFastModel(agentControls, account);
+ const deepModelOverride = resolveConfiguredDeepModel(agentControls, account);
+ const effectiveStoredAgentControls: ProjectAgentControls | null = agentControls
+ ? {
+ ...agentControls,
+ modelOverride: currentModelOverride,
+ fastModelOverride,
+ deepModelOverride,
+ }
+ : null;
let activeMode: MasterAgentExecutionModeResolution["activeMode"] = "custom";
if (!currentModelOverride && !currentReasoningEffort) {
@@ -663,7 +712,7 @@ function resolveMasterAgentExecutionMode(
return {
storedAgentControls,
- effectiveAgentControls: storedAgentControls,
+ effectiveAgentControls: effectiveStoredAgentControls,
activeMode,
effectiveMode: activeMode,
fastPathEligible: activeMode === "fast",
@@ -1616,6 +1665,7 @@ function isApiCompatibleProvider(provider: AiProvider): provider is ApiCompatibl
return (
provider === "openai_api" ||
provider === "aliyun_qwen_api" ||
+ provider === "deepseek_api" ||
provider === "minimax_api" ||
provider === "glm_api" ||
provider === "hyzq_api" ||
@@ -2263,7 +2313,7 @@ async function queueAndStartOpenAiMasterAgentReply(params: {
taskId: params.taskId,
deviceId: candidate.deviceId,
accountId: candidate.account.accountId,
- accountLabel: candidate.account.label,
+ accountLabel: candidate.model,
});
}
@@ -2392,7 +2442,7 @@ async function enqueueOpenAiMasterAgentReply(params: {
requestedByAccount: params.requestedByAccount,
deviceId: primaryCandidate.deviceId,
accountId: primaryCandidate.account.accountId,
- accountLabel: primaryCandidate.account.label,
+ accountLabel: primaryCandidate.model,
...params.taskAuthorization,
relayViaMasterAgent: params.relayViaMasterAgent,
externalReplyTarget: params.externalReplyTarget,
@@ -3683,6 +3733,8 @@ export async function replyToMasterAgentUserMessage(params: {
const replyMetadata = buildMasterAgentModeMetadata(modeResolution);
const controlIntent = classifyMasterAgentControlIntent(params.requestText);
const relayViaMasterAgent = params.interactionMode === "takeover_single_thread";
+ const forcePrimaryApiExecution =
+ isApiCompatibleProvider(runtime.account.provider) && Boolean(runtime.account.apiKey?.trim());
const selectedMasterAccount = await resolveMasterNodeExecutionCandidate({
backendChoices,
runtimeAccount: runtime.account,
@@ -3700,13 +3752,16 @@ export async function replyToMasterAgentUserMessage(params: {
modeResolution,
backendOverride: executionConfig.agentControls?.backendOverride,
});
+ const selectedReplyBackendId = forcePrimaryApiExecution && apiExecutionCandidates.length > 0
+ ? "openai-api"
+ : selectedBackend.backendId;
const replyMode = resolveMasterAgentReplyMode({
requestedMode: params.mode,
selectedBackendId: preferApiExecutionForSmartMode && apiExecutionCandidates.length > 0
? apiExecutionCandidates[0]?.provider === "aliyun_qwen_api"
? "aliyun-qwen"
: "openai-api"
- : selectedBackend.backendId,
+ : selectedReplyBackendId,
apiCandidateCount: apiExecutionCandidates.length,
modeResolution,
});
@@ -4019,7 +4074,7 @@ export async function replyToMasterAgentUserMessage(params: {
if (
apiExecutionCandidates.length > 0 &&
- (preferApiExecutionForSmartMode || selectedBackend.backendId !== "master-codex-node")
+ (forcePrimaryApiExecution || preferApiExecutionForSmartMode || selectedBackend.backendId !== "master-codex-node")
) {
const queuedReply = await enqueueOpenAiMasterAgentReply({
candidates: apiExecutionCandidates,
@@ -4080,7 +4135,7 @@ export async function replyToMasterAgentUserMessage(params: {
}
}
- if (selectedBackend.backendId === "master-codex-node" && !preferApiExecutionForSmartMode) {
+ if (selectedBackend.backendId === "master-codex-node" && !preferApiExecutionForSmartMode && !forcePrimaryApiExecution) {
return runMasterNodeExecution();
}
@@ -4093,7 +4148,7 @@ export async function replyToMasterAgentUserMessage(params: {
requestText: params.requestText,
projectId: replyProjectId,
currentSessionExpiresAt: params.currentSessionExpiresAt,
- senderLabel: `主 Agent · ${candidate.account.label || aiRoleLabel(candidate.account.role)}`,
+ senderLabel: `主 Agent · ${candidate.model}`,
agentControls,
promptPolicy: executionConfig.promptPolicy,
userPrompt: executionConfig.userPrompt,
diff --git a/src/lib/boss-projections.ts b/src/lib/boss-projections.ts
index aa08d1e..109c3c5 100644
--- a/src/lib/boss-projections.ts
+++ b/src/lib/boss-projections.ts
@@ -363,6 +363,8 @@ function aiProviderLabel(provider: AiProvider) {
return "OpenAI API";
case "aliyun_qwen_api":
return "阿里百炼 Qwen";
+ case "deepseek_api":
+ return "DeepSeek API";
default:
return provider;
}
diff --git a/tests/ai-account-validation.test.ts b/tests/ai-account-validation.test.ts
index 11d5f5f..da07f7f 100644
--- a/tests/ai-account-validation.test.ts
+++ b/tests/ai-account-validation.test.ts
@@ -249,6 +249,68 @@ test("validateAiAccountConnection probes GLM accounts through chat completions",
}
});
+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();
diff --git a/tests/master-agent-openai-fallback.test.ts b/tests/master-agent-openai-fallback.test.ts
index 8b8853b..8bbe444 100644
--- a/tests/master-agent-openai-fallback.test.ts
+++ b/tests/master-agent-openai-fallback.test.ts
@@ -113,7 +113,7 @@ test("replyToMasterAgentUserMessage falls back to a runnable OpenAI API account
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.equal(reply?.senderLabel, "主 Agent · gpt-5.4");
assert.match(reply?.body ?? "", /主Agent链路正常/);
} finally {
globalThis.fetch = originalFetch;
@@ -194,6 +194,64 @@ test("replyToMasterAgentUserMessage can retry the same degraded API account when
}
});
+test("replyToMasterAgentUserMessage uses active DeepSeek API accounts directly", async () => {
+ await saveAiAccount({
+ accountId: "deepseek-primary",
+ label: "DeepSeek 主控",
+ role: "primary",
+ provider: "deepseek_api",
+ displayName: "DeepSeek V4 主链路",
+ model: "deepseek-v4-pro",
+ apiKey: "sk-deepseek-demo-123456",
+ enabled: true,
+ setActive: true,
+ loginStatusNote: "DeepSeek API 主链路。",
+ });
+
+ 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: "DeepSeek 主链路正常。",
+ },
+ },
+ ],
+ }), {
+ status: 200,
+ headers: {
+ "content-type": "application/json",
+ "x-request-id": "req-deepseek-primary",
+ },
+ });
+ }
+ throw new Error(`unexpected fetch: ${String(input)}`);
+ }) as typeof fetch;
+
+ try {
+ const result = await replyToMasterAgentUserMessage({
+ requestMessageId: "msg-deepseek-primary",
+ requestText: "请只回复:DeepSeek 主链路正常。",
+ requestedBy: "Boss 超级管理员",
+ requestedByAccount: "krisolo",
+ mode: "wait",
+ });
+
+ assert.equal(result.ok, true);
+ assert.equal(result.accountId, "deepseek-primary");
+ assert.equal(result.requestId, "req-deepseek-primary");
+
+ const state = await readState();
+ const reply = state.projects.find((project) => project.id === "master-agent")?.messages.at(-1);
+ assert.equal(reply?.senderLabel, "主 Agent · deepseek-v4-pro");
+ assert.match(reply?.body ?? "", /DeepSeek 主链路正常/);
+ } finally {
+ globalThis.fetch = originalFetch;
+ }
+});
+
test("replyToMasterAgentUserMessage falls back to a runnable aliyun qwen backup account when the master node is offline", async () => {
await saveAiAccount({
accountId: "master-codex-primary",
@@ -254,7 +312,7 @@ test("replyToMasterAgentUserMessage falls back to a runnable aliyun qwen backup
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 · 阿里备用");
+ assert.equal(reply?.senderLabel, "主 Agent · qwen3.5-plus");
assert.match(reply?.body ?? "", /阿里备用链路正常/);
} finally {
globalThis.fetch = originalFetch;