From 581f1449df2cbfbd0208236df61cc2da04685b60 Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Fri, 7 Feb 2025 21:15:08 +0800 Subject: [PATCH 01/11] add anthropic --- packages/core/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/package.json b/packages/core/package.json index 581048b7875..09e1148b20e 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -65,6 +65,7 @@ "dependencies": { "@tavily/core": "^0.0.2", "@ai-sdk/openai": "1.1.9", + "@ai-sdk/anthropic": "1.1.6", "ai": "4.1.24", "@types/uuid": "10.0.0", "dotenv": "16.4.5", From c6e4a9324c0fa91e467c0353de931853b80c51b2 Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Fri, 7 Feb 2025 22:21:17 +0800 Subject: [PATCH 02/11] handle anthropic provider --- packages/core/src/generation.ts | 86 +++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/packages/core/src/generation.ts b/packages/core/src/generation.ts index 18186ec27ac..94e096f0cac 100644 --- a/packages/core/src/generation.ts +++ b/packages/core/src/generation.ts @@ -1,5 +1,6 @@ // ================ IMPORTS ================ import { createOpenAI } from "@ai-sdk/openai"; +import { createAnthropic } from "@ai-sdk/anthropic"; import { experimental_generateImage as aiGenerateImage, generateObject as aiGenerateObject, @@ -85,7 +86,22 @@ async function withRetry( } } - export function initializeModelClient(runtime: IAgentRuntime, modelClass:ModelClass = ModelClass.DEFAULT) { +function createModelClient(provider: string, apiKey: string, baseURL: string, runtime: IAgentRuntime) { + const modelClients: Record = { + "anthropic": createAnthropic, + "claude": createAnthropic, + }; + + const createClient = modelClients[provider] || createOpenAI; + + return createClient({ + apiKey, + baseURL, + fetch: runtime.fetch, + }); +} + +export function initializeModelClient(runtime: IAgentRuntime, modelClass:ModelClass = ModelClass.DEFAULT) { elizaLogger.info(`Initializing model client with runtime: ${runtime.modelProvider}`); const provider = runtime.getModelProvider()?.provider || runtime.modelProvider; @@ -128,12 +144,9 @@ async function withRetry( throw new Error(`Model name not specified for class ${modelClass}`); } - const client = createOpenAI({ - apiKey, - baseURL, - fetch: runtime.fetch, - }); - + const client = createModelClient(provider, apiKey, baseURL, runtime); + // console.log(client) + elizaLogger.info(`Initialized model client for ${provider} with baseURL ${baseURL} and model ${model}`); return { @@ -325,6 +338,43 @@ export async function generateTrueOrFalse({ return result === 'true'; } +function getModelConfig( + runtime: IAgentRuntime, + client: any, + model: string, + mode: 'auto' | 'json' | 'tool', + options: { + context: string; + output?: 'object' | 'array' | 'enum' | 'no-schema'; + schema?: ZodSchema; + schemaName?: string; + schemaDescription?: string; + enumValues?: string[]; + stopSequences?: string[]; + } +): any { + const isAnthropic = + runtime.getModelProvider()?.provider === "anthropic" || + runtime.getModelProvider()?.provider === "claude"; + + if (isAnthropic && mode === "json") { + elizaLogger.warn("Anthropic does not support JSON mode. Switching to 'auto'."); + mode = "auto"; + } + + const config = { + model: client.languageModel(model), + prompt: options.context.toString(), + system: runtime.character.system ?? settings.SYSTEM_PROMPT ?? undefined, + output: options.output as never, + mode: mode as never, + ...(options.schema ? { schema: options.schema, schemaName: options.schemaName, schemaDescription: options.schemaDescription } : {}), + ...(options.enumValues ? { enum: options.enumValues } : {}), + }; + + return options.stopSequences ? { ...config, stopSequences: options.stopSequences } : config; +} + // ================ OBJECT GENERATION FUNCTIONS ================ export const generateObject = async ({ runtime, @@ -352,19 +402,15 @@ export const generateObject = async ({ throw new Error('Enum values are required when output type is enum'); } - // Create the base configuration object - const config = { - model: client.languageModel(model), - prompt: context.toString(), - system: runtime.character.system ?? settings.SYSTEM_PROMPT ?? undefined, - output: output as never, - mode: mode as never, - ...(schema ? { schema, schemaName, schemaDescription } : {}), - ...(enumValues ? { enum: enumValues } : {}) - }; - - // Only add stopSequences if it's defined - const finalConfig = stopSequences ? { ...config, stopSequences } : config; + const finalConfig = getModelConfig(runtime, client, model, mode, { + context, + output, + schema, + schemaName, + schemaDescription, + enumValues, + stopSequences, + }); const {object} = await aiGenerateObject(finalConfig); From cdfc9c0140f4dcd0b6957d306ac34fc8c75662ff Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Fri, 7 Feb 2025 22:21:51 +0800 Subject: [PATCH 03/11] make model provider optional --- packages/core/src/environment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/environment.ts b/packages/core/src/environment.ts index 544aef51344..5f1117d70b4 100644 --- a/packages/core/src/environment.ts +++ b/packages/core/src/environment.ts @@ -75,7 +75,7 @@ export const CharacterSchema = z.object({ id: z.string().uuid().optional(), name: z.string(), system: z.string().optional(), - modelProvider: z.nativeEnum(ModelProviderName), + modelProvider: z.nativeEnum(ModelProviderName).optional(), modelEndpointOverride: z.string().optional(), templates: z.record(z.string()).optional(), bio: z.union([z.string(), z.array(z.string())]), From e8642b2e61a88d6aa15c544607760854fc25016f Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Fri, 7 Feb 2025 22:23:12 +0800 Subject: [PATCH 04/11] clean code --- packages/core/src/generation.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core/src/generation.ts b/packages/core/src/generation.ts index 94e096f0cac..bbd4a974d67 100644 --- a/packages/core/src/generation.ts +++ b/packages/core/src/generation.ts @@ -145,8 +145,7 @@ export function initializeModelClient(runtime: IAgentRuntime, modelClass:ModelCl } const client = createModelClient(provider, apiKey, baseURL, runtime); - // console.log(client) - + elizaLogger.info(`Initialized model client for ${provider} with baseURL ${baseURL} and model ${model}`); return { From 38532dcb2232b317b4b6762ff043afa358370926 Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Fri, 7 Feb 2025 22:29:13 +0800 Subject: [PATCH 05/11] rename --- packages/core/src/generation.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/generation.ts b/packages/core/src/generation.ts index bbd4a974d67..ec92b21d71f 100644 --- a/packages/core/src/generation.ts +++ b/packages/core/src/generation.ts @@ -401,7 +401,7 @@ export const generateObject = async ({ throw new Error('Enum values are required when output type is enum'); } - const finalConfig = getModelConfig(runtime, client, model, mode, { + const config = getModelConfig(runtime, client, model, mode, { context, output, schema, @@ -411,7 +411,7 @@ export const generateObject = async ({ stopSequences, }); - const {object} = await aiGenerateObject(finalConfig); + const {object} = await aiGenerateObject(config); elizaLogger.debug(`Received Object response from ${model} model.`); return schema ? schema.parse(object) : object; From 21a9ad7be27126c6b28247fd2ccb394c23673462 Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Fri, 7 Feb 2025 22:40:58 +0800 Subject: [PATCH 06/11] use include to check if anthropic function --- packages/core/src/generation.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/core/src/generation.ts b/packages/core/src/generation.ts index ec92b21d71f..0469822268a 100644 --- a/packages/core/src/generation.ts +++ b/packages/core/src/generation.ts @@ -86,13 +86,18 @@ async function withRetry( } } -function createModelClient(provider: string, apiKey: string, baseURL: string, runtime: IAgentRuntime) { - const modelClients: Record = { - "anthropic": createAnthropic, - "claude": createAnthropic, - }; +function isAnthropicProvider(runtime: IAgentRuntime): boolean { + const provider = runtime.getModelProvider()?.provider; + return ( + provider.toLowerCase().includes("anthropic") || + provider.toLowerCase().includes("claude") + ); +} - const createClient = modelClients[provider] || createOpenAI; +function createModelClient(apiKey: string, baseURL: string, runtime: IAgentRuntime) { + const createClient = isAnthropicProvider(runtime) + ? createAnthropic + : createOpenAI; return createClient({ apiKey, @@ -144,7 +149,7 @@ export function initializeModelClient(runtime: IAgentRuntime, modelClass:ModelCl throw new Error(`Model name not specified for class ${modelClass}`); } - const client = createModelClient(provider, apiKey, baseURL, runtime); + const client = createModelClient(apiKey, baseURL, runtime); elizaLogger.info(`Initialized model client for ${provider} with baseURL ${baseURL} and model ${model}`); @@ -356,7 +361,7 @@ function getModelConfig( runtime.getModelProvider()?.provider === "anthropic" || runtime.getModelProvider()?.provider === "claude"; - if (isAnthropic && mode === "json") { + if (isAnthropicProvider(runtime) && mode === "json") { elizaLogger.warn("Anthropic does not support JSON mode. Switching to 'auto'."); mode = "auto"; } From 94e2f69717c3af607d6d158a49e92d863d981a4a Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Fri, 7 Feb 2025 22:41:42 +0800 Subject: [PATCH 07/11] update provider type --- packages/core/src/environment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/environment.ts b/packages/core/src/environment.ts index 5f1117d70b4..7b2d3d6c9ec 100644 --- a/packages/core/src/environment.ts +++ b/packages/core/src/environment.ts @@ -75,7 +75,7 @@ export const CharacterSchema = z.object({ id: z.string().uuid().optional(), name: z.string(), system: z.string().optional(), - modelProvider: z.nativeEnum(ModelProviderName).optional(), + modelProvider: z.string().optional(), modelEndpointOverride: z.string().optional(), templates: z.record(z.string()).optional(), bio: z.union([z.string(), z.array(z.string())]), From b4aa9c42b317b85196345060b6aa1151e06a3094 Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Fri, 7 Feb 2025 23:28:08 +0800 Subject: [PATCH 08/11] handle image model --- packages/core/src/generation.ts | 39 +++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/packages/core/src/generation.ts b/packages/core/src/generation.ts index 0469822268a..126d38389b5 100644 --- a/packages/core/src/generation.ts +++ b/packages/core/src/generation.ts @@ -86,16 +86,15 @@ async function withRetry( } } -function isAnthropicProvider(runtime: IAgentRuntime): boolean { - const provider = runtime.getModelProvider()?.provider; +function isAnthropicProvider(provider: string): boolean { return ( provider.toLowerCase().includes("anthropic") || provider.toLowerCase().includes("claude") ); } -function createModelClient(apiKey: string, baseURL: string, runtime: IAgentRuntime) { - const createClient = isAnthropicProvider(runtime) +function createModelClient(provider: string, apiKey: string, baseURL: string, runtime: IAgentRuntime) { + const createClient = isAnthropicProvider(provider) ? createAnthropic : createOpenAI; @@ -106,10 +105,13 @@ function createModelClient(apiKey: string, baseURL: string, runtime: IAgentRunti }); } -export function initializeModelClient(runtime: IAgentRuntime, modelClass:ModelClass = ModelClass.DEFAULT) { +export function initializeModelClient( + provider: string, + runtime: IAgentRuntime, + modelClass: ModelClass = ModelClass.DEFAULT +) { elizaLogger.info(`Initializing model client with runtime: ${runtime.modelProvider}`); - const provider = runtime.getModelProvider()?.provider || runtime.modelProvider; const baseURL = runtime.getModelProvider()?.endpoint; const apiKey = runtime.token || process.env.PROVIDER_API_KEY || @@ -149,7 +151,7 @@ export function initializeModelClient(runtime: IAgentRuntime, modelClass:ModelCl throw new Error(`Model name not specified for class ${modelClass}`); } - const client = createModelClient(apiKey, baseURL, runtime); + const client = createModelClient(provider, apiKey, baseURL, runtime); elizaLogger.info(`Initialized model client for ${provider} with baseURL ${baseURL} and model ${model}`); @@ -199,8 +201,8 @@ export async function generateText({ }); - - const { client, model, systemPrompt } = initializeModelClient(runtime, modelClass); + const provider = runtime.getModelProvider()?.provider || runtime.modelProvider; + const { client, model, systemPrompt } = initializeModelClient(provider, runtime, modelClass); elizaLogger.info(`Generating text with model ${model} and system prompt ${systemPrompt} and context ${context} and tools ${tools} and onStepFinish ${onStepFinish} and maxSteps ${maxSteps}`); @@ -357,11 +359,9 @@ function getModelConfig( stopSequences?: string[]; } ): any { - const isAnthropic = - runtime.getModelProvider()?.provider === "anthropic" || - runtime.getModelProvider()?.provider === "claude"; + const provider = runtime.getModelProvider()?.provider; - if (isAnthropicProvider(runtime) && mode === "json") { + if (isAnthropicProvider(provider) && mode === "json") { elizaLogger.warn("Anthropic does not support JSON mode. Switching to 'auto'."); mode = "auto"; } @@ -400,7 +400,8 @@ export const generateObject = async ({ } elizaLogger.debug(`Generating object with ${runtime.modelProvider} model. for ${schemaName}`); - const { client, model } = initializeModelClient(runtime, modelClass); + const provider = runtime.getModelProvider()?.provider || runtime.modelProvider; + const { client, model } = initializeModelClient(provider, runtime, modelClass); if (output === 'enum' && !enumValues) { throw new Error('Enum values are required when output type is enum'); @@ -500,7 +501,8 @@ export async function generateMessageResponse({ elizaLogger.debug("Context:", context); return await withRetry(async () => { - const { client, model, systemPrompt } = initializeModelClient(runtime, modelClass); + const provider = runtime.getModelProvider()?.provider || runtime.modelProvider; + const { client, model, systemPrompt } = initializeModelClient(provider, runtime, modelClass); elizaLogger.info(`Generating message response with model: ${model} & model class: ${modelClass}`); @@ -556,14 +558,17 @@ export const generateImage = async ( elizaLogger.warn("No model settings found for the image model provider."); return { success: false, error: "No model settings available" }; } - const { model, client } = initializeModelClient(runtime, ModelClass.IMAGE); + + + const provider = runtime.imageVisionModelProvider; + const { model, client } = initializeModelClient(provider, runtime, ModelClass.IMAGE); elizaLogger.info("Generating image with options:", { imageModelProvider: model, }); await withRetry(async () => { const result = await aiGenerateImage({ - model: client.imageModel(model), + model: (client as any).imageModel(model), prompt: data.prompt, size: `${data.width}x${data.height}`, n: data.count, From 86b4d0854a99504d4351ae444269124972152da0 Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Fri, 7 Feb 2025 23:52:54 +0800 Subject: [PATCH 09/11] Prevent image generation with unsupported providers for now --- packages/core/src/generation.ts | 43 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/packages/core/src/generation.ts b/packages/core/src/generation.ts index 126d38389b5..7c459317e04 100644 --- a/packages/core/src/generation.ts +++ b/packages/core/src/generation.ts @@ -86,15 +86,16 @@ async function withRetry( } } -function isAnthropicProvider(provider: string): boolean { +function isAnthropicProvider(runtime: IAgentRuntime): boolean { + const provider = runtime.getModelProvider()?.provider; return ( provider.toLowerCase().includes("anthropic") || provider.toLowerCase().includes("claude") ); } -function createModelClient(provider: string, apiKey: string, baseURL: string, runtime: IAgentRuntime) { - const createClient = isAnthropicProvider(provider) +function createModelClient(apiKey: string, baseURL: string, runtime: IAgentRuntime) { + const createClient = isAnthropicProvider(runtime) ? createAnthropic : createOpenAI; @@ -105,13 +106,10 @@ function createModelClient(provider: string, apiKey: string, baseURL: string, ru }); } -export function initializeModelClient( - provider: string, - runtime: IAgentRuntime, - modelClass: ModelClass = ModelClass.DEFAULT -) { +export function initializeModelClient(runtime: IAgentRuntime, modelClass: ModelClass = ModelClass.DEFAULT) { elizaLogger.info(`Initializing model client with runtime: ${runtime.modelProvider}`); + const provider = runtime.getModelProvider()?.provider || runtime.modelProvider; const baseURL = runtime.getModelProvider()?.endpoint; const apiKey = runtime.token || process.env.PROVIDER_API_KEY || @@ -151,7 +149,7 @@ export function initializeModelClient( throw new Error(`Model name not specified for class ${modelClass}`); } - const client = createModelClient(provider, apiKey, baseURL, runtime); + const client = createModelClient(apiKey, baseURL, runtime); elizaLogger.info(`Initialized model client for ${provider} with baseURL ${baseURL} and model ${model}`); @@ -201,8 +199,8 @@ export async function generateText({ }); - const provider = runtime.getModelProvider()?.provider || runtime.modelProvider; - const { client, model, systemPrompt } = initializeModelClient(provider, runtime, modelClass); + + const { client, model, systemPrompt } = initializeModelClient(runtime, modelClass); elizaLogger.info(`Generating text with model ${model} and system prompt ${systemPrompt} and context ${context} and tools ${tools} and onStepFinish ${onStepFinish} and maxSteps ${maxSteps}`); @@ -359,9 +357,11 @@ function getModelConfig( stopSequences?: string[]; } ): any { - const provider = runtime.getModelProvider()?.provider; + const isAnthropic = + runtime.getModelProvider()?.provider === "anthropic" || + runtime.getModelProvider()?.provider === "claude"; - if (isAnthropicProvider(provider) && mode === "json") { + if (isAnthropicProvider(runtime) && mode === "json") { elizaLogger.warn("Anthropic does not support JSON mode. Switching to 'auto'."); mode = "auto"; } @@ -400,8 +400,7 @@ export const generateObject = async ({ } elizaLogger.debug(`Generating object with ${runtime.modelProvider} model. for ${schemaName}`); - const provider = runtime.getModelProvider()?.provider || runtime.modelProvider; - const { client, model } = initializeModelClient(provider, runtime, modelClass); + const { client, model } = initializeModelClient(runtime, modelClass); if (output === 'enum' && !enumValues) { throw new Error('Enum values are required when output type is enum'); @@ -501,8 +500,7 @@ export async function generateMessageResponse({ elizaLogger.debug("Context:", context); return await withRetry(async () => { - const provider = runtime.getModelProvider()?.provider || runtime.modelProvider; - const { client, model, systemPrompt } = initializeModelClient(provider, runtime, modelClass); + const { client, model, systemPrompt } = initializeModelClient(runtime, modelClass); elizaLogger.info(`Generating message response with model: ${model} & model class: ${modelClass}`); @@ -558,10 +556,15 @@ export const generateImage = async ( elizaLogger.warn("No model settings found for the image model provider."); return { success: false, error: "No model settings available" }; } - - const provider = runtime.imageVisionModelProvider; - const { model, client } = initializeModelClient(provider, runtime, ModelClass.IMAGE); + if (isAnthropicProvider(runtime)) { + return { + success: false, + error: "Unsupported provider: Anthropic does not support image generation.", + }; + } + + const { model, client } = initializeModelClient(runtime, ModelClass.IMAGE); elizaLogger.info("Generating image with options:", { imageModelProvider: model, }); From 885ae225f550257439720033848e1b7b222407a6 Mon Sep 17 00:00:00 2001 From: Ting Chien Meng Date: Fri, 7 Feb 2025 23:59:58 +0800 Subject: [PATCH 10/11] clean code --- packages/core/src/generation.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/core/src/generation.ts b/packages/core/src/generation.ts index 7c459317e04..3243fe9ca39 100644 --- a/packages/core/src/generation.ts +++ b/packages/core/src/generation.ts @@ -357,10 +357,6 @@ function getModelConfig( stopSequences?: string[]; } ): any { - const isAnthropic = - runtime.getModelProvider()?.provider === "anthropic" || - runtime.getModelProvider()?.provider === "claude"; - if (isAnthropicProvider(runtime) && mode === "json") { elizaLogger.warn("Anthropic does not support JSON mode. Switching to 'auto'."); mode = "auto"; From 6e0d4c04b74295c16570d8f1f7f22108ff3f13fe Mon Sep 17 00:00:00 2001 From: Sayo Date: Fri, 7 Feb 2025 21:44:10 +0530 Subject: [PATCH 11/11] Update generation.ts --- packages/core/src/generation.ts | 73 +++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/packages/core/src/generation.ts b/packages/core/src/generation.ts index 3243fe9ca39..a383c24a86e 100644 --- a/packages/core/src/generation.ts +++ b/packages/core/src/generation.ts @@ -106,8 +106,39 @@ function createModelClient(apiKey: string, baseURL: string, runtime: IAgentRunti }); } -export function initializeModelClient(runtime: IAgentRuntime, modelClass: ModelClass = ModelClass.DEFAULT) { +// Add this utility function near other utility functions +function validateModelConfig( + provider: string, + config: { + apiKey?: string; + baseURL?: string; + modelProvider?: any; + modelClass?: ModelClass; + model?: string; + } +) { + const validations = [ + { value: config.apiKey, name: 'API key', for: provider }, + { value: config.baseURL, name: 'endpoint URL', for: provider }, + { value: config.modelProvider, name: 'model provider' }, + { value: config.modelProvider?.models, name: 'model configurations', in: 'provider' }, + { value: config.model, name: 'model name', for: `class ${config.modelClass}` } + ]; + + for (const check of validations) { + if (!check.value) { + const message = check.for + ? `No ${check.name} found for ${check.for}` + : check.in + ? `${check.name} not found in ${check.in}` + : `${check.name} not initialized`; + elizaLogger.error(message); + throw new Error(message); + } + } +} +export function initializeModelClient(runtime: IAgentRuntime, modelClass: ModelClass = ModelClass.DEFAULT) { elizaLogger.info(`Initializing model client with runtime: ${runtime.modelProvider}`); const provider = runtime.getModelProvider()?.provider || runtime.modelProvider; const baseURL = runtime.getModelProvider()?.endpoint; @@ -116,38 +147,18 @@ export function initializeModelClient(runtime: IAgentRuntime, modelClass: ModelC runtime.character.settings.secrets.PROVIDER_API_KEY || runtime.getSetting('PROVIDER_API_KEY'); - if (!apiKey) { - elizaLogger.error(`No API key found for ${provider}`); - throw new Error(`No API key found for ${provider}`); - } - - if (!baseURL) { - elizaLogger.error(`No endpoint URL found for ${provider}`); - throw new Error(`No endpoint URL found for ${provider}`); - } - const modelProvider = runtime.getModelProvider(); - if (!modelProvider) { - elizaLogger.error('Model provider not initialized'); - throw new Error('Model provider not initialized'); - } - - if (!modelProvider.models) { - elizaLogger.error('Model configurations not found in provider'); - throw new Error('Model configurations not found in provider'); - } - - const modelConfig = modelProvider.models[modelClass]; - if (!modelConfig) { - elizaLogger.error(`No model configuration found for class ${modelClass}`); - throw new Error(`No model configuration found for class ${modelClass}`); - } + const modelConfig = modelProvider?.models?.[modelClass]; + const model = modelConfig?.name; - const model = modelConfig.name; - if (!model) { - elizaLogger.error(`Model name not specified for class ${modelClass}`); - throw new Error(`Model name not specified for class ${modelClass}`); - } + // Single validation call replaces multiple if-checks + validateModelConfig(provider, { + apiKey, + baseURL, + modelProvider, + modelClass, + model + }); const client = createModelClient(apiKey, baseURL, runtime);