lucidicai 1.2.14__py3-none-any.whl → 1.2.16__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 +18 -2
- lucidicai/client.py +19 -3
- lucidicai/event.py +2 -2
- lucidicai/model_pricing.py +14 -1
- lucidicai/providers/anthropic_handler.py +0 -7
- lucidicai/providers/langchain.py +0 -78
- lucidicai/providers/openai_handler.py +1 -56
- lucidicai/providers/pydantic_ai_handler.py +1 -18
- lucidicai/session.py +10 -4
- lucidicai/step.py +4 -4
- lucidicai/streaming.py +2 -3
- {lucidicai-1.2.14.dist-info → lucidicai-1.2.16.dist-info}/METADATA +1 -1
- lucidicai-1.2.16.dist-info/RECORD +25 -0
- lucidicai-1.2.14.dist-info/RECORD +0 -25
- {lucidicai-1.2.14.dist-info → lucidicai-1.2.16.dist-info}/WHEEL +0 -0
- {lucidicai-1.2.14.dist-info → lucidicai-1.2.16.dist-info}/top_level.txt +0 -0
lucidicai/__init__.py
CHANGED
|
@@ -101,9 +101,11 @@ def init(
|
|
|
101
101
|
agent_id: Optional[str] = None,
|
|
102
102
|
task: Optional[str] = None,
|
|
103
103
|
providers: Optional[List[ProviderType]] = [],
|
|
104
|
+
production_monitoring: Optional[bool] = False,
|
|
104
105
|
mass_sim_id: Optional[str] = None,
|
|
105
106
|
rubrics: Optional[list] = None,
|
|
106
107
|
tags: Optional[list] = None,
|
|
108
|
+
masking_function = None,
|
|
107
109
|
) -> str:
|
|
108
110
|
"""
|
|
109
111
|
Initialize the Lucidic client.
|
|
@@ -117,6 +119,7 @@ def init(
|
|
|
117
119
|
mass_sim_id: Optional mass simulation ID, if session is to be part of a mass simulation.
|
|
118
120
|
rubrics: Optional rubrics for evaluation, list of strings.
|
|
119
121
|
tags: Optional tags for the session, list of strings.
|
|
122
|
+
masking_function: Optional function to mask sensitive data.
|
|
120
123
|
|
|
121
124
|
Raises:
|
|
122
125
|
InvalidOperationError: If the client is already initialized.
|
|
@@ -137,6 +140,13 @@ def init(
|
|
|
137
140
|
if not getattr(client, 'initialized', False):
|
|
138
141
|
client = Client(lucidic_api_key=lucidic_api_key, agent_id=agent_id)
|
|
139
142
|
|
|
143
|
+
if not production_monitoring:
|
|
144
|
+
production_monitoring = os.getenv("LUCIDIC_PRODUCTION_MONITORING", False)
|
|
145
|
+
if production_monitoring == "True":
|
|
146
|
+
production_monitoring = True
|
|
147
|
+
else:
|
|
148
|
+
production_monitoring = False
|
|
149
|
+
|
|
140
150
|
# Set up providers
|
|
141
151
|
_setup_providers(client, providers)
|
|
142
152
|
session_id = client.init_session(
|
|
@@ -144,8 +154,11 @@ def init(
|
|
|
144
154
|
mass_sim_id=mass_sim_id,
|
|
145
155
|
task=task,
|
|
146
156
|
rubrics=rubrics,
|
|
147
|
-
tags=tags
|
|
157
|
+
tags=tags,
|
|
158
|
+
production_monitoring=production_monitoring,
|
|
148
159
|
)
|
|
160
|
+
if masking_function:
|
|
161
|
+
client.masking_function = masking_function
|
|
149
162
|
logger.info("Session initialized successfully")
|
|
150
163
|
return session_id
|
|
151
164
|
|
|
@@ -154,7 +167,8 @@ def continue_session(
|
|
|
154
167
|
session_id: str,
|
|
155
168
|
lucidic_api_key: Optional[str] = None,
|
|
156
169
|
agent_id: Optional[str] = None,
|
|
157
|
-
providers: Optional[List[ProviderType]] = []
|
|
170
|
+
providers: Optional[List[ProviderType]] = [],
|
|
171
|
+
masking_function = None,
|
|
158
172
|
):
|
|
159
173
|
if lucidic_api_key is None:
|
|
160
174
|
lucidic_api_key = os.getenv("LUCIDIC_API_KEY", None)
|
|
@@ -177,6 +191,8 @@ def continue_session(
|
|
|
177
191
|
# Set up providers
|
|
178
192
|
_setup_providers(client, providers)
|
|
179
193
|
session_id = client.continue_session(session_id=session_id)
|
|
194
|
+
if masking_function:
|
|
195
|
+
client.masking_function = masking_function
|
|
180
196
|
logger.info(f"Session {session_id} continuing...")
|
|
181
197
|
return session_id # For consistency
|
|
182
198
|
|
lucidicai/client.py
CHANGED
|
@@ -4,6 +4,7 @@ from datetime import datetime, timezone
|
|
|
4
4
|
from typing import Optional, Tuple
|
|
5
5
|
|
|
6
6
|
import requests
|
|
7
|
+
import logging
|
|
7
8
|
from requests.adapters import HTTPAdapter, Retry
|
|
8
9
|
from urllib3.util import Retry
|
|
9
10
|
|
|
@@ -30,6 +31,7 @@ class Client:
|
|
|
30
31
|
self.providers = []
|
|
31
32
|
self.api_key = lucidic_api_key
|
|
32
33
|
self.agent_id = agent_id
|
|
34
|
+
self.masking_function = None
|
|
33
35
|
self.request_session = requests.Session()
|
|
34
36
|
retry_cfg = Retry(
|
|
35
37
|
total=3, # 3 attempts in total
|
|
@@ -73,7 +75,8 @@ class Client:
|
|
|
73
75
|
mass_sim_id: Optional[str] = None,
|
|
74
76
|
task: Optional[str] = None,
|
|
75
77
|
rubrics: Optional[list] = None,
|
|
76
|
-
tags: Optional[list] = None
|
|
78
|
+
tags: Optional[list] = None,
|
|
79
|
+
production_monitoring: Optional[bool] = False
|
|
77
80
|
) -> None:
|
|
78
81
|
self.session = Session(
|
|
79
82
|
agent_id=self.agent_id,
|
|
@@ -81,7 +84,8 @@ class Client:
|
|
|
81
84
|
mass_sim_id=mass_sim_id,
|
|
82
85
|
task=task,
|
|
83
86
|
rubrics=rubrics,
|
|
84
|
-
tags=tags
|
|
87
|
+
tags=tags,
|
|
88
|
+
production_monitoring=production_monitoring
|
|
85
89
|
)
|
|
86
90
|
self.initialized = True
|
|
87
91
|
return self.session.session_id
|
|
@@ -147,4 +151,16 @@ class Client:
|
|
|
147
151
|
response.raise_for_status()
|
|
148
152
|
except requests.exceptions.HTTPError as e:
|
|
149
153
|
raise InvalidOperationError(f"Request to Lucidic AI Backend failed: {e.response.text}")
|
|
150
|
-
return response.json()
|
|
154
|
+
return response.json()
|
|
155
|
+
|
|
156
|
+
def mask(self, data):
|
|
157
|
+
if not self.masking_function:
|
|
158
|
+
return data
|
|
159
|
+
if not data:
|
|
160
|
+
return data
|
|
161
|
+
try:
|
|
162
|
+
return self.masking_function(data)
|
|
163
|
+
except Exception as e:
|
|
164
|
+
logger = logging.getLogger('Lucidic')
|
|
165
|
+
logger.error(f"Error in custom masking function: {repr(e)}")
|
|
166
|
+
return "<Error in custom masking function, this is a fully-masked placeholder>"
|
lucidicai/event.py
CHANGED
|
@@ -40,8 +40,8 @@ class Event:
|
|
|
40
40
|
self.is_finished = kwargs['is_finished']
|
|
41
41
|
request_data = {
|
|
42
42
|
"event_id": self.event_id,
|
|
43
|
-
"description": kwargs.get("description", None),
|
|
44
|
-
"result": kwargs.get("result", None),
|
|
43
|
+
"description": Client().mask(kwargs.get("description", None)),
|
|
44
|
+
"result": Client().mask(kwargs.get("result", None)),
|
|
45
45
|
"is_finished": self.is_finished,
|
|
46
46
|
"cost_added": kwargs.get("cost_added", None),
|
|
47
47
|
"model": kwargs.get("model", None),
|
lucidicai/model_pricing.py
CHANGED
|
@@ -141,6 +141,7 @@ MODEL_PRICING = {
|
|
|
141
141
|
"deepseek-ai/deepseek-r1-distill-llama-70b": {"input": 0.75, "output": 0.99},
|
|
142
142
|
"deepseek-coder": {"input": 0.14, "output": 0.28},
|
|
143
143
|
"deepseek-chat": {"input": 0.14, "output": 0.28},
|
|
144
|
+
"deepseek/deepseek-v3-0324": {"input": 0.14, "output": 0.28},
|
|
144
145
|
|
|
145
146
|
# Qwen Models
|
|
146
147
|
"qwen-qwq-32b": {"input": 0.29, "output": 0.39},
|
|
@@ -148,6 +149,8 @@ MODEL_PRICING = {
|
|
|
148
149
|
"qwen-turbo": {"input": 0.3, "output": 0.6},
|
|
149
150
|
"qwen-plus": {"input": 0.5, "output": 2.0},
|
|
150
151
|
"qwen-max": {"input": 2.0, "output": 6.0},
|
|
152
|
+
"qwen2.5-32b-instruct": {"input": 0.7, "output": "2.8"},
|
|
153
|
+
"qwen2.5-max": {"input": 1.6, "output": 6.4},
|
|
151
154
|
|
|
152
155
|
# Google Gemma Models
|
|
153
156
|
"gemma-2-9b": {"input": 0.20, "output": 0.20},
|
|
@@ -163,7 +166,14 @@ MODEL_PRICING = {
|
|
|
163
166
|
"pplx-7b-chat": {"input": 0.07, "output": 0.28},
|
|
164
167
|
"pplx-70b-chat": {"input": 0.7, "output": 2.8},
|
|
165
168
|
"pplx-7b-online": {"input": 0.07, "output": 0.28},
|
|
166
|
-
"pplx-70b-online": {"input": 0.7, "output": 2.8}
|
|
169
|
+
"pplx-70b-online": {"input": 0.7, "output": 2.8},
|
|
170
|
+
|
|
171
|
+
# Grok Models
|
|
172
|
+
"grok-3-latest": {"input": 3, "output": 15},
|
|
173
|
+
"grok-3": {"input": 3, "output": 15},
|
|
174
|
+
"grok-3-fast": {"input": 5, "output": 25},
|
|
175
|
+
"grok-3-mini": {"input": 0.3, "output": 0.5},
|
|
176
|
+
"grok-3-mini-fast": {"input": 0.6, "output": 4},
|
|
167
177
|
|
|
168
178
|
}
|
|
169
179
|
|
|
@@ -179,6 +189,7 @@ PROVIDER_AVERAGES = {
|
|
|
179
189
|
"qwen": {"input": 0.5, "output": 1.0}, # Qwen average
|
|
180
190
|
"together": {"input": 0.15, "output": 0.15}, # Together AI average
|
|
181
191
|
"perplexity": {"input": 0.4, "output": 1.5}, # Perplexity average
|
|
192
|
+
"grok": {"input": 2.4, "output": 12}, # Grok average
|
|
182
193
|
}
|
|
183
194
|
|
|
184
195
|
def get_provider_from_model(model: str) -> str:
|
|
@@ -205,6 +216,8 @@ def get_provider_from_model(model: str) -> str:
|
|
|
205
216
|
return "together"
|
|
206
217
|
elif any(pplx in model_lower for pplx in ["pplx", "perplexity"]):
|
|
207
218
|
return "perplexity"
|
|
219
|
+
elif any(grok in model_lower for grok in ["grok", "xAI"]):
|
|
220
|
+
return "grok"
|
|
208
221
|
else:
|
|
209
222
|
return "unknown"
|
|
210
223
|
|
|
@@ -51,7 +51,6 @@ class AnthropicHandler(BaseProvider):
|
|
|
51
51
|
return " ".join(descriptions), screenshots
|
|
52
52
|
|
|
53
53
|
def handle_response(self, response, kwargs):
|
|
54
|
-
event = Client().session.active_step
|
|
55
54
|
|
|
56
55
|
# for synchronous streaming responses
|
|
57
56
|
if isinstance(response, Stream):
|
|
@@ -222,9 +221,6 @@ class AnthropicHandler(BaseProvider):
|
|
|
222
221
|
self.original_create_async = AsyncMessages.create
|
|
223
222
|
|
|
224
223
|
def patched_create(*args, **kwargs):
|
|
225
|
-
step = Client().session.active_step
|
|
226
|
-
if not step:
|
|
227
|
-
return self.original_create(*args, **kwargs)
|
|
228
224
|
description, images = self._format_messages(kwargs.get("messages", []))
|
|
229
225
|
|
|
230
226
|
event_id = Client().session.create_event(
|
|
@@ -237,9 +233,6 @@ class AnthropicHandler(BaseProvider):
|
|
|
237
233
|
return self.handle_response(result, kwargs)
|
|
238
234
|
|
|
239
235
|
async def patched_create_async(*args, **kwargs):
|
|
240
|
-
step = Client().session.active_step
|
|
241
|
-
if not step:
|
|
242
|
-
return self.original_create_async(*args, **kwargs)
|
|
243
236
|
description, images = self._format_messages(kwargs.get("messages", []))
|
|
244
237
|
|
|
245
238
|
event_id = Client().session.create_event(
|
lucidicai/providers/langchain.py
CHANGED
|
@@ -63,11 +63,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
63
63
|
text.append(prompt)
|
|
64
64
|
elif isinstance(prompt, dict) and 'image' in prompt:
|
|
65
65
|
images.append(prompt['image'])
|
|
66
|
-
|
|
67
|
-
# Make sure we have a valid session and step
|
|
68
|
-
if not (Client().session and Client().session.active_step):
|
|
69
|
-
logger.warning("Cannot create event - no active session or step")
|
|
70
|
-
return
|
|
71
66
|
|
|
72
67
|
try:
|
|
73
68
|
# Create a new event
|
|
@@ -112,12 +107,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
112
107
|
image_url = block.get("image_url", "")
|
|
113
108
|
image_str = image_url.get('url', "")
|
|
114
109
|
images_b64.append(image_str[image_str.find(',') + 1:])
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
# Make sure we have a valid session and step
|
|
118
|
-
if not (Client().session and Client().session.active_step):
|
|
119
|
-
logger.warning("Cannot create event - no active session or step")
|
|
120
|
-
return
|
|
121
110
|
|
|
122
111
|
try:
|
|
123
112
|
# Create a new event
|
|
@@ -157,11 +146,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
157
146
|
message = response.generations[0][0].message
|
|
158
147
|
usage = message.usage_metadata
|
|
159
148
|
cost = calculate_cost(model, usage)
|
|
160
|
-
|
|
161
|
-
# Make sure we have a valid session
|
|
162
|
-
if not (Client().session and Client().session.active_step):
|
|
163
|
-
logger.warning("Cannot end event - no active session or step")
|
|
164
|
-
return
|
|
165
149
|
|
|
166
150
|
try:
|
|
167
151
|
if run_str in self.run_to_event:
|
|
@@ -206,11 +190,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
206
190
|
logger.debug("Handling LLM error in Langchain Handler, ending event...")
|
|
207
191
|
run_str = str(run_id)
|
|
208
192
|
model = self.run_to_model.get(run_str, "unknown")
|
|
209
|
-
|
|
210
|
-
# Make sure we have a valid session
|
|
211
|
-
if not (Client().session and Client().session.active_step):
|
|
212
|
-
logger.warning("Cannot end event - no active session or step")
|
|
213
|
-
return
|
|
214
193
|
|
|
215
194
|
try:
|
|
216
195
|
if run_str in self.run_to_event:
|
|
@@ -266,12 +245,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
266
245
|
image_url = block.get("image_url", "")
|
|
267
246
|
image_str = image_url.get('url', "")
|
|
268
247
|
images_b64.append(image_str[image_str.find(',') + 1:])
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
# Make sure we have a valid session and step
|
|
272
|
-
if not (Client().session and Client().session.active_step):
|
|
273
|
-
logger.warning("Cannot create event - no active session or step")
|
|
274
|
-
return
|
|
275
248
|
|
|
276
249
|
try:
|
|
277
250
|
# Create a new event
|
|
@@ -285,11 +258,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
285
258
|
logger.debug("Ending chain execution in Langchain Handler, ending event...")
|
|
286
259
|
run_id = str(kwargs.get("run_id", "unknown"))
|
|
287
260
|
|
|
288
|
-
# Make sure we have a valid session
|
|
289
|
-
if not (Client().session and Client().session.active_step):
|
|
290
|
-
logger.warning("Cannot end event - no active session or step")
|
|
291
|
-
return
|
|
292
|
-
|
|
293
261
|
# Extract result from outputs
|
|
294
262
|
result = None
|
|
295
263
|
if outputs:
|
|
@@ -321,11 +289,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
321
289
|
"""Handle chain errors"""
|
|
322
290
|
logger.debug("Handling chain error in Langchain Handler, ending event...")
|
|
323
291
|
run_id = str(kwargs.get("run_id", "unknown"))
|
|
324
|
-
|
|
325
|
-
# Make sure we have a valid session
|
|
326
|
-
if not (Client().session and Client().session.active_step):
|
|
327
|
-
logger.warning("Cannot end event - no active session or step")
|
|
328
|
-
return
|
|
329
292
|
|
|
330
293
|
try:
|
|
331
294
|
if run_id in self.run_to_event:
|
|
@@ -352,11 +315,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
352
315
|
run_id = str(kwargs.get("run_id", "unknown"))
|
|
353
316
|
tool_name = serialized.get("name", "Unknown Tool")
|
|
354
317
|
description = f"Tool Call ({tool_name}): {input_str[:100]}..."
|
|
355
|
-
|
|
356
|
-
# Make sure we have a valid session and step
|
|
357
|
-
if not (Client().session and Client().session.active_step):
|
|
358
|
-
logger.warning("Cannot create event - no active session or step")
|
|
359
|
-
return
|
|
360
318
|
|
|
361
319
|
try:
|
|
362
320
|
# Create event
|
|
@@ -372,11 +330,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
372
330
|
logger.debug("Ending tool execution in Langchain Handler, ending event...")
|
|
373
331
|
run_id = str(kwargs.get("run_id", "unknown"))
|
|
374
332
|
|
|
375
|
-
# Make sure we have a valid session and step
|
|
376
|
-
if not (Client().session and Client().session.active_step):
|
|
377
|
-
logger.warning("Cannot end event - no active session or step")
|
|
378
|
-
return
|
|
379
|
-
|
|
380
333
|
# Get result from output
|
|
381
334
|
result = None
|
|
382
335
|
if output is not None:
|
|
@@ -404,11 +357,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
404
357
|
"""
|
|
405
358
|
logger.debug("Handling tool error in Langchain Handler, ending event...")
|
|
406
359
|
run_id = str(kwargs.get("run_id", "unknown"))
|
|
407
|
-
|
|
408
|
-
# Make sure we have a valid session and step
|
|
409
|
-
if not (Client().session and Client().session.active_step):
|
|
410
|
-
logger.warning("Cannot end event - no active session or step")
|
|
411
|
-
return
|
|
412
360
|
|
|
413
361
|
try:
|
|
414
362
|
if run_id in self.run_to_event:
|
|
@@ -434,11 +382,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
434
382
|
run_id = str(kwargs.get("run_id", "unknown"))
|
|
435
383
|
retriever_type = serialized.get("name", "Unknown Retriever")
|
|
436
384
|
description = f"Retriever ({retriever_type}): {query[:100]}..."
|
|
437
|
-
|
|
438
|
-
# Make sure we have a valid session and step
|
|
439
|
-
if not (Client().session and Client().session.active_step):
|
|
440
|
-
logger.warning("Cannot create event - no active session or step")
|
|
441
|
-
return
|
|
442
385
|
|
|
443
386
|
try:
|
|
444
387
|
# Create event
|
|
@@ -454,11 +397,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
454
397
|
logger.debug("Ending retriever execution in Langchain Handler, ending event...")
|
|
455
398
|
run_id = str(kwargs.get("run_id", "unknown"))
|
|
456
399
|
|
|
457
|
-
# Make sure we have a valid session and step
|
|
458
|
-
if not (Client().session and Client().session.active_step):
|
|
459
|
-
logger.warning("Cannot end event - no active session or step")
|
|
460
|
-
return
|
|
461
|
-
|
|
462
400
|
# Extract result from documents
|
|
463
401
|
result = None
|
|
464
402
|
if documents:
|
|
@@ -493,11 +431,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
493
431
|
"""
|
|
494
432
|
logger.debug("Handling retriever error in Langchain Handler, ending event...")
|
|
495
433
|
run_id = str(kwargs.get("run_id", "unknown"))
|
|
496
|
-
|
|
497
|
-
# Make sure we have a valid session and step
|
|
498
|
-
if not (Client().session and Client().session.active_step):
|
|
499
|
-
logger.warning("Cannot end event - no active session or step")
|
|
500
|
-
return
|
|
501
434
|
|
|
502
435
|
try:
|
|
503
436
|
if run_id in self.run_to_event:
|
|
@@ -524,11 +457,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
524
457
|
tool = getattr(action, 'tool', 'unknown_tool')
|
|
525
458
|
description = f"Agent Action: {tool}"
|
|
526
459
|
|
|
527
|
-
# Make sure we have a valid session and step
|
|
528
|
-
if not (Client().session and Client().session.active_step):
|
|
529
|
-
logger.warning("Cannot create event - no active session or step")
|
|
530
|
-
return
|
|
531
|
-
|
|
532
460
|
# Extract useful information from the action
|
|
533
461
|
result = None
|
|
534
462
|
try:
|
|
@@ -571,12 +499,6 @@ class LucidicLangchainHandler(BaseCallbackHandler):
|
|
|
571
499
|
"""
|
|
572
500
|
logger.debug("Handling agent finish in Langchain Handler, ending event...")
|
|
573
501
|
run_id = str(kwargs.get("run_id", "unknown"))
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
# Make sure we have a valid session and step
|
|
577
|
-
if not (Client().session and Client().session.active_step):
|
|
578
|
-
logger.warning("Cannot end event - no active session or step")
|
|
579
|
-
return
|
|
580
502
|
|
|
581
503
|
# Extract result from finish
|
|
582
504
|
result = None
|
|
@@ -122,20 +122,7 @@ class OpenAIHandler(BaseProvider):
|
|
|
122
122
|
if session is None:
|
|
123
123
|
logger.info(f"[OpenAI Handler] No session, skipping tracking")
|
|
124
124
|
return await original_method(*args, **kwargs)
|
|
125
|
-
|
|
126
|
-
# Auto-create step if no active step exists
|
|
127
|
-
if session.active_step is None:
|
|
128
|
-
logger.info(f"[OpenAI Handler] No active step, auto-creating step")
|
|
129
|
-
try:
|
|
130
|
-
step_id = session.create_step(
|
|
131
|
-
state="Auto-created step for API call",
|
|
132
|
-
action=f"Execute {method_name}",
|
|
133
|
-
goal="Process API request"
|
|
134
|
-
)
|
|
135
|
-
logger.info(f"[OpenAI Handler] Created step: {step_id}")
|
|
136
|
-
except Exception as e:
|
|
137
|
-
logger.error(f"[OpenAI Handler] Failed to auto-create step: {e}")
|
|
138
|
-
return await original_method(*args, **kwargs)
|
|
125
|
+
|
|
139
126
|
|
|
140
127
|
# Prepare kwargs
|
|
141
128
|
self._prepare_streaming_kwargs(method_name, kwargs)
|
|
@@ -157,20 +144,6 @@ class OpenAIHandler(BaseProvider):
|
|
|
157
144
|
logger.info(f"[OpenAI Handler] No session, skipping tracking")
|
|
158
145
|
return original_method(*args, **kwargs)
|
|
159
146
|
|
|
160
|
-
# Auto-create step if no active step exists
|
|
161
|
-
if session.active_step is None:
|
|
162
|
-
logger.info(f"[OpenAI Handler] No active step, auto-creating step")
|
|
163
|
-
try:
|
|
164
|
-
step_id = session.create_step(
|
|
165
|
-
state="Auto-created step for API call",
|
|
166
|
-
action=f"Execute {method_name}",
|
|
167
|
-
goal="Process API request"
|
|
168
|
-
)
|
|
169
|
-
logger.info(f"[OpenAI Handler] Created step: {step_id}")
|
|
170
|
-
except Exception as e:
|
|
171
|
-
logger.error(f"[OpenAI Handler] Failed to auto-create step: {e}")
|
|
172
|
-
return original_method(*args, **kwargs)
|
|
173
|
-
|
|
174
147
|
# Prepare kwargs
|
|
175
148
|
self._prepare_streaming_kwargs(method_name, kwargs)
|
|
176
149
|
|
|
@@ -394,20 +367,6 @@ class OpenAIHandler(BaseProvider):
|
|
|
394
367
|
logger.info(f"[OpenAI Handler] No session, skipping tracking")
|
|
395
368
|
return await original_method(*args, **kwargs)
|
|
396
369
|
|
|
397
|
-
# Auto-create step if no active step exists
|
|
398
|
-
if session.active_step is None:
|
|
399
|
-
logger.info(f"[OpenAI Handler] No active step, auto-creating step")
|
|
400
|
-
try:
|
|
401
|
-
step_id = session.create_step(
|
|
402
|
-
state="Auto-created step for responses API call",
|
|
403
|
-
action="Execute responses.create",
|
|
404
|
-
goal="Process API request"
|
|
405
|
-
)
|
|
406
|
-
logger.info(f"[OpenAI Handler] Created step: {step_id}")
|
|
407
|
-
except Exception as e:
|
|
408
|
-
logger.error(f"[OpenAI Handler] Failed to auto-create step: {e}")
|
|
409
|
-
return await original_method(*args, **kwargs)
|
|
410
|
-
|
|
411
370
|
# Check for agent context
|
|
412
371
|
agent_name = self._get_agent_name_from_input(kwargs.get('input', []))
|
|
413
372
|
|
|
@@ -500,20 +459,6 @@ class OpenAIHandler(BaseProvider):
|
|
|
500
459
|
logger.info(f"[OpenAI Handler] No session, skipping tracking")
|
|
501
460
|
return original_method(*args, **kwargs)
|
|
502
461
|
|
|
503
|
-
# Auto-create step if no active step exists
|
|
504
|
-
if session.active_step is None:
|
|
505
|
-
logger.info(f"[OpenAI Handler] No active step, auto-creating step")
|
|
506
|
-
try:
|
|
507
|
-
step_id = session.create_step(
|
|
508
|
-
state="Auto-created step for responses API call",
|
|
509
|
-
action="Execute responses.create",
|
|
510
|
-
goal="Process API request"
|
|
511
|
-
)
|
|
512
|
-
logger.info(f"[OpenAI Handler] Created step: {step_id}")
|
|
513
|
-
except Exception as e:
|
|
514
|
-
logger.error(f"[OpenAI Handler] Failed to auto-create step: {e}")
|
|
515
|
-
return original_method(*args, **kwargs)
|
|
516
|
-
|
|
517
462
|
# Check for agent context
|
|
518
463
|
agent_name = self._get_agent_name_from_input(kwargs.get('input', []))
|
|
519
464
|
|
|
@@ -381,11 +381,6 @@ class PydanticAIHandler(BaseProvider):
|
|
|
381
381
|
|
|
382
382
|
def _wrap_request(self, model_instance, messages, model_settings, model_request_parameters, original_method):
|
|
383
383
|
"""Wrap regular request method to track LLM calls"""
|
|
384
|
-
# Create event before API call
|
|
385
|
-
step = Client().session.active_step
|
|
386
|
-
if step is None:
|
|
387
|
-
return original_method(model_instance, messages, model_settings, model_request_parameters)
|
|
388
|
-
|
|
389
384
|
description = self._format_messages(messages)
|
|
390
385
|
event_id = Client().session.create_event(
|
|
391
386
|
description=description,
|
|
@@ -412,13 +407,6 @@ class PydanticAIHandler(BaseProvider):
|
|
|
412
407
|
|
|
413
408
|
def _wrap_request_stream_context_manager(self, model_instance, messages, model_settings, model_request_parameters, original_method):
|
|
414
409
|
"""Return an async context manager for streaming requests"""
|
|
415
|
-
# Create event before API call
|
|
416
|
-
event_id = None
|
|
417
|
-
step = Client().session.active_step
|
|
418
|
-
|
|
419
|
-
if step is None:
|
|
420
|
-
return original_method(model_instance, messages, model_settings, model_request_parameters)
|
|
421
|
-
|
|
422
410
|
description = self._format_messages(messages)
|
|
423
411
|
event_id = Client().session.create_event(
|
|
424
412
|
description=description,
|
|
@@ -466,13 +454,8 @@ class PydanticAIHandler(BaseProvider):
|
|
|
466
454
|
|
|
467
455
|
async def _wrap_request_stream(self, model_instance, messages, model_settings, model_request_parameters, original_method):
|
|
468
456
|
"""Wrap streaming request method"""
|
|
469
|
-
# Create event before API call
|
|
470
|
-
step = Client().session.active_step
|
|
471
|
-
if step is None:
|
|
472
|
-
return original_method(model_instance, messages, model_settings, model_request_parameters)
|
|
473
|
-
|
|
474
457
|
description = self._format_messages(messages)
|
|
475
|
-
event =
|
|
458
|
+
event = Client().session.create_event(
|
|
476
459
|
description=description,
|
|
477
460
|
result="Streaming response..."
|
|
478
461
|
)
|
lucidicai/session.py
CHANGED
|
@@ -43,7 +43,8 @@ class Session:
|
|
|
43
43
|
"task": kwargs.get("task", None),
|
|
44
44
|
"mass_sim_id": kwargs.get("mass_sim_id", None),
|
|
45
45
|
"rubrics": kwargs.get("rubrics", None),
|
|
46
|
-
"tags": kwargs.get("tags", None)
|
|
46
|
+
"tags": kwargs.get("tags", None),
|
|
47
|
+
"production_monitoring": kwargs.get("production_monitoring", False)
|
|
47
48
|
}
|
|
48
49
|
data = Client().make_request('initsession', 'POST', request_data)
|
|
49
50
|
self.session_id = data["session_id"]
|
|
@@ -73,9 +74,9 @@ class Session:
|
|
|
73
74
|
"is_finished": kwargs.get("is_finished", None),
|
|
74
75
|
"task": kwargs.get("task", None),
|
|
75
76
|
"is_successful": kwargs.get("is_successful", None),
|
|
76
|
-
"is_successful_reason": kwargs.get("is_successful_reason", None),
|
|
77
|
+
"is_successful_reason": Client().mask(kwargs.get("is_successful_reason", None)),
|
|
77
78
|
"session_eval": kwargs.get("session_eval", None),
|
|
78
|
-
"session_eval_reason": kwargs.get("session_eval_reason", None),
|
|
79
|
+
"session_eval_reason": Client().mask(kwargs.get("session_eval_reason", None)),
|
|
79
80
|
"tags": kwargs.get("tags", None)
|
|
80
81
|
}
|
|
81
82
|
Client().make_request('updatesession', 'PUT', request_data)
|
|
@@ -101,12 +102,14 @@ class Session:
|
|
|
101
102
|
|
|
102
103
|
def create_event(self, **kwargs):
|
|
103
104
|
# Get step_id from kwargs or active step
|
|
105
|
+
temp_step_created = False
|
|
104
106
|
if 'step_id' in kwargs and kwargs['step_id'] is not None:
|
|
105
107
|
step_id = kwargs['step_id']
|
|
106
108
|
elif self._active_step:
|
|
107
109
|
step_id = self._active_step
|
|
108
110
|
else:
|
|
109
|
-
|
|
111
|
+
step_id = self.create_step()
|
|
112
|
+
temp_step_created = True
|
|
110
113
|
kwargs.pop('step_id', None)
|
|
111
114
|
event = Event(
|
|
112
115
|
session_id=self.session_id,
|
|
@@ -115,6 +118,9 @@ class Session:
|
|
|
115
118
|
)
|
|
116
119
|
self.event_history[event.event_id] = event
|
|
117
120
|
self._active_event = event
|
|
121
|
+
if temp_step_created:
|
|
122
|
+
self.update_step(step_id=step_id, is_finished=True)
|
|
123
|
+
self._active_step = None
|
|
118
124
|
return event.event_id
|
|
119
125
|
|
|
120
126
|
def update_event(self, **kwargs):
|
lucidicai/step.py
CHANGED
|
@@ -48,11 +48,11 @@ class Step:
|
|
|
48
48
|
upload_image_to_s3(presigned_url, screenshot, "JPEG")
|
|
49
49
|
request_data = {
|
|
50
50
|
"step_id": self.step_id,
|
|
51
|
-
"goal": kwargs['goal'] if 'goal' in kwargs else None,
|
|
52
|
-
"action": kwargs['action'] if 'action' in kwargs else None,
|
|
53
|
-
"state": kwargs['state'] if 'state' in kwargs else None,
|
|
51
|
+
"goal": Client().mask(kwargs['goal']) if 'goal' in kwargs else None,
|
|
52
|
+
"action": Client().mask(kwargs['action']) if 'action' in kwargs else None,
|
|
53
|
+
"state": Client().mask(kwargs['state']) if 'state' in kwargs else None,
|
|
54
54
|
"eval_score": kwargs['eval_score'] if 'eval_score' in kwargs else None,
|
|
55
|
-
"eval_description": kwargs['eval_description'] if 'eval_description' in kwargs else None,
|
|
55
|
+
"eval_description": Client().mask(kwargs['eval_description']) if 'eval_description' in kwargs else None,
|
|
56
56
|
"is_finished": kwargs['is_finished'] if 'is_finished' in kwargs else None,
|
|
57
57
|
"has_screenshot": True if screenshot else None
|
|
58
58
|
}
|
lucidicai/streaming.py
CHANGED
|
@@ -14,7 +14,6 @@ class StreamingResponseWrapper:
|
|
|
14
14
|
|
|
15
15
|
def __init__(self, response: Any, session: Any, kwargs: Dict[str, Any]):
|
|
16
16
|
self.response = response
|
|
17
|
-
self.session = session
|
|
18
17
|
self.kwargs = kwargs
|
|
19
18
|
self.chunks = []
|
|
20
19
|
self.start_time = time.time()
|
|
@@ -34,7 +33,7 @@ class StreamingResponseWrapper:
|
|
|
34
33
|
logger.info(f"[Streaming] Using existing event ID: {self.event_id}")
|
|
35
34
|
return
|
|
36
35
|
|
|
37
|
-
if
|
|
36
|
+
if Client().session:
|
|
38
37
|
description, images = self._format_messages(self.kwargs.get('messages', ''))
|
|
39
38
|
|
|
40
39
|
event_data = {
|
|
@@ -54,7 +53,7 @@ class StreamingResponseWrapper:
|
|
|
54
53
|
if images:
|
|
55
54
|
event_data['screenshots'] = images
|
|
56
55
|
|
|
57
|
-
self.event_id =
|
|
56
|
+
self.event_id = Client().session.create_event(**event_data)
|
|
58
57
|
logger.debug(f"[Streaming] Created new streaming event with ID: {self.event_id}")
|
|
59
58
|
except Exception as e:
|
|
60
59
|
logger.error(f"[Streaming] Error creating initial streaming event: {str(e)}")
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
lucidicai/__init__.py,sha256=-4tgIeJ0MIxxA-AfQ7xbyo3hCUXXRGFHLGurrjq3xdM,17680
|
|
2
|
+
lucidicai/action.py,sha256=sPRd1hTIVXDqnvG9ZXWEipUFh0bsXcE0Fm7RVqmVccM,237
|
|
3
|
+
lucidicai/client.py,sha256=jBEQFiLP6cLXmL_jrZt6LCWEfjPaEIf9VqAJFSNTBaM,6299
|
|
4
|
+
lucidicai/constants.py,sha256=_u0z3M4geZgS1g-CrOZUVjtcew8l70dKQnpVQvlXh9w,2172
|
|
5
|
+
lucidicai/errors.py,sha256=gTg0bdzjuTcUnakRbZnxjngO4gZnRLVwRHRglpZZJsM,970
|
|
6
|
+
lucidicai/event.py,sha256=2j5G4drwVhmdQkk9-armYQj1ctmLm2H_rNfPsfV_8wA,2004
|
|
7
|
+
lucidicai/image_upload.py,sha256=ShacoEaGXbQESatfp-CrIygsDntt9IkcCqZcc9uLZVQ,3130
|
|
8
|
+
lucidicai/model_pricing.py,sha256=Q_Kd8OtKPqtvZ4pIh__ztKb3RXe-cX-8xgrM-AIUj9E,12189
|
|
9
|
+
lucidicai/session.py,sha256=OqcAAVaAChbPxpUy9ciHDb1YuznmCfHEOAfIsfb8Kgw,5162
|
|
10
|
+
lucidicai/singleton.py,sha256=gfT3XdWLXSIWMqDXbY6-pnesMZ8RGRitaEPhIsgrRPw,1272
|
|
11
|
+
lucidicai/state.py,sha256=4Tb1X6l2or6w_e62FYSuEeghAv3xXm5gquKwzCpvdok,235
|
|
12
|
+
lucidicai/step.py,sha256=_oBIyTBZBvNkUkYHIrwWd75KMSlMtR9Ws2Lo71Lyff8,2522
|
|
13
|
+
lucidicai/streaming.py,sha256=Y59vQOqhcOvTQWSAIamAnGCaQqCZz77N62_V2fuQlFA,11565
|
|
14
|
+
lucidicai/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
lucidicai/providers/anthropic_handler.py,sha256=GZEa4QOrjZ9ftu_qTwY3L410HwKzkXgN7omYRsEQ4LU,10174
|
|
16
|
+
lucidicai/providers/base_providers.py,sha256=nrZVr4Y9xcAiMn4uAN3t3k6DlHNTvlXrA4qQg7lANOQ,544
|
|
17
|
+
lucidicai/providers/langchain.py,sha256=xLJPFV2hfCOXsundCUZiYBf-g0dS5MDUYKoz22W8fO8,22184
|
|
18
|
+
lucidicai/providers/openai_agents_handler.py,sha256=AAMtY7HZ-7UvTn1RVwd-uHhibJusZoOnWSw32xNcewo,18957
|
|
19
|
+
lucidicai/providers/openai_handler.py,sha256=CrFlM7RUAQjOmqWjAkV71dBRhe7gu-YEKXtSHfb70DE,32119
|
|
20
|
+
lucidicai/providers/opentelemetry_converter.py,sha256=xOHCqoTyO4hUkL6k7fxy84PbljPpYep6ET9ZqbkJehc,17665
|
|
21
|
+
lucidicai/providers/pydantic_ai_handler.py,sha256=Rpi3c8XWmA_RUyRqzKWshbulJMD9hapTQCUig2h0yzo,28262
|
|
22
|
+
lucidicai-1.2.16.dist-info/METADATA,sha256=bnXc6fwTJrxlu59g2mSZVsq_gFGIQIYGZ6olKBFBblo,577
|
|
23
|
+
lucidicai-1.2.16.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
|
|
24
|
+
lucidicai-1.2.16.dist-info/top_level.txt,sha256=vSSdM3lclF4I5tyVC0xxUk8eIRnnYXMe1hW-eO91HUo,10
|
|
25
|
+
lucidicai-1.2.16.dist-info/RECORD,,
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
lucidicai/__init__.py,sha256=sNUGk7kd2IsjL39WgRkc7VuulRbFB5o1liK_65iEH9E,17034
|
|
2
|
-
lucidicai/action.py,sha256=sPRd1hTIVXDqnvG9ZXWEipUFh0bsXcE0Fm7RVqmVccM,237
|
|
3
|
-
lucidicai/client.py,sha256=axJ9JjDq6qIuyyYtiQlMREPTKD_eKve-0pOBKHH7HZg,5695
|
|
4
|
-
lucidicai/constants.py,sha256=_u0z3M4geZgS1g-CrOZUVjtcew8l70dKQnpVQvlXh9w,2172
|
|
5
|
-
lucidicai/errors.py,sha256=gTg0bdzjuTcUnakRbZnxjngO4gZnRLVwRHRglpZZJsM,970
|
|
6
|
-
lucidicai/event.py,sha256=9Z1yuP7Pef0sdXABU9SCHCLZSu6DfK--uGZoq-a9_IA,1974
|
|
7
|
-
lucidicai/image_upload.py,sha256=ShacoEaGXbQESatfp-CrIygsDntt9IkcCqZcc9uLZVQ,3130
|
|
8
|
-
lucidicai/model_pricing.py,sha256=benQS2sp0-bboqP13e9l3ZYaYJcoqdIjHEaufCWoNw4,11599
|
|
9
|
-
lucidicai/session.py,sha256=goLQxBvXkLT5kS3eSfht3IFqvfYfgULC4eECSIanrPc,4909
|
|
10
|
-
lucidicai/singleton.py,sha256=gfT3XdWLXSIWMqDXbY6-pnesMZ8RGRitaEPhIsgrRPw,1272
|
|
11
|
-
lucidicai/state.py,sha256=4Tb1X6l2or6w_e62FYSuEeghAv3xXm5gquKwzCpvdok,235
|
|
12
|
-
lucidicai/step.py,sha256=egDmr3z3ZXu5nBJqeepj0Ml3ifDuyg07OwTB6vOJCaY,2462
|
|
13
|
-
lucidicai/streaming.py,sha256=wQ32xMCHvaNaM6OQoAhY-yS5KoLi71KQPCbcxjpLzbU,11658
|
|
14
|
-
lucidicai/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
lucidicai/providers/anthropic_handler.py,sha256=h6T_Iw0jcpwMhozAb8jOf6L_PihCKVaSScMBBA_otI0,10493
|
|
16
|
-
lucidicai/providers/base_providers.py,sha256=nrZVr4Y9xcAiMn4uAN3t3k6DlHNTvlXrA4qQg7lANOQ,544
|
|
17
|
-
lucidicai/providers/langchain.py,sha256=SSzgoY9UQ1kWuxYpgk1zil2EJGIVGyeWOVAPFvCifNQ,25521
|
|
18
|
-
lucidicai/providers/openai_agents_handler.py,sha256=AAMtY7HZ-7UvTn1RVwd-uHhibJusZoOnWSw32xNcewo,18957
|
|
19
|
-
lucidicai/providers/openai_handler.py,sha256=j2SW3YlGY1FhMO7d03WaIRxAtti6xATnoo2h8jh-uJk,35166
|
|
20
|
-
lucidicai/providers/opentelemetry_converter.py,sha256=xOHCqoTyO4hUkL6k7fxy84PbljPpYep6ET9ZqbkJehc,17665
|
|
21
|
-
lucidicai/providers/pydantic_ai_handler.py,sha256=Vu03SEqRuQNbmOK3iPwWVqczVRZNDDVoilDILIycK8c,28935
|
|
22
|
-
lucidicai-1.2.14.dist-info/METADATA,sha256=_zXTh7KcZmfq_YmlgytwfJNJDtAxE7Hy4iSKHbK0pNk,577
|
|
23
|
-
lucidicai-1.2.14.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
|
|
24
|
-
lucidicai-1.2.14.dist-info/top_level.txt,sha256=vSSdM3lclF4I5tyVC0xxUk8eIRnnYXMe1hW-eO91HUo,10
|
|
25
|
-
lucidicai-1.2.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|