opik 1.9.39__py3-none-any.whl → 1.9.86__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 (195) hide show
  1. opik/api_objects/attachment/attachment_context.py +36 -0
  2. opik/api_objects/attachment/attachments_extractor.py +153 -0
  3. opik/api_objects/attachment/client.py +1 -0
  4. opik/api_objects/attachment/converters.py +2 -0
  5. opik/api_objects/attachment/decoder.py +18 -0
  6. opik/api_objects/attachment/decoder_base64.py +83 -0
  7. opik/api_objects/attachment/decoder_helpers.py +137 -0
  8. opik/api_objects/constants.py +2 -0
  9. opik/api_objects/dataset/dataset.py +133 -40
  10. opik/api_objects/dataset/rest_operations.py +2 -0
  11. opik/api_objects/experiment/experiment.py +6 -0
  12. opik/api_objects/helpers.py +8 -4
  13. opik/api_objects/local_recording.py +6 -5
  14. opik/api_objects/observation_data.py +101 -0
  15. opik/api_objects/opik_client.py +78 -45
  16. opik/api_objects/opik_query_language.py +9 -3
  17. opik/api_objects/prompt/chat/chat_prompt.py +18 -1
  18. opik/api_objects/prompt/client.py +8 -1
  19. opik/api_objects/span/span_data.py +3 -88
  20. opik/api_objects/threads/threads_client.py +7 -4
  21. opik/api_objects/trace/trace_data.py +3 -74
  22. opik/api_objects/validation_helpers.py +3 -3
  23. opik/cli/exports/__init__.py +131 -0
  24. opik/cli/exports/dataset.py +278 -0
  25. opik/cli/exports/experiment.py +784 -0
  26. opik/cli/exports/project.py +685 -0
  27. opik/cli/exports/prompt.py +578 -0
  28. opik/cli/exports/utils.py +406 -0
  29. opik/cli/harbor.py +39 -0
  30. opik/cli/imports/__init__.py +439 -0
  31. opik/cli/imports/dataset.py +143 -0
  32. opik/cli/imports/experiment.py +1192 -0
  33. opik/cli/imports/project.py +262 -0
  34. opik/cli/imports/prompt.py +177 -0
  35. opik/cli/imports/utils.py +280 -0
  36. opik/cli/main.py +14 -12
  37. opik/config.py +12 -1
  38. opik/datetime_helpers.py +12 -0
  39. opik/decorator/arguments_helpers.py +4 -1
  40. opik/decorator/base_track_decorator.py +111 -37
  41. opik/decorator/context_manager/span_context_manager.py +5 -1
  42. opik/decorator/generator_wrappers.py +5 -4
  43. opik/decorator/span_creation_handler.py +13 -4
  44. opik/evaluation/engine/engine.py +111 -28
  45. opik/evaluation/engine/evaluation_tasks_executor.py +71 -19
  46. opik/evaluation/evaluator.py +12 -0
  47. opik/evaluation/metrics/conversation/llm_judges/conversational_coherence/metric.py +3 -1
  48. opik/evaluation/metrics/conversation/llm_judges/session_completeness/metric.py +3 -1
  49. opik/evaluation/metrics/conversation/llm_judges/user_frustration/metric.py +3 -1
  50. opik/evaluation/metrics/heuristics/equals.py +11 -7
  51. opik/evaluation/metrics/llm_judges/answer_relevance/metric.py +3 -1
  52. opik/evaluation/metrics/llm_judges/context_precision/metric.py +3 -1
  53. opik/evaluation/metrics/llm_judges/context_recall/metric.py +3 -1
  54. opik/evaluation/metrics/llm_judges/factuality/metric.py +1 -1
  55. opik/evaluation/metrics/llm_judges/g_eval/metric.py +3 -1
  56. opik/evaluation/metrics/llm_judges/hallucination/metric.py +3 -1
  57. opik/evaluation/metrics/llm_judges/moderation/metric.py +3 -1
  58. opik/evaluation/metrics/llm_judges/structure_output_compliance/metric.py +3 -1
  59. opik/evaluation/metrics/llm_judges/syc_eval/metric.py +4 -2
  60. opik/evaluation/metrics/llm_judges/trajectory_accuracy/metric.py +3 -1
  61. opik/evaluation/metrics/llm_judges/usefulness/metric.py +3 -1
  62. opik/evaluation/metrics/ragas_metric.py +43 -23
  63. opik/evaluation/models/litellm/litellm_chat_model.py +7 -2
  64. opik/evaluation/models/litellm/util.py +4 -20
  65. opik/evaluation/models/models_factory.py +19 -5
  66. opik/evaluation/rest_operations.py +3 -3
  67. opik/evaluation/threads/helpers.py +3 -2
  68. opik/file_upload/file_uploader.py +13 -0
  69. opik/file_upload/upload_options.py +2 -0
  70. opik/integrations/adk/legacy_opik_tracer.py +9 -11
  71. opik/integrations/adk/opik_tracer.py +2 -2
  72. opik/integrations/adk/patchers/adk_otel_tracer/opik_adk_otel_tracer.py +2 -2
  73. opik/integrations/dspy/callback.py +100 -14
  74. opik/integrations/dspy/parsers.py +168 -0
  75. opik/integrations/harbor/__init__.py +17 -0
  76. opik/integrations/harbor/experiment_service.py +269 -0
  77. opik/integrations/harbor/opik_tracker.py +528 -0
  78. opik/integrations/haystack/opik_tracer.py +2 -2
  79. opik/integrations/langchain/__init__.py +15 -2
  80. opik/integrations/langchain/langgraph_tracer_injector.py +88 -0
  81. opik/integrations/langchain/opik_tracer.py +258 -160
  82. opik/integrations/langchain/provider_usage_extractors/langchain_run_helpers/helpers.py +7 -4
  83. opik/integrations/llama_index/callback.py +43 -6
  84. opik/integrations/openai/agents/opik_tracing_processor.py +8 -10
  85. opik/integrations/openai/opik_tracker.py +99 -4
  86. opik/integrations/openai/videos/__init__.py +9 -0
  87. opik/integrations/openai/videos/binary_response_write_to_file_decorator.py +88 -0
  88. opik/integrations/openai/videos/videos_create_decorator.py +159 -0
  89. opik/integrations/openai/videos/videos_download_decorator.py +110 -0
  90. opik/message_processing/batching/base_batcher.py +14 -21
  91. opik/message_processing/batching/batch_manager.py +22 -10
  92. opik/message_processing/batching/batchers.py +32 -40
  93. opik/message_processing/batching/flushing_thread.py +0 -3
  94. opik/message_processing/emulation/emulator_message_processor.py +36 -1
  95. opik/message_processing/emulation/models.py +21 -0
  96. opik/message_processing/messages.py +9 -0
  97. opik/message_processing/preprocessing/__init__.py +0 -0
  98. opik/message_processing/preprocessing/attachments_preprocessor.py +70 -0
  99. opik/message_processing/preprocessing/batching_preprocessor.py +53 -0
  100. opik/message_processing/preprocessing/constants.py +1 -0
  101. opik/message_processing/preprocessing/file_upload_preprocessor.py +38 -0
  102. opik/message_processing/preprocessing/preprocessor.py +36 -0
  103. opik/message_processing/processors/__init__.py +0 -0
  104. opik/message_processing/processors/attachments_extraction_processor.py +146 -0
  105. opik/message_processing/{message_processors.py → processors/message_processors.py} +15 -1
  106. opik/message_processing/{message_processors_chain.py → processors/message_processors_chain.py} +3 -2
  107. opik/message_processing/{online_message_processor.py → processors/online_message_processor.py} +11 -9
  108. opik/message_processing/queue_consumer.py +4 -2
  109. opik/message_processing/streamer.py +71 -33
  110. opik/message_processing/streamer_constructors.py +36 -8
  111. opik/plugins/pytest/experiment_runner.py +1 -1
  112. opik/plugins/pytest/hooks.py +5 -3
  113. opik/rest_api/__init__.py +42 -0
  114. opik/rest_api/datasets/client.py +321 -123
  115. opik/rest_api/datasets/raw_client.py +470 -145
  116. opik/rest_api/experiments/client.py +26 -0
  117. opik/rest_api/experiments/raw_client.py +26 -0
  118. opik/rest_api/llm_provider_key/client.py +4 -4
  119. opik/rest_api/llm_provider_key/raw_client.py +4 -4
  120. opik/rest_api/llm_provider_key/types/provider_api_key_write_provider.py +2 -1
  121. opik/rest_api/manual_evaluation/client.py +101 -0
  122. opik/rest_api/manual_evaluation/raw_client.py +172 -0
  123. opik/rest_api/optimizations/client.py +0 -166
  124. opik/rest_api/optimizations/raw_client.py +0 -248
  125. opik/rest_api/projects/client.py +9 -0
  126. opik/rest_api/projects/raw_client.py +13 -0
  127. opik/rest_api/projects/types/project_metric_request_public_metric_type.py +4 -0
  128. opik/rest_api/prompts/client.py +130 -2
  129. opik/rest_api/prompts/raw_client.py +175 -0
  130. opik/rest_api/traces/client.py +101 -0
  131. opik/rest_api/traces/raw_client.py +120 -0
  132. opik/rest_api/types/__init__.py +50 -0
  133. opik/rest_api/types/audio_url.py +19 -0
  134. opik/rest_api/types/audio_url_public.py +19 -0
  135. opik/rest_api/types/audio_url_write.py +19 -0
  136. opik/rest_api/types/automation_rule_evaluator.py +38 -2
  137. opik/rest_api/types/automation_rule_evaluator_object_object_public.py +33 -2
  138. opik/rest_api/types/automation_rule_evaluator_public.py +33 -2
  139. opik/rest_api/types/automation_rule_evaluator_span_user_defined_metric_python.py +22 -0
  140. opik/rest_api/types/automation_rule_evaluator_span_user_defined_metric_python_public.py +22 -0
  141. opik/rest_api/types/automation_rule_evaluator_span_user_defined_metric_python_write.py +22 -0
  142. opik/rest_api/types/automation_rule_evaluator_update.py +27 -1
  143. opik/rest_api/types/automation_rule_evaluator_update_span_user_defined_metric_python.py +22 -0
  144. opik/rest_api/types/automation_rule_evaluator_write.py +27 -1
  145. opik/rest_api/types/dataset.py +2 -0
  146. opik/rest_api/types/dataset_item.py +1 -1
  147. opik/rest_api/types/dataset_item_batch.py +4 -0
  148. opik/rest_api/types/dataset_item_changes_public.py +5 -0
  149. opik/rest_api/types/dataset_item_compare.py +1 -1
  150. opik/rest_api/types/dataset_item_filter.py +4 -0
  151. opik/rest_api/types/dataset_item_page_compare.py +0 -1
  152. opik/rest_api/types/dataset_item_page_public.py +0 -1
  153. opik/rest_api/types/dataset_item_public.py +1 -1
  154. opik/rest_api/types/dataset_public.py +2 -0
  155. opik/rest_api/types/dataset_version_public.py +10 -0
  156. opik/rest_api/types/dataset_version_summary.py +46 -0
  157. opik/rest_api/types/dataset_version_summary_public.py +46 -0
  158. opik/rest_api/types/experiment.py +9 -0
  159. opik/rest_api/types/experiment_public.py +9 -0
  160. opik/rest_api/types/group_content_with_aggregations.py +1 -0
  161. opik/rest_api/types/llm_as_judge_message_content.py +2 -0
  162. opik/rest_api/types/llm_as_judge_message_content_public.py +2 -0
  163. opik/rest_api/types/llm_as_judge_message_content_write.py +2 -0
  164. opik/rest_api/types/manual_evaluation_request_entity_type.py +1 -1
  165. opik/rest_api/types/project.py +1 -0
  166. opik/rest_api/types/project_detailed.py +1 -0
  167. opik/rest_api/types/project_metric_response_public_metric_type.py +4 -0
  168. opik/rest_api/types/project_reference.py +31 -0
  169. opik/rest_api/types/project_reference_public.py +31 -0
  170. opik/rest_api/types/project_stats_summary_item.py +1 -0
  171. opik/rest_api/types/prompt_version.py +1 -0
  172. opik/rest_api/types/prompt_version_detail.py +1 -0
  173. opik/rest_api/types/prompt_version_page_public.py +5 -0
  174. opik/rest_api/types/prompt_version_public.py +1 -0
  175. opik/rest_api/types/prompt_version_update.py +33 -0
  176. opik/rest_api/types/provider_api_key.py +5 -1
  177. opik/rest_api/types/provider_api_key_provider.py +2 -1
  178. opik/rest_api/types/provider_api_key_public.py +5 -1
  179. opik/rest_api/types/provider_api_key_public_provider.py +2 -1
  180. opik/rest_api/types/service_toggles_config.py +11 -1
  181. opik/rest_api/types/span_user_defined_metric_python_code.py +20 -0
  182. opik/rest_api/types/span_user_defined_metric_python_code_public.py +20 -0
  183. opik/rest_api/types/span_user_defined_metric_python_code_write.py +20 -0
  184. opik/types.py +36 -0
  185. opik/validation/chat_prompt_messages.py +241 -0
  186. opik/validation/feedback_score.py +3 -3
  187. opik/validation/validator.py +28 -0
  188. {opik-1.9.39.dist-info → opik-1.9.86.dist-info}/METADATA +7 -7
  189. {opik-1.9.39.dist-info → opik-1.9.86.dist-info}/RECORD +193 -142
  190. opik/cli/export.py +0 -791
  191. opik/cli/import_command.py +0 -575
  192. {opik-1.9.39.dist-info → opik-1.9.86.dist-info}/WHEEL +0 -0
  193. {opik-1.9.39.dist-info → opik-1.9.86.dist-info}/entry_points.txt +0 -0
  194. {opik-1.9.39.dist-info → opik-1.9.86.dist-info}/licenses/LICENSE +0 -0
  195. {opik-1.9.39.dist-info → opik-1.9.86.dist-info}/top_level.txt +0 -0
