diff --git a/extensions/arcee/index.ts b/extensions/arcee/index.ts index e8eec9d1969..bb764a5a73d 100644 --- a/extensions/arcee/index.ts +++ b/extensions/arcee/index.ts @@ -5,10 +5,6 @@ import { type ProviderCatalogContext, } from "openclaw/plugin-sdk/provider-catalog-shared"; import { OPENAI_COMPATIBLE_REPLAY_HOOKS } from "openclaw/plugin-sdk/provider-model-shared"; -import { - ARCEE_TRINITY_LARGE_THINKING_COMPAT, - shouldContributeArceeTrinityLargeThinkingCompat, -} from "./models.js"; import { applyArceeConfig, applyArceeOpenRouterConfig, @@ -21,7 +17,11 @@ import { normalizeArceeOpenRouterBaseUrl, toArceeOpenRouterModelId, } from "./provider-catalog.js"; -import { normalizeArceeProviderConfig } from "./provider-policy-api.js"; +import { + ARCEE_TRINITY_LARGE_THINKING_COMPAT, + normalizeArceeProviderConfig, + shouldContributeArceeTrinityLargeThinkingCompat, +} from "./provider-policy.js"; const PROVIDER_ID = "arcee"; const ARCEE_WIZARD_GROUP = { diff --git a/extensions/arcee/models.ts b/extensions/arcee/models.ts index 8c7ac699a94..cb8873301f2 100644 --- a/extensions/arcee/models.ts +++ b/extensions/arcee/models.ts @@ -1,58 +1,7 @@ -import type { - ModelCompatConfig, - ModelDefinitionConfig, -} from "openclaw/plugin-sdk/provider-model-shared"; +import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-types"; +import { ARCEE_BASE_URL, ARCEE_TRINITY_LARGE_THINKING_COMPAT } from "./provider-policy.js"; -export const ARCEE_BASE_URL = "https://api.arcee.ai/api/v1"; -export const ARCEE_TRINITY_LARGE_THINKING_COMPAT = { - supportsReasoningEffort: false, - supportsTools: false, -} as const satisfies ModelCompatConfig; - -const ARCEE_PROVIDER_ID = "arcee"; -const ARCEE_TRINITY_LARGE_THINKING_ID = "trinity-large-thinking"; -const ARCEE_TRINITY_LARGE_THINKING_REF = `${ARCEE_PROVIDER_ID}/${ARCEE_TRINITY_LARGE_THINKING_ID}`; - -function normalizeModelId(modelId: string): string { - return modelId.trim().toLowerCase(); -} - -function normalizeBaseUrl(baseUrl: unknown): string { - return typeof baseUrl === "string" ? baseUrl.trim().replace(/\/+$/, "") : ""; -} - -export function isArceeTrinityLargeThinkingModelId(modelId: string): boolean { - const normalized = normalizeModelId(modelId); - return ( - normalized === ARCEE_TRINITY_LARGE_THINKING_ID || - normalized === ARCEE_TRINITY_LARGE_THINKING_REF - ); -} - -export function shouldContributeArceeTrinityLargeThinkingCompat(params: { - provider?: unknown; - modelId: string; - model: { id: string; provider?: unknown; baseUrl?: unknown }; -}): boolean { - const modelId = normalizeModelId(params.modelId); - const resolvedId = normalizeModelId(params.model.id); - if ( - modelId === ARCEE_TRINITY_LARGE_THINKING_REF || - resolvedId === ARCEE_TRINITY_LARGE_THINKING_REF - ) { - return true; - } - if ( - modelId !== ARCEE_TRINITY_LARGE_THINKING_ID && - resolvedId !== ARCEE_TRINITY_LARGE_THINKING_ID - ) { - return false; - } - if (params.provider === ARCEE_PROVIDER_ID || params.model.provider === ARCEE_PROVIDER_ID) { - return true; - } - return normalizeBaseUrl(params.model.baseUrl) === normalizeBaseUrl(ARCEE_BASE_URL); -} +export { ARCEE_BASE_URL, ARCEE_TRINITY_LARGE_THINKING_COMPAT }; export const ARCEE_MODEL_CATALOG: ModelDefinitionConfig[] = [ { diff --git a/extensions/arcee/provider-catalog.ts b/extensions/arcee/provider-catalog.ts index 5631ad2998d..844d9a68dd6 100644 --- a/extensions/arcee/provider-catalog.ts +++ b/extensions/arcee/provider-catalog.ts @@ -1,31 +1,13 @@ -import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-shared"; -import { buildArceeModelDefinition, ARCEE_BASE_URL, ARCEE_MODEL_CATALOG } from "./models.js"; +import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-types"; +import { buildArceeModelDefinition, ARCEE_MODEL_CATALOG } from "./models.js"; +import { + ARCEE_BASE_URL, + normalizeArceeOpenRouterBaseUrl, + OPENROUTER_BASE_URL, + toArceeOpenRouterModelId, +} from "./provider-policy.js"; -export const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"; -const OPENROUTER_LEGACY_BASE_URL = "https://openrouter.ai/v1"; - -function normalizeBaseUrl(baseUrl: string | undefined): string { - return (baseUrl ?? "").trim().replace(/\/+$/, ""); -} - -export function normalizeArceeOpenRouterBaseUrl(baseUrl: string | undefined): string | undefined { - const normalized = normalizeBaseUrl(baseUrl); - if (!normalized) { - return undefined; - } - if (normalized === OPENROUTER_BASE_URL || normalized === OPENROUTER_LEGACY_BASE_URL) { - return OPENROUTER_BASE_URL; - } - return undefined; -} - -export function toArceeOpenRouterModelId(modelId: string): string { - const normalized = modelId.trim(); - if (!normalized || normalized.startsWith("arcee/")) { - return normalized; - } - return `arcee/${normalized}`; -} +export { normalizeArceeOpenRouterBaseUrl, OPENROUTER_BASE_URL, toArceeOpenRouterModelId }; export function buildArceeCatalogModels(): NonNullable { return ARCEE_MODEL_CATALOG.map(buildArceeModelDefinition); diff --git a/extensions/arcee/provider-policy-api.ts b/extensions/arcee/provider-policy-api.ts index 318869d6455..54ce4951661 100644 --- a/extensions/arcee/provider-policy-api.ts +++ b/extensions/arcee/provider-policy-api.ts @@ -1,51 +1,7 @@ -import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-shared"; -import { - ARCEE_TRINITY_LARGE_THINKING_COMPAT, - isArceeTrinityLargeThinkingModelId, -} from "./models.js"; -import { normalizeArceeOpenRouterBaseUrl } from "./provider-catalog.js"; +import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-types"; +import { normalizeArceeProviderConfig } from "./provider-policy.js"; -export function normalizeArceeProviderConfig( - providerConfig: ModelProviderConfig, -): ModelProviderConfig { - let changed = false; - const normalizedBaseUrl = normalizeArceeOpenRouterBaseUrl(providerConfig.baseUrl); - const baseUrl = - normalizedBaseUrl && normalizedBaseUrl !== providerConfig.baseUrl - ? normalizedBaseUrl - : providerConfig.baseUrl; - if (baseUrl !== providerConfig.baseUrl) { - changed = true; - } - - const hasModels = Array.isArray(providerConfig.models); - const models = hasModels - ? providerConfig.models.map((model) => { - if (!isArceeTrinityLargeThinkingModelId(model.id)) { - return model; - } - if ( - model.compat?.supportsReasoningEffort === - ARCEE_TRINITY_LARGE_THINKING_COMPAT.supportsReasoningEffort && - model.compat?.supportsTools === ARCEE_TRINITY_LARGE_THINKING_COMPAT.supportsTools - ) { - return model; - } - changed = true; - return { - ...model, - compat: { - ...model.compat, - ...ARCEE_TRINITY_LARGE_THINKING_COMPAT, - }, - }; - }) - : providerConfig.models; - - return changed - ? { ...providerConfig, baseUrl, ...(hasModels ? { models } : {}) } - : providerConfig; -} +export { normalizeArceeProviderConfig }; export function normalizeConfig(params: { providerConfig: ModelProviderConfig }) { return normalizeArceeProviderConfig(params.providerConfig); diff --git a/extensions/arcee/provider-policy.ts b/extensions/arcee/provider-policy.ts new file mode 100644 index 00000000000..10ca6fe9cd1 --- /dev/null +++ b/extensions/arcee/provider-policy.ts @@ -0,0 +1,118 @@ +import type { + ModelCompatConfig, + ModelProviderConfig, +} from "openclaw/plugin-sdk/provider-model-types"; + +export const ARCEE_BASE_URL = "https://api.arcee.ai/api/v1"; +export const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"; +export const ARCEE_TRINITY_LARGE_THINKING_COMPAT = { + supportsReasoningEffort: false, + supportsTools: false, +} as const satisfies ModelCompatConfig; + +const ARCEE_PROVIDER_ID = "arcee"; +const OPENROUTER_LEGACY_BASE_URL = "https://openrouter.ai/v1"; +const ARCEE_TRINITY_LARGE_THINKING_ID = "trinity-large-thinking"; +const ARCEE_TRINITY_LARGE_THINKING_REF = `${ARCEE_PROVIDER_ID}/${ARCEE_TRINITY_LARGE_THINKING_ID}`; + +function normalizeModelId(modelId: string): string { + return modelId.trim().toLowerCase(); +} + +function normalizeBaseUrl(baseUrl: unknown): string { + return typeof baseUrl === "string" ? baseUrl.trim().replace(/\/+$/, "") : ""; +} + +export function normalizeArceeOpenRouterBaseUrl(baseUrl: string | undefined): string | undefined { + const normalized = normalizeBaseUrl(baseUrl); + if (!normalized) { + return undefined; + } + if (normalized === OPENROUTER_BASE_URL || normalized === OPENROUTER_LEGACY_BASE_URL) { + return OPENROUTER_BASE_URL; + } + return undefined; +} + +export function toArceeOpenRouterModelId(modelId: string): string { + const normalized = modelId.trim(); + if (!normalized || normalized.startsWith("arcee/")) { + return normalized; + } + return `arcee/${normalized}`; +} + +export function isArceeTrinityLargeThinkingModelId(modelId: string): boolean { + const normalized = normalizeModelId(modelId); + return ( + normalized === ARCEE_TRINITY_LARGE_THINKING_ID || + normalized === ARCEE_TRINITY_LARGE_THINKING_REF + ); +} + +export function shouldContributeArceeTrinityLargeThinkingCompat(params: { + provider?: unknown; + modelId: string; + model: { id: string; provider?: unknown; baseUrl?: unknown }; +}): boolean { + const modelId = normalizeModelId(params.modelId); + const resolvedId = normalizeModelId(params.model.id); + if ( + modelId === ARCEE_TRINITY_LARGE_THINKING_REF || + resolvedId === ARCEE_TRINITY_LARGE_THINKING_REF + ) { + return true; + } + if ( + modelId !== ARCEE_TRINITY_LARGE_THINKING_ID && + resolvedId !== ARCEE_TRINITY_LARGE_THINKING_ID + ) { + return false; + } + if (params.provider === ARCEE_PROVIDER_ID || params.model.provider === ARCEE_PROVIDER_ID) { + return true; + } + return normalizeBaseUrl(params.model.baseUrl) === normalizeBaseUrl(ARCEE_BASE_URL); +} + +export function normalizeArceeProviderConfig( + providerConfig: ModelProviderConfig, +): ModelProviderConfig { + let changed = false; + const normalizedBaseUrl = normalizeArceeOpenRouterBaseUrl(providerConfig.baseUrl); + const baseUrl = + normalizedBaseUrl && normalizedBaseUrl !== providerConfig.baseUrl + ? normalizedBaseUrl + : providerConfig.baseUrl; + if (baseUrl !== providerConfig.baseUrl) { + changed = true; + } + + const hasModels = Array.isArray(providerConfig.models); + const models = hasModels + ? providerConfig.models.map((model) => { + if (!isArceeTrinityLargeThinkingModelId(model.id)) { + return model; + } + if ( + model.compat?.supportsReasoningEffort === + ARCEE_TRINITY_LARGE_THINKING_COMPAT.supportsReasoningEffort && + model.compat?.supportsTools === ARCEE_TRINITY_LARGE_THINKING_COMPAT.supportsTools + ) { + return model; + } + changed = true; + return { + ...model, + compat: { + ...model.compat, + ...ARCEE_TRINITY_LARGE_THINKING_COMPAT, + }, + }; + }) + : providerConfig.models; + + return changed + ? { ...providerConfig, baseUrl, ...(hasModels ? { models } : {}) } + : providerConfig; +}