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
@@ -15,6 +15,7 @@ from ..errors.bad_request_error import BadRequestError
15
15
  from ..errors.conflict_error import ConflictError
16
16
  from ..errors.not_found_error import NotFoundError
17
17
  from ..types.dataset_expansion_response import DatasetExpansionResponse
18
+ from ..types.dataset_item_changes_public import DatasetItemChangesPublic
18
19
  from ..types.dataset_item_filter import DatasetItemFilter
19
20
  from ..types.dataset_item_page_compare import DatasetItemPageCompare
20
21
  from ..types.dataset_item_page_public import DatasetItemPagePublic
@@ -43,12 +44,108 @@ class RawDatasetsClient:
43
44
  def __init__(self, *, client_wrapper: SyncClientWrapper):
44
45
  self._client_wrapper = client_wrapper
45
46
 
47
+ def apply_dataset_item_changes(
48
+ self,
49
+ id: str,
50
+ *,
51
+ request: DatasetItemChangesPublic,
52
+ override: typing.Optional[bool] = None,
53
+ request_options: typing.Optional[RequestOptions] = None,
54
+ ) -> HttpResponse[DatasetVersionPublic]:
55
+ """
56
+ Apply delta changes (add, edit, delete) to a dataset version with conflict detection.
57
+
58
+ This endpoint:
59
+ - Creates a new version with the applied changes
60
+ - Validates that baseVersion matches the latest version (unless override=true)
61
+ - Returns 409 Conflict if baseVersion is stale and override is not set
62
+
63
+ Use `override=true` query parameter to force version creation even with stale baseVersion.
64
+
65
+ Parameters
66
+ ----------
67
+ id : str
68
+
69
+ request : DatasetItemChangesPublic
70
+
71
+ override : typing.Optional[bool]
72
+
73
+ request_options : typing.Optional[RequestOptions]
74
+ Request-specific configuration.
75
+
76
+ Returns
77
+ -------
78
+ HttpResponse[DatasetVersionPublic]
79
+ Version created successfully
80
+ """
81
+ _response = self._client_wrapper.httpx_client.request(
82
+ f"v1/private/datasets/{jsonable_encoder(id)}/items/changes",
83
+ method="POST",
84
+ params={
85
+ "override": override,
86
+ },
87
+ json=request,
88
+ headers={
89
+ "content-type": "application/json",
90
+ },
91
+ request_options=request_options,
92
+ omit=OMIT,
93
+ )
94
+ try:
95
+ if 200 <= _response.status_code < 300:
96
+ _data = typing.cast(
97
+ DatasetVersionPublic,
98
+ parse_obj_as(
99
+ type_=DatasetVersionPublic, # type: ignore
100
+ object_=_response.json(),
101
+ ),
102
+ )
103
+ return HttpResponse(response=_response, data=_data)
104
+ if _response.status_code == 400:
105
+ raise BadRequestError(
106
+ headers=dict(_response.headers),
107
+ body=typing.cast(
108
+ typing.Optional[typing.Any],
109
+ parse_obj_as(
110
+ type_=typing.Optional[typing.Any], # type: ignore
111
+ object_=_response.json(),
112
+ ),
113
+ ),
114
+ )
115
+ if _response.status_code == 404:
116
+ raise NotFoundError(
117
+ headers=dict(_response.headers),
118
+ body=typing.cast(
119
+ typing.Optional[typing.Any],
120
+ parse_obj_as(
121
+ type_=typing.Optional[typing.Any], # type: ignore
122
+ object_=_response.json(),
123
+ ),
124
+ ),
125
+ )
126
+ if _response.status_code == 409:
127
+ raise ConflictError(
128
+ headers=dict(_response.headers),
129
+ body=typing.cast(
130
+ typing.Optional[typing.Any],
131
+ parse_obj_as(
132
+ type_=typing.Optional[typing.Any], # type: ignore
133
+ object_=_response.json(),
134
+ ),
135
+ ),
136
+ )
137
+ _response_json = _response.json()
138
+ except JSONDecodeError:
139
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
140
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
141
+
46
142
  def batch_update_dataset_items(
47
143
  self,
48
144
  *,
49
145
  update: DatasetItemUpdate,
50
146
  ids: typing.Optional[typing.Sequence[str]] = OMIT,
51
147
  filters: typing.Optional[typing.Sequence[DatasetItemFilter]] = OMIT,
148
+ dataset_id: typing.Optional[str] = OMIT,
52
149
  merge_tags: typing.Optional[bool] = OMIT,
53
150
  request_options: typing.Optional[RequestOptions] = None,
54
151
  ) -> HttpResponse[None]:
@@ -64,6 +161,9 @@ class RawDatasetsClient:
64
161
 
65
162
  filters : typing.Optional[typing.Sequence[DatasetItemFilter]]
66
163
 
164
+ dataset_id : typing.Optional[str]
165
+ Dataset ID. Required when using 'filters', optional when using 'ids'.
166
+
67
167
  merge_tags : typing.Optional[bool]
68
168
  If true, merge tags with existing tags instead of replacing them. Default: false. When using 'filters', this is automatically set to true.
69
169
 
@@ -82,6 +182,7 @@ class RawDatasetsClient:
82
182
  "filters": convert_and_respect_annotation_metadata(
83
183
  object_=filters, annotation=typing.Sequence[DatasetItemFilter], direction="write"
84
184
  ),
185
+ "dataset_id": dataset_id,
85
186
  "update": convert_and_respect_annotation_metadata(
86
187
  object_=update, annotation=DatasetItemUpdate, direction="write"
87
188
  ),
