opik 1.8.39__py3-none-any.whl → 1.9.71__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 (592) hide show
  1. opik/__init__.py +19 -3
  2. opik/anonymizer/__init__.py +5 -0
  3. opik/anonymizer/anonymizer.py +12 -0
  4. opik/anonymizer/factory.py +80 -0
  5. opik/anonymizer/recursive_anonymizer.py +64 -0
  6. opik/anonymizer/rules.py +56 -0
  7. opik/anonymizer/rules_anonymizer.py +35 -0
  8. opik/api_objects/attachment/attachment_context.py +36 -0
  9. opik/api_objects/attachment/attachments_extractor.py +153 -0
  10. opik/api_objects/attachment/client.py +1 -0
  11. opik/api_objects/attachment/converters.py +2 -0
  12. opik/api_objects/attachment/decoder.py +18 -0
  13. opik/api_objects/attachment/decoder_base64.py +83 -0
  14. opik/api_objects/attachment/decoder_helpers.py +137 -0
  15. opik/api_objects/data_helpers.py +79 -0
  16. opik/api_objects/dataset/dataset.py +64 -4
  17. opik/api_objects/dataset/rest_operations.py +11 -2
  18. opik/api_objects/experiment/experiment.py +57 -57
  19. opik/api_objects/experiment/experiment_item.py +2 -1
  20. opik/api_objects/experiment/experiments_client.py +64 -0
  21. opik/api_objects/experiment/helpers.py +35 -11
  22. opik/api_objects/experiment/rest_operations.py +65 -5
  23. opik/api_objects/helpers.py +8 -5
  24. opik/api_objects/local_recording.py +81 -0
  25. opik/api_objects/opik_client.py +600 -108
  26. opik/api_objects/opik_query_language.py +39 -5
  27. opik/api_objects/prompt/__init__.py +12 -2
  28. opik/api_objects/prompt/base_prompt.py +69 -0
  29. opik/api_objects/prompt/base_prompt_template.py +29 -0
  30. opik/api_objects/prompt/chat/__init__.py +1 -0
  31. opik/api_objects/prompt/chat/chat_prompt.py +210 -0
  32. opik/api_objects/prompt/chat/chat_prompt_template.py +350 -0
  33. opik/api_objects/prompt/chat/content_renderer_registry.py +203 -0
  34. opik/api_objects/prompt/client.py +189 -47
  35. opik/api_objects/prompt/text/__init__.py +1 -0
  36. opik/api_objects/prompt/text/prompt.py +174 -0
  37. opik/api_objects/prompt/{prompt_template.py → text/prompt_template.py} +10 -6
  38. opik/api_objects/prompt/types.py +23 -0
  39. opik/api_objects/search_helpers.py +89 -0
  40. opik/api_objects/span/span_data.py +35 -25
  41. opik/api_objects/threads/threads_client.py +39 -5
  42. opik/api_objects/trace/trace_client.py +52 -2
  43. opik/api_objects/trace/trace_data.py +15 -24
  44. opik/api_objects/validation_helpers.py +3 -3
  45. opik/cli/__init__.py +5 -0
  46. opik/cli/__main__.py +6 -0
  47. opik/cli/configure.py +66 -0
  48. opik/cli/exports/__init__.py +131 -0
  49. opik/cli/exports/dataset.py +278 -0
  50. opik/cli/exports/experiment.py +784 -0
  51. opik/cli/exports/project.py +685 -0
  52. opik/cli/exports/prompt.py +578 -0
  53. opik/cli/exports/utils.py +406 -0
  54. opik/cli/harbor.py +39 -0
  55. opik/cli/healthcheck.py +21 -0
  56. opik/cli/imports/__init__.py +439 -0
  57. opik/cli/imports/dataset.py +143 -0
  58. opik/cli/imports/experiment.py +1192 -0
  59. opik/cli/imports/project.py +262 -0
  60. opik/cli/imports/prompt.py +177 -0
  61. opik/cli/imports/utils.py +280 -0
  62. opik/cli/main.py +49 -0
  63. opik/cli/proxy.py +93 -0
  64. opik/cli/usage_report/__init__.py +16 -0
  65. opik/cli/usage_report/charts.py +783 -0
  66. opik/cli/usage_report/cli.py +274 -0
  67. opik/cli/usage_report/constants.py +9 -0
  68. opik/cli/usage_report/extraction.py +749 -0
  69. opik/cli/usage_report/pdf.py +244 -0
  70. opik/cli/usage_report/statistics.py +78 -0
  71. opik/cli/usage_report/utils.py +235 -0
  72. opik/config.py +13 -7
  73. opik/configurator/configure.py +17 -0
  74. opik/datetime_helpers.py +12 -0
  75. opik/decorator/arguments_helpers.py +9 -1
  76. opik/decorator/base_track_decorator.py +205 -133
  77. opik/decorator/context_manager/span_context_manager.py +123 -0
  78. opik/decorator/context_manager/trace_context_manager.py +84 -0
  79. opik/decorator/opik_args/__init__.py +13 -0
  80. opik/decorator/opik_args/api_classes.py +71 -0
  81. opik/decorator/opik_args/helpers.py +120 -0
  82. opik/decorator/span_creation_handler.py +25 -6
  83. opik/dict_utils.py +3 -3
  84. opik/evaluation/__init__.py +13 -2
  85. opik/evaluation/engine/engine.py +272 -75
  86. opik/evaluation/engine/evaluation_tasks_executor.py +6 -3
  87. opik/evaluation/engine/helpers.py +31 -6
  88. opik/evaluation/engine/metrics_evaluator.py +237 -0
  89. opik/evaluation/evaluation_result.py +168 -2
  90. opik/evaluation/evaluator.py +533 -62
  91. opik/evaluation/metrics/__init__.py +103 -4
  92. opik/evaluation/metrics/aggregated_metric.py +35 -6
  93. opik/evaluation/metrics/base_metric.py +1 -1
  94. opik/evaluation/metrics/conversation/__init__.py +48 -0
  95. opik/evaluation/metrics/conversation/conversation_thread_metric.py +56 -2
  96. opik/evaluation/metrics/conversation/g_eval_wrappers.py +19 -0
  97. opik/evaluation/metrics/conversation/helpers.py +14 -15
  98. opik/evaluation/metrics/conversation/heuristics/__init__.py +14 -0
  99. opik/evaluation/metrics/conversation/heuristics/degeneration/__init__.py +3 -0
  100. opik/evaluation/metrics/conversation/heuristics/degeneration/metric.py +189 -0
  101. opik/evaluation/metrics/conversation/heuristics/degeneration/phrases.py +12 -0
  102. opik/evaluation/metrics/conversation/heuristics/knowledge_retention/__init__.py +3 -0
  103. opik/evaluation/metrics/conversation/heuristics/knowledge_retention/metric.py +172 -0
  104. opik/evaluation/metrics/conversation/llm_judges/__init__.py +32 -0
  105. opik/evaluation/metrics/conversation/{conversational_coherence → llm_judges/conversational_coherence}/metric.py +22 -17
  106. opik/evaluation/metrics/conversation/{conversational_coherence → llm_judges/conversational_coherence}/templates.py +1 -1
  107. opik/evaluation/metrics/conversation/llm_judges/g_eval_wrappers.py +442 -0
  108. opik/evaluation/metrics/conversation/{session_completeness → llm_judges/session_completeness}/metric.py +13 -7
  109. opik/evaluation/metrics/conversation/{session_completeness → llm_judges/session_completeness}/templates.py +1 -1
  110. opik/evaluation/metrics/conversation/llm_judges/user_frustration/__init__.py +0 -0
  111. opik/evaluation/metrics/conversation/{user_frustration → llm_judges/user_frustration}/metric.py +21 -14
  112. opik/evaluation/metrics/conversation/{user_frustration → llm_judges/user_frustration}/templates.py +1 -1
  113. opik/evaluation/metrics/conversation/types.py +4 -5
  114. opik/evaluation/metrics/conversation_types.py +9 -0
  115. opik/evaluation/metrics/heuristics/bertscore.py +107 -0
  116. opik/evaluation/metrics/heuristics/bleu.py +35 -15
  117. opik/evaluation/metrics/heuristics/chrf.py +127 -0
  118. opik/evaluation/metrics/heuristics/contains.py +47 -11
  119. opik/evaluation/metrics/heuristics/distribution_metrics.py +331 -0
  120. opik/evaluation/metrics/heuristics/gleu.py +113 -0
  121. opik/evaluation/metrics/heuristics/language_adherence.py +123 -0
  122. opik/evaluation/metrics/heuristics/meteor.py +119 -0
  123. opik/evaluation/metrics/heuristics/prompt_injection.py +150 -0
  124. opik/evaluation/metrics/heuristics/readability.py +129 -0
  125. opik/evaluation/metrics/heuristics/rouge.py +26 -9
  126. opik/evaluation/metrics/heuristics/spearman.py +88 -0
  127. opik/evaluation/metrics/heuristics/tone.py +155 -0
  128. opik/evaluation/metrics/heuristics/vader_sentiment.py +77 -0
  129. opik/evaluation/metrics/llm_judges/answer_relevance/metric.py +20 -5
  130. opik/evaluation/metrics/llm_judges/context_precision/metric.py +20 -6
  131. opik/evaluation/metrics/llm_judges/context_recall/metric.py +20 -6
  132. opik/evaluation/metrics/llm_judges/g_eval/__init__.py +5 -0
  133. opik/evaluation/metrics/llm_judges/g_eval/metric.py +219 -68
  134. opik/evaluation/metrics/llm_judges/g_eval/parser.py +102 -52
  135. opik/evaluation/metrics/llm_judges/g_eval/presets.py +209 -0
  136. opik/evaluation/metrics/llm_judges/g_eval_presets/__init__.py +36 -0
  137. opik/evaluation/metrics/llm_judges/g_eval_presets/agent_assessment.py +77 -0
  138. opik/evaluation/metrics/llm_judges/g_eval_presets/bias_classifier.py +181 -0
  139. opik/evaluation/metrics/llm_judges/g_eval_presets/compliance_risk.py +41 -0
  140. opik/evaluation/metrics/llm_judges/g_eval_presets/prompt_uncertainty.py +41 -0
  141. opik/evaluation/metrics/llm_judges/g_eval_presets/qa_suite.py +146 -0
  142. opik/evaluation/metrics/llm_judges/hallucination/metric.py +16 -3
  143. opik/evaluation/metrics/llm_judges/llm_juries/__init__.py +3 -0
  144. opik/evaluation/metrics/llm_judges/llm_juries/metric.py +76 -0
  145. opik/evaluation/metrics/llm_judges/moderation/metric.py +16 -4
  146. opik/evaluation/metrics/llm_judges/structure_output_compliance/__init__.py +0 -0
  147. opik/evaluation/metrics/llm_judges/structure_output_compliance/metric.py +144 -0
  148. opik/evaluation/metrics/llm_judges/structure_output_compliance/parser.py +79 -0
  149. opik/evaluation/metrics/llm_judges/structure_output_compliance/schema.py +15 -0
  150. opik/evaluation/metrics/llm_judges/structure_output_compliance/template.py +50 -0
  151. opik/evaluation/metrics/llm_judges/syc_eval/__init__.py +0 -0
  152. opik/evaluation/metrics/llm_judges/syc_eval/metric.py +252 -0
  153. opik/evaluation/metrics/llm_judges/syc_eval/parser.py +82 -0
  154. opik/evaluation/metrics/llm_judges/syc_eval/template.py +155 -0
  155. opik/evaluation/metrics/llm_judges/trajectory_accuracy/metric.py +20 -5
  156. opik/evaluation/metrics/llm_judges/usefulness/metric.py +16 -4
  157. opik/evaluation/metrics/ragas_metric.py +43 -23
  158. opik/evaluation/models/__init__.py +8 -0
  159. opik/evaluation/models/base_model.py +107 -1
  160. opik/evaluation/models/langchain/langchain_chat_model.py +15 -7
  161. opik/evaluation/models/langchain/message_converters.py +97 -15
  162. opik/evaluation/models/litellm/litellm_chat_model.py +156 -29
  163. opik/evaluation/models/litellm/util.py +125 -0
  164. opik/evaluation/models/litellm/warning_filters.py +16 -4
  165. opik/evaluation/models/model_capabilities.py +187 -0
  166. opik/evaluation/models/models_factory.py +25 -3
  167. opik/evaluation/preprocessing.py +92 -0
  168. opik/evaluation/report.py +70 -12
  169. opik/evaluation/rest_operations.py +49 -45
  170. opik/evaluation/samplers/__init__.py +4 -0
  171. opik/evaluation/samplers/base_dataset_sampler.py +40 -0
  172. opik/evaluation/samplers/random_dataset_sampler.py +48 -0
  173. opik/evaluation/score_statistics.py +66 -0
  174. opik/evaluation/scorers/__init__.py +4 -0
  175. opik/evaluation/scorers/scorer_function.py +55 -0
  176. opik/evaluation/scorers/scorer_wrapper_metric.py +130 -0
  177. opik/evaluation/test_case.py +3 -2
  178. opik/evaluation/test_result.py +1 -0
  179. opik/evaluation/threads/evaluator.py +31 -3
  180. opik/evaluation/threads/helpers.py +3 -2
  181. opik/evaluation/types.py +9 -1
  182. opik/exceptions.py +33 -0
  183. opik/file_upload/file_uploader.py +13 -0
  184. opik/file_upload/upload_options.py +2 -0
  185. opik/hooks/__init__.py +23 -0
  186. opik/hooks/anonymizer_hook.py +36 -0
  187. opik/hooks/httpx_client_hook.py +112 -0
  188. opik/httpx_client.py +12 -9
  189. opik/id_helpers.py +18 -0
  190. opik/integrations/adk/graph/subgraph_edges_builders.py +1 -2
  191. opik/integrations/adk/helpers.py +16 -7
  192. opik/integrations/adk/legacy_opik_tracer.py +7 -4
  193. opik/integrations/adk/opik_tracer.py +14 -1
  194. opik/integrations/adk/patchers/adk_otel_tracer/opik_adk_otel_tracer.py +7 -3
  195. opik/integrations/adk/recursive_callback_injector.py +4 -7
  196. opik/integrations/bedrock/converse/__init__.py +0 -0
  197. opik/integrations/bedrock/converse/chunks_aggregator.py +188 -0
  198. opik/integrations/bedrock/{converse_decorator.py → converse/converse_decorator.py} +4 -3
  199. opik/integrations/bedrock/invoke_agent_decorator.py +5 -4
  200. opik/integrations/bedrock/invoke_model/__init__.py +0 -0
  201. opik/integrations/bedrock/invoke_model/chunks_aggregator/__init__.py +78 -0
  202. opik/integrations/bedrock/invoke_model/chunks_aggregator/api.py +45 -0
  203. opik/integrations/bedrock/invoke_model/chunks_aggregator/base.py +23 -0
  204. opik/integrations/bedrock/invoke_model/chunks_aggregator/claude.py +121 -0
  205. opik/integrations/bedrock/invoke_model/chunks_aggregator/format_detector.py +107 -0
  206. opik/integrations/bedrock/invoke_model/chunks_aggregator/llama.py +108 -0
  207. opik/integrations/bedrock/invoke_model/chunks_aggregator/mistral.py +118 -0
  208. opik/integrations/bedrock/invoke_model/chunks_aggregator/nova.py +99 -0
  209. opik/integrations/bedrock/invoke_model/invoke_model_decorator.py +178 -0
  210. opik/integrations/bedrock/invoke_model/response_types.py +34 -0
  211. opik/integrations/bedrock/invoke_model/stream_wrappers.py +122 -0
  212. opik/integrations/bedrock/invoke_model/usage_converters.py +87 -0
  213. opik/integrations/bedrock/invoke_model/usage_extraction.py +108 -0
  214. opik/integrations/bedrock/opik_tracker.py +42 -4
  215. opik/integrations/bedrock/types.py +19 -0
  216. opik/integrations/crewai/crewai_decorator.py +8 -51
  217. opik/integrations/crewai/opik_tracker.py +31 -10
  218. opik/integrations/crewai/patchers/__init__.py +5 -0
  219. opik/integrations/crewai/patchers/flow.py +118 -0
  220. opik/integrations/crewai/patchers/litellm_completion.py +30 -0
  221. opik/integrations/crewai/patchers/llm_client.py +207 -0
  222. opik/integrations/dspy/callback.py +80 -17
  223. opik/integrations/dspy/parsers.py +168 -0
  224. opik/integrations/harbor/__init__.py +17 -0
  225. opik/integrations/harbor/experiment_service.py +269 -0
  226. opik/integrations/harbor/opik_tracker.py +528 -0
  227. opik/integrations/haystack/opik_connector.py +2 -2
  228. opik/integrations/haystack/opik_tracer.py +3 -7
  229. opik/integrations/langchain/__init__.py +3 -1
  230. opik/integrations/langchain/helpers.py +96 -0
  231. opik/integrations/langchain/langgraph_async_context_bridge.py +131 -0
  232. opik/integrations/langchain/langgraph_tracer_injector.py +88 -0
  233. opik/integrations/langchain/opik_encoder_extension.py +1 -1
  234. opik/integrations/langchain/opik_tracer.py +474 -229
  235. opik/integrations/litellm/__init__.py +5 -0
  236. opik/integrations/litellm/completion_chunks_aggregator.py +115 -0
  237. opik/integrations/litellm/litellm_completion_decorator.py +242 -0
  238. opik/integrations/litellm/opik_tracker.py +43 -0
  239. opik/integrations/litellm/stream_patchers.py +151 -0
  240. opik/integrations/llama_index/callback.py +146 -107
  241. opik/integrations/openai/agents/opik_tracing_processor.py +1 -2
  242. opik/integrations/openai/openai_chat_completions_decorator.py +2 -16
  243. opik/integrations/openai/opik_tracker.py +1 -1
  244. opik/integrations/sagemaker/auth.py +5 -1
  245. opik/llm_usage/google_usage.py +3 -1
  246. opik/llm_usage/opik_usage.py +7 -8
  247. opik/llm_usage/opik_usage_factory.py +4 -2
  248. opik/logging_messages.py +6 -0
  249. opik/message_processing/batching/base_batcher.py +14 -21
  250. opik/message_processing/batching/batch_manager.py +22 -10
  251. opik/message_processing/batching/batch_manager_constuctors.py +10 -0
  252. opik/message_processing/batching/batchers.py +59 -27
  253. opik/message_processing/batching/flushing_thread.py +0 -3
  254. opik/message_processing/emulation/__init__.py +0 -0
  255. opik/message_processing/emulation/emulator_message_processor.py +578 -0
  256. opik/message_processing/emulation/local_emulator_message_processor.py +140 -0
  257. opik/message_processing/emulation/models.py +162 -0
  258. opik/message_processing/encoder_helpers.py +79 -0
  259. opik/message_processing/messages.py +56 -1
  260. opik/message_processing/preprocessing/__init__.py +0 -0
  261. opik/message_processing/preprocessing/attachments_preprocessor.py +70 -0
  262. opik/message_processing/preprocessing/batching_preprocessor.py +53 -0
  263. opik/message_processing/preprocessing/constants.py +1 -0
  264. opik/message_processing/preprocessing/file_upload_preprocessor.py +38 -0
  265. opik/message_processing/preprocessing/preprocessor.py +36 -0
  266. opik/message_processing/processors/__init__.py +0 -0
  267. opik/message_processing/processors/attachments_extraction_processor.py +146 -0
  268. opik/message_processing/processors/message_processors.py +92 -0
  269. opik/message_processing/processors/message_processors_chain.py +96 -0
  270. opik/message_processing/{message_processors.py → processors/online_message_processor.py} +85 -29
  271. opik/message_processing/queue_consumer.py +9 -3
  272. opik/message_processing/streamer.py +71 -33
  273. opik/message_processing/streamer_constructors.py +43 -10
  274. opik/opik_context.py +16 -4
  275. opik/plugins/pytest/hooks.py +5 -3
  276. opik/rest_api/__init__.py +346 -15
  277. opik/rest_api/alerts/__init__.py +7 -0
  278. opik/rest_api/alerts/client.py +667 -0
  279. opik/rest_api/alerts/raw_client.py +1015 -0
  280. opik/rest_api/alerts/types/__init__.py +7 -0
  281. opik/rest_api/alerts/types/get_webhook_examples_request_alert_type.py +5 -0
  282. opik/rest_api/annotation_queues/__init__.py +4 -0
  283. opik/rest_api/annotation_queues/client.py +668 -0
  284. opik/rest_api/annotation_queues/raw_client.py +1019 -0
  285. opik/rest_api/automation_rule_evaluators/client.py +34 -2
  286. opik/rest_api/automation_rule_evaluators/raw_client.py +24 -0
  287. opik/rest_api/client.py +15 -0
  288. opik/rest_api/dashboards/__init__.py +4 -0
  289. opik/rest_api/dashboards/client.py +462 -0
  290. opik/rest_api/dashboards/raw_client.py +648 -0
  291. opik/rest_api/datasets/client.py +1310 -44
  292. opik/rest_api/datasets/raw_client.py +2269 -358
  293. opik/rest_api/experiments/__init__.py +2 -2
  294. opik/rest_api/experiments/client.py +191 -5
  295. opik/rest_api/experiments/raw_client.py +301 -7
  296. opik/rest_api/experiments/types/__init__.py +4 -1
  297. opik/rest_api/experiments/types/experiment_update_status.py +5 -0
  298. opik/rest_api/experiments/types/experiment_update_type.py +5 -0
  299. opik/rest_api/experiments/types/experiment_write_status.py +5 -0
  300. opik/rest_api/feedback_definitions/types/find_feedback_definitions_request_type.py +1 -1
  301. opik/rest_api/llm_provider_key/client.py +20 -0
  302. opik/rest_api/llm_provider_key/raw_client.py +20 -0
  303. opik/rest_api/llm_provider_key/types/provider_api_key_write_provider.py +1 -1
  304. opik/rest_api/manual_evaluation/__init__.py +4 -0
  305. opik/rest_api/manual_evaluation/client.py +347 -0
  306. opik/rest_api/manual_evaluation/raw_client.py +543 -0
  307. opik/rest_api/optimizations/client.py +145 -9
  308. opik/rest_api/optimizations/raw_client.py +237 -13
  309. opik/rest_api/optimizations/types/optimization_update_status.py +3 -1
  310. opik/rest_api/prompts/__init__.py +2 -2
  311. opik/rest_api/prompts/client.py +227 -6
  312. opik/rest_api/prompts/raw_client.py +331 -2
  313. opik/rest_api/prompts/types/__init__.py +3 -1
  314. opik/rest_api/prompts/types/create_prompt_version_detail_template_structure.py +5 -0
  315. opik/rest_api/prompts/types/prompt_write_template_structure.py +5 -0
  316. opik/rest_api/spans/__init__.py +0 -2
  317. opik/rest_api/spans/client.py +238 -76
  318. opik/rest_api/spans/raw_client.py +307 -95
  319. opik/rest_api/spans/types/__init__.py +0 -2
  320. opik/rest_api/traces/client.py +572 -161
  321. opik/rest_api/traces/raw_client.py +736 -229
  322. opik/rest_api/types/__init__.py +352 -17
  323. opik/rest_api/types/aggregation_data.py +1 -0
  324. opik/rest_api/types/alert.py +33 -0
  325. opik/rest_api/types/alert_alert_type.py +5 -0
  326. opik/rest_api/types/alert_page_public.py +24 -0
  327. opik/rest_api/types/alert_public.py +33 -0
  328. opik/rest_api/types/alert_public_alert_type.py +5 -0
  329. opik/rest_api/types/alert_trigger.py +27 -0
  330. opik/rest_api/types/alert_trigger_config.py +28 -0
  331. opik/rest_api/types/alert_trigger_config_public.py +28 -0
  332. opik/rest_api/types/alert_trigger_config_public_type.py +10 -0
  333. opik/rest_api/types/alert_trigger_config_type.py +10 -0
  334. opik/rest_api/types/alert_trigger_config_write.py +22 -0
  335. opik/rest_api/types/alert_trigger_config_write_type.py +10 -0
  336. opik/rest_api/types/alert_trigger_event_type.py +19 -0
  337. opik/rest_api/types/alert_trigger_public.py +27 -0
  338. opik/rest_api/types/alert_trigger_public_event_type.py +19 -0
  339. opik/rest_api/types/alert_trigger_write.py +23 -0
  340. opik/rest_api/types/alert_trigger_write_event_type.py +19 -0
  341. opik/rest_api/types/alert_write.py +28 -0
  342. opik/rest_api/types/alert_write_alert_type.py +5 -0
  343. opik/rest_api/types/annotation_queue.py +42 -0
  344. opik/rest_api/types/annotation_queue_batch.py +27 -0
  345. opik/rest_api/types/annotation_queue_item_ids.py +19 -0
  346. opik/rest_api/types/annotation_queue_page_public.py +28 -0
  347. opik/rest_api/types/annotation_queue_public.py +38 -0
  348. opik/rest_api/types/annotation_queue_public_scope.py +5 -0
  349. opik/rest_api/types/annotation_queue_reviewer.py +20 -0
  350. opik/rest_api/types/annotation_queue_reviewer_public.py +20 -0
  351. opik/rest_api/types/annotation_queue_scope.py +5 -0
  352. opik/rest_api/types/annotation_queue_write.py +31 -0
  353. opik/rest_api/types/annotation_queue_write_scope.py +5 -0
  354. opik/rest_api/types/audio_url.py +19 -0
  355. opik/rest_api/types/audio_url_public.py +19 -0
  356. opik/rest_api/types/audio_url_write.py +19 -0
  357. opik/rest_api/types/automation_rule_evaluator.py +62 -2
  358. opik/rest_api/types/automation_rule_evaluator_llm_as_judge.py +2 -0
  359. opik/rest_api/types/automation_rule_evaluator_llm_as_judge_public.py +2 -0
  360. opik/rest_api/types/automation_rule_evaluator_llm_as_judge_write.py +2 -0
  361. opik/rest_api/types/automation_rule_evaluator_object_object_public.py +155 -0
  362. opik/rest_api/types/automation_rule_evaluator_page_public.py +3 -2
  363. opik/rest_api/types/automation_rule_evaluator_public.py +57 -2
  364. opik/rest_api/types/automation_rule_evaluator_span_llm_as_judge.py +22 -0
  365. opik/rest_api/types/automation_rule_evaluator_span_llm_as_judge_public.py +22 -0
  366. opik/rest_api/types/automation_rule_evaluator_span_llm_as_judge_write.py +22 -0
  367. opik/rest_api/types/automation_rule_evaluator_span_user_defined_metric_python.py +22 -0
  368. opik/rest_api/types/automation_rule_evaluator_span_user_defined_metric_python_public.py +22 -0
  369. opik/rest_api/types/automation_rule_evaluator_span_user_defined_metric_python_write.py +22 -0
  370. opik/rest_api/types/automation_rule_evaluator_trace_thread_llm_as_judge.py +2 -0
  371. opik/rest_api/types/automation_rule_evaluator_trace_thread_llm_as_judge_public.py +2 -0
  372. opik/rest_api/types/automation_rule_evaluator_trace_thread_llm_as_judge_write.py +2 -0
  373. opik/rest_api/types/automation_rule_evaluator_trace_thread_user_defined_metric_python.py +2 -0
  374. opik/rest_api/types/automation_rule_evaluator_trace_thread_user_defined_metric_python_public.py +2 -0
  375. opik/rest_api/types/automation_rule_evaluator_trace_thread_user_defined_metric_python_write.py +2 -0
  376. opik/rest_api/types/automation_rule_evaluator_update.py +51 -1
  377. opik/rest_api/types/automation_rule_evaluator_update_llm_as_judge.py +2 -0
  378. opik/rest_api/types/automation_rule_evaluator_update_span_llm_as_judge.py +22 -0
  379. opik/rest_api/types/automation_rule_evaluator_update_span_user_defined_metric_python.py +22 -0
  380. opik/rest_api/types/automation_rule_evaluator_update_trace_thread_llm_as_judge.py +2 -0
  381. opik/rest_api/types/automation_rule_evaluator_update_trace_thread_user_defined_metric_python.py +2 -0
  382. opik/rest_api/types/automation_rule_evaluator_update_user_defined_metric_python.py +2 -0
  383. opik/rest_api/types/automation_rule_evaluator_user_defined_metric_python.py +2 -0
  384. opik/rest_api/types/automation_rule_evaluator_user_defined_metric_python_public.py +2 -0
  385. opik/rest_api/types/automation_rule_evaluator_user_defined_metric_python_write.py +2 -0
  386. opik/rest_api/types/automation_rule_evaluator_write.py +51 -1
  387. opik/rest_api/types/boolean_feedback_definition.py +25 -0
  388. opik/rest_api/types/boolean_feedback_definition_create.py +20 -0
  389. opik/rest_api/types/boolean_feedback_definition_public.py +25 -0
  390. opik/rest_api/types/boolean_feedback_definition_update.py +20 -0
  391. opik/rest_api/types/boolean_feedback_detail.py +29 -0
  392. opik/rest_api/types/boolean_feedback_detail_create.py +29 -0
  393. opik/rest_api/types/boolean_feedback_detail_public.py +29 -0
  394. opik/rest_api/types/boolean_feedback_detail_update.py +29 -0
  395. opik/rest_api/types/dashboard_page_public.py +24 -0
  396. opik/rest_api/types/dashboard_public.py +30 -0
  397. opik/rest_api/types/dataset.py +4 -0
  398. opik/rest_api/types/dataset_expansion.py +42 -0
  399. opik/rest_api/types/dataset_expansion_response.py +39 -0
  400. opik/rest_api/types/dataset_item.py +2 -0
  401. opik/rest_api/types/dataset_item_changes_public.py +5 -0
  402. opik/rest_api/types/dataset_item_compare.py +2 -0
  403. opik/rest_api/types/dataset_item_filter.py +27 -0
  404. opik/rest_api/types/dataset_item_filter_operator.py +21 -0
  405. opik/rest_api/types/dataset_item_page_compare.py +5 -0
  406. opik/rest_api/types/dataset_item_page_public.py +5 -0
  407. opik/rest_api/types/dataset_item_public.py +2 -0
  408. opik/rest_api/types/dataset_item_update.py +39 -0
  409. opik/rest_api/types/dataset_item_write.py +1 -0
  410. opik/rest_api/types/dataset_public.py +4 -0
  411. opik/rest_api/types/dataset_public_status.py +5 -0
  412. opik/rest_api/types/dataset_status.py +5 -0
  413. opik/rest_api/types/dataset_version_diff.py +22 -0
  414. opik/rest_api/types/dataset_version_diff_stats.py +24 -0
  415. opik/rest_api/types/dataset_version_page_public.py +23 -0
  416. opik/rest_api/types/dataset_version_public.py +59 -0
  417. opik/rest_api/types/dataset_version_summary.py +46 -0
  418. opik/rest_api/types/dataset_version_summary_public.py +46 -0
  419. opik/rest_api/types/experiment.py +7 -2
  420. opik/rest_api/types/experiment_group_response.py +2 -0
  421. opik/rest_api/types/experiment_public.py +7 -2
  422. opik/rest_api/types/experiment_public_status.py +5 -0
  423. opik/rest_api/types/experiment_score.py +20 -0
  424. opik/rest_api/types/experiment_score_public.py +20 -0
  425. opik/rest_api/types/experiment_score_write.py +20 -0
  426. opik/rest_api/types/experiment_status.py +5 -0
  427. opik/rest_api/types/feedback.py +25 -1
  428. opik/rest_api/types/feedback_create.py +20 -1
  429. opik/rest_api/types/feedback_object_public.py +27 -1
  430. opik/rest_api/types/feedback_public.py +25 -1
  431. opik/rest_api/types/feedback_score_batch_item.py +2 -1
  432. opik/rest_api/types/feedback_score_batch_item_thread.py +2 -1
  433. opik/rest_api/types/feedback_score_public.py +4 -0
  434. opik/rest_api/types/feedback_update.py +20 -1
  435. opik/rest_api/types/group_content_with_aggregations.py +1 -0
  436. opik/rest_api/types/group_detail.py +19 -0
  437. opik/rest_api/types/group_details.py +20 -0
  438. opik/rest_api/types/guardrail.py +1 -0
  439. opik/rest_api/types/guardrail_write.py +1 -0
  440. opik/rest_api/types/ids_holder.py +19 -0
  441. opik/rest_api/types/image_url.py +20 -0
  442. opik/rest_api/types/image_url_public.py +20 -0
  443. opik/rest_api/types/image_url_write.py +20 -0
  444. opik/rest_api/types/llm_as_judge_message.py +5 -1
  445. opik/rest_api/types/llm_as_judge_message_content.py +26 -0
  446. opik/rest_api/types/llm_as_judge_message_content_public.py +26 -0
  447. opik/rest_api/types/llm_as_judge_message_content_write.py +26 -0
  448. opik/rest_api/types/llm_as_judge_message_public.py +5 -1
  449. opik/rest_api/types/llm_as_judge_message_write.py +5 -1
  450. opik/rest_api/types/llm_as_judge_model_parameters.py +3 -0
  451. opik/rest_api/types/llm_as_judge_model_parameters_public.py +3 -0
  452. opik/rest_api/types/llm_as_judge_model_parameters_write.py +3 -0
  453. opik/rest_api/types/manual_evaluation_request.py +38 -0
  454. opik/rest_api/types/manual_evaluation_request_entity_type.py +5 -0
  455. opik/rest_api/types/manual_evaluation_response.py +27 -0
  456. opik/rest_api/types/optimization.py +4 -2
  457. opik/rest_api/types/optimization_public.py +4 -2
  458. opik/rest_api/types/optimization_public_status.py +3 -1
  459. opik/rest_api/types/optimization_status.py +3 -1
  460. opik/rest_api/types/optimization_studio_config.py +27 -0
  461. opik/rest_api/types/optimization_studio_config_public.py +27 -0
  462. opik/rest_api/types/optimization_studio_config_write.py +27 -0
  463. opik/rest_api/types/optimization_studio_log.py +22 -0
  464. opik/rest_api/types/optimization_write.py +4 -2
  465. opik/rest_api/types/optimization_write_status.py +3 -1
  466. opik/rest_api/types/project.py +1 -0
  467. opik/rest_api/types/project_detailed.py +1 -0
  468. opik/rest_api/types/project_reference.py +31 -0
  469. opik/rest_api/types/project_reference_public.py +31 -0
  470. opik/rest_api/types/project_stats_summary_item.py +1 -0
  471. opik/rest_api/types/prompt.py +6 -0
  472. opik/rest_api/types/prompt_detail.py +6 -0
  473. opik/rest_api/types/prompt_detail_template_structure.py +5 -0
  474. opik/rest_api/types/prompt_public.py +6 -0
  475. opik/rest_api/types/prompt_public_template_structure.py +5 -0
  476. opik/rest_api/types/prompt_template_structure.py +5 -0
  477. opik/rest_api/types/prompt_version.py +3 -0
  478. opik/rest_api/types/prompt_version_detail.py +3 -0
  479. opik/rest_api/types/prompt_version_detail_template_structure.py +5 -0
  480. opik/rest_api/types/prompt_version_link.py +1 -0
  481. opik/rest_api/types/prompt_version_link_public.py +1 -0
  482. opik/rest_api/types/prompt_version_page_public.py +5 -0
  483. opik/rest_api/types/prompt_version_public.py +3 -0
  484. opik/rest_api/types/prompt_version_public_template_structure.py +5 -0
  485. opik/rest_api/types/prompt_version_template_structure.py +5 -0
  486. opik/rest_api/types/prompt_version_update.py +33 -0
  487. opik/rest_api/types/provider_api_key.py +9 -0
  488. opik/rest_api/types/provider_api_key_provider.py +1 -1
  489. opik/rest_api/types/provider_api_key_public.py +9 -0
  490. opik/rest_api/types/provider_api_key_public_provider.py +1 -1
  491. opik/rest_api/types/score_name.py +1 -0
  492. opik/rest_api/types/service_toggles_config.py +18 -0
  493. opik/rest_api/types/span.py +1 -2
  494. opik/rest_api/types/span_enrichment_options.py +31 -0
  495. opik/rest_api/types/span_experiment_item_bulk_write_view.py +1 -2
  496. opik/rest_api/types/span_filter.py +23 -0
  497. opik/rest_api/types/span_filter_operator.py +21 -0
  498. opik/rest_api/types/span_filter_write.py +23 -0
  499. opik/rest_api/types/span_filter_write_operator.py +21 -0
  500. opik/rest_api/types/span_llm_as_judge_code.py +27 -0
  501. opik/rest_api/types/span_llm_as_judge_code_public.py +27 -0
  502. opik/rest_api/types/span_llm_as_judge_code_write.py +27 -0
  503. opik/rest_api/types/span_public.py +1 -2
  504. opik/rest_api/types/span_update.py +46 -0
  505. opik/rest_api/types/span_user_defined_metric_python_code.py +20 -0
  506. opik/rest_api/types/span_user_defined_metric_python_code_public.py +20 -0
  507. opik/rest_api/types/span_user_defined_metric_python_code_write.py +20 -0
  508. opik/rest_api/types/span_write.py +1 -2
  509. opik/rest_api/types/studio_evaluation.py +20 -0
  510. opik/rest_api/types/studio_evaluation_public.py +20 -0
  511. opik/rest_api/types/studio_evaluation_write.py +20 -0
  512. opik/rest_api/types/studio_llm_model.py +21 -0
  513. opik/rest_api/types/studio_llm_model_public.py +21 -0
  514. opik/rest_api/types/studio_llm_model_write.py +21 -0
  515. opik/rest_api/types/studio_message.py +20 -0
  516. opik/rest_api/types/studio_message_public.py +20 -0
  517. opik/rest_api/types/studio_message_write.py +20 -0
  518. opik/rest_api/types/studio_metric.py +21 -0
  519. opik/rest_api/types/studio_metric_public.py +21 -0
  520. opik/rest_api/types/studio_metric_write.py +21 -0
  521. opik/rest_api/types/studio_optimizer.py +21 -0
  522. opik/rest_api/types/studio_optimizer_public.py +21 -0
  523. opik/rest_api/types/studio_optimizer_write.py +21 -0
  524. opik/rest_api/types/studio_prompt.py +20 -0
  525. opik/rest_api/types/studio_prompt_public.py +20 -0
  526. opik/rest_api/types/studio_prompt_write.py +20 -0
  527. opik/rest_api/types/trace.py +11 -2
  528. opik/rest_api/types/trace_enrichment_options.py +32 -0
  529. opik/rest_api/types/trace_experiment_item_bulk_write_view.py +1 -2
  530. opik/rest_api/types/trace_filter.py +23 -0
  531. opik/rest_api/types/trace_filter_operator.py +21 -0
  532. opik/rest_api/types/trace_filter_write.py +23 -0
  533. opik/rest_api/types/trace_filter_write_operator.py +21 -0
  534. opik/rest_api/types/trace_public.py +11 -2
  535. opik/rest_api/types/trace_thread_filter_write.py +23 -0
  536. opik/rest_api/types/trace_thread_filter_write_operator.py +21 -0
  537. opik/rest_api/types/trace_thread_identifier.py +1 -0
  538. opik/rest_api/types/trace_update.py +39 -0
  539. opik/rest_api/types/trace_write.py +1 -2
  540. opik/rest_api/types/value_entry.py +2 -0
  541. opik/rest_api/types/value_entry_compare.py +2 -0
  542. opik/rest_api/types/value_entry_experiment_item_bulk_write_view.py +2 -0
  543. opik/rest_api/types/value_entry_public.py +2 -0
  544. opik/rest_api/types/video_url.py +19 -0
  545. opik/rest_api/types/video_url_public.py +19 -0
  546. opik/rest_api/types/video_url_write.py +19 -0
  547. opik/rest_api/types/webhook.py +28 -0
  548. opik/rest_api/types/webhook_examples.py +19 -0
  549. opik/rest_api/types/webhook_public.py +28 -0
  550. opik/rest_api/types/webhook_test_result.py +23 -0
  551. opik/rest_api/types/webhook_test_result_status.py +5 -0
  552. opik/rest_api/types/webhook_write.py +23 -0
  553. opik/rest_api/types/welcome_wizard_tracking.py +22 -0
  554. opik/rest_api/types/workspace_configuration.py +5 -0
  555. opik/rest_api/welcome_wizard/__init__.py +4 -0
  556. opik/rest_api/welcome_wizard/client.py +195 -0
  557. opik/rest_api/welcome_wizard/raw_client.py +208 -0
  558. opik/rest_api/workspaces/client.py +14 -2
  559. opik/rest_api/workspaces/raw_client.py +10 -0
  560. opik/s3_httpx_client.py +14 -1
  561. opik/simulation/__init__.py +6 -0
  562. opik/simulation/simulated_user.py +99 -0
  563. opik/simulation/simulator.py +108 -0
  564. opik/synchronization.py +5 -6
  565. opik/{decorator/tracing_runtime_config.py → tracing_runtime_config.py} +6 -7
  566. opik/types.py +36 -0
  567. opik/validation/chat_prompt_messages.py +241 -0
  568. opik/validation/feedback_score.py +3 -3
  569. opik/validation/validator.py +28 -0
  570. opik-1.9.71.dist-info/METADATA +370 -0
  571. opik-1.9.71.dist-info/RECORD +1110 -0
  572. opik/api_objects/prompt/prompt.py +0 -112
  573. opik/cli.py +0 -193
  574. opik/hooks.py +0 -13
  575. opik/integrations/bedrock/chunks_aggregator.py +0 -55
  576. opik/integrations/bedrock/helpers.py +0 -8
  577. opik/rest_api/types/automation_rule_evaluator_object_public.py +0 -100
  578. opik/rest_api/types/json_node_experiment_item_bulk_write_view.py +0 -5
  579. opik-1.8.39.dist-info/METADATA +0 -339
  580. opik-1.8.39.dist-info/RECORD +0 -790
  581. /opik/{evaluation/metrics/conversation/conversational_coherence → decorator/context_manager}/__init__.py +0 -0
  582. /opik/evaluation/metrics/conversation/{session_completeness → llm_judges/conversational_coherence}/__init__.py +0 -0
  583. /opik/evaluation/metrics/conversation/{conversational_coherence → llm_judges/conversational_coherence}/schema.py +0 -0
  584. /opik/evaluation/metrics/conversation/{user_frustration → llm_judges/session_completeness}/__init__.py +0 -0
  585. /opik/evaluation/metrics/conversation/{session_completeness → llm_judges/session_completeness}/schema.py +0 -0
  586. /opik/evaluation/metrics/conversation/{user_frustration → llm_judges/user_frustration}/schema.py +0 -0
  587. /opik/integrations/bedrock/{stream_wrappers.py → converse/stream_wrappers.py} +0 -0
  588. /opik/rest_api/{spans/types → types}/span_update_type.py +0 -0
  589. {opik-1.8.39.dist-info → opik-1.9.71.dist-info}/WHEEL +0 -0
  590. {opik-1.8.39.dist-info → opik-1.9.71.dist-info}/entry_points.txt +0 -0
  591. {opik-1.8.39.dist-info → opik-1.9.71.dist-info}/licenses/LICENSE +0 -0
  592. {opik-1.8.39.dist-info → opik-1.9.71.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,7 @@ from typing import Any, Callable, Dict, List, Optional, Union
3
3
 
4
4
  from .. import datetime_helpers, llm_usage
5
5
  from ..api_objects import helpers, span
6
- from ..types import ErrorInfoDict, SpanType
6
+ from ..types import ErrorInfoDict, SpanType, DistributedTraceHeadersDict
7
7
 
8
8
 
9
9
  @dataclasses.dataclass
@@ -34,6 +34,7 @@ class EndSpanParameters(BaseArguments):
34
34
  model: Optional[str] = None
35
35
  provider: Optional[str] = None
36
36
  error_info: Optional[ErrorInfoDict] = None
37
+ total_cost: Optional[float] = None
37
38
 
38
39
 
39
40
  @dataclasses.dataclass
@@ -51,6 +52,7 @@ class StartSpanParameters(BaseArguments):
51
52
  project_name: Optional[str] = None
52
53
  model: Optional[str] = None
53
54
  provider: Optional[str] = None
55
+ thread_id: Optional[str] = None # used for traces only
54
56
 
55
57
 
56
58
  @dataclasses.dataclass
@@ -91,3 +93,9 @@ def create_span_data(
91
93
  provider=start_span_arguments.provider,
92
94
  )
93
95
  return span_data
96
+
97
+
98
+ def extract_distributed_trace_headers(
99
+ kwargs: Dict[str, Any],
100
+ ) -> Optional[DistributedTraceHeadersDict]:
101
+ return kwargs.pop("opik_distributed_trace_headers", None)
@@ -11,9 +11,10 @@ from typing import (
11
11
  Set,
12
12
  Tuple,
13
13
  Union,
14
+ NamedTuple,
14
15
  )
15
16
 
16
- from .. import context_storage, logging_messages
17
+ from .. import context_storage, logging_messages, tracing_runtime_config
17
18
  from ..api_objects import opik_client, span, trace
18
19
  from ..types import DistributedTraceHeadersDict, ErrorInfoDict, SpanType
19
20
  from . import (
@@ -21,8 +22,8 @@ from . import (
21
22
  error_info_collector,
22
23
  generator_wrappers,
23
24
  inspect_helpers,
25
+ opik_args,
24
26
  span_creation_handler,
25
- tracing_runtime_config,
26
27
  )
27
28
 
28
29
  LOGGER = logging.getLogger(__name__)
@@ -30,6 +31,12 @@ LOGGER = logging.getLogger(__name__)
30
31
  TRACES_CREATED_BY_DECORATOR: Set[str] = set()
31
32
 
32
33
 
34
+ class TrackingStartOptions(NamedTuple):
35
+ start_span_parameters: arguments_helpers.StartSpanParameters
36
+ opik_args: Optional[opik_args.OpikArgs]
37
+ opik_distributed_trace_headers: Optional[DistributedTraceHeadersDict]
38
+
39
+
33
40
  class BaseTrackDecorator(abc.ABC):
34
41
  """
35
42
  For internal usage.
@@ -152,6 +159,10 @@ class BaseTrackDecorator(abc.ABC):
152
159
  So these spans can't be parents for other spans. This is usually the case LLM API calls
153
160
  with `stream=True`.
154
161
  """
162
+ # Idempotency: skip re-decoration if already tracked
163
+ if hasattr(func, "opik_tracked") and func.opik_tracked: # type: ignore
164
+ return func
165
+
155
166
  if inspect.isgeneratorfunction(func):
156
167
  return self._tracked_sync_generator(func=func, track_options=track_options)
157
168
 
@@ -172,6 +183,54 @@ class BaseTrackDecorator(abc.ABC):
172
183
  track_options=track_options,
173
184
  )
174
185
 
186
+ def _prepare_tracking_start_options(
187
+ self,
188
+ func: Callable,
189
+ track_options: arguments_helpers.TrackOptions,
190
+ args: Tuple,
191
+ kwargs: Dict[str, Any],
192
+ ) -> TrackingStartOptions:
193
+ opik_distributed_trace_headers = (
194
+ arguments_helpers.extract_distributed_trace_headers(kwargs)
195
+ )
196
+
197
+ opik_args_ = None
198
+ try:
199
+ opik_args_ = opik_args.extract_opik_args(kwargs, func)
200
+
201
+ start_span_arguments = self._start_span_inputs_preprocessor(
202
+ func=func,
203
+ track_options=track_options,
204
+ args=args,
205
+ kwargs=kwargs,
206
+ )
207
+
208
+ # Apply opik_args to start span arguments
209
+ start_span_arguments = opik_args.apply_opik_args_to_start_span_params(
210
+ params=start_span_arguments,
211
+ opik_args=opik_args_,
212
+ )
213
+ except Exception as exception:
214
+ LOGGER.error(
215
+ logging_messages.UNEXPECTED_EXCEPTION_ON_SPAN_CREATION_FOR_TRACKED_FUNCTION,
216
+ inspect_helpers.get_function_name(func),
217
+ (args, kwargs),
218
+ str(exception),
219
+ exc_info=True,
220
+ )
221
+
222
+ start_span_arguments = arguments_helpers.StartSpanParameters(
223
+ name=inspect_helpers.get_function_name(func),
224
+ type=track_options.type,
225
+ tags=track_options.tags,
226
+ metadata=track_options.metadata,
227
+ project_name=track_options.project_name,
228
+ )
229
+
230
+ return TrackingStartOptions(
231
+ start_span_arguments, opik_args_, opik_distributed_trace_headers
232
+ )
233
+
175
234
  def _tracked_sync_generator(
176
235
  self, func: Callable, track_options: arguments_helpers.TrackOptions
177
236
  ) -> Callable:
@@ -179,31 +238,19 @@ class BaseTrackDecorator(abc.ABC):
179
238
  def wrapper(*args, **kwargs) -> Any: # type: ignore
180
239
  if not tracing_runtime_config.is_tracing_active():
181
240
  return func(*args, **kwargs)
182
- try:
183
- opik_distributed_trace_headers: Optional[
184
- DistributedTraceHeadersDict
185
- ] = kwargs.pop("opik_distributed_trace_headers", None)
186
241
 
187
- start_span_arguments = self._start_span_inputs_preprocessor(
188
- func=func,
189
- track_options=track_options,
190
- args=args,
191
- kwargs=kwargs,
192
- )
193
- except Exception as exception:
194
- LOGGER.error(
195
- logging_messages.UNEXPECTED_EXCEPTION_ON_SPAN_CREATION_FOR_TRACKED_FUNCTION,
196
- inspect_helpers.get_function_name(func),
197
- (args, kwargs),
198
- str(exception),
199
- exc_info=True,
200
- )
242
+ track_start_options = self._prepare_tracking_start_options(
243
+ func=func,
244
+ track_options=track_options,
245
+ args=args,
246
+ kwargs=kwargs,
247
+ )
201
248
 
202
249
  try:
203
250
  result = generator_wrappers.SyncTrackedGenerator(
204
251
  func(*args, **kwargs),
205
- start_span_arguments=start_span_arguments,
206
- opik_distributed_trace_headers=opik_distributed_trace_headers,
252
+ start_span_arguments=track_start_options.start_span_parameters,
253
+ opik_distributed_trace_headers=track_start_options.opik_distributed_trace_headers,
207
254
  track_options=track_options,
208
255
  finally_callback=self._after_call,
209
256
  )
@@ -229,31 +276,19 @@ class BaseTrackDecorator(abc.ABC):
229
276
  def wrapper(*args, **kwargs) -> Any: # type: ignore
230
277
  if not tracing_runtime_config.is_tracing_active():
231
278
  return func(*args, **kwargs)
232
- try:
233
- opik_distributed_trace_headers: Optional[
234
- DistributedTraceHeadersDict
235
- ] = kwargs.pop("opik_distributed_trace_headers", None)
236
279
 
237
- start_span_arguments = self._start_span_inputs_preprocessor(
238
- func=func,
239
- track_options=track_options,
240
- args=args,
241
- kwargs=kwargs,
242
- )
243
- except Exception as exception:
244
- LOGGER.error(
245
- logging_messages.UNEXPECTED_EXCEPTION_ON_SPAN_CREATION_FOR_TRACKED_FUNCTION,
246
- inspect_helpers.get_function_name(func),
247
- (args, kwargs),
248
- str(exception),
249
- exc_info=True,
250
- )
280
+ track_start_options = self._prepare_tracking_start_options(
281
+ func=func,
282
+ track_options=track_options,
283
+ args=args,
284
+ kwargs=kwargs,
285
+ )
251
286
 
252
287
  try:
253
288
  result = generator_wrappers.AsyncTrackedGenerator(
254
289
  func(*args, **kwargs),
255
- start_span_arguments=start_span_arguments,
256
- opik_distributed_trace_headers=opik_distributed_trace_headers,
290
+ start_span_arguments=track_start_options.start_span_parameters,
291
+ opik_distributed_trace_headers=track_start_options.opik_distributed_trace_headers,
257
292
  track_options=track_options,
258
293
  finally_callback=self._after_call,
259
294
  )
@@ -301,25 +336,24 @@ class BaseTrackDecorator(abc.ABC):
301
336
  )
