lucidicai 2.1.3__py3-none-any.whl → 3.1.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 +32 -390
- lucidicai/api/client.py +31 -2
- lucidicai/api/resources/__init__.py +16 -1
- lucidicai/api/resources/dataset.py +422 -82
- lucidicai/api/resources/evals.py +209 -0
- lucidicai/api/resources/event.py +399 -27
- lucidicai/api/resources/experiment.py +108 -0
- lucidicai/api/resources/feature_flag.py +78 -0
- lucidicai/api/resources/prompt.py +84 -0
- lucidicai/api/resources/session.py +545 -38
- lucidicai/client.py +408 -480
- lucidicai/core/config.py +73 -48
- lucidicai/core/errors.py +3 -3
- lucidicai/sdk/bound_decorators.py +321 -0
- lucidicai/sdk/context.py +20 -2
- lucidicai/sdk/decorators.py +283 -74
- lucidicai/sdk/event.py +538 -36
- lucidicai/sdk/event_builder.py +2 -4
- lucidicai/sdk/features/dataset.py +391 -1
- lucidicai/sdk/features/feature_flag.py +344 -3
- lucidicai/sdk/init.py +49 -347
- lucidicai/sdk/session.py +502 -0
- lucidicai/sdk/shutdown_manager.py +103 -46
- lucidicai/session_obj.py +321 -0
- lucidicai/telemetry/context_capture_processor.py +13 -6
- lucidicai/telemetry/extract.py +60 -63
- lucidicai/telemetry/litellm_bridge.py +3 -44
- lucidicai/telemetry/lucidic_exporter.py +143 -131
- lucidicai/telemetry/openai_agents_instrumentor.py +2 -2
- lucidicai/telemetry/openai_patch.py +7 -6
- lucidicai/telemetry/telemetry_manager.py +183 -0
- lucidicai/telemetry/utils/model_pricing.py +21 -30
- lucidicai/telemetry/utils/provider.py +77 -0
- lucidicai/utils/images.py +27 -11
- lucidicai/utils/serialization.py +27 -0
- {lucidicai-2.1.3.dist-info → lucidicai-3.1.0.dist-info}/METADATA +1 -1
- {lucidicai-2.1.3.dist-info → lucidicai-3.1.0.dist-info}/RECORD +39 -29
- {lucidicai-2.1.3.dist-info → lucidicai-3.1.0.dist-info}/WHEEL +0 -0
- {lucidicai-2.1.3.dist-info → lucidicai-3.1.0.dist-info}/top_level.txt +0 -0
lucidicai/sdk/init.py
CHANGED
|
@@ -1,264 +1,34 @@
|
|
|
1
|
-
"""SDK
|
|
1
|
+
"""SDK utilities module.
|
|
2
2
|
|
|
3
|
-
This module
|
|
3
|
+
This module provides utility functions for session and context management.
|
|
4
|
+
The main entry point for the SDK is the LucidicAI class in client.py.
|
|
5
|
+
|
|
6
|
+
Note: Global session creation functions (create_session, init) have been removed.
|
|
7
|
+
Use the LucidicAI class for all SDK operations.
|
|
4
8
|
"""
|
|
5
|
-
import uuid
|
|
6
|
-
from typing import List, Optional
|
|
7
9
|
import asyncio
|
|
8
10
|
import threading
|
|
11
|
+
from typing import Optional
|
|
9
12
|
from weakref import WeakKeyDictionary
|
|
10
13
|
|
|
11
|
-
from ..
|
|
12
|
-
from
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
from opentelemetry.sdk.trace import TracerProvider
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class SDKState:
|
|
26
|
-
"""Container for SDK runtime state."""
|
|
27
|
-
|
|
28
|
-
def __init__(self):
|
|
29
|
-
self.http: Optional[HttpClient] = None
|
|
30
|
-
self.event_queue: Optional[EventQueue] = None
|
|
31
|
-
self.session_id: Optional[str] = None
|
|
32
|
-
self.tracer_provider: Optional[TracerProvider] = None
|
|
33
|
-
self.resources = {}
|
|
34
|
-
# Task-local storage for async task isolation
|
|
35
|
-
self.task_sessions: WeakKeyDictionary = WeakKeyDictionary()
|
|
36
|
-
# Thread-local storage for thread isolation
|
|
37
|
-
self.thread_local = threading.local()
|
|
38
|
-
|
|
39
|
-
def reset(self):
|
|
40
|
-
"""Reset SDK state."""
|
|
41
|
-
# Shutdown telemetry first to ensure all spans are exported
|
|
42
|
-
if self.tracer_provider:
|
|
43
|
-
try:
|
|
44
|
-
# Force flush all pending spans with 5 second timeout
|
|
45
|
-
debug("[SDK] Flushing OpenTelemetry spans...")
|
|
46
|
-
self.tracer_provider.force_flush(timeout_millis=5000)
|
|
47
|
-
# Shutdown the tracer provider and all processors
|
|
48
|
-
self.tracer_provider.shutdown()
|
|
49
|
-
debug("[SDK] TracerProvider shutdown complete")
|
|
50
|
-
except Exception as e:
|
|
51
|
-
error(f"[SDK] Error shutting down TracerProvider: {e}")
|
|
52
|
-
|
|
53
|
-
if self.event_queue:
|
|
54
|
-
self.event_queue.shutdown()
|
|
55
|
-
if self.http:
|
|
56
|
-
self.http.close()
|
|
57
|
-
|
|
58
|
-
self.http = None
|
|
59
|
-
self.event_queue = None
|
|
60
|
-
self.session_id = None
|
|
61
|
-
self.tracer_provider = None
|
|
62
|
-
self.resources = {}
|
|
63
|
-
self.task_sessions.clear()
|
|
64
|
-
# Clear thread-local storage for current thread
|
|
65
|
-
if hasattr(self.thread_local, 'session_id'):
|
|
66
|
-
delattr(self.thread_local, 'session_id')
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
# Global SDK state
|
|
70
|
-
_sdk_state = SDKState()
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def init(
|
|
74
|
-
session_name: Optional[str] = None,
|
|
75
|
-
session_id: Optional[str] = None,
|
|
76
|
-
api_key: Optional[str] = None,
|
|
77
|
-
agent_id: Optional[str] = None,
|
|
78
|
-
task: Optional[str] = None,
|
|
79
|
-
providers: Optional[List[str]] = None,
|
|
80
|
-
production_monitoring: bool = False,
|
|
81
|
-
experiment_id: Optional[str] = None,
|
|
82
|
-
evaluators: Optional[List] = None,
|
|
83
|
-
tags: Optional[List] = None,
|
|
84
|
-
datasetitem_id: Optional[str] = None,
|
|
85
|
-
masking_function: Optional[callable] = None,
|
|
86
|
-
auto_end: bool = True,
|
|
87
|
-
capture_uncaught: bool = True,
|
|
88
|
-
) -> str:
|
|
89
|
-
"""Initialize the Lucidic SDK.
|
|
90
|
-
|
|
91
|
-
Args:
|
|
92
|
-
session_name: Name for the session
|
|
93
|
-
session_id: Custom session ID (optional)
|
|
94
|
-
api_key: API key (uses env if not provided)
|
|
95
|
-
agent_id: Agent ID (uses env if not provided)
|
|
96
|
-
task: Task description
|
|
97
|
-
providers: List of telemetry providers to instrument
|
|
98
|
-
production_monitoring: Enable production monitoring
|
|
99
|
-
experiment_id: Experiment ID to associate with session
|
|
100
|
-
evaluators: Ealuators to use
|
|
101
|
-
tags: Session tags
|
|
102
|
-
datasetitem_id: Dataset item ID
|
|
103
|
-
masking_function: Function to mask sensitive data
|
|
104
|
-
auto_end: Automatically end session on exit
|
|
105
|
-
capture_uncaught: Capture uncaught exceptions
|
|
106
|
-
|
|
107
|
-
Returns:
|
|
108
|
-
Session ID
|
|
109
|
-
|
|
110
|
-
Raises:
|
|
111
|
-
APIKeyVerificationError: If API credentials are invalid
|
|
112
|
-
"""
|
|
113
|
-
global _sdk_state
|
|
114
|
-
|
|
115
|
-
# Create or update configuration
|
|
116
|
-
config = SDKConfig.from_env(
|
|
117
|
-
api_key=api_key,
|
|
118
|
-
agent_id=agent_id,
|
|
119
|
-
auto_end=auto_end,
|
|
120
|
-
production_monitoring=production_monitoring
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
if providers:
|
|
124
|
-
config.telemetry.providers = providers
|
|
125
|
-
|
|
126
|
-
config.error_handling.capture_uncaught = capture_uncaught
|
|
127
|
-
|
|
128
|
-
# Validate configuration
|
|
129
|
-
errors = config.validate()
|
|
130
|
-
if errors:
|
|
131
|
-
raise ValueError(f"Invalid configuration: {', '.join(errors)}")
|
|
132
|
-
|
|
133
|
-
# Set global config
|
|
134
|
-
set_config(config)
|
|
135
|
-
|
|
136
|
-
# Initialize HTTP client
|
|
137
|
-
if not _sdk_state.http:
|
|
138
|
-
debug("[SDK] Initializing HTTP client")
|
|
139
|
-
_sdk_state.http = HttpClient(config)
|
|
140
|
-
|
|
141
|
-
# Initialize resources
|
|
142
|
-
if not _sdk_state.resources:
|
|
143
|
-
_sdk_state.resources = {
|
|
144
|
-
'events': EventResource(_sdk_state.http),
|
|
145
|
-
'sessions': SessionResource(_sdk_state.http),
|
|
146
|
-
'datasets': DatasetResource(_sdk_state.http)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
# Initialize event queue
|
|
150
|
-
if not _sdk_state.event_queue:
|
|
151
|
-
debug("[SDK] Initializing event queue")
|
|
152
|
-
# Create a mock client object for backward compatibility
|
|
153
|
-
# The queue needs a client with make_request method
|
|
154
|
-
class ClientAdapter:
|
|
155
|
-
def make_request(self, endpoint, method, data):
|
|
156
|
-
return _sdk_state.http.request(method, endpoint, json=data)
|
|
157
|
-
|
|
158
|
-
_sdk_state.event_queue = EventQueue(ClientAdapter())
|
|
159
|
-
|
|
160
|
-
# Register cleanup handler
|
|
161
|
-
register_cleanup_handler(lambda: _sdk_state.event_queue.force_flush())
|
|
162
|
-
debug("[SDK] Event queue initialized and cleanup handler registered")
|
|
163
|
-
|
|
164
|
-
# Create or retrieve session
|
|
165
|
-
if session_id:
|
|
166
|
-
# Use provided session ID
|
|
167
|
-
real_session_id = session_id
|
|
168
|
-
else:
|
|
169
|
-
# Create new session
|
|
170
|
-
real_session_id = str(uuid.uuid4())
|
|
171
|
-
|
|
172
|
-
# Create session via API - only send non-None values
|
|
173
|
-
session_params = {
|
|
174
|
-
'session_id': real_session_id,
|
|
175
|
-
'session_name': session_name or 'Unnamed Session',
|
|
176
|
-
'agent_id': config.agent_id,
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
# Only add optional fields if they have values
|
|
180
|
-
if task:
|
|
181
|
-
session_params['task'] = task
|
|
182
|
-
if tags:
|
|
183
|
-
session_params['tags'] = tags
|
|
184
|
-
if experiment_id:
|
|
185
|
-
session_params['experiment_id'] = experiment_id
|
|
186
|
-
if datasetitem_id:
|
|
187
|
-
session_params['datasetitem_id'] = datasetitem_id
|
|
188
|
-
if evaluators:
|
|
189
|
-
session_params['evaluators'] = evaluators
|
|
190
|
-
if production_monitoring:
|
|
191
|
-
session_params['production_monitoring'] = production_monitoring
|
|
192
|
-
|
|
193
|
-
debug(f"[SDK] Creating session with params: {session_params}")
|
|
194
|
-
session_resource = _sdk_state.resources['sessions']
|
|
195
|
-
session_data = session_resource.create_session(session_params)
|
|
196
|
-
|
|
197
|
-
# Use the session_id returned by the backend
|
|
198
|
-
real_session_id = session_data.get('session_id', real_session_id)
|
|
199
|
-
_sdk_state.session_id = real_session_id
|
|
200
|
-
|
|
201
|
-
info(f"[SDK] Session created: {truncate_id(real_session_id)} (name: {session_name or 'Unnamed Session'})")
|
|
202
|
-
|
|
203
|
-
# Set active session in context
|
|
204
|
-
set_active_session(real_session_id)
|
|
205
|
-
|
|
206
|
-
# Register session with shutdown manager
|
|
207
|
-
debug(f"[SDK] Registering session with shutdown manager (auto_end={auto_end})")
|
|
208
|
-
shutdown_manager = get_shutdown_manager()
|
|
209
|
-
session_state = SessionState(
|
|
210
|
-
session_id=real_session_id,
|
|
211
|
-
http_client=_sdk_state.resources, # Pass resources dict which has sessions
|
|
212
|
-
event_queue=_sdk_state.event_queue,
|
|
213
|
-
auto_end=auto_end
|
|
214
|
-
)
|
|
215
|
-
shutdown_manager.register_session(real_session_id, session_state)
|
|
216
|
-
|
|
217
|
-
# Initialize telemetry if providers specified
|
|
218
|
-
if providers:
|
|
219
|
-
debug(f"[SDK] Initializing telemetry for providers: {providers}")
|
|
220
|
-
_initialize_telemetry(providers)
|
|
221
|
-
|
|
222
|
-
return real_session_id
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
def _initialize_telemetry(providers: List[str]) -> None:
|
|
226
|
-
"""Initialize telemetry providers.
|
|
227
|
-
|
|
228
|
-
Args:
|
|
229
|
-
providers: List of provider names
|
|
230
|
-
"""
|
|
231
|
-
global _sdk_state
|
|
232
|
-
|
|
233
|
-
if not _sdk_state.tracer_provider:
|
|
234
|
-
# Import here to avoid circular dependency
|
|
235
|
-
from ..telemetry.lucidic_exporter import LucidicSpanExporter
|
|
236
|
-
from ..telemetry.context_capture_processor import ContextCaptureProcessor
|
|
237
|
-
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
238
|
-
|
|
239
|
-
# Create tracer provider with our processors
|
|
240
|
-
_sdk_state.tracer_provider = TracerProvider()
|
|
241
|
-
|
|
242
|
-
# Add context capture processor FIRST to capture context before export
|
|
243
|
-
context_processor = ContextCaptureProcessor()
|
|
244
|
-
_sdk_state.tracer_provider.add_span_processor(context_processor)
|
|
245
|
-
|
|
246
|
-
# Add exporter processor
|
|
247
|
-
exporter = LucidicSpanExporter()
|
|
248
|
-
export_processor = BatchSpanProcessor(exporter)
|
|
249
|
-
_sdk_state.tracer_provider.add_span_processor(export_processor)
|
|
250
|
-
|
|
251
|
-
# Instrument providers
|
|
252
|
-
instrument_providers(providers, _sdk_state.tracer_provider, {})
|
|
253
|
-
|
|
254
|
-
info(f"[Telemetry] Initialized for providers: {providers}")
|
|
14
|
+
from ..utils.logger import debug, truncate_id
|
|
15
|
+
from .context import current_session_id
|
|
16
|
+
|
|
17
|
+
# Module-level storage for async task isolation
|
|
18
|
+
_task_sessions: WeakKeyDictionary = WeakKeyDictionary()
|
|
19
|
+
|
|
20
|
+
# Module-level thread-local storage
|
|
21
|
+
_thread_local = threading.local()
|
|
22
|
+
|
|
23
|
+
# Reference to tracer provider (set by TelemetryManager)
|
|
24
|
+
_tracer_provider = None
|
|
255
25
|
|
|
256
26
|
|
|
257
27
|
def set_task_session(session_id: str) -> None:
|
|
258
28
|
"""Set session ID for current async task (if in async context)."""
|
|
259
29
|
try:
|
|
260
30
|
if task := asyncio.current_task():
|
|
261
|
-
|
|
31
|
+
_task_sessions[task] = session_id
|
|
262
32
|
debug(f"[SDK] Set task-local session {truncate_id(session_id)} for task {task.get_name()}")
|
|
263
33
|
except RuntimeError:
|
|
264
34
|
# Not in async context, ignore
|
|
@@ -269,7 +39,7 @@ def clear_task_session() -> None:
|
|
|
269
39
|
"""Clear session ID for current async task (if in async context)."""
|
|
270
40
|
try:
|
|
271
41
|
if task := asyncio.current_task():
|
|
272
|
-
|
|
42
|
+
_task_sessions.pop(task, None)
|
|
273
43
|
debug(f"[SDK] Cleared task-local session for task {task.get_name()}")
|
|
274
44
|
except RuntimeError:
|
|
275
45
|
# Not in async context, ignore
|
|
@@ -281,22 +51,22 @@ def set_thread_session(session_id: str) -> None:
|
|
|
281
51
|
|
|
282
52
|
This provides true thread-local storage that doesn't inherit from parent thread.
|
|
283
53
|
"""
|
|
284
|
-
|
|
54
|
+
_thread_local.session_id = session_id
|
|
285
55
|
current_thread = threading.current_thread()
|
|
286
56
|
debug(f"[SDK] Set thread-local session {truncate_id(session_id)} for thread {current_thread.name}")
|
|
287
57
|
|
|
288
58
|
|
|
289
59
|
def clear_thread_session() -> None:
|
|
290
60
|
"""Clear session ID for current thread."""
|
|
291
|
-
if hasattr(
|
|
292
|
-
delattr(
|
|
61
|
+
if hasattr(_thread_local, 'session_id'):
|
|
62
|
+
delattr(_thread_local, 'session_id')
|
|
293
63
|
current_thread = threading.current_thread()
|
|
294
64
|
debug(f"[SDK] Cleared thread-local session for thread {current_thread.name}")
|
|
295
65
|
|
|
296
66
|
|
|
297
67
|
def get_thread_session() -> Optional[str]:
|
|
298
68
|
"""Get session ID from thread-local storage."""
|
|
299
|
-
return getattr(
|
|
69
|
+
return getattr(_thread_local, 'session_id', None)
|
|
300
70
|
|
|
301
71
|
|
|
302
72
|
def is_main_thread() -> bool:
|
|
@@ -310,13 +80,12 @@ def get_session_id() -> Optional[str]:
|
|
|
310
80
|
Priority:
|
|
311
81
|
1. Task-local session (for async tasks)
|
|
312
82
|
2. Thread-local session (for threads) - NO FALLBACK for threads
|
|
313
|
-
3.
|
|
314
|
-
4. Context variable session (fallback for main thread only)
|
|
83
|
+
3. Context variable session (for main thread)
|
|
315
84
|
"""
|
|
316
85
|
# First check task-local storage for async isolation
|
|
317
86
|
try:
|
|
318
87
|
if task := asyncio.current_task():
|
|
319
|
-
if task_session :=
|
|
88
|
+
if task_session := _task_sessions.get(task):
|
|
320
89
|
debug(f"[SDK] Using task-local session {truncate_id(task_session)}")
|
|
321
90
|
return task_session
|
|
322
91
|
except RuntimeError:
|
|
@@ -334,102 +103,35 @@ def get_session_id() -> Optional[str]:
|
|
|
334
103
|
debug(f"[SDK] Thread {threading.current_thread().name} has no thread-local session")
|
|
335
104
|
return thread_session # Return None if not set - don't fall back!
|
|
336
105
|
|
|
337
|
-
# For main thread
|
|
338
|
-
return
|
|
339
|
-
|
|
106
|
+
# For main thread: use context variable
|
|
107
|
+
return current_session_id.get(None)
|
|
340
108
|
|
|
341
|
-
def get_http() -> Optional[HttpClient]:
|
|
342
|
-
"""Get the HTTP client instance."""
|
|
343
|
-
return _sdk_state.http
|
|
344
109
|
|
|
110
|
+
def get_tracer_provider():
|
|
111
|
+
"""Get the tracer provider instance.
|
|
345
112
|
|
|
346
|
-
|
|
347
|
-
"""
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
def get_resources() -> dict:
|
|
352
|
-
"""Get API resource instances."""
|
|
353
|
-
return _sdk_state.resources
|
|
354
|
-
|
|
113
|
+
Returns the tracer provider set by the TelemetryManager.
|
|
114
|
+
"""
|
|
115
|
+
global _tracer_provider
|
|
116
|
+
if _tracer_provider is not None:
|
|
117
|
+
return _tracer_provider
|
|
355
118
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
119
|
+
# Try to get from TelemetryManager
|
|
120
|
+
try:
|
|
121
|
+
from ..telemetry.telemetry_manager import get_telemetry_manager
|
|
122
|
+
manager = get_telemetry_manager()
|
|
123
|
+
if manager._tracer_provider:
|
|
124
|
+
return manager._tracer_provider
|
|
125
|
+
except Exception:
|
|
126
|
+
pass
|
|
360
127
|
|
|
128
|
+
return None
|
|
361
129
|
|
|
362
|
-
def set_resources(resources: dict) -> None:
|
|
363
|
-
"""Set API resource instances in SDK state."""
|
|
364
|
-
global _sdk_state
|
|
365
|
-
_sdk_state.resources = resources
|
|
366
130
|
|
|
131
|
+
def set_tracer_provider(provider) -> None:
|
|
132
|
+
"""Set the tracer provider instance.
|
|
367
133
|
|
|
368
|
-
|
|
369
|
-
"""Ensure HTTP client and resources are initialized, creating them if needed.
|
|
370
|
-
|
|
371
|
-
This function checks if the HTTP client and resources already exist in SDK state.
|
|
372
|
-
If not, it creates them and stores them in SDK state for reuse.
|
|
373
|
-
|
|
374
|
-
Args:
|
|
375
|
-
api_key: API key (uses env if not provided)
|
|
376
|
-
agent_id: Agent ID (uses env if not provided)
|
|
377
|
-
|
|
378
|
-
Returns:
|
|
379
|
-
Dictionary of API resources with 'datasets' key
|
|
380
|
-
|
|
381
|
-
Raises:
|
|
382
|
-
APIKeyVerificationError: If API key is not available
|
|
134
|
+
Called by TelemetryManager when initializing telemetry.
|
|
383
135
|
"""
|
|
384
|
-
global
|
|
385
|
-
|
|
386
|
-
# If we already have resources with datasets, return them
|
|
387
|
-
if _sdk_state.resources and 'datasets' in _sdk_state.resources:
|
|
388
|
-
return _sdk_state.resources
|
|
389
|
-
|
|
390
|
-
# Need to create HTTP client and resources
|
|
391
|
-
from dotenv import load_dotenv
|
|
392
|
-
import os
|
|
393
|
-
from ..core.errors import APIKeyVerificationError
|
|
394
|
-
|
|
395
|
-
load_dotenv()
|
|
396
|
-
|
|
397
|
-
# Get credentials
|
|
398
|
-
if api_key is None:
|
|
399
|
-
api_key = os.getenv("LUCIDIC_API_KEY", None)
|
|
400
|
-
if api_key is None:
|
|
401
|
-
raise APIKeyVerificationError(
|
|
402
|
-
"Make sure to either pass your API key or set the LUCIDIC_API_KEY environment variable."
|
|
403
|
-
)
|
|
404
|
-
|
|
405
|
-
if agent_id is None:
|
|
406
|
-
agent_id = os.getenv("LUCIDIC_AGENT_ID", None)
|
|
407
|
-
|
|
408
|
-
# Create or reuse HTTP client
|
|
409
|
-
if not _sdk_state.http:
|
|
410
|
-
debug("[SDK] Creating HTTP client for standalone use")
|
|
411
|
-
config = SDKConfig.from_env(api_key=api_key, agent_id=agent_id)
|
|
412
|
-
_sdk_state.http = HttpClient(config)
|
|
413
|
-
|
|
414
|
-
# Create resources if not already present
|
|
415
|
-
if not _sdk_state.resources:
|
|
416
|
-
_sdk_state.resources = {}
|
|
417
|
-
|
|
418
|
-
if 'datasets' not in _sdk_state.resources:
|
|
419
|
-
debug("[SDK] Creating DatasetResource for standalone use")
|
|
420
|
-
_sdk_state.resources['datasets'] = DatasetResource(_sdk_state.http)
|
|
421
|
-
|
|
422
|
-
return _sdk_state.resources
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
def get_tracer_provider() -> Optional[TracerProvider]:
|
|
426
|
-
"""Get the tracer provider instance."""
|
|
427
|
-
return _sdk_state.tracer_provider
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
def clear_state() -> None:
|
|
431
|
-
"""Clear SDK state (for testing)."""
|
|
432
|
-
global _sdk_state
|
|
433
|
-
debug("[SDK] Clearing SDK state")
|
|
434
|
-
_sdk_state.reset()
|
|
435
|
-
_sdk_state = SDKState()
|
|
136
|
+
global _tracer_provider
|
|
137
|
+
_tracer_provider = provider
|