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
@@ -6,6 +6,7 @@ import typing
6
6
  import pydantic
7
7
  from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
8
8
  from .dataset_status import DatasetStatus
9
+ from .dataset_version_summary import DatasetVersionSummary
9
10
  from .dataset_visibility import DatasetVisibility
10
11
 
11
12
 
@@ -27,6 +28,7 @@ class Dataset(UniversalBaseModel):
27
28
  most_recent_optimization_at: typing.Optional[dt.datetime] = None
28
29
  last_created_optimization_at: typing.Optional[dt.datetime] = None
29
30
  status: typing.Optional[DatasetStatus] = None
31
+ latest_version: typing.Optional[DatasetVersionSummary] = None
30
32
 
31
33
  if IS_PYDANTIC_V2:
32
34
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -12,7 +12,7 @@ from .json_node import JsonNode
12
12
 
13
13
  class DatasetItem(UniversalBaseModel):
14
14
  id: typing.Optional[str] = None
15
- draft_item_id: typing.Optional[str] = None
15
+ dataset_item_id: typing.Optional[str] = None
16
16
  trace_id: typing.Optional[str] = None
17
17
  span_id: typing.Optional[str] = None
18
18
  source: DatasetItemSource
@@ -19,6 +19,10 @@ class DatasetItemBatch(UniversalBaseModel):
19
19
  """
20
20
 
21
21
  items: typing.List[DatasetItem]
22
+ batch_group_id: typing.Optional[str] = pydantic.Field(default=None)
23
+ """
24
+ 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.
25
+ """
22
26
 
23
27
  if IS_PYDANTIC_V2:
24
28
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -0,0 +1,5 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ DatasetItemChangesPublic = typing.Dict[str, typing.Optional[typing.Any]]
@@ -12,7 +12,7 @@ from .json_node import JsonNode
12
12
 
13
13
  class DatasetItemCompare(UniversalBaseModel):
14
14
  id: typing.Optional[str] = None
15
- draft_item_id: typing.Optional[str] = None
15
+ dataset_item_id: typing.Optional[str] = None
16
16
  trace_id: typing.Optional[str] = None
17
17
  span_id: typing.Optional[str] = None
18
18
  source: DatasetItemCompareSource
@@ -8,6 +8,10 @@ from .dataset_item_filter_operator import DatasetItemFilterOperator
8
8
 
9
9
 
10
10
  class DatasetItemFilter(UniversalBaseModel):
11
+ """
12
+ 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'.
13
+ """
14
+
11
15
  field: typing.Optional[str] = None
12
16
  operator: typing.Optional[DatasetItemFilterOperator] = None
13
17
  key: typing.Optional[str] = None
@@ -19,7 +19,6 @@ class DatasetItemPageCompare(UniversalBaseModel):
19
19
  sortable_by: typing_extensions.Annotated[typing.Optional[typing.List[str]], FieldMetadata(alias="sortableBy")] = (
20
20
  None
21
21
  )
22
- has_draft: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="hasDraft")] = None
23
22
 
24
23
  if IS_PYDANTIC_V2:
25
24
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -19,7 +19,6 @@ class DatasetItemPagePublic(UniversalBaseModel):
19
19
  sortable_by: typing_extensions.Annotated[typing.Optional[typing.List[str]], FieldMetadata(alias="sortableBy")] = (
20
20
  None
21
21
  )
22
- has_draft: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="hasDraft")] = None
23
22
 
24
23
  if IS_PYDANTIC_V2:
25
24
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -12,7 +12,7 @@ from .json_node import JsonNode
12
12
 
13
13
  class DatasetItemPublic(UniversalBaseModel):
14
14
  id: typing.Optional[str] = None
15
- draft_item_id: typing.Optional[str] = None
15
+ dataset_item_id: typing.Optional[str] = None
16
16
  trace_id: typing.Optional[str] = None
17
17
  span_id: typing.Optional[str] = None
18
18
  source: DatasetItemPublicSource
@@ -7,6 +7,7 @@ import pydantic
7
7
  from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
8
8
  from .dataset_public_status import DatasetPublicStatus
9
9
  from .dataset_public_visibility import DatasetPublicVisibility
10
+ from .dataset_version_summary_public import DatasetVersionSummaryPublic
10
11
 
11
12
 
12
13
  class DatasetPublic(UniversalBaseModel):
@@ -27,6 +28,7 @@ class DatasetPublic(UniversalBaseModel):
27
28
  most_recent_optimization_at: typing.Optional[dt.datetime] = None
28
29
  last_created_optimization_at: typing.Optional[dt.datetime] = None
29
30
  status: typing.Optional[DatasetPublicStatus] = None
31
+ latest_version: typing.Optional[DatasetVersionSummaryPublic] = None
30
32
 
31
33
  if IS_PYDANTIC_V2:
32
34
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -12,6 +12,16 @@ class DatasetVersionPublic(UniversalBaseModel):
12
12
  dataset_id: typing.Optional[str] = None
13
13
  version_hash: typing.Optional[str] = None
14
14
  tags: typing.Optional[typing.List[str]] = None
15
+ is_latest: typing.Optional[bool] = pydantic.Field(default=None)
16
+ """
17
+ Indicates whether this is the latest version of the dataset
18
+ """
19
+
20
+ version_name: typing.Optional[str] = pydantic.Field(default=None)
21
+ """
22
+ Sequential version name formatted as 'v1', 'v2', etc.
23
+ """
24
+
15
25
  items_total: typing.Optional[int] = pydantic.Field(default=None)
16
26
  """
