lucidicai 2.1.3__py3-none-any.whl → 3.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. lucidicai/__init__.py +32 -390
  2. lucidicai/api/client.py +31 -2
  3. lucidicai/api/resources/__init__.py +16 -1
  4. lucidicai/api/resources/dataset.py +422 -82
  5. lucidicai/api/resources/event.py +399 -27
  6. lucidicai/api/resources/experiment.py +108 -0
  7. lucidicai/api/resources/feature_flag.py +78 -0
  8. lucidicai/api/resources/prompt.py +84 -0
  9. lucidicai/api/resources/session.py +545 -38
  10. lucidicai/client.py +395 -480
  11. lucidicai/core/config.py +73 -48
  12. lucidicai/core/errors.py +3 -3
  13. lucidicai/sdk/bound_decorators.py +321 -0
  14. lucidicai/sdk/context.py +20 -2
  15. lucidicai/sdk/decorators.py +283 -74
  16. lucidicai/sdk/event.py +538 -36
  17. lucidicai/sdk/event_builder.py +2 -4
  18. lucidicai/sdk/features/dataset.py +391 -1
  19. lucidicai/sdk/features/feature_flag.py +344 -3
  20. lucidicai/sdk/init.py +49 -347
  21. lucidicai/sdk/session.py +502 -0
  22. lucidicai/sdk/shutdown_manager.py +103 -46
  23. lucidicai/session_obj.py +321 -0
  24. lucidicai/telemetry/context_capture_processor.py +13 -6
  25. lucidicai/telemetry/extract.py +60 -63
  26. lucidicai/telemetry/litellm_bridge.py +3 -44
  27. lucidicai/telemetry/lucidic_exporter.py +143 -131
  28. lucidicai/telemetry/openai_agents_instrumentor.py +2 -2
  29. lucidicai/telemetry/openai_patch.py +7 -6
  30. lucidicai/telemetry/telemetry_manager.py +183 -0
  31. lucidicai/telemetry/utils/model_pricing.py +21 -30
  32. lucidicai/telemetry/utils/provider.py +77 -0
  33. lucidicai/utils/images.py +27 -11
  34. lucidicai/utils/serialization.py +27 -0
  35. {lucidicai-2.1.3.dist-info → lucidicai-3.0.0.dist-info}/METADATA +1 -1
  36. {lucidicai-2.1.3.dist-info → lucidicai-3.0.0.dist-info}/RECORD +38 -29
  37. {lucidicai-2.1.3.dist-info → lucidicai-3.0.0.dist-info}/WHEEL +0 -0
  38. {lucidicai-2.1.3.dist-info → lucidicai-3.0.0.dist-info}/top_level.txt +0 -0
@@ -1,23 +1,360 @@
1
1
  """Session resource API operations."""
2
- from typing import Any, Dict, List, Optional
2
+ import logging
3
+ import threading
4
+ import uuid
5
+ from typing import Any, Dict, List, Optional, TYPE_CHECKING
3
6
 
4
7
  from ..client import HttpClient
5
8
 
9
+ if TYPE_CHECKING:
10
+ from ...client import LucidicAI
11
+ from ...session_obj import Session
12
+ from ...core.config import SDKConfig
13
+
14
+ logger = logging.getLogger("Lucidic")
15
+
16
+
17
+ def _truncate_id(id_str: Optional[str]) -> str:
18
+ """Truncate ID for logging."""
19
+ if not id_str:
20
+ return "None"
21
+ return f"{id_str[:8]}..." if len(id_str) > 8 else id_str
22
+
6
23
 
7
24
  class SessionResource:
8
25
  """Handle session-related API operations."""
9
-
10
- def __init__(self, http: HttpClient):
26
+
27
+ def __init__(
28
+ self,
29
+ http: HttpClient,
30
+ client: "LucidicAI",
31
+ config: "SDKConfig",
32
+ production: bool = False,
33
+ ):
11
34
  """Initialize session resource.
12
-
35
+
13
36
  Args:
14
37
  http: HTTP client instance
38
+ client: Parent LucidicAI client
39
+ config: SDK configuration
40
+ production: Whether to suppress errors in production mode
15
41
  """
16
42
  self.http = http
