mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
refactor(copilot): extract _reduce_context helper, rename vars for clarity
Consolidate retry-setup logic into _reduce_context() to reduce indentation in the streaming loop. Rename _query_attempt → _attempt and _MAX_QUERY_ATTEMPTS → _MAX_STREAM_ATTEMPTS for clarity.
This commit is contained in:
@@ -104,7 +104,7 @@ def _mock_compress_result(
|
||||
class TestScenarioNormalFlow:
|
||||
"""When no error occurs, no retry logic fires."""
|
||||
|
||||
def test_max_query_attempts_is_three(self):
|
||||
def test_max_attempts_is_three(self):
|
||||
"""Verify the constant is 3 (compact + DB fallback + exhaustion)."""
|
||||
assert _MAX_STREAM_ATTEMPTS == 3
|
||||
|
||||
@@ -239,12 +239,12 @@ class TestScenarioNoTranscriptFallback:
|
||||
"""When transcript_content is empty, attempt 2 goes straight to DB
|
||||
fallback (the else branch in the retry logic)."""
|
||||
# This scenario verifies the state transitions:
|
||||
# _query_attempt == 1, transcript_content == "" → else branch
|
||||
# _attempt == 1, transcript_content == "" → else branch
|
||||
transcript_content = ""
|
||||
_query_attempt = 1
|
||||
_attempt = 1
|
||||
|
||||
# Simulate the retry logic decision
|
||||
if _query_attempt == 1 and transcript_content:
|
||||
if _attempt == 1 and transcript_content:
|
||||
path = "compact"
|
||||
else:
|
||||
path = "db_fallback"
|
||||
@@ -300,9 +300,9 @@ class TestScenarioDoubleFailDBFallback:
|
||||
assert validate_transcript(result)
|
||||
|
||||
# If attempt 2 also fails, attempt 3 skips compaction:
|
||||
_query_attempt = 2
|
||||
_attempt = 2
|
||||
transcript_content = result # Still set from earlier
|
||||
if _query_attempt == 1 and transcript_content:
|
||||
if _attempt == 1 and transcript_content:
|
||||
path = "compact"
|
||||
else:
|
||||
path = "db_fallback"
|
||||
@@ -322,7 +322,7 @@ class TestScenarioAllAttemptsExhausted:
|
||||
_stream_error: Exception | None = None
|
||||
transcript_caused_error = False
|
||||
|
||||
for _query_attempt in range(_MAX_STREAM_ATTEMPTS):
|
||||
for _attempt in range(_MAX_STREAM_ATTEMPTS):
|
||||
_stream_error = Exception("some error")
|
||||
|
||||
# After loop: check exhaustion
|
||||
@@ -372,7 +372,7 @@ class TestScenarioCompactionIdentical:
|
||||
transcript_content = "some transcript content"
|
||||
compacted = transcript_content # Identical!
|
||||
|
||||
# Simulate the retry decision at _query_attempt == 1
|
||||
# Simulate the retry decision at _attempt == 1
|
||||
use_compacted = (
|
||||
compacted
|
||||
and compacted != transcript_content
|
||||
@@ -464,8 +464,8 @@ class TestRetryStateMachine:
|
||||
attempts_made = 0
|
||||
_tried_compaction = False
|
||||
|
||||
for _query_attempt in range(min(_MAX_STREAM_ATTEMPTS, len(attempt_results))):
|
||||
if _query_attempt > 0:
|
||||
for _attempt in range(min(_MAX_STREAM_ATTEMPTS, len(attempt_results))):
|
||||
if _attempt > 0:
|
||||
_stream_error = None
|
||||
stream_completed = False
|
||||
|
||||
@@ -483,7 +483,7 @@ class TestRetryStateMachine:
|
||||
transcript_caused_error = True
|
||||
|
||||
attempts_made += 1
|
||||
result = attempt_results[_query_attempt]
|
||||
result = attempt_results[_attempt]
|
||||
|
||||
if result == "error":
|
||||
_stream_error = Exception("simulated error")
|
||||
|
||||
@@ -95,38 +95,43 @@ config = ChatConfig()
|
||||
_MAX_STREAM_ATTEMPTS = 3
|
||||
|
||||
|
||||
async def _retry_with_compacted_transcript(
|
||||
async def _reduce_context(
|
||||
transcript_content: str,
|
||||
tried_compaction: bool,
|
||||
session_id: str,
|
||||
sdk_cwd: str,
|
||||
log_prefix: str,
|
||||
) -> tuple[TranscriptBuilder, bool, str | None, bool]:
|
||||
"""Compact the transcript via LLM summarization and prepare for retry.
|
||||
) -> tuple[TranscriptBuilder, bool, str | None, bool, bool]:
|
||||
"""Prepare reduced context for a retry attempt.
|
||||
|
||||
Returns ``(transcript_builder, use_resume, resume_file, success)``.
|
||||
On failure, returns a fresh builder with ``use_resume=False``.
|
||||
On the first retry, compacts the transcript via LLM summarization.
|
||||
On subsequent retries (or if compaction fails), drops the transcript
|
||||
entirely so the query is rebuilt from DB messages only.
|
||||
|
||||
Returns ``(builder, use_resume, resume_file, transcript_lost, tried_compaction)``.
|
||||
``transcript_lost`` is True when the transcript was dropped (caller
|
||||
should set ``transcript_caused_error``).
|
||||
"""
|
||||
compacted = await compact_transcript(transcript_content, log_prefix=log_prefix)
|
||||
if compacted and compacted != transcript_content and validate_transcript(compacted):
|
||||
logger.info("%s Using compacted transcript for retry", log_prefix)
|
||||
tb = TranscriptBuilder()
|
||||
tb.load_previous(compacted, log_prefix=log_prefix)
|
||||
resume_file = write_transcript_to_tempfile(compacted, session_id, sdk_cwd)
|
||||
if resume_file:
|
||||
return tb, True, resume_file, True
|
||||
logger.warning("%s Failed to write compacted transcript", log_prefix)
|
||||
# First retry: try compacting
|
||||
if transcript_content and not tried_compaction:
|
||||
compacted = await compact_transcript(transcript_content, log_prefix=log_prefix)
|
||||
if (
|
||||
compacted
|
||||
and compacted != transcript_content
|
||||
and validate_transcript(compacted)
|
||||
):
|
||||
logger.info("%s Using compacted transcript for retry", log_prefix)
|
||||
tb = TranscriptBuilder()
|
||||
tb.load_previous(compacted, log_prefix=log_prefix)
|
||||
resume_file = write_transcript_to_tempfile(compacted, session_id, sdk_cwd)
|
||||
if resume_file:
|
||||
return tb, True, resume_file, False, True
|
||||
logger.warning("%s Failed to write compacted transcript", log_prefix)
|
||||
logger.warning("%s Compaction failed, dropping transcript", log_prefix)
|
||||
|
||||
logger.warning("%s Compaction failed, will fall back to DB messages", log_prefix)
|
||||
return TranscriptBuilder(), False, None, False
|
||||
|
||||
|
||||
def _retry_without_transcript(log_prefix: str) -> tuple[TranscriptBuilder, bool, None]:
|
||||
"""Drop the transcript entirely and rebuild query from DB messages.
|
||||
|
||||
Returns ``(transcript_builder, use_resume, resume_file)``.
|
||||
"""
|
||||
# Subsequent retry or compaction failed: drop transcript entirely
|
||||
logger.warning("%s Dropping transcript, rebuilding from DB messages", log_prefix)
|
||||
return TranscriptBuilder(), False, None
|
||||
return TranscriptBuilder(), False, None, True, True
|
||||
|
||||
|
||||
def _setup_langfuse_otel() -> None:
|
||||
@@ -997,45 +1002,39 @@ async def stream_chat_completion_sdk(
|
||||
|
||||
for _attempt in range(_MAX_STREAM_ATTEMPTS):
|
||||
if _attempt > 0:
|
||||
_stream_error = None
|
||||
stream_completed = False
|
||||
|
||||
logger.info(
|
||||
"%s Retrying with reduced context (%d/%d)",
|
||||
log_prefix,
|
||||
_attempt + 1,
|
||||
_MAX_STREAM_ATTEMPTS,
|
||||
)
|
||||
_stream_error = None
|
||||
stream_completed = False
|
||||
|
||||
# First retry: try compacting the transcript.
|
||||
# Subsequent retries: drop transcript, rebuild from DB.
|
||||
if transcript_content and not _tried_compaction:
|
||||
_tried_compaction = True
|
||||
tb, use_resume, resume_file, success = (
|
||||
await _retry_with_compacted_transcript(
|
||||
transcript_content, session_id, sdk_cwd, log_prefix
|
||||
)
|
||||
)
|
||||
transcript_builder = tb
|
||||
transcript_msg_count = 0
|
||||
if not success:
|
||||
transcript_caused_error = True
|
||||
else:
|
||||
transcript_builder, use_resume, resume_file = (
|
||||
_retry_without_transcript(log_prefix)
|
||||
)
|
||||
transcript_msg_count = 0
|
||||
(
|
||||
transcript_builder,
|
||||
use_resume,
|
||||
resume_file,
|
||||
transcript_lost,
|
||||
_tried_compaction,
|
||||
) = await _reduce_context(
|
||||
transcript_content,
|
||||
_tried_compaction,
|
||||
session_id,
|
||||
sdk_cwd,
|
||||
log_prefix,
|
||||
)
|
||||
transcript_msg_count = 0
|
||||
if transcript_lost:
|
||||
transcript_caused_error = True
|
||||
|
||||
# Rebuild SDK options with updated resume state
|
||||
# Rebuild SDK options and query for the reduced context
|
||||
sdk_options_kwargs_retry = dict(sdk_options_kwargs)
|
||||
if use_resume and resume_file:
|
||||
sdk_options_kwargs_retry["resume"] = resume_file
|
||||
elif "resume" in sdk_options_kwargs_retry:
|
||||
del sdk_options_kwargs_retry["resume"]
|
||||
options = ClaudeAgentOptions(**sdk_options_kwargs_retry) # type: ignore[arg-type] # dynamic kwargs
|
||||
|
||||
# Rebuild query with updated resume/transcript state
|
||||
query_message, was_compacted = await _build_query_message(
|
||||
current_message,
|
||||
session,
|
||||
@@ -1045,7 +1044,6 @@ async def stream_chat_completion_sdk(
|
||||
)
|
||||
if attachments.hint:
|
||||
query_message = f"{query_message}\n\n{attachments.hint}"
|
||||
|
||||
adapter = SDKResponseAdapter(
|
||||
message_id=message_id, session_id=session_id
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user