@@ -9,6 +9,7 @@ from ..types.prompt_detail import PromptDetail
9
9
  from ..types.prompt_page_public import PromptPagePublic
10
10
  from ..types.prompt_version_detail import PromptVersionDetail
11
11
  from ..types.prompt_version_page_public import PromptVersionPagePublic
12
+ from ..types.prompt_version_update import PromptVersionUpdate
12
13
  from .raw_client import AsyncRawPromptsClient, RawPromptsClient
13
14
  from .types.create_prompt_version_detail_template_structure import CreatePromptVersionDetailTemplateStructure
14
15
  from .types.prompt_write_template_structure import PromptWriteTemplateStructure
@@ -182,6 +183,57 @@ class PromptsClient:
182
183
  )
183
184
  return _response.data
184
185
 
186
+ def update_prompt_versions(
187
+ self,
188
+ *,
189
+ ids: typing.Sequence[str],
190
+ update: PromptVersionUpdate,
191
+ merge_tags: typing.Optional[bool] = OMIT,
192
+ request_options: typing.Optional[RequestOptions] = None,
193
+ ) -> None:
194
+ """
195
+ Update one or more prompt versions.
196
+
197
+ Note: Prompt versions are immutable by design.
198
+ Only organizational properties, such as tags etc., can be updated.
199
+ Core properties like template and metadata cannot be modified after creation.
200
+
201
+ PATCH semantics:
202
+ - non-empty values update the field
203
+ - null values preserve existing field values (no change)
204
+ - empty values explicitly clear the field
205
+
206
+ Parameters
207
+ ----------
208
+ ids : typing.Sequence[str]
209
+ IDs of prompt versions to update
210
+
211
+ update : PromptVersionUpdate
212
+
213
+ merge_tags : typing.Optional[bool]
214
+ Tag merge behavior:
215
+ - true: Add new tags to existing tags (union)
216
+ - false: Replace all existing tags with new tags (default behaviour if not provided)
217
+
218
+ request_options : typing.Optional[RequestOptions]
219
+ Request-specific configuration.
220
+
221
+ Returns
222
+ -------
223
+ None
224
+
225
+ Examples
226
+ --------
227
+ from Opik import OpikApi
228
+ from Opik import PromptVersionUpdate
229
+ client = OpikApi(api_key="YOUR_API_KEY", workspace_name="YOUR_WORKSPACE_NAME", )
230
+ client.prompts.update_prompt_versions(ids=['ids'], update=PromptVersionUpdate(), )
231
+ """
232
+ _response = self._raw_client.update_prompt_versions(
233
+ ids=ids, update=update, merge_tags=merge_tags, request_options=request_options
234
+ )
235
+ return _response.data
236
+
185
237
  def get_prompt_by_id(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> PromptDetail:
186
238
  """
187
239
  Get prompt by id
@@ -330,6 +382,9 @@ class PromptsClient:
330
382
  *,
331
383
  page: typing.Optional[int] = None,
332
384
  size: typing.Optional[int] = None,
385
+ search: typing.Optional[str] = None,
386
+ sorting: typing.Optional[str] = None,
387
+ filters: typing.Optional[str] = None,
333
388
  request_options: typing.Optional[RequestOptions] = None,
334
389
  ) -> PromptVersionPagePublic:
335
390
  """
@@ -343,6 +398,13 @@ class PromptsClient:
343
398
 
344
399
  size : typing.Optional[int]
345
400
 
401
+ search : typing.Optional[str]
402
+ Search text to find in template or change description fields
403
+
404
+ sorting : typing.Optional[str]
405
+
406
+ filters : typing.Optional[str]
407
+
346
408
  request_options : typing.Optional[RequestOptions]
347
409
  Request-specific configuration.
348
410
 
@@ -357,7 +419,9 @@ class PromptsClient:
357
419
  client = OpikApi(api_key="YOUR_API_KEY", workspace_name="YOUR_WORKSPACE_NAME", )
358
420
  client.prompts.get_prompt_versions(id='id', )
359
421
  """
360
- _response = self._raw_client.get_prompt_versions(id, page=page, size=size, request_options=request_options)
422
+ _response = self._raw_client.get_prompt_versions(
423
+ id, page=page, size=size, search=search, sorting=sorting, filters=filters, request_options=request_options
424
+ )
361
425
  return _response.data
362
426
 
363
427
  def restore_prompt_version(
@@ -592,6 +656,60 @@ class AsyncPromptsClient:
592
656
  )
593
657
  return _response.data
594
658
 
659
+ async def update_prompt_versions(
660
+ self,
661
+ *,
662
+ ids: typing.Sequence[str],
663
+ update: PromptVersionUpdate,
664
+ merge_tags: typing.Optional[bool] = OMIT,
665
+ request_options: typing.Optional[RequestOptions] = None,
666
+ ) -> None:
667
+ """
668
+ Update one or more prompt versions.
669
+
670
+ Note: Prompt versions are immutable by design.
671
+ Only organizational properties, such as tags etc., can be updated.
672
+ Core properties like template and metadata cannot be modified after creation.
673
+
674
+ PATCH semantics:
675
+ - non-empty values update the field
676
+ - null values preserve existing field values (no change)
677
+ - empty values explicitly clear the field
678
+
679
+ Parameters
680
+ ----------
681
+ ids : typing.Sequence[str]
682
+ IDs of prompt versions to update
683
+
684
+ update : PromptVersionUpdate
685
+
686
+ merge_tags : typing.Optional[bool]
687
+ Tag merge behavior:
688
+ - true: Add new tags to existing tags (union)
689
+ - false: Replace all existing tags with new tags (default behaviour if not provided)
690
+
691
+ request_options : typing.Optional[RequestOptions]
692
+ Request-specific configuration.
693
+
694
+ Returns
695
+ -------
696
+ None
697
+
698
+ Examples
699
+ --------
700
+ from Opik import AsyncOpikApi
701
+ from Opik import PromptVersionUpdate
702
+ import asyncio
703
+ client = AsyncOpikApi(api_key="YOUR_API_KEY", workspace_name="YOUR_WORKSPACE_NAME", )
704
+ async def main() -> None:
705
+ await client.prompts.update_prompt_versions(ids=['ids'], update=PromptVersionUpdate(), )
706
+ asyncio.run(main())
707
+ """
708
+ _response = await self._raw_client.update_prompt_versions(
709
+ ids=ids, update=update, merge_tags=merge_tags, request_options=request_options
710
+ )
711
+ return _response.data
712
+
595
713
  async def get_prompt_by_id(
596
714
  self, id: str, *, request_options: typing.Optional[RequestOptions] = None
597
715
  ) -> PromptDetail:
@@ -757,6 +875,9 @@ class AsyncPromptsClient:
757
875
  *,
758
876
  page: typing.Optional[int] = None,
759
877
  size: typing.Optional[int] = None,
878
+ search: typing.Optional[str] = None,
879
+ sorting: typing.Optional[str] = None,
880
+ filters: typing.Optional[str] = None,
760
881
  request_options: typing.Optional[RequestOptions] = None,
761
882
  ) -> PromptVersionPagePublic:
762
883
  """
@@ -770,6 +891,13 @@ class AsyncPromptsClient:
770
891
 
771
892
  size : typing.Optional[int]
772
893
 
894
+ search : typing.Optional[str]
895
+ Search text to find in template or change description fields
896
+
897
+ sorting : typing.Optional[str]
898
+
899
+ filters : typing.Optional[str]
900
+
773
901
  request_options : typing.Optional[RequestOptions]
774
902
  Request-specific configuration.
775
903
 
@@ -788,7 +916,7 @@ class AsyncPromptsClient:
788
916
  asyncio.run(main())
789
917
  """
790
918
  _response = await self._raw_client.get_prompt_versions(
791
- id, page=page, size=size, request_options=request_options
919
+ id, page=page, size=size, search=search, sorting=sorting, filters=filters, request_options=request_options
792
920
  )
793
921
  return _response.data
794
922
 
@@ -19,6 +19,7 @@ from ..types.prompt_detail import PromptDetail
19
19
  from ..types.prompt_page_public import PromptPagePublic
20
20
  from ..types.prompt_version_detail import PromptVersionDetail
21
21
  from ..types.prompt_version_page_public import PromptVersionPagePublic
22
+ from ..types.prompt_version_update import PromptVersionUpdate
22
23
  from .types.create_prompt_version_detail_template_structure import CreatePromptVersionDetailTemplateStructure
23
24
  from .types.prompt_write_template_structure import PromptWriteTemplateStructure
24
25
  from .types.prompt_write_type import PromptWriteType
@@ -289,6 +290,80 @@ class RawPromptsClient:
289
290
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
290
291
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
291
292
 
293
+ def update_prompt_versions(
294
+ self,
295
+ *,
296
+ ids: typing.Sequence[str],
297
+ update: PromptVersionUpdate,
298
+ merge_tags: typing.Optional[bool] = OMIT,
299
+ request_options: typing.Optional[RequestOptions] = None,
300
+ ) -> HttpResponse[None]:
301
+ """
302
+ Update one or more prompt versions.
303
+
304
+ Note: Prompt versions are immutable by design.
305
+ Only organizational properties, such as tags etc., can be updated.
306
+ Core properties like template and metadata cannot be modified after creation.
307
+
308
+ PATCH semantics:
309
+ - non-empty values update the field
310
+ - null values preserve existing field values (no change)
311
+ - empty values explicitly clear the field
312
+
313
+ Parameters
314
+ ----------
315
+ ids : typing.Sequence[str]
316
+ IDs of prompt versions to update
317
+
318
+ update : PromptVersionUpdate
319
+
320
+ merge_tags : typing.Optional[bool]
321
+ Tag merge behavior:
322
+ - true: Add new tags to existing tags (union)
323
+ - false: Replace all existing tags with new tags (default behaviour if not provided)
324
+
325
+ request_options : typing.Optional[RequestOptions]
326
+ Request-specific configuration.
327
+
328
+ Returns
329
+ -------
330
+ HttpResponse[None]
331
+ """
332
+ _response = self._client_wrapper.httpx_client.request(
333
+ "v1/private/prompts/versions",
334
+ method="PATCH",
335
+ json={
336
+ "ids": ids,
337
+ "update": convert_and_respect_annotation_metadata(
338
+ object_=update, annotation=PromptVersionUpdate, direction="write"
339
+ ),
340
+ "merge_tags": merge_tags,
341
+ },
342
+ headers={
343
+ "content-type": "application/json",
344
+ },
345
+ request_options=request_options,
346
+ omit=OMIT,
347
+ )
348
+ try:
349
+ if 200 <= _response.status_code < 300:
350
+ return HttpResponse(response=_response, data=None)
351
+ if _response.status_code == 400:
352
+ raise BadRequestError(
353
+ headers=dict(_response.headers),
354
+ body=typing.cast(
355
+ typing.Optional[typing.Any],
356
+ parse_obj_as(
357
+ type_=typing.Optional[typing.Any], # type: ignore
358
+ object_=_response.json(),
359
+ ),
360
+ ),
361
+ )
362
+ _response_json = _response.json()
363
+ except JSONDecodeError:
364
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
365
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
366
+
292
367
  def get_prompt_by_id(
293
368
  self, id: str, *, request_options: typing.Optional[RequestOptions] = None
294
369
  ) -> HttpResponse[PromptDetail]:
@@ -553,6 +628,9 @@ class RawPromptsClient:
553
628
  *,
554
629
  page: typing.Optional[int] = None,
555
630
  size: typing.Optional[int] = None,
631
+ search: typing.Optional[str] = None,
632
+ sorting: typing.Optional[str] = None,
633
+ filters: typing.Optional[str] = None,
556
634
  request_options: typing.Optional[RequestOptions] = None,
557
635
  ) -> HttpResponse[PromptVersionPagePublic]:
558
636
  """
@@ -566,6 +644,13 @@ class RawPromptsClient:
566
644
 
567
645
  size : typing.Optional[int]
568
646
 
647
+ search : typing.Optional[str]
648
+ Search text to find in template or change description fields
649
+
650
+ sorting : typing.Optional[str]
651
+
652
+ filters : typing.Optional[str]
653
+
569
654
  request_options : typing.Optional[RequestOptions]
570
655
  Request-specific configuration.
571
656
 
@@ -580,6 +665,9 @@ class RawPromptsClient:
580
665
  params={
581
666
  "page": page,
582
667
  "size": size,
668
+ "search": search,
669
+ "sorting": sorting,
670
+ "filters": filters,
583
671
  },
584
672
  request_options=request_options,
585
673
  )