17
-
18
- def create_session(self, params: Dict[str, Any]) -> Dict[str, Any]:
43
+ self._client = client
44
+ self._config = config
45
+ self._production = production
46
+
47
+ # ==================== High-Level Session Methods ====================
48
+
49
+ def create(
50
+ self,
51
+ session_name: Optional[str] = None,
52
+ session_id: Optional[str] = None,
53
+ task: Optional[str] = None,
54
+ tags: Optional[List[str]] = None,
55
+ experiment_id: Optional[str] = None,
56
+ datasetitem_id: Optional[str] = None,
57
+ evaluators: Optional[List[str]] = None,
58
+ auto_end: Optional[bool] = None,
59
+ production_monitoring: bool = False,
60
+ ) -> "Session":
19
61
  """Create a new session.
20
-
62
+
63
+ Sessions track a unit of work and can be used as context managers.
64
+
65
+ Args:
66
+ session_name: Human-readable name for the session.
67
+ session_id: Optional custom session ID. Auto-generated if not provided.
68
+ task: Task description for the session.
69
+ tags: List of tags for filtering/grouping.
70
+ experiment_id: Link session to an experiment.
71
+ datasetitem_id: Link session to a dataset item.
72
+ evaluators: List of evaluator names to run.
73
+ auto_end: Override client's auto_end setting for this session.
74
+ production_monitoring: Enable lightweight production monitoring.
75
+
76
+ Returns:
77
+ A Session object that can be used as a context manager.
78
+
79
+ Example:
80
+ with client.sessions.create(session_name="My Session") as session:
81
+ # Do work
82
+ pass
83
+ """
84
+ # Late imports to avoid circular dependencies
85
+ from ...session_obj import Session
86
+ from ...core.errors import LucidicError
87
+ from ...sdk.shutdown_manager import ShutdownManager, SessionState
88
+
89
+ if not self._client.is_valid:
90
+ if self._production:
91
+ # Return a dummy session in production mode
92
+ return Session(
93
+ client=self._client,
94
+ session_id=session_id or str(uuid.uuid4()),
95
+ session_name=session_name,
96
+ auto_end=False,
97
+ )
98
+ raise LucidicError("Client is not properly configured")
99
+
100
+ # Use client's auto_end by default
101
+ if auto_end is None:
102
+ auto_end = self._config.auto_end
103
+
104
+ # Generate session ID if not provided
105
+ real_session_id = session_id or str(uuid.uuid4())
106
+
107
+ # Build session parameters
108
+ session_params: Dict[str, Any] = {
109
+ "session_id": real_session_id,
110
+ "session_name": session_name or "Unnamed Session",
111
+ "agent_id": self._config.agent_id,
112
+ }
113
+ if task:
114
+ session_params["task"] = task
115
+ if tags:
116
+ session_params["tags"] = tags
117
+ if experiment_id:
118
+ session_params["experiment_id"] = experiment_id
119
+ if datasetitem_id:
120
+ session_params["datasetitem_id"] = datasetitem_id
121
+ if evaluators:
122
+ session_params["evaluators"] = evaluators
123
+ if production_monitoring:
124
+ session_params["production_monitoring"] = True
125
+
126
+ try:
127
+ # Create via API
128
+ response = self.create_session(session_params)
129
+ real_session_id = response.get("session_id", real_session_id)
130
+ except Exception as e:
131
+ if self._production:
132
+ logger.error(f"[SessionResource] Failed to create session: {e}")
133
+ else:
134
+ raise
135
+
136
+ # Create Session object
137
+ session = Session(
138
+ client=self._client,
139
+ session_id=real_session_id,
140
+ session_name=session_name,
141
+ auto_end=auto_end,
142
+ )
143
+
144
+ # Bind session context immediately
145
+ session._bind_context()
146
+
147
+ # Track session
148
+ with self._client._session_lock:
149
+ self._client._sessions[real_session_id] = session
150
+
151
+ # Register with shutdown manager for auto-end
152
+ if auto_end:
153
+ shutdown_manager = ShutdownManager()
154
+ state = SessionState(
155
+ session_id=real_session_id,
156
+ http_client=self._client._resources,
157
+ auto_end=auto_end,
158
+ )
159
+ shutdown_manager.register_session(real_session_id, state)
160
+
161
+ logger.debug(f"[SessionResource] Created session {real_session_id[:8]}...")
162
+ return session
163
+
164
+ async def acreate(
165
+ self,
166
+ session_name: Optional[str] = None,
167
+ session_id: Optional[str] = None,
168
+ task: Optional[str] = None,
169
+ tags: Optional[List[str]] = None,
170
+ experiment_id: Optional[str] = None,
171
+ datasetitem_id: Optional[str] = None,
172
+ evaluators: Optional[List[str]] = None,
173
+ auto_end: Optional[bool] = None,
174
+ production_monitoring: bool = False,
175
+ ) -> "Session":
176
+ """Create a new session (async version).
177
+
178
+ See create() for full documentation.
179
+ """
180
+ # Late imports to avoid circular dependencies
181
+ from ...session_obj import Session
182
+ from ...core.errors import LucidicError
183
+ from ...sdk.shutdown_manager import ShutdownManager, SessionState
184
+
185
+ if not self._client.is_valid:
186
+ if self._production:
187
+ return Session(
188
+ client=self._client,
189
+ session_id=session_id or str(uuid.uuid4()),
190
+ session_name=session_name,
191
+ auto_end=False,
192
+ )
193
+ raise LucidicError("Client is not properly configured")
194
+
195
+ if auto_end is None:
196
+ auto_end = self._config.auto_end
197
+
198
+ real_session_id = session_id or str(uuid.uuid4())
199
+
200
+ session_params: Dict[str, Any] = {
201
+ "session_id": real_session_id,
202
+ "session_name": session_name or "Unnamed Session",
203
+ "agent_id": self._config.agent_id,
204
+ }
205
+ if task:
206
+ session_params["task"] = task
207
+ if tags:
208
+ session_params["tags"] = tags
209
+ if experiment_id:
210
+ session_params["experiment_id"] = experiment_id
211
+ if datasetitem_id:
212
+ session_params["datasetitem_id"] = datasetitem_id
213
+ if evaluators:
214
+ session_params["evaluators"] = evaluators
215
+ if production_monitoring:
216
+ session_params["production_monitoring"] = True
217
+
218
+ try:
219
+ response = await self.acreate_session(session_params)
220
+ real_session_id = response.get("session_id", real_session_id)
221
+ except Exception as e:
222
+ if self._production:
223
+ logger.error(f"[SessionResource] Failed to create session: {e}")
224
+ else:
225
+ raise
226
+
227
+ session = Session(
228
+ client=self._client,
229
+ session_id=real_session_id,
230
+ session_name=session_name,
231
+ auto_end=auto_end,
232
+ )
233
+
234
+ session._bind_context()
235
+
236
+ with self._client._session_lock:
237
+ self._client._sessions[real_session_id] = session
238
+
239
+ if auto_end:
240
+ shutdown_manager = ShutdownManager()
241
+ state = SessionState(
242
+ session_id=real_session_id,
243
+ http_client=self._client._resources,
244
+ auto_end=auto_end,
245
+ )
246
+ shutdown_manager.register_session(real_session_id, state)
247
+
248
+ logger.debug(f"[SessionResource] Created async session {real_session_id[:8]}...")
249
+ return session
250
+
251
+ def end(
252
+ self,
253
+ session_id: Optional[str] = None,
254
+ is_successful: Optional[bool] = None,
255
+ is_successful_reason: Optional[str] = None,
256
+ session_eval: Optional[float] = None,
257
+ session_eval_reason: Optional[str] = None,
258
+ ) -> None:
259
+ """End a session.
260
+
261
+ Args:
262
+ session_id: Session ID to end. If None, attempts to use current context session.
263
+ is_successful: Whether the session was successful.
264
+ is_successful_reason: Reason for success/failure status.
265
+ session_eval: Evaluation score (0.0 to 1.0).
266
+ session_eval_reason: Reason for the evaluation score.
267
+ """
268
+ from ...sdk.shutdown_manager import ShutdownManager
269
+
270
+ if not self._client.is_valid:
271
+ return
272
+
273
+ # If no session_id, try to get from context
274
+ if not session_id:
275
+ from ...sdk.context import current_session_id
276
+ session_id = current_session_id.get(None)
277
+
278
+ if not session_id:
279
+ logger.debug("[SessionResource] No session to end")
280
+ return
281
+
282
+ try:
283
+ self.end_session(
284
+ session_id=session_id,
285
+ is_successful=is_successful,
286
+ is_successful_reason=is_successful_reason,
287
+ session_eval=session_eval,
288
+ session_eval_reason=session_eval_reason,
289
+ )
290
+ except Exception as e:
291
+ if self._production:
292
+ logger.error(f"[SessionResource] Failed to end session: {e}")
293
+ else:
294
+ raise
295
+
296
+ # Remove from tracking
297
+ with self._client._session_lock:
298
+ self._client._sessions.pop(session_id, None)
299
+
300
+ # Unregister from shutdown manager
301
+ shutdown_manager = ShutdownManager()
302
+ shutdown_manager.unregister_session(session_id)
303
+
304
+ logger.debug(f"[SessionResource] Ended session {session_id[:8]}...")
305
+
306
+ async def aend(
307
+ self,
308
+ session_id: Optional[str] = None,
309
+ is_successful: Optional[bool] = None,
310
+ is_successful_reason: Optional[str] = None,
311
+ session_eval: Optional[float] = None,
312
+ session_eval_reason: Optional[str] = None,
313
+ ) -> None:
314
+ """End a session (async version).
315
+
316
+ See end() for full documentation.
317
+ """
318
+ from ...sdk.shutdown_manager import ShutdownManager
319
+
320
+ if not self._client.is_valid:
321
+ return
322
+
323
+ if not session_id:
324
+ from ...sdk.context import current_session_id
325
+ session_id = current_session_id.get(None)
326
+
327
+ if not session_id:
328
+ logger.debug("[SessionResource] No session to end")
329
+ return
330
+
331
+ try:
332
+ await self.aend_session(
333
+ session_id=session_id,
334
+ is_successful=is_successful,
335
+ is_successful_reason=is_successful_reason,
336
+ session_eval=session_eval,
337
+ session_eval_reason=session_eval_reason,
338
+ )
339
+ except Exception as e:
340
+ if self._production:
341
+ logger.error(f"[SessionResource] Failed to end session: {e}")
342
+ else:
343
+ raise
344
+
345
+ with self._client._session_lock:
346
+ self._client._sessions.pop(session_id, None)
347
+
348
+ shutdown_manager = ShutdownManager()
349
+ shutdown_manager.unregister_session(session_id)
350
+
351
+ logger.debug(f"[SessionResource] Ended async session {session_id[:8]}...")
352
+
353
+ # ==================== Low-Level HTTP Methods ====================
354
+
355
+ def create_session(self, params: Dict[str, Any]) -> Dict[str, Any]:
356
+ """Create a new session via API.
357
+
21
358
  Args:
22
359
  params: Session parameters including:
23
360
  - session_name: Name of the session
@@ -25,37 +362,63 @@ class SessionResource:
25
362
  - task: Optional task description
26
363
  - tags: Optional tags
27
364
  - etc.
28
-
365
+
29
366
  Returns:
30
367
  Created session data with session_id
31
368
  """
