Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions pyrit/converter/random_translation_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,12 @@ def __init__(
default_languages = SeedDataset.from_yaml_file(
RandomTranslationConverter._DEFAULT_LANGUAGES_SEED_PROMPT_PATH
)
self.languages = [prompt.value for prompt in default_languages.prompts]
selected_languages = [prompt.value for prompt in default_languages.prompts]
else:
self.languages = languages
selected_languages = list(languages)
# Random selection and identity share one canonical order, so reordering the same pool neither
# changes the seeded translations nor the identifier that is supposed to describe them.
self.languages = sorted(selected_languages, key=str.casefold)

def _build_identifier(self) -> ComponentIdentifier:
"""
Expand All @@ -95,7 +98,7 @@ def _build_identifier(self) -> ComponentIdentifier:
params={
**llm_identifier.params,
**word_level_identifier.params,
"languages": sorted(self.languages, key=str.casefold),
"languages": self.languages,
},
converter_target=self._converter_target.get_identifier(),
)
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/converter/test_random_translation_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytest
from unit.mocks import get_mock_target_identifier

from pyrit.common.random_context import configure_random_seed, get_configured_random_seed
from pyrit.converter import (
RandomTranslationConverter,
WordPositionSelectionStrategy,
Expand Down Expand Up @@ -81,6 +82,25 @@ def test_random_translation_converter_identifier_canonicalizes_language_order(mo
assert first.get_identifier().hash == reordered.get_identifier().hash


async def test_random_translation_converter_canonicalizes_language_order_for_selection(mock_target) -> None:
"""Same language pool in a different order must produce the same translations under one seed."""
original_seed = get_configured_random_seed()
configure_random_seed(seed=42)
try:
first = RandomTranslationConverter(converter_target=mock_target, languages=["French", "Spanish"])
reordered = RandomTranslationConverter(converter_target=mock_target, languages=["Spanish", "French"])

await first.convert_async(prompt="alpha beta gamma delta epsilon")
await reordered.convert_async(prompt="alpha beta gamma delta epsilon")
finally:
configure_random_seed(seed=original_seed)

assert first.get_identifier().hash == reordered.get_identifier().hash
first_message = mock_target.send_prompt_async.call_args_list[0].kwargs["message"]
reordered_message = mock_target.send_prompt_async.call_args_list[1].kwargs["message"]
assert first_message.message_pieces[0].original_value == reordered_message.message_pieces[0].original_value


def test_random_translation_converter_identifier_distinguishes_language_pools(mock_target) -> None:
first = RandomTranslationConverter(converter_target=mock_target, languages=["French", "Spanish"])
different = RandomTranslationConverter(converter_target=mock_target, languages=["German", "Japanese"])
Expand Down
Loading