test: flatten provider catalog integration hotspots

This commit is contained in:
Peter Steinberger
2026-04-05 15:51:06 +01:00
parent 9408f682f6
commit b723b30def
2 changed files with 91 additions and 67 deletions

View File

@@ -2,17 +2,19 @@ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import {
buildAnthropicVertexProvider,
mergeImplicitAnthropicVertexProvider,
resolveImplicitAnthropicVertexProvider,
} from "../../extensions/anthropic-vertex/api.js";
import { resolveImplicitProvidersForTest } from "./models-config.e2e-harness.js";
describe("anthropic-vertex implicit provider", () => {
it("offers Claude models when GOOGLE_CLOUD_PROJECT_ID is set", async () => {
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
const providers = await resolveImplicitProvidersForTest({
agentDir,
it("offers Claude models when GOOGLE_CLOUD_PROJECT_ID is set", () => {
const provider = resolveImplicitAnthropicVertexProvider({
env: { GOOGLE_CLOUD_PROJECT_ID: "vertex-project" },
});
expect(providers?.["anthropic-vertex"]).toBeUndefined();
expect(provider).toBeNull();
});
it("accepts ADC credentials when the file includes a project_id", async () => {
@@ -125,56 +127,35 @@ describe("anthropic-vertex implicit provider", () => {
}
});
it("accepts explicit metadata auth opt-in without local credential files", async () => {
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
const providers = await resolveImplicitProvidersForTest({
agentDir,
it("accepts explicit metadata auth opt-in without local credential files", () => {
const provider = resolveImplicitAnthropicVertexProvider({
env: {
ANTHROPIC_VERTEX_USE_GCP_METADATA: "true",
GOOGLE_CLOUD_LOCATION: "us-east5",
},
});
expect(providers?.["anthropic-vertex"]?.baseUrl).toBe(
"https://us-east5-aiplatform.googleapis.com",
);
expect(provider?.baseUrl).toBe("https://us-east5-aiplatform.googleapis.com");
});
it("merges the bundled catalog into explicit anthropic-vertex provider overrides", async () => {
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
const adcDir = mkdtempSync(join(tmpdir(), "openclaw-adc-"));
const credentialsPath = join(adcDir, "application_default_credentials.json");
writeFileSync(credentialsPath, JSON.stringify({ project_id: "vertex-project" }), "utf8");
try {
const providers = await resolveImplicitProvidersForTest({
agentDir,
const provider = mergeImplicitAnthropicVertexProvider({
existing: {
baseUrl: "https://europe-west4-aiplatform.googleapis.com",
headers: { "x-test-header": "1" },
},
implicit: buildAnthropicVertexProvider({
env: {
GOOGLE_APPLICATION_CREDENTIALS: credentialsPath,
GOOGLE_CLOUD_LOCATION: "us-east5",
},
config: {
models: {
providers: {
"anthropic-vertex": {
baseUrl: "https://europe-west4-aiplatform.googleapis.com",
headers: { "x-test-header": "1" },
},
},
},
} as unknown as OpenClawConfig,
});
}),
});
expect(providers?.["anthropic-vertex"]?.baseUrl).toBe(
"https://europe-west4-aiplatform.googleapis.com",
);
expect(providers?.["anthropic-vertex"]?.headers).toEqual({ "x-test-header": "1" });
expect(providers?.["anthropic-vertex"]?.models?.map((model) => model.id)).toEqual([
"claude-opus-4-6",
"claude-sonnet-4-6",
]);
} finally {
rmSync(adcDir, { recursive: true, force: true });
}
expect(provider.baseUrl).toBe("https://europe-west4-aiplatform.googleapis.com");
expect(provider.headers).toEqual({ "x-test-header": "1" });
expect(provider.models?.map((model) => model.id)).toEqual([
"claude-opus-4-6",
"claude-sonnet-4-6",
]);
});
it("does not accept generic Kubernetes env without a GCP ADC signal", async () => {

View File

@@ -2,34 +2,50 @@ import { mkdtempSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import stepfunPlugin from "../../extensions/stepfun/index.js";
import {
buildStepFunPlanProvider,
buildStepFunProvider,
} from "../../extensions/stepfun/provider-catalog.js";
import {
registerProviderPlugin,
requireRegisteredProvider,
} from "../../test/helpers/plugins/provider-registration.js";
import { upsertAuthProfile } from "./auth-profiles.js";
import { resolveImplicitProvidersForTest } from "./models-config.e2e-harness.js";
import { resolveMissingProviderApiKey } from "./models-config.providers.secrets.js";
const EXPECTED_STANDARD_MODELS = ["step-3.5-flash"];
const EXPECTED_PLAN_MODELS = ["step-3.5-flash", "step-3.5-flash-2603"];
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" },
const env = { STEPFUN_API_KEY: "test-stepfun-key" } as NodeJS.ProcessEnv;
const standardProvider = resolveMissingProviderApiKey({
providerKey: "stepfun",
provider: buildStepFunProvider(),
env,
profileApiKey: undefined,
});
const planProvider = resolveMissingProviderApiKey({
providerKey: "stepfun-plan",
provider: buildStepFunPlanProvider(),
env,
profileApiKey: undefined,
});
expect(providers?.stepfun).toMatchObject({
expect(standardProvider).toMatchObject({
baseUrl: "https://api.stepfun.ai/v1",
api: "openai-completions",
apiKey: "STEPFUN_API_KEY",
});
expect(providers?.["stepfun-plan"]).toMatchObject({
expect(planProvider).toMatchObject({
baseUrl: "https://api.stepfun.ai/step_plan/v1",
api: "openai-completions",
apiKey: "STEPFUN_API_KEY",
});
expect(providers?.stepfun?.models?.map((model) => model.id)).toEqual(EXPECTED_STANDARD_MODELS);
expect(providers?.["stepfun-plan"]?.models?.map((model) => model.id)).toEqual(
EXPECTED_PLAN_MODELS,
);
expect(standardProvider.models?.map((model) => model.id)).toEqual(EXPECTED_STANDARD_MODELS);
expect(planProvider.models?.map((model) => model.id)).toEqual(EXPECTED_PLAN_MODELS);
});
it("falls back to global endpoints for untagged StepFun auth profiles", async () => {
@@ -65,24 +81,51 @@ 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: [],
},
const { providers } = await registerProviderPlugin({
plugin: stepfunPlugin,
id: "stepfun",
name: "StepFun",
});
const standardProvider = requireRegisteredProvider(providers, "stepfun");
const planProvider = requireRegisteredProvider(providers, "stepfun-plan");
const config = {
models: {
providers: {
"stepfun-plan": {
baseUrl: "https://api.stepfun.com/step_plan/v1",
models: [],
},
},
},
};
const resolveProviderApiKey = () => ({
apiKey: "STEPFUN_API_KEY",
discoveryApiKey: "test-stepfun-key",
});
const resolveProviderAuth = () => ({
apiKey: "STEPFUN_API_KEY",
discoveryApiKey: "test-stepfun-key",
mode: "api_key" as const,
source: "env" as const,
});
expect(providers?.stepfun?.baseUrl).toBe("https://api.stepfun.com/v1");
expect(providers?.["stepfun-plan"]?.baseUrl).toBe("https://api.stepfun.com/step_plan/v1");
const standardCatalog = await standardProvider.catalog?.run({
agentDir: "/tmp/openclaw-stepfun-test",
env: { STEPFUN_API_KEY: "test-stepfun-key" } as NodeJS.ProcessEnv,
config,
resolveProviderApiKey,
resolveProviderAuth,
} as never);
const planCatalog = await planProvider.catalog?.run({
agentDir: "/tmp/openclaw-stepfun-test",
env: { STEPFUN_API_KEY: "test-stepfun-key" } as NodeJS.ProcessEnv,
config,
resolveProviderApiKey,
resolveProviderAuth,
} as never);
expect(standardCatalog?.provider.baseUrl).toBe("https://api.stepfun.com/v1");
expect(planCatalog?.provider.baseUrl).toBe("https://api.stepfun.com/step_plan/v1");
});
it("discovers both providers from shared regional auth profiles", async () => {