feat: Add Anthropic Compatible provider support

- Added support for 'anthropic-compatible' provider nodes in backend.
- Implemented isAnthropicCompatible logic in open-sse for /messages URL construction and headers.
- Added UI for creating and managing Anthropic Compatible providers in the dashboard.
- Updated validation logic for Anthropic-compatible endpoints.
- Sanitize base URL input (strip trailing /messages) to prevent 404s and improve UX.
- Improve validation: use GET /models (2xx success), and support x-api-key / Authorization Bearer hybrid proxies.
- Enable model import via /models for Anthropic Compatible providers.
- Ensure Authorization is omitted when x-api-key is present to avoid strict proxy conflicts.
- Resolve Anthropic-compatible credentials by prefix during model resolution (e.g., acx/model).
- Update default executor to match provider header/url behavior for Anthropic-compatible providers.
This commit is contained in:
ramhaidar
2026-02-03 15:11:41 +07:00
parent 7881db81ec
commit da5bdef4cb
13 changed files with 614 additions and 154 deletions
+29 -1
View File
@@ -1,6 +1,6 @@
import { NextResponse } from "next/server";
import { getProviderNodeById } from "@/models";
import { isOpenAICompatibleProvider } from "@/shared/constants/providers";
import { isOpenAICompatibleProvider, isAnthropicCompatibleProvider } from "@/shared/constants/providers";
// POST /api/providers/validate - Validate API key with provider
export async function POST(request) {
@@ -33,6 +33,34 @@ export async function POST(request) {
});
}
if (isAnthropicCompatibleProvider(provider)) {
const node = await getProviderNodeById(provider);
if (!node) {
return NextResponse.json({ error: "Anthropic Compatible node not found" }, { status: 404 });
}
let normalizedBase = node.baseUrl?.trim().replace(/\/$/, "") || "";
if (normalizedBase.endsWith("/messages")) {
normalizedBase = normalizedBase.slice(0, -9); // remove /messages
}
const modelsUrl = `${normalizedBase}/models`;
const res = await fetch(modelsUrl, {
headers: {
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
"Authorization": `Bearer ${apiKey}`
},
});
isValid = res.ok;
return NextResponse.json({
valid: isValid,
error: isValid ? null : "Invalid API key",
});
}
switch (provider) {
case "openai":
const openaiRes = await fetch("https://api.openai.com/v1/models", {