17
27
  Total number of items in this version
@@ -0,0 +1,46 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ import pydantic
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
7
+
8
+
9
+ class DatasetVersionSummary(UniversalBaseModel):
10
+ """
11
+ Summary of the latest dataset version
12
+ """
13
+
14
+ id: typing.Optional[str] = pydantic.Field(default=None)
15
+ """
16
+ Unique identifier of the version
17
+ """
18
+
19
+ version_hash: typing.Optional[str] = pydantic.Field(default=None)
20
+ """
21
+ Hash of the version content
22
+ """
23
+
24
+ version_name: typing.Optional[str] = pydantic.Field(default=None)
25
+ """
26
+ Sequential version name formatted as 'v1', 'v2', etc.
27
+ """
28
+
29
+ change_description: typing.Optional[str] = pydantic.Field(default=None)
30
+ """
31
+ Description of changes in this version
32
+ """
33
+
34
+ tags: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
35
+ """
36
+ Tags associated with this version
37
+ """
38
+
39
+ if IS_PYDANTIC_V2:
40
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
41
+ else:
42
+
43
+ class Config:
44
+ frozen = True
45
+ smart_union = True
46
+ extra = pydantic.Extra.allow
@@ -0,0 +1,46 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ import pydantic
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
7
+
8
+
9
+ class DatasetVersionSummaryPublic(UniversalBaseModel):
10
+ """
11
+ Summary of the latest dataset version
12
+ """
13
+
14
+ id: typing.Optional[str] = pydantic.Field(default=None)
15
+ """
16
+ Unique identifier of the version
17
+ """
18
+
19
+ version_hash: typing.Optional[str] = pydantic.Field(default=None)
20
+ """
21
+ Hash of the version content
22
+ """
23
+
24
+ version_name: typing.Optional[str] = pydantic.Field(default=None)
25
+ """
26
+ Sequential version name formatted as 'v1', 'v2', etc.
27
+ """
28
+
29
+ change_description: typing.Optional[str] = pydantic.Field(default=None)
30
+ """
31
+ Description of changes in this version
32
+ """
33
+
34
+ tags: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
35
+ """
36
+ Tags associated with this version
37
+ """
38
+
39
+ if IS_PYDANTIC_V2:
40
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
41
+ else:
42
+
43
+ class Config:
44
+ frozen = True
45
+ smart_union = True
46
+ extra = pydantic.Extra.allow
@@ -6,6 +6,7 @@ import typing
6
6
  import pydantic
