Files
wehub-resource-sync 5a558eb09e
TypeScript SDK Compatibility V1.x E2E Tests / Select Node version matrix (push) Has been cancelled
TypeScript SDK Compatibility V1.x E2E Tests / TypeScript SDK Compatibility V1.x E2E Tests Node ${{matrix.node_version}} (push) Has been cancelled
TypeScript SDK E2E Tests / TypeScript SDK E2E Tests Node ${{matrix.node_version}} (push) Has been cancelled
Opik Optimizer - E2E Tests / build-opik (push) Has been cancelled
TypeScript SDK Compatibility V1.x E2E Tests / build-opik (push) Has been cancelled
Python SDK E2E Tests / Select Python version matrix (push) Has been cancelled
Python SDK E2E Tests / Python SDK E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Python SDK E2E Tests / build-opik (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / Select Python version matrix (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / Python SDK Compatibility V1.x E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / build-opik (push) Has been cancelled
TypeScript SDK E2E Tests / Select Node version matrix (push) Has been cancelled
TypeScript SDK E2E Tests / build-opik (push) Has been cancelled
Opik Optimizer - E2E Tests / Opik Optimizer E2E Tests Python ${{matrix.python_version}} (push) Has been cancelled
Opik Optimizer - E2E Tests / Opik Optimizer Integration Smoke Tests (push) Has been cancelled
🐙 Code Quality / detect (push) Has been cancelled
🐙 Code Quality / lint (${{ matrix.leg.name }}) (push) Has been cancelled
🐙 Code Quality / summary (push) Has been cancelled
TypeScript SDK Library Integration Tests / Check Secrets (push) Has been cancelled
TypeScript SDK Library Integration Tests / opik-vercel (Vercel AI SDK / eve) (push) Has been cancelled
SDK Library Integration Tests Runner / Check Secrets (push) Has been cancelled
SDK Library Integration Tests Runner / Missed OpenAI API Key Warning (push) Has been cancelled
SDK Library Integration Tests Runner / Build (push) Has been cancelled
SDK Library Integration Tests Runner / openai_tests (push) Has been cancelled
SDK Library Integration Tests Runner / langchain_tests (push) Has been cancelled
SDK Library Integration Tests Runner / langchain_legacy_tests (push) Has been cancelled
SDK Library Integration Tests Runner / llama_index_tests (push) Has been cancelled
SDK Library Integration Tests Runner / anthropic_tests (push) Has been cancelled
SDK Library Integration Tests Runner / mistral_tests (push) Has been cancelled
SDK Library Integration Tests Runner / groq_tests (push) Has been cancelled
SDK Library Integration Tests Runner / aisuite_tests (push) Has been cancelled
SDK Library Integration Tests Runner / haystack_tests (push) Has been cancelled
SDK Library Integration Tests Runner / dspy_tests (push) Has been cancelled
SDK Library Integration Tests Runner / crewai_v0_tests (push) Has been cancelled
SDK Library Integration Tests Runner / crewai_v1_tests (push) Has been cancelled
SDK Library Integration Tests Runner / genai_tests (push) Has been cancelled
SDK Library Integration Tests Runner / adk_tests (push) Has been cancelled
SDK Library Integration Tests Runner / adk_legacy_1_3_0_tests (push) Has been cancelled
SDK Library Integration Tests Runner / evaluation_metrics_tests (push) Has been cancelled
SDK Library Integration Tests Runner / bedrock_tests (push) Has been cancelled
SDK Library Integration Tests Runner / litellm_tests (push) Has been cancelled
SDK Library Integration Tests Runner / harbor_tests (push) Has been cancelled
SDK Library Integration Tests Runner / Slack Notification (push) Has been cancelled
Lint Opik Helm Chart / render-equality (push) Has been cancelled
Opik Optimizer - Unit Tests / Opik Optimizer Unit Tests Python ${{matrix.python_version}} (push) Has been cancelled
Python BE E2E Tests / Python BE E2E (push) Has been cancelled
Python Backend Tests / run-python-backend-tests (push) Has been cancelled
Python SDK Unit Tests / Python SDK Unit Tests ${{matrix.python_version}} (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
SDK E2E Libraries Integration Tests / Check Secrets (push) Has been cancelled
SDK E2E Libraries Integration Tests / Missed OpenAI API Key Warning (push) Has been cancelled
SDK E2E Libraries Integration Tests / build-opik (push) Has been cancelled
SDK E2E Libraries Integration Tests / E2E Lib Integration Python ${{matrix.python_version}} (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-gemini) (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-langchain) (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-openai) (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-otel) (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-vercel) (push) Has been cancelled
TypeScript SDK Build & Publish / build-and-publish (push) Has been cancelled
TypeScript SDK Unit Tests / Test on Node ${{ matrix.node-version }} (push) Has been cancelled
Backend Tests / discover-tests (push) Has been cancelled
Backend Tests / ${{ matrix.name }} (push) Has been cancelled
Build and Publish SDK / build-and-publish (push) Has been cancelled
Build Opik Docker Images / set-version (push) Has been cancelled
Build Opik Docker Images / build-backend (push) Has been cancelled
Build Opik Docker Images / build-sandbox-executor-python (push) Has been cancelled
Build Opik Docker Images / build-python-backend (push) Has been cancelled
Build Opik Docker Images / build-frontend (push) Has been cancelled
Build Opik Docker Images / create-git-tag (push) Has been cancelled
ClickHouse Migration Cluster Check / validate-clickhouse-migrations (push) Has been cancelled
Docs - Publish / run (push) Has been cancelled
E2E Tests - Post Merge (v2) / 🧪 E2E v2 Tests (${{ github.event.inputs.tier || 't1' }}) (push) Has been cancelled
E2E Tests - Post Merge (v2) / 📢 Slack Notification (push) Has been cancelled
Frontend Unit Tests / Test on Node 20 (push) Has been cancelled
Guardrails E2E Tests / Select Python version matrix (push) Has been cancelled
Guardrails E2E Tests / Guardrails E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Guardrails E2E Tests / 📢 Slack Notification (push) Has been cancelled
Guardrails Backend Unit Tests / Guardrails Backend Unit Tests (push) Has been cancelled
Guardrails Backend Unit Tests / 📢 Slack Notification (push) Has been cancelled
Lint Opik Helm Chart / lint-helm-chart (Helm v3.21.0) (push) Has been cancelled
Lint Opik Helm Chart / lint-helm-chart (Helm v4.2.0) (push) Has been cancelled
Lint Opik Helm Chart / unittest-helm-chart (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:25:44 +08:00

1162 lines
38 KiB
Python

import json
import uuid
import pytest
import opik
from opik.api_objects.prompt import PromptType
from .. import verifiers
def _generate_random_suffix():
return str(uuid.uuid4())[-6:]
def _generate_random_prompt_name():
return f"some-prompt-name-{_generate_random_suffix()}"
def _generate_random_tag():
return f"tag-{_generate_random_suffix()}"
def _generate_random_tags(n=2):
return [_generate_random_tag() for _ in range(n)]
def test_prompt__create__happyflow(opik_client: opik.Opik):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"some-prompt-name-{unique_identifier}"
prompt_template = f"some-prompt-text-{unique_identifier}"
prompt = opik_client.create_prompt(
name=prompt_name,
prompt=prompt_template,
metadata={"outer-key": {"inner-key": "inner-value"}},
)
verifiers.verify_prompt_version(
prompt,
name=prompt_name,
template=prompt_template,
type=PromptType.MUSTACHE,
metadata={"outer-key": {"inner-key": "inner-value"}},
version_id=prompt.__internal_api__version_id__,
prompt_id=prompt.__internal_api__prompt_id__,
commit=prompt.commit,
)
def test_prompt__create_new_version__happyflow(opik_client: opik.Opik):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"some-prompt-name-{unique_identifier}"
prompt_template = f"some-prompt-text-{unique_identifier}"
# create initial version
prompt = opik_client.create_prompt(
name=prompt_name,
prompt=prompt_template,
)
unique_identifier_new = str(uuid.uuid4())[-6:]
prompt_template_new = f"some-prompt-text-{unique_identifier_new}"
# must create new version
new_prompt = opik_client.create_prompt(
name=prompt_name,
prompt=prompt_template_new,
)
verifiers.verify_prompt_version(
new_prompt,
name=prompt.name,
template=prompt_template_new,
)
assert new_prompt.__internal_api__prompt_id__ == prompt.__internal_api__prompt_id__
assert (
new_prompt.__internal_api__version_id__ != prompt.__internal_api__version_id__
)
assert new_prompt.commit != prompt.commit
assert new_prompt.prompt != prompt.prompt
def test_prompt__do_not_create_new_version_with_the_same_template(
opik_client: opik.Opik,
):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"some-prompt-name-{unique_identifier}"
prompt_template = f"some-prompt-text-{unique_identifier}"
# create initial version
prompt = opik_client.create_prompt(
name=prompt_name,
prompt=prompt_template,
)
# must NOT create new version
new_prompt = opik_client.create_prompt(
name=prompt_name,
prompt=prompt_template,
)
verifiers.verify_prompt_version(
new_prompt,
name=prompt.name,
template=prompt.prompt,
)
assert new_prompt.__internal_api__prompt_id__ == prompt.__internal_api__prompt_id__
assert (
new_prompt.__internal_api__version_id__ == prompt.__internal_api__version_id__
)
assert new_prompt.commit == prompt.commit
assert new_prompt.prompt == prompt.prompt
def test_prompt__get_by_name__happyflow(opik_client: opik.Opik):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"some-prompt-name-{unique_identifier}"
prompt_template = f"some-prompt-text-{unique_identifier}"
original_prompt_version = opik_client.create_prompt(
name=prompt_name,
prompt=prompt_template,
)
unique_identifier_new = str(uuid.uuid4())[-6:]
prompt_template_new = f"some-prompt-text-{unique_identifier_new}"
new_prompt_version = opik_client.create_prompt(
name=prompt_name,
prompt=prompt_template_new,
)
new_prompt_version_from_api = opik_client.get_prompt(
name=original_prompt_version.name
)
assert (
new_prompt_version_from_api.__internal_api__prompt_id__
== new_prompt_version.__internal_api__prompt_id__
)
assert (
new_prompt_version_from_api.__internal_api__version_id__
== new_prompt_version.__internal_api__version_id__
)
assert new_prompt_version_from_api.commit == new_prompt_version.commit
assert new_prompt_version_from_api.prompt == new_prompt_version.prompt
previous_prompt_from_api = opik_client.get_prompt(
name=original_prompt_version.name, commit=original_prompt_version.commit
)
assert (
previous_prompt_from_api.__internal_api__prompt_id__
== original_prompt_version.__internal_api__prompt_id__
)
assert (
previous_prompt_from_api.__internal_api__version_id__
== original_prompt_version.__internal_api__version_id__
)
assert previous_prompt_from_api.commit == original_prompt_version.commit
assert previous_prompt_from_api.prompt == original_prompt_version.prompt
def test_prompt__get__not_exists(opik_client: opik.Opik):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"some-prompt-name-{unique_identifier}"
prompt = opik_client.get_prompt(prompt_name)
assert prompt is None
def test_prompt__initialize_class_instance(opik_client: opik.Opik):
unique_identifier = str(uuid.uuid4())[-6:]
template = "Hello, {name} from {place}! Nice to meet you, {name}."
prompt = opik.Prompt(name=f"test-{unique_identifier}", prompt=template)
prompt_from_api = opik_client.get_prompt(name=prompt.name)
verifiers.verify_prompt_version(
prompt_from_api,
name=prompt.name,
template=prompt.prompt,
version_id=prompt.__internal_api__version_id__,
prompt_id=prompt.__internal_api__prompt_id__,
commit=prompt.commit,
)
def test_prompt__format():
unique_identifier = str(uuid.uuid4())[-6:]
template = "Hello, {{name}} from {{place}}! Nice to meet you, {{name}}."
prompt = opik.Prompt(name=f"test-{unique_identifier}", prompt=template)
result = prompt.format(name="John", place="The Earth")
assert result == "Hello, John from The Earth! Nice to meet you, John."
assert prompt.prompt == template
def test_prompt__create_with_custom_type(opik_client: opik.Opik):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"some-prompt-name-{unique_identifier}"
prompt_template = f"some-prompt-text-{unique_identifier}"
prompt = opik_client.create_prompt(
name=prompt_name, prompt=prompt_template, type="jinja2"
)
verifiers.verify_prompt_version(
prompt,
name=prompt_name,
template=prompt_template,
type=PromptType.JINJA2,
)
def test_prompt__type_persists_in_get(opik_client: opik.Opik):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"some-prompt-name-{unique_identifier}"
prompt_template = f"some-prompt-text-{unique_identifier}"
opik_client.create_prompt(name=prompt_name, prompt=prompt_template, type="jinja2")
retrieved_prompt = opik_client.get_prompt(name=prompt_name)
verifiers.verify_prompt_version(
retrieved_prompt,
name=prompt_name,
template=prompt_template,
type=PromptType.JINJA2,
)
def test_prompt__type_in_new_version(opik_client: opik.Opik):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"some-prompt-name-{unique_identifier}"
prompt_template = f"some-prompt-text-{unique_identifier}"
prompt = opik_client.create_prompt(
name=prompt_name,
prompt=prompt_template,
)
assert prompt.type == PromptType.MUSTACHE
new_prompt = opik_client.create_prompt(
name=prompt_name, prompt=prompt_template + "-v2", type="jinja2"
)
verifiers.verify_prompt_version(
new_prompt,
type=PromptType.JINJA2,
prompt_id=prompt.__internal_api__prompt_id__,
)
assert (
new_prompt.__internal_api__version_id__ != prompt.__internal_api__version_id__
)
assert new_prompt.commit != prompt.commit
assert new_prompt.prompt != prompt.prompt
def test_prompt__search_prompts__returns_all_versions(opik_client: opik.Opik):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name_1 = f"some-prompt-name-{unique_identifier}"
prompt_name_2 = f"some-prompt-name-{unique_identifier}-v2"
opik_client.create_prompt(name=prompt_name_1, prompt="old-template-1")
opik_client.create_prompt(name=prompt_name_1, prompt="new-template-1")
opik_client.create_prompt(name=prompt_name_2, prompt="some-template-2")
prompts = opik_client.search_prompts()
templates = {p.prompt for p in prompts if isinstance(p, opik.Prompt)}
assert "new-template-1" in templates
assert "some-template-2" in templates
def test_prompt__get_prompts__with_filters__happyflow(opik_client: opik.Opik):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"some-prompt-name-{unique_identifier}"
prompt_template_1 = f"some-prompt-text-{unique_identifier}"
prompt_template_2 = f"some-prompt-text-{unique_identifier}-v2"
# Create two versions for the same prompt
_ = opik_client.create_prompt(name=prompt_name, prompt=prompt_template_1)
prompt_version2 = opik_client.create_prompt(
name=prompt_name, prompt=prompt_template_2
)
# Add tags to prompt version 2
opik_client.rest_client.prompts.update_prompt(
id=prompt_version2.__internal_api__prompt_id__,
name=prompt_version2.name,
tags=["alpha", "beta"],
)
filtered_prompts = opik_client.search_prompts(
filter_string=f'name contains "{prompt_name}" AND tags contains "alpha" AND tags contains "beta"',
)
assert len(filtered_prompts) == 1
assert filtered_prompts[0].prompt == prompt_template_2
def test_prompt__search_prompts__by_name__happyflow(opik_client: opik.Opik):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name_1 = f"common-prefix-{unique_identifier}-one"
prompt_name_2 = f"common-prefix-{unique_identifier}-two"
prompt_name_3 = f"other-group-{unique_identifier}-three"
# Create three prompts with different names
opik_client.create_prompt(name=prompt_name_1, prompt="template-1")
opik_client.create_prompt(name=prompt_name_2, prompt="template-2")
opik_client.create_prompt(name=prompt_name_3, prompt="template-3")
# Search by name substring via OQL (no additional filters) to retrieve only two matching prompts
results = opik_client.search_prompts(
filter_string=f'name contains "common-prefix-{unique_identifier}"'
)
names = set(p.name for p in results if isinstance(p, opik.Prompt))
assert len(results) == 2
assert names == set([prompt_name_1, prompt_name_2])
def test_prompt__template_structure_immutable__error(opik_client: opik.Opik):
"""Test that template_structure is immutable after prompt creation."""
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"test-immutable-structure-{unique_identifier}"
# Create initial text prompt
text_prompt = opik_client.create_prompt(
name=prompt_name,
prompt="This is a text prompt: {{variable}}",
)
# Verify text prompt was created
verifiers.verify_prompt_version(
text_prompt,
name=prompt_name,
template="This is a text prompt: {{variable}}",
)
# Attempt to create a chat prompt version with the same name should fail
with pytest.raises(opik.exceptions.PromptTemplateStructureMismatch):
opik_client.create_chat_prompt(
name=prompt_name,
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"},
],
)
# Verify the original text prompt remains unchanged
retrieved_prompt = opik_client.get_prompt(name=prompt_name)
assert retrieved_prompt is not None
verifiers.verify_prompt_version(
retrieved_prompt,
name=prompt_name,
template=text_prompt.prompt,
commit=text_prompt.commit,
prompt_id=text_prompt.__internal_api__prompt_id__,
version_id=text_prompt.__internal_api__version_id__,
)
def test_get_prompt__string_prompt__returns_prompt(opik_client: opik.Opik):
"""Test that get_prompt() returns a Prompt object for text prompts."""
unique_id = str(uuid.uuid4())[-6:]
prompt_name = f"text-prompt-{unique_id}"
# Create a text prompt
created_prompt = opik_client.create_prompt(
name=prompt_name,
prompt="Hello {{name}}",
)
# Retrieve it with get_prompt()
retrieved_prompt = opik_client.get_prompt(name=prompt_name)
assert retrieved_prompt is not None
assert isinstance(retrieved_prompt, opik.Prompt)
assert retrieved_prompt.name == prompt_name
assert retrieved_prompt.commit == created_prompt.commit
def test_get_prompt__chat_prompt__returns_none(opik_client: opik.Opik):
"""Test that get_prompt() raises an error for chat prompts (type mismatch)."""
unique_id = str(uuid.uuid4())[-6:]
prompt_name = f"chat-prompt-{unique_id}"
# Create a chat prompt
chat_prompt = opik_client.create_chat_prompt(
name=prompt_name,
messages=[
{"role": "system", "content": "You are helpful"},
{"role": "user", "content": "Hello"},
],
)
# Try to retrieve it with get_prompt() - should raise an error due to type mismatch
with pytest.raises(opik.exceptions.PromptTemplateStructureMismatch):
opik_client.get_prompt(name=prompt_name)
# Verify the chat prompt remains unchanged
retrieved_chat_prompt = opik_client.get_chat_prompt(name=prompt_name)
assert retrieved_chat_prompt is not None
verifiers.verify_chat_prompt_version(
retrieved_chat_prompt,
name=prompt_name,
messages=chat_prompt.template,
commit=chat_prompt.commit,
prompt_id=chat_prompt.__internal_api__prompt_id__,
version_id=chat_prompt.__internal_api__version_id__,
)
def test_get_prompt_history__string_prompt__returns_prompts(opik_client: opik.Opik):
"""Test that get_prompt_history() returns Prompt objects for text prompts."""
unique_id = str(uuid.uuid4())[-6:]
prompt_name = f"text-prompt-history-{unique_id}"
# Create multiple versions of a text prompt
v1 = opik_client.create_prompt(name=prompt_name, prompt="Version 1")
v2 = opik_client.create_prompt(name=prompt_name, prompt="Version 2")
v3 = opik_client.create_prompt(name=prompt_name, prompt="Version 3")
# Retrieve history
history = opik_client.get_prompt_history(name=prompt_name)
assert len(history) == 3
assert all(isinstance(p, opik.Prompt) for p in history)
assert history[0].name == prompt_name
# Verify commits are in the history
commits = {p.commit for p in history}
assert v1.commit in commits
assert v2.commit in commits
assert v3.commit in commits
def test_get_prompt_history__chat_prompt__returns_empty_list(opik_client: opik.Opik):
"""Test that get_prompt_history() raises an error for chat prompts (type mismatch)."""
unique_id = str(uuid.uuid4())[-6:]
prompt_name = f"chat-prompt-history-{unique_id}"
# Create a chat prompt
chat_prompt = opik_client.create_chat_prompt(
name=prompt_name,
messages=[{"role": "user", "content": "Hello"}],
)
# Try to get history with get_prompt_history() - should raise an error due to type mismatch
with pytest.raises(opik.exceptions.PromptTemplateStructureMismatch):
opik_client.get_prompt_history(name=prompt_name)
# Verify the chat prompt remains unchanged
retrieved_chat_prompt = opik_client.get_chat_prompt(name=prompt_name)
assert retrieved_chat_prompt is not None
verifiers.verify_chat_prompt_version(
retrieved_chat_prompt,
name=prompt_name,
messages=chat_prompt.template,
commit=chat_prompt.commit,
prompt_id=chat_prompt.__internal_api__prompt_id__,
version_id=chat_prompt.__internal_api__version_id__,
)
def test_search_prompts__returns_both_types(opik_client: opik.Opik):
"""Test that search_prompts() returns both text and chat prompts."""
unique_id = str(uuid.uuid4())[-6:]
# Create text prompts
text_prompt_1 = opik_client.create_prompt(
name=f"text-search-{unique_id}-1",
prompt="Text prompt 1",
)
text_prompt_2 = opik_client.create_prompt(
name=f"text-search-{unique_id}-2",
prompt="Text prompt 2",
)
# Create chat prompts with similar names
chat_prompt_1 = opik_client.create_chat_prompt(
name=f"chat-search-{unique_id}-1",
messages=[{"role": "user", "content": "Chat 1"}],
)
chat_prompt_2 = opik_client.create_chat_prompt(
name=f"chat-search-{unique_id}-2",
messages=[{"role": "user", "content": "Chat 2"}],
)
# Search for all prompts with the unique_id
results = opik_client.search_prompts(filter_string=f'name contains "{unique_id}"')
# Should return both text and chat prompts
assert len(results) == 4
text_prompts = [p for p in results if isinstance(p, opik.Prompt)]
chat_prompts = [p for p in results if isinstance(p, opik.ChatPrompt)]
assert len(text_prompts) == 2
assert len(chat_prompts) == 2
assert {p.name for p in text_prompts} == {
text_prompt_1.name,
text_prompt_2.name,
}
assert {p.name for p in chat_prompts} == {chat_prompt_1.name, chat_prompt_2.name}
def test_search_prompts__filter_by_template_structure_text(opik_client: opik.Opik):
"""Test that search_prompts() can filter by template_structure='text'."""
unique_id = str(uuid.uuid4())[-6:]
# Create text and chat prompts
text_prompt = opik_client.create_prompt(
name=f"text-search-{unique_id}",
prompt="Text prompt",
)
_ = opik_client.create_chat_prompt(
name=f"chat-search-{unique_id}",
messages=[{"role": "user", "content": "Chat"}],
)
# Search for only text prompts
results = opik_client.search_prompts(
filter_string=f'name contains "{unique_id}" AND template_structure = "text"'
)
# Should only return text prompts
assert len(results) == 1
assert isinstance(results[0], opik.Prompt)
assert results[0].name == text_prompt.name
def test_search_prompts__filter_by_template_structure_chat(opik_client: opik.Opik):
"""Test that search_prompts() can filter by template_structure='chat'."""
unique_id = str(uuid.uuid4())[-6:]
# Create text and chat prompts
_ = opik_client.create_prompt(
name=f"text-search-{unique_id}",
prompt="Text prompt",
)
chat_prompt = opik_client.create_chat_prompt(
name=f"chat-search-{unique_id}",
messages=[{"role": "user", "content": "Chat"}],
)
# Search for only chat prompts
results = opik_client.search_prompts(
filter_string=f'name contains "{unique_id}" AND template_structure = "chat"'
)
# Should only return chat prompts
assert len(results) == 1
assert isinstance(results[0], opik.ChatPrompt)
assert results[0].name == chat_prompt.name
def test_get_prompt__with_commit__string_prompt(opik_client: opik.Opik):
"""Test that get_prompt() with commit works for text prompts."""
unique_id = str(uuid.uuid4())[-6:]
prompt_name = f"string-prompt-commit-{unique_id}"
# Create multiple versions
v1 = opik_client.create_prompt(name=prompt_name, prompt="Version 1")
_ = opik_client.create_prompt(name=prompt_name, prompt="Version 2")
# Retrieve specific version by commit
retrieved_v1 = opik_client.get_prompt(name=prompt_name, commit=v1.commit)
assert retrieved_v1 is not None
assert isinstance(retrieved_v1, opik.Prompt)
assert retrieved_v1.commit == v1.commit
assert retrieved_v1.prompt == "Version 1"
def test_get_prompt__nonexistent__returns_none(opik_client: opik.Opik):
"""Test that get_prompt() returns None for non-existent prompts."""
result = opik_client.get_prompt(name="nonexistent-prompt-12345")
assert result is None
def test_prompt__format_playground_chat_prompt__returns_json(opik_client: opik.Opik):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"chat-prompt-{unique_identifier}"
# JSON template representing a chat messages array with multimodal content
# Build as Python structure for readability, then convert to JSON
prompt_structure = [
{
"role": "system",
"content": "You are {{assistant_type}}",
},
{
"role": "user",
"content": "{{user_message}}",
},
{
"role": "assistant",
"content": "{{assistant_response}}",
},
{
"role": "user",
"content": [
{
"type": "text",
"text": "{{followup_text}}",
},
{
"type": "image_url",
"image_url": {
"url": "{{image_url}}",
},
},
{
"type": "video_url",
"video_url": {
"url": "{{video_url}}",
},
},
],
},
]
prompt_template = json.dumps(prompt_structure)
# Create a playground chat prompt with the appropriate metadata
prompt = opik_client.create_prompt(
name=prompt_name,
prompt=prompt_template,
metadata={
"created_from": "opik_ui",
"type": "messages_json",
},
)
# Format the prompt with variables
result = prompt.format(
assistant_type="a helpful AI",
user_message="Hello!",
assistant_response="Hi there! How can I help you today?",
followup_text="Can you analyze this image and video?",
image_url="https://example.com/image.jpg",
video_url="https://example.com/video.mp4",
)
# Should return parsed JSON (list of dicts), not a string
expected_result = [
{
"role": "system",
"content": "You are a helpful AI",
},
{
"role": "user",
"content": "Hello!",
},
{
"role": "assistant",
"content": "Hi there! How can I help you today?",
},
{
"role": "user",
"content": [
{
"type": "text",
"text": "Can you analyze this image and video?",
},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/image.jpg",
},
},
{
"type": "video_url",
"video_url": {
"url": "https://example.com/video.mp4",
},
},
],
},
]
assert result == expected_result
def test_prompt__format_playground_chat_prompt__invalid_json__returns_string(
opik_client: opik.Opik,
):
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"invalid-chat-prompt-{unique_identifier}"
# Invalid JSON template (missing closing bracket)
prompt_template = '[{"role": "system", "content": "{{content}}"}'
# Create a playground chat prompt with the appropriate metadata
prompt = opik_client.create_prompt(
name=prompt_name,
prompt=prompt_template,
metadata={
"created_from": "opik_ui",
"type": "messages_json",
},
)
# Format the prompt - should handle invalid JSON gracefully
result = prompt.format(content="test content")
# Should return the formatted string (not parsed) because JSON is invalid
assert isinstance(result, str)
assert result == '[{"role": "system", "content": "test content"}'
def test_prompt__create_with_additional_parameters__happyflow(opik_client: opik.Opik):
"""Test that create_prompt() accepts tags and description parameters."""
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"prompt-with-params-{unique_identifier}"
prompt_template = f"some-prompt-text-{unique_identifier}"
tags = ["tag1", "tag2", "production"]
description = "This is a test prompt description"
# Create prompt with tags and description
prompt = opik_client.create_prompt(
name=prompt_name,
prompt=prompt_template,
tags=tags,
description=description,
)
# Verify prompt was created
verifiers.verify_prompt_version(
prompt,
name=prompt_name,
template=prompt_template,
)
# Verify tags were set by searching for the prompt
filtered_prompts = opik_client.search_prompts(
filter_string=f'name = "{prompt_name}" AND tags contains "tag1"',
)
assert len(filtered_prompts) == 1
assert filtered_prompts[0].name == prompt_name
# Retrieve the prompt to verify description was set
retrieved_prompt = opik_client.get_prompt(name=prompt_name)
assert retrieved_prompt is not None
assert retrieved_prompt.name == prompt_name
def test_prompt__create_with_tags__happyflow(opik_client: opik.Opik):
"""Test that create_prompt() accepts tags parameter and tags can be accessed from search results."""
unique_identifier = str(uuid.uuid4())[-6:]
prompt_name = f"prompt-with-tags-{unique_identifier}"
prompt_template = f"some-prompt-text-{unique_identifier}"
tags = ["text-tag1", "text-tag2", "production"]
# Create text prompt with tags
prompt = opik_client.create_prompt(
name=prompt_name,
prompt=prompt_template,
tags=tags,
)
# Verify prompt was created
verifiers.verify_prompt_version(
prompt,
name=prompt_name,
template=prompt_template,
)
# Verify tags were set by searching for the prompt and accessing tags property
filtered_prompts = opik_client.search_prompts(
filter_string=f'name = "{prompt_name}" AND tags contains "text-tag1"',
)
assert len(filtered_prompts) == 1
assert filtered_prompts[0].name == prompt_name
assert set(filtered_prompts[0].tags) == set(tags)
def test_prompt__filter_versions(opik_client: opik.Opik):
prompt_name = _generate_random_prompt_name()
shared_tag = _generate_random_tag()
v1 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v1-{_generate_random_suffix()}",
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[v1.version_id],
tags=[shared_tag, _generate_random_tag()],
)
v2 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v2-{_generate_random_suffix()}",
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[v2.version_id],
tags=_generate_random_tags(),
)
v3 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v3-{_generate_random_suffix()}",
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[v3.version_id],
tags=[_generate_random_tag(), shared_tag],
)
filtered_versions = opik_client.get_prompt_history(
name=prompt_name,
filter_string=f'tags contains "{shared_tag}"',
)
assert len(filtered_versions) == 2
version_ids = {v.version_id for v in filtered_versions}
assert v1.version_id in version_ids
assert v3.version_id in version_ids
assert v2.version_id not in version_ids
def test_prompt__search_versions(opik_client: opik.Opik):
prompt_name = _generate_random_prompt_name()
search_term = f"unique-search-term-{_generate_random_suffix()}"
v1 = opik_client.create_prompt(
name=prompt_name,
prompt=f"This template contains {search_term} for testing",
)
v2 = opik_client.create_prompt(
name=prompt_name,
prompt=f"This template has different content {_generate_random_suffix()} for testing",
)
v3 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Another template with {search_term} included",
)
search_results = opik_client.get_prompt_history(
name=prompt_name, search=search_term
)
assert len(search_results) == 2
version_ids = {v.version_id for v in search_results}
assert v1.version_id in version_ids
assert v3.version_id in version_ids
assert v2.version_id not in version_ids
def test_chat_prompt__filter_versions(opik_client: opik.Opik):
prompt_name = _generate_random_prompt_name()
shared_tag = _generate_random_tag()
v1 = opik_client.create_chat_prompt(
name=prompt_name,
messages=[
{"role": "user", "content": f"Message v1-{_generate_random_suffix()}"}
],
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[v1.version_id],
tags=[shared_tag, _generate_random_tag()],
)
v2 = opik_client.create_chat_prompt(
name=prompt_name,
messages=[
{"role": "user", "content": f"Message v2-{_generate_random_suffix()}"}
],
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[v2.version_id],
tags=_generate_random_tags(),
)
v3 = opik_client.create_chat_prompt(
name=prompt_name,
messages=[
{"role": "user", "content": f"Message v3-{_generate_random_suffix()}"}
],
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[v3.version_id],
tags=[_generate_random_tag(), shared_tag],
)
filtered_versions = opik_client.get_chat_prompt_history(
name=prompt_name,
filter_string=f'tags contains "{shared_tag}"',
)
assert len(filtered_versions) == 2
version_ids = {v.version_id for v in filtered_versions}
assert v1.version_id in version_ids
assert v3.version_id in version_ids
assert v2.version_id not in version_ids
def test_chat_prompt__search_versions(opik_client: opik.Opik):
prompt_name = _generate_random_prompt_name()
search_term = f"unique-search-term-{_generate_random_suffix()}"
v1 = opik_client.create_chat_prompt(
name=prompt_name,
messages=[
{
"role": "user",
"content": f"This message contains {search_term} for testing",
}
],
)
v2 = opik_client.create_chat_prompt(
name=prompt_name,
messages=[
{
"role": "user",
"content": f"This message has different content {_generate_random_suffix()} for testing",
}
],
)
v3 = opik_client.create_chat_prompt(
name=prompt_name,
messages=[
{"role": "user", "content": f"Another message with {search_term} included"}
],
)
search_results = opik_client.get_chat_prompt_history(
name=prompt_name, search=search_term
)
assert len(search_results) == 2
version_ids = {v.version_id for v in search_results}
assert v1.version_id in version_ids
assert v3.version_id in version_ids
assert v2.version_id not in version_ids
def test_prompt__update_version_tags__replace_mode(opik_client: opik.Opik):
prompt_name = _generate_random_prompt_name()
version1 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v1-{_generate_random_suffix()}",
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version1.version_id],
tags=_generate_random_tags(),
merge=False,
)
version2 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v2-{_generate_random_suffix()}",
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version2.version_id],
tags=_generate_random_tags(),
merge=False,
)
new_tags = _generate_random_tags()
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version1.version_id, version2.version_id],
tags=new_tags,
merge=False,
)
history = opik_client.get_prompt_history(name=prompt_name)
assert len(history) == 2
v1_in_history = next(
(v for v in history if v.version_id == version1.version_id), None
)
v2_in_history = next(
(v for v in history if v.version_id == version2.version_id), None
)
assert set(v1_in_history.tags) == set(new_tags)
assert set(v2_in_history.tags) == set(new_tags)
def test_prompt__update_version_tags__default_replace_mode(opik_client: opik.Opik):
prompt_name = _generate_random_prompt_name()
version1 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v1-{_generate_random_suffix()}",
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version1.version_id],
tags=_generate_random_tags(),
)
version2 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v2-{_generate_random_suffix()}",
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version2.version_id],
tags=_generate_random_tags(),
)
new_tags = _generate_random_tags()
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version1.version_id, version2.version_id],
tags=new_tags,
)
history = opik_client.get_prompt_history(name=prompt_name)
v1_in_history = next(
(v for v in history if v.version_id == version1.version_id), None
)
v2_in_history = next(
(v for v in history if v.version_id == version2.version_id), None
)
assert set(v1_in_history.tags) == set(new_tags)
assert set(v2_in_history.tags) == set(new_tags)
def test_prompt__update_version_tags__clear_with_empty_array(opik_client: opik.Opik):
prompt_name = _generate_random_prompt_name()
version1 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v1-{_generate_random_suffix()}",
)
version2 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v2-{_generate_random_suffix()}",
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version1.version_id, version2.version_id],
tags=_generate_random_tags(),
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version1.version_id, version2.version_id],
tags=[],
)
history = opik_client.get_prompt_history(name=prompt_name)
assert len(history) == 2
v1_in_history = next(
(v for v in history if v.version_id == version1.version_id), None
)
v2_in_history = next(
(v for v in history if v.version_id == version2.version_id), None
)
assert v1_in_history.tags == []
assert v2_in_history.tags == []
@pytest.mark.parametrize("merge_param", [False, True, None])
def test_prompt__update_version_tags__preserve_with_none(
opik_client: opik.Opik, merge_param
):
prompt_name = _generate_random_prompt_name()
version1 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v1-{_generate_random_suffix()}",
)
initial_tags_v1 = _generate_random_tags()
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version1.version_id],
tags=initial_tags_v1,
)
version2 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v2-{_generate_random_suffix()}",
)
initial_tags_v2 = _generate_random_tags()
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version2.version_id],
tags=initial_tags_v2,
)
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version1.version_id, version2.version_id],
tags=None,
merge=merge_param,
)
history = opik_client.get_prompt_history(name=prompt_name)
assert len(history) == 2
v1_in_history = next(
(v for v in history if v.version_id == version1.version_id), None
)
v2_in_history = next(
(v for v in history if v.version_id == version2.version_id), None
)
assert set(v1_in_history.tags) == set(initial_tags_v1)
assert set(v2_in_history.tags) == set(initial_tags_v2)
def test_prompt__update_version_tags__merge_mode(opik_client: opik.Opik):
prompt_name = _generate_random_prompt_name()
version1 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v1-{_generate_random_suffix()}",
)
initial_tags_v1 = _generate_random_tags()
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version1.version_id],
tags=initial_tags_v1,
merge=False,
)
version2 = opik_client.create_prompt(
name=prompt_name,
prompt=f"Template v2-{_generate_random_suffix()}",
)
initial_tags_v2 = _generate_random_tags()
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version2.version_id],
tags=initial_tags_v2,
merge=False,
)
additional_tags = _generate_random_tags()
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[version1.version_id, version2.version_id],
tags=additional_tags,
merge=True,
)
history = opik_client.get_prompt_history(name=prompt_name)
assert len(history) == 2
v1_in_history = next(
(v for v in history if v.version_id == version1.version_id), None
)
v2_in_history = next(
(v for v in history if v.version_id == version2.version_id), None
)
assert set(v1_in_history.tags) == set(initial_tags_v1 + additional_tags)
assert set(v2_in_history.tags) == set(initial_tags_v2 + additional_tags)
def test_chat_prompt__update_version_tags(opik_client: opik.Opik):
prompt_name = _generate_random_prompt_name()
v1 = opik_client.create_chat_prompt(
name=prompt_name,
messages=[
{"role": "user", "content": f"Message v1 {_generate_random_suffix()}"}
],
)
v2 = opik_client.create_chat_prompt(
name=prompt_name,
messages=[
{"role": "user", "content": f"Message v2 {_generate_random_suffix()}"}
],
)
new_tags = _generate_random_tags()
opik_client.get_prompts_client().batch_update_prompt_version_tags(
version_ids=[v1.version_id, v2.version_id],
tags=new_tags,
merge=False,
)
history = opik_client.get_chat_prompt_history(name=prompt_name)
assert len(history) == 2
v1_in_history = next((v for v in history if v.version_id == v1.version_id), None)
v2_in_history = next((v for v in history if v.version_id == v2.version_id), None)
assert set(v1_in_history.tags) == set(new_tags)
assert set(v2_in_history.tags) == set(new_tags)