Conversation
| Each target class defines default capabilities via the _DEFAULT_CAPABILITIES | ||
| class attribute. Users can override individual capabilities per instance | ||
| through constructor parameters, which is useful for targets whose | ||
| capabilities depend on deployment configuration (e.g., Playwright, HTTP). |
There was a problem hiding this comment.
Can we document whether or not _DEFAULT_CAPABILITIES is required for all targets? Since we define an empty one in the PromptTarget base class, this might be a nit since users don't necessarily have to add it to their own targets, but we should be explicit so users adding new targets can do so easily.
Also a nit, I'm also not seeing any tests to ensure all targets have this attribute. We don't necessarily need a regression test but it might be worth adding if we expect most or all targets here to use it
|
|
||
| mock_memory = MagicMock() | ||
| mock_memory.get_conversation.return_value = sample_conversations | ||
| mock_memory.get_message_pieces.return_value = sample_conversations |
| input_modalities: list[PromptDataType] = field(default_factory=lambda: ["text"]) | ||
|
|
||
| # The output modalities supported by the target (e.g., "text", "image"). | ||
| output_modalities: list[PromptDataType] = field(default_factory=lambda: ["text"]) |
There was a problem hiding this comment.
Nit: What do you think about making these into sets? It would be functionally identical but I'm curious if we want to preserve the ordering
| supports_multi_message_pieces: bool = True | ||
|
|
||
| # Whether the target natively supports JSON output (e.g., via a "json" response format). | ||
| supports_json_response: bool = False |
There was a problem hiding this comment.
You likely want to split this to json_schema_support and json_output_support because they're different params. In one you include the schema, in the other you put json=True
| # Whether the target natively supports JSON output (e.g., via a "json" response format). | ||
| supports_json_response: bool = False | ||
|
|
||
| # The input modalities supported by the target (e.g., "text", "image"). |
There was a problem hiding this comment.
We also likely want editable_history; This let's us set the system history that are not actually responses from the target. We use PromptChatTarget for this currently.
| import abc | ||
| from typing import Optional | ||
|
|
||
| from pyrit.identifiers import ComponentIdentifier |
There was a problem hiding this comment.
We can probably deprecate PromptChatTarget and remove it from the inheritence chain, since we should check via prompt capabilities now
There was a problem hiding this comment.
note this may be part of a future PR
| custom_capabilities=custom_capabilities, | ||
| ) | ||
|
|
||
| def set_system_prompt( |
There was a problem hiding this comment.
We should probably get rid of this also. set_system_prompt is error prone and you can always do it with prepended_conversation
There was a problem hiding this comment.
note this may be part of a future PR. We also need to think through how we set the system prompt for things like RealTimeTarget since they are multi-turn, you can set the system prompt, but you can't edit the history.
| self._underlying_model = underlying_model | ||
| self._capabilities = capabilities if capabilities is not None else type(self)._DEFAULT_CAPABILITIES | ||
| self._capabilities = ( | ||
| custom_capabilities if custom_capabilities is not None else type(self)._DEFAULT_CAPABILITIES |
| # The input modalities supported by the target (e.g., "text", "image"). | ||
| input_modalities: list[PromptDataType] = field(default_factory=lambda: ["text"]) | ||
|
|
||
| # The output modalities supported by the target (e.g., "text", "image"). | ||
| output_modalities: list[PromptDataType] = field(default_factory=lambda: ["text"]) |
There was a problem hiding this comment.
I worry about this a little. You have multi-piece and input modalities, but just because an endpoint supports text and image and video and multiple pieces doesn't mean it supports all combinations of those, right?
It might just accept text+image and text+video, but not all three together, or not image+video.
A solution to this would be to drop the multi-piece support field, and instead make input and output modalities of type set[set[PromptDataType]] (set because the order is irrelevant and we can check membership in constant time (although complexity is hardly an issue here). I think @fitzpr's PR #1383 has this as sets of sets if you want an idea.
Wdyt? Did you consider this and decide it's not good for some reason? I might be missing some cases because I haven't spent as much time on it.
| self._model_name = model_name | ||
| self._underlying_model = underlying_model | ||
| self._capabilities = capabilities if capabilities is not None else type(self)._DEFAULT_CAPABILITIES | ||
| self._capabilities = ( |
There was a problem hiding this comment.
self._capabilities is defined here but the later changes reference self.capabilities?
|
|
||
| return ComponentIdentifier.of(self, params=all_params, children=children) | ||
|
|
||
| def is_json_response_supported(self) -> bool: |
There was a problem hiding this comment.
I think we should remove the methods like this (and supports_multi_turn, etc, and just have people validate using the capabilities property.
| f"This target supports only the following data types: {supported_types}. Received: {piece_type}." | ||
| ) | ||
|
|
||
| if not self.supports_multi_turn: |
There was a problem hiding this comment.
self.capabilities.supports_multi_turn? Right now, we have a convenience property for this but not some of the others. Since we have a bunch now, we could just get rid of it?
| supports_multi_turn: bool = False | ||
|
|
||
| # Whether the target natively supports multiple message pieces in a single request. | ||
| supports_multi_message_pieces: bool = True |
There was a problem hiding this comment.
I might default to the least capable; supports_multi_message_pieces = False
|
|
||
| """ | ||
|
|
||
| _DEFAULT_CAPABILITIES: TargetCapabilities = TargetCapabilities( |
There was a problem hiding this comment.
Similarly, without knowing the endpoint, it might make sense to make this restrictive. It depends on the type of openai endpoint which modalities and json support it has.
| from the actual model. If not provided, `model_name` will be used for the identifier. | ||
| Defaults to None. | ||
| capabilities (TargetCapabilities, Optional): Override the default capabilities for | ||
| custom_capabilities (TargetCapabilities, Optional): Override the default capabilities for |
There was a problem hiding this comment.
I wonder if we could have a mapping of known default capabilities here, or potentially retrieved from a list in target_capabilites class.
if underlying_model == "gpt-5.1":
_default = X
elif ...
There was a problem hiding this comment.
We also talked about a method to discover these which I think will be useful. But the defaults we know could go a long way early on :)
| _DEFAULT_CAPABILITIES: TargetCapabilities = TargetCapabilities(supports_multi_turn=False) | ||
| _DEFAULT_CAPABILITIES: TargetCapabilities = TargetCapabilities( | ||
| supports_multi_turn=False, | ||
| input_modalities=["text", "image_path"], |
There was a problem hiding this comment.
Depends, many only support input_modality text. If we go the route of most restrictive, that'd be the default.
| Initialize the image target with specified parameters. | ||
|
|
||
| Args: | ||
| model_name (str, Optional): The name of the model (or deployment name in Azure). |
There was a problem hiding this comment.
Should we keep the doc helpers here?
|
|
||
| Args: | ||
| custom_functions: Mapping of user-defined function names (e.g., "my_func"). | ||
| model_name (str, Optional): The name of the model (or deployment name in Azure). |
There was a problem hiding this comment.
I think re-adding these doc strings?
| SUPPORTED_DATA_TYPES = {"text", "image_path"} | ||
| _DEFAULT_CAPABILITIES: TargetCapabilities = TargetCapabilities(supports_multi_turn=True) | ||
| _DEFAULT_CAPABILITIES: TargetCapabilities = TargetCapabilities( | ||
| supports_multi_turn=True, |
There was a problem hiding this comment.
maybe only minimal since it's generic?
| interaction_func: InteractionFunction, | ||
| page: "Page", | ||
| max_requests_per_minute: Optional[int] = None, | ||
| capabilities: Optional[TargetCapabilities] = None, |
There was a problem hiding this comment.
custom_capabilities here?
| is_json_supported: bool = True, | ||
| audio_response_config: Optional[OpenAIChatAudioConfig] = None, | ||
| extra_body_parameters: Optional[dict[str, Any]] = None, | ||
| custom_capabilities: Optional[TargetCapabilities] = None, |
There was a problem hiding this comment.
why don't we expose this param in other prompt target child classes?
| class OpenAITTSTarget(OpenAITarget): | ||
| """A prompt target for OpenAI Text-to-Speech (TTS) endpoints.""" | ||
|
|
||
| _DEFAULT_CAPABILITIES: TargetCapabilities = TargetCapabilities(supports_multi_turn=False) |
There was a problem hiding this comment.
does this support multi turn now?
Description
This PR builds on #1433 to expand the TargetCapabilities class and consolidate the logic in Targets to use the TargetCapabilities class rather than misc variables. This is the first of at least 2 more PRs which will allow users to query target capabilities and add validation to attacks, converters, scorers, etc which have requirements for targets.
TargetCapabilitiesdataclass — expanded fields:supports_multi_turn(existing)supports_multi_message_pieces— rejects messages with >1 piece whenFalsesupports_json_response— whether JSON response format is supportedinput_modalities— allowed input data types (text, image_path, audio_path, …)output_modalities— produced output data typesAdded
assert_satisfies()to validate oneTargetCapabilitiesagainst another. This will be useful later when validating whether a target satisfies the requirements of an attack / scorer / converterPromptTarget._validate_request()— converted from abstract to a concrete baseimplementation that auto-enforces capabilities:
supports_multi_message_pieces=Falseconverted_value_data_typeagainstinput_modalitiessupports_multi_turn=FalseAll ad-hoc inline validation in individual targets was deleted.
Renamed constructor param
capabilities→custom_capabilities.Added
is_json_response_supported()delegating tocapabilities.supports_json_response.Per-target
_DEFAULT_CAPABILITIESdeclarations added/updated:OpenAIChatTargetOpenAICompletionTargetsupports_multi_message_pieces=FalseOpenAITTSTargetOpenAIImageTargetOpenAIVideoTargetRealtimeTargetPlaywrightTargetPlaywrightCopilotTargetWebSocketCopilotTargetPromptShieldTargetHuggingFaceChatTargetCrucibleTargetTests and Documentation
test_target_capabilities.pycovering modality declarations,assert_satisfies, and per-target defaultstest_supports_multi_turn.pyextended with constructor override testspytest.raiseserror message patterns updated to the new unified formatget_conversation→get_message_piecespatch_central_databasefixture added to HTTP target tests that were missing it