Skip to content

Commit 7d828ed

Browse files
rlundeen2Copilot
andauthored
MAINT: Unify scenario initialize_async's into common parameter bag (#2132)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent aaff32c commit 7d828ed

56 files changed

Lines changed: 3489 additions & 1204 deletions

Some content is hidden

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

.env_example

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
PLATFORM_OPENAI_CHAT_ENDPOINT="https://api.openai.com/v1"
3232
PLATFORM_OPENAI_CHAT_KEY="sk-xxxxx"
33-
PLATFORM_OPENAI_CHAT_GPT4O_MODEL="gpt-4o"
33+
PLATFORM_OPENAI_CHAT_MODEL="gpt-4o"
3434

3535
# Note: For Azure OpenAI endpoints, use the new format with /openai/v1 and specify the model separately
3636
# Example: https://xxxx.openai.azure.com/openai/v1
@@ -113,7 +113,7 @@ AZURE_FOUNDRY_DEEPSEEK_MODEL=""
113113

114114
AZURE_FOUNDRY_PHI4_ENDPOINT="https://xxxxx.models.ai.azure.com"
115115
AZURE_CHAT_PHI4_KEY="xxxxx"
116-
AZURE_FOUNDRY_PHI4_MODEL=""
116+
AZURE_CHAT_PHI4_MODEL=""
117117

118118
AZURE_FOUNDRY_MISTRAL_LARGE_ENDPOINT="https://xxxxx.services.ai.azure.com/openai/v1/"
119119
AZURE_FOUNDRY_MISTRAL_LARGE_KEY="xxxxx"
@@ -141,7 +141,7 @@ DEFAULT_OPENAI_FRONTEND_MODEL = "gpt-4o"
141141

142142
OPENAI_CHAT_ENDPOINT=${PLATFORM_OPENAI_CHAT_ENDPOINT}
143143
OPENAI_CHAT_KEY=${PLATFORM_OPENAI_CHAT_KEY}
144-
OPENAI_CHAT_MODEL=${PLATFORM_OPENAI_CHAT_GPT4O_MODEL}
144+
OPENAI_CHAT_MODEL=${PLATFORM_OPENAI_CHAT_MODEL}
145145
# The following line can be populated if using an Azure OpenAI deployment
146146
# where the deployment name differs from the actual underlying model
147147
OPENAI_CHAT_UNDERLYING_MODEL=""

.github/instructions/scenarios.instructions.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ Scenarios orchestrate multi-attack security testing campaigns. Each scenario gro
1313
All scenarios inherit from `Scenario` (ABC) and must:
1414

1515
1. **Define `VERSION`** as a class constant (increment on breaking changes)
16-
2. **Optionally declare `BASELINE_ATTACK_POLICY`** (defaults to `BaselineAttackPolicy.Enabled` — a baseline `PromptSendingAttack` is prepended and callers can opt out per run via `initialize_async(include_baseline=False)`):
16+
2. **Optionally declare `BASELINE_ATTACK_POLICY`** (defaults to `BaselineAttackPolicy.Enabled` — a baseline `PromptSendingAttack` is prepended and callers can opt out per run by setting `include_baseline=False` in the run params, see "Run Parameters" below):
1717
- `BaselineAttackPolicy.Disabled` — baseline supported but off by default (e.g. `Jailbreak`, where templates dominate the run).
18-
- `BaselineAttackPolicy.Forbidden` — baseline is meaningless for this scenario's comparison axis (e.g. `AdversarialBenchmark`, which compares against gold-standard answers). Explicit `include_baseline=True` raises `ValueError`.
18+
- `BaselineAttackPolicy.Forbidden` — baseline is meaningless for this scenario's comparison axis (e.g. `AdversarialBenchmark`, which compares against gold-standard answers). Supplying `include_baseline=True` raises `ValueError`.
1919
3. **Pass `strategy_class`, `default_strategy`, and `default_dataset_config` to `super().__init__()`:**
2020

