|
25 | 25 | from . import _session_util |
26 | 26 | from ..errors.already_exists_error import AlreadyExistsError |
27 | 27 | from ..events.event import Event |
| 28 | +from ..features import FeatureName |
| 29 | +from ..features import is_feature_enabled |
28 | 30 | from .base_session_service import BaseSessionService |
29 | 31 | from .base_session_service import GetSessionConfig |
30 | 32 | from .base_session_service import ListSessionsResponse |
|
34 | 36 | logger = logging.getLogger('google_adk.' + __name__) |
35 | 37 |
|
36 | 38 |
|
| 39 | +def _light_copy(session: Session) -> Session: |
| 40 | + """Returns a light copy of the session. |
| 41 | +
|
| 42 | + Main difference between this and true shallow-copy is that container fields |
| 43 | + (e.g., events and state) are also shallow-copied. What this means is appending |
| 44 | + to events/state of the copied session won't affect the original while avoiding |
| 45 | + the potentially expensive cost of a full/recursive deep-copy of all events and |
| 46 | + state. |
| 47 | + """ |
| 48 | + copied_session = session.model_copy(deep=False) |
| 49 | + copied_session.events = copy.copy(session.events) |
| 50 | + copied_session.state = copy.copy(session.state) |
| 51 | + return copied_session |
| 52 | + |
| 53 | + |
| 54 | +def _copy_session(session: Session) -> Session: |
| 55 | + if is_feature_enabled(FeatureName.IN_MEMORY_SESSION_SERVICE_LIGHT_COPY): |
| 56 | + return _light_copy(session) |
| 57 | + else: |
| 58 | + return copy.deepcopy(session) |
| 59 | + |
| 60 | + |
37 | 61 | class InMemorySessionService(BaseSessionService): |
38 | 62 | """An in-memory implementation of the session service. |
39 | 63 |
|
@@ -124,7 +148,7 @@ def _create_session_impl( |
124 | 148 | self.sessions[app_name][user_id] = {} |
125 | 149 | self.sessions[app_name][user_id][session_id] = session |
126 | 150 |
|
127 | | - copied_session = copy.deepcopy(session) |
| 151 | + copied_session = _copy_session(session) |
128 | 152 | return self._merge_state(app_name, user_id, copied_session) |
129 | 153 |
|
130 | 154 | @override |
@@ -175,7 +199,7 @@ def _get_session_impl( |
175 | 199 | return None |
176 | 200 |
|
177 | 201 | session = self.sessions[app_name][user_id].get(session_id) |
178 | | - copied_session = copy.deepcopy(session) |
| 202 | + copied_session = _copy_session(session) |
179 | 203 |
|
180 | 204 | if config: |
181 | 205 | if config.num_recent_events is not None: |
@@ -247,13 +271,13 @@ def _list_sessions_impl( |
247 | 271 | if user_id is None: |
248 | 272 | for uid in list(self.sessions[app_name].keys()): |
249 | 273 | for session in list(self.sessions[app_name][uid].values()): |
250 | | - copied_session = copy.deepcopy(session) |
| 274 | + copied_session = _copy_session(session) |
251 | 275 | copied_session.events = [] |
252 | 276 | copied_session = self._merge_state(app_name, uid, copied_session) |
253 | 277 | sessions_without_events.append(copied_session) |
254 | 278 | else: |
255 | 279 | for session in list(self.sessions[app_name][user_id].values()): |
256 | | - copied_session = copy.deepcopy(session) |
| 280 | + copied_session = _copy_session(session) |
257 | 281 | copied_session.events = [] |
258 | 282 | copied_session = self._merge_state(app_name, user_id, copied_session) |
259 | 283 | sessions_without_events.append(copied_session) |
|
0 commit comments