32
- return self.http.post("initsession", params)
33
-
34
- def get_session(self, session_id: str) -> Dict[str, Any]:
369
+ session_id = params.get("session_id")
370
+ session_name = params.get("session_name")
371
+ logger.debug(
372
+ f"[Session] create_session() called - "
373
+ f"session_id={_truncate_id(session_id)}, name={session_name!r}, "
374
+ f"params={list(params.keys())}"
375
+ )
376
+
377
+ response = self.http.post("initsession", params)
378
+
379
+ resp_session_id = response.get("session_id") if response else None
380
+ logger.debug(
381
+ f"[Session] create_session() response - "
382
+ f"session_id={_truncate_id(resp_session_id)}, response_keys={list(response.keys()) if response else 'None'}"
383
+ )
384
+ return response
385
+
386
+ def get(self, session_id: str) -> Dict[str, Any]:
35
387
  """Get a session by ID.
36
-
388
+
37
389
  Args:
38
390
  session_id: Session ID
39
-
391
+
40
392
  Returns:
41
393
  Session data
42
394
  """
43
395
  return self.http.get(f"sessions/{session_id}")
44
-
45
- def update_session(self, session_id: str, updates: Dict[str, Any]) -> Dict[str, Any]:
396
+
397
+ def update(self, session_id: str, **updates) -> Dict[str, Any]:
46
398
  """Update an existing session.
47
-
399
+
48
400
  Args:
49
401
  session_id: Session ID
50
- updates: Fields to update (task, is_finished, etc.)
51
-
402
+ **updates: Fields to update (task, is_finished, etc.)
403
+
52
404
  Returns:
53
405
  Updated session data
54
406
  """
