diff --git a/src/toad/acp/agent_session.py b/src/toad/acp/agent_session.py index 4e893cbe5..91a7096e9 100644 --- a/src/toad/acp/agent_session.py +++ b/src/toad/acp/agent_session.py @@ -6,7 +6,8 @@ import os from dataclasses import dataclass, replace from collections.abc import Callable -from agent_comms.route_selection import RouteChanged, RouteSelection +from agent_comms.errors import RouteChangedError +from agent_comms.route_selection import RouteSelection from agent_comms.thread_presentation import SessionDisconnected import toad from toad import constants @@ -340,7 +341,7 @@ async def reconnect(self, plan: SessionLoadPlan | None = None) -> None: try: await asyncio.to_thread( RouteSelection.capture, self.agent.controller.transcripts.access.launch_root.path) - except RouteChanged as error: + except RouteChangedError as error: self.startup_failed(f"Reconnect blocked before restart: {error}") return await self.agent.stop() diff --git a/src/toad/acp/comms_updates.py b/src/toad/acp/comms_updates.py index 71b946336..0089b848d 100644 --- a/src/toad/acp/comms_updates.py +++ b/src/toad/acp/comms_updates.py @@ -121,12 +121,12 @@ def input_started(self, update: InputStartedUpdate) -> None: @handles(CoordinationChangedUpdate) def coordination_changed(self, update: CoordinationChangedUpdate) -> None: from pathlib import Path - from agent_comms.route_selection import RouteChanged + from agent_comms.errors import RouteChangedError agent = self.agent root = agent.controller.transcripts.access.launch_root.path if Path(update.wire_root).resolve() != root.resolve(): - raise RouteChanged("ACP owner reported a different coordination root") + raise RouteChangedError("ACP owner reported a different coordination root") agent.coordination = update agent.project_root_path = Path(update.worktree) agent.context_measurement = ContextMeasurement.saved(update.context_usage) diff --git a/src/toad/comms_root.py b/src/toad/comms_root.py index 389acd951..6149e73b3 100644 --- a/src/toad/comms_root.py +++ b/src/toad/comms_root.py @@ -25,7 +25,8 @@ from agent_comms.mro_dispatch import MroDispatch, handles from agent_comms.presentation import MessageNotification, NoRevision, ReadState from agent_comms.revision_views import ExternalTranscriptsView, StatusView -from agent_comms.route_selection import RouteChanged, RouteSelection, run_selected_write +from agent_comms.errors import RouteChangedError +from agent_comms.route_selection import RouteSelection, run_selected_write from agent_comms.ui_model.observation import ( ObserveNotifications, NotificationsObserved, NotificationsUnreadable, ReadNotifications, ObservationProcess, ObserveSidebar, ObserveThreads, ObserveViews, RevisionObserved, @@ -107,7 +108,7 @@ def attach(self, access, previous): waiters, access.sidebar_waiters = access.sidebar_waiters, [] for _, waiter in waiters: if not waiter.done(): - waiter.set_exception(RouteChanged("Comms service changed before the sidebar was read")) + waiter.set_exception(RouteChangedError("Comms service changed before the sidebar was read")) access.revision = NoRevision() access.sidebar_interest = access.sidebar_current = None access.thread_status.clear() @@ -253,7 +254,7 @@ def references_for(self, root): async def current_references(self, access, root): try: await access.current_sidebar() - except RouteChanged: + except RouteChangedError: return await access.observation.current_references(access, root) return access.reference_context(root) @@ -331,7 +332,7 @@ def open_current(self) -> Observing | FailedObservation: def require(self, selected: RouteSelection) -> Observing: """The service for ``selected``; a new selection opens it and starts its observation.""" if RouteSelection.capture() != selected: - raise RouteChanged("Comms route changed before the operation") + raise RouteChangedError("Comms route changed before the operation") with self.opening: return self.observation.require(self, selected) @@ -343,7 +344,7 @@ def open_selected(self, selected: RouteSelection) -> Observing: acquisition.enter_context(selected.route.hold_client_route()) service = wire(selected.route) if service.root.resolve() != selected.root or RouteSelection.capture() != selected: - raise RouteChanged("Comms route changed while opening the service") + raise RouteChangedError("Comms route changed while opening the service") observed = Observing( selected, service, SidebarModel(self.app.call_next), ObservationProcess(service.route), self.app.running_loop, access=self) diff --git a/src/toad/session_navigation.py b/src/toad/session_navigation.py index be2b8460f..24cb66bc5 100644 --- a/src/toad/session_navigation.py +++ b/src/toad/session_navigation.py @@ -12,8 +12,8 @@ from agent_comms.presentation import NoRevision, ReadState from agent_comms.revision_views import RegistrationsView -from agent_comms.errors import UnknownChannelError, UnregisteredThreadError -from agent_comms.route_selection import RouteChanged, root_is_current +from agent_comms.errors import RouteChangedError, UnknownChannelError, UnregisteredThreadError +from agent_comms.route_selection import root_is_current from agent_comms.thread_identity import ThreadIncarnation from toad.navigation_preparation import CommsNavigationRequest from toad.session_entry import (HistorySessionEntry, NativeSessionEntry, @@ -197,7 +197,7 @@ async def history(self, *, owner_mode: str, project_path: Path, me: str, return app.selected_mode prepared = await app.navigation_reader.read(CommsNavigationRequest( comms, owner_mode, me, conversation, source.coordination_root)) - except (UnknownChannelError, UnregisteredThreadError, RouteChanged) as error: + except (UnknownChannelError, UnregisteredThreadError, RouteChangedError) as error: app.show_error(error, "Comms target unavailable") return app.selected_mode if prepared is None: @@ -311,7 +311,7 @@ async def _retire_requested_views(self) -> None: await self.retire_missing() async def retire_missing(self) -> None: - from agent_comms.route_selection import RouteChanged, RouteSelection + from agent_comms.route_selection import RouteSelection # Borrow each open entry, including hidden views. Core decides # which of their sources no longer exist; Toad only closes the views. @@ -339,7 +339,7 @@ def read(): retired = service.views.retired_views(threads, channels) if RouteSelection.capture(root) != selected: continue # Replaced while reading; the next observation reads it. - except RouteChanged: + except RouteChangedError: continue # The next observation reads the replacement route. answers[root] = service, retired return answers diff --git a/src/toad/target_commands.py b/src/toad/target_commands.py index e75ae05ba..23f10c3ca 100644 --- a/src/toad/target_commands.py +++ b/src/toad/target_commands.py @@ -11,7 +11,8 @@ from agent_comms.comms import Comms from agent_comms.channel_targets import ChannelSelection, CommandTarget, NoChannel -from agent_comms.route_selection import RouteChanged, root_is_current +from agent_comms.errors import RouteChangedError +from agent_comms.route_selection import root_is_current from toad.slash_command import CommandPresentation, LocalCommand, SlashCommand from agent_comms.cli_commands import CliCommand, TargetAction from toad.thread_actions import ThreadAction @@ -42,7 +43,7 @@ def title(self): def current(self): if not root_is_current(self.comms.root): - raise RouteChanged('Comms route changed; reopen this view') + raise RouteChangedError('Comms route changed; reopen this view') return self def available_actions(self): diff --git a/src/toad/thread_actions.py b/src/toad/thread_actions.py index b430fc847..321d3a850 100644 --- a/src/toad/thread_actions.py +++ b/src/toad/thread_actions.py @@ -11,7 +11,8 @@ from agent_comms.cli_commands import TargetAction, TargetEdit, TargetBatchResult, TargetFailed from agent_comms.cli_result import CliResult from agent_comms.native_pi import NativePiUnavailable -from agent_comms.route_selection import RouteChanged, RouteSelection +from agent_comms.errors import RouteChangedError +from agent_comms.route_selection import RouteSelection if TYPE_CHECKING: from toad.app import ToadApp @@ -138,7 +139,7 @@ async def prepare(): fields = await ctx.app.preparation.run_thread( lambda: asyncio.run(definition.prepare_fields())) ctx.current() - except (NativePiUnavailable, RouteChanged) as error: + except (NativePiUnavailable, RouteChangedError) as error: ctx.app.show_error(error, definition.label) return if ctx.app.screen is screen: