diff --git a/.idea/DigmaJCEFProjectPersistence.xml b/.idea/DigmaJCEFProjectPersistence.xml index 7106797..e85fae3 100644 --- a/.idea/DigmaJCEFProjectPersistence.xml +++ b/.idea/DigmaJCEFProjectPersistence.xml @@ -6,6 +6,10 @@ + + + + \ No newline at end of file diff --git a/.idea/aws.xml b/.idea/aws.xml index b63b642..f64dd54 100644 --- a/.idea/aws.xml +++ b/.idea/aws.xml @@ -8,4 +8,7 @@ + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml index da2d3e9..04afe0b 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -5,6 +5,7 @@ + @@ -12,9 +13,11 @@ - + + + @@ -53,6 +56,13 @@ + + + + + diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 92519c8..c60416d 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -15,10 +15,14 @@ + + + + diff --git a/examples/glassfish-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java b/examples/glassfish-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java index d35c5c3..1fed5be 100644 --- a/examples/glassfish-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java +++ b/examples/glassfish-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java @@ -1,7 +1,7 @@ package io.jefrajames.booking; -import dev.langchain4j.service.SystemMessage; -import io.smallrye.llm.spi.RegisterAIService; +import org.eclipse.microprofile.ai.llm.SystemMessage; +import org.eclipse.microprofile.ai.llm.RegisterAIService; import java.time.temporal.ChronoUnit; diff --git a/examples/glassfish-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java b/examples/glassfish-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java index 68488de..a121bdb 100644 --- a/examples/glassfish-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java +++ b/examples/glassfish-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java @@ -1,9 +1,9 @@ package io.jefrajames.booking; -import dev.langchain4j.service.SystemMessage; -import dev.langchain4j.service.UserMessage; +import org.eclipse.microprofile.ai.llm.SystemMessage; +import org.eclipse.microprofile.ai.llm.UserMessage; import dev.langchain4j.service.V; -import io.smallrye.llm.spi.RegisterAIService; +import org.eclipse.microprofile.ai.llm.RegisterAIService; @SuppressWarnings("CdiManagedBeanInconsistencyInspection") @RegisterAIService(chatMemoryMaxMessages = 5, diff --git a/examples/helidon-car-booking-portable-ext/src/main/java/io/jefrajames/booking/ChatAiService.java b/examples/helidon-car-booking-portable-ext/src/main/java/io/jefrajames/booking/ChatAiService.java index 01a10d2..ee1da7b 100644 --- a/examples/helidon-car-booking-portable-ext/src/main/java/io/jefrajames/booking/ChatAiService.java +++ b/examples/helidon-car-booking-portable-ext/src/main/java/io/jefrajames/booking/ChatAiService.java @@ -1,10 +1,10 @@ package io.jefrajames.booking; -import dev.langchain4j.service.SystemMessage; +import org.eclipse.microprofile.ai.llm.SystemMessage; import org.eclipse.microprofile.faulttolerance.Fallback; import org.eclipse.microprofile.faulttolerance.Retry; import org.eclipse.microprofile.faulttolerance.Timeout; -import io.smallrye.llm.spi.RegisterAIService; +import org.eclipse.microprofile.ai.llm.RegisterAIService; import java.time.temporal.ChronoUnit; diff --git a/examples/helidon-car-booking-portable-ext/src/main/java/io/jefrajames/booking/FraudAiService.java b/examples/helidon-car-booking-portable-ext/src/main/java/io/jefrajames/booking/FraudAiService.java index 651b98a..57ef1fc 100644 --- a/examples/helidon-car-booking-portable-ext/src/main/java/io/jefrajames/booking/FraudAiService.java +++ b/examples/helidon-car-booking-portable-ext/src/main/java/io/jefrajames/booking/FraudAiService.java @@ -1,12 +1,12 @@ package io.jefrajames.booking; -import dev.langchain4j.service.SystemMessage; -import dev.langchain4j.service.UserMessage; +import org.eclipse.microprofile.ai.llm.SystemMessage; +import org.eclipse.microprofile.ai.llm.UserMessage; import dev.langchain4j.service.V; import org.eclipse.microprofile.faulttolerance.Fallback; import org.eclipse.microprofile.faulttolerance.Retry; import org.eclipse.microprofile.faulttolerance.Timeout; -import io.smallrye.llm.spi.RegisterAIService; +import org.eclipse.microprofile.ai.llm.RegisterAIService; import java.time.temporal.ChronoUnit; diff --git a/examples/helidon-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java b/examples/helidon-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java index 01a10d2..ee1da7b 100644 --- a/examples/helidon-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java +++ b/examples/helidon-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java @@ -1,10 +1,10 @@ package io.jefrajames.booking; -import dev.langchain4j.service.SystemMessage; +import org.eclipse.microprofile.ai.llm.SystemMessage; import org.eclipse.microprofile.faulttolerance.Fallback; import org.eclipse.microprofile.faulttolerance.Retry; import org.eclipse.microprofile.faulttolerance.Timeout; -import io.smallrye.llm.spi.RegisterAIService; +import org.eclipse.microprofile.ai.llm.RegisterAIService; import java.time.temporal.ChronoUnit; diff --git a/examples/helidon-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java b/examples/helidon-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java index 651b98a..57ef1fc 100644 --- a/examples/helidon-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java +++ b/examples/helidon-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java @@ -1,12 +1,12 @@ package io.jefrajames.booking; -import dev.langchain4j.service.SystemMessage; -import dev.langchain4j.service.UserMessage; +import org.eclipse.microprofile.ai.llm.SystemMessage; +import org.eclipse.microprofile.ai.llm.UserMessage; import dev.langchain4j.service.V; import org.eclipse.microprofile.faulttolerance.Fallback; import org.eclipse.microprofile.faulttolerance.Retry; import org.eclipse.microprofile.faulttolerance.Timeout; -import io.smallrye.llm.spi.RegisterAIService; +import org.eclipse.microprofile.ai.llm.RegisterAIService; import java.time.temporal.ChronoUnit; diff --git a/examples/liberty-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java b/examples/liberty-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java index bc6892f..290504c 100644 --- a/examples/liberty-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java +++ b/examples/liberty-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java @@ -6,8 +6,8 @@ import org.eclipse.microprofile.faulttolerance.Retry; import org.eclipse.microprofile.faulttolerance.Timeout; -import dev.langchain4j.service.SystemMessage; -import io.smallrye.llm.spi.RegisterAIService; +import org.eclipse.microprofile.ai.llm.SystemMessage; +import org.eclipse.microprofile.ai.llm.RegisterAIService; //@SuppressWarnings("CdiManagedBeanInconsistencyInspection") @RegisterAIService(tools = BookingService.class, chatMemoryMaxMessages = 10) diff --git a/examples/liberty-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java b/examples/liberty-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java index 68488de..a121bdb 100644 --- a/examples/liberty-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java +++ b/examples/liberty-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java @@ -1,9 +1,9 @@ package io.jefrajames.booking; -import dev.langchain4j.service.SystemMessage; -import dev.langchain4j.service.UserMessage; +import org.eclipse.microprofile.ai.llm.SystemMessage; +import org.eclipse.microprofile.ai.llm.UserMessage; import dev.langchain4j.service.V; -import io.smallrye.llm.spi.RegisterAIService; +import org.eclipse.microprofile.ai.llm.RegisterAIService; @SuppressWarnings("CdiManagedBeanInconsistencyInspection") @RegisterAIService(chatMemoryMaxMessages = 5, diff --git a/examples/quarkus-car-booking/pom.xml b/examples/quarkus-car-booking/pom.xml index a0fbb32..4cf9e64 100644 --- a/examples/quarkus-car-booking/pom.xml +++ b/examples/quarkus-car-booking/pom.xml @@ -110,6 +110,12 @@ rest-assured test + + io.smallrye.llm + mp-ai-api + 1.0.0-SNAPSHOT + compile + diff --git a/examples/quarkus-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java b/examples/quarkus-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java index 7e00c9b..7ddaa0b 100644 --- a/examples/quarkus-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java +++ b/examples/quarkus-car-booking/src/main/java/io/jefrajames/booking/ChatAiService.java @@ -2,13 +2,12 @@ import java.time.temporal.ChronoUnit; +import org.eclipse.microprofile.ai.llm.RegisterAIService; +import org.eclipse.microprofile.ai.llm.SystemMessage; import org.eclipse.microprofile.faulttolerance.Fallback; import org.eclipse.microprofile.faulttolerance.Retry; import org.eclipse.microprofile.faulttolerance.Timeout; -import dev.langchain4j.service.SystemMessage; -import io.smallrye.llm.spi.RegisterAIService; - @SuppressWarnings("CdiManagedBeanInconsistencyInspection") @RegisterAIService(tools = BookingService.class, chatMemoryMaxMessages = 10) public interface ChatAiService { diff --git a/examples/quarkus-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java b/examples/quarkus-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java index 61fdeef..eaa8a82 100644 --- a/examples/quarkus-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java +++ b/examples/quarkus-car-booking/src/main/java/io/jefrajames/booking/FraudAiService.java @@ -2,14 +2,14 @@ import java.time.temporal.ChronoUnit; +import org.eclipse.microprofile.ai.llm.RegisterAIService; +import org.eclipse.microprofile.ai.llm.SystemMessage; +import org.eclipse.microprofile.ai.llm.UserMessage; import org.eclipse.microprofile.faulttolerance.Fallback; import org.eclipse.microprofile.faulttolerance.Retry; import org.eclipse.microprofile.faulttolerance.Timeout; -import dev.langchain4j.service.SystemMessage; -import dev.langchain4j.service.UserMessage; import dev.langchain4j.service.V; -import io.smallrye.llm.spi.RegisterAIService; @SuppressWarnings("CdiManagedBeanInconsistencyInspection") @RegisterAIService(chatMemoryMaxMessages = 5) diff --git a/mp-ai-api/pom.xml b/mp-ai-api/pom.xml new file mode 100644 index 0000000..b13c105 --- /dev/null +++ b/mp-ai-api/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + io.smallrye.llm + smallrye-llm-parent + 1.0.0-SNAPSHOT + + mp-ai-api + Archetype - mp-ai-api + http://maven.apache.org + + + jakarta.enterprise + jakarta.enterprise.cdi-api + 3.0.0 + provided + + + diff --git a/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/spi/RegisterAIService.java b/mp-ai-api/src/main/java/org/eclipse/microprofile/ai/llm/RegisterAIService.java similarity index 95% rename from smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/spi/RegisterAIService.java rename to mp-ai-api/src/main/java/org/eclipse/microprofile/ai/llm/RegisterAIService.java index b48605f..2c3f8c5 100644 --- a/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/spi/RegisterAIService.java +++ b/mp-ai-api/src/main/java/org/eclipse/microprofile/ai/llm/RegisterAIService.java @@ -1,4 +1,4 @@ -package io.smallrye.llm.spi; +package org.eclipse.microprofile.ai.llm; import static java.lang.annotation.RetentionPolicy.RUNTIME; diff --git a/mp-ai-api/src/main/java/org/eclipse/microprofile/ai/llm/SystemMessage.java b/mp-ai-api/src/main/java/org/eclipse/microprofile/ai/llm/SystemMessage.java new file mode 100644 index 0000000..fa3322a --- /dev/null +++ b/mp-ai-api/src/main/java/org/eclipse/microprofile/ai/llm/SystemMessage.java @@ -0,0 +1,16 @@ +package org.eclipse.microprofile.ai.llm; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface SystemMessage { + String[] value() default { "" }; + + String delimiter() default "\n"; + + String fromResource() default ""; +} diff --git a/mp-ai-api/src/main/java/org/eclipse/microprofile/ai/llm/UserMessage.java b/mp-ai-api/src/main/java/org/eclipse/microprofile/ai/llm/UserMessage.java new file mode 100644 index 0000000..6c54972 --- /dev/null +++ b/mp-ai-api/src/main/java/org/eclipse/microprofile/ai/llm/UserMessage.java @@ -0,0 +1,16 @@ +package org.eclipse.microprofile.ai.llm; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.PARAMETER }) +public @interface UserMessage { + String[] value() default { "" }; + + String delimiter() default "\n"; + + String fromResource() default ""; +} diff --git a/mp-ai-api/src/main/resources/META-INF/maven/archetype.xml b/mp-ai-api/src/main/resources/META-INF/maven/archetype.xml new file mode 100644 index 0000000..d3bb399 --- /dev/null +++ b/mp-ai-api/src/main/resources/META-INF/maven/archetype.xml @@ -0,0 +1,9 @@ + + mp-ai-api + + src/main/java/App.java + + + src/test/java/AppTest.java + + diff --git a/mp-ai-api/src/main/resources/archetype-resources/pom.xml b/mp-ai-api/src/main/resources/archetype-resources/pom.xml new file mode 100644 index 0000000..a059fd3 --- /dev/null +++ b/mp-ai-api/src/main/resources/archetype-resources/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + $io.smallrye.llm + $mp-ai-api + $1.0.0-SNAPSHOT + + + junit + junit + 3.8.1 + test + + + diff --git a/mp-ai-api/src/main/resources/archetype-resources/src/main/java/App.java b/mp-ai-api/src/main/resources/archetype-resources/src/main/java/App.java new file mode 100644 index 0000000..97f4620 --- /dev/null +++ b/mp-ai-api/src/main/resources/archetype-resources/src/main/java/App.java @@ -0,0 +1,13 @@ +package $io.smallrye.llm; + +/** + * Hello world! + * + */ +public class App +{ + public static void main( String[] args ) + { + System.out.println( "Hello World!" ); + } +} diff --git a/mp-ai-api/src/main/resources/archetype-resources/src/test/java/AppTest.java b/mp-ai-api/src/main/resources/archetype-resources/src/test/java/AppTest.java new file mode 100644 index 0000000..24ff3d3 --- /dev/null +++ b/mp-ai-api/src/main/resources/archetype-resources/src/test/java/AppTest.java @@ -0,0 +1,38 @@ +package $io.smallrye.llm; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Unit test for simple App. + */ +public class AppTest + extends TestCase +{ + /** + * Create the test case + * + * @param testName name of the test case + */ + public AppTest( String testName ) + { + super( testName ); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() + { + return new TestSuite( AppTest.class ); + } + + /** + * Rigourous Test :-) + */ + public void testApp() + { + assertTrue( true ); + } +} diff --git a/pom.xml b/pom.xml index 88a3405..32f8224 100644 --- a/pom.xml +++ b/pom.xml @@ -81,6 +81,7 @@ smallrye-llm-langchain4j-buildcompatible-extension smallrye-llm-langchain4j-core smallrye-llm-langchain4j-config-mpconfig + mp-ai-api diff --git a/smallrye-llm-langchain4j-buildcompatible-extension/pom.xml b/smallrye-llm-langchain4j-buildcompatible-extension/pom.xml index 1d055e0..1460a9a 100644 --- a/smallrye-llm-langchain4j-buildcompatible-extension/pom.xml +++ b/smallrye-llm-langchain4j-buildcompatible-extension/pom.xml @@ -86,6 +86,12 @@ weld-junit5 test + + io.smallrye.llm + mp-ai-api + 1.0.0-SNAPSHOT + compile + diff --git a/smallrye-llm-langchain4j-buildcompatible-extension/src/main/java/io/smallrye/llm/aiservice/Langchain4JAIServiceBuildCompatibleExtension.java b/smallrye-llm-langchain4j-buildcompatible-extension/src/main/java/io/smallrye/llm/aiservice/Langchain4JAIServiceBuildCompatibleExtension.java index 2cdbeb2..26d5701 100644 --- a/smallrye-llm-langchain4j-buildcompatible-extension/src/main/java/io/smallrye/llm/aiservice/Langchain4JAIServiceBuildCompatibleExtension.java +++ b/smallrye-llm-langchain4j-buildcompatible-extension/src/main/java/io/smallrye/llm/aiservice/Langchain4JAIServiceBuildCompatibleExtension.java @@ -9,21 +9,20 @@ import jakarta.enterprise.inject.build.compatible.spi.BuildCompatibleExtension; import jakarta.enterprise.inject.build.compatible.spi.ClassConfig; import jakarta.enterprise.inject.build.compatible.spi.Enhancement; -import jakarta.enterprise.inject.build.compatible.spi.FieldConfig; +import jakarta.enterprise.inject.build.compatible.spi.MethodConfig; import jakarta.enterprise.inject.build.compatible.spi.Synthesis; import jakarta.enterprise.inject.build.compatible.spi.SyntheticBeanBuilder; import jakarta.enterprise.inject.build.compatible.spi.SyntheticComponents; import jakarta.enterprise.inject.literal.NamedLiteral; import jakarta.enterprise.lang.model.AnnotationInfo; import jakarta.enterprise.lang.model.declarations.ClassInfo; -import jakarta.enterprise.lang.model.declarations.FieldInfo; -import jakarta.enterprise.lang.model.types.ClassType; import jakarta.inject.Named; +import org.eclipse.microprofile.ai.llm.RegisterAIService; +import org.eclipse.microprofile.ai.llm.SystemMessage; +import org.eclipse.microprofile.ai.llm.UserMessage; import org.jboss.logging.Logger; -import io.smallrye.llm.spi.RegisterAIService; - public class Langchain4JAIServiceBuildCompatibleExtension implements BuildCompatibleExtension { private static final Logger LOGGER = Logger.getLogger(Langchain4JAIServiceBuildCompatibleExtension.class); private static final Set> detectedAIServicesDeclaredInterfaces = new HashSet<>(); @@ -47,29 +46,18 @@ public void protectedToolsToBePurgedByQuarkus(ClassConfig classConfig) throws Cl } } - @SuppressWarnings("unused") - @Enhancement(types = Object.class, withAnnotations = RegisterAIService.class, withSubtypes = true) - @Priority(10) - public void detectRegisterAIService(ClassConfig classConfig) throws ClassNotFoundException { - ClassInfo classInfo = classConfig.info(); - registerAIService(classInfo); - } - @Enhancement(types = Object.class, withSubtypes = true) @Priority(30) - public void detectRegisterAIService(FieldConfig config) throws ClassNotFoundException { - FieldInfo info = config.info(); - if (info.type().isClass()) { - ClassType classType = info.type().asClass(); - ClassInfo classInfo = classType.declaration(); - AnnotationInfo annotationInfo = classInfo.annotation(RegisterAIService.class); - if (annotationInfo != null) { - registerAIService(classInfo); - } + public void detectRegisterAIService(ClassConfig config) throws ClassNotFoundException, NoSuchMethodException { + ClassInfo classInfo = config.info(); + AnnotationInfo annotationInfo = classInfo.annotation(RegisterAIService.class); + if (annotationInfo != null) { + registerAIService(config); } } - private void registerAIService(ClassInfo classInfo) throws ClassNotFoundException { + private void registerAIService(ClassConfig classConfig) throws ClassNotFoundException, NoSuchMethodException { + ClassInfo classInfo = classConfig.info(); if (classInfo.isInterface()) { String className = classInfo.name(); Class interfaceClass = getLoadClass(className); @@ -85,6 +73,28 @@ private void registerAIService(ClassInfo classInfo) throws ClassNotFoundExceptio } } + private void convertSystemMessages(ClassConfig classConfig) throws ClassNotFoundException, NoSuchMethodException { + AnnotationInfo annotation = classConfig.info().annotation(SystemMessage.class); + if (annotation != null) { + classConfig.addAnnotation(SystemMessageAnnotationConverter.fromMP(annotation)); + } + for (MethodConfig methodConfig : classConfig.methods()) { + if (methodConfig.info().hasAnnotation(SystemMessage.class)) { + methodConfig.addAnnotation( + SystemMessageAnnotationConverter.fromMP(methodConfig.info().annotation(SystemMessage.class))); + } + } + } + + private void convertUserMessages(ClassConfig classConfig) throws ClassNotFoundException, NoSuchMethodException { + for (MethodConfig methodConfig : classConfig.methods()) { + if (methodConfig.info().hasAnnotation(UserMessage.class)) { + methodConfig.addAnnotation( + UserMessageAnnotationConverter.fromMP(methodConfig.info().annotation(UserMessage.class))); + } + } + } + private static Class getLoadClass(String className) throws ClassNotFoundException { return Thread.currentThread().getContextClassLoader().loadClass(className); } diff --git a/smallrye-llm-langchain4j-buildcompatible-extension/src/test/java/io/smallrye/llm/core/BceExtensionTest.java b/smallrye-llm-langchain4j-buildcompatible-extension/src/test/java/io/smallrye/llm/core/BceExtensionTest.java index be64a7d..acfa2d1 100644 --- a/smallrye-llm-langchain4j-buildcompatible-extension/src/test/java/io/smallrye/llm/core/BceExtensionTest.java +++ b/smallrye-llm-langchain4j-buildcompatible-extension/src/test/java/io/smallrye/llm/core/BceExtensionTest.java @@ -75,6 +75,7 @@ void ensureInjectAndScope() { Assertions.assertNotNull(myDummyApplicationScopedAIService); assertBeanScope(MyDummyAIService.class, RequestScoped.class); assertBeanScope(MyDummyApplicationScopedAIService.class, ApplicationScoped.class); + } @Test diff --git a/smallrye-llm-langchain4j-buildcompatible-extension/src/test/java/io/smallrye/llm/core/MyDummyAIService.java b/smallrye-llm-langchain4j-buildcompatible-extension/src/test/java/io/smallrye/llm/core/MyDummyAIService.java index fb87b1f..d0d0d2c 100644 --- a/smallrye-llm-langchain4j-buildcompatible-extension/src/test/java/io/smallrye/llm/core/MyDummyAIService.java +++ b/smallrye-llm-langchain4j-buildcompatible-extension/src/test/java/io/smallrye/llm/core/MyDummyAIService.java @@ -1,9 +1,10 @@ package io.smallrye.llm.core; -import dev.langchain4j.service.SystemMessage; -import dev.langchain4j.service.UserMessage; +import org.eclipse.microprofile.ai.llm.RegisterAIService; +import org.eclipse.microprofile.ai.llm.SystemMessage; +import org.eclipse.microprofile.ai.llm.UserMessage; + import dev.langchain4j.service.V; -import io.smallrye.llm.spi.RegisterAIService; @SuppressWarnings("CdiManagedBeanInconsistencyInspection") @RegisterAIService diff --git a/smallrye-llm-langchain4j-buildcompatible-extension/src/test/java/io/smallrye/llm/core/MyDummyApplicationScopedAIService.java b/smallrye-llm-langchain4j-buildcompatible-extension/src/test/java/io/smallrye/llm/core/MyDummyApplicationScopedAIService.java index 81deb7e..c86cf42 100644 --- a/smallrye-llm-langchain4j-buildcompatible-extension/src/test/java/io/smallrye/llm/core/MyDummyApplicationScopedAIService.java +++ b/smallrye-llm-langchain4j-buildcompatible-extension/src/test/java/io/smallrye/llm/core/MyDummyApplicationScopedAIService.java @@ -2,7 +2,7 @@ import jakarta.enterprise.context.ApplicationScoped; -import io.smallrye.llm.spi.RegisterAIService; +import org.eclipse.microprofile.ai.llm.RegisterAIService; @SuppressWarnings("CdiManagedBeanInconsistencyInspection") @RegisterAIService(scope = ApplicationScoped.class) diff --git a/smallrye-llm-langchain4j-core/pom.xml b/smallrye-llm-langchain4j-core/pom.xml index 014aadc..fc39980 100644 --- a/smallrye-llm-langchain4j-core/pom.xml +++ b/smallrye-llm-langchain4j-core/pom.xml @@ -11,6 +11,11 @@ http://maven.apache.org + + io.smallrye.llm + mp-ai-api + ${project.version} + org.jboss.logging jboss-logging @@ -25,4 +30,97 @@ langchain4j + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.3.0 + + + unpack + generate-sources + + unpack + + + + + dev.langchain4j + langchain4j + ${dev.langchain4j.version} + sources + + dev/langchain4j/service/DefaultAiServices.java + + + + DefaultAiServices + MPDefaultAiServices + + + ${project.build.directory}/generated-sources + + + + + + + + com.google.code.maven-replacer-plugin + maven-replacer-plugin + 1.3.5 + + + replaceTokens + generate-sources + + replace + + + + + target/generated-sources/dev/langchain4j/service/MPDefaultAiServices.java + + + class DefaultAiServices + public class MPDefaultAiServices + + + DefaultAiServices\( + public MPDefaultAiServices( + + + dev.langchain4j.service.SystemMessage + org.eclipse.microprofile.ai.llm.SystemMessage + + + dev.langchain4j.service.UserMessage + org.eclipse.microprofile.ai.llm.UserMessage + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.2.0 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources + + + + + + + diff --git a/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/aiservice/CommonAIServiceCreator.java b/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/aiservice/CommonAIServiceCreator.java index 35546d9..a2a4faf 100644 --- a/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/aiservice/CommonAIServiceCreator.java +++ b/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/aiservice/CommonAIServiceCreator.java @@ -7,13 +7,13 @@ import jakarta.enterprise.inject.Instance; import jakarta.enterprise.inject.literal.NamedLiteral; +import org.eclipse.microprofile.ai.llm.RegisterAIService; import org.jboss.logging.Logger; import dev.langchain4j.model.chat.ChatLanguageModel; import dev.langchain4j.rag.content.retriever.ContentRetriever; import dev.langchain4j.service.AiServices; import io.smallrye.llm.core.langchain4j.core.config.spi.ChatMemoryFactoryProvider; -import io.smallrye.llm.spi.RegisterAIService; public class CommonAIServiceCreator { diff --git a/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/aiservice/SystemMessageAnnotationConverter.java b/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/aiservice/SystemMessageAnnotationConverter.java new file mode 100644 index 0000000..0e647d1 --- /dev/null +++ b/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/aiservice/SystemMessageAnnotationConverter.java @@ -0,0 +1,37 @@ +package io.smallrye.llm.aiservice; + +import jakarta.enterprise.lang.model.AnnotationInfo; +import jakarta.enterprise.lang.model.AnnotationMember; +import jakarta.enterprise.util.AnnotationLiteral; + +import org.eclipse.microprofile.ai.llm.SystemMessage; + +public class SystemMessageAnnotationConverter { + + public static SystemMessage fromMP(AnnotationInfo source) { + return new LangChain4JSystemMessage(source); + } + + public static class LangChain4JSystemMessage extends AnnotationLiteral implements SystemMessage { + private final AnnotationInfo source; + + public LangChain4JSystemMessage(AnnotationInfo source) { + this.source = source; + } + + @Override + public String[] value() { + return source.value().asArray().stream().map(AnnotationMember::asString).toArray(String[]::new); + } + + @Override + public String delimiter() { + return source.member("delimiter").asString(); + } + + @Override + public String fromResource() { + return source.member("fromResource").asString(); + } + } +} diff --git a/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/aiservice/UserMessageAnnotationConverter.java b/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/aiservice/UserMessageAnnotationConverter.java new file mode 100644 index 0000000..e139bfe --- /dev/null +++ b/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/aiservice/UserMessageAnnotationConverter.java @@ -0,0 +1,37 @@ +package io.smallrye.llm.aiservice; + +import jakarta.enterprise.lang.model.AnnotationInfo; +import jakarta.enterprise.lang.model.AnnotationMember; +import jakarta.enterprise.util.AnnotationLiteral; + +import org.eclipse.microprofile.ai.llm.UserMessage; + +public class UserMessageAnnotationConverter { + + public static UserMessage fromMP(AnnotationInfo source) { + return new LangChain4JUserMessage(source); + } + + public static class LangChain4JUserMessage extends AnnotationLiteral implements UserMessage { + private final AnnotationInfo source; + + public LangChain4JUserMessage(AnnotationInfo source) { + this.source = source; + } + + @Override + public String[] value() { + return source.value().asArray().stream().map(AnnotationMember::asString).toArray(String[]::new); + } + + @Override + public String delimiter() { + return source.member("delimiter").asString(); + } + + @Override + public String fromResource() { + return source.member("fromResource").asString(); + } + } +} diff --git a/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/langchain4jadapter/MPAIServiceFactory.java b/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/langchain4jadapter/MPAIServiceFactory.java new file mode 100644 index 0000000..f7993cd --- /dev/null +++ b/smallrye-llm-langchain4j-core/src/main/java/io/smallrye/llm/langchain4jadapter/MPAIServiceFactory.java @@ -0,0 +1,13 @@ +package io.smallrye.llm.langchain4jadapter; + +import dev.langchain4j.service.AiServiceContext; +import dev.langchain4j.service.AiServices; +import dev.langchain4j.service.MPDefaultAiServices; +import dev.langchain4j.spi.services.AiServicesFactory; + +public class MPAIServiceFactory implements AiServicesFactory { + @Override + public AiServices create(AiServiceContext context) { + return new MPDefaultAiServices(context); + } +} diff --git a/smallrye-llm-langchain4j-portable-extension/pom.xml b/smallrye-llm-langchain4j-portable-extension/pom.xml index 4690195..7fb5d38 100644 --- a/smallrye-llm-langchain4j-portable-extension/pom.xml +++ b/smallrye-llm-langchain4j-portable-extension/pom.xml @@ -55,5 +55,17 @@ weld-core-impl provided + + io.smallrye.llm + mp-ai-api + 1.0.0-SNAPSHOT + test + + + io.smallrye.llm + mp-ai-api + 1.0.0-SNAPSHOT + compile + diff --git a/smallrye-llm-langchain4j-portable-extension/src/main/java/io/smallrye/llm/core/langchain4j/portableextension/LangChain4JAIServicePortableExtension.java b/smallrye-llm-langchain4j-portable-extension/src/main/java/io/smallrye/llm/core/langchain4j/portableextension/LangChain4JAIServicePortableExtension.java index 304de6c..44c8800 100644 --- a/smallrye-llm-langchain4j-portable-extension/src/main/java/io/smallrye/llm/core/langchain4j/portableextension/LangChain4JAIServicePortableExtension.java +++ b/smallrye-llm-langchain4j-portable-extension/src/main/java/io/smallrye/llm/core/langchain4j/portableextension/LangChain4JAIServicePortableExtension.java @@ -17,10 +17,10 @@ import jakarta.enterprise.inject.spi.ProcessInjectionPoint; import jakarta.enterprise.inject.spi.WithAnnotations; +import org.eclipse.microprofile.ai.llm.RegisterAIService; import org.jboss.logging.Logger; import io.smallrye.llm.aiservice.CommonAIServiceCreator; -import io.smallrye.llm.spi.RegisterAIService; public class LangChain4JAIServicePortableExtension implements Extension { private static final Logger LOGGER = Logger.getLogger(LangChain4JAIServicePortableExtension.class); diff --git a/smallrye-llm-langchain4j-portable-extension/src/test/java/io/smallrye/llm/core/MyDummyAIService.java b/smallrye-llm-langchain4j-portable-extension/src/test/java/io/smallrye/llm/core/MyDummyAIService.java index fb87b1f..d0d0d2c 100644 --- a/smallrye-llm-langchain4j-portable-extension/src/test/java/io/smallrye/llm/core/MyDummyAIService.java +++ b/smallrye-llm-langchain4j-portable-extension/src/test/java/io/smallrye/llm/core/MyDummyAIService.java @@ -1,9 +1,10 @@ package io.smallrye.llm.core; -import dev.langchain4j.service.SystemMessage; -import dev.langchain4j.service.UserMessage; +import org.eclipse.microprofile.ai.llm.RegisterAIService; +import org.eclipse.microprofile.ai.llm.SystemMessage; +import org.eclipse.microprofile.ai.llm.UserMessage; + import dev.langchain4j.service.V; -import io.smallrye.llm.spi.RegisterAIService; @SuppressWarnings("CdiManagedBeanInconsistencyInspection") @RegisterAIService diff --git a/smallrye-llm-langchain4j-portable-extension/src/test/java/io/smallrye/llm/core/MyDummyApplicationScopedAIService.java b/smallrye-llm-langchain4j-portable-extension/src/test/java/io/smallrye/llm/core/MyDummyApplicationScopedAIService.java index 81deb7e..c86cf42 100644 --- a/smallrye-llm-langchain4j-portable-extension/src/test/java/io/smallrye/llm/core/MyDummyApplicationScopedAIService.java +++ b/smallrye-llm-langchain4j-portable-extension/src/test/java/io/smallrye/llm/core/MyDummyApplicationScopedAIService.java @@ -2,7 +2,7 @@ import jakarta.enterprise.context.ApplicationScoped; -import io.smallrye.llm.spi.RegisterAIService; +import org.eclipse.microprofile.ai.llm.RegisterAIService; @SuppressWarnings("CdiManagedBeanInconsistencyInspection") @RegisterAIService(scope = ApplicationScoped.class) diff --git a/smallrye-llm-langchain4j-portable-extension/src/test/java/io/smallrye/llm/core/PortableExtensionTest.java b/smallrye-llm-langchain4j-portable-extension/src/test/java/io/smallrye/llm/core/PortableExtensionTest.java index 4e124cc..01ba768 100644 --- a/smallrye-llm-langchain4j-portable-extension/src/test/java/io/smallrye/llm/core/PortableExtensionTest.java +++ b/smallrye-llm-langchain4j-portable-extension/src/test/java/io/smallrye/llm/core/PortableExtensionTest.java @@ -1,8 +1,12 @@ package io.smallrye.llm.core; import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import java.lang.reflect.UndeclaredThrowableException; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.Callable; +import java.util.stream.Collectors; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.RequestScoped; @@ -78,6 +82,17 @@ void ensureInjectAndScope() { Assertions.assertNotNull(myDummyApplicationScopedAIService); assertBeanScope(MyDummyAIService.class, RequestScoped.class); assertBeanScope(MyDummyApplicationScopedAIService.class, ApplicationScoped.class); + + List detectFraudForCustomer = Arrays.stream(myDummyAIService.getClass().getDeclaredMethods()) + .filter(m -> m.getName().equals("detectFraudForCustomer")).collect(Collectors.toList()); + + Assertions.assertEquals(1, detectFraudForCustomer.size()); + + Assertions.assertTrue( + detectFraudForCustomer.get(0).isAnnotationPresent(org.eclipse.microprofile.ai.llm.SystemMessage.class)); + Assertions.assertTrue( + detectFraudForCustomer.get(0).isAnnotationPresent(org.eclipse.microprofile.ai.llm.UserMessage.class)); + } @Test