fix: route Pascal through multimodal model

This commit is contained in:
134 2026-07-11 22:59:56 +08:00
parent af3d17f4a2
commit 7bb1f06b11
4 changed files with 44 additions and 12 deletions

View File

@ -1,7 +1,7 @@
import { NextResponse } from "next/server";
import { getProviderDefaultBaseUrl } from "@/lib/ai/provider-defaults";
import { resolveModelRuntimeId } from "@/lib/ai/model-runtime";
import { getAgentAiModelWithProvider } from "@/lib/db/queries";
import { getMultimodalAiModelWithProvider } from "@/lib/db/queries";
import { createLogger } from "@/lib/observability/logger";
import { isPascalInternalRequest } from "@/lib/pascal/internal-auth";
@ -36,9 +36,9 @@ export async function GET(request: Request) {
return NextResponse.json({ error: "not_found" }, { status: 404 });
}
const configured = await getAgentAiModelWithProvider();
const configured = await getMultimodalAiModelWithProvider();
if (!configured) {
return NextResponse.json({ configured: false });
return NextResponse.json({ configured: false, selection: "multimodal" });
}
return NextResponse.json({
@ -47,6 +47,7 @@ export async function GET(request: Request) {
model: configured.model.displayName || configured.model.modelId,
provider: configured.provider.name,
providerType: configured.provider.type,
selection: "multimodal",
});
}
@ -66,15 +67,15 @@ export async function POST(request: Request) {
return openAiError("Invalid JSON body.", 400);
}
const configured = await getAgentAiModelWithProvider();
const configured = await getMultimodalAiModelWithProvider();
if (!configured) {
return openAiError("No enabled Agent text model is configured.", 503);
return openAiError("No enabled multimodal model is configured.", 503);
}
const { model, provider } = configured;
if (!OPENAI_COMPATIBLE_PROVIDER_TYPES.has(provider.type)) {
return openAiError(
`The configured Agent provider type '${provider.type}' is not OpenAI-compatible.`,
`The configured multimodal provider type '${provider.type}' is not OpenAI-compatible.`,
503
);
}
@ -85,7 +86,7 @@ export async function POST(request: Request) {
providerType: provider.type,
});
if (!baseUrl || !runtimeModelId || !provider.apiKey) {
return openAiError("The configured Agent model is incomplete.", 503);
return openAiError("The configured multimodal model is incomplete.", 503);
}
const startedAt = Date.now();
@ -122,6 +123,9 @@ export async function POST(request: Request) {
modelId: model.id,
providerId: provider.id,
});
return openAiError("The configured Agent model is temporarily unavailable.", 502);
return openAiError(
"The configured multimodal model is temporarily unavailable.",
502
);
}
}

View File

@ -110,8 +110,9 @@ include it inside the main HTTPS `server` block.
The private Pascal service points its OpenAI-compatible model base URL to
`/api/internal/pascal-agent/v1` on this application and authenticates with
`PASCAL_PROXY_SECRET`. That gateway resolves the current enabled Agent model
and provider from system settings on every request. OpenAI-compatible
`PASCAL_PROXY_SECRET`. On every request, that gateway resolves the enabled
model explicitly marked as `multimodalModel` and its provider from system
settings. It does not fall back to the Agent Auto model. OpenAI-compatible
`openai`, `custom`, `alibaba`, and `zhipu` providers work without copying their
API keys into the Pascal service.

View File

@ -1,7 +1,7 @@
# Pascal Editor 可复用生产部署
本项目把 Pascal Editor 作为独立 Bun/Next.js 服务运行,并通过主站 Nginx
同域挂载。部署脚本会复用主站登录态、系统设置中的 Agent 文本模型和主站
同域挂载。部署脚本会复用主站登录态、系统设置中显式标记的“多模态模型”和主站
Git 仓库里的 `pascal-editor-ai-agent` 独立分支。
## 默认结构
@ -72,7 +72,7 @@ sudo env \
sudo env PASCAL_SMOKE_CONFIRM=1 pnpm pascal:smoke
```
真实冒烟会调用当前系统设置中的 Agent 模型,因此默认不会在一键部署时
真实冒烟会调用当前系统设置中显式标记的“多模态模型”,因此默认不会在一键部署时
执行。需要每次部署自动执行时设置 `RUN_AGENT_SMOKE_TEST=true`。
## 常用覆盖项

View File

@ -4782,6 +4782,33 @@ export async function getAgentAiModelWithProvider() {
return candidates[0];
}
export async function getMultimodalAiModelWithProvider() {
const models = await getEnabledAiModelsWithProvider(false);
const healthPriority = (status?: string | null) => {
if (status === "healthy") return 0;
if (status === "degraded") return 1;
if (status === "auto_disabled") return 2;
return 3;
};
const candidates = models
.filter(
({ model }) =>
isAiModelMultimodal(model) && model.healthStatus !== "auto_disabled"
)
.sort((a, b) => {
const byHealth =
healthPriority(a.model.healthStatus) -
healthPriority(b.model.healthStatus);
if (byHealth !== 0) return byHealth;
if (a.model.isDefault !== b.model.isDefault) {
return Number(b.model.isDefault) - Number(a.model.isDefault);
}
return (a.model.sortOrder ?? 0) - (b.model.sortOrder ?? 0);
});
return candidates[0];
}
/**
* 🆕 获取指定父模型的所有子模型
* 用于火山引擎视频等需要智能选择模型的场景