7
7
  from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
8
8
  from .comment import Comment
9
+ from .dataset_version_summary import DatasetVersionSummary
9
10
  from .experiment_score import ExperimentScore
10
11
  from .experiment_status import ExperimentStatus
11
12
  from .experiment_type import ExperimentType
@@ -19,8 +20,10 @@ class Experiment(UniversalBaseModel):
19
20
  id: typing.Optional[str] = None
20
21
  dataset_name: str
21
22
  dataset_id: typing.Optional[str] = None
23
+ project_id: typing.Optional[str] = None
22
24
  name: typing.Optional[str] = None
23
25
  metadata: typing.Optional[JsonListString] = None
26
+ tags: typing.Optional[typing.List[str]] = None
24
27
  type: typing.Optional[ExperimentType] = None
25
28
  optimization_id: typing.Optional[str] = None
26
29
  feedback_scores: typing.Optional[typing.List[FeedbackScoreAverage]] = None
@@ -38,6 +41,12 @@ class Experiment(UniversalBaseModel):
38
41
  experiment_scores: typing.Optional[typing.List[ExperimentScore]] = None
39
42
  prompt_version: typing.Optional[PromptVersionLink] = None
40
43
  prompt_versions: typing.Optional[typing.List[PromptVersionLink]] = None
44
+ dataset_version_id: typing.Optional[str] = pydantic.Field(default=None)
45
+ """
46
+ ID of the dataset version this experiment is linked to. If not provided at creation, experiment will be automatically linked to the latest version.
47
+ """
48
+
49
+ dataset_version_summary: typing.Optional[DatasetVersionSummary] = None
41
50
 
42
51
  if IS_PYDANTIC_V2:
43
52
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -6,6 +6,7 @@ import typing
6
6
  import pydantic
7
7
  from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
8
8
  from .comment_public import CommentPublic
9
+ from .dataset_version_summary_public import DatasetVersionSummaryPublic
9
10
  from .experiment_public_status import ExperimentPublicStatus
10
11
  from .experiment_public_type import ExperimentPublicType
11
12
  from .experiment_score_public import ExperimentScorePublic
@@ -19,8 +20,10 @@ class ExperimentPublic(UniversalBaseModel):
19
20
  id: typing.Optional[str] = None
20
21
  dataset_name: str
21
22
  dataset_id: typing.Optional[str] = None
23
+ project_id: typing.Optional[str] = None
22
24
  name: typing.Optional[str] = None
23
25
  metadata: typing.Optional[JsonListStringPublic] = None
26
+ tags: typing.Optional[typing.List[str]] = None
24
27
  type: typing.Optional[ExperimentPublicType] = None
25
28
  optimization_id: typing.Optional[str] = None
26
29
  feedback_scores: typing.Optional[typing.List[FeedbackScoreAveragePublic]] = None
@@ -38,6 +41,12 @@ class ExperimentPublic(UniversalBaseModel):
38
41
  experiment_scores: typing.Optional[typing.List[ExperimentScorePublic]] = None
39
42
  prompt_version: typing.Optional[PromptVersionLinkPublic] = None
40
43
  prompt_versions: typing.Optional[typing.List[PromptVersionLinkPublic]] = None
44
+ dataset_version_id: typing.Optional[str] = pydantic.Field(default=None)
45
+ """
46
+ ID of the dataset version this experiment is linked to. If not provided at creation, experiment will be automatically linked to the latest version.
47
+ """
48
+
49
+ dataset_version_summary: typing.Optional[DatasetVersionSummaryPublic] = None
41
50
 
42
51
  if IS_PYDANTIC_V2:
43
52
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -8,6 +8,7 @@ from .aggregation_data import AggregationData
8
8
 
9
9
 
10
10
  class GroupContentWithAggregations(UniversalBaseModel):
