Skip to content

Commit d5b6cf0

Browse files
rlundeen2Copilot
andauthored
FEAT: BuildableRegistry Creation (#2057)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3a5bcd6 commit d5b6cf0

51 files changed

Lines changed: 2705 additions & 1237 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

doc/code/converters/6_selectively_converting.ipynb

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@
215215
"source": [
216216
"# Convert words at specific positions (e.g., words 3, 4, and 5)\n",
217217
"converter = SelectiveTextConverter(\n",
218-
" converter=Base64Converter(),\n",
218+
" sub_converter=Base64Converter(),\n",
219219
" selection_strategy=WordIndexSelectionStrategy(indices=[3, 4, 5]),\n",
220220
")\n",
221221
"\n",
@@ -293,7 +293,7 @@
293293
"source": [
294294
"# Convert all numbers in the prompt\n",
295295
"converter = SelectiveTextConverter(\n",
296-
" converter=Base64Converter(),\n",
296+
" sub_converter=Base64Converter(),\n",
297297
" selection_strategy=WordRegexSelectionStrategy(pattern=r\"\\d+\"),\n",
298298
")\n",
299299
"\n",
@@ -373,7 +373,7 @@
373373
"source": [
374374
"# Convert the second half of the prompt\n",
375375
"converter = SelectiveTextConverter(\n",
376-
" converter=ROT13Converter(),\n",
376+
" sub_converter=ROT13Converter(),\n",
377377
" selection_strategy=WordPositionSelectionStrategy(start_proportion=0.5, end_proportion=1.0),\n",
378378
")\n",
379379
"\n",
@@ -452,7 +452,7 @@
452452
],
453453
"source": [
454454
"converter = SelectiveTextConverter(\n",
455-
" converter=Base64Converter(),\n",
455+
" sub_converter=Base64Converter(),\n",
456456
" selection_strategy=WordProportionSelectionStrategy(proportion=0.3, seed=42),\n",
457457
")\n",
458458
"\n",
@@ -530,7 +530,7 @@
530530
"source": [
531531
"# Convert specific sensitive words\n",
532532
"converter = SelectiveTextConverter(\n",
533-
" converter=Base64Converter(),\n",
533+
" sub_converter=Base64Converter(),\n",
534534
" selection_strategy=WordKeywordSelectionStrategy(keywords=[\"password\", \"secret\", \"confidential\"]),\n",
535535
")\n",
536536
"\n",
@@ -610,13 +610,13 @@
610610
"source": [
611611
"# First convert the first half to russian\n",
612612
"first_converter = SelectiveTextConverter(\n",
613-
" converter=TranslationConverter(converter_target=OpenAIChatTarget(), language=\"russian\"),\n",
613+
" sub_converter=TranslationConverter(converter_target=OpenAIChatTarget(), language=\"russian\"),\n",
614614
" selection_strategy=WordPositionSelectionStrategy(start_proportion=0.0, end_proportion=0.5),\n",
615615
")\n",
616616
"\n",
617617
"# Then converts the second half to spanish\n",
618618
"second_converter = SelectiveTextConverter(\n",
619-
" converter=TranslationConverter(converter_target=OpenAIChatTarget(), language=\"spanish\"),\n",
619+
" sub_converter=TranslationConverter(converter_target=OpenAIChatTarget(), language=\"spanish\"),\n",
620620
" selection_strategy=WordPositionSelectionStrategy(start_proportion=0.5, end_proportion=1.0),\n",
621621
")\n",
622622
"\n",
@@ -699,20 +699,20 @@
699699
],
700700
"source": [
701701
"first_converter = SelectiveTextConverter(\n",
702-
" converter=ToneConverter(converter_target=OpenAIChatTarget(), tone=\"angry\"),\n",
702+
" sub_converter=ToneConverter(converter_target=OpenAIChatTarget(), tone=\"angry\"),\n",
703703
" selection_strategy=WordPositionSelectionStrategy(start_proportion=0.5, end_proportion=1.0),\n",
704704
" preserve_tokens=True,\n",
705705
")\n",
706706
"\n",
707707
"# Second converter auto-detects tokens from first converter\n",
708708
"second_converter = SelectiveTextConverter(\n",
709-
" converter=TranslationConverter(converter_target=OpenAIChatTarget(), language=\"spanish\"),\n",
709+
" sub_converter=TranslationConverter(converter_target=OpenAIChatTarget(), language=\"spanish\"),\n",
710710
" selection_strategy=TokenSelectionStrategy(), # Detects tokens from first converter\n",
711711
" preserve_tokens=True,\n",
712712
")\n",
713713
"\n",
714714
"third_converter = SelectiveTextConverter(\n",
715-
" converter=EmojiConverter(),\n",
715+
" sub_converter=EmojiConverter(),\n",
716716
" selection_strategy=TokenSelectionStrategy(), # Detects tokens from second converter\n",
717717
" preserve_tokens=False,\n",
718718
")\n",

doc/code/converters/6_selectively_converting.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
# %%
7979
# Convert words at specific positions (e.g., words 3, 4, and 5)
8080
converter = SelectiveTextConverter(
81-
converter=Base64Converter(),
81+
sub_converter=Base64Converter(),
8282
selection_strategy=WordIndexSelectionStrategy(indices=[3, 4, 5]),
8383
)
8484

@@ -101,7 +101,7 @@
101101
# %%
102102
# Convert all numbers in the prompt
103103
converter = SelectiveTextConverter(
104-
converter=Base64Converter(),
104+
sub_converter=Base64Converter(),
105105
selection_strategy=WordRegexSelectionStrategy(pattern=r"\d+"),
106106
)
107107

@@ -126,7 +126,7 @@
126126
# %%
127127
# Convert the second half of the prompt
128128
converter = SelectiveTextConverter(
129-
converter=ROT13Converter(),
129+
sub_converter=ROT13Converter(),
130130
selection_strategy=WordPositionSelectionStrategy(start_proportion=0.5, end_proportion=1.0),
131131
)
132132

@@ -150,7 +150,7 @@
150150

151151
# %%
152152
converter = SelectiveTextConverter(
153-
converter=Base64Converter(),
153+
sub_converter=Base64Converter(),
154154
selection_strategy=WordProportionSelectionStrategy(proportion=0.3, seed=42),
155155
)
156156

@@ -173,7 +173,7 @@
173173
# %%
174174
# Convert specific sensitive words
175175
converter = SelectiveTextConverter(
176-
converter=Base64Converter(),
176+
sub_converter=Base64Converter(),
177177
selection_strategy=WordKeywordSelectionStrategy(keywords=["password", "secret", "confidential"]),
178178
)
179179

@@ -198,13 +198,13 @@
198198
# %%
199199
# First convert the first half to russian
200200
first_converter = SelectiveTextConverter(
201-
converter=TranslationConverter(converter_target=OpenAIChatTarget(), language="russian"),
201+
sub_converter=TranslationConverter(converter_target=OpenAIChatTarget(), language="russian"),
202202
selection_strategy=WordPositionSelectionStrategy(start_proportion=0.0, end_proportion=0.5),
203203
)
204204

205205
# Then converts the second half to spanish
206206
second_converter = SelectiveTextConverter(
207-
converter=TranslationConverter(converter_target=OpenAIChatTarget(), language="spanish"),
207+
sub_converter=TranslationConverter(converter_target=OpenAIChatTarget(), language="spanish"),
208208
selection_strategy=WordPositionSelectionStrategy(start_proportion=0.5, end_proportion=1.0),
209209
)
210210

@@ -229,20 +229,20 @@
229229
# %%
230230

231231
first_converter = SelectiveTextConverter(
232-
converter=ToneConverter(converter_target=OpenAIChatTarget(), tone="angry"),
232+
sub_converter=ToneConverter(converter_target=OpenAIChatTarget(), tone="angry"),
233233
selection_strategy=WordPositionSelectionStrategy(start_proportion=0.5, end_proportion=1.0),
234234
preserve_tokens=True,
235235
)
236236

237237
# Second converter auto-detects tokens from first converter
238238
second_converter = SelectiveTextConverter(
239-
converter=TranslationConverter(converter_target=OpenAIChatTarget(), language="spanish"),
239+
sub_converter=TranslationConverter(converter_target=OpenAIChatTarget(), language="spanish"),
240240
selection_strategy=TokenSelectionStrategy(), # Detects tokens from first converter
241241
preserve_tokens=True,
242242
)
243243

244244
third_converter = SelectiveTextConverter(
245-
converter=EmojiConverter(),
245+
sub_converter=EmojiConverter(),
246246
selection_strategy=TokenSelectionStrategy(), # Detects tokens from second converter
247247
preserve_tokens=False,
248248
)

doc/code/scenarios/2_custom_scenario_parameters.ipynb

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@
4949
"id": "1",
5050
"metadata": {},
5151
"outputs": [
52+
{
53+
"name": "stderr",
54+
"output_type": "stream",
55+
"text": [
56+
"./AppData/Local/miniconda3/Lib/site-packages/requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.5.0) or chardet (7.4.3)/charset_normalizer (3.3.2) doesn't match a supported version!\n",
57+
" warnings.warn(\n"
58+
]
59+
},
5260
{
5361
"name": "stdout",
5462
"output_type": "stream",
@@ -63,7 +71,7 @@
6371
"output_type": "stream",
6472
"text": [
6573
"[pyrit:alembic] No new upgrade operations detected.\n",
66-
"Parameter(name='max_turns', description='Maximum conversation turns for the persuasive_rta strategy.', default=5, param_type=<class 'int'>, choices=None)\n"
74+
"Parameter(name='max_turns', description='Maximum conversation turns for the persuasive_rta strategy.', default=5, param_type=<class 'int'>, destination=<ParameterDestination.CONSTRUCTOR: 'constructor'>)\n"
6775
]
6876
}
6977
],
@@ -93,8 +101,9 @@
93101
"- **name**: dict key in `self.params`, converted to `--kebab-case` for the CLI\n",
94102
"- **description**: shown in `--list-scenarios` and `--help`\n",
95103
"- **default**: value used when not supplied; deep-copied per run\n",
96-
"- **param_type**: `str`, `int`, `float`, `bool`, `list[str]`, or `None` (raw passthrough)\n",
97-
"- **choices**: optional tuple of allowed values (not supported with `list` types)\n",
104+
"- **param_type**: `str`, `int`, `float`, `bool`, a `Literal[...]`/`Enum` (a\n",
105+
" constrained scalar that carries its own allowed set), a `list[...]` of any of\n",
106+
" those, or `None` (raw passthrough)\n",
98107
"\n",
99108
"A more complete declaration list might look like:"
100109
]
@@ -109,29 +118,30 @@
109118
"name": "stdout",
110119
"output_type": "stream",
111120
"text": [
112-
"Parameter(name='objective', description='Goal the attack pursues', default=None, param_type=<class 'str'>, choices=None)\n",
113-
"Parameter(name='max_turns', description='Conversation cap', default=5, param_type=<class 'int'>, choices=None)\n",
114-
"Parameter(name='mode', description='Speed mode', default='fast', param_type=<class 'str'>, choices=('fast', 'slow'))\n",
115-
"Parameter(name='tags', description='Tag list', default=['default'], param_type=list[str], choices=None)\n"
121+
"Parameter(name='objective', description='Goal the attack pursues', default=None, param_type=<class 'str'>, destination=<ParameterDestination.CONSTRUCTOR: 'constructor'>)\n",
122+
"Parameter(name='max_turns', description='Conversation cap', default=5, param_type=<class 'int'>, destination=<ParameterDestination.CONSTRUCTOR: 'constructor'>)\n",
123+
"Parameter(name='mode', description='Speed mode', default='fast', param_type=typing.Literal['fast', 'slow'], destination=<ParameterDestination.CONSTRUCTOR: 'constructor'>)\n",
124+
"Parameter(name='tags', description='Tag list', default=['default'], param_type=list[str], destination=<ParameterDestination.CONSTRUCTOR: 'constructor'>)\n"
116125
]
117126
}
118127
],
119128
"source": [
120-
"from pyrit.common import Parameter\n",
129+
"from typing import Literal\n",
130+
"\n",
131+
"from pyrit.models import Parameter\n",
121132
"\n",
122133
"# What a scenario author would return from supported_parameters():\n",
123134
"example_declarations = [\n",
124135
" # Scalar with no default — author must guard against None at run time\n",
125136
" Parameter(name=\"objective\", description=\"Goal the attack pursues\", param_type=str),\n",
126137
" # Scalar with default\n",
127138
" Parameter(name=\"max_turns\", description=\"Conversation cap\", default=5, param_type=int),\n",
128-
" # Choices: behaves like an enum\n",
139+
" # Constrained scalar: a Literal behaves like an enum (the type *is* the allowed set)\n",
129140
" Parameter(\n",
130141
" name=\"mode\",\n",
131142
" description=\"Speed mode\",\n",
132143
" default=\"fast\",\n",
133-
" param_type=str,\n",
134-
" choices=(\"fast\", \"slow\"),\n",
144+
" param_type=Literal[\"fast\", \"slow\"],\n",
135145
" ),\n",
136146
" # List parameter\n",
137147
" Parameter(name=\"tags\", description=\"Tag list\", default=[\"default\"], param_type=list[str]),\n",
@@ -257,6 +267,27 @@
257267
"id": "8",
258268
"metadata": {},
259269
"outputs": [
270+
{
271+
"name": "stderr",
272+
"output_type": "stream",
273+
"text": [
274+
"TargetRegistry entry 'objective_scorer_chat' not found. Falling back to default OpenAIChatTarget.\n"
275+
]
276+
},
277+
{
278+
"name": "stderr",
279+
"output_type": "stream",
280+
"text": [
281+
"Using fallback default objective scorer: TrueFalseInverterScorer with chat target: OpenAIChatTarget\n"
282+
]
283+
},
284+
{
285+
"name": "stderr",
286+
"output_type": "stream",
287+
"text": [
288+
"TextAdaptive: _EXCLUDED_TECHNIQUES entries ['prompt_sending'] are not in the current scenario-techniques catalog ['context_compliance', 'crescendo_history_lecture', 'crescendo_journalist_interview', 'crescendo_movie_director', 'crescendo_simulated', 'many_shot', 'pair', 'red_teaming', 'role_play', 'tap', 'violent_durian']; the exclusion is a no-op for those entries. Remove stale entries or update the catalog.\n"
289+
]
290+
},
260291
{
261292
"name": "stderr",
262293
"output_type": "stream",
@@ -496,7 +527,7 @@
496527
"name": "python",
497528
"nbconvert_exporter": "python",
498529
"pygments_lexer": "ipython3",
499-
"version": "3.13.13"
530+
"version": "3.13.5"
500531
}
501532
},
502533
"nbformat": 4,

doc/code/scenarios/2_custom_scenario_parameters.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,27 +67,29 @@
6767
# - **name**: dict key in `self.params`, converted to `--kebab-case` for the CLI
6868
# - **description**: shown in `--list-scenarios` and `--help`
6969
# - **default**: value used when not supplied; deep-copied per run
70-
# - **param_type**: `str`, `int`, `float`, `bool`, `list[str]`, or `None` (raw passthrough)
71-
# - **choices**: optional tuple of allowed values (not supported with `list` types)
70+
# - **param_type**: `str`, `int`, `float`, `bool`, a `Literal[...]`/`Enum` (a
71+
# constrained scalar that carries its own allowed set), a `list[...]` of any of
72+
# those, or `None` (raw passthrough)
7273
#
7374
# A more complete declaration list might look like:
7475

7576
# %%
76-
from pyrit.common import Parameter
77+
from typing import Literal
78+
79+
from pyrit.models import Parameter
7780

7881
# What a scenario author would return from supported_parameters():
7982
example_declarations = [
8083
# Scalar with no default — author must guard against None at run time
8184
Parameter(name="objective", description="Goal the attack pursues", param_type=str),
8285
# Scalar with default
8386
Parameter(name="max_turns", description="Conversation cap", default=5, param_type=int),
84-
# Choices: behaves like an enum
87+
# Constrained scalar: a Literal behaves like an enum (the type *is* the allowed set)
8588
Parameter(
8689
name="mode",
8790
description="Speed mode",
8891
default="fast",
89-
param_type=str,
90-
choices=("fast", "slow"),
92+
param_type=Literal["fast", "slow"],
9193
),
9294
# List parameter
9395
Parameter(name="tags", description="Tag list", default=["default"], param_type=list[str]),

0 commit comments

Comments
 (0)