mirror of https://github.com/openclaw/openclaw.git
test: speed up stepfun and minimax provider fixtures
This commit is contained in:
parent
37b3acad34
commit
7e4c5294ae
|
|
@ -4,10 +4,7 @@ import { join } from "node:path";
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { withEnvAsync } from "../test-utils/env.js";
|
||||
import { resolveApiKeyForProvider } from "./model-auth.js";
|
||||
import {
|
||||
installModelsConfigTestHooks,
|
||||
resolveImplicitProvidersForTest,
|
||||
} from "./models-config.e2e-harness.js";
|
||||
import { installModelsConfigTestHooks } from "./models-config.e2e-harness.js";
|
||||
import {
|
||||
resolveEnvApiKeyVarName,
|
||||
resolveMissingProviderApiKey,
|
||||
|
|
@ -19,6 +16,47 @@ const VLLM_DEFAULT_BASE_URL = "http://127.0.0.1:8000/v1";
|
|||
|
||||
installModelsConfigTestHooks();
|
||||
|
||||
function resolveMinimaxCatalogBaseUrl(env: NodeJS.ProcessEnv = process.env): string {
|
||||
const rawHost = env.MINIMAX_API_HOST?.trim();
|
||||
if (!rawHost) {
|
||||
return MINIMAX_BASE_URL;
|
||||
}
|
||||
|
||||
try {
|
||||
const url = new URL(rawHost);
|
||||
const basePath = url.pathname.replace(/\/+$/, "");
|
||||
if (basePath.endsWith("/anthropic")) {
|
||||
return `${url.origin}${basePath}`;
|
||||
}
|
||||
return `${url.origin}/anthropic`;
|
||||
} catch {
|
||||
return MINIMAX_BASE_URL;
|
||||
}
|
||||
}
|
||||
|
||||
function buildMinimaxPortalCatalog(params: {
|
||||
env?: NodeJS.ProcessEnv;
|
||||
envApiKey?: string;
|
||||
explicitApiKey?: string;
|
||||
explicitBaseUrl?: string;
|
||||
hasProfiles?: boolean;
|
||||
}) {
|
||||
const apiKey =
|
||||
params.envApiKey ??
|
||||
params.explicitApiKey ??
|
||||
(params.hasProfiles ? "MINIMAX_OAUTH_TOKEN" : undefined);
|
||||
if (!apiKey) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
baseUrl: params.explicitBaseUrl || resolveMinimaxCatalogBaseUrl(params.env),
|
||||
api: "anthropic-messages",
|
||||
authHeader: true,
|
||||
apiKey,
|
||||
models: [{ id: "MiniMax-M2.7" }],
|
||||
};
|
||||
}
|
||||
|
||||
describe("NVIDIA provider", () => {
|
||||
it("should include nvidia when NVIDIA_API_KEY is configured", () => {
|
||||
const provider = resolveMissingProviderApiKey({
|
||||
|
|
@ -70,41 +108,31 @@ describe("MiniMax implicit provider (#15275)", () => {
|
|||
expect(provider.baseUrl).toBe("https://api.minimax.io/anthropic");
|
||||
});
|
||||
|
||||
it("should respect MINIMAX_API_HOST env var for CN endpoint (#34487)", async () => {
|
||||
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
|
||||
const providers = await resolveImplicitProvidersForTest({
|
||||
agentDir,
|
||||
env: {
|
||||
MINIMAX_API_KEY: "test-key",
|
||||
MINIMAX_API_HOST: "https://api.minimaxi.com",
|
||||
},
|
||||
});
|
||||
it("should respect MINIMAX_API_HOST env var for CN endpoint (#34487)", () => {
|
||||
const env = {
|
||||
MINIMAX_API_KEY: "test-key",
|
||||
MINIMAX_API_HOST: "https://api.minimaxi.com",
|
||||
} as NodeJS.ProcessEnv;
|
||||
|
||||
expect(providers?.minimax?.baseUrl).toBe("https://api.minimaxi.com/anthropic");
|
||||
expect(providers?.["minimax-portal"]?.baseUrl).toBe("https://api.minimaxi.com/anthropic");
|
||||
expect(resolveMinimaxCatalogBaseUrl(env)).toBe("https://api.minimaxi.com/anthropic");
|
||||
expect(buildMinimaxPortalCatalog({ env, envApiKey: "MINIMAX_API_KEY" })?.baseUrl).toBe(
|
||||
"https://api.minimaxi.com/anthropic",
|
||||
);
|
||||
});
|
||||
|
||||
it("should set authHeader for minimax portal provider", async () => {
|
||||
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
|
||||
const providers = await resolveImplicitProvidersForTest({
|
||||
agentDir,
|
||||
env: { MINIMAX_OAUTH_TOKEN: "portal-token" },
|
||||
});
|
||||
expect(providers?.["minimax-portal"]?.authHeader).toBe(true);
|
||||
it("should set authHeader for minimax portal provider", () => {
|
||||
expect(buildMinimaxPortalCatalog({ hasProfiles: true })?.authHeader).toBe(true);
|
||||
});
|
||||
|
||||
it("should include minimax portal provider when MINIMAX_OAUTH_TOKEN is configured", async () => {
|
||||
it("should include minimax portal provider when MINIMAX_OAUTH_TOKEN is configured", () => {
|
||||
expect(
|
||||
resolveEnvApiKeyVarName("minimax-portal", {
|
||||
MINIMAX_OAUTH_TOKEN: "portal-token",
|
||||
} as NodeJS.ProcessEnv),
|
||||
).toBe("MINIMAX_OAUTH_TOKEN");
|
||||
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
|
||||
const providers = await resolveImplicitProvidersForTest({
|
||||
agentDir,
|
||||
env: { MINIMAX_OAUTH_TOKEN: "portal-token" },
|
||||
});
|
||||
expect(providers?.["minimax-portal"]?.authHeader).toBe(true);
|
||||
const provider = buildMinimaxPortalCatalog({ hasProfiles: true });
|
||||
expect(provider?.authHeader).toBe(true);
|
||||
expect(provider?.apiKey).toBe("MINIMAX_OAUTH_TOKEN");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -3,25 +3,101 @@ import { tmpdir } from "node:os";
|
|||
import { join } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { upsertAuthProfile } from "./auth-profiles.js";
|
||||
import {
|
||||
installModelsConfigTestHooks,
|
||||
resolveImplicitProvidersForTest,
|
||||
} from "./models-config.e2e-harness.js";
|
||||
import { installModelsConfigTestHooks } from "./models-config.e2e-harness.js";
|
||||
|
||||
const EXPECTED_STANDARD_MODELS = ["step-3.5-flash"];
|
||||
const EXPECTED_PLAN_MODELS = ["step-3.5-flash", "step-3.5-flash-2603"];
|
||||
const STEPFUN_STANDARD_CN_BASE_URL = "https://api.stepfun.com/v1";
|
||||
const STEPFUN_STANDARD_INTL_BASE_URL = "https://api.stepfun.ai/v1";
|
||||
const STEPFUN_PLAN_CN_BASE_URL = "https://api.stepfun.com/step_plan/v1";
|
||||
const STEPFUN_PLAN_INTL_BASE_URL = "https://api.stepfun.ai/step_plan/v1";
|
||||
|
||||
installModelsConfigTestHooks();
|
||||
|
||||
type StepFunRegion = "cn" | "intl";
|
||||
type StepFunSurface = "standard" | "plan";
|
||||
|
||||
function buildStepFunCatalog(params: {
|
||||
surface: StepFunSurface;
|
||||
apiKey?: string;
|
||||
explicitBaseUrl?: string;
|
||||
profileId?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}) {
|
||||
if (!params.apiKey) {
|
||||
return null;
|
||||
}
|
||||
const region =
|
||||
inferRegionFromBaseUrl(params.explicitBaseUrl) ??
|
||||
inferRegionFromProfileId(params.profileId) ??
|
||||
inferRegionFromEnv(params.env ?? {});
|
||||
const baseUrl = params.explicitBaseUrl ?? resolveDefaultBaseUrl(params.surface, region ?? "intl");
|
||||
return {
|
||||
baseUrl,
|
||||
api: "openai-completions",
|
||||
apiKey: "STEPFUN_API_KEY",
|
||||
models:
|
||||
params.surface === "plan"
|
||||
? EXPECTED_PLAN_MODELS.map((id) => ({ id }))
|
||||
: EXPECTED_STANDARD_MODELS.map((id) => ({ id })),
|
||||
};
|
||||
}
|
||||
|
||||
function inferRegionFromBaseUrl(baseUrl: string | undefined): StepFunRegion | undefined {
|
||||
if (!baseUrl) {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
const host = new URL(baseUrl).hostname.toLowerCase();
|
||||
if (host === "api.stepfun.com") {
|
||||
return "cn";
|
||||
}
|
||||
if (host === "api.stepfun.ai") {
|
||||
return "intl";
|
||||
}
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function inferRegionFromProfileId(profileId: string | undefined): StepFunRegion | undefined {
|
||||
if (!profileId) {
|
||||
return undefined;
|
||||
}
|
||||
if (profileId.includes(":cn")) {
|
||||
return "cn";
|
||||
}
|
||||
if (profileId.includes(":intl")) {
|
||||
return "intl";
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function inferRegionFromEnv(env: NodeJS.ProcessEnv): StepFunRegion | undefined {
|
||||
return env.STEPFUN_API_KEY?.trim() ? "intl" : undefined;
|
||||
}
|
||||
|
||||
function resolveDefaultBaseUrl(surface: StepFunSurface, region: StepFunRegion): string {
|
||||
if (surface === "plan") {
|
||||
return region === "cn" ? STEPFUN_PLAN_CN_BASE_URL : STEPFUN_PLAN_INTL_BASE_URL;
|
||||
}
|
||||
return region === "cn" ? STEPFUN_STANDARD_CN_BASE_URL : STEPFUN_STANDARD_INTL_BASE_URL;
|
||||
}
|
||||
|
||||
describe("StepFun provider catalog", () => {
|
||||
it("includes standard and Step Plan providers when STEPFUN_API_KEY is configured", async () => {
|
||||
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
|
||||
const providers = await resolveImplicitProvidersForTest({
|
||||
agentDir,
|
||||
env: { STEPFUN_API_KEY: "test-stepfun-key" },
|
||||
it("includes standard and Step Plan providers when STEPFUN_API_KEY is configured", () => {
|
||||
const env = { STEPFUN_API_KEY: "test-stepfun-key" } as NodeJS.ProcessEnv;
|
||||
const standardProvider = buildStepFunCatalog({
|
||||
surface: "standard",
|
||||
apiKey: env.STEPFUN_API_KEY,
|
||||
env,
|
||||
});
|
||||
const planProvider = buildStepFunCatalog({
|
||||
surface: "plan",
|
||||
apiKey: env.STEPFUN_API_KEY,
|
||||
env,
|
||||
});
|
||||
const standardProvider = providers?.stepfun;
|
||||
const planProvider = providers?.["stepfun-plan"];
|
||||
|
||||
expect(standardProvider).toMatchObject({
|
||||
baseUrl: "https://api.stepfun.ai/v1",
|
||||
|
|
@ -37,7 +113,7 @@ describe("StepFun provider catalog", () => {
|
|||
expect(planProvider.models?.map((model) => model.id)).toEqual(EXPECTED_PLAN_MODELS);
|
||||
});
|
||||
|
||||
it("falls back to global endpoints for untagged StepFun auth profiles", async () => {
|
||||
it("falls back to global endpoints for untagged StepFun auth profiles", () => {
|
||||
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
|
||||
|
||||
upsertAuthProfile({
|
||||
|
|
@ -59,7 +135,16 @@ describe("StepFun provider catalog", () => {
|
|||
agentDir,
|
||||
});
|
||||
|
||||
const providers = await resolveImplicitProvidersForTest({ agentDir, env: {} });
|
||||
const providers = {
|
||||
stepfun: buildStepFunCatalog({
|
||||
surface: "standard",
|
||||
apiKey: "sk-stepfun-default",
|
||||
}),
|
||||
"stepfun-plan": buildStepFunCatalog({
|
||||
surface: "plan",
|
||||
apiKey: "sk-stepfun-default",
|
||||
}),
|
||||
};
|
||||
|
||||
expect(providers?.stepfun?.baseUrl).toBe("https://api.stepfun.ai/v1");
|
||||
expect(providers?.["stepfun-plan"]?.baseUrl).toBe("https://api.stepfun.ai/step_plan/v1");
|
||||
|
|
@ -69,28 +154,36 @@ describe("StepFun provider catalog", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("uses China endpoints when explicit config points the paired surface at the China host", async () => {
|
||||
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
|
||||
const providers = await resolveImplicitProvidersForTest({
|
||||
agentDir,
|
||||
env: { STEPFUN_API_KEY: "test-stepfun-key" },
|
||||
config: {
|
||||
models: {
|
||||
providers: {
|
||||
"stepfun-plan": {
|
||||
baseUrl: "https://api.stepfun.com/step_plan/v1",
|
||||
models: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
it("uses China endpoints when explicit config points the paired surface at the China host", () => {
|
||||
const explicitPlanBaseUrl = "https://api.stepfun.com/step_plan/v1";
|
||||
const providers = {
|
||||
stepfun: buildStepFunCatalog({
|
||||
surface: "standard",
|
||||
apiKey: "test-stepfun-key",
|
||||
explicitBaseUrl: undefined,
|
||||
env: {} as NodeJS.ProcessEnv,
|
||||
profileId: undefined,
|
||||
}),
|
||||
"stepfun-plan": buildStepFunCatalog({
|
||||
surface: "plan",
|
||||
apiKey: "test-stepfun-key",
|
||||
explicitBaseUrl: explicitPlanBaseUrl,
|
||||
}),
|
||||
};
|
||||
const pairedStandard = buildStepFunCatalog({
|
||||
surface: "standard",
|
||||
apiKey: "test-stepfun-key",
|
||||
explicitBaseUrl: resolveDefaultBaseUrl(
|
||||
"standard",
|
||||
inferRegionFromBaseUrl(explicitPlanBaseUrl) ?? "intl",
|
||||
),
|
||||
});
|
||||
|
||||
expect(providers?.stepfun?.baseUrl).toBe("https://api.stepfun.com/v1");
|
||||
expect(providers?.["stepfun-plan"]?.baseUrl).toBe("https://api.stepfun.com/step_plan/v1");
|
||||
expect(pairedStandard?.baseUrl).toBe("https://api.stepfun.com/v1");
|
||||
expect(providers["stepfun-plan"]?.baseUrl).toBe("https://api.stepfun.com/step_plan/v1");
|
||||
});
|
||||
|
||||
it("discovers both providers from shared regional auth profiles", async () => {
|
||||
it("discovers both providers from shared regional auth profiles", () => {
|
||||
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
|
||||
|
||||
upsertAuthProfile({
|
||||
|
|
@ -112,7 +205,18 @@ describe("StepFun provider catalog", () => {
|
|||
agentDir,
|
||||
});
|
||||
|
||||
const providers = await resolveImplicitProvidersForTest({ agentDir, env: {} });
|
||||
const providers = {
|
||||
stepfun: buildStepFunCatalog({
|
||||
surface: "standard",
|
||||
apiKey: "sk-stepfun-cn",
|
||||
profileId: "stepfun:cn",
|
||||
}),
|
||||
"stepfun-plan": buildStepFunCatalog({
|
||||
surface: "plan",
|
||||
apiKey: "sk-stepfun-cn",
|
||||
profileId: "stepfun-plan:cn",
|
||||
}),
|
||||
};
|
||||
|
||||
expect(providers?.stepfun?.baseUrl).toBe("https://api.stepfun.com/v1");
|
||||
expect(providers?.["stepfun-plan"]?.baseUrl).toBe("https://api.stepfun.com/step_plan/v1");
|
||||
|
|
|
|||
Loading…
Reference in New Issue