11
+ label: typing.Optional[str] = None
11
12
  aggregations: typing.Optional[AggregationData] = None
12
13
 
13
14
  if IS_PYDANTIC_V2:
@@ -4,6 +4,7 @@ import typing
4
4
 
5
5
  import pydantic
6
6
  from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
7
+ from .audio_url import AudioUrl
7
8
  from .image_url import ImageUrl
8
9
  from .video_url import VideoUrl
9
10
 
@@ -13,6 +14,7 @@ class LlmAsJudgeMessageContent(UniversalBaseModel):
13
14
  text: typing.Optional[str] = None
14
15
  image_url: typing.Optional[ImageUrl] = None
15
16
  video_url: typing.Optional[VideoUrl] = None
17
+ audio_url: typing.Optional[AudioUrl] = None
16
18
 
17
19
  if IS_PYDANTIC_V2:
18
20
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -4,6 +4,7 @@ import typing
4
4
 
5
5
  import pydantic
6
6
  from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
7
+ from .audio_url_public import AudioUrlPublic
7
8
  from .image_url_public import ImageUrlPublic
8
9
  from .video_url_public import VideoUrlPublic
9
10
 
@@ -13,6 +14,7 @@ class LlmAsJudgeMessageContentPublic(UniversalBaseModel):
13
14
  text: typing.Optional[str] = None
14
15
  image_url: typing.Optional[ImageUrlPublic] = None
15
16
  video_url: typing.Optional[VideoUrlPublic] = None
17
+ audio_url: typing.Optional[AudioUrlPublic] = None
16
18
 
17
19
  if IS_PYDANTIC_V2:
18
20
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -4,6 +4,7 @@ import typing
4
4
 
5
5
  import pydantic
6
6
  from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
7
+ from .audio_url_write import AudioUrlWrite
7
8
  from .image_url_write import ImageUrlWrite
8
9
  from .video_url_write import VideoUrlWrite
9
10
 
@@ -13,6 +14,7 @@ class LlmAsJudgeMessageContentWrite(UniversalBaseModel):
13
14
  text: typing.Optional[str] = None
14
15
  image_url: typing.Optional[ImageUrlWrite] = None
15
16
  video_url: typing.Optional[VideoUrlWrite] = None
17
+ audio_url: typing.Optional[AudioUrlWrite] = None
16
18
 
17
19
  if IS_PYDANTIC_V2:
18
20
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -2,4 +2,4 @@
2
2
 
3
3
  import typing
4
4
 
5
- ManualEvaluationRequestEntityType = typing.Union[typing.Literal["trace", "thread"], typing.Any]
5
+ ManualEvaluationRequestEntityType = typing.Union[typing.Literal["trace", "thread", "span"], typing.Any]
@@ -27,6 +27,7 @@ class Project(UniversalBaseModel):
27
27
  total_estimated_cost_sum: typing.Optional[float] = None
28
28
  usage: typing.Optional[typing.Dict[str, float]] = None
29
29
  trace_count: typing.Optional[int] = None
30
+ thread_count: typing.Optional[int] = None
30
31
  guardrails_failed_count: typing.Optional[int] = None
31
32
  error_count: typing.Optional[ErrorCountWithDeviation] = None
32
33
 
@@ -27,6 +27,7 @@ class ProjectDetailed(UniversalBaseModel):
27
27
  total_estimated_cost_sum: typing.Optional[float] = None
28
28
  usage: typing.Optional[typing.Dict[str, float]] = None
29
29
  trace_count: typing.Optional[int] = None
30
+ thread_count: typing.Optional[int] = None
30
31
  guardrails_failed_count: typing.Optional[int] = None
31
32
  error_count: typing.Optional[ErrorCountWithDeviationDetailed] = None
32
33
 