407
+ logger.debug(
408
+ f"[Session] update() called - "
409
+ f"session_id={_truncate_id(session_id)}, updates={updates}"
410
+ )
411
+
55
412
  # Add session_id to the updates payload
56
413
  updates["session_id"] = session_id
57
- return self.http.put("updatesession", updates)
58
-
414
+ response = self.http.put("updatesession", updates)
415
+
416
+ logger.debug(
417
+ f"[Session] update() response - "
418
+ f"session_id={_truncate_id(session_id)}, response_keys={list(response.keys()) if response else 'None'}"
419
+ )
420
+ return response
421
+
59
422
  def end_session(
60
423
  self,
61
424
  session_id: str,
@@ -64,37 +427,43 @@ class SessionResource:
64
427
  session_eval: Optional[float] = None,
65
428
  session_eval_reason: Optional[str] = None
66
429
  ) -> Dict[str, Any]:
67
- """End a session.
68
-
430
+ """End a session via API.
431
+
69
432
  Args:
70
433
  session_id: Session ID
71
434
  is_successful: Whether session was successful
72
435
  is_successful_reason: Reason for success or failure
73
436
  session_eval: Session evaluation score
74
437
  session_eval_reason: Reason for evaluation
75
-
438
+
76
439
  Returns:
77
440
  Final session data
