diff --git a/src/fabledassistant/services/generation_task.py b/src/fabledassistant/services/generation_task.py index d3e90dd..6808101 100644 --- a/src/fabledassistant/services/generation_task.py +++ b/src/fabledassistant/services/generation_task.py @@ -410,18 +410,20 @@ async def run_generation( buf.append_event("status", {"status": "Generating response..." if _round == 0 else "Composing response..."}) t_stream = time.monotonic() - round_content_start = len(buf.content_so_far) - round_tokens_start = timing.get("output_tokens") or 0 - round_prompt_tokens_start = timing.get("prompt_tokens") or 0 approx_msg_chars = sum(len(str(m.get("content", ""))) for m in messages) effective_think = think retried_with_think = False - logger.info( - "CTX_DIAG round_start conv=%d round=%d num_ctx=%d msgs=%d approx_chars=%d think=%s", - conv_id, _round, num_ctx, len(messages), approx_msg_chars, effective_think, - ) + attempt = 0 while True: + attempt_content_start = len(buf.content_so_far) + attempt_output_tokens_start = timing.get("output_tokens") or 0 + attempt_prompt_tokens_start = timing.get("prompt_tokens") or 0 + attempt_tool_calls_start = len(round_tool_calls) + logger.info( + "CTX_DIAG attempt_start conv=%d round=%d attempt=%d num_ctx=%d msgs=%d approx_chars=%d think=%s", + conv_id, _round, attempt, num_ctx, len(messages), approx_msg_chars, effective_think, + ) async for chunk in _stream_with_retry(messages, model, tools, effective_think, num_ctx=num_ctx): if buf.cancel_event.is_set(): cancelled = True @@ -523,24 +525,23 @@ async def run_generation( if cancelled: break - round_content_added = len(buf.content_so_far) - round_content_start - round_tokens_added = (timing.get("output_tokens") or 0) - round_tokens_start - round_prompt_tokens = (timing.get("prompt_tokens") or 0) - round_prompt_tokens_start - headroom = num_ctx - round_prompt_tokens if round_prompt_tokens else None + attempt_content_added = len(buf.content_so_far) - attempt_content_start + attempt_tokens_added = (timing.get("output_tokens") or 0) - attempt_output_tokens_start + attempt_prompt_tokens = (timing.get("prompt_tokens") or 0) - attempt_prompt_tokens_start + attempt_tool_calls_added = len(round_tool_calls) - attempt_tool_calls_start + headroom = num_ctx - attempt_prompt_tokens if attempt_prompt_tokens else None is_silent = ( - not round_tool_calls - and round_content_added == 0 - and round_tokens_added > 0 + attempt_tool_calls_added == 0 + and attempt_content_added == 0 + and attempt_tokens_added > 0 ) logger.info( - "CTX_DIAG round_end conv=%d round=%d think=%s prompt_tokens=%d output_tokens=%d headroom=%s content_added=%d tool_calls=%d silent=%s", - conv_id, _round, effective_think, round_prompt_tokens, round_tokens_added, - headroom, round_content_added, len(round_tool_calls), is_silent, + "CTX_DIAG attempt_end conv=%d round=%d attempt=%d think=%s prompt_tokens=%d output_tokens=%d headroom=%s content_added=%d tool_calls=%d silent=%s", + conv_id, _round, attempt, effective_think, attempt_prompt_tokens, attempt_tokens_added, + headroom, attempt_content_added, attempt_tool_calls_added, is_silent, ) if ( - not round_tool_calls - and round_content_added == 0 - and round_tokens_added > 0 + is_silent and not effective_think and not retried_with_think ): @@ -549,11 +550,12 @@ async def run_generation( # think=True — reasoning mode produces more reliable output. logger.warning( "Silent round %d for conv %d (tokens=%d); retrying with think=True", - _round, conv_id, round_tokens_added, + _round, conv_id, attempt_tokens_added, ) buf.append_event("status", {"status": "Retrying with reasoning enabled..."}) effective_think = True retried_with_think = True + attempt += 1 continue break