refactor(providers): unify lifecycle-safe manifest registration (#114381)

* refactor(providers): canonicalize manifest-driven registration

* fix(zai): eliminate type-only SDK import side effects
This commit is contained in:
Peter Steinberger
2026-07-27 03:20:02 -04:00
committed by GitHub
parent 65cce37480
commit eec2c0cc26
20 changed files with 892 additions and 825 deletions

View File

@@ -6,8 +6,21 @@ import { registerSingleProviderPlugin } from "openclaw/plugin-sdk/plugin-test-ru
import { describe, expect, it } from "vitest";
import plugin from "./index.js";
import { BYTEPLUS_CODING_MODEL_CATALOG, BYTEPLUS_MODEL_CATALOG } from "./models.js";
import { BYTEPLUS_PROVIDER_CATALOG_ENTRIES } from "./provider-catalog.js";
describe("byteplus plugin", () => {
it("preserves both provider-owned static catalogs and paired ordering", async () => {
const provider = await registerSingleProviderPlugin(plugin);
expect(provider.catalog?.order).toBe("paired");
expect(provider.staticCatalog?.order).toBe("paired");
expect(await provider.staticCatalog?.run({} as never)).toEqual({
providers: Object.fromEntries(
BYTEPLUS_PROVIDER_CATALOG_ENTRIES.map(({ id, buildProvider }) => [id, buildProvider()]),
),
});
});
it("augments the catalog with bundled standard and plan models", async () => {
const provider = await registerSingleProviderPlugin(plugin);
expect(provider.auth?.[0]?.starterModel).toBe("byteplus-plan/ark-code-latest");

View File

@@ -1,10 +1,9 @@
/**
* BytePlus provider plugin entrypoint for model and video generation providers.
*/
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth-api-key";
import { buildOpenAICompatibleLiveModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-live-runtime";
import { readManifestProviderDefaultModelRef } from "openclaw/plugin-sdk/provider-catalog-shared";
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
import { ensureModelAllowlistEntry } from "openclaw/plugin-sdk/provider-onboard";
import manifest from "./openclaw.plugin.json" with { type: "json" };
import { BYTEPLUS_PROVIDER_CATALOG_ENTRIES } from "./provider-catalog.js";
@@ -13,90 +12,65 @@ import { buildBytePlusVideoGenerationProvider } from "./video-generation-provide
const PROVIDER_ID = "byteplus";
const BYTEPLUS_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(manifest, "byteplus-plan")!;
export default definePluginEntry({
export default defineSingleProviderPluginEntry({
id: PROVIDER_ID,
name: "BytePlus Provider",
description: "Bundled BytePlus provider plugin",
register(api) {
api.registerProvider({
id: PROVIDER_ID,
label: "BytePlus",
docsPath: "/concepts/model-providers#byteplus-international",
envVars: ["BYTEPLUS_API_KEY"],
auth: [
createProviderApiKeyAuthMethod({
providerId: PROVIDER_ID,
methodId: "api-key",
label: "BytePlus API key",
hint: "API key",
optionKey: "byteplusApiKey",
flagName: "--byteplus-api-key",
envVar: "BYTEPLUS_API_KEY",
promptMessage: "Enter BytePlus API key",
defaultModel: BYTEPLUS_DEFAULT_MODEL_REF,
expectedProviders: ["byteplus"],
applyConfig: (cfg) =>
ensureModelAllowlistEntry({
cfg,
modelRef: BYTEPLUS_DEFAULT_MODEL_REF,
}),
wizard: {
choiceId: "byteplus-api-key",
choiceLabel: "BytePlus API key",
groupId: "byteplus",
groupLabel: "BytePlus",
groupHint: "API key",
},
}),
],
catalog: {
order: "paired",
run: async (ctx) => {
const auth = ctx.resolveProviderApiKey(PROVIDER_ID);
const apiKey = auth.apiKey;
if (!apiKey) {
return null;
}
return {
providers: Object.fromEntries(
await Promise.all(
BYTEPLUS_PROVIDER_CATALOG_ENTRIES.map(
async ({ id, buildProvider }) =>
[
id,
await buildOpenAICompatibleLiveModelProviderConfig({
providerId: id,
providerConfig: buildProvider(),
apiKey,
discoveryApiKey: auth.discoveryApiKey,
}),
] as const,
),
manifest,
provider: {
label: "BytePlus",
docsPath: "/concepts/model-providers#byteplus-international",
manifestAuth: {
defaultModel: BYTEPLUS_DEFAULT_MODEL_REF,
applyConfig: (cfg) =>
ensureModelAllowlistEntry({ cfg, modelRef: BYTEPLUS_DEFAULT_MODEL_REF }),
},
catalog: {
order: "paired",
run: async (ctx) => {
const auth = ctx.resolveProviderApiKey(PROVIDER_ID);
const apiKey = auth.apiKey;
if (!apiKey) {
return null;
}
return {
providers: Object.fromEntries(
await Promise.all(
BYTEPLUS_PROVIDER_CATALOG_ENTRIES.map(
async ({ id, buildProvider }) =>
[
id,
await buildOpenAICompatibleLiveModelProviderConfig({
providerId: id,
providerConfig: buildProvider(),
apiKey,
discoveryApiKey: auth.discoveryApiKey,
}),
] as const,
),
),
};
},
},
staticCatalog: {
order: "paired",
run: async () => ({
providers: Object.fromEntries(
BYTEPLUS_PROVIDER_CATALOG_ENTRIES.map(({ id, buildProvider }) => [id, buildProvider()]),
),
}),
};
},
augmentModelCatalog: () =>
BYTEPLUS_PROVIDER_CATALOG_ENTRIES.flatMap(({ id: provider, models }) =>
models.map((entry) => ({
provider,
id: entry.id,
name: entry.name,
reasoning: entry.reasoning,
input: [...entry.input],
contextWindow: entry.contextWindow,
})),
staticRun: async () => ({
providers: Object.fromEntries(
BYTEPLUS_PROVIDER_CATALOG_ENTRIES.map(({ id, buildProvider }) => [id, buildProvider()]),
),
});
}),
},
augmentModelCatalog: () =>
BYTEPLUS_PROVIDER_CATALOG_ENTRIES.flatMap(({ id: provider, models }) =>
models.map((entry) => ({
provider,
id: entry.id,
name: entry.name,
reasoning: entry.reasoning,
input: [...entry.input],
contextWindow: entry.contextWindow,
})),
),
},
register(api) {
api.registerVideoGenerationProvider(buildBytePlusVideoGenerationProvider());
},
});