302
337
  error_info = error_info_collector.collect(exception)
303
338
  func_exception = exception
304
- finally:
305
- stream_or_stream_manager = self._streams_handler(
306
- result,
307
- track_options.capture_output,
308
- track_options.generations_aggregator,
309
- )
310
- if stream_or_stream_manager is not None:
311
- return stream_or_stream_manager
312
-
313
- self._after_call(
314
- output=result,
315
- error_info=error_info,
316
- capture_output=track_options.capture_output,
317
- flush=track_options.flush,
318
- )
319
- if func_exception is not None:
320
- raise func_exception
321
- else:
322
- return result
339
+
340
+ stream_or_stream_manager = self._streams_handler(
341
+ result,
342
+ track_options.capture_output,
343
+ track_options.generations_aggregator,
344
+ )
345
+ if stream_or_stream_manager is not None:
346
+ return stream_or_stream_manager
347
+
348
+ self._after_call(
349
+ output=result,
350
+ error_info=error_info,
351
+ capture_output=track_options.capture_output,
352
+ flush=track_options.flush,
353
+ )
354
+ if func_exception is not None:
355
+ raise func_exception
356
+ return result
323
357
 
324
358
  wrapper.opik_tracked = True # type: ignore
325
359
 
@@ -355,25 +389,24 @@ class BaseTrackDecorator(abc.ABC):
355
389
  )