@@ -13,6 +13,10 @@ ProjectMetricResponsePublicMetricType = typing.Union[
13
13
  "THREAD_COUNT",
14
14
  "THREAD_DURATION",
15
15
  "THREAD_FEEDBACK_SCORES",
16
+ "SPAN_FEEDBACK_SCORES",
17
+ "SPAN_COUNT",
18
+ "SPAN_DURATION",
19
+ "SPAN_TOKEN_USAGE",
16
20
  ],
17
21
  typing.Any,
18
22
  ]
@@ -0,0 +1,31 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ import pydantic
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
7
+
8
+
9
+ class ProjectReference(UniversalBaseModel):
10
+ """
11
+ Project reference with ID and name
12
+ """
13
+
14
+ project_id: str = pydantic.Field()
15
+ """
16
+ Project ID
17
+ """
18
+
19
+ project_name: str = pydantic.Field()
20
+ """
21
+ Project name
22
+ """
23
+
24
+ if IS_PYDANTIC_V2:
25
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
26
+ else:
27
+
28
+ class Config:
29
+ frozen = True
30
+ smart_union = True
31
+ extra = pydantic.Extra.allow
@@ -0,0 +1,31 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ import pydantic
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
7
+
8
+
9
+ class ProjectReferencePublic(UniversalBaseModel):
10
+ """
11
+ Project reference with ID and name
12
+ """
13
+
14
+ project_id: str = pydantic.Field()
15
+ """
16
+ Project ID
17
+ """
18
+
19
+ project_name: str = pydantic.Field()
20
+ """
21
+ Project name
22
+ """
23
+
24
+ if IS_PYDANTIC_V2:
25
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
26
+ else:
27
+
28
+ class Config:
29
+ frozen = True
30
+ smart_union = True
31
+ extra = pydantic.Extra.allow
@@ -17,6 +17,7 @@ class ProjectStatsSummaryItem(UniversalBaseModel):
17
17
  total_estimated_cost_sum: typing.Optional[float] = None
18
18
  usage: typing.Optional[typing.Dict[str, float]] = None
19
19
  trace_count: typing.Optional[int] = None
20
+ thread_count: typing.Optional[int] = None
20
21
  guardrails_failed_count: typing.Optional[int] = None
21
22
  error_count: typing.Optional[ErrorCountWithDeviation] = None
22
23
 
@@ -26,6 +26,7 @@ class PromptVersion(UniversalBaseModel):
26
26
  metadata: typing.Optional[JsonNode] = None
27
27
  type: typing.Optional[PromptVersionType] = None
28
28
  change_description: typing.Optional[str] = None
29
+ tags: typing.Optional[typing.List[str]] = None
29
30
  variables: typing.Optional[typing.List[str]] = None
30
31
  template_structure: typing.Optional[PromptVersionTemplateStructure] = None
31
32
  created_at: typing.Optional[dt.datetime] = None
@@ -26,6 +26,7 @@ class PromptVersionDetail(UniversalBaseModel):
26
26
  metadata: typing.Optional[JsonNodeDetail] = None
27
27
  type: typing.Optional[PromptVersionDetailType] = None
28
28
  change_description: typing.Optional[str] = None
29
+ tags: typing.Optional[typing.List[str]] = None
29
30
  variables: typing.Optional[typing.List[str]] = None
30
31
  template_structure: typing.Optional[PromptVersionDetailTemplateStructure] = None
31
32
  created_at: typing.Optional[dt.datetime] = None
@@ -3,7 +3,9 @@
3
3
  import typing
4
4
 
5
5
  import pydantic
6
+ import typing_extensions
6
7
  from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
8
+ from ..core.serialization import FieldMetadata
7
9
  from .prompt_version_public import PromptVersionPublic
8
10
 
9
11
 
@@ -12,6 +14,9 @@ class PromptVersionPagePublic(UniversalBaseModel):
12
14
  size: typing.Optional[int] = None
13
15
  total: typing.Optional[int] = None
14
16
  content: typing.Optional[typing.List[PromptVersionPublic]] = None
