mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
refactor(providers): manifest-declared default models and unified onboarding presets (#113794)
* feat(model-catalog): declare provider default models * refactor(providers): source onboarding defaults from manifests * fix(cohere): remove unused model id export * fix(chutes): preserve public default model id * fix(model-catalog): accept provider default models
This commit is contained in:
committed by
GitHub
parent
54df949aaa
commit
be6ec97e11
@@ -0,0 +1,20 @@
|
||||
import { resolveAgentModelPrimaryValue } from "openclaw/plugin-sdk/provider-onboard";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { applyCerebrasConfig, CEREBRAS_DEFAULT_MODEL_REF } from "./onboard.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
describe("Cerebras onboarding", () => {
|
||||
it("applies the manifest catalog, default, and alias", () => {
|
||||
const config = applyCerebrasConfig({});
|
||||
|
||||
expect(config.models?.providers?.cerebras?.models.map((model) => model.id)).toEqual(
|
||||
manifest.modelCatalog.providers.cerebras.models.map((model) => model.id),
|
||||
);
|
||||
expect(resolveAgentModelPrimaryValue(config.agents?.defaults?.model)).toBe(
|
||||
CEREBRAS_DEFAULT_MODEL_REF,
|
||||
);
|
||||
expect(config.agents?.defaults?.models).toEqual({
|
||||
[CEREBRAS_DEFAULT_MODEL_REF]: { alias: "Cerebras GLM 4.7" },
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,4 @@
|
||||
/**
|
||||
* Cerebras onboarding config helpers.
|
||||
*/
|
||||
import { readManifestProviderDefaultModelRef } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import {
|
||||
createModelCatalogPresetAppliers,
|
||||
type OpenClawConfig,
|
||||
@@ -10,9 +8,12 @@ import {
|
||||
CEREBRAS_BASE_URL,
|
||||
CEREBRAS_MODEL_CATALOG,
|
||||
} from "./models.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
/** Default Cerebras model reference used after onboarding. */
|
||||
export const CEREBRAS_DEFAULT_MODEL_REF = "cerebras/zai-glm-4.7";
|
||||
export const CEREBRAS_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(
|
||||
manifest,
|
||||
"cerebras",
|
||||
)!;
|
||||
|
||||
const cerebrasPresetAppliers = createModelCatalogPresetAppliers({
|
||||
primaryModelRef: CEREBRAS_DEFAULT_MODEL_REF,
|
||||
@@ -25,7 +26,6 @@ const cerebrasPresetAppliers = createModelCatalogPresetAppliers({
|
||||
}),
|
||||
});
|
||||
|
||||
/** Applies Cerebras provider/catalog config and default model aliases. */
|
||||
export function applyCerebrasConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return cerebrasPresetAppliers.applyConfig(cfg);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"cerebras": {
|
||||
"baseUrl": "https://api.cerebras.ai/v1",
|
||||
"api": "openai-completions",
|
||||
"defaultModel": "zai-glm-4.7",
|
||||
"models": [
|
||||
{
|
||||
"id": "zai-glm-4.7",
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
/**
|
||||
* Public Chutes provider plugin API exports.
|
||||
*/
|
||||
export {
|
||||
buildChutesModelDefinition,
|
||||
CHUTES_BASE_URL,
|
||||
CHUTES_DEFAULT_MODEL_ID,
|
||||
CHUTES_DEFAULT_MODEL_REF,
|
||||
CHUTES_MODEL_CATALOG,
|
||||
discoverChutesModels,
|
||||
} from "./models.js";
|
||||
@@ -14,4 +9,6 @@ export {
|
||||
applyChutesApiKeyConfig,
|
||||
applyChutesConfig,
|
||||
applyChutesProviderConfig,
|
||||
CHUTES_DEFAULT_MODEL_ID,
|
||||
CHUTES_DEFAULT_MODEL_REF,
|
||||
} from "./onboard.js";
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
import { expectDefined } from "@openclaw/normalization-core";
|
||||
import { clearLiveCatalogCacheForTests } from "openclaw/plugin-sdk/provider-catalog-live-runtime";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { CHUTES_DEFAULT_MODEL_ID } from "./api.js";
|
||||
import {
|
||||
buildChutesModelDefinition,
|
||||
CHUTES_DEFAULT_MODEL_ID,
|
||||
CHUTES_DEFAULT_MODEL_REF,
|
||||
CHUTES_MODEL_CATALOG,
|
||||
discoverChutesModels,
|
||||
} from "./models.js";
|
||||
import { applyChutesConfig } from "./onboard.js";
|
||||
import { applyChutesConfig, CHUTES_DEFAULT_MODEL_REF } from "./onboard.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
const EXPECTED_STATIC_MODEL_IDS = [
|
||||
@@ -136,7 +135,8 @@ describe("chutes-models", () => {
|
||||
const runtimeIds = CHUTES_MODEL_CATALOG.map((model) => model.id);
|
||||
expect(manifestIds).toEqual(EXPECTED_STATIC_MODEL_IDS);
|
||||
expect(runtimeIds).toEqual(EXPECTED_STATIC_MODEL_IDS);
|
||||
expect(CHUTES_DEFAULT_MODEL_ID).toBe("zai-org/GLM-5.2-TEE");
|
||||
expect(CHUTES_DEFAULT_MODEL_ID).toBe(manifest.modelCatalog.providers.chutes.defaultModel);
|
||||
expect(manifest.modelCatalog.providers.chutes.defaultModel).toBe("zai-org/GLM-5.2-TEE");
|
||||
expect(
|
||||
manifest.modelCatalog.providers.chutes.models
|
||||
.filter((model) => "status" in model && model.status === "deprecated")
|
||||
@@ -171,6 +171,13 @@ describe("chutes-models", () => {
|
||||
expect(cfg.agents?.defaults?.models?.["chutes-vision"]?.alias).toBe(
|
||||
"chutes/moonshotai/Kimi-K2.6-TEE",
|
||||
);
|
||||
expect(Object.keys(cfg.agents?.defaults?.models ?? {}).toSorted()).toEqual(
|
||||
[
|
||||
...EXPECTED_STATIC_MODEL_IDS.map((id) => `chutes/${id}`),
|
||||
"chutes-pro",
|
||||
"chutes-vision",
|
||||
].toSorted(),
|
||||
);
|
||||
const catalogBackedTargets = [
|
||||
CHUTES_DEFAULT_MODEL_REF,
|
||||
"chutes/deepseek-ai/DeepSeek-V3.2-TEE",
|
||||
|
||||
@@ -30,10 +30,6 @@ const CHUTES_MANIFEST_PROVIDER = buildManifestModelProviderConfig({
|
||||
|
||||
/** Base URL for Chutes OpenAI-compatible inference. */
|
||||
export const CHUTES_BASE_URL = CHUTES_MANIFEST_PROVIDER.baseUrl;
|
||||
/** Default Chutes model id used for onboarding. */
|
||||
export const CHUTES_DEFAULT_MODEL_ID = "zai-org/GLM-5.2-TEE";
|
||||
/** Default Chutes model ref used for onboarding. */
|
||||
export const CHUTES_DEFAULT_MODEL_REF = `chutes/${CHUTES_DEFAULT_MODEL_ID}`;
|
||||
|
||||
const CHUTES_DEFAULT_CONTEXT_WINDOW = 128000;
|
||||
const CHUTES_DEFAULT_MAX_TOKENS = 4096;
|
||||
|
||||
@@ -1,26 +1,18 @@
|
||||
/**
|
||||
* Chutes onboarding config helpers for OAuth and API-key setup.
|
||||
*/
|
||||
import { readManifestProviderDefaultModelRef } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import {
|
||||
applyAgentDefaultModelPrimary,
|
||||
applyProviderConfigWithModelCatalogPreset,
|
||||
createModelCatalogPresetAppliers,
|
||||
type OpenClawConfig,
|
||||
} from "openclaw/plugin-sdk/provider-onboard";
|
||||
import {
|
||||
CHUTES_BASE_URL,
|
||||
CHUTES_DEFAULT_MODEL_REF,
|
||||
CHUTES_MODEL_CATALOG,
|
||||
buildChutesModelDefinition,
|
||||
} from "./models.js";
|
||||
import { CHUTES_BASE_URL, CHUTES_MODEL_CATALOG, buildChutesModelDefinition } from "./models.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
export { CHUTES_DEFAULT_MODEL_REF };
|
||||
export const CHUTES_DEFAULT_MODEL_ID = manifest.modelCatalog.providers.chutes.defaultModel;
|
||||
export const CHUTES_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(manifest, "chutes")!;
|
||||
|
||||
/**
|
||||
* Apply Chutes provider configuration without changing the default model.
|
||||
* Registers all catalog models and convenience aliases.
|
||||
*/
|
||||
export function applyChutesProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return applyProviderConfigWithModelCatalogPreset(cfg, {
|
||||
const chutesPresetAppliers = createModelCatalogPresetAppliers({
|
||||
primaryModelRef: CHUTES_DEFAULT_MODEL_REF,
|
||||
resolveParams: (_cfg: OpenClawConfig) => ({
|
||||
providerId: "chutes",
|
||||
api: "openai-completions",
|
||||
baseUrl: CHUTES_BASE_URL,
|
||||
@@ -33,12 +25,13 @@ export function applyChutesProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
},
|
||||
{ modelRef: "chutes-pro", alias: "chutes/deepseek-ai/DeepSeek-V3.2-TEE" },
|
||||
],
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
||||
export function applyChutesProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return chutesPresetAppliers.applyProviderConfig(cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply Chutes provider configuration AND set Chutes as the default model.
|
||||
*/
|
||||
export function applyChutesConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
const next = applyChutesProviderConfig(cfg);
|
||||
return {
|
||||
@@ -60,7 +53,6 @@ export function applyChutesConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
};
|
||||
}
|
||||
|
||||
/** Applies Chutes provider config and sets the default model for API-key auth. */
|
||||
export function applyChutesApiKeyConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return applyAgentDefaultModelPrimary(applyChutesProviderConfig(cfg), CHUTES_DEFAULT_MODEL_REF);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"chutes": {
|
||||
"baseUrl": "https://llm.chutes.ai/v1",
|
||||
"api": "openai-completions",
|
||||
"defaultModel": "zai-org/GLM-5.2-TEE",
|
||||
"models": [
|
||||
{
|
||||
"id": "deepseek-ai/DeepSeek-V3.2-TEE",
|
||||
|
||||
@@ -5,10 +5,10 @@ import { registerSingleProviderPlugin } from "openclaw/plugin-sdk/plugin-test-ru
|
||||
import { buildOpenAICompletionsParams } from "openclaw/plugin-sdk/provider-transport-runtime";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import plugin from "./index.js";
|
||||
import { COHERE_COMMAND_A_PLUS_MODEL_ID } from "./models.js";
|
||||
import { buildCohereProvider, COHERE_LIVE_MODEL_DISCOVERY } from "./provider-catalog.js";
|
||||
import { createCohereCompletionsWrapper } from "./stream.js";
|
||||
|
||||
const COHERE_COMMAND_A_PLUS_MODEL_ID = "command-a-plus-05-2026";
|
||||
const COHERE_COMMAND_A_REASONING_MODEL_ID = "command-a-reasoning-08-2025";
|
||||
const COHERE_COMMAND_A_VISION_MODEL_ID = "command-a-vision-07-2025";
|
||||
const COHERE_NORTH_MINI_CODE_MODEL_ID = "north-mini-code-1-0";
|
||||
|
||||
@@ -10,7 +10,7 @@ const COHERE_MANIFEST_CATALOG = manifest.modelCatalog.providers.cohere;
|
||||
|
||||
export const COHERE_BASE_URL = COHERE_MANIFEST_CATALOG.baseUrl;
|
||||
export const COHERE_MODEL_CATALOG = COHERE_MANIFEST_CATALOG.models;
|
||||
export const COHERE_COMMAND_A_PLUS_MODEL_ID = "command-a-plus-05-2026";
|
||||
const COHERE_COMMAND_A_PLUS_MODEL_ID = "command-a-plus-05-2026";
|
||||
const COHERE_COMMAND_A_REASONING_MODEL_ID = "command-a-reasoning-08-2025";
|
||||
const COHERE_NORTH_MINI_CODE_MODEL_ID = "north-mini-code-1-0";
|
||||
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import { readManifestProviderDefaultModelRef } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import {
|
||||
createModelCatalogPresetAppliers,
|
||||
type OpenClawConfig,
|
||||
} from "openclaw/plugin-sdk/provider-onboard";
|
||||
import {
|
||||
buildCohereModelDefinition,
|
||||
COHERE_BASE_URL,
|
||||
COHERE_COMMAND_A_PLUS_MODEL_ID,
|
||||
COHERE_MODEL_CATALOG,
|
||||
} from "./models.js";
|
||||
import { buildCohereModelDefinition, COHERE_BASE_URL, COHERE_MODEL_CATALOG } from "./models.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
const COHERE_DEFAULT_MODEL_ID = COHERE_COMMAND_A_PLUS_MODEL_ID;
|
||||
export const COHERE_DEFAULT_MODEL_REF = `cohere/${COHERE_DEFAULT_MODEL_ID}`;
|
||||
export const COHERE_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(manifest, "cohere")!;
|
||||
|
||||
const coherePresetAppliers = createModelCatalogPresetAppliers({
|
||||
primaryModelRef: COHERE_DEFAULT_MODEL_REF,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"cohere": {
|
||||
"baseUrl": "https://api.cohere.ai/compatibility/v1",
|
||||
"api": "openai-completions",
|
||||
"defaultModel": "command-a-plus-05-2026",
|
||||
"models": [
|
||||
{
|
||||
"id": "command-a-plus-05-2026",
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { resolveAgentModelPrimaryValue } from "openclaw/plugin-sdk/provider-onboard";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { applyDeepSeekConfig, DEEPSEEK_DEFAULT_MODEL_REF } from "./onboard.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
describe("DeepSeek onboarding", () => {
|
||||
it("applies the manifest catalog, default, and alias", () => {
|
||||
const config = applyDeepSeekConfig({});
|
||||
|
||||
expect(config.models?.providers?.deepseek?.models.map((model) => model.id)).toEqual(
|
||||
manifest.modelCatalog.providers.deepseek.models.map((model) => model.id),
|
||||
);
|
||||
expect(resolveAgentModelPrimaryValue(config.agents?.defaults?.model)).toBe(
|
||||
DEEPSEEK_DEFAULT_MODEL_REF,
|
||||
);
|
||||
expect(config.agents?.defaults?.models).toEqual({
|
||||
[DEEPSEEK_DEFAULT_MODEL_REF]: { alias: "DeepSeek" },
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,32 +1,31 @@
|
||||
// Deepseek setup module handles plugin onboarding behavior.
|
||||
import { readManifestProviderDefaultModelRef } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import {
|
||||
applyAgentDefaultModelPrimary,
|
||||
applyProviderConfigWithModelCatalog,
|
||||
createModelCatalogPresetAppliers,
|
||||
type OpenClawConfig,
|
||||
} from "openclaw/plugin-sdk/provider-onboard";
|
||||
import { buildDeepSeekModelDefinition, DEEPSEEK_BASE_URL, DEEPSEEK_MODEL_CATALOG } from "./api.js";
|
||||
import {
|
||||
buildDeepSeekModelDefinition,
|
||||
DEEPSEEK_BASE_URL,
|
||||
DEEPSEEK_MODEL_CATALOG,
|
||||
} from "./models.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
export const DEEPSEEK_DEFAULT_MODEL_REF = "deepseek/deepseek-v4-flash";
|
||||
export const DEEPSEEK_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(
|
||||
manifest,
|
||||
"deepseek",
|
||||
)!;
|
||||
|
||||
function applyDeepSeekProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
const models = { ...cfg.agents?.defaults?.models };
|
||||
models[DEEPSEEK_DEFAULT_MODEL_REF] = {
|
||||
...models[DEEPSEEK_DEFAULT_MODEL_REF],
|
||||
alias: models[DEEPSEEK_DEFAULT_MODEL_REF]?.alias ?? "DeepSeek",
|
||||
};
|
||||
|
||||
return applyProviderConfigWithModelCatalog(cfg, {
|
||||
agentModels: models,
|
||||
const deepSeekPresetAppliers = createModelCatalogPresetAppliers({
|
||||
primaryModelRef: DEEPSEEK_DEFAULT_MODEL_REF,
|
||||
resolveParams: (_cfg: OpenClawConfig) => ({
|
||||
providerId: "deepseek",
|
||||
api: "openai-completions",
|
||||
baseUrl: DEEPSEEK_BASE_URL,
|
||||
catalogModels: DEEPSEEK_MODEL_CATALOG.map(buildDeepSeekModelDefinition),
|
||||
});
|
||||
}
|
||||
aliases: [{ modelRef: DEEPSEEK_DEFAULT_MODEL_REF, alias: "DeepSeek" }],
|
||||
}),
|
||||
});
|
||||
|
||||
export function applyDeepSeekConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return applyAgentDefaultModelPrimary(
|
||||
applyDeepSeekProviderConfig(cfg),
|
||||
DEEPSEEK_DEFAULT_MODEL_REF,
|
||||
);
|
||||
return deepSeekPresetAppliers.applyConfig(cfg);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"deepseek": {
|
||||
"baseUrl": "https://api.deepseek.com",
|
||||
"api": "openai-completions",
|
||||
"defaultModel": "deepseek-v4-flash",
|
||||
"models": [
|
||||
{
|
||||
"id": "deepseek-v4-flash",
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Fireworks plugin entrypoint registers its OpenClaw integration.
|
||||
import type { ProviderResolveDynamicModelContext } from "openclaw/plugin-sdk/plugin-entry";
|
||||
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
|
||||
import {
|
||||
@@ -8,13 +7,14 @@ import {
|
||||
normalizeModelCompat,
|
||||
} from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { isFireworksKimiModelId } from "./model-id.js";
|
||||
import { applyFireworksConfig, FIREWORKS_DEFAULT_MODEL_REF } from "./onboard.js";
|
||||
import { applyFireworksConfig } from "./onboard.js";
|
||||
import {
|
||||
buildFireworksProvider,
|
||||
FIREWORKS_BASE_URL,
|
||||
FIREWORKS_DEFAULT_CONTEXT_WINDOW,
|
||||
FIREWORKS_DEFAULT_MAX_TOKENS,
|
||||
FIREWORKS_DEFAULT_MODEL_ID,
|
||||
FIREWORKS_DEFAULT_MODEL_REF,
|
||||
isFireworksCatalogModelId,
|
||||
} from "./provider-catalog.js";
|
||||
import { wrapFireworksProviderStream } from "./stream.js";
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { resolveAgentModelPrimaryValue } from "openclaw/plugin-sdk/provider-onboard";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { applyFireworksConfig } from "./onboard.js";
|
||||
import { FIREWORKS_DEFAULT_MODEL_REF, buildFireworksCatalogModels } from "./provider-catalog.js";
|
||||
|
||||
describe("Fireworks onboarding", () => {
|
||||
it("applies the manifest catalog, default, and alias", () => {
|
||||
const config = applyFireworksConfig({});
|
||||
|
||||
expect(config.models?.providers?.fireworks?.models).toEqual(buildFireworksCatalogModels());
|
||||
expect(resolveAgentModelPrimaryValue(config.agents?.defaults?.model)).toBe(
|
||||
FIREWORKS_DEFAULT_MODEL_REF,
|
||||
);
|
||||
expect(config.agents?.defaults?.models).toEqual({
|
||||
[FIREWORKS_DEFAULT_MODEL_REF]: { alias: "Kimi K2.6 Turbo" },
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,3 @@
|
||||
// Fireworks setup module handles plugin onboarding behavior.
|
||||
import {
|
||||
createDefaultModelsPresetAppliers,
|
||||
type OpenClawConfig,
|
||||
@@ -7,10 +6,9 @@ import {
|
||||
buildFireworksCatalogModels,
|
||||
buildFireworksProvider,
|
||||
FIREWORKS_DEFAULT_MODEL_ID,
|
||||
FIREWORKS_DEFAULT_MODEL_REF,
|
||||
} from "./provider-catalog.js";
|
||||
|
||||
export const FIREWORKS_DEFAULT_MODEL_REF = `fireworks/${FIREWORKS_DEFAULT_MODEL_ID}`;
|
||||
|
||||
const fireworksPresetAppliers = createDefaultModelsPresetAppliers({
|
||||
primaryModelRef: FIREWORKS_DEFAULT_MODEL_REF,
|
||||
resolveParams: (_cfg: OpenClawConfig) => {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"fireworks": {
|
||||
"baseUrl": "https://api.fireworks.ai/inference/v1",
|
||||
"api": "openai-completions",
|
||||
"defaultModel": "accounts/fireworks/routers/kimi-k2p6-turbo",
|
||||
"models": [
|
||||
{
|
||||
"id": "accounts/fireworks/models/kimi-k2p6",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Fireworks provider module implements model/runtime integration.
|
||||
import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import {
|
||||
buildManifestModelProviderConfig,
|
||||
readManifestProviderDefaultModelRef,
|
||||
} from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import type {
|
||||
ModelDefinitionConfig,
|
||||
ModelProviderConfig,
|
||||
@@ -10,9 +12,13 @@ const FIREWORKS_MANIFEST_PROVIDER = buildManifestModelProviderConfig({
|
||||
providerId: "fireworks",
|
||||
catalog: manifest.modelCatalog.providers.fireworks,
|
||||
});
|
||||
export const FIREWORKS_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(
|
||||
manifest,
|
||||
"fireworks",
|
||||
)!;
|
||||
|
||||
export const FIREWORKS_BASE_URL = FIREWORKS_MANIFEST_PROVIDER.baseUrl;
|
||||
export const FIREWORKS_DEFAULT_MODEL_ID = "accounts/fireworks/routers/kimi-k2p6-turbo";
|
||||
export const FIREWORKS_DEFAULT_MODEL_ID = FIREWORKS_DEFAULT_MODEL_REF.slice("fireworks/".length);
|
||||
|
||||
function requireFireworksManifestModel(id: string): ModelDefinitionConfig {
|
||||
const model = FIREWORKS_MANIFEST_PROVIDER.models.find((entry) => entry.id === id);
|
||||
|
||||
@@ -8,6 +8,7 @@ import { capturePluginRegistration } from "openclaw/plugin-sdk/plugin-test-runti
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveGroqReasoningCompatPatch } from "./api.js";
|
||||
import plugin from "./index.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
describe("groq provider compat", () => {
|
||||
it("recovers only matching implicit-budget rejections without changing normal tools", async () => {
|
||||
@@ -343,10 +344,10 @@ describe("groq provider compat", () => {
|
||||
});
|
||||
expect(provider.auth).toHaveLength(1);
|
||||
expect(provider.auth[0]).toMatchObject({
|
||||
defaultModel: "groq/openai/gpt-oss-120b",
|
||||
id: "api-key",
|
||||
kind: "api_key",
|
||||
label: "Groq API key",
|
||||
starterModel: `groq/${manifest.modelCatalog.providers.groq.defaultModel}`,
|
||||
wizard: {
|
||||
choiceId: "groq-api-key",
|
||||
groupId: "groq",
|
||||
|
||||
@@ -4,15 +4,17 @@ import {
|
||||
streamSimple,
|
||||
type AssistantMessageEvent,
|
||||
} from "openclaw/plugin-sdk/llm";
|
||||
// Groq plugin entrypoint registers its OpenClaw integration.
|
||||
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
||||
import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth-api-key";
|
||||
import { buildOpenAICompatibleProviderCatalog } from "openclaw/plugin-sdk/provider-catalog-live-runtime";
|
||||
import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import {
|
||||
buildManifestModelProviderConfig,
|
||||
readManifestProviderDefaultModelRef,
|
||||
} from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import { groqMediaUnderstandingProvider } from "./media-understanding-provider.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
const GROQ_DEFAULT_MODEL_REF = "groq/openai/gpt-oss-120b";
|
||||
const GROQ_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(manifest, "groq")!;
|
||||
const GROQ_OVERSIZED_RECOVERY_MODEL_ID = "llama-3.3-70b-versatile";
|
||||
const GROQ_FALLBACK_MAX_TOKENS = 1_024;
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"groq": {
|
||||
"baseUrl": "https://api.groq.com/openai/v1",
|
||||
"api": "openai-completions",
|
||||
"defaultModel": "openai/gpt-oss-120b",
|
||||
"models": [
|
||||
{
|
||||
"id": "groq/compound",
|
||||
|
||||
@@ -4,12 +4,9 @@ export {
|
||||
buildMistralModelDefinition,
|
||||
MISTRAL_BASE_URL,
|
||||
MISTRAL_DEFAULT_MODEL_ID,
|
||||
} from "./model-definitions.js";
|
||||
export {
|
||||
applyMistralConfig,
|
||||
applyMistralProviderConfig,
|
||||
MISTRAL_DEFAULT_MODEL_REF,
|
||||
} from "./onboard.js";
|
||||
} from "./model-definitions.js";
|
||||
export { applyMistralConfig, applyMistralProviderConfig } from "./onboard.js";
|
||||
|
||||
const MISTRAL_MAX_TOKENS_FIELD = "max_tokens";
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Mistral plugin entrypoint registers its OpenClaw integration.
|
||||
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
|
||||
import {
|
||||
applyMistralModelCompat,
|
||||
@@ -8,7 +7,8 @@ import {
|
||||
} from "./api.js";
|
||||
import { mistralMediaUnderstandingProvider } from "./media-understanding-provider.js";
|
||||
import { mistralMemoryEmbeddingProviderAdapter } from "./memory-embedding-adapter.js";
|
||||
import { applyMistralConfig, MISTRAL_DEFAULT_MODEL_REF } from "./onboard.js";
|
||||
import { MISTRAL_DEFAULT_MODEL_REF } from "./model-definitions.js";
|
||||
import { applyMistralConfig } from "./onboard.js";
|
||||
import { buildMistralProvider } from "./provider-catalog.js";
|
||||
import { buildMistralRealtimeTranscriptionProvider } from "./realtime-transcription-provider.js";
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
// Mistral plugin module implements model definitions behavior.
|
||||
import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import {
|
||||
buildManifestModelProviderConfig,
|
||||
readManifestProviderDefaultModelRef,
|
||||
} from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
const MISTRAL_MANIFEST_CATALOG = manifest.modelCatalog.providers.mistral;
|
||||
|
||||
export const MISTRAL_BASE_URL = MISTRAL_MANIFEST_CATALOG.baseUrl;
|
||||
export const MISTRAL_DEFAULT_MODEL_ID = "mistral-large-latest";
|
||||
export const MISTRAL_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(manifest, "mistral")!;
|
||||
export const MISTRAL_DEFAULT_MODEL_ID = MISTRAL_DEFAULT_MODEL_REF.slice("mistral/".length);
|
||||
|
||||
export function buildMistralModelDefinition(): ModelDefinitionConfig {
|
||||
const model = buildMistralCatalogModels().find((entry) => entry.id === MISTRAL_DEFAULT_MODEL_ID);
|
||||
|
||||
@@ -5,11 +5,8 @@ import {
|
||||
} from "openclaw/plugin-sdk/provider-test-contracts";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildMistralModelDefinition as buildBundledMistralModelDefinition } from "./model-definitions.js";
|
||||
import {
|
||||
applyMistralConfig,
|
||||
applyMistralProviderConfig,
|
||||
MISTRAL_DEFAULT_MODEL_REF,
|
||||
} from "./onboard.js";
|
||||
import { MISTRAL_DEFAULT_MODEL_REF } from "./model-definitions.js";
|
||||
import { applyMistralConfig, applyMistralProviderConfig } from "./onboard.js";
|
||||
|
||||
describe("mistral onboard", () => {
|
||||
it("adds Mistral provider with correct settings", () => {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Mistral setup module handles plugin onboarding behavior.
|
||||
import {
|
||||
createDefaultModelPresetAppliers,
|
||||
type OpenClawConfig,
|
||||
@@ -7,10 +6,9 @@ import {
|
||||
buildMistralModelDefinition,
|
||||
MISTRAL_BASE_URL,
|
||||
MISTRAL_DEFAULT_MODEL_ID,
|
||||
MISTRAL_DEFAULT_MODEL_REF,
|
||||
} from "./model-definitions.js";
|
||||
|
||||
export const MISTRAL_DEFAULT_MODEL_REF = `mistral/${MISTRAL_DEFAULT_MODEL_ID}`;
|
||||
|
||||
const mistralPresetAppliers = createDefaultModelPresetAppliers({
|
||||
primaryModelRef: MISTRAL_DEFAULT_MODEL_REF,
|
||||
resolveParams: (_cfg: OpenClawConfig) => ({
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"mistral": {
|
||||
"baseUrl": "https://api.mistral.ai/v1",
|
||||
"api": "openai-completions",
|
||||
"defaultModel": "mistral-large-latest",
|
||||
"models": [
|
||||
{
|
||||
"id": "codestral-latest",
|
||||
|
||||
@@ -10,8 +10,8 @@ import {
|
||||
} from "./models.js";
|
||||
import {
|
||||
applyTokenHubConfig,
|
||||
TOKENHUB_DEFAULT_MODEL_REF,
|
||||
applyTokenPlanConfig,
|
||||
TOKENHUB_DEFAULT_MODEL_REF,
|
||||
TOKENPLAN_DEFAULT_MODEL_REF,
|
||||
} from "./onboard.js";
|
||||
import { buildTokenHubProvider, buildTokenPlanProvider } from "./provider-catalog.js";
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { resolveAgentModelPrimaryValue } from "openclaw/plugin-sdk/provider-onboard";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
applyTokenHubConfig,
|
||||
applyTokenPlanConfig,
|
||||
TOKENHUB_DEFAULT_MODEL_REF,
|
||||
TOKENPLAN_DEFAULT_MODEL_REF,
|
||||
} from "./onboard.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
describe("Tencent onboarding", () => {
|
||||
it("applies the TokenHub manifest catalog, default, and aliases", () => {
|
||||
const config = applyTokenHubConfig({});
|
||||
|
||||
expect(config.models?.providers?.["tencent-tokenhub"]?.models.map((model) => model.id)).toEqual(
|
||||
manifest.modelCatalog.providers["tencent-tokenhub"].models.map((model) => model.id),
|
||||
);
|
||||
expect(resolveAgentModelPrimaryValue(config.agents?.defaults?.model)).toBe(
|
||||
TOKENHUB_DEFAULT_MODEL_REF,
|
||||
);
|
||||
expect(config.agents?.defaults?.models).toEqual({
|
||||
[TOKENHUB_DEFAULT_MODEL_REF]: { alias: "Hy3 (TokenHub)" },
|
||||
"tencent-tokenhub/hy3-preview": { alias: "Hy3 preview (TokenHub)" },
|
||||
});
|
||||
});
|
||||
|
||||
it("applies the TokenPlan manifest catalog, default, and alias", () => {
|
||||
const config = applyTokenPlanConfig({});
|
||||
|
||||
expect(
|
||||
config.models?.providers?.["tencent-tokenplan"]?.models.map((model) => model.id),
|
||||
).toEqual(manifest.modelCatalog.providers["tencent-tokenplan"].models.map((model) => model.id));
|
||||
expect(resolveAgentModelPrimaryValue(config.agents?.defaults?.model)).toBe(
|
||||
TOKENPLAN_DEFAULT_MODEL_REF,
|
||||
);
|
||||
expect(config.agents?.defaults?.models).toEqual({
|
||||
[TOKENPLAN_DEFAULT_MODEL_REF]: { alias: "Hy3 (TokenPlan)" },
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,6 @@
|
||||
// Tencent setup module handles plugin onboarding behavior.
|
||||
import { readManifestProviderDefaultModelRef } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import {
|
||||
applyAgentDefaultModelPrimary,
|
||||
applyProviderConfigWithModelCatalog,
|
||||
createModelCatalogPresetAppliers,
|
||||
type OpenClawConfig,
|
||||
} from "openclaw/plugin-sdk/provider-onboard";
|
||||
import {
|
||||
@@ -13,63 +12,49 @@ import {
|
||||
TOKENPLAN_BASE_URL,
|
||||
TOKENPLAN_MODEL_CATALOG,
|
||||
TOKENPLAN_PROVIDER_ID,
|
||||
} from "./api.js";
|
||||
} from "./models.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
// ---------- TokenHub ----------
|
||||
|
||||
export const TOKENHUB_DEFAULT_MODEL_REF = `${TOKENHUB_PROVIDER_ID}/hy3`;
|
||||
const TOKENHUB_PREVIEW_MODEL_REF = `${TOKENHUB_PROVIDER_ID}/hy3-preview`;
|
||||
export const TOKENHUB_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(
|
||||
manifest,
|
||||
TOKENHUB_PROVIDER_ID,
|
||||
)!;
|
||||
|
||||
function applyTokenHubProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
const models = { ...cfg.agents?.defaults?.models };
|
||||
models[TOKENHUB_DEFAULT_MODEL_REF] = {
|
||||
...models[TOKENHUB_DEFAULT_MODEL_REF],
|
||||
alias: models[TOKENHUB_DEFAULT_MODEL_REF]?.alias ?? "Hy3 (TokenHub)",
|
||||
};
|
||||
models[TOKENHUB_PREVIEW_MODEL_REF] = {
|
||||
...models[TOKENHUB_PREVIEW_MODEL_REF],
|
||||
alias: models[TOKENHUB_PREVIEW_MODEL_REF]?.alias ?? "Hy3 preview (TokenHub)",
|
||||
};
|
||||
|
||||
return applyProviderConfigWithModelCatalog(cfg, {
|
||||
agentModels: models,
|
||||
const tokenHubPresetAppliers = createModelCatalogPresetAppliers({
|
||||
primaryModelRef: TOKENHUB_DEFAULT_MODEL_REF,
|
||||
resolveParams: (_cfg: OpenClawConfig) => ({
|
||||
providerId: TOKENHUB_PROVIDER_ID,
|
||||
api: "openai-completions",
|
||||
baseUrl: TOKENHUB_BASE_URL,
|
||||
catalogModels: TOKENHUB_MODEL_CATALOG.map(buildTokenHubModelDefinition),
|
||||
});
|
||||
}
|
||||
aliases: [
|
||||
{ modelRef: TOKENHUB_DEFAULT_MODEL_REF, alias: "Hy3 (TokenHub)" },
|
||||
{ modelRef: TOKENHUB_PREVIEW_MODEL_REF, alias: "Hy3 preview (TokenHub)" },
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
export function applyTokenHubConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return applyAgentDefaultModelPrimary(
|
||||
applyTokenHubProviderConfig(cfg),
|
||||
TOKENHUB_DEFAULT_MODEL_REF,
|
||||
);
|
||||
return tokenHubPresetAppliers.applyConfig(cfg);
|
||||
}
|
||||
|
||||
// ---------- TokenPlan ----------
|
||||
export const TOKENPLAN_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(
|
||||
manifest,
|
||||
TOKENPLAN_PROVIDER_ID,
|
||||
)!;
|
||||
|
||||
export const TOKENPLAN_DEFAULT_MODEL_REF = `${TOKENPLAN_PROVIDER_ID}/hy3`;
|
||||
|
||||
function applyTokenPlanProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
const models = { ...cfg.agents?.defaults?.models };
|
||||
models[TOKENPLAN_DEFAULT_MODEL_REF] = {
|
||||
...models[TOKENPLAN_DEFAULT_MODEL_REF],
|
||||
alias: models[TOKENPLAN_DEFAULT_MODEL_REF]?.alias ?? "Hy3 (TokenPlan)",
|
||||
};
|
||||
|
||||
return applyProviderConfigWithModelCatalog(cfg, {
|
||||
agentModels: models,
|
||||
const tokenPlanPresetAppliers = createModelCatalogPresetAppliers({
|
||||
primaryModelRef: TOKENPLAN_DEFAULT_MODEL_REF,
|
||||
resolveParams: (_cfg: OpenClawConfig) => ({
|
||||
providerId: TOKENPLAN_PROVIDER_ID,
|
||||
api: "openai-completions",
|
||||
baseUrl: TOKENPLAN_BASE_URL,
|
||||
catalogModels: TOKENPLAN_MODEL_CATALOG.map(buildTokenPlanModelDefinition),
|
||||
});
|
||||
}
|
||||
aliases: [{ modelRef: TOKENPLAN_DEFAULT_MODEL_REF, alias: "Hy3 (TokenPlan)" }],
|
||||
}),
|
||||
});
|
||||
|
||||
export function applyTokenPlanConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return applyAgentDefaultModelPrimary(
|
||||
applyTokenPlanProviderConfig(cfg),
|
||||
TOKENPLAN_DEFAULT_MODEL_REF,
|
||||
);
|
||||
return tokenPlanPresetAppliers.applyConfig(cfg);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"tencent-tokenhub": {
|
||||
"baseUrl": "https://tokenhub.tencentmaas.com/v1",
|
||||
"api": "openai-completions",
|
||||
"defaultModel": "hy3",
|
||||
"models": [
|
||||
{
|
||||
"id": "hy3-preview",
|
||||
@@ -80,6 +81,7 @@
|
||||
"tencent-tokenplan": {
|
||||
"baseUrl": "https://api.lkeap.cloud.tencent.com/plan/v3",
|
||||
"api": "openai-completions",
|
||||
"defaultModel": "hy3",
|
||||
"models": [
|
||||
{
|
||||
"id": "hy3",
|
||||
|
||||
@@ -5,7 +5,8 @@ import {
|
||||
type ModelCompatConfig,
|
||||
} from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { applyVeniceConfig, VENICE_DEFAULT_MODEL_REF } from "./onboard.js";
|
||||
import { VENICE_DEFAULT_MODEL_REF } from "./models.js";
|
||||
import { applyVeniceConfig } from "./onboard.js";
|
||||
import { buildVeniceProvider } from "./provider-catalog.js";
|
||||
import { createVeniceDeepSeekV4Wrapper } from "./stream.js";
|
||||
import { fetchVeniceUsage } from "./usage.js";
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// Venice plugin module implements models behavior.
|
||||
import {
|
||||
getCachedLiveProviderModelRows,
|
||||
LiveModelCatalogHttpError,
|
||||
} from "openclaw/plugin-sdk/provider-catalog-live-runtime";
|
||||
import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import {
|
||||
buildManifestModelProviderConfig,
|
||||
readManifestProviderDefaultModelRef,
|
||||
} from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { createSubsystemLogger, retryAsync } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
@@ -17,8 +19,7 @@ const VENICE_MANIFEST_PROVIDER = buildManifestModelProviderConfig({
|
||||
});
|
||||
|
||||
export const VENICE_BASE_URL = VENICE_MANIFEST_PROVIDER.baseUrl;
|
||||
const VENICE_DEFAULT_MODEL_ID = "kimi-k2-5";
|
||||
export const VENICE_DEFAULT_MODEL_REF = `venice/${VENICE_DEFAULT_MODEL_ID}`;
|
||||
export const VENICE_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(manifest, "venice")!;
|
||||
const VENICE_ALLOWED_HOSTNAMES = ["api.venice.ai"];
|
||||
|
||||
const VENICE_DEFAULT_COST = {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { resolveAgentModelPrimaryValue } from "openclaw/plugin-sdk/provider-onboard";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { VENICE_DEFAULT_MODEL_REF } from "./models.js";
|
||||
import { applyVeniceConfig } from "./onboard.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
describe("Venice onboarding", () => {
|
||||
it("applies the manifest catalog, default, and alias", () => {
|
||||
const config = applyVeniceConfig({});
|
||||
|
||||
expect(config.models?.providers?.venice?.models.map((model) => model.id)).toEqual(
|
||||
manifest.modelCatalog.providers.venice.models.map((model) => model.id),
|
||||
);
|
||||
expect(resolveAgentModelPrimaryValue(config.agents?.defaults?.model)).toBe(
|
||||
VENICE_DEFAULT_MODEL_REF,
|
||||
);
|
||||
expect(config.agents?.defaults?.models).toEqual({
|
||||
[VENICE_DEFAULT_MODEL_REF]: { alias: "Kimi K2.5" },
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -10,8 +10,6 @@ import {
|
||||
VENICE_MODEL_CATALOG,
|
||||
} from "./api.js";
|
||||
|
||||
export { VENICE_DEFAULT_MODEL_REF };
|
||||
|
||||
const venicePresetAppliers = createModelCatalogPresetAppliers({
|
||||
primaryModelRef: VENICE_DEFAULT_MODEL_REF,
|
||||
resolveParams: (_cfg: OpenClawConfig) => ({
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
"venice": {
|
||||
"baseUrl": "https://api.venice.ai/api/v1",
|
||||
"api": "openai-completions",
|
||||
"defaultModel": "kimi-k2-5",
|
||||
"models": [
|
||||
{
|
||||
"id": "zai-org-glm-5-2",
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Zai plugin module implements model definitions behavior.
|
||||
import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
@@ -7,7 +6,7 @@ export const ZAI_CODING_GLOBAL_BASE_URL = "https://api.z.ai/api/coding/paas/v4";
|
||||
export const ZAI_CODING_CN_BASE_URL = "https://open.bigmodel.cn/api/coding/paas/v4";
|
||||
export const ZAI_GLOBAL_BASE_URL = "https://api.z.ai/api/paas/v4";
|
||||
export const ZAI_CN_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
|
||||
export const ZAI_DEFAULT_MODEL_ID = "glm-5.1";
|
||||
export const ZAI_DEFAULT_MODEL_ID = manifest.modelCatalog.providers.zai.defaultModel;
|
||||
export const ZAI_CODING_DEFAULT_MODEL_ID = "glm-5.2";
|
||||
|
||||
const ZAI_MANIFEST_CATALOG = manifest.modelCatalog.providers.zai;
|
||||
|
||||
@@ -40,6 +40,13 @@ describe("zai onboard", () => {
|
||||
).not.toHaveProperty("baseUrl");
|
||||
});
|
||||
|
||||
it("uses the manifest default and alias for a fresh general endpoint setup", () => {
|
||||
expect(resolveAgentModelPrimaryValue(defaultCfg.agents?.defaults?.model)).toBe("zai/glm-5.1");
|
||||
expect(defaultCfg.agents?.defaults?.models).toEqual({
|
||||
"zai/glm-5.1": { alias: "GLM" },
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves GLM-5.2 through the selected Coding Plan or custom endpoint", async () => {
|
||||
for (const [name, cfg, expectedBaseUrl] of [
|
||||
["coding-cn", applyZaiConfig({}, { endpoint: "coding-cn" }), ZAI_CODING_CN_BASE_URL],
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"zai": {
|
||||
"baseUrl": "https://api.z.ai/api/paas/v4",
|
||||
"api": "openai-completions",
|
||||
"defaultModel": "glm-5.1",
|
||||
"models": [
|
||||
{
|
||||
"id": "glm-5.2",
|
||||
|
||||
@@ -14,6 +14,7 @@ describe("model catalog normalization", () => {
|
||||
headers: {
|
||||
"x-provider": "openai",
|
||||
},
|
||||
defaultModel: " gpt-5.4 ",
|
||||
defaultUtilityModel: " gpt-5.6-luna ",
|
||||
models: [
|
||||
{
|
||||
@@ -130,6 +131,7 @@ describe("model catalog normalization", () => {
|
||||
headers: {
|
||||
"x-provider": "openai",
|
||||
},
|
||||
defaultModel: "gpt-5.4",
|
||||
defaultUtilityModel: "gpt-5.6-luna",
|
||||
models: [
|
||||
{
|
||||
|
||||
@@ -537,11 +537,13 @@ function normalizeModelCatalogProvider(value: unknown): ModelCatalogProvider | u
|
||||
const baseUrl = normalizeOptionalString(value.baseUrl) ?? "";
|
||||
const api = normalizeModelCatalogApi(value.api);
|
||||
const headers = normalizeStringMap(value.headers);
|
||||
const defaultModel = normalizeOptionalString(value.defaultModel) ?? "";
|
||||
const defaultUtilityModel = normalizeOptionalString(value.defaultUtilityModel) ?? "";
|
||||
return {
|
||||
...(baseUrl ? { baseUrl } : {}),
|
||||
...(api ? { api } : {}),
|
||||
...(headers ? { headers } : {}),
|
||||
...(defaultModel ? { defaultModel } : {}),
|
||||
...(defaultUtilityModel ? { defaultUtilityModel } : {}),
|
||||
models,
|
||||
};
|
||||
|
||||
@@ -245,6 +245,8 @@ export type ModelCatalogProvider = {
|
||||
baseUrl?: string;
|
||||
api?: ModelCatalogApi;
|
||||
headers?: Record<string, string>;
|
||||
/** Provider-recommended primary model id. */
|
||||
defaultModel?: string;
|
||||
/** Provider-recommended small model id for short internal utility tasks. */
|
||||
defaultUtilityModel?: string;
|
||||
models: ModelCatalogModel[];
|
||||
|
||||
@@ -13,6 +13,8 @@ const validBundle = {
|
||||
anthropic: {
|
||||
baseUrl: "https://evil.test",
|
||||
headers: { Authorization: "bad" },
|
||||
defaultModel: "claude-test",
|
||||
defaultUtilityModel: "claude-test",
|
||||
models: [
|
||||
{
|
||||
id: "claude-test",
|
||||
@@ -35,6 +37,10 @@ describe("remote model catalog bundle", () => {
|
||||
}
|
||||
expect(anthropic).not.toHaveProperty("baseUrl");
|
||||
expect(anthropic).not.toHaveProperty("headers");
|
||||
expect(anthropic).toMatchObject({
|
||||
defaultModel: "claude-test",
|
||||
defaultUtilityModel: "claude-test",
|
||||
});
|
||||
expect(anthropic.models[0]).not.toHaveProperty("baseUrl");
|
||||
expect(anthropic.models[0]).not.toHaveProperty("headers");
|
||||
expect(anthropic.models[0]?.compat).toEqual({ nested: {} });
|
||||
|
||||
@@ -57,6 +57,7 @@ export const remoteModelCatalogProviderSchema = z
|
||||
baseUrl: z.string().optional(),
|
||||
api: z.enum(MODEL_CATALOG_APIS).optional(),
|
||||
headers: stringMapSchema.optional(),
|
||||
defaultModel: z.string().optional(),
|
||||
defaultUtilityModel: z.string().optional(),
|
||||
models: z.array(modelSchema).min(1),
|
||||
})
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
clearLiveCatalogCacheForTests,
|
||||
getCachedLiveCatalogValue,
|
||||
readConfiguredProviderCatalogEntries,
|
||||
readManifestProviderDefaultModelRef,
|
||||
supportsNativeStreamingUsageCompat,
|
||||
} from "./provider-catalog-shared.js";
|
||||
import type { ModelDefinitionConfig } from "./provider-model-shared.js";
|
||||
@@ -298,6 +299,7 @@ describe("provider-catalog-shared manifest provider configs", () => {
|
||||
const catalog: ModelCatalogProvider = {
|
||||
baseUrl: "https://api.example.test/v1",
|
||||
api: "openai-completions",
|
||||
defaultModel: " example-model ",
|
||||
headers: { "x-provider": "example" },
|
||||
models: [
|
||||
{
|
||||
@@ -368,6 +370,12 @@ describe("provider-catalog-shared manifest provider configs", () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(
|
||||
readManifestProviderDefaultModelRef(
|
||||
{ modelCatalog: { providers: { example: catalog } } },
|
||||
"example",
|
||||
),
|
||||
).toBe("example/example-model");
|
||||
});
|
||||
|
||||
it("normalizes retired nested Gemini ids before emitting manifest provider config", () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Provider catalog helpers normalize, hash, and expose model catalogs for provider plugins.
|
||||
import { createHash } from "node:crypto";
|
||||
import { normalizeModelCatalog } from "@openclaw/model-catalog-core/model-catalog-normalize";
|
||||
import { buildModelCatalogRef } from "@openclaw/model-catalog-core/model-catalog-refs";
|
||||
import type {
|
||||
ModelCatalogCost,
|
||||
ModelCatalogMediaInputConfig,
|
||||
@@ -12,6 +13,7 @@ import {
|
||||
isFutureDateTimestampMs,
|
||||
resolveExpiresAtMsFromDurationMs,
|
||||
} from "../../packages/normalization-core/src/number-coercion.js";
|
||||
import { normalizeOptionalString } from "../../packages/normalization-core/src/string-coerce.js";
|
||||
import { normalizeConfiguredProviderCatalogModelId } from "../agents/model-ref-shared.js";
|
||||
import { resolveProviderRequestCapabilities } from "../agents/provider-attribution.js";
|
||||
import type { ModelDefinitionConfig } from "../config/types.models.js";
|
||||
@@ -125,6 +127,19 @@ function countRawManifestCatalogModels(catalog: unknown): number | undefined {
|
||||
return Array.isArray(models) ? models.length : undefined;
|
||||
}
|
||||
|
||||
/** Reads a provider's normalized manifest default as a fully qualified model ref. */
|
||||
export function readManifestProviderDefaultModelRef(
|
||||
manifest: unknown,
|
||||
providerId: string,
|
||||
): string | undefined {
|
||||
const catalog = (manifest as { modelCatalog?: { providers?: Record<string, unknown> } })
|
||||
?.modelCatalog?.providers?.[providerId];
|
||||
const defaultModel = normalizeOptionalString(
|
||||
(catalog as { defaultModel?: unknown })?.defaultModel,
|
||||
);
|
||||
return defaultModel ? buildModelCatalogRef(providerId, defaultModel) : undefined;
|
||||
}
|
||||
|
||||
function cloneManifestCatalogTieredCost(
|
||||
tier: ModelCatalogTieredCost,
|
||||
): NonNullable<ModelDefinitionConfig["cost"]["tieredPricing"]>[number] {
|
||||
|
||||
Reference in New Issue
Block a user