356
390
  error_info = error_info_collector.collect(exception)
357
391
  func_exception = exception
358
- finally:
359
- stream_or_stream_manager = self._streams_handler(
360
- result,
361
- track_options.capture_output,
362
- track_options.generations_aggregator,
363
- )
364
- if stream_or_stream_manager is not None:
365
- return stream_or_stream_manager
366
-
367
- self._after_call(
368
- output=result,
369
- error_info=error_info,
370
- capture_output=track_options.capture_output,
371
- flush=track_options.flush,
372
- )
373
- if func_exception is not None:
374
- raise func_exception
375
- else:
376
- return result
392
+
393
+ stream_or_stream_manager = self._streams_handler(
394
+ result,
395
+ track_options.capture_output,
396
+ track_options.generations_aggregator,
397
+ )
398
+ if stream_or_stream_manager is not None:
399
+ return stream_or_stream_manager
400
+
401
+ self._after_call(
402
+ output=result,
403
+ error_info=error_info,
404
+ capture_output=track_options.capture_output,
405
+ flush=track_options.flush,
406
+ )
407
+ if func_exception is not None:
408
+ raise func_exception
409
+ return result
377
410
 
378
411
  wrapper.opik_tracked = True # type: ignore
379
412
  return wrapper
@@ -408,61 +441,19 @@ class BaseTrackDecorator(abc.ABC):
408
441
  args: Tuple,