@@ -246,6 +347,7 @@ class RawDatasetsClient:
246
347
  items: typing.Sequence[DatasetItemWrite],
247
348
  dataset_name: typing.Optional[str] = OMIT,
248
349
  dataset_id: typing.Optional[str] = OMIT,
350
+ batch_group_id: typing.Optional[str] = OMIT,
249
351
  request_options: typing.Optional[RequestOptions] = None,
250
352
  ) -> HttpResponse[None]:
251
353
  """
@@ -261,6 +363,9 @@ class RawDatasetsClient:
261
363
  dataset_id : typing.Optional[str]
262
364
  If null, dataset_name must be provided
263
365
 
366
+ batch_group_id : typing.Optional[str]
367
+ Optional batch group ID to group multiple batches into a single dataset version. If null, mutates the latest version instead of creating a new one.
368
+
264
369
  request_options : typing.Optional[RequestOptions]
265
370
  Request-specific configuration.
266
371
 
@@ -277,6 +382,7 @@ class RawDatasetsClient:
277
382
  "items": convert_and_respect_annotation_metadata(
278
383
  object_=items, annotation=typing.Sequence[DatasetItemWrite], direction="write"
279
384
  ),
385
+ "batch_group_id": batch_group_id,
280
386
  },
281
387
  headers={
282
388
  "content-type": "application/json",
@@ -615,14 +721,34 @@ class RawDatasetsClient:
615
721
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
616
722
 
617
723
  def delete_dataset_items(
618
- self, *, item_ids: typing.Sequence[str], request_options: typing.Optional[RequestOptions] = None
724
+ self,
725
+ *,
726
+ item_ids: typing.Optional[typing.Sequence[str]] = OMIT,
727
+ dataset_id: typing.Optional[str] = OMIT,
728
+ filters: typing.Optional[typing.Sequence[DatasetItemFilter]] = OMIT,
729
+ batch_group_id: typing.Optional[str] = OMIT,
730
+ request_options: typing.Optional[RequestOptions] = None,
619
731
  ) -> HttpResponse[None]:
620
732
  """
621
- Delete dataset items
733
+ Delete dataset items using one of two modes:
734
+ 1. **Delete by IDs**: Provide 'item_ids' to delete specific items by their IDs
735
+ 2. **Delete by filters**: Provide 'dataset_id' with optional 'filters' to delete items matching criteria
736
+
737
+ When using filters, an empty 'filters' array will delete all items in the specified dataset.
622
738
 
623
739
  Parameters
624
740
  ----------
625
- item_ids : typing.Sequence[str]
741
+ item_ids : typing.Optional[typing.Sequence[str]]
742
+ List of dataset item IDs to delete (max 1000). Use this to delete specific items by their IDs. Mutually exclusive with 'dataset_id' and 'filters'.
743
+
744
+ dataset_id : typing.Optional[str]
745
+ Dataset ID to scope the deletion. Required when using 'filters'. Mutually exclusive with 'item_ids'.
746
+
747
+ filters : typing.Optional[typing.Sequence[DatasetItemFilter]]
748
+ Filters to select dataset items to delete within the specified dataset. Must be used with 'dataset_id'. Mutually exclusive with 'item_ids'. Empty array means 'delete all items in the dataset'.
749
+
750
+ batch_group_id : typing.Optional[str]
751
+ Optional batch group ID to group multiple delete operations into a single dataset version. If null, mutates the latest version instead of creating a new one.
626
752
 
627
753
  request_options : typing.Optional[RequestOptions]
628
754
  Request-specific configuration.
@@ -636,6 +762,11 @@ class RawDatasetsClient:
636
762
  method="POST",
637
763
  json={
638
764
  "item_ids": item_ids,
765
+ "dataset_id": dataset_id,
766
+ "filters": convert_and_respect_annotation_metadata(
767
+ object_=filters, annotation=typing.Sequence[DatasetItemFilter], direction="write"
768
+ ),
769
+ "batch_group_id": batch_group_id,
639
770
  },
640
771
  headers={
641
772
  "content-type": "application/json",
@@ -646,6 +777,17 @@ class RawDatasetsClient:
646
777
  try:
647
778
  if 200 <= _response.status_code < 300:
648
779
  return HttpResponse(response=_response, data=None)
780
+ if _response.status_code == 400:
781
+ raise BadRequestError(
782
+ headers=dict(_response.headers),
783
+ body=typing.cast(
784
+ typing.Optional[typing.Any],
785
+ parse_obj_as(
786
+ type_=typing.Optional[typing.Any], # type: ignore
787
+ object_=_response.json(),
788
+ ),
789
+ ),
790
+ )
649
791
  _response_json = _response.json()
650
792
  except JSONDecodeError:
651
793
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
@@ -1156,6 +1298,7 @@ class RawDatasetsClient:
1156
1298
  dataset_name: str,
1157
1299
  last_retrieved_id: typing.Optional[str] = OMIT,
1158
1300
  steam_limit: typing.Optional[int] = OMIT,
1301
+ dataset_version: typing.Optional[str] = OMIT,
1159
1302
  request_options: typing.Optional[RequestOptions] = None,
1160
1303
  ) -> typing.Iterator[HttpResponse[typing.Iterator[bytes]]]:
