From 00a653c29fc887889dcbe3c5c07e9e8c4a1e2198 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Fri, 27 Jun 2025 14:56:48 +0300 Subject: [PATCH] AI rule node: use `Map.ofEntries()` in model type resolver --- .../data/ai/model/AiModelTypeIdResolver.java | 124 ++++++++---------- 1 file changed, 58 insertions(+), 66 deletions(-) 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 d4339ccd7b..ff31515096 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 @@ -27,75 +27,67 @@ import org.thingsboard.server.common.data.ai.model.chat.GoogleVertexAiGeminiChat import org.thingsboard.server.common.data.ai.model.chat.MistralAiChatModel; import org.thingsboard.server.common.data.ai.model.chat.OpenAiChatModel; -import java.util.Collections; -import java.util.HashMap; import java.util.Map; public final class AiModelTypeIdResolver extends TypeIdResolverBase { - private static final Map> typeIdToModelClass; - - static { - Map> map = new HashMap<>(); - - // OpenAI models - map.put("OPENAI::o4-mini", OpenAiChatModel.class); - // map.put("OPENAI::o3-pro", OpenAiChatModel.class); // needs verification with Gov ID :) - // map.put("OPENAI::o3", OpenAiChatModel.class); // needs verification with Gov ID :) - map.put("OPENAI::o3-mini", OpenAiChatModel.class); - // map.put("OPENAI::o1-pro", OpenAiChatModel.class); // LC4j sends requests to v1/chat/completions, but o1-pro is only supported in v1/responses - map.put("OPENAI::o1", OpenAiChatModel.class); - map.put("OPENAI::gpt-4.1", OpenAiChatModel.class); - map.put("OPENAI::gpt-4.1-mini", OpenAiChatModel.class); - map.put("OPENAI::gpt-4.1-nano", OpenAiChatModel.class); - map.put("OPENAI::gpt-4o", OpenAiChatModel.class); - map.put("OPENAI::gpt-4o-mini", OpenAiChatModel.class); - - // Google AI Gemini models - map.put("GOOGLE_AI_GEMINI::gemini-2.5-pro", GoogleAiGeminiChatModel.class); - map.put("GOOGLE_AI_GEMINI::gemini-2.5-flash", GoogleAiGeminiChatModel.class); - map.put("GOOGLE_AI_GEMINI::gemini-2.0-flash", GoogleAiGeminiChatModel.class); - map.put("GOOGLE_AI_GEMINI::gemini-2.0-flash-lite", GoogleAiGeminiChatModel.class); - map.put("GOOGLE_AI_GEMINI::gemini-1.5-pro", GoogleAiGeminiChatModel.class); - map.put("GOOGLE_AI_GEMINI::gemini-1.5-flash", GoogleAiGeminiChatModel.class); - map.put("GOOGLE_AI_GEMINI::gemini-1.5-flash-8b", GoogleAiGeminiChatModel.class); - - // Google Vertex AI Gemini models - map.put("GOOGLE_VERTEX_AI_GEMINI::gemini-2.5-pro", GoogleVertexAiGeminiChatModel.class); - map.put("GOOGLE_VERTEX_AI_GEMINI::gemini-2.5-flash", GoogleVertexAiGeminiChatModel.class); - map.put("GOOGLE_VERTEX_AI_GEMINI::gemini-2.0-flash", GoogleVertexAiGeminiChatModel.class); - map.put("GOOGLE_VERTEX_AI_GEMINI::gemini-2.0-flash-lite", GoogleVertexAiGeminiChatModel.class); - map.put("GOOGLE_VERTEX_AI_GEMINI::gemini-1.5-pro", GoogleVertexAiGeminiChatModel.class); - map.put("GOOGLE_VERTEX_AI_GEMINI::gemini-1.5-flash", GoogleVertexAiGeminiChatModel.class); - map.put("GOOGLE_VERTEX_AI_GEMINI::gemini-1.5-flash-8b", GoogleVertexAiGeminiChatModel.class); - - // Mistral AI models - map.put("MISTRAL_AI::magistral-medium-latest", MistralAiChatModel.class); - map.put("MISTRAL_AI::magistral-small-latest", MistralAiChatModel.class); - map.put("MISTRAL_AI::mistral-large-latest", MistralAiChatModel.class); - map.put("MISTRAL_AI::mistral-medium-latest", MistralAiChatModel.class); - map.put("MISTRAL_AI::mistral-small-latest", MistralAiChatModel.class); - map.put("MISTRAL_AI::pixtral-large-latest", MistralAiChatModel.class); - map.put("MISTRAL_AI::ministral-8b-latest", MistralAiChatModel.class); - map.put("MISTRAL_AI::ministral-3b-latest", MistralAiChatModel.class); - map.put("MISTRAL_AI::open-mistral-nemo", MistralAiChatModel.class); - - // Anthropic models - map.put("ANTHROPIC::claude-opus-4-0", AnthropicChatModel.class); - map.put("ANTHROPIC::claude-sonnet-4-0", AnthropicChatModel.class); - map.put("ANTHROPIC::claude-3-7-sonnet-latest", AnthropicChatModel.class); - map.put("ANTHROPIC::claude-3-5-sonnet-latest", AnthropicChatModel.class); - map.put("ANTHROPIC::claude-3-5-haiku-latest", AnthropicChatModel.class); - map.put("ANTHROPIC::claude-3-opus-latest", AnthropicChatModel.class); - - // Amazon Bedrock models - map.put("AMAZON_BEDROCK::amazon.nova-lite-v1:0", AmazonBedrockChatModel.class); - - // GitHub Models models - map.put("GITHUB_MODELS::gpt-4o", GitHubModelsChatModel.class); - - typeIdToModelClass = Collections.unmodifiableMap(map); - } + private static final Map> typeIdToModelClass = Map.ofEntries( + // OpenAI models + Map.entry("OPENAI::o4-mini", OpenAiChatModel.class), + // Map.entry("OPENAI::o3-pro", OpenAiChatModel.class); // needs verification with Gov ID :) + // Map.entry("OPENAI::o3", OpenAiChatModel.class); // needs verification with Gov ID :) + Map.entry("OPENAI::o3-mini", OpenAiChatModel.class), + // Map.entry("OPENAI::o1-pro", OpenAiChatModel.class); // LC4j sends requests to v1/chat/completions, but o1-pro is only supported in v1/responses + Map.entry("OPENAI::o1", OpenAiChatModel.class), + Map.entry("OPENAI::gpt-4.1", OpenAiChatModel.class), + Map.entry("OPENAI::gpt-4.1-mini", OpenAiChatModel.class), + Map.entry("OPENAI::gpt-4.1-nano", OpenAiChatModel.class), + Map.entry("OPENAI::gpt-4o", OpenAiChatModel.class), + Map.entry("OPENAI::gpt-4o-mini", OpenAiChatModel.class), + + // Google AI Gemini models + Map.entry("GOOGLE_AI_GEMINI::gemini-2.5-pro", GoogleAiGeminiChatModel.class), + Map.entry("GOOGLE_AI_GEMINI::gemini-2.5-flash", GoogleAiGeminiChatModel.class), + Map.entry("GOOGLE_AI_GEMINI::gemini-2.0-flash", GoogleAiGeminiChatModel.class), + Map.entry("GOOGLE_AI_GEMINI::gemini-2.0-flash-lite", GoogleAiGeminiChatModel.class), + Map.entry("GOOGLE_AI_GEMINI::gemini-1.5-pro", GoogleAiGeminiChatModel.class), + Map.entry("GOOGLE_AI_GEMINI::gemini-1.5-flash", GoogleAiGeminiChatModel.class), + Map.entry("GOOGLE_AI_GEMINI::gemini-1.5-flash-8b", GoogleAiGeminiChatModel.class), + + // Google Vertex AI Gemini models + Map.entry("GOOGLE_VERTEX_AI_GEMINI::gemini-2.5-pro", GoogleVertexAiGeminiChatModel.class), + Map.entry("GOOGLE_VERTEX_AI_GEMINI::gemini-2.5-flash", GoogleVertexAiGeminiChatModel.class), + Map.entry("GOOGLE_VERTEX_AI_GEMINI::gemini-2.0-flash", GoogleVertexAiGeminiChatModel.class), + Map.entry("GOOGLE_VERTEX_AI_GEMINI::gemini-2.0-flash-lite", GoogleVertexAiGeminiChatModel.class), + Map.entry("GOOGLE_VERTEX_AI_GEMINI::gemini-1.5-pro", GoogleVertexAiGeminiChatModel.class), + Map.entry("GOOGLE_VERTEX_AI_GEMINI::gemini-1.5-flash", GoogleVertexAiGeminiChatModel.class), + Map.entry("GOOGLE_VERTEX_AI_GEMINI::gemini-1.5-flash-8b", GoogleVertexAiGeminiChatModel.class), + + // Mistral AI models + Map.entry("MISTRAL_AI::magistral-medium-latest", MistralAiChatModel.class), + Map.entry("MISTRAL_AI::magistral-small-latest", MistralAiChatModel.class), + Map.entry("MISTRAL_AI::mistral-large-latest", MistralAiChatModel.class), + Map.entry("MISTRAL_AI::mistral-medium-latest", MistralAiChatModel.class), + Map.entry("MISTRAL_AI::mistral-small-latest", MistralAiChatModel.class), + Map.entry("MISTRAL_AI::pixtral-large-latest", MistralAiChatModel.class), + Map.entry("MISTRAL_AI::ministral-8b-latest", MistralAiChatModel.class), + Map.entry("MISTRAL_AI::ministral-3b-latest", MistralAiChatModel.class), + Map.entry("MISTRAL_AI::open-mistral-nemo", MistralAiChatModel.class), + + // Anthropic models + Map.entry("ANTHROPIC::claude-opus-4-0", AnthropicChatModel.class), + Map.entry("ANTHROPIC::claude-sonnet-4-0", AnthropicChatModel.class), + Map.entry("ANTHROPIC::claude-3-7-sonnet-latest", AnthropicChatModel.class), + Map.entry("ANTHROPIC::claude-3-5-sonnet-latest", AnthropicChatModel.class), + Map.entry("ANTHROPIC::claude-3-5-haiku-latest", AnthropicChatModel.class), + Map.entry("ANTHROPIC::claude-3-opus-latest", AnthropicChatModel.class), + + // Amazon Bedrock models + Map.entry("AMAZON_BEDROCK::amazon.nova-lite-v1:0", AmazonBedrockChatModel.class), + + // GitHub Models models + Map.entry("GITHUB_MODELS::gpt-4o", GitHubModelsChatModel.class) + ); private JavaType baseType; @@ -117,7 +109,7 @@ public final class AiModelTypeIdResolver extends TypeIdResolverBase { @Override public JavaType typeFromId(DatabindContext context, String id) { Class modelClass = typeIdToModelClass.get(id); - if (modelClass == null) { + 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); } return context.constructSpecializedType(baseType, modelClass);