3434import org .apache .flink .api .common .typeinfo .TypeInformation ;
3535import org .apache .flink .api .java .functions .KeySelector ;
3636import org .apache .flink .api .java .typeutils .RowTypeInfo ;
37+ import org .apache .flink .streaming .api .datastream .DataStream ;
3738import org .apache .flink .streaming .api .environment .StreamExecutionEnvironment ;
3839import org .apache .flink .table .api .DataTypes ;
3940import org .apache .flink .table .api .Schema ;
4647import org .junit .jupiter .api .Test ;
4748
4849import java .io .IOException ;
50+ import java .util .ArrayList ;
4951import java .util .List ;
5052
5153import static org .apache .flink .agents .api .agents .AgentExecutionOptions .ERROR_HANDLING_STRATEGY ;
@@ -114,7 +116,7 @@ public void testReActAgent() throws Exception {
114116 agentsEnv .getConfig ().set (MAX_RETRIES , 3 );
115117
116118 // Declare the ReAct agent.
117- Agent agent = getAgent ();
119+ Agent agent = getAgent (true );
118120
119121 // Create input table from sample data
120122 Table inputTable =
@@ -152,8 +154,74 @@ public void testReActAgent() throws Exception {
152154 checkResult (results );
153155 }
154156
155- // create ReAct agent.
156- private static Agent getAgent () {
157+ @ Test
158+ public void testReActAgentNoOutputSchema () throws Exception {
159+ Assumptions .assumeTrue (ollamaReady , String .format ("%s is not ready" , OLLAMA_MODEL ));
160+ StreamExecutionEnvironment env = StreamExecutionEnvironment .getExecutionEnvironment ();
161+ env .setParallelism (1 );
162+
163+ // Create the table environment
164+ StreamTableEnvironment tableEnv = StreamTableEnvironment .create (env );
165+ tableEnv .getConfig ().set ("table.exec.result.display.max-column-width" , "100" );
166+
167+ // Create agents execution environment
168+ AgentsExecutionEnvironment agentsEnv =
169+ AgentsExecutionEnvironment .getExecutionEnvironment (env , tableEnv );
170+
171+ // register resource to agents execution environment.
172+ agentsEnv
173+ .addResource (
174+ "ollama" ,
175+ ResourceType .CHAT_MODEL_CONNECTION ,
176+ ResourceDescriptor .Builder .newBuilder (
177+ ResourceName .ChatModel .OLLAMA_CONNECTION )
178+ .addInitialArgument ("endpoint" , "http://localhost:11434" )
179+ .addInitialArgument ("requestTimeout" , 240 )
180+ .build ())
181+ .addResource (
182+ "add" ,
183+ ResourceType .TOOL ,
184+ Tool .fromMethod (
185+ ReActAgentTest .class .getMethod ("add" , Double .class , Double .class )))
186+ .addResource (
187+ "multiply" ,
188+ ResourceType .TOOL ,
189+ Tool .fromMethod (
190+ ReActAgentTest .class .getMethod (
191+ "multiply" , Double .class , Double .class )));
192+
193+ agentsEnv .getConfig ().set (ERROR_HANDLING_STRATEGY , ReActAgent .ErrorHandlingStrategy .RETRY );
194+ agentsEnv .getConfig ().set (MAX_RETRIES , 3 );
195+
196+ // Declare the ReAct agent without an output schema.
197+ Agent agent = getAgent (false );
198+
199+ // Create input table from sample data
200+ Table inputTable =
201+ tableEnv .fromValues (
202+ DataTypes .ROW (
203+ DataTypes .FIELD ("a" , DataTypes .DOUBLE ()),
204+ DataTypes .FIELD ("b" , DataTypes .DOUBLE ()),
205+ DataTypes .FIELD ("c" , DataTypes .DOUBLE ())),
206+ Row .of (2131 , 29847 , 3 ));
207+
208+ // Apply agent to the Table; without an output schema the result is a string.
209+ DataStream <Object > out =
210+ agentsEnv
211+ .fromTable (
212+ inputTable ,
213+ (KeySelector <Object , Double >)
214+ value -> (Double ) ((Row ) value ).getField ("a" ))
215+ .apply (agent )
216+ .toDataStream ();
217+
218+ out .print ();
219+
220+ env .execute ();
221+ }
222+
223+ // create ReAct agent; pass false to skip the output schema.
224+ private static Agent getAgent (boolean withSchema ) {
157225 ResourceDescriptor chatModelDescriptor =
158226 ResourceDescriptor .Builder .newBuilder (ResourceName .ChatModel .OLLAMA_SETUP )
159227 .addInitialArgument ("connection" , "ollama" )
@@ -162,21 +230,24 @@ private static Agent getAgent() {
162230 .addInitialArgument ("extract_reasoning" , true )
163231 .build ();
164232
165- Prompt prompt =
166- Prompt .fromMessages (
167- List .of (
168- new ChatMessage (
169- MessageRole .SYSTEM ,
170- "Must call function tool to do the calculate." ),
171- new ChatMessage (
172- MessageRole .SYSTEM ,
173- "An example of output is {\" result\" : 30.32}" ),
174- new ChatMessage (MessageRole .USER , "What is ({a} + {b}) * {c}." )));
233+ List <ChatMessage > messages = new ArrayList <>();
234+ messages .add (
235+ new ChatMessage (
236+ MessageRole .SYSTEM , "Must call function tool to do the calculate." ));
237+ if (withSchema ) {
238+ messages .add (
239+ new ChatMessage (
240+ MessageRole .SYSTEM , "An example of output is {\" result\" : 30.32}" ));
241+ }
242+ messages .add (new ChatMessage (MessageRole .USER , "What is ({a} + {b}) * {c}." ));
243+
175244 RowTypeInfo outputTypeInfo =
176- new RowTypeInfo (
177- new TypeInformation [] {BasicTypeInfo .DOUBLE_TYPE_INFO },
178- new String [] {"result" });
179- return new ReActAgent (chatModelDescriptor , prompt , outputTypeInfo );
245+ withSchema
246+ ? new RowTypeInfo (
247+ new TypeInformation [] {BasicTypeInfo .DOUBLE_TYPE_INFO },
248+ new String [] {"result" })
249+ : null ;
250+ return new ReActAgent (chatModelDescriptor , Prompt .fromMessages (messages ), outputTypeInfo );
180251 }
181252
182253 private void checkResult (CloseableIterator <?> results ) {
0 commit comments