2828)
2929from astrbot .core .provider .entities import (
3030 LLMResponse ,
31- LLM_CONTROL_CODE_EMPTY_COMPLETION_RETRY ,
3231 LLM_CONTROL_CODE_UNKNOWN_TOOL_CALL ,
3332 ProviderRequest ,
3433 ToolCallsResult ,
@@ -88,10 +87,6 @@ def _get_persona_custom_error_message(self) -> str | None:
8887 event = getattr (self .run_context .context , "event" , None )
8988 return extract_persona_custom_error_message_from_event (event )
9089
91- @staticmethod
92- def _is_empty_completion_retry (resp : LLMResponse ) -> bool :
93- return resp .control_code == LLM_CONTROL_CODE_EMPTY_COMPLETION_RETRY
94-
9590 @staticmethod
9691 def _is_unknown_tool_call (resp : LLMResponse ) -> bool :
9792 return resp .control_code == LLM_CONTROL_CODE_UNKNOWN_TOOL_CALL
@@ -257,24 +252,6 @@ async def _iter_llm_responses_with_fallback(
257252 yield resp
258253 continue
259254
260- if self ._is_empty_completion_retry (resp ):
261- # Empty/unparseable response from model, retry same provider once
262- logger .warning (
263- "Chat Model %s returned empty/unparseable completion, retrying once..." ,
264- candidate_id ,
265- )
266- try :
267- async for retry_resp in self ._iter_llm_responses (include_model = idx == 0 ):
268- if retry_resp .is_chunk :
269- yield retry_resp
270- continue
271- yield retry_resp
272- return
273- except Exception as retry_exc :
274- logger .warning ("Retry also failed: %s" , retry_exc )
275- last_exception = retry_exc
276- break
277-
278255 if (
279256 resp .role == "err"
280257 and not has_stream_output
@@ -294,80 +271,6 @@ async def _iter_llm_responses_with_fallback(
294271 return
295272 except Exception as exc : # noqa: BLE001
296273 last_exception = exc
297- _exc_str = str (exc ).lower ()
298- # Auto-compress context when model_max_prompt_tokens_exceeded
299- if (
300- "model_max_prompt_tokens_exceeded" in _exc_str
301- or "prompt token count" in _exc_str
302- or "tokens_exceeded" in _exc_str
303- or "context_length_exceeded" in _exc_str
304- or ("token" in _exc_str and "exceed" in _exc_str )
305- ):
306- logger .warning (
307- "Chat Model %s: token limit exceeded, forcing context compression and retrying..." ,
308- candidate_id ,
309- )
310- try :
311- from astrbot .core .agent .context .truncator import ContextTruncator
312- _truncator = ContextTruncator ()
313- _before_total = len (self .run_context .messages )
314- # Aggressively halve until small enough (up to 5 rounds)
315- _compression_success = False
316- for _halve_round in range (5 ):
317- _before = len (self .run_context .messages )
318- self .run_context .messages = _truncator .truncate_by_halving (
319- self .run_context .messages
320- )
321- _after = len (self .run_context .messages )
322- logger .info (
323- "Forced context truncation round %d: %d -> %d messages." ,
324- _halve_round + 1 , _before , _after ,
325- )
326- if _after <= 4 :
327- break # Can't shrink further
328- # Retry same candidate
329- try :
330- async for resp in self ._iter_llm_responses (include_model = idx == 0 ):
331- if resp .is_chunk :
332- has_stream_output = True
333- yield resp
334- continue
335- yield resp
336- logger .info (
337- "Context truncation succeeded after %d round(s): %d -> %d messages." ,
338- _halve_round + 1 , _before_total , _after ,
339- )
340- _compression_success = True
341- return
342- if has_stream_output :
343- _compression_success = True
344- return
345- _compression_success = True
346- break # succeeded without stream output
347- except Exception as retry_exc :
348- _exc_str2 = str (retry_exc ).lower ()
349- if not (
350- "model_max_prompt_tokens_exceeded" in _exc_str2
351- or "prompt token count" in _exc_str2
352- or "tokens_exceeded" in _exc_str2
353- or "context_length_exceeded" in _exc_str2
354- or ("token" in _exc_str2 and "exceed" in _exc_str2 )
355- ):
356- last_exception = retry_exc
357- logger .warning (
358- "Chat Model %s retry after compression failed: %s" ,
359- candidate_id , retry_exc ,
360- )
361- break
362- last_exception = retry_exc
363- logger .warning (
364- "Chat Model %s still token-exceeded after round %d, halving again..." ,
365- candidate_id , _halve_round + 1 ,
366- )
367- continue
368- except Exception as compress_exc :
369- logger .error ("Failed to compress context: %s" , compress_exc )
370- continue
371274 logger .warning (
372275 "Chat Model %s request error: %s" ,
373276 candidate_id ,
@@ -404,15 +307,21 @@ def follow_up(
404307 * ,
405308 message_text : str ,
406309 ) -> FollowUpTicket | None :
407- """Queue a follow-up message for the next tool result."""
310+ """Queue a follow-up message to be injected into the next tool result.
311+
312+ Returns None if the agent is already done (message arrived too late) or
313+ if the message text is empty.
314+ """
408315 if self .done ():
316+ logger .debug ("follow_up: agent already done, message discarded." )
409317 return None
410318 text = (message_text or "" ).strip ()
411319 if not text :
412320 return None
413321 ticket = FollowUpTicket (seq = self ._follow_up_seq , text = text )
414322 self ._follow_up_seq += 1
415323 self ._pending_follow_ups .append (ticket )
324+ logger .debug ("follow_up: queued ticket seq=%d, pending=%d" , ticket .seq , len (self ._pending_follow_ups ))
416325 return ticket
417326
418327 def _resolve_unconsumed_follow_ups (self ) -> None :
@@ -431,15 +340,16 @@ def _consume_follow_up_notice(self) -> str:
431340 for ticket in follow_ups :
432341 ticket .consumed = True
433342 ticket .resolved .set ()
343+
434344 follow_up_lines = "\n " .join (
435345 f"{ idx } . { ticket .text } " for idx , ticket in enumerate (follow_ups , start = 1 )
436346 )
347+ count = len (follow_ups )
348+ plural = "messages" if count > 1 else "message"
437349 return (
438- "\n \n [FOLLOW-UP] The user sent additional message(s) while you were working. "
439- "Treat these as supplementary instructions for the current task — DO NOT stop "
440- "or restart the current operation. Instead, seamlessly incorporate them into "
441- "your ongoing work. Continue the task flow without interrupting it. "
442- "Do NOT acknowledge receipt explicitly; just act on them naturally.\n "
350+ f"\n \n [FOLLOW-UP x{ count } ] The user sent { count } { plural } while you were working. "
351+ "Incorporate them as supplementary instructions seamlessly — "
352+ "do NOT stop, restart, or explicitly acknowledge receipt; just act naturally.\n "
443353 f"{ follow_up_lines } "
444354 )
445355
@@ -778,7 +688,7 @@ async def step_until_done(
778688 self .run_context .messages .append (
779689 Message (
780690 role = "user" ,
781- content = "工具调用次数已达到上限,请停止使用工具,并根据已经收集到的信息,对你的任务和发现进行总结,然后直接回复用户。" ,
691+ content = "工具调用次数已达到上限,请停止使用工具,并根据已经收集到的信息,对你的任务和发现进行总结,然后直接回复用户。(Tool call limit reached. Stop using tools and summarize your findings directly for the user.) " ,
782692 )
783693 )
784694 # 再执行最后一步
0 commit comments