mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
fix(test): use POST /v1/messages to validate anthropic-compatible connections
GET /models is not part of the Anthropic API spec and many compatible proxies do not implement it, causing the connection test to always fail even with a valid API key. Switch to POST /v1/messages with max_tokens=1 — the same approach used for the built-in anthropic provider — and treat any non-401/403 response as valid, since 400/529 still confirms the key was accepted. Use node.defaultModel / connection.defaultModel when set so the test respects the configured model rather than always falling back to claude-3-haiku-20240307. Co-authored-by: Rehan Choirul <rehanchrl@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
decolua
co-authored by
Cursor
parent
6c10edf8ba
commit
584cf66a70
@@ -355,10 +355,25 @@ async function testApiKeyConnection(connection, effectiveProxy = null) {
|
|||||||
try {
|
try {
|
||||||
modelsBase = modelsBase.replace(/\/$/, "");
|
modelsBase = modelsBase.replace(/\/$/, "");
|
||||||
if (modelsBase.endsWith("/messages")) modelsBase = modelsBase.slice(0, -9);
|
if (modelsBase.endsWith("/messages")) modelsBase = modelsBase.slice(0, -9);
|
||||||
const res = await fetchWithConnectionProxy(`${modelsBase}/models`, {
|
const messagesUrl = `${modelsBase}/v1/messages`;
|
||||||
headers: { "x-api-key": connection.apiKey, "anthropic-version": "2023-06-01", "Authorization": `Bearer ${connection.apiKey}` },
|
const model = connection.defaultModel || "claude-3-haiku-20240307";
|
||||||
|
const res = await fetchWithConnectionProxy(messagesUrl, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"x-api-key": connection.apiKey,
|
||||||
|
"anthropic-version": "2023-06-01",
|
||||||
|
"content-type": "application/json",
|
||||||
|
"Authorization": `Bearer ${connection.apiKey}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model,
|
||||||
|
max_tokens: 1,
|
||||||
|
messages: [{ role: "user", content: "test" }],
|
||||||
|
}),
|
||||||
}, effectiveProxy);
|
}, effectiveProxy);
|
||||||
return { valid: res.ok, error: res.ok ? null : "Invalid API key or base URL" };
|
// 400/529 still confirms key accepted; only 401/403 = bad key
|
||||||
|
const valid = res.status !== 401 && res.status !== 403;
|
||||||
|
return { valid, error: valid ? null : "Invalid API key or base URL" };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return { valid: false, error: err.message };
|
return { valid: false, error: err.message };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,17 +155,26 @@ export async function POST(request) {
|
|||||||
normalizedBase = normalizedBase.slice(0, -9); // remove /messages
|
normalizedBase = normalizedBase.slice(0, -9); // remove /messages
|
||||||
}
|
}
|
||||||
|
|
||||||
const modelsUrl = `${normalizedBase}/models`;
|
const messagesUrl = `${normalizedBase}/v1/messages`;
|
||||||
|
const model = node.defaultModel || "claude-3-haiku-20240307";
|
||||||
|
|
||||||
const res = await fetch(modelsUrl, {
|
const res = await fetch(messagesUrl, {
|
||||||
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"x-api-key": apiKey,
|
"x-api-key": apiKey,
|
||||||
"anthropic-version": "2023-06-01",
|
"anthropic-version": "2023-06-01",
|
||||||
"Authorization": `Bearer ${apiKey}`
|
"content-type": "application/json",
|
||||||
|
"Authorization": `Bearer ${apiKey}`,
|
||||||
},
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model,
|
||||||
|
max_tokens: 1,
|
||||||
|
messages: [{ role: "user", content: "test" }],
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
isValid = res.ok;
|
// 400/529 still confirms key accepted; only 401/403 = bad key
|
||||||
|
isValid = res.status !== 401 && res.status !== 403;
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
valid: isValid,
|
valid: isValid,
|
||||||
error: isValid ? null : "Invalid API key",
|
error: isValid ? null : "Invalid API key",
|
||||||
|
|||||||
Reference in New Issue
Block a user