diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/AiModelTypeIdResolver.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/AiModelTypeIdResolver.java index ff31515096..96a5a70390 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/AiModelTypeIdResolver.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ai/model/AiModelTypeIdResolver.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.ai.model.chat.GoogleAiGeminiChatModel; import org.thingsboard.server.common.data.ai.model.chat.GoogleVertexAiGeminiChatModel; import org.thingsboard.server.common.data.ai.model.chat.MistralAiChatModel; import org.thingsboard.server.common.data.ai.model.chat.OpenAiChatModel; +import org.thingsboard.server.common.data.ai.provider.AiProvider; import java.util.Map; @@ -89,6 +90,8 @@ public final class AiModelTypeIdResolver extends TypeIdResolverBase { Map.entry("GITHUB_MODELS::gpt-4o", GitHubModelsChatModel.class) ); + private static final String PROVIDER_MODEL_SEPARATOR = "::"; + private JavaType baseType; @Override @@ -109,9 +112,28 @@ public final class AiModelTypeIdResolver extends TypeIdResolverBase { @Override public JavaType typeFromId(DatabindContext context, String id) { Class modelClass = typeIdToModelClass.get(id); - if (modelClass == null) { // TODO: if provider is unknown - throw, if provider is valid but model is unknown - fallback to default model - throw new IllegalArgumentException("Unknown model type ID: " + id); + if (modelClass != null) { // known model + return context.constructSpecializedType(baseType, modelClass); } + + String[] parts = id.split(PROVIDER_MODEL_SEPARATOR, 2); + if (parts.length != 2) { + throw new IllegalArgumentException("Invalid model type ID format: " + id + ". Expected format: PROVIDER::MODEL_ID"); + } + + String providerName = parts[0]; + + // Check if the provider exists + AiProvider provider; + try { + provider = AiProvider.valueOf(providerName); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Unknown AI provider: " + providerName); + } + + // Provider is valid but model is unknown - fallback to default model class + modelClass = provider.getDefaultModelClass(); + return context.constructSpecializedType(baseType, modelClass); } @@ -123,7 +145,7 @@ public final class AiModelTypeIdResolver extends TypeIdResolverBase { private static String generateId(AiModel model) { String provider = model.providerConfig().provider().name(); String modelId = model.modelConfig().modelId(); - return provider + "::" + modelId; + return provider + PROVIDER_MODEL_SEPARATOR + modelId; } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/AiProvider.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/AiProvider.java index d0a5bd0510..f4ae843447 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/AiProvider.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ai/provider/AiProvider.java @@ -15,15 +15,34 @@ */ package org.thingsboard.server.common.data.ai.provider; +import org.thingsboard.server.common.data.ai.model.chat.AmazonBedrockChatModel; +import org.thingsboard.server.common.data.ai.model.chat.AnthropicChatModel; +import org.thingsboard.server.common.data.ai.model.chat.AzureOpenAiChatModel; +import org.thingsboard.server.common.data.ai.model.chat.GitHubModelsChatModel; +import org.thingsboard.server.common.data.ai.model.chat.GoogleAiGeminiChatModel; +import org.thingsboard.server.common.data.ai.model.chat.GoogleVertexAiGeminiChatModel; +import org.thingsboard.server.common.data.ai.model.chat.MistralAiChatModel; +import org.thingsboard.server.common.data.ai.model.chat.OpenAiChatModel; + public enum AiProvider { - OPENAI, - AZURE_OPENAI, - GOOGLE_AI_GEMINI, - GOOGLE_VERTEX_AI_GEMINI, - MISTRAL_AI, - ANTHROPIC, - AMAZON_BEDROCK, - GITHUB_MODELS + OPENAI(OpenAiChatModel.class), + AZURE_OPENAI(AzureOpenAiChatModel.class), + GOOGLE_AI_GEMINI(GoogleAiGeminiChatModel.class), + GOOGLE_VERTEX_AI_GEMINI(GoogleVertexAiGeminiChatModel.class), + MISTRAL_AI(MistralAiChatModel.class), + ANTHROPIC(AnthropicChatModel.class), + AMAZON_BEDROCK(AmazonBedrockChatModel.class), + GITHUB_MODELS(GitHubModelsChatModel.class); + + private final Class defaultModelClass; + + AiProvider(Class defaultModelClass) { + this.defaultModelClass = defaultModelClass; + } + + public Class getDefaultModelClass() { + return defaultModelClass; + } }