lucidicai 1.2.15__py3-none-any.whl → 1.2.17__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 (40) hide show
  1. lucidicai/__init__.py +111 -21
  2. lucidicai/client.py +22 -5
  3. lucidicai/decorators.py +357 -0
  4. lucidicai/event.py +2 -2
  5. lucidicai/image_upload.py +24 -1
  6. lucidicai/providers/anthropic_handler.py +0 -7
  7. lucidicai/providers/image_storage.py +45 -0
  8. lucidicai/providers/langchain.py +0 -78
  9. lucidicai/providers/lucidic_exporter.py +259 -0
  10. lucidicai/providers/lucidic_span_processor.py +648 -0
  11. lucidicai/providers/openai_agents_instrumentor.py +307 -0
  12. lucidicai/providers/openai_handler.py +1 -56
  13. lucidicai/providers/otel_handlers.py +266 -0
  14. lucidicai/providers/otel_init.py +197 -0
  15. lucidicai/providers/otel_provider.py +168 -0
  16. lucidicai/providers/pydantic_ai_handler.py +2 -19
  17. lucidicai/providers/text_storage.py +53 -0
  18. lucidicai/providers/universal_image_interceptor.py +276 -0
  19. lucidicai/session.py +17 -4
  20. lucidicai/step.py +4 -4
  21. lucidicai/streaming.py +2 -3
  22. lucidicai/telemetry/__init__.py +0 -0
  23. lucidicai/telemetry/base_provider.py +21 -0
  24. lucidicai/telemetry/lucidic_exporter.py +259 -0
  25. lucidicai/telemetry/lucidic_span_processor.py +665 -0
  26. lucidicai/telemetry/openai_agents_instrumentor.py +306 -0
  27. lucidicai/telemetry/opentelemetry_converter.py +436 -0
  28. lucidicai/telemetry/otel_handlers.py +266 -0
  29. lucidicai/telemetry/otel_init.py +197 -0
  30. lucidicai/telemetry/otel_provider.py +168 -0
  31. lucidicai/telemetry/pydantic_ai_handler.py +600 -0
  32. lucidicai/telemetry/utils/__init__.py +0 -0
  33. lucidicai/telemetry/utils/image_storage.py +45 -0
  34. lucidicai/telemetry/utils/text_storage.py +53 -0
  35. lucidicai/telemetry/utils/universal_image_interceptor.py +276 -0
  36. {lucidicai-1.2.15.dist-info → lucidicai-1.2.17.dist-info}/METADATA +1 -1
  37. lucidicai-1.2.17.dist-info/RECORD +49 -0
  38. lucidicai-1.2.15.dist-info/RECORD +0 -25
  39. {lucidicai-1.2.15.dist-info → lucidicai-1.2.17.dist-info}/WHEEL +0 -0
  40. {lucidicai-1.2.15.dist-info → lucidicai-1.2.17.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,53 @@
1
+ """Thread-local storage for text content from multimodal messages"""
2
+ import threading
3
+ from typing import List, Optional
4
+ import logging
5
+
6
+ logger = logging.getLogger("Lucidic")
7
+
8
+ # Thread-local storage for text content
9
+ _text_storage = threading.local()
10
+
11
+ def store_text(text: str, message_index: int = 0) -> None:
12
+ """Store text content for a message
13
+
14
+ Args:
15
+ text: The text content to store
16
+ message_index: The index of the message (default 0)
17
+ """
18
+ if not hasattr(_text_storage, 'texts'):
19
+ _text_storage.texts = {}
20
+
21
+ _text_storage.texts[message_index] = text
22
+ logger.debug(f"[TextStorage] Stored text for message {message_index}: {text[:50]}...")
23
+
24
+ def get_stored_text(message_index: int = 0) -> Optional[str]:
25
+ """Get stored text for a message
26
+
27
+ Args:
28
+ message_index: The index of the message (default 0)
29
+
30
+ Returns:
31
+ The stored text or None if not found
32
+ """
33
+ if not hasattr(_text_storage, 'texts'):
34
+ return None
35
+
36
+ return _text_storage.texts.get(message_index)
37
+
38
+ def get_all_stored_texts() -> dict:
39
+ """Get all stored texts
40
+
41
+ Returns:
42
+ Dictionary of message_index -> text
43
+ """
44
+ if not hasattr(_text_storage, 'texts'):
45
+ return {}
46
+
47
+ return _text_storage.texts.copy()
48
+
49
+ def clear_stored_texts() -> None:
50
+ """Clear all stored texts"""
51
+ if hasattr(_text_storage, 'texts'):
52
+ _text_storage.texts = {}
53
+ logger.debug("[TextStorage] Cleared all stored texts")
@@ -0,0 +1,276 @@
1
+ """Universal image interceptor for all LLM providers to capture images from multimodal requests"""
2
+ import logging
3
+ import os
4
+ from typing import Any, Dict, List, Union, Tuple
5
+ from .image_storage import store_image, get_stored_images
6
+ from .text_storage import store_text, clear_stored_texts
7
+
8
+ logger = logging.getLogger("Lucidic")
9
+ DEBUG = os.getenv("LUCIDIC_DEBUG", "False") == "True"
10
+ VERBOSE = os.getenv("LUCIDIC_VERBOSE", "False") == "True"
11
+
12
+ class UniversalImageInterceptor:
13
+ """Universal image interceptor that can handle different provider formats"""
14
+
15
+ @staticmethod
16
+ def extract_and_store_images_openai(messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
17
+ """Extract and store images from OpenAI-style messages
18
+
19
+ OpenAI format:
20
+ {
21
+ "role": "user",
22
+ "content": [
23
+ {"type": "text", "text": "What's in this image?"},
24
+ {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,..."}}
25
+ ]
26
+ }
27
+ """
28
+ processed_messages = []
29
+ clear_stored_texts() # Clear any previous texts
30
+
31
+ for msg_idx, message in enumerate(messages):
32
+ if isinstance(message, dict):
33
+ content = message.get('content')
34
+ if isinstance(content, list):
35
+ # Extract and store text content for multimodal messages
36
+ text_parts = []
37
+ has_images = False
38
+
39
+ for item in content:
40
+ if isinstance(item, dict):
41
+ if item.get('type') == 'text':
42
+ text_parts.append(item.get('text', ''))
43
+ elif item.get('type') == 'image_url':
44
+ has_images = True
45
+ image_data = item.get('image_url', {})
46
+ if isinstance(image_data, dict):
47
+ url = image_data.get('url', '')
48
+ if url.startswith('data:image'):
49
+ # Store the image
50
+ placeholder = store_image(url)
51
+ if DEBUG:
52
+ logger.info(f"[Universal Interceptor] Stored OpenAI image, placeholder: {placeholder}")
53
+
54
+ # If we have both text and images, store the text separately
55
+ if text_parts and has_images:
56
+ combined_text = ' '.join(text_parts)
57
+ store_text(combined_text, msg_idx)
58
+ if VERBOSE:
59
+ logger.info(f"[Universal Interceptor] Stored text for multimodal message {msg_idx}: {combined_text[:50]}...")
60
+
61
+ processed_messages.append(message)
62
+ return processed_messages
63
+
64
+ @staticmethod
65
+ def extract_and_store_images_anthropic(messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
66
+ """Extract and store images from Anthropic-style messages
67
+
68
+ Anthropic format:
69
+ {
70
+ "role": "user",
71
+ "content": [
72
+ {"type": "text", "text": "What's in this image?"},
73
+ {"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": "..."}}
74
+ ]
75
+ }
76
+ """
77
+ processed_messages = []
78
+ for message in messages:
79
+ if isinstance(message, dict):
80
+ content = message.get('content')
81
+ if isinstance(content, list):
82
+ for item in content:
83
+ if isinstance(item, dict) and item.get('type') == 'image':
84
+ source = item.get('source', {})
85
+ if isinstance(source, dict):
86
+ data = source.get('data', '')
87
+ media_type = source.get('media_type', 'image/jpeg')
88
+ if data:
89
+ # Convert to data URL format for consistency
90
+ data_url = f"data:{media_type};base64,{data}"
91
+ placeholder = store_image(data_url)
92
+ if DEBUG:
93
+ logger.info(f"[Universal Interceptor] Stored Anthropic image, placeholder: {placeholder}")
94
+ processed_messages.append(message)
95
+ return processed_messages
96
+
97
+ @staticmethod
98
+ def extract_and_store_images_google(messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
99
+ """Extract and store images from Google/Gemini-style messages
100
+
101
+ Google format can vary but often uses:
102
+ {
103
+ "parts": [
104
+ {"text": "What's in this image?"},
105
+ {"inline_data": {"mime_type": "image/jpeg", "data": "..."}}
106
+ ]
107
+ }
108
+ """
109
+ processed_messages = []
110
+ for message in messages:
111
+ if isinstance(message, dict):
112
+ parts = message.get('parts', [])
113
+ for part in parts:
114
+ if isinstance(part, dict) and 'inline_data' in part:
115
+ inline_data = part['inline_data']
116
+ if isinstance(inline_data, dict):
117
+ data = inline_data.get('data', '')
118
+ mime_type = inline_data.get('mime_type', 'image/jpeg')
119
+ if data:
120
+ # Convert to data URL format
121
+ data_url = f"data:{mime_type};base64,{data}"
122
+ placeholder = store_image(data_url)
123
+ if DEBUG:
124
+ logger.info(f"[Universal Interceptor] Stored Google image, placeholder: {placeholder}")
125
+ processed_messages.append(message)
126
+ return processed_messages
127
+
128
+ @staticmethod
129
+ def intercept_images(messages: Any, provider: str = "auto") -> Any:
130
+ """Universal image interception for any provider
131
+
132
+ Args:
133
+ messages: The messages to process
134
+ provider: The provider type ("openai", "anthropic", "google", "auto")
135
+ If "auto", will try to detect the format
136
+
137
+ Returns:
138
+ The processed messages (unchanged, but images are stored)
139
+ """
140
+ if not messages or not isinstance(messages, list):
141
+ return messages
142
+
143
+ # Auto-detect provider format if needed
144
+ if provider == "auto":
145
+ provider = UniversalImageInterceptor._detect_provider_format(messages)
146
+
147
+ # Process based on provider
148
+ if provider == "openai":
149
+ return UniversalImageInterceptor.extract_and_store_images_openai(messages)
150
+ elif provider == "anthropic":
151
+ return UniversalImageInterceptor.extract_and_store_images_anthropic(messages)
152
+ elif provider == "google":
153
+ return UniversalImageInterceptor.extract_and_store_images_google(messages)
154
+ else:
155
+ if DEBUG:
156
+ logger.warning(f"[Universal Interceptor] Unknown provider format: {provider}")
157
+ return messages
158
+
159
+ @staticmethod
160
+ def _detect_provider_format(messages: List[Dict[str, Any]]) -> str:
161
+ """Detect the provider format based on message structure"""
162
+ for message in messages:
163
+ if isinstance(message, dict):
164
+ # Check for OpenAI format
165
+ content = message.get('content')
166
+ if isinstance(content, list):
167
+ for item in content:
168
+ if isinstance(item, dict):
169
+ if item.get('type') == 'image_url' and 'image_url' in item:
170
+ return "openai"
171
+ elif item.get('type') == 'image' and 'source' in item:
172
+ return "anthropic"
173
+
174
+ # Check for Google format
175
+ if 'parts' in message:
176
+ return "google"
177
+
178
+ return "unknown"
179
+
180
+ @staticmethod
181
+ def create_interceptor(provider: str):
182
+ """Create a function interceptor for a specific provider
183
+
184
+ Args:
185
+ provider: The provider type ("openai", "anthropic", "google")
186
+
187
+ Returns:
188
+ A function that can wrap the provider's API call
189
+ """
190
+ def interceptor(original_func):
191
+ def wrapper(*args, **kwargs):
192
+ # Extract messages from kwargs (common location)
193
+ messages = kwargs.get('messages', None)
194
+
195
+ # For Anthropic, messages might be in args[1]
196
+ if messages is None and len(args) > 1 and isinstance(args[1], list):
197
+ messages = args[1]
198
+
199
+ # Intercept images if messages found
200
+ if messages:
201
+ UniversalImageInterceptor.intercept_images(messages, provider)
202
+
203
+ # Call the original function
204
+ return original_func(*args, **kwargs)
205
+
206
+ return wrapper
207
+
208
+ return interceptor
209
+
210
+ @staticmethod
211
+ def create_async_interceptor(provider: str):
212
+ """Create an async function interceptor for a specific provider"""
213
+ def interceptor(original_func):
214
+ async def wrapper(*args, **kwargs):
215
+ # Extract messages from kwargs (common location)
216
+ messages = kwargs.get('messages', None)
217
+
218
+ # For Anthropic, messages might be in args[1]
219
+ if messages is None and len(args) > 1 and isinstance(args[1], list):
220
+ messages = args[1]
221
+
222
+ # Intercept images if messages found
223
+ if messages:
224
+ UniversalImageInterceptor.intercept_images(messages, provider)
225
+
226
+ # Call the original function
227
+ return await original_func(*args, **kwargs)
228
+
229
+ return wrapper
230
+
231
+ return interceptor
232
+
233
+
234
+ def patch_openai_client(client):
235
+ """Patch an OpenAI client instance to intercept images"""
236
+ interceptor = UniversalImageInterceptor.create_interceptor("openai")
237
+
238
+ if hasattr(client, 'chat') and hasattr(client.chat, 'completions'):
239
+ original_create = client.chat.completions.create
240
+ client.chat.completions.create = interceptor(original_create)
241
+ if DEBUG:
242
+ logger.info("[Universal Interceptor] Patched OpenAI client for image interception")
243
+ return client
244
+
245
+
246
+ def patch_anthropic_client(client):
247
+ """Patch an Anthropic client instance to intercept images"""
248
+ interceptor = UniversalImageInterceptor.create_interceptor("anthropic")
249
+ async_interceptor = UniversalImageInterceptor.create_async_interceptor("anthropic")
250
+
251
+ if hasattr(client, 'messages'):
252
+ if hasattr(client.messages, 'create'):
253
+ original_create = client.messages.create
254
+ client.messages.create = interceptor(original_create)
255
+
256
+ # Handle async version
257
+ if hasattr(client.messages, 'acreate'):
258
+ original_acreate = client.messages.acreate
259
+ client.messages.acreate = async_interceptor(original_acreate)
260
+
261
+ if DEBUG:
262
+ logger.info("[Universal Interceptor] Patched Anthropic client for image interception")
263
+ return client
264
+
265
+
266
+ def patch_google_client(client):
267
+ """Patch a Google/Gemini client instance to intercept images"""
268
+ interceptor = UniversalImageInterceptor.create_interceptor("google")
269
+
270
+ # Google's client structure varies, but often uses generate_content
271
+ if hasattr(client, 'generate_content'):
272
+ original_generate = client.generate_content
273
+ client.generate_content = interceptor(original_generate)
274
+ if DEBUG:
275
+ logger.info("[Universal Interceptor] Patched Google client for image interception")
276
+ return client
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lucidicai
3
- Version: 1.2.15
3
+ Version: 1.2.17
4
4
  Summary: Lucidic AI Python SDK
5
5
  Author: Andy Liang
6
6
  Author-email: andy@lucidic.ai
@@ -0,0 +1,49 @@
1
+ lucidicai/__init__.py,sha256=lj8_84KeLYcJVrqUnkuyeFKUfwv1L5qY85gtpMxEsIM,19765
2
+ lucidicai/action.py,sha256=sPRd1hTIVXDqnvG9ZXWEipUFh0bsXcE0Fm7RVqmVccM,237
3
+ lucidicai/client.py,sha256=_EHUB--u-hvdhKTks4jpqvA18-GBwJfnyjoPZOXkA04,6374
4
+ lucidicai/constants.py,sha256=_u0z3M4geZgS1g-CrOZUVjtcew8l70dKQnpVQvlXh9w,2172
5
+ lucidicai/decorators.py,sha256=oqXyfHk9f9UmeaIquuU8mtzed1qZtO_-svwadpoat6g,13950
6
+ lucidicai/errors.py,sha256=gTg0bdzjuTcUnakRbZnxjngO4gZnRLVwRHRglpZZJsM,970
7
+ lucidicai/event.py,sha256=2j5G4drwVhmdQkk9-armYQj1ctmLm2H_rNfPsfV_8wA,2004
8
+ lucidicai/image_upload.py,sha256=6SRudg-BpInM2gzMx1Yf1Rz_Zyh8inwoJ7U4pBw7ruY,3807
9
+ lucidicai/model_pricing.py,sha256=Q_Kd8OtKPqtvZ4pIh__ztKb3RXe-cX-8xgrM-AIUj9E,12189
10
+ lucidicai/session.py,sha256=_67V6Be9Js-JEdCfiY_wkr4VUkQOdwZKUGUwf5mGXps,5429
11
+ lucidicai/singleton.py,sha256=gfT3XdWLXSIWMqDXbY6-pnesMZ8RGRitaEPhIsgrRPw,1272
12
+ lucidicai/state.py,sha256=4Tb1X6l2or6w_e62FYSuEeghAv3xXm5gquKwzCpvdok,235
13
+ lucidicai/step.py,sha256=_oBIyTBZBvNkUkYHIrwWd75KMSlMtR9Ws2Lo71Lyff8,2522
14
+ lucidicai/streaming.py,sha256=Y59vQOqhcOvTQWSAIamAnGCaQqCZz77N62_V2fuQlFA,11565
15
+ lucidicai/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ lucidicai/providers/anthropic_handler.py,sha256=GZEa4QOrjZ9ftu_qTwY3L410HwKzkXgN7omYRsEQ4LU,10174
17
+ lucidicai/providers/base_providers.py,sha256=nrZVr4Y9xcAiMn4uAN3t3k6DlHNTvlXrA4qQg7lANOQ,544
18
+ lucidicai/providers/image_storage.py,sha256=4Z59ZpVexr7-lcExfr8GsqXe0y2VZmr8Yjwa-3DeOxU,1457
19
+ lucidicai/providers/langchain.py,sha256=xLJPFV2hfCOXsundCUZiYBf-g0dS5MDUYKoz22W8fO8,22184
20
+ lucidicai/providers/lucidic_exporter.py,sha256=-uM7jnz7mkapo9ni7hhN7m3EDa0M_Uhz03NdiqfiP9k,10759
21
+ lucidicai/providers/lucidic_span_processor.py,sha256=8bNV-6W1Y8ELi54vMVqQ_mXJouaOJvF3MkeBdamip0w,26799
22
+ lucidicai/providers/openai_agents_handler.py,sha256=AAMtY7HZ-7UvTn1RVwd-uHhibJusZoOnWSw32xNcewo,18957
23
+ lucidicai/providers/openai_agents_instrumentor.py,sha256=AMCTPeLvmHMNGGxelNaHIMu2s7eppLmruIYnlQ1WHDY,12732
24
+ lucidicai/providers/openai_handler.py,sha256=CrFlM7RUAQjOmqWjAkV71dBRhe7gu-YEKXtSHfb70DE,32119
25
+ lucidicai/providers/opentelemetry_converter.py,sha256=xOHCqoTyO4hUkL6k7fxy84PbljPpYep6ET9ZqbkJehc,17665
26
+ lucidicai/providers/otel_handlers.py,sha256=HFCBryXB3LQ5ir03PWWlskH7Y-Yip88kFVm1HQAUXRc,10516
27
+ lucidicai/providers/otel_init.py,sha256=RMsWRG3WZWvZN6WeLWSehsfUB_vWSuclVMCcSO31GEU,7770
28
+ lucidicai/providers/otel_provider.py,sha256=ixLc80-_Vag0EO_92wj2m3_lg6HXyIpz9Md4JdVAbtM,7043
29
+ lucidicai/providers/pydantic_ai_handler.py,sha256=Yhd9VTJhq292ZzJF04O_jYGRh-1bzs70BzQdo7a2Z9M,28269
30
+ lucidicai/providers/text_storage.py,sha256=L62MMJ8E23TDqDTUv2aRntdKMCItsXV7XjY6cFwx2DE,1503
31
+ lucidicai/providers/universal_image_interceptor.py,sha256=7d-hw4xihRwvvA1AP8-vqYNChtmVXKmn09MN4pDS7KQ,12126
32
+ lucidicai/telemetry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
+ lucidicai/telemetry/base_provider.py,sha256=nrZVr4Y9xcAiMn4uAN3t3k6DlHNTvlXrA4qQg7lANOQ,544
34
+ lucidicai/telemetry/lucidic_exporter.py,sha256=h2GOnEk22Fpeke4Zc7SSk391yr0joUApVwolV5Q4hz4,10818
35
+ lucidicai/telemetry/lucidic_span_processor.py,sha256=LhkyJGBnTKpTWdBi2wyW9th4CWZ9EtZ8ulaE0rwYj0Y,27432
36
+ lucidicai/telemetry/openai_agents_instrumentor.py,sha256=__wIbeglMnEEf4AGTQ--FXeWCKmz2yy8SBupwprEdZA,12694
37
+ lucidicai/telemetry/opentelemetry_converter.py,sha256=xOHCqoTyO4hUkL6k7fxy84PbljPpYep6ET9ZqbkJehc,17665
38
+ lucidicai/telemetry/otel_handlers.py,sha256=XgeDCL7ZjtaQ7HX8HKmYGTDqO6yne7gXZaScpdKvq98,10527
39
+ lucidicai/telemetry/otel_init.py,sha256=RMsWRG3WZWvZN6WeLWSehsfUB_vWSuclVMCcSO31GEU,7770
40
+ lucidicai/telemetry/otel_provider.py,sha256=GZPhSEsEPVKrr5A0u5-WNn7OmxNgRWBcam9dyqjf91o,7042
41
+ lucidicai/telemetry/pydantic_ai_handler.py,sha256=WPa3tFcVgVnPPO3AxcNOTbNkmODLgNOrU2_3GVtWqUw,28261
42
+ lucidicai/telemetry/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
+ lucidicai/telemetry/utils/image_storage.py,sha256=4Z59ZpVexr7-lcExfr8GsqXe0y2VZmr8Yjwa-3DeOxU,1457
44
+ lucidicai/telemetry/utils/text_storage.py,sha256=L62MMJ8E23TDqDTUv2aRntdKMCItsXV7XjY6cFwx2DE,1503
45
+ lucidicai/telemetry/utils/universal_image_interceptor.py,sha256=zPfVsMjtKxJP2n2OOjKbtPiQJTZ0sf5_28GWprOnJP4,12185
46
+ lucidicai-1.2.17.dist-info/METADATA,sha256=SljtwfhzcGtEwnsx6JAmqDmYY9KniQi5mY3KH3xhR6M,577
47
+ lucidicai-1.2.17.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
48
+ lucidicai-1.2.17.dist-info/top_level.txt,sha256=vSSdM3lclF4I5tyVC0xxUk8eIRnnYXMe1hW-eO91HUo,10
49
+ lucidicai-1.2.17.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=Q_Kd8OtKPqtvZ4pIh__ztKb3RXe-cX-8xgrM-AIUj9E,12189
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.15.dist-info/METADATA,sha256=gM8vDiiFysOgG0OG6hcgnxYH4k2U1t1Mb0D_2cpfQfk,577
23
- lucidicai-1.2.15.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
24
- lucidicai-1.2.15.dist-info/top_level.txt,sha256=vSSdM3lclF4I5tyVC0xxUk8eIRnnYXMe1hW-eO91HUo,10
25
- lucidicai-1.2.15.dist-info/RECORD,,