17
+ sortable_by: typing_extensions.Annotated[typing.Optional[typing.List[str]], FieldMetadata(alias="sortableBy")] = (
18
+ None
19
+ )
15
20
 
16
21
  if IS_PYDANTIC_V2:
17
22
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -26,6 +26,7 @@ class PromptVersionPublic(UniversalBaseModel):
26
26
  metadata: typing.Optional[JsonNodePublic] = None
27
27
  type: typing.Optional[PromptVersionPublicType] = None
28
28
  change_description: typing.Optional[str] = None
29
+ tags: typing.Optional[typing.List[str]] = None
29
30
  template_structure: typing.Optional[PromptVersionPublicTemplateStructure] = None
30
31
  created_at: typing.Optional[dt.datetime] = None
31
32
  created_by: typing.Optional[str] = None
@@ -0,0 +1,33 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ import pydantic
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
7
+
8
+
9
+ class PromptVersionUpdate(UniversalBaseModel):
10
+ """
11
+ Update to apply to prompt versions.
12
+ Note: Prompt versions are immutable by design.
13
+ Only organizational properties (such as tags etc.) can be updated.
14
+ Core properties like template, metadata etc. cannot be modified after creation.
15
+ """
16
+
17
+ tags: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
18
+ """
19
+ Tags to set or merge with existing tags. Follows PATCH semantics:
20
+ - If merge_tags is true, these tags will be added to existing tags.
21
+ - If merge_tags is false, these tags will replace all existing tags.
22
+ - null: preserve existing tags (no change).
23
+ - empty set: clear all tags merge_tags is false.
24
+ """
25
+
26
+ if IS_PYDANTIC_V2:
27
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
28
+ else:
29
+
30
+ class Config:
31
+ frozen = True
32
+ smart_union = True
33
+ extra = pydantic.Extra.allow
@@ -15,7 +15,7 @@ class ProviderApiKey(UniversalBaseModel):
15
15
  name: typing.Optional[str] = None
16
16
  provider_name: typing.Optional[str] = pydantic.Field(default=None)
17
17
  """
18
- Provider name - required for custom LLM providers to uniquely identify them (e.g., 'ollama', 'vllm'). Must not be blank for custom providers. Should not be set for standard providers (OpenAI, Anthropic, etc.). This requirement is conditional and validation is enforced programmatically.
18
+ Provider name - required for custom LLM and Bedrock providers to uniquely identify them (e.g., 'ollama', 'vllm', 'Bedrock us-east-1'). Must not be blank for custom and Bedrock providers. Should not be set for standard providers (OpenAI, Anthropic, etc.). This requirement is conditional and validation is enforced programmatically.
19
19
  """
20
20
 
21
21
  headers: typing.Optional[typing.Dict[str, str]] = None
@@ -25,6 +25,10 @@ class ProviderApiKey(UniversalBaseModel):
25
25
  created_by: typing.Optional[str] = None
26
26
  last_updated_at: typing.Optional[dt.datetime] = None
27
27
  last_updated_by: typing.Optional[str] = None
28
+ read_only: typing.Optional[bool] = pydantic.Field(default=None)
29
+ """
30
+ If true, this provider is system-managed and cannot be edited or deleted
31
+ """
28
32
 
29
33
  if IS_PYDANTIC_V2:
30
34
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -3,5 +3,6 @@
3
3
  import typing
4
4
 
5
5
  ProviderApiKeyProvider = typing.Union[
6
- typing.Literal["openai", "anthropic", "gemini", "openrouter", "vertex-ai", "custom-llm"], typing.Any
6
+ typing.Literal["openai", "anthropic", "gemini", "openrouter", "vertex-ai", "bedrock", "custom-llm", "opik-free"],
7
+ typing.Any,
7
8
  ]
@@ -15,7 +15,7 @@ class ProviderApiKeyPublic(UniversalBaseModel):
15
15
  name: typing.Optional[str] = None
16
16
  provider_name: typing.Optional[str] = pydantic.Field(default=None)
