mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-17 20:52:15 +03:00
269 lines
10 KiB
TypeScript
269 lines
10 KiB
TypeScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { resolveAlternateFormat } from "../../open-sse/config/providers/alternateFormats.ts";
|
|
import type { RegistryEntry } from "../../open-sse/config/providers/shared.ts";
|
|
import { getTargetFormat } from "../../open-sse/services/provider.ts";
|
|
import { DefaultExecutor } from "../../open-sse/executors/default.ts";
|
|
import { FORMATS } from "../../open-sse/translator/formats.ts";
|
|
import { translateRequest } from "../../open-sse/translator/index.ts";
|
|
import { getAlternateFormats } from "../../src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts";
|
|
|
|
const ENTRY: RegistryEntry = {
|
|
id: "demo",
|
|
format: "openai",
|
|
executor: "default",
|
|
authType: "apikey",
|
|
authHeader: "bearer",
|
|
baseUrl: "https://example.com/v1",
|
|
models: [],
|
|
alternateFormats: [
|
|
{
|
|
format: "claude",
|
|
baseUrl: "https://example.com/anthropic/v1/messages",
|
|
authHeader: "x-api-key",
|
|
headers: { "Anthropic-Version": "2023-06-01" },
|
|
label: "Anthropic-compatible",
|
|
},
|
|
],
|
|
};
|
|
|
|
test("retorna a alternativa quando targetFormat da conexao casa", () => {
|
|
const alt = resolveAlternateFormat(ENTRY, { targetFormat: "claude" });
|
|
assert.equal(alt?.format, "claude");
|
|
assert.equal(alt?.authHeader, "x-api-key");
|
|
});
|
|
|
|
test("retorna null quando targetFormat nao casa com nenhuma alternativa", () => {
|
|
assert.equal(resolveAlternateFormat(ENTRY, { targetFormat: "gemini" }), null);
|
|
});
|
|
|
|
test("retorna null quando a conexao nao tem targetFormat", () => {
|
|
assert.equal(resolveAlternateFormat(ENTRY, {}), null);
|
|
assert.equal(resolveAlternateFormat(ENTRY, null), null);
|
|
assert.equal(resolveAlternateFormat(ENTRY, undefined), null);
|
|
});
|
|
|
|
test("retorna null quando a entry nao declara alternativas", () => {
|
|
assert.equal(
|
|
resolveAlternateFormat({ ...ENTRY, alternateFormats: undefined }, { targetFormat: "claude" }),
|
|
null
|
|
);
|
|
assert.equal(resolveAlternateFormat(null, { targetFormat: "claude" }), null);
|
|
});
|
|
|
|
test("ignora targetFormat que nao e string nao-vazia", () => {
|
|
assert.equal(resolveAlternateFormat(ENTRY, { targetFormat: 42 }), null);
|
|
assert.equal(resolveAlternateFormat(ENTRY, { targetFormat: "" }), null);
|
|
});
|
|
|
|
// Task 2: getTargetFormat honra o override da conexao.
|
|
test("getTargetFormat: sem override da conexao usa o formato padrao do registry", () => {
|
|
assert.equal(getTargetFormat("xiaomi-mimo", null), "openai");
|
|
});
|
|
|
|
test("getTargetFormat: override da conexao troca o formato quando declarado", () => {
|
|
assert.equal(getTargetFormat("xiaomi-mimo", { targetFormat: "claude" }), "claude");
|
|
});
|
|
|
|
test("getTargetFormat: override desconhecido cai no formato padrao", () => {
|
|
assert.equal(getTargetFormat("xiaomi-mimo", { targetFormat: "gemini" }), "openai");
|
|
});
|
|
|
|
// Task 3: resolucao de base URL honra a alternativa.
|
|
//
|
|
// Reproduz a precedencia implementada em BaseExecutor.resolveBaseUrl. Nao
|
|
// instanciamos o executor real aqui porque getRegistryEntry() le do registry
|
|
// estatico de providers (chaveado por provider id) e nenhuma entry real
|
|
// declara alternateFormats ainda (isso e a Task 5) — nao ha como injetar uma
|
|
// entry fake no registry sem sair do escopo desta task. O contrato de
|
|
// precedencia (manual > alternativa > default) e o mesmo aplicado no
|
|
// producao; tests/unit/refactor-resolveBaseUrl.test.ts ja cobre o caminho
|
|
// real (instanciando BaseExecutor) para os casos sem alternativa, e
|
|
// permanece verde apos a mudanca desta task.
|
|
function precedence(psd: unknown, entry: unknown, configBaseUrl: string) {
|
|
const psdBaseUrl = (psd as { baseUrl?: unknown } | null)?.baseUrl;
|
|
if (typeof psdBaseUrl === "string" && psdBaseUrl) return psdBaseUrl;
|
|
const alt = resolveAlternateFormat(entry as never, psd);
|
|
if (alt?.baseUrl) return alt.baseUrl;
|
|
return configBaseUrl;
|
|
}
|
|
|
|
const ENTRY_WITH_ALT = {
|
|
alternateFormats: [
|
|
{
|
|
format: "claude",
|
|
baseUrl: "https://alt.example.com/anthropic/v1/messages",
|
|
label: "Anthropic",
|
|
},
|
|
],
|
|
} as never;
|
|
|
|
test("resolveBaseUrl: baseUrl manual da conexao vence a alternativa", () => {
|
|
const url = precedence(
|
|
{ baseUrl: "https://manual.example.com/v1", targetFormat: "claude" },
|
|
ENTRY_WITH_ALT,
|
|
"https://default.example.com/v1"
|
|
);
|
|
assert.equal(url, "https://manual.example.com/v1");
|
|
});
|
|
|
|
test("resolveBaseUrl: alternativa vence o baseUrl padrao", () => {
|
|
const url = precedence(
|
|
{ targetFormat: "claude" },
|
|
ENTRY_WITH_ALT,
|
|
"https://default.example.com/v1"
|
|
);
|
|
assert.equal(url, "https://alt.example.com/anthropic/v1/messages");
|
|
});
|
|
|
|
test("resolveBaseUrl: sem override usa o baseUrl padrao", () => {
|
|
const url = precedence({}, ENTRY_WITH_ALT, "https://default.example.com/v1");
|
|
assert.equal(url, "https://default.example.com/v1");
|
|
});
|
|
|
|
// Task 4: auth header e headers extras honram a alternativa.
|
|
//
|
|
// Mesma limitacao da Task 3: nenhuma entry real do registry declara
|
|
// alternateFormats ainda, entao reproduzimos a escolha de authHeader
|
|
// implementada em DefaultExecutor.buildHeaders (default.ts) sem instanciar o
|
|
// executor inteiro. O teste de regressao abaixo (via DefaultExecutor real)
|
|
// cobre o caminho sem alternativa para garantir que a nova chamada a
|
|
// resolveAlternateFormat nao alterou o comportamento por-default existente.
|
|
function pickAuthHeader(entry: unknown, psd: unknown) {
|
|
const alt = resolveAlternateFormat(entry as never, psd);
|
|
return alt?.authHeader || (entry as { authHeader?: string } | null)?.authHeader || "bearer";
|
|
}
|
|
|
|
const ENTRY_AUTH = {
|
|
authHeader: "bearer",
|
|
alternateFormats: [
|
|
{
|
|
format: "claude",
|
|
baseUrl: "https://alt.example.com/anthropic/v1/messages",
|
|
authHeader: "x-api-key",
|
|
headers: { "Anthropic-Version": "2023-06-01" },
|
|
label: "Anthropic",
|
|
},
|
|
],
|
|
} as never;
|
|
|
|
test("authHeader: formato alternativo troca bearer por x-api-key", () => {
|
|
assert.equal(pickAuthHeader(ENTRY_AUTH, { targetFormat: "claude" }), "x-api-key");
|
|
});
|
|
|
|
test("authHeader: sem override mantem o header da entry", () => {
|
|
assert.equal(pickAuthHeader(ENTRY_AUTH, {}), "bearer");
|
|
});
|
|
|
|
test("alternativa carrega headers extras do protocolo", () => {
|
|
const alt = resolveAlternateFormat(ENTRY_AUTH, { targetFormat: "claude" });
|
|
assert.equal(alt?.headers?.["Anthropic-Version"], "2023-06-01");
|
|
});
|
|
|
|
// Regression via producao real: com um targetFormat que NAO casa com nenhuma
|
|
// alternativa declarada, buildHeaders cai no authHeader "bearer" padrao da
|
|
// entry, provando que a nova chamada a resolveAlternateFormat nao regrediu o
|
|
// caminho default. (Ate a Task 5, xiaomi-mimo nao declarava alternateFormats
|
|
// nenhuma — agora declara a variante "claude", ver
|
|
// tests/unit/xiaomi-providers-registry.test.ts para a cobertura end-to-end
|
|
// do caminho COM alternativa, incluindo o caso "claude" que este teste
|
|
// cobria antes.)
|
|
test("DefaultExecutor.buildHeaders: targetFormat que nao casa mantem o authHeader padrao", () => {
|
|
const executor = new DefaultExecutor("xiaomi-mimo");
|
|
const headers = executor.buildHeaders(
|
|
{
|
|
apiKey: "sk-test",
|
|
providerSpecificData: { targetFormat: "gemini" },
|
|
} as never,
|
|
true
|
|
) as Record<string, string>;
|
|
assert.equal(headers["Authorization"], "Bearer sk-test");
|
|
assert.equal(headers["x-api-key"], undefined);
|
|
});
|
|
|
|
test("getAlternateFormats: provedor com alternativas retorna a lista", () => {
|
|
const list = getAlternateFormats("xiaomi-mimo");
|
|
assert.equal(list.length, 1);
|
|
assert.equal(list[0].format, "claude");
|
|
});
|
|
|
|
test("getAlternateFormats: provedor sem alternativas retorna lista vazia", () => {
|
|
assert.deepEqual(getAlternateFormats("xai"), []);
|
|
assert.deepEqual(getAlternateFormats(null), []);
|
|
assert.deepEqual(getAlternateFormats(undefined), []);
|
|
});
|
|
|
|
test("DeepSeek defaults to Responses and exposes the official Anthropic endpoint", () => {
|
|
assert.equal(getTargetFormat("deepseek", null), "openai-responses");
|
|
assert.equal(getTargetFormat("deepseek", { targetFormat: "claude" }), "claude");
|
|
|
|
const defaultExecutor = new DefaultExecutor("deepseek");
|
|
assert.equal(
|
|
defaultExecutor.buildUrl("deepseek-v4-pro", true, 0, { apiKey: "sk-test" } as never),
|
|
"https://api.deepseek.com/responses"
|
|
);
|
|
const defaultHeaders = defaultExecutor.buildHeaders({ apiKey: "sk-test" } as never, true);
|
|
assert.equal(defaultHeaders.Authorization, "Bearer sk-test");
|
|
|
|
const anthropicCredentials = {
|
|
apiKey: "sk-test",
|
|
providerSpecificData: { targetFormat: "claude" },
|
|
} as never;
|
|
assert.equal(
|
|
defaultExecutor.buildUrl("deepseek-v4-pro", true, 0, anthropicCredentials),
|
|
"https://api.deepseek.com/anthropic/v1/messages"
|
|
);
|
|
const anthropicHeaders = defaultExecutor.buildHeaders(anthropicCredentials, true);
|
|
assert.equal(anthropicHeaders["x-api-key"], "sk-test");
|
|
assert.equal(typeof anthropicHeaders["Anthropic-Version"], "string");
|
|
|
|
const alternates = getAlternateFormats("deepseek");
|
|
assert.equal(alternates.length, 1);
|
|
assert.equal(alternates[0].format, "claude");
|
|
});
|
|
|
|
test("DeepSeek reuses the generic Chat-to-Responses and Responses-to-Anthropic translators", () => {
|
|
const responsesBody = translateRequest(
|
|
FORMATS.OPENAI,
|
|
FORMATS.OPENAI_RESPONSES,
|
|
"deepseek-v4-pro",
|
|
{
|
|
model: "deepseek-v4-pro",
|
|
messages: [{ role: "user", content: "hello" }],
|
|
max_tokens: 123,
|
|
stream: true,
|
|
},
|
|
true,
|
|
{},
|
|
"deepseek"
|
|
) as Record<string, unknown>;
|
|
assert.equal(responsesBody.messages, undefined);
|
|
assert.equal(responsesBody.max_output_tokens, 123);
|
|
assert.deepEqual(responsesBody.input, [
|
|
{
|
|
type: "message",
|
|
role: "user",
|
|
content: [{ type: "input_text", text: "hello" }],
|
|
status: "completed",
|
|
},
|
|
]);
|
|
|
|
const anthropicBody = translateRequest(
|
|
FORMATS.OPENAI_RESPONSES,
|
|
FORMATS.CLAUDE,
|
|
"deepseek-v4-pro",
|
|
{
|
|
model: "deepseek-v4-pro",
|
|
input: [{ role: "user", content: [{ type: "input_text", text: "hello" }] }],
|
|
stream: true,
|
|
},
|
|
true,
|
|
{},
|
|
"deepseek"
|
|
) as Record<string, unknown>;
|
|
assert.equal(anthropicBody.input, undefined);
|
|
assert.deepEqual(anthropicBody.messages, [
|
|
{ role: "user", content: [{ type: "text", text: "hello" }] },
|
|
]);
|
|
});
|