refactor: add provider onboarding preset appliers

This commit is contained in:
Peter Steinberger
2026-03-23 01:39:10 +00:00
parent 956fe72b39
commit 7d032ed38c
16 changed files with 368 additions and 178 deletions

View File

@@ -185,6 +185,13 @@ API key auth, and dynamic model resolution.
});
```
If your auth flow also needs to patch `models.providers.*`, aliases, and
the agent default model during onboarding, use the preset helpers from
`openclaw/plugin-sdk/provider-onboard`. The narrowest helpers are
`createDefaultModelPresetAppliers(...)`,
`createDefaultModelsPresetAppliers(...)`, and
`createModelCatalogPresetAppliers(...)`.
</Step>
<Step title="Add dynamic model resolution">

View File

@@ -4,27 +4,27 @@ import {
HUGGINGFACE_MODEL_CATALOG,
} from "openclaw/plugin-sdk/provider-models";
import {
applyProviderConfigWithModelCatalogPreset,
createModelCatalogPresetAppliers,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
export const HUGGINGFACE_DEFAULT_MODEL_REF = "huggingface/deepseek-ai/DeepSeek-R1";
function applyHuggingfacePreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
return applyProviderConfigWithModelCatalogPreset(cfg, {
const huggingfacePresetAppliers = createModelCatalogPresetAppliers({
primaryModelRef: HUGGINGFACE_DEFAULT_MODEL_REF,
resolveParams: (_cfg: OpenClawConfig) => ({
providerId: "huggingface",
api: "openai-completions",
baseUrl: HUGGINGFACE_BASE_URL,
catalogModels: HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition),
aliases: [{ modelRef: HUGGINGFACE_DEFAULT_MODEL_REF, alias: "Hugging Face" }],
primaryModelRef,
});
}
}),
});
export function applyHuggingfaceProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyHuggingfacePreset(cfg);
return huggingfacePresetAppliers.applyProviderConfig(cfg);
}
export function applyHuggingfaceConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyHuggingfacePreset(cfg, HUGGINGFACE_DEFAULT_MODEL_REF);
return huggingfacePresetAppliers.applyConfig(cfg);
}

View File

@@ -1,29 +1,27 @@
import { KILOCODE_BASE_URL, KILOCODE_DEFAULT_MODEL_REF } from "openclaw/plugin-sdk/provider-models";
import {
applyProviderConfigWithModelCatalogPreset,
createModelCatalogPresetAppliers,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
import { buildKilocodeProvider } from "./provider-catalog.js";
export { KILOCODE_BASE_URL, KILOCODE_DEFAULT_MODEL_REF };
export function applyKilocodeProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyProviderConfigWithModelCatalogPreset(cfg, {
const kilocodePresetAppliers = createModelCatalogPresetAppliers({
primaryModelRef: KILOCODE_DEFAULT_MODEL_REF,
resolveParams: (_cfg: OpenClawConfig) => ({
providerId: "kilocode",
api: "openai-completions",
baseUrl: KILOCODE_BASE_URL,
catalogModels: buildKilocodeProvider().models ?? [],
aliases: [{ modelRef: KILOCODE_DEFAULT_MODEL_REF, alias: "Kilo Gateway" }],
});
}),
});
export function applyKilocodeProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
return kilocodePresetAppliers.applyProviderConfig(cfg);
}
export function applyKilocodeConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyProviderConfigWithModelCatalogPreset(cfg, {
providerId: "kilocode",
api: "openai-completions",
baseUrl: KILOCODE_BASE_URL,
catalogModels: buildKilocodeProvider().models ?? [],
aliases: [{ modelRef: KILOCODE_DEFAULT_MODEL_REF, alias: "Kilo Gateway" }],
primaryModelRef: KILOCODE_DEFAULT_MODEL_REF,
});
return kilocodePresetAppliers.applyConfig(cfg);
}

View File

@@ -1,5 +1,5 @@
import {
applyProviderConfigWithDefaultModelPreset,
createDefaultModelPresetAppliers,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
import {
@@ -15,26 +15,28 @@ function resolveKimiCodingDefaultModel() {
return buildKimiCodingProvider().models[0];
}
function applyKimiCodingPreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
const defaultModel = resolveKimiCodingDefaultModel();
if (!defaultModel) {
return cfg;
}
return applyProviderConfigWithDefaultModelPreset(cfg, {
providerId: "kimi",
api: "anthropic-messages",
baseUrl: KIMI_CODING_BASE_URL,
defaultModel,
defaultModelId: KIMI_CODING_DEFAULT_MODEL_ID,
aliases: [{ modelRef: KIMI_MODEL_REF, alias: "Kimi" }],
primaryModelRef,
});
}
const kimiCodingPresetAppliers = createDefaultModelPresetAppliers({
primaryModelRef: KIMI_MODEL_REF,
resolveParams: (_cfg: OpenClawConfig) => {
const defaultModel = resolveKimiCodingDefaultModel();
if (!defaultModel) {
return null;
}
return {
providerId: "kimi",
api: "anthropic-messages",
baseUrl: KIMI_CODING_BASE_URL,
defaultModel,
defaultModelId: KIMI_CODING_DEFAULT_MODEL_ID,
aliases: [{ modelRef: KIMI_MODEL_REF, alias: "Kimi" }],
};
},
});
export function applyKimiCodeProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyKimiCodingPreset(cfg);
return kimiCodingPresetAppliers.applyProviderConfig(cfg);
}
export function applyKimiCodeConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyKimiCodingPreset(cfg, KIMI_MODEL_REF);
return kimiCodingPresetAppliers.applyConfig(cfg);
}

View File

@@ -1,5 +1,5 @@
import {
applyProviderConfigWithDefaultModelPreset,
createDefaultModelPresetAppliers,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
import {
@@ -10,22 +10,22 @@ import {
export const MISTRAL_DEFAULT_MODEL_REF = `mistral/${MISTRAL_DEFAULT_MODEL_ID}`;
function applyMistralPreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
return applyProviderConfigWithDefaultModelPreset(cfg, {
const mistralPresetAppliers = createDefaultModelPresetAppliers({
primaryModelRef: MISTRAL_DEFAULT_MODEL_REF,
resolveParams: (_cfg: OpenClawConfig) => ({
providerId: "mistral",
api: "openai-completions",
baseUrl: MISTRAL_BASE_URL,
defaultModel: buildMistralModelDefinition(),
defaultModelId: MISTRAL_DEFAULT_MODEL_ID,
aliases: [{ modelRef: MISTRAL_DEFAULT_MODEL_REF, alias: "Mistral" }],
primaryModelRef,
});
}
}),
});
export function applyMistralProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyMistralPreset(cfg);
return mistralPresetAppliers.applyProviderConfig(cfg);
}
export function applyMistralConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyMistralPreset(cfg, MISTRAL_DEFAULT_MODEL_REF);
return mistralPresetAppliers.applyConfig(cfg);
}

View File

@@ -1,5 +1,5 @@
import {
applyProviderConfigWithModelCatalogPreset,
createModelCatalogPresetAppliers,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
import {
@@ -11,45 +11,35 @@ import { buildModelStudioProvider } from "./provider-catalog.js";
export { MODELSTUDIO_CN_BASE_URL, MODELSTUDIO_DEFAULT_MODEL_REF, MODELSTUDIO_GLOBAL_BASE_URL };
function applyModelStudioProviderConfigWithBaseUrl(
cfg: OpenClawConfig,
baseUrl: string,
primaryModelRef?: string,
): OpenClawConfig {
const provider = buildModelStudioProvider();
return applyProviderConfigWithModelCatalogPreset(cfg, {
providerId: "modelstudio",
api: provider.api ?? "openai-completions",
baseUrl,
catalogModels: provider.models ?? [],
aliases: [
...(provider.models ?? []).map((model) => `modelstudio/${model.id}`),
{ modelRef: MODELSTUDIO_DEFAULT_MODEL_REF, alias: "Qwen" },
],
primaryModelRef,
});
}
const modelStudioPresetAppliers = createModelCatalogPresetAppliers<[string]>({
primaryModelRef: MODELSTUDIO_DEFAULT_MODEL_REF,
resolveParams: (_cfg: OpenClawConfig, baseUrl: string) => {
const provider = buildModelStudioProvider();
return {
providerId: "modelstudio",
api: provider.api ?? "openai-completions",
baseUrl,
catalogModels: provider.models ?? [],
aliases: [
...(provider.models ?? []).map((model) => `modelstudio/${model.id}`),
{ modelRef: MODELSTUDIO_DEFAULT_MODEL_REF, alias: "Qwen" },
],
};
},
});
export function applyModelStudioProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyModelStudioProviderConfigWithBaseUrl(cfg, MODELSTUDIO_GLOBAL_BASE_URL);
return modelStudioPresetAppliers.applyProviderConfig(cfg, MODELSTUDIO_GLOBAL_BASE_URL);
}
export function applyModelStudioProviderConfigCn(cfg: OpenClawConfig): OpenClawConfig {
return applyModelStudioProviderConfigWithBaseUrl(cfg, MODELSTUDIO_CN_BASE_URL);
return modelStudioPresetAppliers.applyProviderConfig(cfg, MODELSTUDIO_CN_BASE_URL);
}
export function applyModelStudioConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyModelStudioProviderConfigWithBaseUrl(
cfg,
MODELSTUDIO_GLOBAL_BASE_URL,
MODELSTUDIO_DEFAULT_MODEL_REF,
);
return modelStudioPresetAppliers.applyConfig(cfg, MODELSTUDIO_GLOBAL_BASE_URL);
}
export function applyModelStudioConfigCn(cfg: OpenClawConfig): OpenClawConfig {
return applyModelStudioProviderConfigWithBaseUrl(
cfg,
MODELSTUDIO_CN_BASE_URL,
MODELSTUDIO_DEFAULT_MODEL_REF,
);
return modelStudioPresetAppliers.applyConfig(cfg, MODELSTUDIO_CN_BASE_URL);
}

View File

@@ -1,5 +1,5 @@
import {
applyProviderConfigWithDefaultModelPreset,
createDefaultModelPresetAppliers,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
import {
@@ -11,43 +11,37 @@ import {
export const MOONSHOT_CN_BASE_URL = "https://api.moonshot.cn/v1";
export const MOONSHOT_DEFAULT_MODEL_REF = `moonshot/${MOONSHOT_DEFAULT_MODEL_ID}`;
const moonshotPresetAppliers = createDefaultModelPresetAppliers<[string]>({
primaryModelRef: MOONSHOT_DEFAULT_MODEL_REF,
resolveParams: (_cfg: OpenClawConfig, baseUrl: string) => {
const defaultModel = buildMoonshotProvider().models[0];
if (!defaultModel) {
return null;
}
return {
providerId: "moonshot",
api: "openai-completions",
baseUrl,
defaultModel,
defaultModelId: MOONSHOT_DEFAULT_MODEL_ID,
aliases: [{ modelRef: MOONSHOT_DEFAULT_MODEL_REF, alias: "Kimi" }],
};
},
});
export function applyMoonshotProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyMoonshotProviderConfigWithBaseUrl(cfg, MOONSHOT_BASE_URL);
return moonshotPresetAppliers.applyProviderConfig(cfg, MOONSHOT_BASE_URL);
}
export function applyMoonshotProviderConfigCn(cfg: OpenClawConfig): OpenClawConfig {
return applyMoonshotProviderConfigWithBaseUrl(cfg, MOONSHOT_CN_BASE_URL);
}
function applyMoonshotProviderConfigWithBaseUrl(
cfg: OpenClawConfig,
baseUrl: string,
primaryModelRef?: string,
): OpenClawConfig {
const defaultModel = buildMoonshotProvider().models[0];
if (!defaultModel) {
return cfg;
}
return applyProviderConfigWithDefaultModelPreset(cfg, {
providerId: "moonshot",
api: "openai-completions",
baseUrl,
defaultModel,
defaultModelId: MOONSHOT_DEFAULT_MODEL_ID,
aliases: [{ modelRef: MOONSHOT_DEFAULT_MODEL_REF, alias: "Kimi" }],
primaryModelRef,
});
return moonshotPresetAppliers.applyProviderConfig(cfg, MOONSHOT_CN_BASE_URL);
}
export function applyMoonshotConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyMoonshotProviderConfigWithBaseUrl(cfg, MOONSHOT_BASE_URL, MOONSHOT_DEFAULT_MODEL_REF);
return moonshotPresetAppliers.applyConfig(cfg, MOONSHOT_BASE_URL);
}
export function applyMoonshotConfigCn(cfg: OpenClawConfig): OpenClawConfig {
return applyMoonshotProviderConfigWithBaseUrl(
cfg,
MOONSHOT_CN_BASE_URL,
MOONSHOT_DEFAULT_MODEL_REF,
);
return moonshotPresetAppliers.applyConfig(cfg, MOONSHOT_CN_BASE_URL);
}

View File

@@ -1,5 +1,5 @@
import {
applyProviderConfigWithDefaultModelsPreset,
createDefaultModelsPresetAppliers,
type ModelApi,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
@@ -37,23 +37,25 @@ function resolveQianfanPreset(cfg: OpenClawConfig): {
};
}
function applyQianfanPreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
const preset = resolveQianfanPreset(cfg);
return applyProviderConfigWithDefaultModelsPreset(cfg, {
providerId: "qianfan",
api: preset.api,
baseUrl: preset.baseUrl,
defaultModels: preset.defaultModels,
defaultModelId: QIANFAN_DEFAULT_MODEL_ID,
aliases: [{ modelRef: QIANFAN_DEFAULT_MODEL_REF, alias: "QIANFAN" }],
primaryModelRef,
});
}
const qianfanPresetAppliers = createDefaultModelsPresetAppliers({
primaryModelRef: QIANFAN_DEFAULT_MODEL_REF,
resolveParams: (cfg: OpenClawConfig) => {
const preset = resolveQianfanPreset(cfg);
return {
providerId: "qianfan",
api: preset.api,
baseUrl: preset.baseUrl,
defaultModels: preset.defaultModels,
defaultModelId: QIANFAN_DEFAULT_MODEL_ID,
aliases: [{ modelRef: QIANFAN_DEFAULT_MODEL_REF, alias: "QIANFAN" }],
};
},
});
export function applyQianfanProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyQianfanPreset(cfg);
return qianfanPresetAppliers.applyProviderConfig(cfg);
}
export function applyQianfanConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyQianfanPreset(cfg, QIANFAN_DEFAULT_MODEL_REF);
return qianfanPresetAppliers.applyConfig(cfg);
}

View File

@@ -5,27 +5,27 @@ import {
SYNTHETIC_MODEL_CATALOG,
} from "openclaw/plugin-sdk/provider-models";
import {
applyProviderConfigWithModelCatalogPreset,
createModelCatalogPresetAppliers,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
export { SYNTHETIC_DEFAULT_MODEL_REF };
function applySyntheticPreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
return applyProviderConfigWithModelCatalogPreset(cfg, {
const syntheticPresetAppliers = createModelCatalogPresetAppliers({
primaryModelRef: SYNTHETIC_DEFAULT_MODEL_REF,
resolveParams: (_cfg: OpenClawConfig) => ({
providerId: "synthetic",
api: "anthropic-messages",
baseUrl: SYNTHETIC_BASE_URL,
catalogModels: SYNTHETIC_MODEL_CATALOG.map(buildSyntheticModelDefinition),
aliases: [{ modelRef: SYNTHETIC_DEFAULT_MODEL_REF, alias: "MiniMax M2.5" }],
primaryModelRef,
});
}
}),
});
export function applySyntheticProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
return applySyntheticPreset(cfg);
return syntheticPresetAppliers.applyProviderConfig(cfg);
}
export function applySyntheticConfig(cfg: OpenClawConfig): OpenClawConfig {
return applySyntheticPreset(cfg, SYNTHETIC_DEFAULT_MODEL_REF);
return syntheticPresetAppliers.applyConfig(cfg);
}

View File

@@ -4,27 +4,27 @@ import {
TOGETHER_MODEL_CATALOG,
} from "openclaw/plugin-sdk/provider-models";
import {
applyProviderConfigWithModelCatalogPreset,
createModelCatalogPresetAppliers,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
export const TOGETHER_DEFAULT_MODEL_REF = "together/moonshotai/Kimi-K2.5";
function applyTogetherPreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
return applyProviderConfigWithModelCatalogPreset(cfg, {
const togetherPresetAppliers = createModelCatalogPresetAppliers({
primaryModelRef: TOGETHER_DEFAULT_MODEL_REF,
resolveParams: (_cfg: OpenClawConfig) => ({
providerId: "together",
api: "openai-completions",
baseUrl: TOGETHER_BASE_URL,
catalogModels: TOGETHER_MODEL_CATALOG.map(buildTogetherModelDefinition),
aliases: [{ modelRef: TOGETHER_DEFAULT_MODEL_REF, alias: "Together AI" }],
primaryModelRef,
});
}
}),
});
export function applyTogetherProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyTogetherPreset(cfg);
return togetherPresetAppliers.applyProviderConfig(cfg);
}
export function applyTogetherConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyTogetherPreset(cfg, TOGETHER_DEFAULT_MODEL_REF);
return togetherPresetAppliers.applyConfig(cfg);
}

View File

@@ -5,27 +5,27 @@ import {
VENICE_MODEL_CATALOG,
} from "openclaw/plugin-sdk/provider-models";
import {
applyProviderConfigWithModelCatalogPreset,
createModelCatalogPresetAppliers,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
export { VENICE_DEFAULT_MODEL_REF };
function applyVenicePreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
return applyProviderConfigWithModelCatalogPreset(cfg, {
const venicePresetAppliers = createModelCatalogPresetAppliers({
primaryModelRef: VENICE_DEFAULT_MODEL_REF,
resolveParams: (_cfg: OpenClawConfig) => ({
providerId: "venice",
api: "openai-completions",
baseUrl: VENICE_BASE_URL,
catalogModels: VENICE_MODEL_CATALOG.map(buildVeniceModelDefinition),
aliases: [{ modelRef: VENICE_DEFAULT_MODEL_REF, alias: "Kimi K2.5" }],
primaryModelRef,
});
}
}),
});
export function applyVeniceProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyVenicePreset(cfg);
return venicePresetAppliers.applyProviderConfig(cfg);
}
export function applyVeniceConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyVenicePreset(cfg, VENICE_DEFAULT_MODEL_REF);
return venicePresetAppliers.applyConfig(cfg);
}

View File

@@ -1,5 +1,5 @@
import {
applyProviderConfigWithDefaultModelsPreset,
createDefaultModelsPresetAppliers,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
import { XAI_BASE_URL, XAI_DEFAULT_MODEL_ID } from "./model-definitions.js";
@@ -7,30 +7,28 @@ import { buildXaiCatalogModels } from "./model-definitions.js";
export const XAI_DEFAULT_MODEL_REF = `xai/${XAI_DEFAULT_MODEL_ID}`;
function applyXaiProviderConfigWithApi(
cfg: OpenClawConfig,
api: "openai-completions" | "openai-responses",
primaryModelRef?: string,
): OpenClawConfig {
return applyProviderConfigWithDefaultModelsPreset(cfg, {
const xaiPresetAppliers = createDefaultModelsPresetAppliers<
["openai-completions" | "openai-responses"]
>({
primaryModelRef: XAI_DEFAULT_MODEL_REF,
resolveParams: (_cfg: OpenClawConfig, api) => ({
providerId: "xai",
api,
baseUrl: XAI_BASE_URL,
defaultModels: buildXaiCatalogModels(),
defaultModelId: XAI_DEFAULT_MODEL_ID,
aliases: [{ modelRef: XAI_DEFAULT_MODEL_REF, alias: "Grok" }],
primaryModelRef,
});
}
}),
});
export function applyXaiProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyXaiProviderConfigWithApi(cfg, "openai-completions");
return xaiPresetAppliers.applyProviderConfig(cfg, "openai-completions");
}
export function applyXaiResponsesApiConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyXaiProviderConfigWithApi(cfg, "openai-responses");
return xaiPresetAppliers.applyProviderConfig(cfg, "openai-responses");
}
export function applyXaiConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyXaiProviderConfigWithApi(cfg, "openai-completions", XAI_DEFAULT_MODEL_REF);
return xaiPresetAppliers.applyConfig(cfg, "openai-completions");
}

View File

@@ -1,30 +1,30 @@
import {
applyAgentDefaultModelPrimary,
applyProviderConfigWithDefaultModels,
createDefaultModelsPresetAppliers,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
import { buildXiaomiProvider, XIAOMI_DEFAULT_MODEL_ID } from "./provider-catalog.js";
export const XIAOMI_DEFAULT_MODEL_REF = `xiaomi/${XIAOMI_DEFAULT_MODEL_ID}`;
const xiaomiPresetAppliers = createDefaultModelsPresetAppliers({
primaryModelRef: XIAOMI_DEFAULT_MODEL_REF,
resolveParams: (_cfg: OpenClawConfig) => {
const defaultProvider = buildXiaomiProvider();
return {
providerId: "xiaomi",
api: defaultProvider.api ?? "openai-completions",
baseUrl: defaultProvider.baseUrl,
defaultModels: defaultProvider.models ?? [],
defaultModelId: XIAOMI_DEFAULT_MODEL_ID,
aliases: [{ modelRef: XIAOMI_DEFAULT_MODEL_REF, alias: "Xiaomi" }],
};
},
});
export function applyXiaomiProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
const models = { ...cfg.agents?.defaults?.models };
models[XIAOMI_DEFAULT_MODEL_REF] = {
...models[XIAOMI_DEFAULT_MODEL_REF],
alias: models[XIAOMI_DEFAULT_MODEL_REF]?.alias ?? "Xiaomi",
};
const defaultProvider = buildXiaomiProvider();
const resolvedApi = defaultProvider.api ?? "openai-completions";
return applyProviderConfigWithDefaultModels(cfg, {
agentModels: models,
providerId: "xiaomi",
api: resolvedApi,
baseUrl: defaultProvider.baseUrl,
defaultModels: defaultProvider.models ?? [],
defaultModelId: XIAOMI_DEFAULT_MODEL_ID,
});
return xiaomiPresetAppliers.applyProviderConfig(cfg);
}
export function applyXiaomiConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyAgentDefaultModelPrimary(applyXiaomiProviderConfig(cfg), XIAOMI_DEFAULT_MODEL_REF);
return xiaomiPresetAppliers.applyConfig(cfg);
}

View File

@@ -9,6 +9,9 @@ export type {
export {
applyAgentDefaultModelPrimary,
applyOnboardAuthAgentModelsAndProviders,
createDefaultModelPresetAppliers,
createDefaultModelsPresetAppliers,
createModelCatalogPresetAppliers,
applyProviderConfigWithDefaultModelPreset,
applyProviderConfigWithDefaultModelsPreset,
applyProviderConfigWithDefaultModel,
@@ -17,5 +20,8 @@ export {
applyProviderConfigWithModelCatalog,
withAgentModelAliases,
} from "../plugins/provider-onboarding-config.js";
export type { AgentModelAliasEntry } from "../plugins/provider-onboarding-config.js";
export type {
AgentModelAliasEntry,
ProviderOnboardPresetAppliers,
} from "../plugins/provider-onboarding-config.js";
export { ensureModelAllowlistEntry } from "../plugins/provider-model-allowlist.js";

View File

@@ -0,0 +1,106 @@
import { describe, expect, it } from "vitest";
import {
createDefaultModelPresetAppliers,
createDefaultModelsPresetAppliers,
createModelCatalogPresetAppliers,
} from "./provider-onboarding-config.js";
describe("provider onboarding preset appliers", () => {
it("creates provider and primary-model appliers for a default model preset", () => {
const appliers = createDefaultModelPresetAppliers({
primaryModelRef: "demo/demo-default",
resolveParams: () => ({
providerId: "demo",
api: "openai-completions" as const,
baseUrl: "https://demo.test/v1",
defaultModel: {
id: "demo-default",
name: "Demo Default",
},
defaultModelId: "demo-default",
aliases: [{ modelRef: "demo/demo-default", alias: "Demo" }],
}),
});
const providerOnly = appliers.applyProviderConfig({});
expect(providerOnly.agents?.defaults?.models).toMatchObject({
"demo/demo-default": {
alias: "Demo",
},
});
expect(providerOnly.agents?.defaults?.model).toBeUndefined();
const withPrimary = appliers.applyConfig({});
expect(withPrimary.agents?.defaults?.model).toEqual({
primary: "demo/demo-default",
});
});
it("passes variant args through default-models resolvers", () => {
const appliers = createDefaultModelsPresetAppliers<[string]>({
primaryModelRef: "demo/a",
resolveParams: (_cfg, baseUrl) => ({
providerId: "demo",
api: "openai-completions" as const,
baseUrl,
defaultModels: [
{ id: "a", name: "Model A" },
{ id: "b", name: "Model B" },
],
aliases: [{ modelRef: "demo/a", alias: "Demo A" }],
}),
});
const cfg = appliers.applyConfig({}, "https://alt.test/v1");
expect(cfg.models?.providers?.demo).toMatchObject({
baseUrl: "https://alt.test/v1",
models: [
{ id: "a", name: "Model A" },
{ id: "b", name: "Model B" },
],
});
expect(cfg.agents?.defaults?.model).toEqual({
primary: "demo/a",
});
});
it("creates model-catalog appliers that preserve existing aliases", () => {
const appliers = createModelCatalogPresetAppliers({
primaryModelRef: "catalog/default",
resolveParams: () => ({
providerId: "catalog",
api: "openai-completions" as const,
baseUrl: "https://catalog.test/v1",
catalogModels: [
{ id: "default", name: "Catalog Default" },
{ id: "backup", name: "Catalog Backup" },
],
aliases: [
"catalog/default",
{ modelRef: "catalog/default", alias: "Catalog Default" },
],
}),
});
const cfg = appliers.applyConfig({
agents: {
defaults: {
models: {
"catalog/default": {
alias: "Existing Alias",
},
},
},
},
});
expect(cfg.agents?.defaults?.models).toMatchObject({
"catalog/default": {
alias: "Existing Alias",
},
});
expect(cfg.agents?.defaults?.model).toEqual({
primary: "catalog/default",
});
});
});

View File

@@ -174,6 +174,59 @@ export function applyProviderConfigWithDefaultModelPreset(
: next;
}
export type ProviderOnboardPresetAppliers<TArgs extends unknown[]> = {
applyProviderConfig: (cfg: OpenClawConfig, ...args: TArgs) => OpenClawConfig;
applyConfig: (cfg: OpenClawConfig, ...args: TArgs) => OpenClawConfig;
};
function createProviderPresetAppliers<
TArgs extends unknown[],
TParams extends {
primaryModelRef?: string;
},
>(params: {
resolveParams: (
cfg: OpenClawConfig,
...args: TArgs
) => Omit<TParams, "primaryModelRef"> | null | undefined;
applyPreset: (cfg: OpenClawConfig, preset: TParams) => OpenClawConfig;
primaryModelRef: string;
}): ProviderOnboardPresetAppliers<TArgs> {
return {
applyProviderConfig(cfg, ...args) {
const resolved = params.resolveParams(cfg, ...args);
return resolved ? params.applyPreset(cfg, resolved as TParams) : cfg;
},
applyConfig(cfg, ...args) {
const resolved = params.resolveParams(cfg, ...args);
if (!resolved) {
return cfg;
}
return params.applyPreset(cfg, {
...(resolved as TParams),
primaryModelRef: params.primaryModelRef,
});
},
};
}
export function createDefaultModelPresetAppliers<TArgs extends unknown[]>(params: {
resolveParams: (
cfg: OpenClawConfig,
...args: TArgs
) =>
| Omit<Parameters<typeof applyProviderConfigWithDefaultModelPreset>[1], "primaryModelRef">
| null
| undefined;
primaryModelRef: string;
}): ProviderOnboardPresetAppliers<TArgs> {
return createProviderPresetAppliers({
resolveParams: params.resolveParams,
applyPreset: applyProviderConfigWithDefaultModelPreset,
primaryModelRef: params.primaryModelRef,
});
}
export function applyProviderConfigWithDefaultModelsPreset(
cfg: OpenClawConfig,
params: {
@@ -199,6 +252,23 @@ export function applyProviderConfigWithDefaultModelsPreset(
: next;
}
export function createDefaultModelsPresetAppliers<TArgs extends unknown[]>(params: {
resolveParams: (
cfg: OpenClawConfig,
...args: TArgs
) =>
| Omit<Parameters<typeof applyProviderConfigWithDefaultModelsPreset>[1], "primaryModelRef">
| null
| undefined;
primaryModelRef: string;
}): ProviderOnboardPresetAppliers<TArgs> {
return createProviderPresetAppliers({
resolveParams: params.resolveParams,
applyPreset: applyProviderConfigWithDefaultModelsPreset,
primaryModelRef: params.primaryModelRef,
});
}
export function applyProviderConfigWithModelCatalog(
cfg: OpenClawConfig,
params: {
@@ -254,6 +324,23 @@ export function applyProviderConfigWithModelCatalogPreset(
: next;
}
export function createModelCatalogPresetAppliers<TArgs extends unknown[]>(params: {
resolveParams: (
cfg: OpenClawConfig,
...args: TArgs
) =>
| Omit<Parameters<typeof applyProviderConfigWithModelCatalogPreset>[1], "primaryModelRef">
| null
| undefined;
primaryModelRef: string;
}): ProviderOnboardPresetAppliers<TArgs> {
return createProviderPresetAppliers({
resolveParams: params.resolveParams,
applyPreset: applyProviderConfigWithModelCatalogPreset,
primaryModelRef: params.primaryModelRef,
});
}
type ProviderModelMergeState = {
providers: Record<string, ModelProviderConfig>;
existingProvider?: ModelProviderConfig;