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:
@@ -355,10 +355,25 @@ async function testApiKeyConnection(connection, effectiveProxy = null) {
|
||||
try {
|
||||
modelsBase = modelsBase.replace(/\/$/, "");
|
||||
if (modelsBase.endsWith("/messages")) modelsBase = modelsBase.slice(0, -9);
|
||||
const res = await fetchWithConnectionProxy(`${modelsBase}/models`, {
|
||||
headers: { "x-api-key": connection.apiKey, "anthropic-version": "2023-06-01", "Authorization": `Bearer ${connection.apiKey}` },
|
||||
const messagesUrl = `${modelsBase}/v1/messages`;
|
||||
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);
|
||||
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) {
|
||||
return { valid: false, error: err.message };
|
||||
}
|
||||
|
||||
@@ -155,17 +155,26 @@ export async function POST(request) {
|
||||
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: {
|
||||
"x-api-key": apiKey,
|
||||
"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({
|
||||
valid: isValid,
|
||||
error: isValid ? null : "Invalid API key",
|
||||
|
||||
Reference in New Issue
Block a user