1161
1304
  """
@@ -1169,6 +1312,8 @@ class RawDatasetsClient:
1169
1312
 
1170
1313
  steam_limit : typing.Optional[int]
1171
1314
 
1315
+ dataset_version : typing.Optional[str]
1316
+
1172
1317
  request_options : typing.Optional[RequestOptions]
1173
1318
  Request-specific configuration. You can pass in configuration such as `chunk_size`, and more to customize the request and response.
1174
1319
 
@@ -1184,6 +1329,7 @@ class RawDatasetsClient:
1184
1329
  "dataset_name": dataset_name,
1185
1330
  "last_retrieved_id": last_retrieved_id,
1186
1331
  "steam_limit": steam_limit,
1332
+ "dataset_version": dataset_version,
1187
1333
  },
1188
1334
  headers={
1189
1335
  "content-type": "application/json",
@@ -1332,6 +1478,40 @@ class RawDatasetsClient:
1332
1478
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1333
1479
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1334
1480
 
1481
+ def delete_version_tag(
1482
+ self, version_hash: str, tag: str, id: str, *, request_options: typing.Optional[RequestOptions] = None
1483
+ ) -> HttpResponse[None]:
1484
+ """
1485
+ Remove a tag from a dataset version. The version itself is not deleted, only the tag reference.
1486
+
1487
+ Parameters
1488
+ ----------
1489
+ version_hash : str
1490
+
1491
+ tag : str
1492
+
1493
+ id : str
1494
+
1495
+ request_options : typing.Optional[RequestOptions]
1496
+ Request-specific configuration.
1497
+
1498
+ Returns
1499
+ -------
1500
+ HttpResponse[None]
1501
+ """
1502
+ _response = self._client_wrapper.httpx_client.request(
1503
+ f"v1/private/datasets/{jsonable_encoder(id)}/versions/{jsonable_encoder(version_hash)}/tags/{jsonable_encoder(tag)}",
1504
+ method="DELETE",
1505
+ request_options=request_options,
1506
+ )
1507
+ try:
1508
+ if 200 <= _response.status_code < 300:
1509
+ return HttpResponse(response=_response, data=None)
1510
+ _response_json = _response.json()
1511
+ except JSONDecodeError:
1512
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1513
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1514
+
1335
1515
  def list_dataset_versions(
1336
1516
  self,
1337
1517
  id: str,
@@ -1394,45 +1574,32 @@ class RawDatasetsClient:
1394
1574
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1395
1575
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1396
1576
 
1397
- def create_dataset_version(
1398
- self,
1399
- id: str,
1400
- *,
1401
- tag: typing.Optional[str] = OMIT,
1402
- change_description: typing.Optional[str] = OMIT,
1403
- metadata: typing.Optional[typing.Dict[str, str]] = OMIT,
1404
- request_options: typing.Optional[RequestOptions] = None,
1405
- ) -> HttpResponse[None]:
1577
+ def restore_dataset_version(
1578
+ self, id: str, *, version_ref: str, request_options: typing.Optional[RequestOptions] = None
1579
+ ) -> HttpResponse[DatasetVersionPublic]:
1406
1580
  """
1407
- Create a new immutable version of the dataset by snapshotting the current state
1581
+ Restores the dataset to a previous version state by creating a new version with items copied from the specified version. If the version is already the latest, returns it as-is (no-op).
1408
1582
 
1409
1583
  Parameters
1410
1584
  ----------
1411
1585
  id : str
1412
1586
 
1413
- tag : typing.Optional[str]
1414
- Optional tag for this version
1415
-
1416
- change_description : typing.Optional[str]
1417
- Optional description of changes in this version
1418
-
1419
- metadata : typing.Optional[typing.Dict[str, str]]
1420
- Optional user-defined metadata
1587
+ version_ref : str
1588
+ Version hash or tag to restore from
1421
1589
 
1422
1590
  request_options : typing.Optional[RequestOptions]
1423
1591
  Request-specific configuration.
1424
1592
 
1425
1593
  Returns
1426
1594
  -------
1427
- HttpResponse[None]
1595
+ HttpResponse[DatasetVersionPublic]
1596
+ Version restored successfully
1428
1597
  """
1429
1598
  _response = self._client_wrapper.httpx_client.request(
1430
- f"v1/private/datasets/{jsonable_encoder(id)}/versions",
1599
+ f"v1/private/datasets/{jsonable_encoder(id)}/versions/restore",
1431
1600
  method="POST",
1432
1601
  json={
1433
- "tag": tag,
1434
- "change_description": change_description,
1435
- "metadata": metadata,
1602
+ "version_ref": version_ref,
1436
1603
  },
1437
1604
  headers={
1438
1605
  "content-type": "application/json",
@@ -1442,20 +1609,16 @@ class RawDatasetsClient:
1442
1609
  )
1443
1610
  try:
1444
1611
  if 200 <= _response.status_code < 300:
1445
- return HttpResponse(response=_response, data=None)
1446
- if _response.status_code == 400:
1447
- raise BadRequestError(
1448
- headers=dict(_response.headers),
1449
- body=typing.cast(
1450
- typing.Optional[typing.Any],
1451
- parse_obj_as(
1452
- type_=typing.Optional[typing.Any], # type: ignore
1453
- object_=_response.json(),
1454
- ),
1612
+ _data = typing.cast(
1613
+ DatasetVersionPublic,
1614
+ parse_obj_as(
1615
+ type_=DatasetVersionPublic, # type: ignore
1616
+ object_=_response.json(),
1455
1617
  ),
1456
1618
  )
1457
- if _response.status_code == 409:
1458
- raise ConflictError(
1619
+ return HttpResponse(response=_response, data=_data)
1620
+ if _response.status_code == 404:
1621
+ raise NotFoundError(
1459
1622
  headers=dict(_response.headers),
1460
1623
  body=typing.cast(
1461
1624
  typing.Optional[typing.Any],
@@ -1470,67 +1633,145 @@ class RawDatasetsClient:
1470
1633
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1471
1634
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1472
1635
 
1473
- def delete_version_tag(
1474
- self, version_hash: str, tag: str, id: str, *, request_options: typing.Optional[RequestOptions] = None
1475
- ) -> HttpResponse[None]:
1636
+ def update_dataset_version(
1637
+ self,
1638
+ version_hash: str,
1639
+ id: str,
1640
+ *,
1641
+ change_description: typing.Optional[str] = OMIT,
1642
+ tags_to_add: typing.Optional[typing.Sequence[str]] = OMIT,
1643
+ request_options: typing.Optional[RequestOptions] = None,
1644
+ ) -> HttpResponse[DatasetVersionPublic]:
1476
1645
  """