78
441
  """
79
- updates = {
442
+ logger.debug(
443
+ f"[Session] end_session() called - "
444
+ f"session_id={_truncate_id(session_id)}, is_successful={is_successful}, "
445
+ f"session_eval={session_eval}"
446
+ )
447
+
448
+ updates: Dict[str, Any] = {
80
449
  "is_finished": True
81
450
  }
82
-
451
+
83
452
  if is_successful is not None:
84
453
  updates["is_successful"] = is_successful
85
-
454
+
86
455
  if session_eval is not None:
87
456
  updates["session_eval"] = session_eval
88
-
457
+
89
458
  if session_eval_reason is not None:
90
459
  updates["session_eval_reason"] = session_eval_reason
91
460
 
92
461
  if is_successful_reason is not None:
93
462
  updates["is_successful_reason"] = is_successful_reason
94
-
95
- return self.update_session(session_id, updates)
96
-
97
- def list_sessions(
463
+
464
+ return self.update(session_id, **updates)
465
+
466
+ def list(
98
467
  self,
99
468
  agent_id: Optional[str] = None,
100
469
  experiment_id: Optional[str] = None,
@@ -102,25 +471,163 @@ class SessionResource:
102
471
  offset: int = 0
103
472
  ) -> Dict[str, Any]:
104
473
  """List sessions with optional filters.
105
-
474
+
106
475
  Args:
107
476
  agent_id: Filter by agent ID
108
477
  experiment_id: Filter by experiment ID
109
478
  limit: Maximum number of sessions
110
479
  offset: Pagination offset
111
-
480
+
112
481
  Returns:
113
482
  List of sessions and pagination info