409
442
  kwargs: Dict[str, Any],
410
443
  ) -> None:
411
- opik_distributed_trace_headers: Optional[DistributedTraceHeadersDict] = None
412
-
413
- try:
414
- opik_distributed_trace_headers = kwargs.pop(
415
- "opik_distributed_trace_headers", None
416
- )
417
-
418
- start_span_arguments = self._start_span_inputs_preprocessor(
419
- func=func,
420
- track_options=track_options,
421
- args=args,
422
- kwargs=kwargs,
423
- )
424
- except Exception as exception:
425
- LOGGER.error(
426
- logging_messages.UNEXPECTED_EXCEPTION_ON_SPAN_CREATION_FOR_TRACKED_FUNCTION,
427
- inspect_helpers.get_function_name(func),
428
- (args, kwargs),
429
- str(exception),
430
- exc_info=True,
431
- )
432
-
433
- start_span_arguments = arguments_helpers.StartSpanParameters(
434
- name=inspect_helpers.get_function_name(func),
435
- type=track_options.type,
436
- tags=track_options.tags,
437
- metadata=track_options.metadata,
438
- project_name=track_options.project_name,
439
- )
440
-
441
- created_trace_data, created_span_data = (
442
- span_creation_handler.create_span_respecting_context(
443
- start_span_arguments=start_span_arguments,
444
- distributed_trace_headers=opik_distributed_trace_headers,
445
- )
444
+ track_start_options = self._prepare_tracking_start_options(
445
+ func=func,
446
+ track_options=track_options,
447
+ args=args,
448
+ kwargs=kwargs,
446
449
  )
447
- client = opik_client.get_client_cached()
448
-
449
- if (
450
- client.config.log_start_trace_span
451
- and tracing_runtime_config.is_tracing_active()
452
- ):
453
- client.span(**created_span_data.as_start_parameters)
454
450
 
455
- if created_trace_data is not None:
456
- context_storage.set_trace_data(created_trace_data)
457
- TRACES_CREATED_BY_DECORATOR.add(created_trace_data.id)
458
-
459
- if (
460
- client.config.log_start_trace_span
461
- and tracing_runtime_config.is_tracing_active()
462
- ):
463
- client.trace(**created_trace_data.as_start_parameters)
464
-
465
- context_storage.add_span_data(created_span_data)
451
+ add_start_candidates(
452
+ start_span_parameters=track_start_options.start_span_parameters,
453
+ opik_distributed_trace_headers=track_start_options.opik_distributed_trace_headers,
454
+ opik_args_data=track_start_options.opik_args,
455
+ tracing_active=tracing_runtime_config.is_tracing_active(),
456
+ )
466
457
 
467
458
  def _after_call(
468
459
  self,
@@ -619,3 +610,84 @@ def pop_end_candidates() -> Tuple[span.SpanData, Optional[trace.TraceData]]:
619
610
  TRACES_CREATED_BY_DECORATOR.discard(possible_trace_data_to_end.id)
620
611
 
621
612
  return span_data_to_end, trace_data_to_end
613
+
614
+
615
+ def add_start_candidates(
616
+ start_span_parameters: arguments_helpers.StartSpanParameters,
617
+ opik_distributed_trace_headers: Optional[DistributedTraceHeadersDict],
618
+ opik_args_data: Optional[opik_args.OpikArgs],
619
+ tracing_active: bool,
620
+ ) -> span_creation_handler.SpanCreationResult:
621
+ """
622
+ Handles the creation and registration of a new start span and trace while respecting the
623
+ tracing context based on given parameters. It also applies relevant arguments
624
+ to the trace if it was created and handles client logging if the tracing is active.
625
+
626
+ Args:
627
+ start_span_parameters: The parameters used to start the span, including the
628
+ span name and other configurations.
629
+ opik_distributed_trace_headers: Optional headers for distributed tracing, which
630
+ are passed to the span creation process.
631
+ opik_args_data : Optional additional arguments that can be applied to the trace
632
+ data after the span is created.
633
+ tracing_active: A boolean indicating whether a tracing is active.
634
+
635
+ Returns:
636
+ The result of the span creation, including the span and trace data.
637
+ """
638
+ span_creation_result = span_creation_handler.create_span_respecting_context(
639
+ start_span_arguments=start_span_parameters,
640
+ distributed_trace_headers=opik_distributed_trace_headers,
641
+ )
642
+ context_storage.add_span_data(span_creation_result.span_data)
643
+
644
+ if tracing_active:
645
+ client = opik_client.get_client_cached()
646
+
647
+ if client.config.log_start_trace_span:
648
+ client.span(**span_creation_result.span_data.as_start_parameters)
649
+
650
+ if span_creation_result.trace_data is not None:
651
+ add_start_trace_candidate(
652
+ trace_data=span_creation_result.trace_data,
653
+ opik_args_data=opik_args_data,
654
+ tracing_active=tracing_active,
655
+ )
656
+
657
+ return span_creation_result
658
+
659
+
660
+ def add_start_trace_candidate(
661
+ trace_data: trace.TraceData,
662
+ opik_args_data: Optional[opik_args.OpikArgs],
663
+ tracing_active: bool,
664
+ ) -> None:
665
+ """
666
+ Adds a start trace candidate to the current context storage and updates
667
+ it with the given Opik arguments if applicable.
668
+
669
+ This function initializes the trace data in the current context and
670
+ tracks its creation. It also applies provided Opik argument modifications
671
+ to the trace and logs the start trace span in the client if tracing is
672
+ active and logging is enabled.
673
+
674
+ Args:
675
+ trace_data: The trace data object to be added and initialized in the
676
+ current context storage. It contains details about the trace.
677
+ opik_args_data: Optional OpikArgs object containing additional data
678
+ to be applied to the trace. This may include configurations
679
+ that modify or enrich the trace data.
680
+ tracing_active: A boolean indicating whether a tracing is active.
681
+ """
682
+ context_storage.set_trace_data(trace_data)
683
+ TRACES_CREATED_BY_DECORATOR.add(trace_data.id)
684
+
685
+ # Handle thread_id and trace updates after span/trace creation
686
+ opik_args.apply_opik_args_to_trace(opik_args=opik_args_data, trace_data=trace_data)
687
+
688
+ if not tracing_active:
689
+ return
690
+
691
+ client = opik_client.get_client_cached()
692
+ if client.config.log_start_trace_span:
693
+ client.trace(**trace_data.as_start_parameters)
@@ -0,0 +1,123 @@
1
+ import logging
2
+ from contextlib import contextmanager
3
+ from typing import Optional, Dict, Any, List, Generator
4
+
5
+ from opik.api_objects import span, opik_client
6
+ from opik.types import SpanType
7
+ from opik import context_storage
8
+ from .. import arguments_helpers, base_track_decorator, error_info_collector
9
+
10
+ LOGGER = logging.getLogger(__name__)
11
+
12
+
13
+ @contextmanager
14
+ def start_as_current_span(
15
+ name: str,
16
+ type: SpanType = "general",
17
+ input: Optional[Dict[str, Any]] = None,
18
+ output: Optional[Dict[str, Any]] = None,
19
+ tags: Optional[List[str]] = None,
20
+ metadata: Optional[Dict[str, Any]] = None,
21
+ project_name: Optional[str] = None,
22
+ model: Optional[str] = None,
23
+ provider: Optional[str] = None,
24
+ flush: bool = False,
25
+ **kwargs: Dict[str, Any],
26
+ ) -> Generator[span.SpanData, Any, None]:
27
+ """
28
+ A context manager for starting and managing a span and parent trace.
29
+
30
+ This function creates a span and parent trace (if missing) with input parameters, processes outputs,
31
+ handles errors, and ensures the span/trace data is saved and flushed at the end of its lifecycle.
32
+ It integrates distributed tracing headers and allows additional metadata, tags, and other
33
+ contextual information to be provided.
34
+
35
+ Args:
36
+ name: The name of the span to create.
37
+ type: The type of the span. Defaults to "general".
38
+ input: A dictionary representing the input data associated with the span.
39
+ output: A dictionary for providing the output associated with the span.
40
+ tags: A list of tags to associate with the span.
41
+ metadata: A dictionary of additional metadata to attach to the span or trace.
42
+ project_name: The name of the project associated with this span.
43
+ model: The model name related to the span or trace.
44
+ provider: The provider responsible for the span or trace.
45
+ flush: Whether to flush the client data after the span is created and processed.
46
+ **kwargs (Dict[str, Any]): Additional parameters that may be passed to the
47
+ context manager.
48
+
49
+ Yields:
50
+ An iterator that provides the span data within the context of the span manager lifecycle.
51
+ """
52
+ start_span_parameters = arguments_helpers.StartSpanParameters(
53
+ name=name,
54
+ input=input,
55
+ type=type,
56
+ project_name=project_name,
57
+ model=model,
58
+ provider=provider,
59
+ )
60
+ distributed_headers = arguments_helpers.extract_distributed_trace_headers(kwargs)
61
+
62
+ # create span/trace with input parameters
63
+ span_creation_result = base_track_decorator.add_start_candidates(
64
+ start_span_parameters=start_span_parameters,
65
+ opik_distributed_trace_headers=distributed_headers,
66
+ opik_args_data=None,
67
+ tracing_active=True,
68
+ )
69
+
70
+ end_arguments = arguments_helpers.EndSpanParameters(
71
+ input=span_creation_result.span_data.input or input,
72
+ output=span_creation_result.span_data.output or output,
73
+ tags=span_creation_result.span_data.tags or tags,
74
+ metadata=span_creation_result.span_data.metadata or metadata,
75
+ provider=span_creation_result.span_data.provider or provider,
76
+ model=span_creation_result.span_data.model or model,
77
+ )
78
+ try:
79
+ yield span_creation_result.span_data
80
+
81
+ # update end arguments
82
+ end_arguments.input = span_creation_result.span_data.input or input
83
+ end_arguments.output = span_creation_result.span_data.output or output
84
+ end_arguments.tags = span_creation_result.span_data.tags or tags
85
+ end_arguments.metadata = span_creation_result.span_data.metadata or metadata
86
+ end_arguments.provider = span_creation_result.span_data.provider or provider
87
+ end_arguments.model = span_creation_result.span_data.model or model
88
+ except Exception as exception:
89
+ LOGGER.error(
90
+ "Error in user's script while executing span context manager: %s",
91
+ str(exception),
92
+ exc_info=True,
93
+ )
94
+
95
+ # collect error info
96
+ end_arguments.error_info = error_info_collector.collect(exception)
97
+ end_arguments.output = None
98
+ raise
99
+ finally:
100
+ # save span/trace data at the end of the context manager
101
+ client = opik_client.get_client_cached()
102
+
103
+ span_creation_result.span_data.init_end_time().update(
104
+ **end_arguments.to_kwargs(),
105
+ )
106
+ client.span(**span_creation_result.span_data.as_parameters)
107
+
108
+ if span_creation_result.trace_data is not None:
109
+ span_creation_result.trace_data.init_end_time().update(
110
+ **end_arguments.to_kwargs(ignore_keys=["usage", "model", "provider"]),
111
+ )
112
+ client.trace(**span_creation_result.trace_data.as_parameters)
113
+
114
+ # Clean up span and trace from context
115
+ opik_context_storage = context_storage.get_current_context_instance()
116
+ opik_context_storage.pop_span_data(ensure_id=span_creation_result.span_data.id)
117
+ if span_creation_result.trace_data is not None:
118
+ opik_context_storage.pop_trace_data(
119
+ ensure_id=span_creation_result.trace_data.id
120
+ )
121
+
122
+ if flush:
123
+ client.flush()
@@ -0,0 +1,84 @@
1
+ import logging
2
+ from contextlib import contextmanager
3
+ from typing import Any, Generator, Optional, Dict, List
4
+
5
+ from opik import datetime_helpers
6
+ from opik.api_objects import trace, opik_client, helpers
7
+ from opik import context_storage
8
+ from .. import base_track_decorator, error_info_collector
9
+
10
+ LOGGER = logging.getLogger(__name__)
11
+
12
+
13
+ @contextmanager
14
+ def start_as_current_trace(
15
+ name: str,
16
+ input: Optional[Dict[str, Any]] = None,
17
+ output: Optional[Dict[str, Any]] = None,
18
+ tags: Optional[List[str]] = None,
19
+ metadata: Optional[Dict[str, Any]] = None,
20
+ project_name: Optional[str] = None,
21
+ thread_id: Optional[str] = None,
22
+ flush: bool = False,
23
+ ) -> Generator[trace.TraceData, Any, None]:
24
+ """
25
+ Starts a trace context manager to collect and manage tracing data during the
26
+ execution of a code block. This function initializes a trace, allows for
27
+ modifications within the context, and finishes the trace, sending data to the
28
+ Opik tracing infrastructure.
29
+
30
+ Args:
31
+ name: The name of the trace for identification purposes.
32
+ input: Optional input data associated with the trace.
33
+ output: Optional output data expected or associated with the trace.
34
+ tags: Optional list of string tags for labeling or describing the trace.
35
+ metadata: Optional dictionary containing additional information about the
36
+ trace.
37
+ project_name: Optional name of the project under which the trace belongs.
38
+ thread_id: Optional thread identifier to associate the trace with a
39
+ specific thread.
40
+ flush: A boolean indicating whether to flush the trace data immediately
41
+ after finishing the trace context.
42
+
43
+ Yields:
44
+ Provides the initialized trace data for manipulation during execution in the context.
45
+ """
46
+ trace_data = trace.TraceData(
47
+ id=helpers.generate_id(),
48
+ start_time=datetime_helpers.local_timestamp(),
49
+ name=name,
50
+ input=input,
51
+ output=output,
52
+ metadata=metadata,
53
+ tags=tags,
54
+ project_name=project_name,
55
+ thread_id=thread_id,
56
+ )
57
+ base_track_decorator.add_start_trace_candidate(
58
+ trace_data=trace_data,
59
+ opik_args_data=None,
60
+ tracing_active=True,
61
+ )
62
+
63
+ try:
64
+ yield trace_data
65
+ except Exception as exception:
66
+ LOGGER.error(
67
+ "Error in user's script while executing trace context manager: %s",
68
+ str(exception),
69
+ exc_info=True,
70
+ )
71
+ trace_data.error_info = error_info_collector.collect(exception)
72
+ trace_data.output = None
73
+ raise
74
+ finally:
75
+ # save trace data at the end of the context manager
76
+ client = opik_client.get_client_cached()
77
+ client.trace(**trace_data.init_end_time().as_parameters)
78
+
79
+ # Clean up trace from context
80
+ opik_context_storage = context_storage.get_current_context_instance()
81
+ opik_context_storage.pop_trace_data(ensure_id=trace_data.id)
82
+
83
+ if flush:
84
+ client.flush()
@@ -0,0 +1,13 @@
1
+ from .api_classes import OpikArgs
2
+ from .helpers import (
3
+ extract_opik_args,
4
+ apply_opik_args_to_start_span_params,
5
+ apply_opik_args_to_trace,
6
+ )
7
+
8
+ __all__ = [
9
+ "OpikArgs",
10
+ "extract_opik_args",
11
+ "apply_opik_args_to_start_span_params",
12
+ "apply_opik_args_to_trace",
13
+ ]