1477
- Remove a tag from a dataset version. The version itself is not deleted, only the tag reference.
1646
+ Update a dataset version's change_description and/or add new tags
1478
1647
 
1479
1648
  Parameters
1480
1649
  ----------
1481
1650
  version_hash : str
1482
1651
 
1483
- tag : str
1484
-
1485
1652
  id : str
1486
1653
 
1654
+ change_description : typing.Optional[str]
1655
+ Optional description of changes in this version
1656
+
1657
+ tags_to_add : typing.Optional[typing.Sequence[str]]
1658
+ Optional list of tags to add to this version
1659
+
1487
1660
  request_options : typing.Optional[RequestOptions]
1488
1661
  Request-specific configuration.
1489
1662
 
1490
1663
  Returns
1491
1664
  -------
1492
- HttpResponse[None]
1665
+ HttpResponse[DatasetVersionPublic]
1666
+ Version updated successfully
1493
1667
  """
1494
1668
  _response = self._client_wrapper.httpx_client.request(
1495
- f"v1/private/datasets/{jsonable_encoder(id)}/versions/{jsonable_encoder(version_hash)}/tags/{jsonable_encoder(tag)}",
1496
- method="DELETE",
1669
+ f"v1/private/datasets/{jsonable_encoder(id)}/versions/hash/{jsonable_encoder(version_hash)}",
1670
+ method="PATCH",
1671
+ json={
1672
+ "change_description": change_description,
1673
+ "tags_to_add": tags_to_add,
1674
+ },
1675
+ headers={
1676
+ "content-type": "application/json",
1677
+ },
1497
1678
  request_options=request_options,
1679
+ omit=OMIT,
1498
1680
  )
1499
1681
  try:
1500
1682
  if 200 <= _response.status_code < 300:
1501
- return HttpResponse(response=_response, data=None)
1683
+ _data = typing.cast(
1684
+ DatasetVersionPublic,
1685
+ parse_obj_as(
1686
+ type_=DatasetVersionPublic, # type: ignore
1687
+ object_=_response.json(),
1688
+ ),
1689
+ )
1690
+ return HttpResponse(response=_response, data=_data)
1691
+ if _response.status_code == 400:
1692
+ raise BadRequestError(
1693
+ headers=dict(_response.headers),
1694
+ body=typing.cast(
1695
+ typing.Optional[typing.Any],
1696
+ parse_obj_as(
1697
+ type_=typing.Optional[typing.Any], # type: ignore
1698
+ object_=_response.json(),
1699
+ ),
1700
+ ),
1701
+ )
1702
+ if _response.status_code == 404:
1703
+ raise NotFoundError(
1704
+ headers=dict(_response.headers),
1705
+ body=typing.cast(
1706
+ typing.Optional[typing.Any],
1707
+ parse_obj_as(
1708
+ type_=typing.Optional[typing.Any], # type: ignore
1709
+ object_=_response.json(),
1710
+ ),
1711
+ ),
1712
+ )
1713
+ if _response.status_code == 409:
1714
+ raise ConflictError(
1715
+ headers=dict(_response.headers),
1716
+ body=typing.cast(
1717
+ typing.Optional[typing.Any],
1718
+ parse_obj_as(
1719
+ type_=typing.Optional[typing.Any], # type: ignore
1720
+ object_=_response.json(),
1721
+ ),
1722
+ ),
1723
+ )
1502
1724
  _response_json = _response.json()
1503
1725
  except JSONDecodeError:
1504
1726
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1505
1727
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1506
1728
 
1507
- def restore_dataset_version(
1508
- self, id: str, *, version_ref: str, request_options: typing.Optional[RequestOptions] = None
1509
- ) -> HttpResponse[DatasetVersionPublic]:
1729
+
1730
+ class AsyncRawDatasetsClient:
1731
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
1732
+ self._client_wrapper = client_wrapper
1733
+
1734
+ async def apply_dataset_item_changes(
1735
+ self,
1736
+ id: str,
1737
+ *,
1738
+ request: DatasetItemChangesPublic,
1739
+ override: typing.Optional[bool] = None,
1740
+ request_options: typing.Optional[RequestOptions] = None,
1741
+ ) -> AsyncHttpResponse[DatasetVersionPublic]:
1510
1742
  """
