From 0c3a15832b5e82e12afa944bbf9684ed8b85ed25 Mon Sep 17 00:00:00 2001 From: Zamil Majdy Date: Thu, 16 Apr 2026 14:04:32 +0700 Subject: [PATCH] fix(backend/copilot): set transcript_content on baseline restore, fix relative import in transcript.py - _restore_cli_session_for_turn now sets result.transcript_content when loading baseline content into the TranscriptBuilder, preventing the _seed_transcript guard in stream_chat_completion_sdk from overwriting the builder with a full DB reconstruction (which would duplicate entries since load_previous appends). - Change transcript.py TYPE_CHECKING and runtime ChatMessage import from absolute (backend.copilot.model) to relative (.model) to match service.py's import style and eliminate Pyright type-identity collisions. - Unpack _load_prior_transcript tuple return in mode_switch_context_test.py and assert dl is not None. - Add assert result.transcript_content != "" in service_helpers_test.py. --- .../backend/backend/copilot/sdk/mode_switch_context_test.py | 6 ++++-- autogpt_platform/backend/backend/copilot/sdk/service.py | 4 ++++ .../backend/backend/copilot/sdk/service_helpers_test.py | 4 ++++ autogpt_platform/backend/backend/copilot/transcript.py | 4 ++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/autogpt_platform/backend/backend/copilot/sdk/mode_switch_context_test.py b/autogpt_platform/backend/backend/copilot/sdk/mode_switch_context_test.py index 44720da519..212fca189b 100644 --- a/autogpt_platform/backend/backend/copilot/sdk/mode_switch_context_test.py +++ b/autogpt_platform/backend/backend/copilot/sdk/mode_switch_context_test.py @@ -277,7 +277,7 @@ class TestSdkToFastModeSwitch: "backend.copilot.baseline.service.download_transcript", new=AsyncMock(return_value=restore), ): - covers = await _load_prior_transcript( + covers, dl = await _load_prior_transcript( user_id="user-1", session_id="session-1", session_messages=[ @@ -290,6 +290,7 @@ class TestSdkToFastModeSwitch: # CLI session is valid and covers the prefix. assert covers is True + assert dl is not None assert baseline_builder.entry_count == 2 @pytest.mark.asyncio @@ -332,7 +333,7 @@ class TestSdkToFastModeSwitch: "backend.copilot.baseline.service.download_transcript", new=AsyncMock(return_value=restore), ): - covers = await _load_prior_transcript( + covers, dl = await _load_prior_transcript( user_id="user-1", session_id="session-1", session_messages=session_messages, @@ -341,5 +342,6 @@ class TestSdkToFastModeSwitch: # With gap filling, covers is True and gap messages are appended. assert covers is True + assert dl is not None # 2 from transcript + 7 gap messages (positions 2..8, excluding last user turn) assert baseline_builder.entry_count == 9 diff --git a/autogpt_platform/backend/backend/copilot/sdk/service.py b/autogpt_platform/backend/backend/copilot/sdk/service.py index a1aafeb87b..cbb98335f8 100644 --- a/autogpt_platform/backend/backend/copilot/sdk/service.py +++ b/autogpt_platform/backend/backend/copilot/sdk/service.py @@ -2538,6 +2538,9 @@ async def _restore_cli_session_for_turn( ) # Load baseline transcript content into builder so the upload path has accurate state. + # Also sets result.transcript_content so the _seed_transcript guard in the caller + # (``not transcript_content``) does not overwrite this builder state with a DB + # reconstruction — which would duplicate entries since load_previous appends. if result.baseline_download is not None: try: raw_for_builder = result.baseline_download.content @@ -2546,6 +2549,7 @@ async def _restore_cli_session_for_turn( stripped = strip_for_upload(raw_for_builder) if validate_transcript(stripped): transcript_builder.load_previous(stripped, log_prefix=log_prefix) + result.transcript_content = stripped except Exception as _load_err: logger.debug( "%s Could not load baseline transcript into builder: %s", diff --git a/autogpt_platform/backend/backend/copilot/sdk/service_helpers_test.py b/autogpt_platform/backend/backend/copilot/sdk/service_helpers_test.py index 66091ee816..3b919c6036 100644 --- a/autogpt_platform/backend/backend/copilot/sdk/service_helpers_test.py +++ b/autogpt_platform/backend/backend/copilot/sdk/service_helpers_test.py @@ -859,6 +859,10 @@ class TestRestoreCliSessionModeCheck: assert result.context_messages[0].role == "user" assert result.context_messages[1].role == "assistant" assert "TRANSCRIPT_ASSISTANT" in (result.context_messages[1].content or "") + # transcript_content must be non-empty so the _seed_transcript guard in + # stream_chat_completion_sdk skips DB reconstruction (which would duplicate + # builder entries since load_previous appends). + assert result.transcript_content != "" @pytest.mark.asyncio async def test_baseline_mode_gap_present_context_includes_gap(self, tmp_path): diff --git a/autogpt_platform/backend/backend/copilot/transcript.py b/autogpt_platform/backend/backend/copilot/transcript.py index 25927bab87..57471ebae6 100644 --- a/autogpt_platform/backend/backend/copilot/transcript.py +++ b/autogpt_platform/backend/backend/copilot/transcript.py @@ -29,7 +29,7 @@ from backend.util.prompt import CompressResult, compress_context from backend.util.workspace_storage import GCSWorkspaceStorage, get_workspace_storage if TYPE_CHECKING: - from backend.copilot.model import ChatMessage + from .model import ChatMessage logger = logging.getLogger(__name__) @@ -858,7 +858,7 @@ def extract_context_messages( A list of ``ChatMessage`` objects covering the prior conversation context, suitable for injection as conversation history. """ - from backend.copilot.model import ChatMessage as _ChatMessage # runtime import + from .model import ChatMessage as _ChatMessage # runtime import prior = session_messages[:-1]