114
483
  """
115
- params = {
484
+ params: Dict[str, Any] = {
116
485
  "limit": limit,
117
486
  "offset": offset
118
487
  }
119
-
488
+
120
489
  if agent_id:
121
490
  params["agent_id"] = agent_id
122
-
491
+
123
492
  if experiment_id:
124
493
  params["experiment_id"] = experiment_id
125
-
126
- return self.http.get("sessions", params)
494
+
495
+ return self.http.get("sessions", params)
496
+
497
+ # ==================== Asynchronous HTTP Methods ====================
498
+
499
+ async def acreate_session(self, params: Dict[str, Any]) -> Dict[str, Any]:
500
+ """Create a new session via API (asynchronous).
501
+
502
+ Args:
503
+ params: Session parameters
504
+
505
+ Returns:
506
+ Created session data with session_id
507
+ """
508
+ session_id = params.get("session_id")
509
+ session_name = params.get("session_name")
510
+ logger.debug(
511
+ f"[Session] acreate_session() called - "
512
+ f"session_id={_truncate_id(session_id)}, name={session_name!r}, "
513
+ f"params={list(params.keys())}"
514
+ )
515
+
516
+ response = await self.http.apost("initsession", params)
517
+
518
+ resp_session_id = response.get("session_id") if response else None
519
+ logger.debug(
520
+ f"[Session] acreate_session() response - "
521
+ f"session_id={_truncate_id(resp_session_id)}, response_keys={list(response.keys()) if response else 'None'}"
522
+ )
523
+ return response
524
+
525
+ async def aget(self, session_id: str) -> Dict[str, Any]:
526
+ """Get a session by ID (asynchronous).
527
+
528
+ Args:
529
+ session_id: Session ID
530
+
531
+ Returns:
532
+ Session data
533
+ """
534
+ return await self.http.aget(f"sessions/{session_id}")
535
+
536
+ async def aupdate(self, session_id: str, **updates) -> Dict[str, Any]:
537
+ """Update an existing session (asynchronous).
538
+
539
+ Args:
540
+ session_id: Session ID
541
+ **updates: Fields to update (task, is_finished, etc.)
542
+
543
+ Returns:
544
+ Updated session data
545
+ """
546
+ logger.debug(
547
+ f"[Session] aupdate() called - "
548
+ f"session_id={_truncate_id(session_id)}, updates={updates}"
549
+ )
550
+
551
+ updates["session_id"] = session_id
552
+ response = await self.http.aput("updatesession", updates)
553
+
554
+ logger.debug(
555
+ f"[Session] aupdate() response - "
556
+ f"session_id={_truncate_id(session_id)}, response_keys={list(response.keys()) if response else 'None'}"
557
+ )
558
+ return response
559
+
560
+ async def aend_session(
561
+ self,
562
+ session_id: str,
563
+ is_successful: Optional[bool] = None,
564
+ is_successful_reason: Optional[str] = None,
565
+ session_eval: Optional[float] = None,
566
+ session_eval_reason: Optional[str] = None
567
+ ) -> Dict[str, Any]:
568
+ """End a session via API (asynchronous).
569
+
570
+ Args:
571
+ session_id: Session ID
572
+ is_successful: Whether session was successful
573
+ is_successful_reason: Reason for success or failure
574
+ session_eval: Session evaluation score
575
+ session_eval_reason: Reason for evaluation
576
+
577
+ Returns:
578
+ Final session data
579
+ """
580
+ logger.debug(
581
+ f"[Session] aend_session() called - "
582
+ f"session_id={_truncate_id(session_id)}, is_successful={is_successful}, "
583
+ f"session_eval={session_eval}"
584
+ )
585
+
586
+ updates: Dict[str, Any] = {
587
+ "is_finished": True
588
+ }
589
+
590
+ if is_successful is not None:
591
+ updates["is_successful"] = is_successful
592
+
593
+ if session_eval is not None:
594
+ updates["session_eval"] = session_eval
595
+
596
+ if session_eval_reason is not None:
597
+ updates["session_eval_reason"] = session_eval_reason
598
+
599
+ if is_successful_reason is not None:
600
+ updates["is_successful_reason"] = is_successful_reason
601
+
602
+ return await self.aupdate(session_id, **updates)
603
+
604
+ async def alist(
605
+ self,
606
+ agent_id: Optional[str] = None,
607
+ experiment_id: Optional[str] = None,
608
+ limit: int = 100,
609
+ offset: int = 0
610
+ ) -> Dict[str, Any]:
611
+ """List sessions with optional filters (asynchronous).
612
+
613
+ Args:
614
+ agent_id: Filter by agent ID
615
+ experiment_id: Filter by experiment ID
616
+ limit: Maximum number of sessions
617
+ offset: Pagination offset
618
+
619
+ Returns:
620
+ List of sessions and pagination info
621
+ """
622
+ params: Dict[str, Any] = {
623
+ "limit": limit,
624
+ "offset": offset
625
+ }
626
+
627
+ if agent_id:
628
+ params["agent_id"] = agent_id
629
+
630
+ if experiment_id:
631
+ params["experiment_id"] = experiment_id
632
+
633
+ return await self.http.aget("sessions", params)