55import asyncio
66import json
77import logging
8+ import time
89from concurrent .futures import Executor , ThreadPoolExecutor
910from datetime import datetime
1011from typing import Any , Callable , Dict , List , Optional , Tuple , Type , final
@@ -45,6 +46,7 @@ class ConversableAgent(Role, Agent):
4546 bind_prompt : Optional [PromptTemplate ] = None
4647 run_mode : Optional [AgentRunMode ] = Field (default = None , description = "Run mode" )
4748 max_retry_count : int = 3
49+ max_timeout : int = 600
4850 llm_client : Optional [AIWrapper ] = None
4951 # 确认当前Agent是否需要进行流式输出
5052 stream_out : bool = True
@@ -363,6 +365,7 @@ async def generate_reply(
363365
364366 fail_reason = None
365367 current_retry_counter = 0
368+ start_time = time .time ()
366369 is_success = True
367370 observation = received_message .content or ""
368371 while current_retry_counter < self .max_retry_count :
@@ -402,10 +405,12 @@ async def generate_reply(
402405 thinking_messages , resource_info = await self ._load_thinking_messages (
403406 received_message = received_message ,
404407 sender = sender ,
408+ observation = observation ,
405409 rely_messages = rely_messages ,
406410 historical_dialogues = historical_dialogues ,
407411 context = reply_message .get_dict_context (),
408412 is_retry_chat = is_retry_chat ,
413+ current_retry_counter = current_retry_counter ,
409414 )
410415 with root_tracer .start_span (
411416 "agent.generate_reply.thinking" ,
@@ -493,6 +498,7 @@ async def generate_reply(
493498 logger .warning ("No retry available!" )
494499 break
495500 fail_reason = reason
501+ observation = fail_reason
496502 await self .write_memories (
497503 question = question ,
498504 ai_message = ai_message ,
@@ -514,6 +520,13 @@ async def generate_reply(
514520 if self .run_mode != AgentRunMode .LOOP or act_out .terminate :
515521 logger .debug (f"Agent { self .name } reply success!{ reply_message } " )
516522 break
523+ time_cost = time .time () - start_time
524+ if time_cost > self .max_timeout :
525+ logger .warning (
526+ f"Agent { self .name } run time out!{ time_cost } > "
527+ f"{ self .max_timeout } "
528+ )
529+ break
517530
518531 # Continue to run the next round
519532 current_retry_counter += 1
@@ -1072,15 +1085,25 @@ async def _load_thinking_messages(
10721085 self ,
10731086 received_message : AgentMessage ,
10741087 sender : Agent ,
1088+ observation : Optional [str ] = None ,
10751089 rely_messages : Optional [List [AgentMessage ]] = None ,
10761090 historical_dialogues : Optional [List [AgentMessage ]] = None ,
10771091 context : Optional [Dict [str , Any ]] = None ,
10781092 is_retry_chat : bool = False ,
1093+ current_retry_counter : Optional [int ] = None ,
10791094 ) -> Tuple [List [AgentMessage ], Optional [Dict ]]:
1080- observation = received_message .content
1081- if not observation :
1095+ question = received_message .content
1096+ observation = observation or question
1097+ if not question :
10821098 raise ValueError ("The received message content is empty!" )
1099+ most_recent_memories = ""
1100+ memory_list = []
1101+ # Read the memories according to the current observation
10831102 memories = await self .read_memories (observation )
1103+ if isinstance (memories , list ):
1104+ memory_list = memories
1105+ else :
1106+ most_recent_memories = memories
10841107 has_memories = True if memories else False
10851108 reply_message_str = ""
10861109 if context is None :
@@ -1102,8 +1125,9 @@ async def _load_thinking_messages(
11021125 elif message .role == ModelMessageRoleType .AI :
11031126 reply_message_str += f"Observation: { message .content } \n "
11041127 if reply_message_str :
1105- memories += "\n " + reply_message_str
1128+ most_recent_memories += "\n " + reply_message_str
11061129 try :
1130+ # Load the resource prompt according to the current observation
11071131 resource_prompt_str , resource_references = await self .load_resource (
11081132 observation , is_retry_chat = is_retry_chat
11091133 )
@@ -1114,21 +1138,19 @@ async def _load_thinking_messages(
11141138 resource_vars = await self .generate_resource_variables (resource_prompt_str )
11151139
11161140 system_prompt = await self .build_system_prompt (
1117- question = observation ,
1118- most_recent_memories = memories ,
1141+ question = question ,
1142+ most_recent_memories = most_recent_memories ,
11191143 resource_vars = resource_vars ,
11201144 context = context ,
11211145 is_retry_chat = is_retry_chat ,
11221146 )
11231147 user_prompt = await self .build_prompt (
1124- question = observation ,
1148+ question = question ,
11251149 is_system = False ,
1126- most_recent_memories = memories ,
1150+ most_recent_memories = most_recent_memories ,
11271151 resource_vars = resource_vars ,
11281152 ** context ,
11291153 )
1130- if not user_prompt :
1131- user_prompt = f"Observation: { observation } "
11321154
11331155 agent_messages = []
11341156 if system_prompt :
@@ -1153,14 +1175,21 @@ async def _load_thinking_messages(
11531175 message .role = ModelMessageRoleType .AI
11541176 agent_messages .append (message )
11551177
1178+ if memory_list :
1179+ agent_messages .extend (memory_list )
1180+
11561181 # Current user input information
1157- agent_messages .append (
1158- AgentMessage (
1159- content = user_prompt ,
1160- role = ModelMessageRoleType .HUMAN ,
1182+ if not user_prompt and (not memory_list or not current_retry_counter ):
1183+ # The user prompt is empty, and the current retry count is 0 or the memory
1184+ # is empty
1185+ user_prompt = f"Observation: { observation } "
1186+ if user_prompt :
1187+ agent_messages .append (
1188+ AgentMessage (
1189+ content = user_prompt ,
1190+ role = ModelMessageRoleType .HUMAN ,
1191+ )
11611192 )
1162- )
1163-
11641193 return agent_messages , resource_references
11651194
11661195
0 commit comments