@@ -54,6 +54,9 @@ public class ChatAgent extends BaseEnterpriseAgent {
5454 private volatile boolean paused = false ;
5555 private final Object pauseLock = new Object ();
5656 private Thread workerThread ;
57+
58+ /** Maximum number of consecutive conversational-only responses before waiting for user input */
59+ private static final int MAX_CONSECUTIVE_CONVERSATIONAL = 5 ;
5760
5861 private AgentExecution agentExecution ;
5962
@@ -169,11 +172,15 @@ public void onApplicationEvent(final ApplicationReadyEvent event) {
169172 }
170173 PromptBuilder promptBuilder = new PromptBuilder (verbRegistry , config );
171174 var prompt = promptBuilder .buildPrompt (false );
175+ // Check if this is an autonomous agent
176+ boolean isAutonomous = null != agentConfigOptions .getType () &&
177+ agentConfigOptions .getType ().equalsIgnoreCase ("chat-autonomous" );
178+
172179 try {
173- if (null != agentConfigOptions . getType () && agentConfigOptions . getType (). equalsIgnoreCase ( "chat" +
174- "- autonomous" )) {
175-
176- response = chatVerbs . promptAgent ( agentExecution , agentExecutionContext , prompt );
180+ if (isAutonomous ) {
181+ // Pass isAutonomous=true to get autonomous-mode prompting
182+ response = chatVerbs . promptAgent ( agentExecution , agentExecutionContext , prompt ,
183+ new ArrayList <>(), "idle" , true );
177184 }
178185 } catch (ZtatException e ) {
179186 throw new RuntimeException (e );
@@ -182,18 +189,25 @@ public void onApplicationEvent(final ApplicationReadyEvent event) {
182189 }
183190
184191
185- if (null != agentConfigOptions . getType () && agentConfigOptions . getType (). equalsIgnoreCase ( "chat-autonomous" ) && response == null ) {
192+ if (isAutonomous && response == null ) {
186193 log .error ("Chat autonomous agent mode enabled but no response received from promptAgent, shutting down..." );
187194 throw new RuntimeException ("Chat autonomous agent mode enabled but no response received from promptAgent" );
188195 }
189196 VerbResponse lastVerbResponse = null ;
190197 LLMResponse nextResponse = null ;
191198 List <VerbResponse > verbResponses = new ArrayList <>();
199+
200+ // Track executed operations across the session for plan state awareness
201+ List <String > executedOperations = new ArrayList <>();
202+ String currentPlanStatus = "idle" ;
203+
204+ // Track consecutive conversational-only responses to prevent infinite loops
205+ int consecutiveConversationalResponses = 0 ;
206+
192207 while (running ) {
193208
194209 // Check if agent is paused if autonomous mode
195- if (null != agentConfigOptions .getType () && agentConfigOptions .getType ().equalsIgnoreCase ("chat" +
196- "-autonomous" )) {
210+ if (isAutonomous ) {
197211 synchronized (pauseLock ) {
198212 while (paused ) {
199213 try {
@@ -213,14 +227,14 @@ public void onApplicationEvent(final ApplicationReadyEvent event) {
213227
214228 Thread .sleep (5_000 );
215229 agentClientService .heartbeat (agentExecution , agentExecution .getUser ().getUsername ());
216- if (null != agentConfigOptions .getType () && agentConfigOptions .getType ().equalsIgnoreCase ("chat" +
217- "-autonomous" )) {
230+ if (isAutonomous ) {
218231 log .info ("Chat autonomous agent mode enabled, executing workload..." );
219232 VerbResponse priorResponse = null ;
220233 Map <String , Object > args = new HashMap <>();
221234
222- var arguments = response . getArguments ();
235+
223236 if (null != response ) {
237+ var arguments = response .getArguments ();
224238 // Handle memory lookup if specified
225239 if (response .getMemoryLookup () != null && !response .getMemoryLookup ().isEmpty ()) {
226240 log .info ("Memory lookup requested: {}" , response .getMemoryLookup ());
@@ -263,7 +277,10 @@ public void onApplicationEvent(final ApplicationReadyEvent event) {
263277 }
264278 }
265279
266- if (response .getNextOperation () != null && !response .getNextOperation ().isEmpty ()) {
280+ // Check if the response requires execution or is purely conversational
281+ if (response .requiresExecution ()) {
282+ currentPlanStatus = "in_progress" ;
283+
267284 var executionResponse = verbRegistry .execute (
268285 agentExecution ,
269286 agentExecutionContext ,
@@ -272,6 +289,11 @@ public void onApplicationEvent(final ApplicationReadyEvent event) {
272289 );
273290 verbResponses .add (executionResponse );
274291 lastVerbResponse = executionResponse ;
292+
293+ // Track the executed operation
294+ if (!executedOperations .contains (response .getNextOperation ())) {
295+ executedOperations .add (response .getNextOperation ());
296+ }
275297
276298 var responses = agentExecutionContext .getAgentDataList ();
277299 var planResponse =
@@ -285,12 +307,32 @@ public void onApplicationEvent(final ApplicationReadyEvent event) {
285307 }
286308 }
287309 log .info ("Plan response: {} from {}" , planResponse , responses );
310+
311+ // Use the enhanced interpret_plan_response with executed operations tracking
288312 nextResponse = chatVerbs .interpret_plan_response (
289313 agentExecution ,
290314 agentExecutionContext ,
291315 verbRegistry .getVerbs ().get (response .getNextOperation ()),
292- planResponse
316+ planResponse ,
317+ executedOperations ,
318+ currentPlanStatus ,
319+ isAutonomous
293320 );
321+
322+ // Update plan status from response
323+ if (nextResponse .getPlanStatus () != null ) {
324+ currentPlanStatus = nextResponse .getPlanStatus ();
325+ }
326+
327+ // Merge executed operations from response
328+ if (nextResponse .getExecutedOperations () != null ) {
329+ for (String op : nextResponse .getExecutedOperations ()) {
330+ if (!executedOperations .contains (op )) {
331+ executedOperations .add (op );
332+ }
333+ }
334+ }
335+
294336 agentExecutionContext .addToPersistentMemory (
295337 "agent_response_" + System .currentTimeMillis (),
296338 nextResponse .getResponseForUser (),
@@ -337,10 +379,33 @@ public void onApplicationEvent(final ApplicationReadyEvent event) {
337379
338380
339381 response = nextResponse ;
382+ // Reset consecutive conversational counter on successful execution
383+ consecutiveConversationalResponses = 0 ;
384+ } else {
385+ // Response is conversational only - no execution needed
386+ consecutiveConversationalResponses ++;
387+ log .info ("Response is conversational only (count: {}), no execution needed. Plan status: {}" ,
388+ consecutiveConversationalResponses , response .getPlanStatus ());
389+ currentPlanStatus = response .getPlanStatus () != null ? response .getPlanStatus () : "idle" ;
390+
391+ // Check if we've exceeded the maximum consecutive conversational responses
392+ if (consecutiveConversationalResponses >= MAX_CONSECUTIVE_CONVERSATIONAL ) {
393+ log .info ("Maximum consecutive conversational responses ({}) reached. Agent will wait for new user input." ,
394+ MAX_CONSECUTIVE_CONVERSATIONAL );
395+ // Reset counter and set response to null to trigger fresh prompt on next iteration
396+ consecutiveConversationalResponses = 0 ;
397+ response = null ;
398+ } else {
399+ // Re-prompt for next action with current plan state
400+ response = chatVerbs .promptAgent (agentExecution , agentExecutionContext , prompt ,
401+ executedOperations , currentPlanStatus , isAutonomous );
402+ }
340403 }
341404
342405 }else {
343- response = chatVerbs .promptAgent (agentExecution , agentExecutionContext , prompt );
406+ response = chatVerbs .promptAgent (agentExecution , agentExecutionContext , prompt ,
407+ executedOperations , currentPlanStatus , isAutonomous );
408+ consecutiveConversationalResponses = 0 ;
344409
345410 }
346411
0 commit comments