1
1
package io .arconia .ai .core .tools .method ;
2
2
3
3
import java .lang .reflect .Method ;
4
- import java .lang .reflect .Modifier ;
5
4
import java .util .Arrays ;
6
5
import java .util .List ;
7
6
import java .util .function .Consumer ;
12
11
13
12
import org .slf4j .Logger ;
14
13
import org .slf4j .LoggerFactory ;
15
- import org .springframework .lang .Nullable ;
16
14
import org .springframework .util .Assert ;
17
15
import org .springframework .util .ClassUtils ;
18
16
import org .springframework .util .ReflectionUtils ;
@@ -31,115 +29,72 @@ public class MethodToolCallbackProvider implements ToolCallbackProvider {
31
29
32
30
private static final Logger logger = LoggerFactory .getLogger (MethodToolCallbackProvider .class );
33
31
34
- @ Nullable
35
- private final List <Object > sourceObjects ;
32
+ private final List <Object > toolObjects ;
36
33
37
- @ Nullable
38
- private final List <Class <?>> sourceTypes ;
39
-
40
- private MethodToolCallbackProvider (@ Nullable List <Object > sourceObjects , @ Nullable List <Class <?>> sourceTypes ) {
41
- Assert .isTrue (sourceObjects != null || sourceTypes != null , "sourceObjects or sourceTypes cannot be null" );
42
- if (sourceObjects != null ) {
43
- Assert .noNullElements (sourceObjects , "sourceObjects cannot contain null elements" );
44
- }
45
- if (sourceTypes != null ) {
46
- Assert .noNullElements (sourceTypes , "sourceTypes cannot contain null elements" );
47
- }
48
- this .sourceObjects = sourceObjects ;
49
- this .sourceTypes = sourceTypes ;
34
+ private MethodToolCallbackProvider (List <Object > toolObjects ) {
35
+ Assert .notNull (toolObjects , "toolObjects cannot be null" );
36
+ Assert .noNullElements (toolObjects , "toolObjects cannot contain null elements" );
37
+ this .toolObjects = toolObjects ;
50
38
}
51
39
52
40
@ Override
53
41
public ToolCallback [] getToolCallbacks () {
54
- if (sourceObjects != null ) {
55
- return getToolCallbacksFromObjects ();
56
- }
57
- return getToolCallbacksFromTypes ();
58
- }
59
-
60
- private ToolCallback [] getToolCallbacksFromObjects () {
61
- var toolCallbacks = sourceObjects .stream ()
62
- .map (sourceObject -> getDeclaredMethodsWithToolAnnotation (sourceObject .getClass ())
63
- .map (method -> MethodToolCallback .builder ()
64
- .toolMetadata (ToolMetadata .from (method ))
65
- .toolMethod (method )
66
- .toolObject (sourceObject )
67
- .build ())
68
- .toArray (ToolCallback []::new ))
69
- .flatMap (Stream ::of )
70
- .toArray (ToolCallback []::new );
71
-
72
- if (ToolUtils .hasDuplicateToolNames (toolCallbacks )) {
73
- throw new IllegalStateException ("Multiple tools with the same name found in sources: "
74
- + sourceObjects .stream ().map (o -> o .getClass ().getName ()).collect (Collectors .joining (", " )));
75
- }
76
-
77
- return toolCallbacks ;
78
- }
79
-
80
- private ToolCallback [] getToolCallbacksFromTypes () {
81
- var toolCallbacks = sourceTypes .stream ()
82
- .map (sourceType -> getDeclaredMethodsWithToolAnnotation (sourceType )
83
- .filter (method -> Modifier .isStatic (method .getModifiers ()))
84
- .map (method -> MethodToolCallback .builder ()
85
- .toolMetadata (ToolMetadata .from (method ))
86
- .toolMethod (method )
42
+ var toolCallbacks = toolObjects .stream ()
43
+ .map (toolObject -> Stream .of (ReflectionUtils .getDeclaredMethods (toolObject .getClass ()))
44
+ .filter (toolMethod -> toolMethod .isAnnotationPresent (Tool .class ))
45
+ .filter (toolMethod -> !isFunctionalType (toolMethod ))
46
+ .map (toolMethod -> MethodToolCallback .builder ()
47
+ .toolMetadata (ToolMetadata .from (toolMethod ))
48
+ .toolMethod (toolMethod )
49
+ .toolObject (toolObject )
87
50
.build ())
88
51
.toArray (ToolCallback []::new ))
89
52
.flatMap (Stream ::of )
90
53
.toArray (ToolCallback []::new );
91
54
92
- if (ToolUtils .hasDuplicateToolNames (toolCallbacks )) {
93
- throw new IllegalStateException ("Multiple tools with the same name found in sources: "
94
- + sourceTypes .stream ().map (Class ::getName ).collect (Collectors .joining (", " )));
95
- }
55
+ validateToolCallbacks (toolCallbacks );
96
56
97
57
return toolCallbacks ;
98
58
}
99
59
100
- private Stream <Method > getDeclaredMethodsWithToolAnnotation (Class <?> sourceType ) {
101
- return Stream .of (ReflectionUtils .getDeclaredMethods (sourceType ))
102
- .filter (method -> method .isAnnotationPresent (Tool .class ))
103
- .filter (method -> !isFunctionalType (method ));
104
- }
105
-
106
- private static boolean isFunctionalType (Method method ) {
107
- var isFunction = ClassUtils .isAssignable (method .getReturnType (), Function .class )
108
- || ClassUtils .isAssignable (method .getReturnType (), Supplier .class )
109
- || ClassUtils .isAssignable (method .getReturnType (), Consumer .class );
60
+ private static boolean isFunctionalType (Method toolMethod ) {
61
+ var isFunction = ClassUtils .isAssignable (toolMethod .getReturnType (), Function .class )
62
+ || ClassUtils .isAssignable (toolMethod .getReturnType (), Supplier .class )
63
+ || ClassUtils .isAssignable (toolMethod .getReturnType (), Consumer .class );
110
64
111
65
if (isFunction ) {
112
66
logger .warn ("Method {} is annotated with @Tool but returns a functional type. "
113
- + "This is not supported and the method will be ignored." , method .getName ());
67
+ + "This is not supported and the method will be ignored." , toolMethod .getName ());
114
68
}
115
69
116
70
return isFunction ;
117
71
}
118
72
73
+ private void validateToolCallbacks (ToolCallback [] toolCallbacks ) {
74
+ List <String > duplicateToolNames = ToolUtils .getDuplicateToolNames (toolCallbacks );
75
+ if (!duplicateToolNames .isEmpty ()) {
76
+ throw new IllegalStateException ("Multiple tools with the same name (%s) found in sources: %s" .formatted (
77
+ String .join (", " , duplicateToolNames ),
78
+ toolObjects .stream ().map (o -> o .getClass ().getName ()).collect (Collectors .joining (", " ))));
79
+ }
80
+ }
81
+
119
82
public static Builder builder () {
120
83
return new Builder ();
121
84
}
122
85
123
86
public static class Builder {
124
87
125
- private List <Object > sourceObjects ;
126
-
127
- private List <Class <?>> sourceTypes ;
128
-
129
- public Builder sources (Object ... sourceObjects ) {
130
- Assert .isNull (this .sourceTypes , "only one of sourceObjects or sourceTypes can be set" );
131
- this .sourceObjects = Arrays .asList (sourceObjects );
132
- return this ;
133
- }
88
+ private List <Object > toolObjects ;
134
89
135
- public Builder sources ( Class <?> ... sourceTypes ) {
136
- Assert .isNull ( this . sourceObjects , "only one of sourceObjects or sourceTypes can be set " );
137
- this .sourceTypes = Arrays .asList (sourceTypes );
90
+ public Builder toolObjects ( Object ... toolObjects ) {
91
+ Assert .notNull ( toolObjects , "toolObjects cannot be null " );
92
+ this .toolObjects = Arrays .asList (toolObjects );
138
93
return this ;
139
94
}
140
95
141
96
public MethodToolCallbackProvider build () {
142
- return new MethodToolCallbackProvider (sourceObjects , sourceTypes );
97
+ return new MethodToolCallbackProvider (toolObjects );
143
98
}
144
99
145
100
}
0 commit comments