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.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;
}
}

View File

@ -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;
}
}