From 448c0deafdbd03f261eb655d6537cb6bd6677caa Mon Sep 17 00:00:00 2001 From: ciregenz Date: Thu, 25 Jun 2026 00:58:57 -0700 Subject: [PATCH] =?UTF-8?q?[eric]=20agents:=20rename=20cryptic=20names=20?= =?UTF-8?q?=E2=80=94=20LivePartial->PartialReply,=20session/lifecycle.py->?= =?UTF-8?q?resume=5Fand=5Fduplicate.py=20(it=20held=20resume/duplicate,=20?= =?UTF-8?q?and=20collided=20with=20SessionLifecycle)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/apps/agents/agent_manager.py | 4 ++-- .../apps/agents/manager/AgentManagerProtocol.py | 4 ++-- .../agents/manager/session/SessionLifecycle.py | 6 +++--- .../{lifecycle.py => resume_and_duplicate.py} | 0 .../{LivePartial.py => PartialReply.py} | 2 +- .../streaming/handle_assistant_message.py | 4 ++-- .../manager/streaming/handle_stream_event.py | 6 +++--- ...lifecycle.py => test_resume_and_duplicate.py} | 16 ++++++++-------- 8 files changed, 21 insertions(+), 21 deletions(-) rename backend/apps/agents/manager/session/{lifecycle.py => resume_and_duplicate.py} (100%) rename backend/apps/agents/manager/streaming/{LivePartial.py => PartialReply.py} (93%) rename backend/tests/{test_lifecycle.py => test_resume_and_duplicate.py} (74%) diff --git a/backend/apps/agents/agent_manager.py b/backend/apps/agents/agent_manager.py index a9c23383..af049e1a 100644 --- a/backend/apps/agents/agent_manager.py +++ b/backend/apps/agents/agent_manager.py @@ -18,7 +18,7 @@ from backend.apps.agents.manager.session.session_store import ( load_session_data as load_session_data, ) from backend.apps.agents.manager.streaming.state import ThinkingState, TurnState -from backend.apps.agents.manager.streaming.LivePartial import LivePartial +from backend.apps.agents.manager.streaming.PartialReply import PartialReply from backend.apps.agents.manager.session.SessionLifecycle import SessionLifecycle from backend.apps.agents.manager.session.SessionPersistence import SessionPersistence from backend.apps.agents.manager.Messaging import Messaging @@ -43,7 +43,7 @@ class AgentManager(SessionLifecycle, SessionPersistence, Messaging, SessionContr # Live mirror of the in-flight streamed assistant text per session, so a # stop can persist the partial reply instantly instead of waiting out the # multi-second SDK teardown the cancel handler sits behind. - self.live_partial: Dict[str, LivePartial] = {} + self.live_partial: Dict[str, PartialReply] = {} # Per-session cancel signal: the loop stashes its asyncio.Event here so a # stop/close can set it. Lives on the manager, not the AgentSession model, # so it stays out of serialization (an Event can't be model_dump'd). diff --git a/backend/apps/agents/manager/AgentManagerProtocol.py b/backend/apps/agents/manager/AgentManagerProtocol.py index efcf02e5..9b47d53b 100644 --- a/backend/apps/agents/manager/AgentManagerProtocol.py +++ b/backend/apps/agents/manager/AgentManagerProtocol.py @@ -17,14 +17,14 @@ from typing import TYPE_CHECKING, Any, Dict if TYPE_CHECKING: from backend.apps.agents.core.models import AgentSession - from backend.apps.agents.manager.streaming.LivePartial import LivePartial + from backend.apps.agents.manager.streaming.PartialReply import PartialReply class AgentManagerProtocol: # State set in AgentManager.__init__. sessions: Dict[str, AgentSession] tasks: Dict[str, asyncio.Task] - live_partial: Dict[str, LivePartial] + live_partial: Dict[str, PartialReply] cancel_events: Dict[str, asyncio.Event] if TYPE_CHECKING: diff --git a/backend/apps/agents/manager/session/SessionLifecycle.py b/backend/apps/agents/manager/session/SessionLifecycle.py index e5edd1ab..c6f7fe74 100644 --- a/backend/apps/agents/manager/session/SessionLifecycle.py +++ b/backend/apps/agents/manager/session/SessionLifecycle.py @@ -19,7 +19,7 @@ from backend.apps.agents.manager.session.session_store import ( ) from backend.apps.agents.manager.session.sync_session_close import sync_session_close from backend.apps.agents.manager.session.apply_context_window import apply_context_window -from backend.apps.agents.manager.session import lifecycle +from backend.apps.agents.manager.session import resume_and_duplicate from backend.apps.agents.manager.view_builder_state import ( view_builder_render_retry_counts, view_builder_dirty_sessions, @@ -139,7 +139,7 @@ class SessionLifecycle(AgentManagerProtocol): async def resume_session(self, session_id: str) -> AgentSession: if session_id in self.sessions: return self.sessions[session_id] - session = lifecycle.load_session_for_resume(session_id) + session = resume_and_duplicate.load_session_for_resume(session_id) self.sessions[session_id] = session await ws_manager.send_to_session(session_id, "agent:status", { "session_id": session_id, @@ -193,7 +193,7 @@ class SessionLifecycle(AgentManagerProtocol): @typechecked async def duplicate_session(self, session_id: str, dashboard_id: Optional[str] = None, up_to_message_id: Optional[str] = None) -> AgentSession: - new_session = lifecycle.build_duplicate_session(self.sessions.get(session_id), session_id, dashboard_id, up_to_message_id) + new_session = resume_and_duplicate.build_duplicate_session(self.sessions.get(session_id), session_id, dashboard_id, up_to_message_id) self.sessions[new_session.id] = new_session await ws_manager.send_to_session(new_session.id, "agent:status", { "session_id": new_session.id, diff --git a/backend/apps/agents/manager/session/lifecycle.py b/backend/apps/agents/manager/session/resume_and_duplicate.py similarity index 100% rename from backend/apps/agents/manager/session/lifecycle.py rename to backend/apps/agents/manager/session/resume_and_duplicate.py diff --git a/backend/apps/agents/manager/streaming/LivePartial.py b/backend/apps/agents/manager/streaming/PartialReply.py similarity index 93% rename from backend/apps/agents/manager/streaming/LivePartial.py rename to backend/apps/agents/manager/streaming/PartialReply.py index 94b5e042..13e37c05 100644 --- a/backend/apps/agents/manager/streaming/LivePartial.py +++ b/backend/apps/agents/manager/streaming/PartialReply.py @@ -7,7 +7,7 @@ from typing import Optional from pydantic import BaseModel, ConfigDict -class LivePartial(BaseModel): +class PartialReply(BaseModel): model_config = ConfigDict(validate_assignment=True) msg_id: Optional[str] = None diff --git a/backend/apps/agents/manager/streaming/handle_assistant_message.py b/backend/apps/agents/manager/streaming/handle_assistant_message.py index c82bcd81..049341b4 100644 --- a/backend/apps/agents/manager/streaming/handle_assistant_message.py +++ b/backend/apps/agents/manager/streaming/handle_assistant_message.py @@ -14,7 +14,7 @@ from backend.apps.agents.core.models import AgentSession, Message from backend.apps.agents.core.ws_manager import ws_manager from backend.apps.agents.manager.streaming.state import ThinkingState, TurnState from backend.apps.agents.manager.streaming.upsert_message import upsert_message -from backend.apps.agents.manager.streaming.LivePartial import LivePartial +from backend.apps.agents.manager.streaming.PartialReply import PartialReply from backend.apps.agents.manager.streaming import thinking as thinking_mod try: @@ -31,7 +31,7 @@ async def handle_assistant_message( session_id: str, turn: TurnState, thinking: ThinkingState, - live_partial: Dict[str, LivePartial], + live_partial: Dict[str, PartialReply], sessions: Dict[str, AgentSession], ) -> None: content_parts = [] diff --git a/backend/apps/agents/manager/streaming/handle_stream_event.py b/backend/apps/agents/manager/streaming/handle_stream_event.py index a3bb6e37..085bd227 100644 --- a/backend/apps/agents/manager/streaming/handle_stream_event.py +++ b/backend/apps/agents/manager/streaming/handle_stream_event.py @@ -13,7 +13,7 @@ from typeguard import typechecked from backend.apps.agents.core.models import AgentSession from backend.apps.agents.core.ws_manager import ws_manager from backend.apps.agents.manager.streaming.state import ThinkingState, TurnState -from backend.apps.agents.manager.streaming.LivePartial import LivePartial +from backend.apps.agents.manager.streaming.PartialReply import PartialReply try: from claude_agent_sdk.types import StreamEvent @@ -28,7 +28,7 @@ async def handle_stream_event( session_id: str, turn: TurnState, thinking: ThinkingState, - live_partial: Dict[str, LivePartial], + live_partial: Dict[str, PartialReply], ) -> None: event = message.event event_type = event.get("type") @@ -113,7 +113,7 @@ async def handle_stream_event( text_chunk = delta.get("text", "") turn.assistant_text_chars += len(text_chunk) turn.stream_text_accum += text_chunk - live_partial[session_id] = LivePartial( + live_partial[session_id] = PartialReply( msg_id=turn.stream_text_msg_id, text=turn.stream_text_accum, branch_id=session.active_branch_id, diff --git a/backend/tests/test_lifecycle.py b/backend/tests/test_resume_and_duplicate.py similarity index 74% rename from backend/tests/test_lifecycle.py rename to backend/tests/test_resume_and_duplicate.py index be0e6e2e..dfdeed46 100644 --- a/backend/tests/test_lifecycle.py +++ b/backend/tests/test_resume_and_duplicate.py @@ -1,8 +1,8 @@ -"""Pins the session build-functions lifted into manager/session/lifecycle.py: +"""Pins the session build-functions lifted into manager/session/resume_and_duplicate.py: the duplicate must be an INDEPENDENT copy (fresh ids, source untouched), and both builders raise when there's no on-disk snapshot to restore from.""" -import backend.apps.agents.manager.session.lifecycle as lifecycle +import backend.apps.agents.manager.session.resume_and_duplicate as resume_and_duplicate from backend.apps.agents.core.models import AgentSession, Message @@ -10,7 +10,7 @@ def test_build_duplicate_session_is_an_independent_copy(): src = AgentSession(name="Orig", model="sonnet", dashboard_id="d1") src.messages = [Message(role="user", content="hello"), Message(role="assistant", content="hi")] - new = lifecycle.build_duplicate_session(src, src.id, None, None) + new = resume_and_duplicate.build_duplicate_session(src, src.id, None, None) assert new.id != src.id assert new.name == "Orig (copy)" @@ -32,23 +32,23 @@ def test_build_duplicate_session_respects_up_to_message_id(): ) src.messages = [m1, m2, m3] - new = lifecycle.build_duplicate_session(src, src.id, None, m2.id) + new = resume_and_duplicate.build_duplicate_session(src, src.id, None, m2.id) assert [m.content for m in new.messages] == ["one", "two"] # truncated at the cut message def test_build_duplicate_session_raises_when_source_missing(monkeypatch): - monkeypatch.setattr(lifecycle, "load_session_data", lambda sid: None, raising=True) + monkeypatch.setattr(resume_and_duplicate, "load_session_data", lambda sid: None, raising=True) try: - lifecycle.build_duplicate_session(None, "ghost", None, None) + resume_and_duplicate.build_duplicate_session(None, "ghost", None, None) assert False, "expected ValueError when neither cache nor disk has the session" except ValueError: pass def test_load_session_for_resume_raises_when_absent(monkeypatch): - monkeypatch.setattr(lifecycle, "load_session_data", lambda sid: None, raising=True) + monkeypatch.setattr(resume_and_duplicate, "load_session_data", lambda sid: None, raising=True) try: - lifecycle.load_session_for_resume("ghost") + resume_and_duplicate.load_session_for_resume("ghost") assert False, "expected ValueError when there's no snapshot on disk" except ValueError: pass