@@ -1004,6 +1092,80 @@ class AsyncRawPromptsClient:
1004
1092
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1005
1093
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1006
1094
 
1095
+ async def update_prompt_versions(
1096
+ self,
1097
+ *,
1098
+ ids: typing.Sequence[str],
1099
+ update: PromptVersionUpdate,
1100
+ merge_tags: typing.Optional[bool] = OMIT,
1101
+ request_options: typing.Optional[RequestOptions] = None,
1102
+ ) -> AsyncHttpResponse[None]:
1103
+ """
1104
+ Update one or more prompt versions.
1105
+
1106
+ Note: Prompt versions are immutable by design.
1107
+ Only organizational properties, such as tags etc., can be updated.
1108
+ Core properties like template and metadata cannot be modified after creation.
1109
+
1110
+ PATCH semantics:
1111
+ - non-empty values update the field
1112
+ - null values preserve existing field values (no change)
1113
+ - empty values explicitly clear the field
1114
+
1115
+ Parameters
1116
+ ----------
1117
+ ids : typing.Sequence[str]
1118
+ IDs of prompt versions to update
1119
+
1120
+ update : PromptVersionUpdate
1121
+
1122
+ merge_tags : typing.Optional[bool]
1123
+ Tag merge behavior:
1124
+ - true: Add new tags to existing tags (union)
1125
+ - false: Replace all existing tags with new tags (default behaviour if not provided)
1126
+
1127
+ request_options : typing.Optional[RequestOptions]
1128
+ Request-specific configuration.
1129
+
1130
+ Returns
1131
+ -------
1132
+ AsyncHttpResponse[None]
1133
+ """
1134
+ _response = await self._client_wrapper.httpx_client.request(
1135
+ "v1/private/prompts/versions",
1136
+ method="PATCH",
1137
+ json={
1138
+ "ids": ids,
1139
+ "update": convert_and_respect_annotation_metadata(
1140
+ object_=update, annotation=PromptVersionUpdate, direction="write"
1141
+ ),
1142
+ "merge_tags": merge_tags,
1143
+ },
1144
+ headers={
1145
+ "content-type": "application/json",
1146
+ },
1147
+ request_options=request_options,
1148
+ omit=OMIT,
1149
+ )
1150
+ try:
1151
+ if 200 <= _response.status_code < 300:
1152
+ return AsyncHttpResponse(response=_response, data=None)
1153
+ if _response.status_code == 400:
1154
+ raise BadRequestError(
1155
+ headers=dict(_response.headers),
1156
+ body=typing.cast(
1157
+ typing.Optional[typing.Any],
1158
+ parse_obj_as(
1159
+ type_=typing.Optional[typing.Any], # type: ignore
1160
+ object_=_response.json(),
1161
+ ),
1162
+ ),
1163
+ )
1164
+ _response_json = _response.json()
1165
+ except JSONDecodeError:
1166
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1167
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1168
+
1007
1169
  async def get_prompt_by_id(
1008
1170
  self, id: str, *, request_options: typing.Optional[RequestOptions] = None
1009
1171
  ) -> AsyncHttpResponse[PromptDetail]:
@@ -1270,6 +1432,9 @@ class AsyncRawPromptsClient:
1270
1432
  *,
1271
1433
  page: typing.Optional[int] = None,
1272
1434
  size: typing.Optional[int] = None,
1435
+ search: typing.Optional[str] = None,
1436
+ sorting: typing.Optional[str] = None,
1437
+ filters: typing.Optional[str] = None,
1273
1438
  request_options: typing.Optional[RequestOptions] = None,
1274
1439
  ) -> AsyncHttpResponse[PromptVersionPagePublic]:
1275
1440
  """
@@ -1283,6 +1448,13 @@ class AsyncRawPromptsClient:
1283
1448
 
1284
1449
  size : typing.Optional[int]
1285
1450
 
1451
+ search : typing.Optional[str]
1452
+ Search text to find in template or change description fields
1453
+
1454
+ sorting : typing.Optional[str]
1455
+
1456
+ filters : typing.Optional[str]
1457
+
1286
1458
  request_options : typing.Optional[RequestOptions]
1287
1459
  Request-specific configuration.
1288
1460
 
@@ -1297,6 +1469,9 @@ class AsyncRawPromptsClient:
1297
1469
  params={
1298
1470
  "page": page,
1299
1471
  "size": size,
1472
+ "search": search,
1473
+ "sorting": sorting,
1474
+ "filters": filters,
1300
1475
  },
1301
1476
  request_options=request_options,
1302
1477
  )
@@ -993,6 +993,55 @@ class TracesClient:
993
993
  _response = self._raw_client.get_thread_comment(comment_id, thread_id, request_options=request_options)
994
994
  return _response.data
995
995
 
996
+ def get_trace_thread_stats(
997
+ self,
998
+ *,
999
+ project_id: typing.Optional[str] = None,
1000
+ project_name: typing.Optional[str] = None,
1001
+ filters: typing.Optional[str] = None,
1002
+ from_time: typing.Optional[dt.datetime] = None,
1003
+ to_time: typing.Optional[dt.datetime] = None,
1004
+ request_options: typing.Optional[RequestOptions] = None,
1005
+ ) -> ProjectStatsPublic:
1006
+ """
1007
+ Get trace thread stats
1008
+
1009
+ Parameters
1010
+ ----------
1011
+ project_id : typing.Optional[str]
1012
+
1013
+ project_name : typing.Optional[str]
1014
+
1015
+ filters : typing.Optional[str]
1016
+
1017
+ from_time : typing.Optional[dt.datetime]
1018
+
1019
+ to_time : typing.Optional[dt.datetime]
1020
+
1021
+ request_options : typing.Optional[RequestOptions]
1022
+ Request-specific configuration.
1023
+
1024
+ Returns
1025
+ -------
1026
+ ProjectStatsPublic
1027
+ Trace thread stats resource
1028
+
1029
+ Examples
1030
+ --------
1031
+ from Opik import OpikApi
1032
+ client = OpikApi(api_key="YOUR_API_KEY", workspace_name="YOUR_WORKSPACE_NAME", )
1033
+ client.traces.get_trace_thread_stats()
1034
+ """
1035
+ _response = self._raw_client.get_trace_thread_stats(
1036
+ project_id=project_id,
1037
+ project_name=project_name,
1038
+ filters=filters,
1039
+ from_time=from_time,
1040
+ to_time=to_time,
1041
+ request_options=request_options,
1042
+ )
1043
+ return _response.data
1044
+
996
1045
  def get_trace_comment(
997
1046
  self, comment_id: str, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None
998
1047
  ) -> Comment:
@@ -2544,6 +2593,58 @@ class AsyncTracesClient:
2544
2593
  _response = await self._raw_client.get_thread_comment(comment_id, thread_id, request_options=request_options)
2545
2594
  return _response.data
2546
2595
 
2596
+ async def get_trace_thread_stats(
2597
+ self,
2598
+ *,
2599
+ project_id: typing.Optional[str] = None,
2600
+ project_name: typing.Optional[str] = None,
2601
+ filters: typing.Optional[str] = None,
2602
+ from_time: typing.Optional[dt.datetime] = None,
2603
+ to_time: typing.Optional[dt.datetime] = None,
2604
+ request_options: typing.Optional[RequestOptions] = None,
2605
+ ) -> ProjectStatsPublic:
2606
+ """
2607
+ Get trace thread stats
2608
+
2609
+ Parameters
2610
+ ----------
2611
+ project_id : typing.Optional[str]
2612
+
2613
+ project_name : typing.Optional[str]
2614
+
2615
+ filters : typing.Optional[str]
2616
+
2617
+ from_time : typing.Optional[dt.datetime]
2618
+
2619
+ to_time : typing.Optional[dt.datetime]
2620
+
2621
+ request_options : typing.Optional[RequestOptions]
2622
+ Request-specific configuration.
2623
+
2624
+ Returns
2625
+ -------
2626
+ ProjectStatsPublic
2627
+ Trace thread stats resource
2628
+
2629
+ Examples
2630
+ --------
2631
+ from Opik import AsyncOpikApi
2632
+ import asyncio
2633
+ client = AsyncOpikApi(api_key="YOUR_API_KEY", workspace_name="YOUR_WORKSPACE_NAME", )
2634
+ async def main() -> None:
2635
+ await client.traces.get_trace_thread_stats()
2636
+ asyncio.run(main())
2637
+ """
2638
+ _response = await self._raw_client.get_trace_thread_stats(
2639
+ project_id=project_id,
2640
+ project_name=project_name,
2641
+ filters=filters,
2642
+ from_time=from_time,
2643
+ to_time=to_time,
2644
+ request_options=request_options,
2645
+ )
2646
+ return _response.data
2647
+
2547
2648
  async def get_trace_comment(
2548
2649
  self, comment_id: str, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None
2549
2650
  ) -> Comment:
@@ -1275,6 +1275,66 @@ class RawTracesClient:
1275
1275
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1276
1276
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1277
1277
 
1278
+ def get_trace_thread_stats(
1279
+ self,
1280
+ *,
1281
+ project_id: typing.Optional[str] = None,
1282
+ project_name: typing.Optional[str] = None,
1283
+ filters: typing.Optional[str] = None,
1284
+ from_time: typing.Optional[dt.datetime] = None,
1285
+ to_time: typing.Optional[dt.datetime] = None,
1286
+ request_options: typing.Optional[RequestOptions] = None,
1287
+ ) -> HttpResponse[ProjectStatsPublic]:
1288
+ """
1289
+ Get trace thread stats
1290
+
1291
+ Parameters
1292
+ ----------
1293
+ project_id : typing.Optional[str]
1294
+
1295
+ project_name : typing.Optional[str]
1296
+
1297
+ filters : typing.Optional[str]
1298
+
1299
+ from_time : typing.Optional[dt.datetime]
1300
+
1301
+ to_time : typing.Optional[dt.datetime]
1302
+
1303
+ request_options : typing.Optional[RequestOptions]
1304
+ Request-specific configuration.
1305
+
1306
+ Returns
1307
+ -------
1308
+ HttpResponse[ProjectStatsPublic]
1309
+ Trace thread stats resource
1310
+ """
1311
+ _response = self._client_wrapper.httpx_client.request(
1312
+ "v1/private/traces/threads/stats",
1313
+ method="GET",
1314
+ params={
1315
+ "project_id": project_id,
1316
+ "project_name": project_name,
1317
+ "filters": filters,
1318
+ "from_time": serialize_datetime(from_time) if from_time is not None else None,
1319
+ "to_time": serialize_datetime(to_time) if to_time is not None else None,
1320
+ },
1321
+ request_options=request_options,
1322
+ )
1323
+ try:
1324
+ if 200 <= _response.status_code < 300:
1325
+ _data = typing.cast(
1326
+ ProjectStatsPublic,
1327
+ parse_obj_as(
1328
+ type_=ProjectStatsPublic, # type: ignore
1329
+ object_=_response.json(),
1330
+ ),
1331
+ )
1332
+ return HttpResponse(response=_response, data=_data)
1333
+ _response_json = _response.json()
1334
+ except JSONDecodeError:
1335
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1336
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1337
+
1278
1338
  def get_trace_comment(
1279
1339
  self, comment_id: str, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None
1280
1340
  ) -> HttpResponse[Comment]:
@@ -3266,6 +3326,66 @@ class AsyncRawTracesClient:
3266
3326
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
3267
3327
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
3268
3328
 
3329
+ async def get_trace_thread_stats(
3330
+ self,
3331
+ *,
3332
+ project_id: typing.Optional[str] = None,
3333
+ project_name: typing.Optional[str] = None,
3334
+ filters: typing.Optional[str] = None,
3335
+ from_time: typing.Optional[dt.datetime] = None,
3336
+ to_time: typing.Optional[dt.datetime] = None,
3337
+ request_options: typing.Optional[RequestOptions] = None,
3338
+ ) -> AsyncHttpResponse[ProjectStatsPublic]:
3339
+ """
3340
+ Get trace thread stats
3341
+
3342
+ Parameters
3343
+ ----------
3344
+ project_id : typing.Optional[str]
3345
+
3346
+ project_name : typing.Optional[str]
3347
+
3348
+ filters : typing.Optional[str]
3349
+
3350
+ from_time : typing.Optional[dt.datetime]
3351
+
3352
+ to_time : typing.Optional[dt.datetime]
3353
+
3354
+ request_options : typing.Optional[RequestOptions]
3355
+ Request-specific configuration.
3356
+
3357
+ Returns
3358
+ -------
3359
+ AsyncHttpResponse[ProjectStatsPublic]
3360
+ Trace thread stats resource
3361
+ """
3362
+ _response = await self._client_wrapper.httpx_client.request(
3363
+ "v1/private/traces/threads/stats",
3364
+ method="GET",
3365
+ params={
3366
+ "project_id": project_id,
3367
+ "project_name": project_name,
3368
+ "filters": filters,
3369
+ "from_time": serialize_datetime(from_time) if from_time is not None else None,
3370
+ "to_time": serialize_datetime(to_time) if to_time is not None else None,
3371
+ },
3372
+ request_options=request_options,
3373
+ )
3374
+ try:
3375
+ if 200 <= _response.status_code < 300:
3376
+ _data = typing.cast(
3377
+ ProjectStatsPublic,
3378
+ parse_obj_as(
3379
+ type_=ProjectStatsPublic, # type: ignore
3380
+ object_=_response.json(),
3381
+ ),
3382
+ )
3383
+ return AsyncHttpResponse(response=_response, data=_data)
3384
+ _response_json = _response.json()
3385
+ except JSONDecodeError:
3386
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
3387
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
3388
+
3269
3389
  async def get_trace_comment(
3270
3390
  self, comment_id: str, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None
3271
3391
  ) -> AsyncHttpResponse[Comment]: