@@ -127,6 +127,10 @@ def __init__(
127127 self .seen_permissions : Dict [str , set ] = {}
128128 self .seen_questions : Dict [str , set ] = {}
129129
130+ # Защита от бесконечного цикла auto-continue: session_id -> count
131+ self .auto_continue_count : Dict [str , int ] = {}
132+ self .AUTO_CONTINUE_MAX = 5
133+
130134 # ---------- SSE callbacks ----------
131135
132136 def _register_sse_callbacks (self ):
@@ -375,8 +379,18 @@ async def _on_session_idle(self, event_type: str, data: dict):
375379 title = child_info .get ("title" , session_id [:12 ])
376380 await self .vk .send_message (target , f"✅ Subagent завершён: { title } " )
377381 else :
378- # Для основной сессии — тихо (последний text.ended уже отправил ответ)
379- logger .debug (f"Session idle: { session_id } " )
382+ # Для основной сессии — пытаемся продолжить работу агента (с защитой от бесконечного цикла)
383+ count = self .auto_continue_count .get (session_id , 0 )
384+ if count >= self .AUTO_CONTINUE_MAX :
385+ logger .info (f"Session idle — max auto-continue ({ self .AUTO_CONTINUE_MAX } ) reached for { session_id } , stopping" )
386+ target = THINKING_PEER_ID if THINKING_PEER_ID else user_id
387+ await self .vk .send_message (target , "✅ Агент завершил работу (достигнут лимит автопродолжений)." )
388+ return
389+ self .auto_continue_count [session_id ] = count + 1
390+ logger .info (f"Session idle — auto-continue { self .auto_continue_count [session_id ]} /{ self .AUTO_CONTINUE_MAX } for { session_id } " )
391+ target = THINKING_PEER_ID if THINKING_PEER_ID else user_id
392+ await self .vk .send_message (target , f"⏳ Агент на паузе, продолжаю… ({ self .auto_continue_count [session_id ]} /{ self .AUTO_CONTINUE_MAX } )" )
393+ await self .opencode_client .send_prompt (session_id , "Продолжи работу, выполни оставшиеся задачи из плана." )
380394
381395 async def _on_session_status (self , event_type : str , data : dict ):
382396 """Обрабатывает изменение статуса сессии (session.status)"""
@@ -441,7 +455,20 @@ async def _on_any_event(self, event_type: str, data: dict):
441455 """Логирует все SSE события для отладки"""
442456 if event_type in self ._NOISY_EVENTS :
443457 return
444- logger .debug (f"SSE event: { event_type } keys={ list (data .keys ()) if isinstance (data , dict ) else '?' } " )
458+ # Логируем важные поля с реальными значениями
459+ extra = ""
460+ if event_type .endswith (".step.ended" ) and isinstance (data , dict ):
461+ finish = data .get ("finish" , "?" )
462+ extra = f" finish={ finish } "
463+ elif event_type == "session.status" and isinstance (data , dict ):
464+ status = data .get ("status" , {})
465+ if isinstance (status , dict ):
466+ extra = f" status_type={ status .get ('type' , '?' )} status_message={ status .get ('message' , '' )} "
467+ else :
468+ extra = f" status={ status } "
469+ elif event_type == "session.idle" and isinstance (data , dict ):
470+ extra = f" sessionID={ data .get ('sessionID' , '?' )[:16 ]} "
471+ logger .debug (f"SSE event: { event_type } { extra } keys={ list (data .keys ()) if isinstance (data , dict ) else '?' } " )
445472
446473 # ---------- Обработка разрешений ----------
447474 def _format_permission_message (self , perm : dict ) -> str :
@@ -765,6 +792,9 @@ async def _handle_user_message(self, user_id: int, message: dict):
765792 # Регистрируем маппинг session -> user для маршрутизации SSE событий
766793 self .session_to_user [session_id ] = user_id
767794
795+ # Сброс счётчика автопродолжения при новом сообщении пользователя
796+ self .auto_continue_count [session_id ] = 0
797+
768798 # Обрабатываем аттачи
769799 attachment_info = ""
770800 if attachments :
@@ -846,6 +876,7 @@ async def _handle_restart_command(self, user_id: int, text: str):
846876 if old_session_id and old_session_id in self .session_to_user :
847877 del self .session_to_user [old_session_id ]
848878 self .session_to_user [new_session_id ] = user_id
879+ self .auto_continue_count [new_session_id ] = 0
849880
850881 await self .vk .send_message (user_id , f"✅ Модель { model_info } загружена" )
851882
0 commit comments