diff --git a/pyproject.toml b/pyproject.toml index f0e2ba5df..80dfbac91 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ members = ["toad"] [tool.uv.sources] ui-theme = { git = "https://github.com/OpenHCSDev/ui-theme.git", rev = "5e58d8b5907cec4dbc8810a9329aaf902f69f675" } -agent-comms = { git = "https://github.com/OpenHCSDev/agent-comms.git", rev = "00a3d74d4b1ab8962941d84a764b3e8c2e57013d" } +agent-comms = { git = "https://github.com/OpenHCSDev/agent-comms.git", rev = "04d414e4bd1b03a2d8985a199d59578704ac9b3c" } textual = { git = "https://github.com/OpenHCSDev/textual.git", rev = "18f4e7a67403d56846ef5abf55c93e3e0639be33" } textual-image = { git = "https://github.com/OpenHCSDev/textual-image.git", rev = "1f1d8b8ea3c30b39da3b14ea0ac0786ce9c49a80" } textual-diff-view = { git = "https://github.com/OpenHCSDev/textual-diff-view.git", rev = "8fa7d4d0db993ea3b761c2760ca9b6a56a6251e9" } diff --git a/src/toad/comms_root.py b/src/toad/comms_root.py index 1eafb4baa..b1b174aa6 100644 --- a/src/toad/comms_root.py +++ b/src/toad/comms_root.py @@ -257,8 +257,8 @@ def sidebar_observed(self, result: SidebarObserved, observed: ObservedCommsServi if previous_references != self.reference_context(str(observed.service.root)): self.events.publish(LinkContextChanged()) self.sidebar_current = result.request - if result.snapshot.read_marker_notice and result.snapshot.read_marker_notice != notice: - app.notify(result.snapshot.read_marker_notice, title="Read positions", severity="warning") + for text in result.snapshot.read_marker_notice.messages_since(notice): + app.notify(text, title="Read positions", severity="warning") if app.open_tabs != tabs: app.events.publish(OpenTabsChanged()) for waiter in self.take_sidebar_waiters(result.request): diff --git a/src/toad/conversation_kind.py b/src/toad/conversation_kind.py index b8ef0e093..5b7851854 100644 --- a/src/toad/conversation_kind.py +++ b/src/toad/conversation_kind.py @@ -67,9 +67,8 @@ async def toggle_dm(cls, screen) -> None: screen.app.session_navigation.direct_messages() @classmethod - def unread(cls, snapshot, target): - from agent_comms.ui_model.unread import UnreadPresentation - return UnreadPresentation.for_channel(snapshot, target) + def unread(cls, sidebar, target): + return sidebar.channel_unread(target) @classmethod def placeholder(cls, target): @@ -242,9 +241,8 @@ def threads_needed(cls, snapshot, me, target): return (snapshot.require(me).incarnation, snapshot.require(target).incarnation) @classmethod - def unread(cls, snapshot, target): - from agent_comms.ui_model.unread import UnreadPresentation - return UnreadPresentation.for_bus(snapshot, target) + def unread(cls, sidebar, target): + return sidebar.bus_unread(target) @classmethod def page(cls, comms: Comms, target: str, **bounds) -> MessagePage: diff --git a/src/toad/screens/welcome.py b/src/toad/screens/welcome.py index 2b58fd14f..b7f788a17 100644 --- a/src/toad/screens/welcome.py +++ b/src/toad/screens/welcome.py @@ -89,7 +89,7 @@ def update(self, model: SidebarModel, key: str, row: CommsRow) -> None: def sync_members(self, changed: frozenset[str] | None = None) -> None: model = self.query_ancestor(WelcomeEntries).model - if model is None or model.snapshot is None or not self.member_container.is_attached: + if model is None or not self.member_container.is_attached: return keys = self.keys(model)[:self.LIMIT] self.display = bool(keys) diff --git a/src/toad/session_entry.py b/src/toad/session_entry.py index 6dbc7a351..f589e1460 100644 --- a/src/toad/session_entry.py +++ b/src/toad/session_entry.py @@ -149,8 +149,7 @@ def accepts_launch(self, sessions: SessionNavigation, agent_identity: str, sessi def tab(self, sessions: SessionNavigation, observed: ObservedCommsService | None) -> OpenTab: source = self.source(sessions) name = source._comms_thread if source else "" - snapshot = observed.sidebar.snapshot if observed is not None else None - if snapshot is None or source is None or not source.belongs_to_wire(observed.service.root): + if observed is None or source is None or not source.belongs_to_wire(observed.service.root): return NamedTab(self.mode, self.details.name.display or "New Session") row = observed.sidebar.threads.rows.get(name) originals = self.original_threads(sessions) @@ -206,9 +205,7 @@ def source(self, sessions: SessionNavigation) -> MainScreen | None: def tab(self, sessions: SessionNavigation, observed: ObservedCommsService | None) -> OpenTab: unread: UnreadPresentation = UnobservedUnread() if observed is not None and Path(self.key.root).resolve() == observed.service.root: - snapshot = observed.sidebar.snapshot - if snapshot is not None: - unread = self.kind.unread(snapshot, self.key.target) + unread = self.kind.unread(observed.sidebar.observation, self.key.target) return NamedTab(self.mode, self.key.title, unread) def depends_on(self, mode: str) -> bool: diff --git a/src/toad/widgets/comms_sidebar.py b/src/toad/widgets/comms_sidebar.py index 5284e741a..4cc459492 100644 --- a/src/toad/widgets/comms_sidebar.py +++ b/src/toad/widgets/comms_sidebar.py @@ -448,7 +448,7 @@ def sync(self, *, channels: frozenset[str] | None, threads: frozenset[str] | Non @property def shows_model(self) -> bool: - return self.model is not None and self.model.snapshot is not None and not self.stale + return self.model is not None and not self.stale def unsubscribe(self) -> None: if self.model is not None: diff --git a/src/toad/widgets/thread_comms.py b/src/toad/widgets/thread_comms.py index 77e110fc5..e5aad6ef5 100644 --- a/src/toad/widgets/thread_comms.py +++ b/src/toad/widgets/thread_comms.py @@ -12,7 +12,7 @@ from pathlib import Path from agent_comms.display_order import ThreadSort -from agent_comms.ui_model.sidebar import ThreadRowModel +from agent_comms.ui_model.sidebar import ThreadRowModel, WaitingSidebar from textual import on from textual.binding import Binding from textual.content import Content @@ -389,16 +389,15 @@ async def _refresh(self, generation): if generation != self._generation or not self.is_attached: return observed = self.app.coordination_access.observation - unread = (observed.sidebar.snapshot - if observed is not None and observed.sidebar.snapshot is not None - and Path(self.wire_root).resolve() == observed.service.root.resolve() - else None) + sidebar = WaitingSidebar() + if observed is not None and Path(self.wire_root).resolve() == observed.service.root.resolve(): + sidebar = observed.sidebar.observation people = {entry.person.thread.name: entry.person for model in snapshot.groups for entry in model.entries if entry.person is not None} def derive() -> tuple[dict[str, ThreadRowModel], int]: # ThreadView presentation may inspect process identity: off the UI thread. - rows = {name: ThreadRowModel.of(person, unread) for name, person in people.items()} + rows = {name: sidebar.thread_row(person) for name, person in people.items()} widest = Content(f"For @{snapshot.owner} · recent window").cell_length + 4 for model in snapshot.groups: for entry in model.entries: diff --git a/src/toad/wire_history.py b/src/toad/wire_history.py index 8737f0013..fb27f4fda 100644 --- a/src/toad/wire_history.py +++ b/src/toad/wire_history.py @@ -191,7 +191,7 @@ def leading(self): if not isinstance(message, HistoricalMessage): return super().leading return (Gap(), Summary.titled(f"History · {message.source.original_root} · @{message.sender} " - f"created {message.sender_created_at}"), self.row.header) + f"{message.sender_incarnation.birth_description}"), self.row.header) @dataclass(frozen=True, eq=False) class WireSource: diff --git a/uv.lock b/uv.lock index 600f3ee18..54edbcaf2 100644 --- a/uv.lock +++ b/uv.lock @@ -21,7 +21,7 @@ wheels = [ [[package]] name = "agent-comms" version = "0.1.0" -source = { git = "https://github.com/OpenHCSDev/agent-comms.git?rev=00a3d74d4b1ab8962941d84a764b3e8c2e57013d#00a3d74d4b1ab8962941d84a764b3e8c2e57013d" } +source = { git = "https://github.com/OpenHCSDev/agent-comms.git?rev=04d414e4bd1b03a2d8985a199d59578704ac9b3c#04d414e4bd1b03a2d8985a199d59578704ac9b3c" } dependencies = [ { name = "aiohttp" }, { name = "metaclass-registry" }, @@ -306,7 +306,7 @@ dev = [ [package.metadata] requires-dist = [ { name = "agent-client-protocol", specifier = "==0.12.1" }, - { name = "agent-comms", extras = ["acp"], git = "https://github.com/OpenHCSDev/agent-comms.git?rev=00a3d74d4b1ab8962941d84a764b3e8c2e57013d" }, + { name = "agent-comms", extras = ["acp"], git = "https://github.com/OpenHCSDev/agent-comms.git?rev=04d414e4bd1b03a2d8985a199d59578704ac9b3c" }, { name = "aiosqlite", specifier = "==0.22.1" }, { name = "bashlex", specifier = "==0.18" }, { name = "click", specifier = "==8.4.0" },