2121
```python
@@ -81,6 +81,34 @@ Requirements:
8181
- `super().__init__()` called with `version`, `strategy_class`, `default_strategy`, `default_dataset_config`, `objective_scorer`
8282
- complex objects like `adversarial_chat` or `objective_scorer` should be passed into the constructor.
8383

84+
## Run Parameters
85+
86+
Run-time inputs (target, strategies, dataset config, concurrency, labels, baseline flag) are **not** arguments to `initialize_async`. They flow through a single parameter bag (`self.params`), populated by `set_params_from_args` from the merged CLI / config / programmatic arguments. `initialize_async` takes no arguments and reads everything from the bag:
87+
88+
```python
89+
scenario.set_params_from_args(args={"objective_target": target, "max_concurrency": 8})
90+
await scenario.initialize_async()
91+
```
92+
93+
The base `Scenario` declares the common run inputs once in `_common_scenario_parameters()`: `objective_target` (a `RegistryReference` — resolved by name or supplied as an instance), the `opaque` live objects `scenario_strategies` / `strategy_converters` / `dataset_config` / `memory_labels` (passed by identity, never coerced or deep-copied), and the scalars `max_concurrency` / `max_retries` / `include_baseline`.
94+
95+
### Declaring custom parameters — add via `additional_parameters`
96+
97+
The base `Scenario` composes `supported_parameters()` as `_common_scenario_parameters() + additional_parameters()`. To add your own parameters, override **`additional_parameters()`** and return just your extras — the common inputs are included for you, so there's no `super()` call to forget:
98+
99+
```python
100+
@classmethod
101+
def additional_parameters(cls) -> list[Parameter]:
102+
return [
103+
Parameter(name="max_turns", description="...", param_type=int, default=5),
104+
]
105+
```
106+
107+
- **Add (common case):** override `additional_parameters` and return `[Parameter(...)]`
108+
- **Remove / replace a common input (rare):** override `supported_parameters` directly and compose against `super()`, e.g. `return [p for p in super().supported_parameters() if p.name != "dataset_config"]`
109+
110+
Dropping a common input is not silent: `set_params_from_args` rejects any value supplied for an undeclared parameter, so the registry/CLI/programmatic path fails loudly. If a scenario resolves its strategies differently (e.g. pairing attacks with converters), override the `_resolve_scenario_strategies` hook rather than `initialize_async` (see `RedTeamAgent`).
111+
84112
## Dataset Loading
85113

86114
Datasets are read from `CentralMemory`.
@@ -272,6 +300,8 @@ New scenarios must be registered in `pyrit/scenario/__init__.py` as virtual pack
272300
## Common Review Issues
273301

274302
- Accessing `self._objective_target` or `self._scenario_strategies` before `initialize_async()`
303+
- Overriding `supported_parameters()` without composing against `super()` (silently drops the common run inputs)
304+
- Adding arguments back onto `initialize_async` instead of declaring them via `supported_parameters()` and reading from `self.params`
275305
- Forgetting `@apply_defaults` on `__init__`
276306
- Empty `seed_groups` passed to `AtomicAttack`
277307
- Missing `VERSION` class constant

doc/code/registry/1_class_registry.ipynb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@
137137
"encoding_class = registry.get_class(\"garak.encoding\")\n",
138138
"scenario = encoding_class() # type: ignore\n",
139139
"\n",
140-
"# Pass dataset configuration to initialize_async\n",
141-
"await scenario.initialize_async(objective_target=target) # type: ignore\n",
140+
"# Set the objective target, then initialize\n",
141+
"scenario.set_params_from_args(args={\"objective_target\": target}) # type: ignore\n",
142+
"await scenario.initialize_async() # type: ignore\n",
142143
"\n",
143144
"# Option 2: Use create_instance() shortcut\n",
144145
"# scenario = registry.create_instance(\"garak.encoding\", objective_target=my_target, ...)\n",

doc/code/registry/1_class_registry.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@
5656
encoding_class = registry.get_class("garak.encoding")
5757
scenario = encoding_class() # type: ignore
5858

59-
# Pass dataset configuration to initialize_async
60-
await scenario.initialize_async(objective_target=target) # type: ignore
59+
# Set the objective target, then initialize
60+
scenario.set_params_from_args(args={"objective_target": target}) # type: ignore
61+
await scenario.initialize_async() # type: ignore
6162

6263
# Option 2: Use create_instance() shortcut
6364
# scenario = registry.create_instance("garak.encoding", objective_target=my_target, ...)

0 commit comments

Comments
 (0)