lucidicai 1.2.21__py3-none-any.whl → 1.3.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.
lucidicai/__init__.py CHANGED
@@ -111,7 +111,7 @@ __all__ = [
111
111
  def init(
112
112
  session_name: Optional[str] = None,
113
113
  session_id: Optional[str] = None,
114
- lucidic_api_key: Optional[str] = None,
114
+ api_key: Optional[str] = None,
115
115
  agent_id: Optional[str] = None,
116
116
  task: Optional[str] = None,
117
117
  providers: Optional[List[ProviderType]] = [],
@@ -128,7 +128,7 @@ def init(
128
128
  Args:
129
129
  session_name: The display name of the session.
130
130
  session_id: Custom ID of the session. If not provided, a random ID will be generated.
131
- lucidic_api_key: API key for authentication. If not provided, will use the LUCIDIC_API_KEY environment variable.
131
+ api_key: API key for authentication. If not provided, will use the LUCIDIC_API_KEY environment variable.
132
132
  agent_id: Agent ID. If not provided, will use the LUCIDIC_AGENT_ID environment variable.
133
133
  task: Task description.
134
134
  providers: List of provider types ("openai", "anthropic", "langchain", "pydantic_ai").
@@ -142,27 +142,29 @@ def init(
142
142
  InvalidOperationError: If the client is already initialized.
143
143
  APIKeyVerificationError: If the API key is invalid.
144
144
  """
145
- if lucidic_api_key is None:
146
- lucidic_api_key = os.getenv("LUCIDIC_API_KEY", None)
147
- if lucidic_api_key is None:
148
- raise APIKeyVerificationError("Make sure to either pass your API key into lai.init() or set the LUCIDIC_API_KEY environment variable.")
149
- if agent_id is None:
150
- agent_id = os.getenv("LUCIDIC_AGENT_ID", None)
151
- if agent_id is None:
152
- raise APIKeyVerificationError("Lucidic agent ID not specified. Make sure to either pass your agent ID into lai.init() or set the LUCIDIC_AGENT_ID environment variable.")
153
-
145
+
154
146
  # get current client which will be NullClient if never lai is never initialized
155
147
  client = Client()
156
- # ff not yet initialized or still the NullClient -> creaet a real client when init is called
148
+ # if not yet initialized or still the NullClient -> creaet a real client when init is called
157
149
  if not getattr(client, 'initialized', False):
158
- client = Client(lucidic_api_key=lucidic_api_key, agent_id=agent_id)
159
-
160
- if not production_monitoring:
161
- production_monitoring = os.getenv("LUCIDIC_PRODUCTION_MONITORING", False)
162
- if production_monitoring == "True":
163
- production_monitoring = True
164
- else:
165
- production_monitoring = False
150
+ if api_key is None:
151
+ api_key = os.getenv("LUCIDIC_API_KEY", None)
152
+ if api_key is None:
153
+ raise APIKeyVerificationError("Make sure to either pass your API key into lai.init() or set the LUCIDIC_API_KEY environment variable.")
154
+ if agent_id is None:
155
+ agent_id = os.getenv("LUCIDIC_AGENT_ID", None)
156
+ if agent_id is None:
157
+ raise APIKeyVerificationError("Lucidic agent ID not specified. Make sure to either pass your agent ID into lai.init() or set the LUCIDIC_AGENT_ID environment variable.")
158
+ client = Client(api_key=api_key, agent_id=agent_id)
159
+ else:
160
+ # Already initialized, this is a re-init
161
+ api_key = api_key or os.getenv("LUCIDIC_API_KEY", None)
162
+ agent_id = agent_id or os.getenv("LUCIDIC_AGENT_ID", None)
163
+ client.agent_id = agent_id
164
+ if api_key is not None and agent_id is not None and (api_key != client.api_key or agent_id != client.agent_id):
165
+ client.set_api_key(api_key)
166
+ client.agent_id = agent_id
167
+
166
168
 
167
169
  # Handle auto_end with environment variable support
168
170
  if auto_end is None:
@@ -170,14 +172,14 @@ def init(
170
172
 
171
173
  # Set up providers
172
174
  _setup_providers(client, providers)
173
- session_id = client.init_session(
175
+ real_session_id = client.init_session(
174
176
  session_name=session_name,
175
177
  mass_sim_id=mass_sim_id,
176
178
  task=task,
177
179
  rubrics=rubrics,
178
180
  tags=tags,
179
181
  production_monitoring=production_monitoring,
180
- custom_session_id=session_id,
182
+ session_id=session_id,
181
183
  )
182
184
  if masking_function:
183
185
  client.masking_function = masking_function
@@ -186,20 +188,20 @@ def init(
186
188
  client.auto_end = auto_end
187
189
 
188
190
  logger.info("Session initialized successfully")
189
- return session_id
191
+ return real_session_id
190
192
 
191
193
 
192
194
  def continue_session(
193
195
  session_id: str,
194
- lucidic_api_key: Optional[str] = None,
196
+ api_key: Optional[str] = None,
195
197
  agent_id: Optional[str] = None,
196
198
  providers: Optional[List[ProviderType]] = [],
197
199
  masking_function = None,
198
200
  auto_end: Optional[bool] = True,
199
201
  ):
200
- if lucidic_api_key is None:
201
- lucidic_api_key = os.getenv("LUCIDIC_API_KEY", None)
202
- if lucidic_api_key is None:
202
+ if api_key is None:
203
+ api_key = os.getenv("LUCIDIC_API_KEY", None)
204
+ if api_key is None:
203
205
  raise APIKeyVerificationError("Make sure to either pass your API key into lai.init() or set the LUCIDIC_API_KEY environment variable.")
204
206
  if agent_id is None:
205
207
  agent_id = os.getenv("LUCIDIC_AGENT_ID", None)
@@ -211,7 +213,7 @@ def continue_session(
211
213
  raise InvalidOperationError("[Lucidic] Session already in progress. Please call lai.end_session() or lai.reset_sdk() first.")
212
214
  # if not yet initialized or still the NullClient -> create a real client when init is called
213
215
  if not getattr(client, 'initialized', False):
214
- client = Client(lucidic_api_key=lucidic_api_key, agent_id=agent_id)
216
+ client = Client(api_key=api_key, agent_id=agent_id)
215
217
 
216
218
  # Handle auto_end with environment variable support
217
219
  if auto_end is None:
@@ -284,8 +286,10 @@ def end_session(
284
286
 
285
287
  def reset_sdk() -> None:
286
288
  """
287
- Reset the SDK.
289
+ DEPRECATED: Reset the SDK.
288
290
  """
291
+ return
292
+
289
293
  client = Client()
290
294
  if not client.initialized:
291
295
  return
@@ -315,6 +319,7 @@ def _auto_end_session():
315
319
  client = Client()
316
320
  if hasattr(client, 'auto_end') and client.auto_end and client.session and not client.session.is_finished:
317
321
  logger.info("Auto-ending active session on exit")
322
+ client.auto_end = False # To avoid repeating auto-end on exit
318
323
  end_session()
319
324
  except Exception as e:
320
325
  logger.debug(f"Error during auto-end session: {e}")
@@ -341,7 +346,7 @@ signal.signal(signal.SIGTERM, _signal_handler)
341
346
  def create_mass_sim(
342
347
  mass_sim_name: str,
343
348
  total_num_sessions: int,
344
- lucidic_api_key: Optional[str] = None,
349
+ api_key: Optional[str] = None,
345
350
  agent_id: Optional[str] = None,
346
351
  task: Optional[str] = None,
347
352
  tags: Optional[list] = None
@@ -352,7 +357,7 @@ def create_mass_sim(
352
357
  Args:
353
358
  mass_sim_name: Name of the mass simulation.
354
359
  total_num_sessions: Total intended number of sessions. More sessions can be added later.
355
- lucidic_api_key: API key for authentication. If not provided, will use the LUCIDIC_API_KEY environment variable.
360
+ api_key: API key for authentication. If not provided, will use the LUCIDIC_API_KEY environment variable.
356
361
  agent_id: Agent ID. If not provided, will use the LUCIDIC_AGENT_ID environment variable.
357
362
  task: Task description.
358
363
  tags: Tags for the mass simulation.
@@ -360,9 +365,9 @@ def create_mass_sim(
360
365
  Returns:
361
366
  mass_sim_id: ID of the created mass simulation. Pass this to lai.init() to create a new session in the mass sim.
362
367
  """
363
- if lucidic_api_key is None:
364
- lucidic_api_key = os.getenv("LUCIDIC_API_KEY", None)
365
- if lucidic_api_key is None:
368
+ if api_key is None:
369
+ api_key = os.getenv("LUCIDIC_API_KEY", None)
370
+ if api_key is None:
366
371
  raise APIKeyVerificationError("Make sure to either pass your API key into lai.init() or set the LUCIDIC_API_KEY environment variable.")
367
372
  if agent_id is None:
368
373
  agent_id = os.getenv("LUCIDIC_AGENT_ID", None)
@@ -372,7 +377,7 @@ def create_mass_sim(
372
377
  client = Client()
373
378
  except LucidicNotInitializedError:
374
379
  client = Client( # TODO: fail hard if incorrect API key or agent ID provided and wrong, fail silently if not provided
375
- lucidic_api_key=lucidic_api_key,
380
+ api_key=api_key,
376
381
  agent_id=agent_id,
377
382
  )
378
383
  mass_sim_id = client.init_mass_sim(mass_sim_name=mass_sim_name, total_num_sims=total_num_sessions, task=task, tags=tags) # TODO: change total_num_sims to total_num_sessions everywhere
lucidicai/client.py CHANGED
@@ -13,7 +13,7 @@ from .errors import APIKeyVerificationError, InvalidOperationError, LucidicNotIn
13
13
  from .telemetry.base_provider import BaseProvider
14
14
  from .session import Session
15
15
  from .singleton import singleton, clear_singletons
16
-
16
+ from .lru import LRUCache
17
17
 
18
18
  NETWORK_RETRIES = 3
19
19
 
@@ -22,14 +22,16 @@ NETWORK_RETRIES = 3
22
22
  class Client:
23
23
  def __init__(
24
24
  self,
25
- lucidic_api_key: str,
25
+ api_key: str,
26
26
  agent_id: str,
27
27
  ):
28
28
  self.base_url = "https://analytics.lucidic.ai/api" if not (os.getenv("LUCIDIC_DEBUG", 'False') == 'True') else "http://localhost:8000/api"
29
29
  self.initialized = False
30
30
  self.session = None
31
+ self.previous_sessions = LRUCache(500) # For LRU cache of previously initialized sessions
32
+ self.custom_session_id_translations = LRUCache(500) # For translations of custom session IDs to real session IDs
31
33
  self.providers = []
32
- self.api_key = lucidic_api_key
34
+ self.api_key = api_key
33
35
  self.agent_id = agent_id
34
36
  self.masking_function = None
35
37
  self.auto_end = False # Default to False until explicitly set during init
@@ -42,13 +44,17 @@ class Client:
42
44
  )
43
45
  adapter = HTTPAdapter(max_retries=retry_cfg, pool_connections=20, pool_maxsize=100)
44
46
  self.request_session.mount("https://", adapter)
45
- self.request_session.headers.update({"Authorization": f"Api-Key {self.api_key}", "User-Agent": "lucidic-sdk/1.1"})
47
+ self.set_api_key(api_key)
46
48
  self.prompts = dict()
49
+
50
+ def set_api_key(self, api_key: str):
51
+ self.api_key = api_key
52
+ self.request_session.headers.update({"Authorization": f"Api-Key {self.api_key}", "User-Agent": "lucidic-sdk/1.1"})
47
53
  try:
48
- self.verify_api_key(self.base_url, lucidic_api_key)
54
+ self.verify_api_key(self.base_url, api_key)
49
55
  except APIKeyVerificationError:
50
56
  raise APIKeyVerificationError("Invalid API Key")
51
-
57
+
52
58
  def clear(self):
53
59
  self.undo_overrides()
54
60
  clear_singletons()
@@ -69,7 +75,7 @@ class Client:
69
75
  def undo_overrides(self):
70
76
  for provider in self.providers:
71
77
  provider.undo_override()
72
-
78
+
73
79
  def init_session(
74
80
  self,
75
81
  session_name: str,
@@ -78,30 +84,69 @@ class Client:
78
84
  rubrics: Optional[list] = None,
79
85
  tags: Optional[list] = None,
80
86
  production_monitoring: Optional[bool] = False,
81
- custom_session_id: Optional[str] = None,
87
+ session_id: Optional[str] = None,
82
88
  ) -> None:
89
+ if session_id:
90
+ # Check if it's a known session ID, maybe custom and maybe real
91
+ if session_id in self.custom_session_id_translations:
92
+ session_id = self.custom_session_id_translations[session_id]
93
+ # Check if it's the same as the current session
94
+ if self.session and self.session.session_id == session_id:
95
+ return self.session.session_id
96
+ # Check if it's a previous session that we have saved
97
+ if session_id in self.previous_sessions:
98
+ if self.session:
99
+ self.previous_sessions[self.session.session_id] = self.session
100
+ self.session = self.previous_sessions.pop(session_id) # Remove from previous sessions because it's now the current session
101
+ return self.session.session_id
102
+
103
+ # Either there's no session ID, or we don't know about the old session
104
+ # We need to go to the backend in both cases
105
+ request_data = {
106
+ "agent_id": self.agent_id,
107
+ "session_name": session_name,
108
+ "task": task,
109
+ "mass_sim_id": mass_sim_id,
110
+ "rubrics": rubrics,
111
+ "tags": tags,
112
+ "session_id": session_id
113
+ }
114
+ data = self.make_request('initsession', 'POST', request_data)
115
+ real_session_id = data["session_id"]
116
+ if session_id and session_id != real_session_id:
117
+ self.custom_session_id_translations[session_id] = real_session_id
118
+
119
+ if self.session:
120
+ self.previous_sessions[self.session.session_id] = self.session
121
+
83
122
  self.session = Session(
84
123
  agent_id=self.agent_id,
124
+ session_id=real_session_id,
85
125
  session_name=session_name,
86
126
  mass_sim_id=mass_sim_id,
87
127
  task=task,
88
128
  rubrics=rubrics,
89
129
  tags=tags,
90
- production_monitoring=production_monitoring,
91
- custom_session_id=custom_session_id
92
130
  )
93
131
  self.initialized = True
94
132
  return self.session.session_id
95
133
 
96
134
  def continue_session(self, session_id: str):
135
+ if session_id in self.custom_session_id_translations:
136
+ session_id = self.custom_session_id_translations[session_id]
137
+ if self.session and self.session.session_id == session_id:
138
+ return self.session.session_id
139
+ if self.session:
140
+ self.previous_sessions[self.session.session_id] = self.session
141
+ data = self.make_request('continuesession', 'POST', {"session_id": session_id})
142
+ real_session_id = data["session_id"]
143
+ if session_id != real_session_id:
144
+ self.custom_session_id_translations[session_id] = real_session_id
97
145
  self.session = Session(
98
146
  agent_id=self.agent_id,
99
- session_id=session_id
147
+ session_id=real_session_id
100
148
  )
101
- if self.session.session_id != session_id:
102
- # Custom session ID provided
103
- self.session.custom_session_id = session_id
104
- self.initialized = True
149
+ logger.info(f"Session {data.get('session_name', '')} continuing...")
105
150
  return self.session.session_id
106
151
 
107
152
  def init_mass_sim(self, **kwargs) -> str:
@@ -131,6 +176,7 @@ class Client:
131
176
  return prompt
132
177
 
133
178
  def make_request(self, endpoint, method, data):
179
+ print(f"Making request to {self.base_url}/{endpoint} with method {method} and data {data}")
134
180
  http_methods = {
135
181
  "GET": lambda data: self.request_session.get(f"{self.base_url}/{endpoint}", params=data),
136
182
  "POST": lambda data: self.request_session.post(f"{self.base_url}/{endpoint}", json=data),
lucidicai/event.py CHANGED
@@ -14,37 +14,47 @@ class Event:
14
14
  self.event_id = None
15
15
  self.screenshots = []
16
16
  self.is_finished = False
17
- self.init_event()
18
- self.update_event(**kwargs)
17
+ self.init_event(**kwargs)
19
18
 
20
-
21
- def init_event(self) -> None:
19
+ def init_event(self, **kwargs) -> None:
22
20
  from .client import Client
23
- request_data = {
24
- "step_id": self.step_id,
25
- # TODO: get rid of these in backend API interface?
26
- # "description": description,
27
- # "result": result
28
- }
21
+ request_data = self._build_request_data(**kwargs)
22
+ if self.step_id:
23
+ request_data['step_id'] = self.step_id
24
+ else:
25
+ request_data['session_id'] = self.session_id
29
26
  data = Client().make_request('initevent', 'POST', request_data)
30
27
  self.event_id = data["event_id"]
28
+ self.step_id = data["step_id"]
29
+ self._upload_screenshots(**kwargs)
30
+ return self.event_id
31
31
 
32
32
  def update_event(self, **kwargs) -> None:
33
33
  from .client import Client
34
- if 'screenshots' in kwargs and kwargs['screenshots'] is not None:
35
- for i in range(len(kwargs['screenshots'])):
36
- presigned_url, bucket_name, object_key = get_presigned_url(Client().agent_id, session_id=self.session_id, event_id=self.event_id, nthscreenshot=len(self.screenshots))
37
- upload_image_to_s3(presigned_url, kwargs['screenshots'][i], "JPEG")
38
- self.screenshots.append(kwargs['screenshots'][i])
39
34
  if 'is_finished' in kwargs:
40
35
  self.is_finished = kwargs['is_finished']
41
- request_data = {
42
- "event_id": self.event_id,
36
+ request_data = self._build_request_data(**kwargs)
37
+ request_data['event_id'] = self.event_id
38
+ Client().make_request('updateevent', 'PUT', request_data)
39
+ self._upload_screenshots(**kwargs)
40
+
41
+ def _build_request_data(self, **kwargs) -> dict:
42
+ from .client import Client
43
+ num_new_screenshots = len(kwargs.get("screenshots", []) or [])
44
+ return {
43
45
  "description": Client().mask(kwargs.get("description", None)),
44
46
  "result": Client().mask(kwargs.get("result", None)),
45
47
  "is_finished": self.is_finished,
46
48
  "cost_added": kwargs.get("cost_added", None),
47
49
  "model": kwargs.get("model", None),
48
- "nscreenshots": len(self.screenshots)
50
+ "nscreenshots": len(self.screenshots) + num_new_screenshots,
51
+ "duration": kwargs.get("duration", None)
49
52
  }
50
- Client().make_request('updateevent', 'PUT', request_data)
53
+
54
+ def _upload_screenshots(self, **kwargs) -> None:
55
+ from .client import Client
56
+ if 'screenshots' in kwargs and kwargs['screenshots'] is not None:
57
+ for i in range(len(kwargs['screenshots'])):
58
+ presigned_url, bucket_name, object_key = get_presigned_url(Client().agent_id, session_id=self.session_id, event_id=self.event_id, nthscreenshot=len(self.screenshots))
59
+ upload_image_to_s3(presigned_url, kwargs['screenshots'][i], "JPEG")
60
+ self.screenshots.append(kwargs['screenshots'][i])
lucidicai/lru.py ADDED
@@ -0,0 +1,19 @@
1
+ from collections import OrderedDict
2
+
3
+ class LRUCache(OrderedDict):
4
+ def __init__(self, capacity: int):
5
+ super().__init__()
6
+ self.capacity = capacity
7
+
8
+ def __getitem__(self, key):
9
+ if key not in self:
10
+ raise KeyError(key)
11
+ self.move_to_end(key) # Mark as recently used
12
+ return super().__getitem__(key)
13
+
14
+ def __setitem__(self, key, value):
15
+ if key in self:
16
+ self.move_to_end(key) # Update position
17
+ super().__setitem__(key, value)
18
+ if len(self) > self.capacity:
19
+ self.popitem(last=False) # Evict least recently used item
lucidicai/session.py CHANGED
@@ -15,11 +15,12 @@ logger = logging.getLogger("Lucidic")
15
15
  class Session:
16
16
  def __init__(
17
17
  self,
18
- agent_id: str,
18
+ agent_id: str,
19
+ session_id = None,
19
20
  **kwargs
20
21
  ):
21
22
  self.agent_id = agent_id
22
- self.session_id = None
23
+ self.session_id = session_id
23
24
  self.step_history = dict()
24
25
  self._active_step: Optional[str] = None # Step ID, not Step object
25
26
  self.event_history = dict()
@@ -30,33 +31,6 @@ class Session:
30
31
  self.session_eval = None
31
32
  self.session_eval_reason = None
32
33
  self.has_gif = None
33
- if kwargs.get("session_id", None) is None: # The kwarg, not the attribute
34
- self.init_session(**kwargs)
35
- else:
36
- self.continue_session(kwargs["session_id"])
37
-
38
- def init_session(self, **kwargs) -> None:
39
- from .client import Client
40
- request_data = {
41
- "agent_id": self.agent_id,
42
- "session_name": kwargs.get("session_name", None),
43
- "task": kwargs.get("task", None),
44
- "mass_sim_id": kwargs.get("mass_sim_id", None),
45
- "rubrics": kwargs.get("rubrics", None),
46
- "tags": kwargs.get("tags", None),
47
- "production_monitoring": kwargs.get("production_monitoring", False),
48
- "custom_session_id": kwargs.get("custom_session_id", None)
49
- }
50
- data = Client().make_request('initsession', 'POST', request_data)
51
- self.session_id = data["session_id"]
52
-
53
- def continue_session(self, session_id: str) -> None:
54
- from .client import Client
55
- self.session_id = session_id
56
- data = Client().make_request('continuesession', 'POST', {"session_id": session_id})
57
- self.session_id = data["session_id"]
58
- logger.info(f"Session {data['session_name']} continuing...")
59
- return self.session_id
60
34
 
61
35
  @property
62
36
  def active_step(self) -> Optional[Step]:
@@ -110,14 +84,12 @@ class Session:
110
84
 
111
85
  def create_event(self, **kwargs):
112
86
  # Get step_id from kwargs or active step
113
- temp_step_created = False
114
87
  if 'step_id' in kwargs and kwargs['step_id'] is not None:
115
88
  step_id = kwargs['step_id']
116
89
  elif self._active_step:
117
90
  step_id = self._active_step
118
91
  else:
119
- step_id = self.create_step()
120
- temp_step_created = True
92
+ step_id = None
121
93
  kwargs.pop('step_id', None)
122
94
  event = Event(
123
95
  session_id=self.session_id,
@@ -126,9 +98,6 @@ class Session:
126
98
  )
127
99
  self.event_history[event.event_id] = event
128
100
  self._active_event = event
129
- if temp_step_created:
130
- self.update_step(step_id=step_id, is_finished=True)
131
- self._active_step = None
132
101
  return event.event_id
133
102
 
134
103
  def update_event(self, **kwargs):
@@ -239,6 +239,12 @@ class LucidicSpanProcessor(SpanProcessor):
239
239
  # Calculate cost
240
240
  cost = self._calculate_cost(attributes)
241
241
 
242
+ # Calculate duration in seconds
243
+ duration_seconds = None
244
+ if span.start_time and span.end_time:
245
+ duration_ns = span.end_time - span.start_time
246
+ duration_seconds = duration_ns / 1_000_000_000
247
+
242
248
  # Check success
243
249
  is_successful = span.status.status_code != StatusCode.ERROR
244
250
 
@@ -247,7 +253,8 @@ class LucidicSpanProcessor(SpanProcessor):
247
253
  'description': description,
248
254
  'result': formatted_result,
249
255
  'model': model,
250
- 'is_finished': True
256
+ 'is_finished': True,
257
+ 'duration': duration_seconds
251
258
  }
252
259
 
253
260
  if images:
@@ -288,6 +295,12 @@ class LucidicSpanProcessor(SpanProcessor):
288
295
  # Calculate cost
289
296
  cost = self._calculate_cost(attributes)
290
297
 
298
+ # Calculate duration in seconds
299
+ duration_seconds = None
300
+ if span.start_time and span.end_time:
301
+ duration_ns = span.end_time - span.start_time
302
+ duration_seconds = duration_ns / 1_000_000_000
303
+
291
304
  # Check success
292
305
  is_successful = span.status.status_code != StatusCode.ERROR
293
306
 
@@ -295,7 +308,8 @@ class LucidicSpanProcessor(SpanProcessor):
295
308
  update_kwargs = {
296
309
  'event_id': event_id,
297
310
  'result': result,
298
- 'is_finished': True
311
+ 'is_finished': True,
312
+ 'duration': duration_seconds
299
313
  }
300
314
 
301
315
  if cost is not None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lucidicai
3
- Version: 1.2.21
3
+ Version: 1.3.0
4
4
  Summary: Lucidic AI Python SDK
5
5
  Author: Andy Liang
6
6
  Author-email: andy@lucidic.ai
@@ -1,13 +1,14 @@
1
- lucidicai/__init__.py,sha256=sUfrleiPQPuXq5e0UnkXPjuTShiVoHnPtl_O0nzPcd8,20589
1
+ lucidicai/__init__.py,sha256=-eSSR9UaMubE0KpbesR2jLU0xUn37oucMNxjgKaCfkA,20738
2
2
  lucidicai/action.py,sha256=sPRd1hTIVXDqnvG9ZXWEipUFh0bsXcE0Fm7RVqmVccM,237
3
- lucidicai/client.py,sha256=3yBVppvwBwesca_pZSKgTUDihzZe5JhVgh1AALCpJ_Q,6620
3
+ lucidicai/client.py,sha256=GOiRL0M2fs5HjOFwPtc2Da45lHcv4-N6BIiI11_I170,9081
4
4
  lucidicai/constants.py,sha256=_u0z3M4geZgS1g-CrOZUVjtcew8l70dKQnpVQvlXh9w,2172
5
5
  lucidicai/decorators.py,sha256=oqXyfHk9f9UmeaIquuU8mtzed1qZtO_-svwadpoat6g,13950
6
6
  lucidicai/errors.py,sha256=gTg0bdzjuTcUnakRbZnxjngO4gZnRLVwRHRglpZZJsM,970
7
- lucidicai/event.py,sha256=iPbNBRb2ZFohBsrRQZHzfa9GbxCsgFIw3M8w4gFrSi4,2000
7
+ lucidicai/event.py,sha256=EF-KNPMBHGdNnhchu5HF7QnYJSMofUaq-QuGL0j_OAE,2521
8
8
  lucidicai/image_upload.py,sha256=6SRudg-BpInM2gzMx1Yf1Rz_Zyh8inwoJ7U4pBw7ruY,3807
9
+ lucidicai/lru.py,sha256=PXiDSoUCOxjamG1QlQx6pDbQCm8h5hKAnnr_NI0PEgE,618
9
10
  lucidicai/model_pricing.py,sha256=o1yWCaF5Qxj4tloXxVG3SZXcTMKtk56J_Nfdo8M4uR0,11947
10
- lucidicai/session.py,sha256=T_4z3CLKMp5DOKSVpdWwMZkZG9ndXU6oiI5Al6DHSTY,5501
11
+ lucidicai/session.py,sha256=NFkWJioqGcRxHjfqwWw-1DZSiScNpnUlY1gtGGApqSQ,4060
11
12
  lucidicai/singleton.py,sha256=gfT3XdWLXSIWMqDXbY6-pnesMZ8RGRitaEPhIsgrRPw,1272
12
13
  lucidicai/state.py,sha256=4Tb1X6l2or6w_e62FYSuEeghAv3xXm5gquKwzCpvdok,235
13
14
  lucidicai/step.py,sha256=_oBIyTBZBvNkUkYHIrwWd75KMSlMtR9Ws2Lo71Lyff8,2522
@@ -33,7 +34,7 @@ lucidicai/telemetry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
33
34
  lucidicai/telemetry/base_provider.py,sha256=nrZVr4Y9xcAiMn4uAN3t3k6DlHNTvlXrA4qQg7lANOQ,544
34
35
  lucidicai/telemetry/litellm_bridge.py,sha256=mOdjEfvP--ToDv8snoOMU4pRQx_Yg4s2o3BMTMzeRK8,14979
35
36
  lucidicai/telemetry/lucidic_exporter.py,sha256=h2GOnEk22Fpeke4Zc7SSk391yr0joUApVwolV5Q4hz4,10818
36
- lucidicai/telemetry/lucidic_span_processor.py,sha256=Hf15USiY2smfr29HXwmMRy7SNLwuLJg5wCUdLKjOp3Y,29420
37
+ lucidicai/telemetry/lucidic_span_processor.py,sha256=9EKD4fvnEQIoPBLhGCAHRxsLAWmJNGFnb1NpwRUlMOI,30048
37
38
  lucidicai/telemetry/openai_agents_instrumentor.py,sha256=__wIbeglMnEEf4AGTQ--FXeWCKmz2yy8SBupwprEdZA,12694
38
39
  lucidicai/telemetry/opentelemetry_converter.py,sha256=xOHCqoTyO4hUkL6k7fxy84PbljPpYep6ET9ZqbkJehc,17665
39
40
  lucidicai/telemetry/otel_handlers.py,sha256=HqGYIWJI_Vp8So2-HMpPjnrgTBSgBHHLDu01z_sq-Qk,14646
@@ -44,7 +45,7 @@ lucidicai/telemetry/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
44
45
  lucidicai/telemetry/utils/image_storage.py,sha256=4Z59ZpVexr7-lcExfr8GsqXe0y2VZmr8Yjwa-3DeOxU,1457
45
46
  lucidicai/telemetry/utils/text_storage.py,sha256=L62MMJ8E23TDqDTUv2aRntdKMCItsXV7XjY6cFwx2DE,1503
46
47
  lucidicai/telemetry/utils/universal_image_interceptor.py,sha256=zPfVsMjtKxJP2n2OOjKbtPiQJTZ0sf5_28GWprOnJP4,12185
47
- lucidicai-1.2.21.dist-info/METADATA,sha256=J9vZ_O1IedeJFTUJu7VynU7-RgADkqXDLSIOE8r_Oms,903
48
- lucidicai-1.2.21.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
49
- lucidicai-1.2.21.dist-info/top_level.txt,sha256=vSSdM3lclF4I5tyVC0xxUk8eIRnnYXMe1hW-eO91HUo,10
50
- lucidicai-1.2.21.dist-info/RECORD,,
48
+ lucidicai-1.3.0.dist-info/METADATA,sha256=wJHfG_fBDPiloTZwrdZVdJiHarwkamEDLT0rhb1mPfQ,902
49
+ lucidicai-1.3.0.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
50
+ lucidicai-1.3.0.dist-info/top_level.txt,sha256=vSSdM3lclF4I5tyVC0xxUk8eIRnnYXMe1hW-eO91HUo,10
51
+ lucidicai-1.3.0.dist-info/RECORD,,