1511
- Restores the dataset to a previous version state. All draft items are replaced with items from the specified version. If the version is not the latest, a new version snapshot is created. If the version is the latest, only draft items are replaced (revert functionality).
1743
+ Apply delta changes (add, edit, delete) to a dataset version with conflict detection.
1744
+
1745
+ This endpoint:
1746
+ - Creates a new version with the applied changes
1747
+ - Validates that baseVersion matches the latest version (unless override=true)
1748
+ - Returns 409 Conflict if baseVersion is stale and override is not set
1749
+
1750
+ Use `override=true` query parameter to force version creation even with stale baseVersion.
1512
1751
 
1513
1752
  Parameters
1514
1753
  ----------
1515
1754
  id : str
1516
1755
 
1517
- version_ref : str
1518
- Version hash or tag to restore from
1756
+ request : DatasetItemChangesPublic
1757
+
1758
+ override : typing.Optional[bool]
1519
1759
 
1520
1760
  request_options : typing.Optional[RequestOptions]
1521
1761
  Request-specific configuration.
1522
1762
 
1523
1763
  Returns
1524
1764
  -------
1525
- HttpResponse[DatasetVersionPublic]
1526
- Version restored successfully
1765
+ AsyncHttpResponse[DatasetVersionPublic]
1766
+ Version created successfully
1527
1767
  """
1528
- _response = self._client_wrapper.httpx_client.request(
1529
- f"v1/private/datasets/{jsonable_encoder(id)}/versions/restore",
1768
+ _response = await self._client_wrapper.httpx_client.request(
1769
+ f"v1/private/datasets/{jsonable_encoder(id)}/items/changes",
1530
1770
  method="POST",
1531
- json={
1532
- "version_ref": version_ref,
1771
+ params={
1772
+ "override": override,
1533
1773
  },
1774
+ json=request,
1534
1775
  headers={
1535
1776
  "content-type": "application/json",
1536
1777
  },
@@ -1546,7 +1787,18 @@ class RawDatasetsClient:
1546
1787
  object_=_response.json(),
1547
1788
  ),
1548
1789
  )
1549
- return HttpResponse(response=_response, data=_data)
1790
+ return AsyncHttpResponse(response=_response, data=_data)
1791
+ if _response.status_code == 400:
1792
+ raise BadRequestError(
1793
+ headers=dict(_response.headers),
1794
+ body=typing.cast(
1795
+ typing.Optional[typing.Any],
1796
+ parse_obj_as(
1797
+ type_=typing.Optional[typing.Any], # type: ignore
1798
+ object_=_response.json(),
1799
+ ),
1800
+ ),
1801
+ )
1550
1802
  if _response.status_code == 404:
1551
1803
  raise NotFoundError(
1552
1804
  headers=dict(_response.headers),
@@ -1558,22 +1810,29 @@ class RawDatasetsClient:
1558
1810
  ),
1559
1811
  ),
1560
1812
  )
1813
+ if _response.status_code == 409:
1814
+ raise ConflictError(
1815
+ headers=dict(_response.headers),
1816
+ body=typing.cast(
1817
+ typing.Optional[typing.Any],
1818
+ parse_obj_as(
1819
+ type_=typing.Optional[typing.Any], # type: ignore
1820
+ object_=_response.json(),
1821
+ ),
1822
+ ),
1823
+ )
1561
1824
  _response_json = _response.json()
1562
1825
  except JSONDecodeError:
1563
1826
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1564
1827
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1565
1828
 
1566
-
1567
- class AsyncRawDatasetsClient:
1568
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
1569
- self._client_wrapper = client_wrapper
1570
-
1571
1829
  async def batch_update_dataset_items(
1572
1830
  self,
1573
1831
  *,
1574
1832
  update: DatasetItemUpdate,
1575
1833
  ids: typing.Optional[typing.Sequence[str]] = OMIT,
1576
1834
  filters: typing.Optional[typing.Sequence[DatasetItemFilter]] = OMIT,
1835
+ dataset_id: typing.Optional[str] = OMIT,
1577
1836
  merge_tags: typing.Optional[bool] = OMIT,
1578
1837
  request_options: typing.Optional[RequestOptions] = None,
1579
1838
  ) -> AsyncHttpResponse[None]:
@@ -1589,6 +1848,9 @@ class AsyncRawDatasetsClient:
1589
1848
 
1590
1849
  filters : typing.Optional[typing.Sequence[DatasetItemFilter]]
1591
1850
 
1851
+ dataset_id : typing.Optional[str]
1852
+ Dataset ID. Required when using 'filters', optional when using 'ids'.
1853
+
1592
1854
  merge_tags : typing.Optional[bool]
1593
1855
  If true, merge tags with existing tags instead of replacing them. Default: false. When using 'filters', this is automatically set to true.
1594
1856
 
@@ -1607,6 +1869,7 @@ class AsyncRawDatasetsClient:
1607
1869
  "filters": convert_and_respect_annotation_metadata(
1608
1870
  object_=filters, annotation=typing.Sequence[DatasetItemFilter], direction="write"
1609
1871
  ),
1872
+ "dataset_id": dataset_id,
1610
1873
  "update": convert_and_respect_annotation_metadata(
1611
1874
  object_=update, annotation=DatasetItemUpdate, direction="write"
1612
1875
  ),
@@ -1771,6 +2034,7 @@ class AsyncRawDatasetsClient:
1771
2034
  items: typing.Sequence[DatasetItemWrite],
1772
2035
  dataset_name: typing.Optional[str] = OMIT,
1773
2036
  dataset_id: typing.Optional[str] = OMIT,
2037
+ batch_group_id: typing.Optional[str] = OMIT,
1774
2038
  request_options: typing.Optional[RequestOptions] = None,
1775
2039
  ) -> AsyncHttpResponse[None]:
1776
2040
  """
