diff --git a/.github/instructions/style-guide.instructions.md b/.github/instructions/style-guide.instructions.md index 42fdab3315..45b702c54e 100644 --- a/.github/instructions/style-guide.instructions.md +++ b/.github/instructions/style-guide.instructions.md @@ -192,6 +192,33 @@ def calculate_score( """ ``` +### Code references in docstrings + +The PyRIT docs build uses **MyST** (Markdown-flavoured), not reStructuredText. +Do **not** use reST cross-reference roles in docstrings or module comments — +they render as raw text under MyST and are inconsistent with the rest of the +codebase, which uses plain double-backtick code spans for symbol names. + +```python +# WRONG — reST roles render as literal `:class:\`SeedPrompt\`` under MyST +"""Returns a :class:`SeedPrompt` instance.""" +"""Delegate to :func:`download_files_async` (deprecated alias).""" +"""See :meth:`PromptTarget.apply_capabilities` for details.""" + +# CORRECT — plain double-backtick code span (matches existing convention) +"""Returns a ``SeedPrompt`` instance.""" +"""Delegate to ``download_files_async`` (deprecated alias).""" +"""See ``PromptTarget.apply_capabilities`` for details.""" +``` + +Roles to avoid include `:class:`, `:func:`, `:meth:`, `:mod:`, `:attr:`, +`:data:`, `:exc:`, `:obj:`, `:ref:`, and any `:py:*:` variants +(e.g. `:py:class:`, `:py:func:`). + +If you genuinely need a Sphinx cross-reference (rare in PyRIT — most +docstrings just name the symbol in backticks), use the MyST role syntax +`` {class}`Name` `` instead. The default, though, is plain double-backticks. + ### Class-Level Constants - Define constants as class attributes, not module-level - Use UPPER_CASE naming for constants @@ -454,6 +481,7 @@ Before committing code, ensure: - [ ] All functions have complete type annotations - [ ] Functions with >1 parameter use keyword-only arguments - [ ] Docstrings include parameter types +- [ ] Docstrings use plain double-backtick code spans for symbol references (no reST roles) - [ ] Enums are used instead of Literals - [ ] Functions are focused and under 20 lines - [ ] Error messages are helpful and specific diff --git a/pyrit/auth/azure_auth.py b/pyrit/auth/azure_auth.py index 31b267230c..c5076ed581 100644 --- a/pyrit/auth/azure_auth.py +++ b/pyrit/auth/azure_auth.py @@ -443,10 +443,10 @@ async def get_speech_config_async( """ Get the speech config, resolving a callable token provider if one is provided. - This is the async counterpart to :func:`get_speech_config`. When a callable + This is the async counterpart to ``get_speech_config``. When a callable ``token_provider`` is supplied, it is invoked (and awaited if async) to obtain a token, which is then used with the ``aad#{resource_id}#{token}`` auth format. - Otherwise, it delegates to the synchronous :func:`get_speech_config`. + Otherwise, it delegates to the synchronous ``get_speech_config``. Args: token_provider (Callable | None): An optional sync or async callable that returns a token string. diff --git a/pyrit/common/data_url_converter.py b/pyrit/common/data_url_converter.py index 1e3e52f87b..fe7c31ae84 100644 --- a/pyrit/common/data_url_converter.py +++ b/pyrit/common/data_url_converter.py @@ -47,7 +47,7 @@ async def convert_local_image_to_data_url_async(image_path: str) -> str: async def convert_local_image_to_data_url(image_path: str) -> str: """ - Delegate to :func:`convert_local_image_to_data_url_async` (deprecated alias). + Delegate to ``convert_local_image_to_data_url_async`` (deprecated alias). Returns: str: A string containing the MIME type and the base64-encoded data of the image, formatted as a data URL. diff --git a/pyrit/common/display_response.py b/pyrit/common/display_response.py index be60649a72..9ec5036c75 100644 --- a/pyrit/common/display_response.py +++ b/pyrit/common/display_response.py @@ -58,7 +58,7 @@ async def display_image_response_async(response_piece: MessagePiece) -> None: async def display_image_response(response_piece: MessagePiece) -> None: - """Delegate to :func:`display_image_response_async` (deprecated alias).""" + """Delegate to ``display_image_response_async`` (deprecated alias).""" print_deprecation_message( old_item="pyrit.common.display_response.display_image_response", new_item="pyrit.common.display_response.display_image_response_async", diff --git a/pyrit/common/download_hf_model.py b/pyrit/common/download_hf_model.py index 0699737e2a..c34ccb7aaf 100644 --- a/pyrit/common/download_hf_model.py +++ b/pyrit/common/download_hf_model.py @@ -129,7 +129,7 @@ async def download_with_limit_async(url: str) -> None: async def download_specific_files(model_id: str, file_patterns: list[str] | None, token: str, cache_dir: Path) -> None: - """Delegate to :func:`download_specific_files_async` (deprecated alias).""" + """Delegate to ``download_specific_files_async`` (deprecated alias).""" print_deprecation_message( old_item="pyrit.common.download_hf_model.download_specific_files", new_item="pyrit.common.download_hf_model.download_specific_files_async", @@ -140,7 +140,7 @@ async def download_specific_files(model_id: str, file_patterns: list[str] | None async def download_chunk(url: str, headers: dict[str, str], start: int, end: int, client: httpx.AsyncClient) -> bytes: """ - Delegate to :func:`download_chunk_async` (deprecated alias). + Delegate to ``download_chunk_async`` (deprecated alias). Returns: The content of the downloaded chunk. @@ -154,7 +154,7 @@ async def download_chunk(url: str, headers: dict[str, str], start: int, end: int async def download_file(url: str, token: str, download_dir: Path, num_splits: int) -> None: - """Delegate to :func:`download_file_async` (deprecated alias).""" + """Delegate to ``download_file_async`` (deprecated alias).""" print_deprecation_message( old_item="pyrit.common.download_hf_model.download_file", new_item="pyrit.common.download_hf_model.download_file_async", @@ -166,7 +166,7 @@ async def download_file(url: str, token: str, download_dir: Path, num_splits: in async def download_files( urls: list[str], token: str, download_dir: Path, num_splits: int = 3, parallel_downloads: int = 4 ) -> None: - """Delegate to :func:`download_files_async` (deprecated alias).""" + """Delegate to ``download_files_async`` (deprecated alias).""" print_deprecation_message( old_item="pyrit.common.download_hf_model.download_files", new_item="pyrit.common.download_hf_model.download_files_async", diff --git a/pyrit/prompt_converter/add_text_image_converter.py b/pyrit/prompt_converter/add_text_image_converter.py index 04cc069d68..759a649942 100644 --- a/pyrit/prompt_converter/add_text_image_converter.py +++ b/pyrit/prompt_converter/add_text_image_converter.py @@ -23,7 +23,7 @@ class AddTextImageConverter(_BaseImageTextConverter): """ Adds a string to an image and wraps the text into multiple lines if necessary. - This class is similar to :class:`AddImageTextConverter` except + This class is similar to ``AddImageTextConverter`` except we pass in text as an argument to the constructor as opposed to an image file path. """ diff --git a/pyrit/prompt_converter/azure_speech_audio_to_text_converter.py b/pyrit/prompt_converter/azure_speech_audio_to_text_converter.py index a2506684ed..a03699e2a1 100644 --- a/pyrit/prompt_converter/azure_speech_audio_to_text_converter.py +++ b/pyrit/prompt_converter/azure_speech_audio_to_text_converter.py @@ -176,7 +176,7 @@ def recognize_audio(self, audio_bytes: bytes) -> str: Recognize audio file and return transcribed text. .. deprecated:: - Use :meth:`convert_async` instead, which resolves token providers correctly. + Use ``convert_async`` instead, which resolves token providers correctly. This method does not support callable token providers. Args: diff --git a/pyrit/prompt_target/common/discover_target_capabilities.py b/pyrit/prompt_target/common/discover_target_capabilities.py index 859d07d428..45600e6009 100644 --- a/pyrit/prompt_target/common/discover_target_capabilities.py +++ b/pyrit/prompt_target/common/discover_target_capabilities.py @@ -6,14 +6,14 @@ This module exposes two complementary probes: -* :func:`_discover_capability_flags_async` discovers the boolean capability flags - defined on :class:`TargetCapabilities` (e.g. ``supports_system_prompt``, +* ``_discover_capability_flags_async`` discovers the boolean capability flags + defined on ``TargetCapabilities`` (e.g. ``supports_system_prompt``, ``supports_multi_message_pieces``). For each capability that has a probe defined, a minimal request is sent to the target. If the request succeeds, the capability is included in the returned set. Capabilities without a registered probe fall back to the target's declared native support from ``target.capabilities``. -* :func:`_discover_input_modalities_async` discovers which input modality +* ``_discover_input_modalities_async`` discovers which input modality combinations a target actually supports by sending a minimal test request for each combination declared in ``TargetCapabilities.input_modalities``. @@ -120,7 +120,7 @@ def _permissive_configuration( Temporarily replace ``target``'s configuration with one that declares every boolean capability as natively supported. - This bypasses :meth:`PromptTarget._validate_request`, which would otherwise + This bypasses ``PromptTarget._validate_request``, which would otherwise short-circuit probes for capabilities the target declares as unsupported before any API call is made. The original configuration is restored on exit. @@ -182,9 +182,9 @@ def _probe_metadata(extra: dict[str, str | int] | None = None) -> dict[str, str def _user_text_piece(*, value: str, conversation_id: str) -> MessagePiece: """ - Build a single user-role text :class:`MessagePiece` for use in a probe. + Build a single user-role text ``MessagePiece`` for use in a probe. - The piece's ``prompt_metadata`` is tagged with :data:`PROBE_METADATA_KEY` + The piece's ``prompt_metadata`` is tagged with ``PROBE_METADATA_KEY`` so that consumers aggregating memory can filter out probe-written rows. Args: @@ -229,7 +229,7 @@ async def _send_and_check_async( retries (int): Number of additional attempts after the first failure. Only transient errors are retried; non-retryable errors and non-error responses are final. Retry attempts use exponential - backoff starting at :data:`DEFAULT_PROBE_RETRY_BACKOFF_SECONDS`. + backoff starting at ``DEFAULT_PROBE_RETRY_BACKOFF_SECONDS``. Defaults to 1. label (str): Short label used in log messages. Defaults to ``"Capability probe"``. @@ -291,8 +291,8 @@ async def _probe_system_prompt_async(target: PromptTarget, timeout_s: float, ret """ Probe whether ``target`` accepts a system prompt followed by a user message. - Writes a system-role :class:`MessagePiece` directly to ``target._memory`` - rather than calling :meth:`pyrit.prompt_target.PromptChatTarget.set_system_prompt` + Writes a system-role ``MessagePiece`` directly to ``target._memory`` + rather than calling ``pyrit.prompt_target.PromptChatTarget.set_system_prompt`` (which is only defined on ``PromptChatTarget`` subclasses anyway). ``set_system_prompt`` can be overridden by subclasses (e.g. mocks) to do nothing or to perform extra work, which would mask whether the underlying @@ -526,10 +526,10 @@ async def _discover_capability_flags_async( Args: target (PromptTarget): The target to probe. capabilities (Iterable[CapabilityName] | None): Capabilities to check. - Defaults to every member of :class:`CapabilityName`. + Defaults to every member of ``CapabilityName``. per_probe_timeout_s (float): Per-attempt timeout (seconds) applied to each probe request. Defaults to - :data:`DEFAULT_PROBE_TIMEOUT_SECONDS`. + ``DEFAULT_PROBE_TIMEOUT_SECONDS``. retries (int): Number of additional attempts after the first failure for each probe. Only exceptions/timeouts are retried; an explicit error response is final. Set to ``0`` to disable retries. @@ -593,7 +593,7 @@ async def _discover_capability_flags_async( # Default mapping of non-text modalities to packaged probe assets. Callers can # override via the ``test_assets`` parameter of -# :func:`_discover_input_modalities_async`. Modalities whose assets do not exist +# ``_discover_input_modalities_async``. Modalities whose assets do not exist # on disk are skipped (logged and excluded from the result). DEFAULT_TEST_ASSETS: dict[PromptDataType, str] = { "audio_path": str(_TARGET_CAPABILITIES_DATASET_PATH / "probe_audio.wav"), @@ -622,11 +622,11 @@ async def _discover_input_modalities_async( declared in ``target.capabilities.input_modalities``. test_assets (dict[PromptDataType, str] | None): Mapping from non-text modality to a file path used as the probe payload. - Defaults to :data:`DEFAULT_TEST_ASSETS`. Combinations whose + Defaults to ``DEFAULT_TEST_ASSETS``. Combinations whose non-text assets are missing on disk are skipped. per_probe_timeout_s (float): Per-attempt timeout (seconds) applied to each probe request. Defaults to - :data:`DEFAULT_PROBE_TIMEOUT_SECONDS`. + ``DEFAULT_PROBE_TIMEOUT_SECONDS``. retries (int): Number of additional attempts after the first failure for each probe. Only exceptions/timeouts are retried; an explicit error response is final. Set to ``0`` to disable retries. @@ -685,7 +685,7 @@ async def discover_target_capabilities_async( """ Probe both the boolean capability flags and the input modality combinations that ``target`` accepts, and return a merged best-effort - :class:`TargetCapabilities`. + ``TargetCapabilities``. Boolean capabilities with a registered probe are checked with live requests; capabilities without a probe fall back to the target's @@ -704,17 +704,17 @@ async def discover_target_capabilities_async( the target's declared support. test_assets (dict[PromptDataType, str] | None): Mapping from non-text modality to a file path used as the probe payload. Defaults to - :data:`DEFAULT_TEST_ASSETS`. Combinations whose non-text assets + ``DEFAULT_TEST_ASSETS``. Combinations whose non-text assets are missing on disk are skipped. capabilities (Iterable[CapabilityName] | None): Capabilities to probe. - Defaults to every member of :class:`CapabilityName`. Capabilities + Defaults to every member of ``CapabilityName``. Capabilities not listed here fall back to the target's declared support. retries (int): Number of additional attempts after the first failure for each probe. Only exceptions/timeouts are retried; an explicit error response is final. Set to ``0`` to disable retries. Defaults to 1. apply (bool): If True, install the discovered capabilities on ``target`` - via :meth:`PromptTarget.apply_capabilities` before returning. + via ``PromptTarget.apply_capabilities`` before returning. Probe results are an upper bound (the request was accepted, not necessarily honored), so leave this False when you want to inspect or diff the result before committing to it. Defaults to False. @@ -790,7 +790,7 @@ def _create_test_message( test_assets: dict[PromptDataType, str], ) -> Message: """ - Build a minimal :class:`Message` that exercises ``modalities``. + Build a minimal ``Message`` that exercises ``modalities``. Args: modalities (frozenset[PromptDataType]): The modalities to include. diff --git a/pyrit/prompt_target/common/prompt_chat_target.py b/pyrit/prompt_target/common/prompt_chat_target.py index 88ee1c824d..2ee028450c 100644 --- a/pyrit/prompt_target/common/prompt_chat_target.py +++ b/pyrit/prompt_target/common/prompt_chat_target.py @@ -13,12 +13,12 @@ class PromptChatTarget(PromptTarget): """ .. deprecated:: 0.14.0 ``PromptChatTarget`` is deprecated and will be removed in v0.16.0. Use - :class:`PromptTarget` directly with a ``TargetConfiguration`` declaring + ``PromptTarget`` directly with a ``TargetConfiguration`` declaring ``supports_multi_turn=True`` and ``supports_editable_history=True``. - Backwards-compatible alias for :class:`PromptTarget`. All chat-target functionality - (``set_system_prompt``, ``is_response_format_json``) lives on :class:`PromptTarget`. - Subclassing or instantiating this class emits a :class:`DeprecationWarning`. + Backwards-compatible alias for ``PromptTarget``. All chat-target functionality + (``set_system_prompt``, ``is_response_format_json``) lives on ``PromptTarget``. + Subclassing or instantiating this class emits a ``DeprecationWarning``. """ _DEFAULT_CONFIGURATION: TargetConfiguration = TargetConfiguration( diff --git a/pyrit/prompt_target/common/prompt_target.py b/pyrit/prompt_target/common/prompt_target.py index 461af0e03b..b1ee5caaa2 100644 --- a/pyrit/prompt_target/common/prompt_target.py +++ b/pyrit/prompt_target/common/prompt_target.py @@ -94,11 +94,11 @@ async def send_prompt_async(self, *, message: Message) -> list[Message]: 1. Validates the message, fetches the conversation from memory, appends ``message``, and runs the normalization pipeline (system‑squash, history‑squash, etc.). 2. Validates the normalized conversation against the target's capabilities. - 3. Delegates to :meth:`_send_prompt_to_target_async` with the normalized + 3. Delegates to ``_send_prompt_to_target_async`` with the normalized conversation. Subclasses MUST NOT override this method. Override - :meth:`_send_prompt_to_target_async` instead. + ``_send_prompt_to_target_async`` instead. Args: message (Message): The message to send. @@ -121,7 +121,7 @@ async def _send_prompt_to_target_async(self, *, normalized_conversation: list[Me """ Target-specific send logic. - Called by :meth:`send_prompt_async` after validation and normalization. + Called by ``send_prompt_async`` after validation and normalization. Args: normalized_conversation (list[Message]): The full conversation @@ -263,7 +263,7 @@ def set_system_prompt( If the target does not natively support system prompts, whether this call is ultimately honored depends on the target's - :class:`CapabilityHandlingPolicy`: + ``CapabilityHandlingPolicy``: * ``ADAPT`` — the normalization pipeline (e.g. system squash) will fold the system message into user content on the wire. @@ -388,7 +388,7 @@ def apply_capabilities(self, *, capabilities: TargetCapabilities) -> None: Policy is preserved because it expresses user intent (ADAPT vs RAISE), independent of what the probe found. To change policy or normalizer - overrides, build a new :class:`TargetConfiguration` and pass it via + overrides, build a new ``TargetConfiguration`` and pass it via ``custom_configuration`` at construction time instead. Note: diff --git a/pyrit/prompt_target/common/target_configuration.py b/pyrit/prompt_target/common/target_configuration.py index 72ca42fcc1..7e11a04673 100644 --- a/pyrit/prompt_target/common/target_configuration.py +++ b/pyrit/prompt_target/common/target_configuration.py @@ -135,9 +135,9 @@ async def normalize_async(self, *, messages: list[Message]) -> list[Message]: def as_identifier_params(self) -> dict[str, Any]: """ Return a deterministic, serializable representation of this configuration - suitable for inclusion in a :class:`ComponentIdentifier`. + suitable for inclusion in a ``ComponentIdentifier``. - The returned dict preserves the structure of :class:`TargetConfiguration` + The returned dict preserves the structure of ``TargetConfiguration`` — capabilities, policy, and pipeline are kept as nested sub-dicts rather than flattened into the caller — so the identifier reflects the shape of the object it describes. @@ -174,8 +174,8 @@ def as_identifier_params(self) -> dict[str, Any]: @staticmethod def _capabilities_to_identifier_params(capabilities: TargetCapabilities) -> dict[str, Any]: """ - Project a :class:`TargetCapabilities` instance into a deterministic dict - suitable for inclusion in a :class:`ComponentIdentifier`. + Project a ``TargetCapabilities`` instance into a deterministic dict + suitable for inclusion in a ``ComponentIdentifier``. Fields are discovered dynamically via ``dataclasses.fields`` so new capability fields are picked up automatically. Set-valued fields (e.g., diff --git a/pyrit/prompt_target/common/target_requirements.py b/pyrit/prompt_target/common/target_requirements.py index 8d13f100d9..cee74c1a5a 100644 --- a/pyrit/prompt_target/common/target_requirements.py +++ b/pyrit/prompt_target/common/target_requirements.py @@ -20,14 +20,14 @@ class TargetRequirements: requires from a target. The single source of truth for capability names is the - :class:`CapabilityName` enum; this class is simply a typed wrapper + ``CapabilityName`` enum; this class is simply a typed wrapper around the set of capabilities a consumer needs. Two tiers of requirement are supported: * ``required`` \u2014 satisfied either by native support on the target or by an ``ADAPT`` entry in the target's - :class:`CapabilityHandlingPolicy`. Use this when the consumer only + ``CapabilityHandlingPolicy``. Use this when the consumer only needs the behavior to appear on the wire. * ``native_required`` \u2014 must be natively supported. Adaptation is rejected. Use this when adaptation would silently change the @@ -38,7 +38,7 @@ class TargetRequirements: Modality requirements are also supported: * ``required_input_modalities`` — each entry is a frozenset of - :class:`PromptDataType` values the consumer needs the target to + ``PromptDataType`` values the consumer needs the target to accept. At least one of the target's input modality combos must be a superset of each required combo. * ``required_output_modalities`` — same semantics for outputs. diff --git a/pyrit/registry/object_registries/attack_technique_registry.py b/pyrit/registry/object_registries/attack_technique_registry.py index 55e15a02e9..8d67dcea35 100644 --- a/pyrit/registry/object_registries/attack_technique_registry.py +++ b/pyrit/registry/object_registries/attack_technique_registry.py @@ -177,7 +177,7 @@ def build_strategy_class_from_specs( - Additional aggregate members from ``aggregate_tags`` keys. - One technique member per spec, with tags from the spec. - Each aggregate maps to a :class:`TagQuery` that determines which + Each aggregate maps to a ``TagQuery`` that determines which technique specs belong to it. This reads from the **spec list** (pure data), not from the mutable @@ -186,7 +186,7 @@ def build_strategy_class_from_specs( Args: class_name: Name for the generated enum class. specs: Technique specifications to include as enum members. - aggregate_tags: Maps aggregate member names to a :class:`TagQuery` + aggregate_tags: Maps aggregate member names to a ``TagQuery`` that selects which techniques belong to the aggregate. An ``ALL`` aggregate (expanding to all techniques) is always added. diff --git a/pyrit/registry/tag_query.py b/pyrit/registry/tag_query.py index 9959105166..ec4aa866eb 100644 --- a/pyrit/registry/tag_query.py +++ b/pyrit/registry/tag_query.py @@ -59,8 +59,8 @@ class TagQuery: against a tag set directly. Composite queries are produced by the ``&`` and ``|`` operators and stored in ``_op`` / ``_children``. - Prefer the classmethod shortcuts :meth:`all`, :meth:`any_of`, and - :meth:`exclude` for single-field leaves. + Prefer the classmethod shortcuts ``all``, ``any_of``, and + ``exclude`` for single-field leaves. Args: include_all: Tags that must **all** be present (AND). diff --git a/pyrit/scenario/scenarios/benchmark/adversarial.py b/pyrit/scenario/scenarios/benchmark/adversarial.py index dfec12839c..cf6a99293b 100644 --- a/pyrit/scenario/scenarios/benchmark/adversarial.py +++ b/pyrit/scenario/scenarios/benchmark/adversarial.py @@ -89,7 +89,7 @@ def __init__( Args: adversarial_models: A non-empty list of ``PromptTarget`` instances - that each satisfy :data:`CHAT_TARGET_REQUIREMENTS` (multi-turn + that each satisfy ``CHAT_TARGET_REQUIREMENTS`` (multi-turn with editable history). Individual techniques selected at run time may impose stricter capability requirements which are enforced when their attack instances are constructed. @@ -106,7 +106,7 @@ def __init__( Raises: ValueError: If ``adversarial_models`` is empty, not a list, or contains a target that does not satisfy - :data:`CHAT_TARGET_REQUIREMENTS`. + ``CHAT_TARGET_REQUIREMENTS``. """ if not adversarial_models: raise ValueError("adversarial_models must be a non-empty list of PromptTarget instances.") diff --git a/pyrit/show_versions.py b/pyrit/show_versions.py index 301faebdd7..5f44c71eae 100644 --- a/pyrit/show_versions.py +++ b/pyrit/show_versions.py @@ -4,7 +4,7 @@ """ Utility methods to print system info for debugging. -Adapted from :py:func:`pandas.show_versions` and :py:func:`sklearn.show_versions`. +Adapted from ``pandas.show_versions`` and ``sklearn.show_versions``. """ import platform diff --git a/tests/unit/mocks.py b/tests/unit/mocks.py index 50c07547f4..e09c5f0758 100644 --- a/tests/unit/mocks.py +++ b/tests/unit/mocks.py @@ -66,7 +66,7 @@ def get_mock_attack_identifier(name: str = "MockAttack", module: str = "tests.un def get_mock_target(name: str = "MockTarget") -> MagicMock: """ Returns a MagicMock target whose ``get_identifier()`` returns a real - :class:`ComponentIdentifier`. Use this wherever a ``MagicMock(spec=PromptTarget)`` + ``ComponentIdentifier``. Use this wherever a ``MagicMock(spec=PromptTarget)`` is needed as an ``objective_target``. Args: diff --git a/tests/unit/prompt_target/test_discover_target_capabilities.py b/tests/unit/prompt_target/test_discover_target_capabilities.py index e21f24a6f2..d483edea6b 100644 --- a/tests/unit/prompt_target/test_discover_target_capabilities.py +++ b/tests/unit/prompt_target/test_discover_target_capabilities.py @@ -799,7 +799,7 @@ class TestVerifyTargetAsync: async def test_returns_target_capabilities_assembled_from_probes(self) -> None: """ ``discover_target_capabilities_async`` runs both the capability and modality probes - and assembles a :class:`TargetCapabilities` populated from the + and assembles a ``TargetCapabilities`` populated from the queried results, copying ``output_modalities`` from the target's declared capabilities and deriving editable history conservatively. """