Skip to content

Commit d31ed34

Browse files
committed
call dedicated method on Router when YChat is reset
1 parent 634d0e4 commit d31ed34

File tree

2 files changed

+66
-3
lines changed

2 files changed

+66
-3
lines changed

jupyter_ai_router/extension.py

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from __future__ import annotations
2+
from typing import TYPE_CHECKING
23
import time
34
from jupyter_events import EventLogger
45
from jupyter_server.extension.application import ExtensionApp
@@ -15,13 +16,18 @@
1516
"https://events.jupyter.org/jupyter_collaboration"
1617
)
1718

19+
# Define `JSD_PRESENT` to indicate whether `jupyter_server_documents` is
20+
# installed in the current environment.
1821
JSD_PRESENT = False
1922
try:
2023
import jupyter_server_documents
2124
JSD_PRESENT = True
2225
except ImportError:
2326
pass
2427

28+
if TYPE_CHECKING:
29+
from jupyterlab_chat.ychat import YChat
30+
2531

2632
class RouterExtension(ExtensionApp):
2733
"""
@@ -33,6 +39,8 @@ class RouterExtension(ExtensionApp):
3339
(r"jupyter-ai-router/health/?", RouteHandler),
3440
]
3541

42+
router: MessageRouter
43+
3644
def initialize_settings(self):
3745
"""Initialize router settings and event listeners."""
3846
start = time.time()
@@ -79,8 +87,24 @@ async def _on_chat_event(
7987
# Connect chat to router
8088
self.router.connect_chat(room_id, ychat)
8189

82-
async def _get_chat(self, room_id: str):
83-
"""Get YChat instance for a room ID."""
90+
async def _get_chat(self, room_id: str) -> YChat | None:
91+
"""
92+
Get YChat instance for a room ID.
93+
94+
Dispatches to either `_get_chat_jcollab()` or `_get_chat_jsd()` based on
95+
whether `jupyter_server_documents` is installed.
96+
"""
97+
98+
if JSD_PRESENT:
99+
return await self._get_chat_jsd(room_id)
100+
else:
101+
return await self._get_chat_jcollab(room_id)
102+
103+
async def _get_chat_jcollab(self, room_id: str) -> YChat | None:
104+
"""
105+
Method used to retrieve the `YChat` instance for a given room when
106+
`jupyter_server_documents` **is not** installed.
107+
"""
84108
if not self.serverapp:
85109
return None
86110

@@ -91,6 +115,33 @@ async def _get_chat(self, room_id: str):
91115
except Exception as e:
92116
self.log.error(f"Error getting chat document for {room_id}: {e}")
93117
return None
118+
119+
async def _get_chat_jsd(self, room_id: str) -> YChat | None:
120+
"""
121+
Method used to retrieve the `YChat` instance for a given room when
122+
`jupyter_server_documents` **is** installed.
123+
124+
This method uniquely attaches a callback which is fired whenever the
125+
`YChat` is reset.
126+
"""
127+
if not self.serverapp:
128+
return None
129+
130+
try:
131+
jcollab_api = self.serverapp.web_app.settings["jupyter_server_ydoc"]
132+
yroom_manager = jcollab_api.yroom_manager
133+
yroom = yroom_manager.get_room(room_id)
134+
135+
def _on_ychat_reset(new_ychat: YChat):
136+
self.router._on_chat_reset(room_id, new_ychat)
137+
138+
ychat = await yroom.get_jupyter_ydoc(on_reset=_on_ychat_reset)
139+
return ychat
140+
except Exception as e:
141+
self.log.error(f"Error getting chat document for {room_id}: {e}")
142+
return None
143+
144+
94145

95146
async def stop_extension(self):
96147
"""Clean up router when extension stops."""

jupyter_ai_router/router.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ def __init__(self, *args, **kwargs):
5555
self.chat_init_observers: List[Callable[[str, "YChat"], Any]] = []
5656
self.slash_cmd_observers: Dict[str, Dict[str, List[Callable[[str, str, Message], Any]]]] = {}
5757
self.chat_msg_observers: Dict[str, List[Callable[[str, Message], Any]]] = {}
58+
self.chat_reset_observers: List[Callable[[str, "YChat"], Any]] = []
5859

5960
# Active chat rooms
6061
self.active_chats: Dict[str, "YChat"] = {}
@@ -71,7 +72,7 @@ def observe_chat_init(self, callback: Callable[[str, "YChat"], Any]) -> None:
7172
"""
7273
self.chat_init_observers.append(callback)
7374
self.log.info("Registered new chat initialization callback")
74-
75+
7576
def observe_slash_cmd_msg(
7677
self, room_id: str, command_pattern: str, callback: Callable[[str, str, Message], Any]
7778
) -> None:
@@ -230,6 +231,17 @@ def _notify_msg_observers(self, room_id: str, message: Message) -> None:
230231
callback(room_id, message)
231232
except Exception as e:
232233
self.log.error(f"Message observer error for {room_id}: {e}")
234+
235+
def _on_chat_reset(self, room_id, ychat: "YChat") -> None:
236+
"""
237+
Method to call when the YChat undergoes a document reset, e.g. when the
238+
`.chat` file is modified directly on disk.
239+
240+
NOTE: Document resets will only occur when `jupyter_server_documents` is
241+
installed.
242+
"""
243+
self.log.warning(f"Detected `YChat` document reset in room '{room_id}'.")
244+
pass
233245

234246
def cleanup(self) -> None:
235247
"""Clean up router resources."""

0 commit comments

Comments
 (0)