@@ -1147,6 +1147,13 @@ public void markIgnoredAnnotations(BuildProducer<MethodParameterIgnoredAnnotatio
1147
1147
}));
1148
1148
}
1149
1149
1150
+ @ BuildStep
1151
+ AnnotationsImpliesAiServiceBuildItem implyAiService () {
1152
+ return new AnnotationsImpliesAiServiceBuildItem (
1153
+ List .of (LangChain4jDotNames .SYSTEM_MESSAGE , LangChain4jDotNames .USER_MESSAGE ,
1154
+ LangChain4jDotNames .MODERATE ));
1155
+ }
1156
+
1150
1157
@ BuildStep
1151
1158
@ Record (ExecutionTime .STATIC_INIT )
1152
1159
public void handleAiServices (
@@ -1167,7 +1174,10 @@ public void handleAiServices(
1167
1174
Optional <MetricsCapabilityBuildItem > metricsCapability ,
1168
1175
Capabilities capabilities ,
1169
1176
List <ToolMethodBuildItem > tools ,
1170
- List <ToolQualifierProvider .BuildItem > toolQualifierProviderItems ) {
1177
+ List <ToolQualifierProvider .BuildItem > toolQualifierProviderItems ,
1178
+ List <AnnotationsImpliesAiServiceBuildItem > annotationsImpliesAiServiceItems ,
1179
+ List <SkipOutputFormatInstructionsBuildItem > skipOutputFormatInstructionsItems ,
1180
+ List <FallbackToDummyUserMessageBuildItem > fallbackToDummyUserMessageItems ) {
1171
1181
1172
1182
IndexView index = indexBuildItem .getIndex ();
1173
1183
@@ -1211,7 +1221,8 @@ public void handleAiServices(
1211
1221
1212
1222
Set <String > detectedForCreate = new HashSet <>(nameToUsed .keySet ());
1213
1223
addCreatedAware (index , detectedForCreate );
1214
- addIfacesWithMessageAnns (index , detectedForCreate );
1224
+ addIfacesWithMessageAnns (index , annotationsImpliesAiServiceItems .stream ()
1225
+ .flatMap (bi -> bi .getAnnotationNames ().stream ()).collect (Collectors .toList ()), detectedForCreate );
1215
1226
Set <String > registeredAiServiceClassNames = declarativeAiServiceItems .stream ()
1216
1227
.map (bi -> bi .getServiceClassInfo ().name ().toString ()).collect (
1217
1228
Collectors .toUnmodifiableSet ());
@@ -1342,7 +1353,13 @@ public void handleAiServices(
1342
1353
config .responseSchema (),
1343
1354
allowedPredicates ,
1344
1355
ignoredPredicates ,
1345
- tools , toolQualifierProviderItems );
1356
+ tools , toolQualifierProviderItems ,
1357
+ skipOutputFormatInstructionsItems .stream ().map (
1358
+ SkipOutputFormatInstructionsBuildItem ::getPredicate )
1359
+ .reduce (mi -> false , Predicate ::or ),
1360
+ fallbackToDummyUserMessageItems .stream ().map (
1361
+ FallbackToDummyUserMessageBuildItem ::getPredicate )
1362
+ .reduce (mi -> false , Predicate ::or ));
1346
1363
if (!methodCreateInfo .getToolClassInfo ().isEmpty ()) {
1347
1364
if ((matchingBI != null )
1348
1365
&& matchingBI .getChatMemoryProviderSupplierClassDotName () == null ) {
@@ -1482,9 +1499,7 @@ private String createMethodId(MethodInfo methodInfo) {
1482
1499
+ Arrays .toString (methodInfo .parameters ().stream ().map (mp -> mp .type ().name ().toString ()).toArray ()) + ')' ;
1483
1500
}
1484
1501
1485
- private void addIfacesWithMessageAnns (IndexView index , Set <String > detectedForCreate ) {
1486
- List <DotName > annotations = List .of (LangChain4jDotNames .SYSTEM_MESSAGE , LangChain4jDotNames .USER_MESSAGE ,
1487
- LangChain4jDotNames .MODERATE );
1502
+ private void addIfacesWithMessageAnns (IndexView index , List <DotName > annotations , Set <String > detectedForCreate ) {
1488
1503
for (DotName annotation : annotations ) {
1489
1504
Collection <AnnotationInstance > instances = index .getAnnotations (annotation );
1490
1505
for (AnnotationInstance instance : instances ) {
@@ -1522,7 +1537,9 @@ private AiServiceMethodCreateInfo gatherMethodMetadata(
1522
1537
Collection <Predicate <AnnotationInstance >> allowedPredicates ,
1523
1538
Collection <Predicate <AnnotationInstance >> ignoredPredicates ,
1524
1539
List <ToolMethodBuildItem > tools ,
1525
- List <ToolQualifierProvider .BuildItem > toolQualifierProviders ) {
1540
+ List <ToolQualifierProvider .BuildItem > toolQualifierProviders ,
1541
+ Predicate <MethodInfo > skipOutputFormatInstructionsPredicate ,
1542
+ Predicate <MethodInfo > fallbackToDummyUserMessagePredicate ) {
1526
1543
validateReturnType (method );
1527
1544
1528
1545
boolean requiresModeration = method .hasAnnotation (LangChain4jDotNames .MODERATE );
@@ -1532,15 +1549,17 @@ private AiServiceMethodCreateInfo gatherMethodMetadata(
1532
1549
1533
1550
// TODO give user ability to provide custom OutputParser
1534
1551
String outputFormatInstructions = "" ;
1535
- Optional <JsonSchema > structuredOutputSchema = Optional .empty ();
1536
- if (!returnType .equals (Multi .class )) {
1537
- outputFormatInstructions = SERVICE_OUTPUT_PARSER .outputFormatInstructions (returnType );
1552
+ if (!skipOutputFormatInstructionsPredicate .test (method )) {
1553
+ Optional <JsonSchema > structuredOutputSchema = Optional .empty ();
1554
+ if (!returnType .equals (Multi .class )) {
1555
+ outputFormatInstructions = SERVICE_OUTPUT_PARSER .outputFormatInstructions (returnType );
1556
+ }
1538
1557
}
1539
1558
1540
1559
List <TemplateParameterInfo > templateParams = gatherTemplateParamInfo (params , allowedPredicates , ignoredPredicates );
1541
1560
Optional <AiServiceMethodCreateInfo .TemplateInfo > systemMessageInfo = gatherSystemMessageInfo (method , templateParams );
1542
1561
AiServiceMethodCreateInfo .UserMessageInfo userMessageInfo = gatherUserMessageInfo (method , templateParams ,
1543
- systemMessageInfo );
1562
+ systemMessageInfo , fallbackToDummyUserMessagePredicate );
1544
1563
1545
1564
AiServiceMethodCreateInfo .ResponseSchemaInfo responseSchemaInfo = ResponseSchemaInfo .of (generateResponseSchema ,
1546
1565
systemMessageInfo ,
@@ -1797,7 +1816,8 @@ private Optional<Integer> gatherOverrideChatModelParameterPosition(MethodInfo me
1797
1816
1798
1817
private AiServiceMethodCreateInfo .UserMessageInfo gatherUserMessageInfo (MethodInfo method ,
1799
1818
List <TemplateParameterInfo > templateParams ,
1800
- Optional <AiServiceMethodCreateInfo .TemplateInfo > systemMessageInfo ) {
1819
+ Optional <AiServiceMethodCreateInfo .TemplateInfo > systemMessageInfo ,
1820
+ Predicate <MethodInfo > fallbackToDummyUserMesage ) {
1801
1821
1802
1822
Optional <Integer > userNameParamPosition = method .annotations (LangChain4jDotNames .USER_NAME ).stream ().filter (
1803
1823
IS_METHOD_PARAMETER_ANNOTATION ).map (METHOD_PARAMETER_POSITION_FUNCTION ).findFirst ();
@@ -1874,6 +1894,14 @@ private AiServiceMethodCreateInfo.UserMessageInfo gatherUserMessageInfo(MethodIn
1874
1894
return AiServiceMethodCreateInfo .UserMessageInfo .fromMethodParam (0 , userNameParamPosition ,
1875
1895
imageParamPosition , audioParamPosition , pdfParamPosition );
1876
1896
}
1897
+
1898
+ if (fallbackToDummyUserMesage .test (method )) {
1899
+ return AiServiceMethodCreateInfo .UserMessageInfo .fromTemplate (
1900
+ AiServiceMethodCreateInfo .TemplateInfo .fromText ("" , Map .of ()), Optional .empty (),
1901
+ Optional .empty (),
1902
+ Optional .empty (), Optional .empty ());
1903
+ }
1904
+
1877
1905
throw illegalConfigurationForMethod (
1878
1906
"For methods with multiple parameters, each parameter must be annotated with @V (or match an template parameter by name), @UserMessage, @UserName or @MemoryId" ,
1879
1907
method );
@@ -2128,8 +2156,7 @@ private List<String> gatherMethodToolClassNames(MethodInfo method) {
2128
2156
}
2129
2157
2130
2158
private List <String > gatherMethodMcpClientNames (MethodInfo method ) {
2131
- // Using the class name to keep the McpToolBox annotation in the mcp module
2132
- AnnotationInstance mcpToolBoxInstance = method .declaredAnnotation ("io.quarkiverse.langchain4j.mcp.runtime.McpToolBox" );
2159
+ AnnotationInstance mcpToolBoxInstance = method .declaredAnnotation (DotNames .MCP_TOOLBOX );
2133
2160
if (mcpToolBoxInstance == null ) {
2134
2161
return null ;
2135
2162
}
0 commit comments