opik 1.9.5__py3-none-any.whl → 1.9.39__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.
- opik/__init__.py +10 -3
- opik/anonymizer/__init__.py +5 -0
- opik/anonymizer/anonymizer.py +12 -0
- opik/anonymizer/factory.py +80 -0
- opik/anonymizer/recursive_anonymizer.py +64 -0
- opik/anonymizer/rules.py +56 -0
- opik/anonymizer/rules_anonymizer.py +35 -0
- opik/api_objects/dataset/rest_operations.py +5 -0
- opik/api_objects/experiment/experiment.py +46 -49
- opik/api_objects/experiment/helpers.py +34 -10
- opik/api_objects/local_recording.py +8 -3
- opik/api_objects/opik_client.py +230 -48
- opik/api_objects/opik_query_language.py +9 -0
- opik/api_objects/prompt/__init__.py +11 -3
- opik/api_objects/prompt/base_prompt.py +69 -0
- opik/api_objects/prompt/base_prompt_template.py +29 -0
- opik/api_objects/prompt/chat/__init__.py +1 -0
- opik/api_objects/prompt/chat/chat_prompt.py +193 -0
- opik/api_objects/prompt/chat/chat_prompt_template.py +350 -0
- opik/api_objects/prompt/{chat_content_renderer_registry.py → chat/content_renderer_registry.py} +37 -35
- opik/api_objects/prompt/client.py +101 -30
- opik/api_objects/prompt/text/__init__.py +1 -0
- opik/api_objects/prompt/text/prompt.py +174 -0
- opik/api_objects/prompt/{prompt_template.py → text/prompt_template.py} +10 -6
- opik/api_objects/prompt/types.py +1 -1
- opik/cli/export.py +6 -2
- opik/cli/usage_report/charts.py +39 -10
- opik/cli/usage_report/cli.py +164 -45
- opik/cli/usage_report/pdf.py +14 -1
- opik/config.py +0 -5
- opik/decorator/base_track_decorator.py +37 -40
- opik/decorator/context_manager/span_context_manager.py +9 -0
- opik/decorator/context_manager/trace_context_manager.py +5 -0
- opik/dict_utils.py +3 -3
- opik/evaluation/__init__.py +13 -2
- opik/evaluation/engine/engine.py +195 -223
- opik/evaluation/engine/helpers.py +8 -7
- opik/evaluation/engine/metrics_evaluator.py +237 -0
- opik/evaluation/evaluation_result.py +35 -1
- opik/evaluation/evaluator.py +318 -30
- opik/evaluation/models/litellm/util.py +78 -6
- opik/evaluation/models/model_capabilities.py +33 -0
- opik/evaluation/report.py +14 -2
- opik/evaluation/rest_operations.py +36 -33
- opik/evaluation/test_case.py +2 -2
- opik/evaluation/types.py +9 -1
- opik/exceptions.py +17 -0
- opik/hooks/__init__.py +17 -1
- opik/hooks/anonymizer_hook.py +36 -0
- opik/id_helpers.py +18 -0
- opik/integrations/adk/helpers.py +16 -7
- opik/integrations/adk/legacy_opik_tracer.py +7 -4
- opik/integrations/adk/opik_tracer.py +3 -1
- opik/integrations/adk/patchers/adk_otel_tracer/opik_adk_otel_tracer.py +7 -3
- opik/integrations/adk/recursive_callback_injector.py +1 -6
- opik/integrations/dspy/callback.py +1 -4
- opik/integrations/haystack/opik_connector.py +2 -2
- opik/integrations/haystack/opik_tracer.py +2 -4
- opik/integrations/langchain/opik_tracer.py +273 -82
- opik/integrations/llama_index/callback.py +110 -108
- opik/integrations/openai/agents/opik_tracing_processor.py +1 -2
- opik/integrations/openai/opik_tracker.py +1 -1
- opik/message_processing/batching/batchers.py +11 -7
- opik/message_processing/encoder_helpers.py +79 -0
- opik/message_processing/messages.py +25 -1
- opik/message_processing/online_message_processor.py +23 -8
- opik/opik_context.py +7 -7
- opik/rest_api/__init__.py +188 -12
- opik/rest_api/client.py +3 -0
- opik/rest_api/dashboards/__init__.py +4 -0
- opik/rest_api/dashboards/client.py +462 -0
- opik/rest_api/dashboards/raw_client.py +648 -0
- opik/rest_api/datasets/client.py +893 -89
- opik/rest_api/datasets/raw_client.py +1328 -87
- opik/rest_api/experiments/client.py +30 -2
- opik/rest_api/experiments/raw_client.py +26 -0
- opik/rest_api/feedback_definitions/types/find_feedback_definitions_request_type.py +1 -1
- opik/rest_api/optimizations/client.py +302 -0
- opik/rest_api/optimizations/raw_client.py +463 -0
- opik/rest_api/optimizations/types/optimization_update_status.py +3 -1
- opik/rest_api/prompts/__init__.py +2 -2
- opik/rest_api/prompts/client.py +34 -4
- opik/rest_api/prompts/raw_client.py +32 -2
- opik/rest_api/prompts/types/__init__.py +3 -1
- opik/rest_api/prompts/types/create_prompt_version_detail_template_structure.py +5 -0
- opik/rest_api/prompts/types/prompt_write_template_structure.py +5 -0
- opik/rest_api/spans/__init__.py +0 -2
- opik/rest_api/spans/client.py +148 -64
- opik/rest_api/spans/raw_client.py +210 -83
- opik/rest_api/spans/types/__init__.py +0 -2
- opik/rest_api/traces/client.py +241 -73
- opik/rest_api/traces/raw_client.py +344 -90
- opik/rest_api/types/__init__.py +200 -15
- opik/rest_api/types/aggregation_data.py +1 -0
- opik/rest_api/types/alert_trigger_config_public_type.py +6 -1
- opik/rest_api/types/alert_trigger_config_type.py +6 -1
- opik/rest_api/types/alert_trigger_config_write_type.py +6 -1
- opik/rest_api/types/automation_rule_evaluator.py +23 -1
- opik/rest_api/types/automation_rule_evaluator_llm_as_judge.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_llm_as_judge_public.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_llm_as_judge_write.py +2 -0
- opik/rest_api/types/{automation_rule_evaluator_object_public.py → automation_rule_evaluator_object_object_public.py} +32 -10
- opik/rest_api/types/automation_rule_evaluator_page_public.py +2 -2
- opik/rest_api/types/automation_rule_evaluator_public.py +23 -1
- opik/rest_api/types/automation_rule_evaluator_span_llm_as_judge.py +22 -0
- opik/rest_api/types/automation_rule_evaluator_span_llm_as_judge_public.py +22 -0
- opik/rest_api/types/automation_rule_evaluator_span_llm_as_judge_write.py +22 -0
- opik/rest_api/types/automation_rule_evaluator_trace_thread_llm_as_judge.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_trace_thread_llm_as_judge_public.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_trace_thread_llm_as_judge_write.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_trace_thread_user_defined_metric_python.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_trace_thread_user_defined_metric_python_public.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_trace_thread_user_defined_metric_python_write.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_update.py +23 -1
- opik/rest_api/types/automation_rule_evaluator_update_llm_as_judge.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_update_span_llm_as_judge.py +22 -0
- opik/rest_api/types/automation_rule_evaluator_update_trace_thread_llm_as_judge.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_update_trace_thread_user_defined_metric_python.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_update_user_defined_metric_python.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_user_defined_metric_python.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_user_defined_metric_python_public.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_user_defined_metric_python_write.py +2 -0
- opik/rest_api/types/automation_rule_evaluator_write.py +23 -1
- opik/rest_api/types/boolean_feedback_definition.py +25 -0
- opik/rest_api/types/boolean_feedback_definition_create.py +20 -0
- opik/rest_api/types/boolean_feedback_definition_public.py +25 -0
- opik/rest_api/types/boolean_feedback_definition_update.py +20 -0
- opik/rest_api/types/boolean_feedback_detail.py +29 -0
- opik/rest_api/types/boolean_feedback_detail_create.py +29 -0
- opik/rest_api/types/boolean_feedback_detail_public.py +29 -0
- opik/rest_api/types/boolean_feedback_detail_update.py +29 -0
- opik/rest_api/types/dashboard_page_public.py +24 -0
- opik/rest_api/types/dashboard_public.py +30 -0
- opik/rest_api/types/dataset.py +2 -0
- opik/rest_api/types/dataset_item.py +2 -0
- opik/rest_api/types/dataset_item_compare.py +2 -0
- opik/rest_api/types/dataset_item_filter.py +23 -0
- opik/rest_api/types/dataset_item_filter_operator.py +21 -0
- opik/rest_api/types/dataset_item_page_compare.py +1 -0
- opik/rest_api/types/dataset_item_page_public.py +1 -0
- opik/rest_api/types/dataset_item_public.py +2 -0
- opik/rest_api/types/dataset_item_update.py +39 -0
- opik/rest_api/types/dataset_item_write.py +1 -0
- opik/rest_api/types/dataset_public.py +2 -0
- opik/rest_api/types/dataset_public_status.py +5 -0
- opik/rest_api/types/dataset_status.py +5 -0
- opik/rest_api/types/dataset_version_diff.py +22 -0
- opik/rest_api/types/dataset_version_diff_stats.py +24 -0
- opik/rest_api/types/dataset_version_page_public.py +23 -0
- opik/rest_api/types/dataset_version_public.py +49 -0
- opik/rest_api/types/experiment.py +2 -0
- opik/rest_api/types/experiment_public.py +2 -0
- opik/rest_api/types/experiment_score.py +20 -0
- opik/rest_api/types/experiment_score_public.py +20 -0
- opik/rest_api/types/experiment_score_write.py +20 -0
- opik/rest_api/types/feedback.py +20 -1
- opik/rest_api/types/feedback_create.py +16 -1
- opik/rest_api/types/feedback_object_public.py +22 -1
- opik/rest_api/types/feedback_public.py +20 -1
- opik/rest_api/types/feedback_score_public.py +4 -0
- opik/rest_api/types/feedback_update.py +16 -1
- opik/rest_api/types/image_url.py +20 -0
- opik/rest_api/types/image_url_public.py +20 -0
- opik/rest_api/types/image_url_write.py +20 -0
- opik/rest_api/types/llm_as_judge_message.py +5 -1
- opik/rest_api/types/llm_as_judge_message_content.py +24 -0
- opik/rest_api/types/llm_as_judge_message_content_public.py +24 -0
- opik/rest_api/types/llm_as_judge_message_content_write.py +24 -0
- opik/rest_api/types/llm_as_judge_message_public.py +5 -1
- opik/rest_api/types/llm_as_judge_message_write.py +5 -1
- opik/rest_api/types/llm_as_judge_model_parameters.py +2 -0
- opik/rest_api/types/llm_as_judge_model_parameters_public.py +2 -0
- opik/rest_api/types/llm_as_judge_model_parameters_write.py +2 -0
- opik/rest_api/types/optimization.py +2 -0
- opik/rest_api/types/optimization_public.py +2 -0
- opik/rest_api/types/optimization_public_status.py +3 -1
- opik/rest_api/types/optimization_status.py +3 -1
- opik/rest_api/types/optimization_studio_config.py +27 -0
- opik/rest_api/types/optimization_studio_config_public.py +27 -0
- opik/rest_api/types/optimization_studio_config_write.py +27 -0
- opik/rest_api/types/optimization_studio_log.py +22 -0
- opik/rest_api/types/optimization_write.py +2 -0
- opik/rest_api/types/optimization_write_status.py +3 -1
- opik/rest_api/types/prompt.py +6 -0
- opik/rest_api/types/prompt_detail.py +6 -0
- opik/rest_api/types/prompt_detail_template_structure.py +5 -0
- opik/rest_api/types/prompt_public.py +6 -0
- opik/rest_api/types/prompt_public_template_structure.py +5 -0
- opik/rest_api/types/prompt_template_structure.py +5 -0
- opik/rest_api/types/prompt_version.py +2 -0
- opik/rest_api/types/prompt_version_detail.py +2 -0
- opik/rest_api/types/prompt_version_detail_template_structure.py +5 -0
- opik/rest_api/types/prompt_version_public.py +2 -0
- opik/rest_api/types/prompt_version_public_template_structure.py +5 -0
- opik/rest_api/types/prompt_version_template_structure.py +5 -0
- opik/rest_api/types/score_name.py +1 -0
- opik/rest_api/types/service_toggles_config.py +6 -0
- opik/rest_api/types/span_enrichment_options.py +31 -0
- opik/rest_api/types/span_filter.py +23 -0
- opik/rest_api/types/span_filter_operator.py +21 -0
- opik/rest_api/types/span_filter_write.py +23 -0
- opik/rest_api/types/span_filter_write_operator.py +21 -0
- opik/rest_api/types/span_llm_as_judge_code.py +27 -0
- opik/rest_api/types/span_llm_as_judge_code_public.py +27 -0
- opik/rest_api/types/span_llm_as_judge_code_write.py +27 -0
- opik/rest_api/types/span_update.py +46 -0
- opik/rest_api/types/studio_evaluation.py +20 -0
- opik/rest_api/types/studio_evaluation_public.py +20 -0
- opik/rest_api/types/studio_evaluation_write.py +20 -0
- opik/rest_api/types/studio_llm_model.py +21 -0
- opik/rest_api/types/studio_llm_model_public.py +21 -0
- opik/rest_api/types/studio_llm_model_write.py +21 -0
- opik/rest_api/types/studio_message.py +20 -0
- opik/rest_api/types/studio_message_public.py +20 -0
- opik/rest_api/types/studio_message_write.py +20 -0
- opik/rest_api/types/studio_metric.py +21 -0
- opik/rest_api/types/studio_metric_public.py +21 -0
- opik/rest_api/types/studio_metric_write.py +21 -0
- opik/rest_api/types/studio_optimizer.py +21 -0
- opik/rest_api/types/studio_optimizer_public.py +21 -0
- opik/rest_api/types/studio_optimizer_write.py +21 -0
- opik/rest_api/types/studio_prompt.py +20 -0
- opik/rest_api/types/studio_prompt_public.py +20 -0
- opik/rest_api/types/studio_prompt_write.py +20 -0
- opik/rest_api/types/trace.py +6 -0
- opik/rest_api/types/trace_public.py +6 -0
- opik/rest_api/types/trace_thread_filter_write.py +23 -0
- opik/rest_api/types/trace_thread_filter_write_operator.py +21 -0
- opik/rest_api/types/trace_thread_update.py +19 -0
- opik/rest_api/types/trace_update.py +39 -0
- opik/rest_api/types/value_entry.py +2 -0
- opik/rest_api/types/value_entry_compare.py +2 -0
- opik/rest_api/types/value_entry_experiment_item_bulk_write_view.py +2 -0
- opik/rest_api/types/value_entry_public.py +2 -0
- opik/rest_api/types/video_url.py +19 -0
- opik/rest_api/types/video_url_public.py +19 -0
- opik/rest_api/types/video_url_write.py +19 -0
- opik/synchronization.py +5 -6
- opik/{decorator/tracing_runtime_config.py → tracing_runtime_config.py} +6 -7
- {opik-1.9.5.dist-info → opik-1.9.39.dist-info}/METADATA +5 -4
- {opik-1.9.5.dist-info → opik-1.9.39.dist-info}/RECORD +246 -151
- opik/api_objects/prompt/chat_prompt_template.py +0 -164
- opik/api_objects/prompt/prompt.py +0 -131
- /opik/rest_api/{spans/types → types}/span_update_type.py +0 -0
- {opik-1.9.5.dist-info → opik-1.9.39.dist-info}/WHEEL +0 -0
- {opik-1.9.5.dist-info → opik-1.9.39.dist-info}/entry_points.txt +0 -0
- {opik-1.9.5.dist-info → opik-1.9.39.dist-info}/licenses/LICENSE +0 -0
- {opik-1.9.5.dist-info → opik-1.9.39.dist-info}/top_level.txt +0 -0
opik/api_objects/opik_client.py
CHANGED
|
@@ -24,8 +24,8 @@ from .dataset import rest_operations as dataset_rest_operations
|
|
|
24
24
|
from .experiment import experiments_client
|
|
25
25
|
from .experiment import helpers as experiment_helpers
|
|
26
26
|
from .experiment import rest_operations as experiment_rest_operations
|
|
27
|
-
from .
|
|
28
|
-
from .prompt
|
|
27
|
+
from . import prompt as prompt_module
|
|
28
|
+
from .prompt import client as prompt_client
|
|
29
29
|
from .threads import threads_client
|
|
30
30
|
from .trace import migration as trace_migration, trace_client
|
|
31
31
|
from .. import (
|
|
@@ -847,8 +847,13 @@ class Opik:
|
|
|
847
847
|
self._rest_client, dataset_name
|
|
848
848
|
)
|
|
849
849
|
|
|
850
|
+
experiments_client = self.get_experiments_client()
|
|
850
851
|
experiments = dataset_rest_operations.get_dataset_experiments(
|
|
851
|
-
self._rest_client,
|
|
852
|
+
rest_client=self._rest_client,
|
|
853
|
+
dataset_id=dataset_id,
|
|
854
|
+
max_results=max_results,
|
|
855
|
+
streamer=self._streamer,
|
|
856
|
+
experiments_client=experiments_client,
|
|
852
857
|
)
|
|
853
858
|
|
|
854
859
|
return experiments
|
|
@@ -912,8 +917,8 @@ class Opik:
|
|
|
912
917
|
dataset_name: str,
|
|
913
918
|
name: Optional[str] = None,
|
|
914
919
|
experiment_config: Optional[Dict[str, Any]] = None,
|
|
915
|
-
prompt: Optional[
|
|
916
|
-
prompts: Optional[List[
|
|
920
|
+
prompt: Optional[prompt_module.base_prompt.BasePrompt] = None,
|
|
921
|
+
prompts: Optional[List[prompt_module.base_prompt.BasePrompt]] = None,
|
|
917
922
|
type: Literal["regular", "trial", "mini-batch"] = "regular",
|
|
918
923
|
optimization_id: Optional[str] = None,
|
|
919
924
|
) -> experiment.Experiment:
|
|
@@ -961,11 +966,48 @@ class Opik:
|
|
|
961
966
|
dataset_name=dataset_name,
|
|
962
967
|
rest_client=self._rest_client,
|
|
963
968
|
streamer=self._streamer,
|
|
969
|
+
experiments_client=self.get_experiments_client(),
|
|
964
970
|
prompts=checked_prompts,
|
|
965
971
|
)
|
|
966
972
|
|
|
967
973
|
return experiment_
|
|
968
974
|
|
|
975
|
+
def update_experiment(
|
|
976
|
+
self,
|
|
977
|
+
id: str,
|
|
978
|
+
name: Optional[str] = None,
|
|
979
|
+
experiment_config: Optional[Dict[str, Any]] = None,
|
|
980
|
+
) -> None:
|
|
981
|
+
"""
|
|
982
|
+
Update an experiment's name and/or configuration.
|
|
983
|
+
|
|
984
|
+
Args:
|
|
985
|
+
id: The experiment ID.
|
|
986
|
+
name: The new name for the experiment. If None, the name will not be updated.
|
|
987
|
+
experiment_config: The new configuration for the experiment. If None, the configuration will not be updated.
|
|
988
|
+
|
|
989
|
+
Raises:
|
|
990
|
+
ValueError: if id is None or empty, or if both name and experiment_config are None
|
|
991
|
+
"""
|
|
992
|
+
if not id:
|
|
993
|
+
raise ValueError(
|
|
994
|
+
f"id must be provided and can not be None or empty, id: {id}"
|
|
995
|
+
)
|
|
996
|
+
|
|
997
|
+
if name is None and experiment_config is None:
|
|
998
|
+
raise ValueError(
|
|
999
|
+
"At least one of 'name' or 'experiment_config' must be provided"
|
|
1000
|
+
)
|
|
1001
|
+
|
|
1002
|
+
# Only include parameters that are provided to avoid clearing fields
|
|
1003
|
+
request_params: Dict[str, Any] = {}
|
|
1004
|
+
if name is not None:
|
|
1005
|
+
request_params["name"] = name
|
|
1006
|
+
if experiment_config is not None:
|
|
1007
|
+
request_params["metadata"] = experiment_config
|
|
1008
|
+
|
|
1009
|
+
self._rest_client.experiments.update_experiment(id, **request_params)
|
|
1010
|
+
|
|
969
1011
|
def get_experiment_by_name(self, name: str) -> experiment.Experiment:
|
|
970
1012
|
"""
|
|
971
1013
|
Returns an existing experiment by its name.
|
|
@@ -985,18 +1027,20 @@ class Opik:
|
|
|
985
1027
|
|
|
986
1028
|
return experiment.Experiment(
|
|
987
1029
|
id=experiment_public.id,
|
|
988
|
-
name=name,
|
|
1030
|
+
name=experiment_public.name,
|
|
989
1031
|
dataset_name=experiment_public.dataset_name,
|
|
990
1032
|
rest_client=self._rest_client,
|
|
991
1033
|
streamer=self._streamer,
|
|
1034
|
+
experiments_client=self.get_experiments_client(),
|
|
992
1035
|
)
|
|
993
1036
|
|
|
994
1037
|
def get_experiments_by_name(self, name: str) -> List[experiment.Experiment]:
|
|
995
1038
|
"""
|
|
996
|
-
Returns a list of existing experiments
|
|
1039
|
+
Returns a list of existing experiments containing the given string in their name.
|
|
1040
|
+
Search is case-insensitive.
|
|
997
1041
|
|
|
998
1042
|
Args:
|
|
999
|
-
name: The
|
|
1043
|
+
name: The string to search for in the experiment names.
|
|
1000
1044
|
|
|
1001
1045
|
Returns:
|
|
1002
1046
|
List[experiment.Experiment]: List of existing experiments.
|
|
@@ -1009,10 +1053,11 @@ class Opik:
|
|
|
1009
1053
|
for public_experiment in experiments_public:
|
|
1010
1054
|
experiment_ = experiment.Experiment(
|
|
1011
1055
|
id=public_experiment.id,
|
|
1012
|
-
name=name,
|
|
1056
|
+
name=public_experiment.name,
|
|
1013
1057
|
dataset_name=public_experiment.dataset_name,
|
|
1014
1058
|
rest_client=self._rest_client,
|
|
1015
1059
|
streamer=self._streamer,
|
|
1060
|
+
experiments_client=self.get_experiments_client(),
|
|
1016
1061
|
)
|
|
1017
1062
|
result.append(experiment_)
|
|
1018
1063
|
|
|
@@ -1045,6 +1090,7 @@ class Opik:
|
|
|
1045
1090
|
dataset_name=experiment_public.dataset_name,
|
|
1046
1091
|
rest_client=self._rest_client,
|
|
1047
1092
|
streamer=self._streamer,
|
|
1093
|
+
experiments_client=self.get_experiments_client(),
|
|
1048
1094
|
)
|
|
1049
1095
|
|
|
1050
1096
|
def end(self, timeout: Optional[int] = None) -> None:
|
|
@@ -1348,70 +1394,188 @@ class Opik:
|
|
|
1348
1394
|
name: str,
|
|
1349
1395
|
prompt: str,
|
|
1350
1396
|
metadata: Optional[Dict[str, Any]] = None,
|
|
1351
|
-
type: PromptType = PromptType.MUSTACHE,
|
|
1352
|
-
) -> Prompt:
|
|
1397
|
+
type: prompt_module.PromptType = prompt_module.PromptType.MUSTACHE,
|
|
1398
|
+
) -> prompt_module.Prompt:
|
|
1353
1399
|
"""
|
|
1354
|
-
Creates a new prompt with the given name and template.
|
|
1355
|
-
If a prompt with the same name already exists, it will create a new version of the existing prompt if the templates differ.
|
|
1400
|
+
Creates a new text prompt with the given name and template.
|
|
1401
|
+
If a text prompt with the same name already exists, it will create a new version of the existing prompt if the templates differ.
|
|
1356
1402
|
|
|
1357
1403
|
Parameters:
|
|
1358
1404
|
name: The name of the prompt.
|
|
1359
1405
|
prompt: The template content of the prompt.
|
|
1360
1406
|
metadata: Optional metadata to be included in the prompt.
|
|
1407
|
+
type: The template type (MUSTACHE or JINJA2).
|
|
1361
1408
|
|
|
1362
1409
|
Returns:
|
|
1363
1410
|
A Prompt object containing details of the created or retrieved prompt.
|
|
1364
1411
|
|
|
1365
1412
|
Raises:
|
|
1366
|
-
|
|
1413
|
+
PromptTemplateStructureMismatch: If a chat prompt with the same name already exists (template structure is immutable).
|
|
1414
|
+
ApiError: If there is an error during the creation of the prompt.
|
|
1367
1415
|
"""
|
|
1368
|
-
|
|
1369
|
-
prompt_version =
|
|
1416
|
+
prompt_client_ = prompt_client.PromptClient(self._rest_client)
|
|
1417
|
+
prompt_version = prompt_client_.create_prompt(
|
|
1370
1418
|
name=name, prompt=prompt, metadata=metadata, type=type
|
|
1371
1419
|
)
|
|
1372
|
-
return Prompt.from_fern_prompt_version(name, prompt_version)
|
|
1420
|
+
return prompt_module.Prompt.from_fern_prompt_version(name, prompt_version)
|
|
1421
|
+
|
|
1422
|
+
def create_chat_prompt(
|
|
1423
|
+
self,
|
|
1424
|
+
name: str,
|
|
1425
|
+
messages: List[Dict[str, Any]],
|
|
1426
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
1427
|
+
type: prompt_module.PromptType = prompt_module.PromptType.MUSTACHE,
|
|
1428
|
+
) -> prompt_module.ChatPrompt:
|
|
1429
|
+
"""
|
|
1430
|
+
Creates a new chat prompt with the given name and message templates.
|
|
1431
|
+
If a chat prompt with the same name already exists, it will create a new version if the messages differ.
|
|
1432
|
+
|
|
1433
|
+
Parameters:
|
|
1434
|
+
name: The name of the chat prompt.
|
|
1435
|
+
messages: List of message dictionaries with 'role' and 'content' fields.
|
|
1436
|
+
metadata: Optional metadata to be included in the prompt.
|
|
1437
|
+
type: The template type (MUSTACHE or JINJA2).
|
|
1438
|
+
|
|
1439
|
+
Returns:
|
|
1440
|
+
A ChatPrompt object containing details of the created or retrieved chat prompt.
|
|
1441
|
+
|
|
1442
|
+
Raises:
|
|
1443
|
+
PromptTemplateStructureMismatch: If a text prompt with the same name already exists (template structure is immutable).
|
|
1444
|
+
ApiError: If there is an error during the creation of the prompt.
|
|
1445
|
+
"""
|
|
1446
|
+
return prompt_module.ChatPrompt(
|
|
1447
|
+
name=name, messages=messages, metadata=metadata, type=type
|
|
1448
|
+
)
|
|
1373
1449
|
|
|
1374
1450
|
def get_prompt(
|
|
1375
1451
|
self,
|
|
1376
1452
|
name: str,
|
|
1377
1453
|
commit: Optional[str] = None,
|
|
1378
|
-
) -> Optional[Prompt]:
|
|
1454
|
+
) -> Optional[prompt_module.Prompt]:
|
|
1379
1455
|
"""
|
|
1380
|
-
Retrieve
|
|
1456
|
+
Retrieve a text prompt by name and optional commit version.
|
|
1457
|
+
|
|
1458
|
+
This method only returns text prompts.
|
|
1381
1459
|
|
|
1382
1460
|
Parameters:
|
|
1383
1461
|
name: The name of the prompt.
|
|
1384
1462
|
commit: An optional commit version of the prompt. If not provided, the latest version is retrieved.
|
|
1385
1463
|
|
|
1386
1464
|
Returns:
|
|
1387
|
-
Prompt: The details of the specified prompt.
|
|
1465
|
+
Prompt: The details of the specified text prompt, or None if not found.
|
|
1466
|
+
|
|
1467
|
+
Raises:
|
|
1468
|
+
PromptTemplateStructureMismatch: If the prompt exists but is a chat prompt (template structure mismatch).
|
|
1388
1469
|
"""
|
|
1389
|
-
|
|
1390
|
-
fern_prompt_version =
|
|
1470
|
+
prompt_client_ = prompt_client.PromptClient(self._rest_client)
|
|
1471
|
+
fern_prompt_version = prompt_client_.get_prompt(
|
|
1472
|
+
name=name, commit=commit, raise_if_not_template_structure="text"
|
|
1473
|
+
)
|
|
1474
|
+
|
|
1391
1475
|
if fern_prompt_version is None:
|
|
1392
1476
|
return None
|
|
1393
1477
|
|
|
1394
|
-
return Prompt.from_fern_prompt_version(name, fern_prompt_version)
|
|
1478
|
+
return prompt_module.Prompt.from_fern_prompt_version(name, fern_prompt_version)
|
|
1395
1479
|
|
|
1396
|
-
def
|
|
1480
|
+
def get_chat_prompt(
|
|
1481
|
+
self,
|
|
1482
|
+
name: str,
|
|
1483
|
+
commit: Optional[str] = None,
|
|
1484
|
+
) -> Optional[prompt_module.ChatPrompt]:
|
|
1397
1485
|
"""
|
|
1398
|
-
Retrieve
|
|
1486
|
+
Retrieve a chat prompt by name and optional commit version.
|
|
1487
|
+
|
|
1488
|
+
This method only returns chat prompts.
|
|
1399
1489
|
|
|
1400
1490
|
Parameters:
|
|
1401
1491
|
name: The name of the prompt.
|
|
1492
|
+
commit: An optional commit version of the prompt. If not provided, the latest version is retrieved.
|
|
1402
1493
|
|
|
1403
1494
|
Returns:
|
|
1404
|
-
|
|
1495
|
+
ChatPrompt: The details of the specified chat prompt, or None if not found.
|
|
1496
|
+
|
|
1497
|
+
Raises:
|
|
1498
|
+
PromptTemplateStructureMismatch: If the prompt exists but is a text prompt (template structure mismatch).
|
|
1405
1499
|
"""
|
|
1406
|
-
|
|
1407
|
-
|
|
1500
|
+
prompt_client_ = prompt_client.PromptClient(self._rest_client)
|
|
1501
|
+
fern_prompt_version = prompt_client_.get_prompt(
|
|
1502
|
+
name=name, commit=commit, raise_if_not_template_structure="chat"
|
|
1503
|
+
)
|
|
1504
|
+
|
|
1505
|
+
if fern_prompt_version is None:
|
|
1506
|
+
return None
|
|
1507
|
+
|
|
1508
|
+
return prompt_module.ChatPrompt.from_fern_prompt_version(
|
|
1509
|
+
name, fern_prompt_version
|
|
1510
|
+
)
|
|
1511
|
+
|
|
1512
|
+
def get_prompt_history(self, name: str) -> List[prompt_module.Prompt]:
|
|
1513
|
+
"""
|
|
1514
|
+
Retrieve all text prompt versions history for a given prompt name.
|
|
1515
|
+
|
|
1516
|
+
Parameters:
|
|
1517
|
+
name: The name of the prompt.
|
|
1518
|
+
|
|
1519
|
+
Returns:
|
|
1520
|
+
List[Prompt]: A list of text Prompt instances for the given name, or an empty list if not found.
|
|
1521
|
+
|
|
1522
|
+
Raises:
|
|
1523
|
+
PromptTemplateStructureMismatch: If the prompt exists but is a chat prompt (template structure mismatch).
|
|
1524
|
+
"""
|
|
1525
|
+
prompt_client_ = prompt_client.PromptClient(self._rest_client)
|
|
1526
|
+
|
|
1527
|
+
# First, validate that this is a text prompt by trying to get the latest version
|
|
1528
|
+
# Let PromptTemplateStructureMismatch exception propagate - this is a hard error
|
|
1529
|
+
latest_version = prompt_client_.get_prompt(
|
|
1530
|
+
name=name, raise_if_not_template_structure="text"
|
|
1531
|
+
)
|
|
1532
|
+
|
|
1533
|
+
if latest_version is None:
|
|
1534
|
+
return []
|
|
1535
|
+
|
|
1536
|
+
# Now get all versions (we know it's a text prompt)
|
|
1537
|
+
fern_prompt_versions = prompt_client_.get_all_prompt_versions(name=name)
|
|
1538
|
+
|
|
1408
1539
|
result = [
|
|
1409
|
-
Prompt.from_fern_prompt_version(name, version)
|
|
1540
|
+
prompt_module.Prompt.from_fern_prompt_version(name, version)
|
|
1410
1541
|
for version in fern_prompt_versions
|
|
1411
1542
|
]
|
|
1412
1543
|
return result
|
|
1413
1544
|
|
|
1414
|
-
def
|
|
1545
|
+
def get_chat_prompt_history(self, name: str) -> List[prompt_module.ChatPrompt]:
|
|
1546
|
+
"""
|
|
1547
|
+
Retrieve all chat prompt versions history for a given prompt name.
|
|
1548
|
+
|
|
1549
|
+
Parameters:
|
|
1550
|
+
name: The name of the prompt.
|
|
1551
|
+
|
|
1552
|
+
Returns:
|
|
1553
|
+
List[ChatPrompt]: A list of ChatPrompt instances for the given name, or an empty list if not found.
|
|
1554
|
+
|
|
1555
|
+
Raises:
|
|
1556
|
+
PromptTemplateStructureMismatch: If the prompt exists but is a text prompt (template structure mismatch).
|
|
1557
|
+
"""
|
|
1558
|
+
prompt_client_ = prompt_client.PromptClient(self._rest_client)
|
|
1559
|
+
|
|
1560
|
+
# First, validate that this is a chat prompt by trying to get the latest version
|
|
1561
|
+
# Let PromptTemplateStructureMismatch exception propagate - this is a hard error
|
|
1562
|
+
latest_version = prompt_client_.get_prompt(
|
|
1563
|
+
name=name, raise_if_not_template_structure="chat"
|
|
1564
|
+
)
|
|
1565
|
+
|
|
1566
|
+
if latest_version is None:
|
|
1567
|
+
return []
|
|
1568
|
+
|
|
1569
|
+
# Now get all versions (we know it's a chat prompt)
|
|
1570
|
+
fern_prompt_versions = prompt_client_.get_all_prompt_versions(name=name)
|
|
1571
|
+
|
|
1572
|
+
result = [
|
|
1573
|
+
prompt_module.ChatPrompt.from_fern_prompt_version(name, version)
|
|
1574
|
+
for version in fern_prompt_versions
|
|
1575
|
+
]
|
|
1576
|
+
return result
|
|
1577
|
+
|
|
1578
|
+
def get_all_prompts(self, name: str) -> List[prompt_module.Prompt]:
|
|
1415
1579
|
"""
|
|
1416
1580
|
DEPRECATED: Please use Opik.get_prompt_history() instead.
|
|
1417
1581
|
Retrieve all the prompt versions history for a given prompt name.
|
|
@@ -1420,16 +1584,18 @@ class Opik:
|
|
|
1420
1584
|
name: The name of the prompt.
|
|
1421
1585
|
|
|
1422
1586
|
Returns:
|
|
1423
|
-
List[Prompt]: A list of Prompt instances for the given name.
|
|
1587
|
+
List[prompt_module.Prompt]: A list of Prompt instances for the given name.
|
|
1424
1588
|
"""
|
|
1425
1589
|
LOGGER.warning(
|
|
1426
1590
|
"Opik.get_all_prompts() is deprecated. Please use Opik.get_prompt_history() instead."
|
|
1427
1591
|
)
|
|
1428
1592
|
return self.get_prompt_history(name)
|
|
1429
1593
|
|
|
1430
|
-
def search_prompts(
|
|
1594
|
+
def search_prompts(
|
|
1595
|
+
self, filter_string: Optional[str] = None
|
|
1596
|
+
) -> List[Union[prompt_module.Prompt, prompt_module.ChatPrompt]]:
|
|
1431
1597
|
"""
|
|
1432
|
-
Retrieve the latest prompt versions for the given search parameters.
|
|
1598
|
+
Retrieve the latest prompt versions (both string and chat prompts) for the given search parameters.
|
|
1433
1599
|
|
|
1434
1600
|
Parameters:
|
|
1435
1601
|
filter_string: A filter string to narrow down the search using Opik Query Language (OQL).
|
|
@@ -1439,11 +1605,13 @@ class Opik:
|
|
|
1439
1605
|
- `id`, `name`: String fields
|
|
1440
1606
|
- `tags`: List field (use "contains" operator only)
|
|
1441
1607
|
- `created_by`: String field
|
|
1608
|
+
- `template_structure`: String field ("string" or "chat")
|
|
1442
1609
|
|
|
1443
1610
|
Supported operators by column:
|
|
1444
1611
|
- `id`: =, !=, contains, not_contains, starts_with, ends_with, >, <
|
|
1445
1612
|
- `name`: =, !=, contains, not_contains, starts_with, ends_with, >, <
|
|
1446
1613
|
- `created_by`: =, !=, contains, not_contains, starts_with, ends_with, >, <
|
|
1614
|
+
- `template_structure`: =, !=
|
|
1447
1615
|
- `tags`: contains (only)
|
|
1448
1616
|
|
|
1449
1617
|
Examples:
|
|
@@ -1452,23 +1620,36 @@ class Opik:
|
|
|
1452
1620
|
- `name contains "summary"` - Filter by name substring
|
|
1453
1621
|
- `created_by = "user@example.com"` - Filter by creator
|
|
1454
1622
|
- `id starts_with "prompt_"` - Filter by ID prefix
|
|
1623
|
+
- `template_structure = "text"` - Only text prompts
|
|
1624
|
+
- `template_structure = "chat"` - Only chat prompts
|
|
1455
1625
|
|
|
1456
|
-
If not provided, all prompts
|
|
1626
|
+
If not provided, all prompts (both text and chat) will be returned.
|
|
1457
1627
|
|
|
1458
1628
|
Returns:
|
|
1459
|
-
List[Prompt]: A list of Prompt instances found.
|
|
1460
|
-
"""
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
prompts: List[Prompt] = [
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1629
|
+
List[Union[Prompt, ChatPrompt]]: A list of Prompt and/or ChatPrompt instances found.
|
|
1630
|
+
"""
|
|
1631
|
+
oql = opik_query_language.OpikQueryLanguage(filter_string or "")
|
|
1632
|
+
parsed_filters = oql.get_filter_expressions()
|
|
1633
|
+
|
|
1634
|
+
prompt_client_ = prompt_client.PromptClient(self._rest_client)
|
|
1635
|
+
search_results = prompt_client_.search_prompts(parsed_filters=parsed_filters)
|
|
1636
|
+
|
|
1637
|
+
# Convert to Prompt or ChatPrompt objects based on template_structure
|
|
1638
|
+
prompts: List[Union[prompt_module.Prompt, prompt_module.ChatPrompt]] = []
|
|
1639
|
+
for result in search_results:
|
|
1640
|
+
if result.template_structure == "chat":
|
|
1641
|
+
prompts.append(
|
|
1642
|
+
prompt_module.ChatPrompt.from_fern_prompt_version(
|
|
1643
|
+
result.name, result.prompt_version_detail
|
|
1644
|
+
)
|
|
1645
|
+
)
|
|
1646
|
+
else:
|
|
1647
|
+
prompts.append(
|
|
1648
|
+
prompt_module.Prompt.from_fern_prompt_version(
|
|
1649
|
+
result.name, result.prompt_version_detail
|
|
1650
|
+
)
|
|
1651
|
+
)
|
|
1652
|
+
|
|
1472
1653
|
return prompts
|
|
1473
1654
|
|
|
1474
1655
|
def create_optimization(
|
|
@@ -1477,8 +1658,9 @@ class Opik:
|
|
|
1477
1658
|
objective_name: str,
|
|
1478
1659
|
name: Optional[str] = None,
|
|
1479
1660
|
metadata: Optional[Dict[str, Any]] = None,
|
|
1661
|
+
optimization_id: Optional[str] = None,
|
|
1480
1662
|
) -> optimization.Optimization:
|
|
1481
|
-
id = id_helpers.generate_id()
|
|
1663
|
+
id = optimization_id or id_helpers.generate_id()
|
|
1482
1664
|
|
|
1483
1665
|
self._rest_client.optimizations.create_optimization(
|
|
1484
1666
|
id=id,
|
|
@@ -29,6 +29,7 @@ COLUMNS = {
|
|
|
29
29
|
"type": "string",
|
|
30
30
|
"model": "string",
|
|
31
31
|
"provider": "string",
|
|
32
|
+
"template_structure": "string",
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
SUPPORTED_OPERATORS = {
|
|
@@ -121,6 +122,14 @@ SUPPORTED_OPERATORS = {
|
|
|
121
122
|
">",
|
|
122
123
|
"<",
|
|
123
124
|
],
|
|
125
|
+
"template_structure": [
|
|
126
|
+
"=",
|
|
127
|
+
"contains",
|
|
128
|
+
"not_contains",
|
|
129
|
+
"starts_with",
|
|
130
|
+
"ends_with",
|
|
131
|
+
"!=",
|
|
132
|
+
],
|
|
124
133
|
}
|
|
125
134
|
|
|
126
135
|
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
from .prompt import Prompt
|
|
1
|
+
from .text.prompt import Prompt
|
|
2
|
+
from .text.prompt_template import PromptTemplate
|
|
3
|
+
from .chat.chat_prompt import ChatPrompt
|
|
4
|
+
from .chat.chat_prompt_template import ChatPromptTemplate
|
|
2
5
|
from .types import PromptType
|
|
3
|
-
from .
|
|
6
|
+
from .base_prompt import BasePrompt
|
|
7
|
+
from .base_prompt_template import BasePromptTemplate
|
|
4
8
|
|
|
5
9
|
__all__ = [
|
|
6
|
-
"Prompt",
|
|
7
10
|
"PromptType",
|
|
11
|
+
"Prompt",
|
|
12
|
+
"ChatPrompt",
|
|
13
|
+
"PromptTemplate",
|
|
8
14
|
"ChatPromptTemplate",
|
|
15
|
+
"BasePrompt",
|
|
16
|
+
"BasePromptTemplate",
|
|
9
17
|
]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base class for prompts.
|
|
3
|
+
|
|
4
|
+
Defines abstract interface that both string and chat prompt variants must implement.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
|
+
|
|
10
|
+
from . import types as prompt_types
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BasePrompt(ABC):
|
|
14
|
+
"""
|
|
15
|
+
Abstract base class for prompts (string and chat).
|
|
16
|
+
|
|
17
|
+
All prompt implementations must provide common properties and methods
|
|
18
|
+
for interacting with the backend API.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def name(self) -> str:
|
|
24
|
+
"""The name of the prompt."""
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def commit(self) -> Optional[str]:
|
|
30
|
+
"""The commit hash of the prompt version."""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def metadata(self) -> Optional[Dict[str, Any]]:
|
|
36
|
+
"""The metadata dictionary associated with the prompt."""
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def type(self) -> prompt_types.PromptType:
|
|
42
|
+
"""The prompt type (MUSTACHE or JINJA2)."""
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
# Internal API fields for backend synchronization
|
|
46
|
+
__internal_api__prompt_id__: str
|
|
47
|
+
__internal_api__version_id__: str
|
|
48
|
+
|
|
49
|
+
@abstractmethod
|
|
50
|
+
def format(self, *args: Any, **kwargs: Any) -> Any:
|
|
51
|
+
"""
|
|
52
|
+
Format the prompt with the provided variables.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Formatted output. Type depends on the implementation:
|
|
56
|
+
- Prompt returns str
|
|
57
|
+
- ChatPrompt returns List[Dict[str, MessageContent]]
|
|
58
|
+
"""
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
@abstractmethod
|
|
62
|
+
def __internal_api__to_info_dict__(self) -> Dict[str, Any]:
|
|
63
|
+
"""
|
|
64
|
+
Convert the prompt to an info dictionary for serialization.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Dictionary containing prompt metadata and version information.
|
|
68
|
+
"""
|
|
69
|
+
pass
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base class for prompt templates.
|
|
3
|
+
|
|
4
|
+
Defines abstract interface that both string and chat template variants must implement.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BasePromptTemplate(ABC):
|
|
12
|
+
"""
|
|
13
|
+
Abstract base class for prompt templates (string and chat).
|
|
14
|
+
|
|
15
|
+
All prompt template implementations must provide a format method
|
|
16
|
+
that takes variables and returns formatted output.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def format(self, *args: Any, **kwargs: Any) -> Any:
|
|
21
|
+
"""
|
|
22
|
+
Format the template with the provided variables.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Formatted output. Type depends on the implementation:
|
|
26
|
+
- PromptTemplate returns str
|
|
27
|
+
- ChatPromptTemplate returns List[Dict[str, MessageContent]]
|
|
28
|
+
"""
|
|
29
|
+
pass
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Empty - all exports handled by parent __init__.py
|