feat: support deepseek api for master agent

This commit is contained in:
AI Bot
2026-05-12 12:52:47 +08:00
parent 4de64ac01c
commit 1c1140b1fd
11 changed files with 246 additions and 23 deletions

View File

@@ -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" ||

View File

@@ -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" ||

View File

@@ -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" ||

View File

@@ -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) ? (
<div className="col-span-2">
<AccountField
label={`API Key${account.apiKeyMasked ? `(已配置 ${account.apiKeyMasked}` : ""}`}
@@ -688,7 +705,9 @@ export function AiAccountsClient({
? "留空则保持现有 Key"
: draft.provider === "aliyun_qwen_api"
? "输入阿里百炼 API Key"
: "输入 OpenAI API Key"
: draft.provider === "deepseek_api"
? "输入 DeepSeek API Key"
: "输入 API Key"
}
type="password"
/>

View File

@@ -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" ||

View File

@@ -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<ApiCompatibleProvider, string[]> = {
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<ApiCompatibleProvider, string[]> = {
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,

View File

@@ -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;
}