17
17
  """
18
- Provider name - required for custom LLM providers to uniquely identify them (e.g., 'ollama', 'vllm'). Must not be blank for custom providers. Should not be set for standard providers (OpenAI, Anthropic, etc.). This requirement is conditional and validation is enforced programmatically.
18
+ Provider name - required for custom LLM and Bedrock providers to uniquely identify them (e.g., 'ollama', 'vllm', 'Bedrock us-east-1'). Must not be blank for custom and Bedrock providers. Should not be set for standard providers (OpenAI, Anthropic, etc.). This requirement is conditional and validation is enforced programmatically.
19
19
  """
20
20
 
21
21
  headers: typing.Optional[typing.Dict[str, str]] = None
@@ -25,6 +25,10 @@ class ProviderApiKeyPublic(UniversalBaseModel):
25
25
  created_by: typing.Optional[str] = None
26
26
  last_updated_at: typing.Optional[dt.datetime] = None
27
27
  last_updated_by: typing.Optional[str] = None
28
+ read_only: typing.Optional[bool] = pydantic.Field(default=None)
29
+ """
30
+ If true, this provider is system-managed and cannot be edited or deleted
31
+ """
28
32
 
29
33
  if IS_PYDANTIC_V2:
30
34
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -3,5 +3,6 @@
3
3
  import typing
4
4
 
5
5
  ProviderApiKeyPublicProvider = typing.Union[
6
- typing.Literal["openai", "anthropic", "gemini", "openrouter", "vertex-ai", "custom-llm"], typing.Any
6
+ typing.Literal["openai", "anthropic", "gemini", "openrouter", "vertex-ai", "bedrock", "custom-llm", "opik-free"],
7
+ typing.Any,
7
8
  ]
@@ -14,6 +14,9 @@ class ServiceTogglesConfig(UniversalBaseModel):
14
14
  bool, FieldMetadata(alias="traceThreadPythonEvaluatorEnabled")
15
15
  ]
16
16
  span_llm_as_judge_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="spanLlmAsJudgeEnabled")]
17
+ span_user_defined_metric_python_enabled: typing_extensions.Annotated[
18
+ bool, FieldMetadata(alias="spanUserDefinedMetricPythonEnabled")
19
+ ]
17
20
  guardrails_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="guardrailsEnabled")]
18
21
  opik_ai_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="opikAIEnabled")]
19
22
  alerts_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="alertsEnabled")]
@@ -21,8 +24,15 @@ class ServiceTogglesConfig(UniversalBaseModel):
21
24
  csv_upload_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="csvUploadEnabled")]
22
25
  export_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="exportEnabled")]
23
26
  optimization_studio_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="optimizationStudioEnabled")]
24
- dashboards_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="dashboardsEnabled")]
25
27
  dataset_versioning_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="datasetVersioningEnabled")]
28
+ openai_provider_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="openaiProviderEnabled")]
29
+ anthropic_provider_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="anthropicProviderEnabled")]
30
+ gemini_provider_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="geminiProviderEnabled")]
31
+ openrouter_provider_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="openrouterProviderEnabled")]
32
+ vertexai_provider_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="vertexaiProviderEnabled")]
33
+ bedrock_provider_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="bedrockProviderEnabled")]
34
+ customllm_provider_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="customllmProviderEnabled")]
35
+ collaborators_tab_enabled: typing_extensions.Annotated[bool, FieldMetadata(alias="collaboratorsTabEnabled")]
26
36
 
27
37
  if IS_PYDANTIC_V2:
28
38
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -0,0 +1,20 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ import pydantic
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
7
+
8
+
9
+ class SpanUserDefinedMetricPythonCode(UniversalBaseModel):
10
+ metric: str
11
+ arguments: typing.Dict[str, str]
12
+
13
+ if IS_PYDANTIC_V2:
14
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
15
+ else:
16
+
17
+ class Config:
18
+ frozen = True
19
+ smart_union = True
20
+ extra = pydantic.Extra.allow