@@ -1786,6 +2050,9 @@ class AsyncRawDatasetsClient:
1786
2050
  dataset_id : typing.Optional[str]
1787
2051
  If null, dataset_name must be provided
1788
2052
 
2053
+ batch_group_id : typing.Optional[str]
2054
+ Optional batch group ID to group multiple batches into a single dataset version. If null, mutates the latest version instead of creating a new one.
2055
+
1789
2056
  request_options : typing.Optional[RequestOptions]
1790
2057
  Request-specific configuration.
1791
2058
 
@@ -1802,6 +2069,7 @@ class AsyncRawDatasetsClient:
1802
2069
  "items": convert_and_respect_annotation_metadata(
1803
2070
  object_=items, annotation=typing.Sequence[DatasetItemWrite], direction="write"
1804
2071
  ),
2072
+ "batch_group_id": batch_group_id,
1805
2073
  },
1806
2074
  headers={
1807
2075
  "content-type": "application/json",
@@ -2142,14 +2410,34 @@ class AsyncRawDatasetsClient:
2142
2410
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
2143
2411
 
2144
2412
  async def delete_dataset_items(
2145
- self, *, item_ids: typing.Sequence[str], request_options: typing.Optional[RequestOptions] = None
2413
+ self,
2414
+ *,
2415
+ item_ids: typing.Optional[typing.Sequence[str]] = OMIT,
2416
+ dataset_id: typing.Optional[str] = OMIT,
2417
+ filters: typing.Optional[typing.Sequence[DatasetItemFilter]] = OMIT,
2418
+ batch_group_id: typing.Optional[str] = OMIT,
2419
+ request_options: typing.Optional[RequestOptions] = None,
2146
2420
  ) -> AsyncHttpResponse[None]:
2147
2421
  """
2148
- Delete dataset items
2422
+ Delete dataset items using one of two modes:
2423
+ 1. **Delete by IDs**: Provide 'item_ids' to delete specific items by their IDs
2424
+ 2. **Delete by filters**: Provide 'dataset_id' with optional 'filters' to delete items matching criteria
2425
+
2426
+ When using filters, an empty 'filters' array will delete all items in the specified dataset.
2149
2427
 
2150
2428
  Parameters
2151
2429
  ----------
2152
- item_ids : typing.Sequence[str]
2430
+ item_ids : typing.Optional[typing.Sequence[str]]
2431
+ List of dataset item IDs to delete (max 1000). Use this to delete specific items by their IDs. Mutually exclusive with 'dataset_id' and 'filters'.
2432
+
2433
+ dataset_id : typing.Optional[str]
2434
+ Dataset ID to scope the deletion. Required when using 'filters'. Mutually exclusive with 'item_ids'.
2435
+
2436
+ filters : typing.Optional[typing.Sequence[DatasetItemFilter]]
2437
+ Filters to select dataset items to delete within the specified dataset. Must be used with 'dataset_id'. Mutually exclusive with 'item_ids'. Empty array means 'delete all items in the dataset'.
2438
+
2439
+ batch_group_id : typing.Optional[str]
2440
+ Optional batch group ID to group multiple delete operations into a single dataset version. If null, mutates the latest version instead of creating a new one.
2153
2441
 
2154
2442
  request_options : typing.Optional[RequestOptions]
2155
2443
  Request-specific configuration.
@@ -2163,6 +2451,11 @@ class AsyncRawDatasetsClient:
2163
2451
  method="POST",
2164
2452
  json={
2165
2453
  "item_ids": item_ids,
2454
+ "dataset_id": dataset_id,
2455
+ "filters": convert_and_respect_annotation_metadata(
2456
+ object_=filters, annotation=typing.Sequence[DatasetItemFilter], direction="write"
2457
+ ),
2458
+ "batch_group_id": batch_group_id,
2166
2459
  },
2167
2460
  headers={
2168
2461
  "content-type": "application/json",
@@ -2173,6 +2466,17 @@ class AsyncRawDatasetsClient:
2173
2466
  try:
2174
2467
  if 200 <= _response.status_code < 300:
2175
2468
  return AsyncHttpResponse(response=_response, data=None)
2469
+ if _response.status_code == 400:
2470
+ raise BadRequestError(
2471
+ headers=dict(_response.headers),
2472
+ body=typing.cast(
2473
+ typing.Optional[typing.Any],
2474
+ parse_obj_as(
2475
+ type_=typing.Optional[typing.Any], # type: ignore
2476
+ object_=_response.json(),
2477
+ ),
2478
+ ),
2479
+ )
2176
2480
  _response_json = _response.json()
2177
2481
  except JSONDecodeError:
2178
2482
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
@@ -2683,6 +2987,7 @@ class AsyncRawDatasetsClient:
2683
2987
  dataset_name: str,
2684
2988
  last_retrieved_id: typing.Optional[str] = OMIT,
2685
2989
  steam_limit: typing.Optional[int] = OMIT,
2990
+ dataset_version: typing.Optional[str] = OMIT,
2686
2991
  request_options: typing.Optional[RequestOptions] = None,
2687
2992
  ) -> typing.AsyncIterator[AsyncHttpResponse[typing.AsyncIterator[bytes]]]:
2688
2993
  """
@@ -2696,6 +3001,8 @@ class AsyncRawDatasetsClient:
2696
3001
 
2697
3002
  steam_limit : typing.Optional[int]
2698
3003
 
3004
+ dataset_version : typing.Optional[str]
3005
+
2699
3006
  request_options : typing.Optional[RequestOptions]
2700
3007
  Request-specific configuration. You can pass in configuration such as `chunk_size`, and more to customize the request and response.
2701
3008
 
@@ -2711,6 +3018,7 @@ class AsyncRawDatasetsClient:
2711
3018
  "dataset_name": dataset_name,
2712
3019
  "last_retrieved_id": last_retrieved_id,
2713
3020
  "steam_limit": steam_limit,
3021
+ "dataset_version": dataset_version,
2714
3022
  },
