AI rule node: support unknown models

This commit is contained in:
Dmytro Skarzhynets 2025-06-27 15:48:24 +03:00
parent d732e31370
commit 3f2a6440a7
No known key found for this signature in database
GPG Key ID: 2B51652F224037DF
2 changed files with 52 additions and 11 deletions

View File

@ -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.GoogleVertexAiGeminiChatModel;
import org.thingsboard.server.common.data.ai.model.chat.MistralAiChatModel; 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.model.chat.OpenAiChatModel;
import org.thingsboard.server.common.data.ai.provider.AiProvider;
import java.util.Map; import java.util.Map;
@ -89,6 +90,8 @@ public final class AiModelTypeIdResolver extends TypeIdResolverBase {
Map.entry("GITHUB_MODELS::gpt-4o", GitHubModelsChatModel.class) Map.entry("GITHUB_MODELS::gpt-4o", GitHubModelsChatModel.class)
); );
private static final String PROVIDER_MODEL_SEPARATOR = "::";
private JavaType baseType; private JavaType baseType;
@Override @Override
@ -109,9 +112,28 @@ public final class AiModelTypeIdResolver extends TypeIdResolverBase {
@Override @Override
public JavaType typeFromId(DatabindContext context, String id) { public JavaType typeFromId(DatabindContext context, String id) {
Class<?> modelClass = typeIdToModelClass.get(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 if (modelClass != null) { // known model
throw new IllegalArgumentException("Unknown model type ID: " + id); 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); return context.constructSpecializedType(baseType, modelClass);
} }
@ -123,7 +145,7 @@ public final class AiModelTypeIdResolver extends TypeIdResolverBase {
private static String generateId(AiModel<?> model) { private static String generateId(AiModel<?> model) {
String provider = model.providerConfig().provider().name(); String provider = model.providerConfig().provider().name();
String modelId = model.modelConfig().modelId(); String modelId = model.modelConfig().modelId();
return provider + "::" + modelId; return provider + PROVIDER_MODEL_SEPARATOR + modelId;
} }
} }

View File

@ -15,15 +15,34 @@
*/ */
package org.thingsboard.server.common.data.ai.provider; 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 { public enum AiProvider {
OPENAI, OPENAI(OpenAiChatModel.class),
AZURE_OPENAI, AZURE_OPENAI(AzureOpenAiChatModel.class),
GOOGLE_AI_GEMINI, GOOGLE_AI_GEMINI(GoogleAiGeminiChatModel.class),
GOOGLE_VERTEX_AI_GEMINI, GOOGLE_VERTEX_AI_GEMINI(GoogleVertexAiGeminiChatModel.class),
MISTRAL_AI, MISTRAL_AI(MistralAiChatModel.class),
ANTHROPIC, ANTHROPIC(AnthropicChatModel.class),
AMAZON_BEDROCK, AMAZON_BEDROCK(AmazonBedrockChatModel.class),
GITHUB_MODELS GITHUB_MODELS(GitHubModelsChatModel.class);
private final Class<?> defaultModelClass;
AiProvider(Class<?> defaultModelClass) {
this.defaultModelClass = defaultModelClass;
}
public Class<?> getDefaultModelClass() {
return defaultModelClass;
}
} }