6262import dev .langchain4j .service .Moderate ;
6363import dev .langchain4j .service .output .ServiceOutputParser ;
6464import io .quarkiverse .langchain4j .ModelName ;
65+ import io .quarkiverse .langchain4j .RegisterAiService ;
6566import io .quarkiverse .langchain4j .ToolBox ;
6667import io .quarkiverse .langchain4j .deployment .config .LangChain4jBuildConfig ;
68+ import io .quarkiverse .langchain4j .deployment .devui .ToolProviderInfo ;
6769import io .quarkiverse .langchain4j .deployment .items .MethodParameterAllowedAnnotationsBuildItem ;
6870import io .quarkiverse .langchain4j .deployment .items .MethodParameterIgnoredAnnotationsBuildItem ;
6971import io .quarkiverse .langchain4j .deployment .items .SelectedChatModelProviderBuildItem ;
@@ -208,13 +210,15 @@ public void findDeclarativeServices(CombinedIndexBuildItem indexBuildItem,
208210 BuildProducer <RequestModerationModelBeanBuildItem > requestModerationModelBeanProducer ,
209211 BuildProducer <RequestImageModelBeanBuildItem > requestImageModelBeanProducer ,
210212 BuildProducer <DeclarativeAiServiceBuildItem > declarativeAiServiceProducer ,
213+ BuildProducer <ToolProviderMetaBuildItem > toolProviderProducer ,
211214 BuildProducer <ReflectiveClassBuildItem > reflectiveClassProducer ,
212215 BuildProducer <GeneratedClassBuildItem > generatedClassProducer ) {
213216 IndexView index = indexBuildItem .getIndex ();
214217
215218 Set <String > chatModelNames = new HashSet <>();
216219 Set <String > moderationModelNames = new HashSet <>();
217220 Set <String > imageModelNames = new HashSet <>();
221+ List <ToolProviderInfo > toolProviderInfos = new ArrayList <>();
218222 ClassOutput generatedClassOutput = new GeneratedClassGizmoAdaptor (generatedClassProducer , true );
219223 for (AnnotationInstance instance : index .getAnnotations (LangChain4jDotNames .REGISTER_AI_SERVICES )) {
220224 if (instance .target ().kind () != AnnotationTarget .Kind .CLASS ) {
@@ -323,6 +327,15 @@ public void findDeclarativeServices(CombinedIndexBuildItem indexBuildItem,
323327 validateSupplierAndRegisterForReflection (moderationModelSupplierClassName , index , reflectiveClassProducer );
324328 }
325329
330+ DotName toolProviderClassName = LangChain4jDotNames .BEAN_IF_EXISTS_TOOL_PROVIDER_SUPPLIER ;
331+ AnnotationValue toolProviderValue = instance .value ("toolProviderSupplier" );
332+ if (toolProviderValue != null ) {
333+ toolProviderClassName = toolProviderValue .asClass ().name ();
334+ validateSupplierAndRegisterForReflection (toolProviderClassName , index , reflectiveClassProducer );
335+ toolProviderInfos .add (new ToolProviderInfo (toolProviderClassName .toString (),
336+ declarativeAiServiceClassInfo .simpleName ()));
337+ }
338+
326339 DotName imageModelSupplierClassName = LangChain4jDotNames .BEAN_IF_EXISTS_IMAGE_MODEL_SUPPLIER ;
327340 AnnotationValue imageModelSupplierValue = instance .value ("imageModelSupplier" );
328341 if (imageModelSupplierValue != null ) {
@@ -381,8 +394,10 @@ public void findDeclarativeServices(CombinedIndexBuildItem indexBuildItem,
381394 cdiScope ,
382395 chatModelName ,
383396 moderationModelName ,
384- imageModelName ));
397+ imageModelName ,
398+ toolProviderClassName ));
385399 }
400+ toolProviderProducer .produce (new ToolProviderMetaBuildItem (toolProviderInfos ));
386401
387402 for (String chatModelName : chatModelNames ) {
388403 requestChatModelBeanProducer .produce (new RequestChatModelBeanBuildItem (chatModelName ));
@@ -462,6 +477,7 @@ public void handleDeclarativeServices(AiServicesRecorder recorder,
462477 boolean needsModerationModelBean = false ;
463478 boolean needsImageModelBean = false ;
464479 Set <DotName > allToolNames = new HashSet <>();
480+ Set <DotName > allToolProviders = new HashSet <>();
465481
466482 for (DeclarativeAiServiceBuildItem bi : declarativeAiServiceItems ) {
467483 ClassInfo declarativeAiServiceClassInfo = bi .getServiceClassInfo ();
@@ -477,6 +493,10 @@ public void handleDeclarativeServices(AiServicesRecorder recorder,
477493
478494 List <String > toolClassNames = bi .getToolDotNames ().stream ().map (DotName ::toString ).collect (Collectors .toList ());
479495
496+ String toolProviderSupplierClassName = (bi .getToolProviderClassDotName () != null
497+ ? bi .getToolProviderClassDotName ().toString ()
498+ : null );
499+
480500 String chatMemoryProviderSupplierClassName = bi .getChatMemoryProviderSupplierClassDotName () != null
481501 ? bi .getChatMemoryProviderSupplierClassDotName ().toString ()
482502 : null ;
@@ -556,7 +576,9 @@ public void handleDeclarativeServices(AiServicesRecorder recorder,
556576 serviceClassName ,
557577 chatLanguageModelSupplierClassName ,
558578 streamingChatLanguageModelSupplierClassName ,
559- toolClassNames , chatMemoryProviderSupplierClassName , retrieverClassName ,
579+ toolClassNames ,
580+ toolProviderSupplierClassName ,
581+ chatMemoryProviderSupplierClassName , retrieverClassName ,
560582 retrievalAugmentorSupplierClassName ,
561583 auditServiceClassSupplierName ,
562584 moderationModelSupplierClassName ,
@@ -668,6 +690,13 @@ public void handleDeclarativeServices(AiServicesRecorder recorder,
668690 needsImageModelBean = true ;
669691 }
670692
693+ if (!RegisterAiService .BeanIfExistsToolProviderSupplier .class .getName ()
694+ .equals (toolProviderSupplierClassName ) && toolProviderSupplierClassName != null ) {
695+ DotName toolProvider = DotName .createSimple (toolProviderSupplierClassName );
696+ configurator .addInjectionPoint (ClassType .create (toolProvider ));
697+ allToolProviders .add (toolProvider );
698+ }
699+
671700 configurator
672701 .addInjectionPoint (ParameterizedType .create (DotNames .CDI_INSTANCE ,
673702 new Type [] { ClassType .create (OutputGuardrail .class ) }, null ))
@@ -700,6 +729,9 @@ public void handleDeclarativeServices(AiServicesRecorder recorder,
700729 if (needsImageModelBean ) {
701730 unremoveableProducer .produce (UnremovableBeanBuildItem .beanTypes (LangChain4jDotNames .IMAGE_MODEL ));
702731 }
732+ if (!allToolProviders .isEmpty ()) {
733+ unremoveableProducer .produce (UnremovableBeanBuildItem .beanTypes (allToolProviders ));
734+ }
703735 if (!allToolNames .isEmpty ()) {
704736 unremoveableProducer .produce (UnremovableBeanBuildItem .beanTypes (allToolNames ));
705737 }
@@ -795,7 +827,7 @@ public void handleAiServices(
795827 for (ClassInfo classInfo : index .getKnownUsers (LangChain4jDotNames .AI_SERVICES )) {
796828 String className = classInfo .name ().toString ();
797829 if (className .startsWith ("io.quarkiverse.langchain4j" ) || className .startsWith ("dev.langchain4j" )) { // TODO: this can be made smarter if
798- // needed
830+ // needed
799831 continue ;
800832 }
801833 try (InputStream is = Thread .currentThread ().getContextClassLoader ().getResourceAsStream (
0 commit comments