2715
3023
  headers={
2716
3024
  "content-type": "application/json",
@@ -2860,6 +3168,40 @@ class AsyncRawDatasetsClient:
2860
3168
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
2861
3169
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
2862
3170
 
3171
+ async def delete_version_tag(
3172
+ self, version_hash: str, tag: str, id: str, *, request_options: typing.Optional[RequestOptions] = None
3173
+ ) -> AsyncHttpResponse[None]:
3174
+ """
3175
+ Remove a tag from a dataset version. The version itself is not deleted, only the tag reference.
3176
+
3177
+ Parameters
3178
+ ----------
3179
+ version_hash : str
3180
+
3181
+ tag : str
3182
+
3183
+ id : str
3184
+
3185
+ request_options : typing.Optional[RequestOptions]
3186
+ Request-specific configuration.
3187
+
3188
+ Returns
3189
+ -------
3190
+ AsyncHttpResponse[None]
3191
+ """
3192
+ _response = await self._client_wrapper.httpx_client.request(
3193
+ f"v1/private/datasets/{jsonable_encoder(id)}/versions/{jsonable_encoder(version_hash)}/tags/{jsonable_encoder(tag)}",
3194
+ method="DELETE",
3195
+ request_options=request_options,
3196
+ )
3197
+ try:
3198
+ if 200 <= _response.status_code < 300:
3199
+ return AsyncHttpResponse(response=_response, data=None)
3200
+ _response_json = _response.json()
3201
+ except JSONDecodeError:
3202
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
3203
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
3204
+
2863
3205
  async def list_dataset_versions(
2864
3206
  self,
2865
3207
  id: str,
@@ -2922,45 +3264,32 @@ class AsyncRawDatasetsClient:
2922
3264
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
2923
3265
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
2924
3266
 
2925
- async def create_dataset_version(
2926
- self,
2927
- id: str,
2928
- *,
2929
- tag: typing.Optional[str] = OMIT,
2930
- change_description: typing.Optional[str] = OMIT,
2931
- metadata: typing.Optional[typing.Dict[str, str]] = OMIT,
2932
- request_options: typing.Optional[RequestOptions] = None,
2933
- ) -> AsyncHttpResponse[None]:
3267
+ async def restore_dataset_version(
3268
+ self, id: str, *, version_ref: str, request_options: typing.Optional[RequestOptions] = None
3269
+ ) -> AsyncHttpResponse[DatasetVersionPublic]:
2934
3270
  """
2935
- Create a new immutable version of the dataset by snapshotting the current state
3271
+ Restores the dataset to a previous version state by creating a new version with items copied from the specified version. If the version is already the latest, returns it as-is (no-op).
2936
3272
 
2937
3273
  Parameters
2938
3274
  ----------
2939
3275
  id : str
2940
3276
 
2941
- tag : typing.Optional[str]
2942
- Optional tag for this version
2943
-
2944
- change_description : typing.Optional[str]
2945
- Optional description of changes in this version
2946
-
2947
- metadata : typing.Optional[typing.Dict[str, str]]
2948
- Optional user-defined metadata
3277
+ version_ref : str
3278
+ Version hash or tag to restore from
2949
3279
 
2950
3280
  request_options : typing.Optional[RequestOptions]
2951
3281
  Request-specific configuration.
2952
3282
 
2953
3283
  Returns
2954
3284
  -------
2955
- AsyncHttpResponse[None]
3285
+ AsyncHttpResponse[DatasetVersionPublic]
3286
+ Version restored successfully
2956
3287
  """
2957
3288
  _response = await self._client_wrapper.httpx_client.request(
2958
- f"v1/private/datasets/{jsonable_encoder(id)}/versions",
3289
+ f"v1/private/datasets/{jsonable_encoder(id)}/versions/restore",
2959
3290
  method="POST",
2960
3291
  json={
2961
- "tag": tag,
2962
- "change_description": change_description,
2963
- "metadata": metadata,
3292
+ "version_ref": version_ref,
2964
3293
  },
2965
3294
  headers={
2966
3295
  "content-type": "application/json",
@@ -2970,20 +3299,16 @@ class AsyncRawDatasetsClient:
2970
3299
  )
2971
3300
  try:
2972
3301
  if 200 <= _response.status_code < 300:
2973
- return AsyncHttpResponse(response=_response, data=None)
2974
- if _response.status_code == 400:
2975
- raise BadRequestError(
2976
- headers=dict(_response.headers),
2977
- body=typing.cast(
2978
- typing.Optional[typing.Any],
2979
- parse_obj_as(
2980
- type_=typing.Optional[typing.Any], # type: ignore
2981
- object_=_response.json(),
2982
- ),
3302
+ _data = typing.cast(
3303
+ DatasetVersionPublic,
3304
+ parse_obj_as(
3305
+ type_=DatasetVersionPublic, # type: ignore
3306
+ object_=_response.json(),
2983
3307
  ),
2984
3308
  )
2985
- if _response.status_code == 409:
2986
- raise ConflictError(
3309
+ return AsyncHttpResponse(response=_response, data=_data)
3310
+ if _response.status_code == 404:
3311
+ raise NotFoundError(
2987
3312
  headers=dict(_response.headers),
2988
3313
  body=typing.cast(
2989
3314
  typing.Optional[typing.Any],
@@ -2998,52 +3323,29 @@ class AsyncRawDatasetsClient:
2998
3323
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
2999
3324
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
3000
3325
 
3001
- async def delete_version_tag(
3002
- self, version_hash: str, tag: str, id: str, *, request_options: typing.Optional[RequestOptions] = None
3003
- ) -> AsyncHttpResponse[None]:
3326
+ async def update_dataset_version(
3327
+ self,
3328
+ version_hash: str,
3329
+ id: str,
3330
+ *,
3331
+ change_description: typing.Optional[str] = OMIT,
3332
+ tags_to_add: typing.Optional[typing.Sequence[str]] = OMIT,
3333
+ request_options: typing.Optional[RequestOptions] = None,
3334
+ ) -> AsyncHttpResponse[DatasetVersionPublic]:
3004
3335
  """
3005
- Remove a tag from a dataset version. The version itself is not deleted, only the tag reference.
3336
+ Update a dataset version's change_description and/or add new tags
3006
3337
 
3007
3338
  Parameters
3008
3339
  ----------
3009
3340
  version_hash : str
3010
3341
 
3011
- tag : str
3012
-
3013
3342
  id : str
3014
3343
 
3015
- request_options : typing.Optional[RequestOptions]
3016
- Request-specific configuration.
3017
-
3018
- Returns
3019
- -------
3020
- AsyncHttpResponse[None]
3021
- """
3022
- _response = await self._client_wrapper.httpx_client.request(
3023
- f"v1/private/datasets/{jsonable_encoder(id)}/versions/{jsonable_encoder(version_hash)}/tags/{jsonable_encoder(tag)}",
3024
- method="DELETE",
3025
- request_options=request_options,
3026
- )
3027
- try:
3028
- if 200 <= _response.status_code < 300:
3029
- return AsyncHttpResponse(response=_response, data=None)
3030
- _response_json = _response.json()
3031
- except JSONDecodeError:
3032
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
3033
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
3034
-
3035
- async def restore_dataset_version(
3036
- self, id: str, *, version_ref: str, request_options: typing.Optional[RequestOptions] = None
3037
- ) -> AsyncHttpResponse[DatasetVersionPublic]:
3038
- """
3039
- Restores the dataset to a previous version state. All draft items are replaced with items from the specified version. If the version is not the latest, a new version snapshot is created. If the version is the latest, only draft items are replaced (revert functionality).
3040
-
3041
- Parameters
3042
- ----------
3043
- id : str
3344
+ change_description : typing.Optional[str]
3345
+ Optional description of changes in this version
3044
3346
 
3045
- version_ref : str
3046
- Version hash or tag to restore from
3347
+ tags_to_add : typing.Optional[typing.Sequence[str]]
3348
+ Optional list of tags to add to this version
3047
3349
 
3048
3350
  request_options : typing.Optional[RequestOptions]
3049
3351
  Request-specific configuration.
@@ -3051,13 +3353,14 @@ class AsyncRawDatasetsClient:
3051
3353
  Returns
3052
3354
  -------
3053
3355
  AsyncHttpResponse[DatasetVersionPublic]
3054
- Version restored successfully
3356
+ Version updated successfully
3055
3357
  """
3056
3358
  _response = await self._client_wrapper.httpx_client.request(
3057
- f"v1/private/datasets/{jsonable_encoder(id)}/versions/restore",
3058
- method="POST",
3359
+ f"v1/private/datasets/{jsonable_encoder(id)}/versions/hash/{jsonable_encoder(version_hash)}",
3360
+ method="PATCH",
3059
3361
  json={
3060
- "version_ref": version_ref,
3362
+ "change_description": change_description,
3363
+ "tags_to_add": tags_to_add,
3061
3364
  },
3062
3365
  headers={
3063
3366
  "content-type": "application/json",
@@ -3075,6 +3378,17 @@ class AsyncRawDatasetsClient:
3075
3378
  ),
3076
3379
  )
3077
3380
  return AsyncHttpResponse(response=_response, data=_data)
3381
+ if _response.status_code == 400:
3382
+ raise BadRequestError(
3383
+ headers=dict(_response.headers),
3384
+ body=typing.cast(
3385
+ typing.Optional[typing.Any],
3386
+ parse_obj_as(
3387
+ type_=typing.Optional[typing.Any], # type: ignore
3388
+ object_=_response.json(),
3389
+ ),
3390
+ ),
3391
+ )
3078
3392
  if _response.status_code == 404:
3079
3393
  raise NotFoundError(
3080
3394
  headers=dict(_response.headers),
@@ -3086,6 +3400,17 @@ class AsyncRawDatasetsClient:
3086
3400
  ),
3087
3401
  ),
3088
3402
  )
3403
+ if _response.status_code == 409:
3404
+ raise ConflictError(
3405
+ headers=dict(_response.headers),
3406
+ body=typing.cast(
3407
+ typing.Optional[typing.Any],
3408
+ parse_obj_as(
3409
+ type_=typing.Optional[typing.Any], # type: ignore
3410
+ object_=_response.json(),
3411
+ ),
3412
+ ),
3413
+ )
3089
3414
  _response_json = _response.json()
3090
3415
  except JSONDecodeError:
3091
3416
  raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)