From 9e3ee3059c16a13feec9d3e855987cc077d27e35 Mon Sep 17 00:00:00 2001 From: Roman Lutz Date: Sun, 22 Feb 2026 04:49:11 -0800 Subject: [PATCH 1/5] Deprecate Gradio-based GUI and HumanInTheLoopConverter in favor of CoPyRIT Add deprecation warnings (removed in v0.13.0) to: - HumanInTheLoopScorerGradio - HumanInTheLoopConverter - pyrit.ui module Add placeholder doc page for CoPyRIT (React-based GUI) and register it in the TOC. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- doc/_toc.yml | 1 + doc/code/gui/0_gui.md | 27 +++++++++++++++++++ .../human_in_the_loop_converter.py | 11 ++++++++ pyrit/score/human/human_in_the_loop_gradio.py | 11 ++++++++ pyrit/ui/__init__.py | 8 ++++++ 5 files changed, 58 insertions(+) create mode 100644 doc/code/gui/0_gui.md diff --git a/doc/_toc.yml b/doc/_toc.yml index 75f77d7fbe..0845047cf3 100644 --- a/doc/_toc.yml +++ b/doc/_toc.yml @@ -139,6 +139,7 @@ chapters: sections: - file: code/registry/1_class_registry - file: code/registry/2_instance_registry + - file: code/gui/0_gui - file: code/front_end/0_front_end sections: - file: code/front_end/1_pyrit_scan diff --git a/doc/code/gui/0_gui.md b/doc/code/gui/0_gui.md new file mode 100644 index 0000000000..174f70d9e0 --- /dev/null +++ b/doc/code/gui/0_gui.md @@ -0,0 +1,27 @@ +# PyRIT GUI (CoPyRIT) + +CoPyRIT is a web-based graphical interface for PyRIT built with React and Fluent UI. It provides an interactive way to run attacks, configure targets and converters, and view results — all from a browser. + +> **Note:** The older Gradio-based GUI (`HumanInTheLoopScorerGradio`) and the `HumanInTheLoopConverter` are deprecated and will be removed in v0.13.0. CoPyRIT covers a much broader part of the user journey — from attack creation and converter configuration to attack history and result analysis — making these limited interactive components obsolete. + +## Getting Started + +There are several ways to run CoPyRIT: + +### PyRIT Backend CLI + +If you have PyRIT installed, use the `pyrit_backend` command to start the server. The bundled frontend is served automatically. + +```bash +pyrit_backend +``` + +Then open `http://localhost:8000` in your browser. + +### Docker + +CoPyRIT is also available as a Docker container. See the [Docker setup](https://github.com/Azure/PyRIT/blob/main/docker/) for details. + +### Azure Deployment + +Azure-hosted deployment is planned for the near future. diff --git a/pyrit/prompt_converter/human_in_the_loop_converter.py b/pyrit/prompt_converter/human_in_the_loop_converter.py index 2494972428..7e55ed0330 100644 --- a/pyrit/prompt_converter/human_in_the_loop_converter.py +++ b/pyrit/prompt_converter/human_in_the_loop_converter.py @@ -4,6 +4,7 @@ import logging from typing import Optional +from pyrit.common.deprecation import print_deprecation_message from pyrit.identifiers import ConverterIdentifier from pyrit.models import PromptDataType from pyrit.prompt_converter.prompt_converter import ConverterResult, PromptConverter @@ -17,6 +18,10 @@ class HumanInTheLoopConverter(PromptConverter): Users can choose to send the prompt as is, modify the prompt, or run the prompt through one of the passed-in converters before sending it. + + .. deprecated:: + This converter is deprecated and will be removed in v0.13.0. + Use the React-based GUI (CoPyRIT) instead. """ SUPPORTED_INPUT_TYPES = ("text",) @@ -32,6 +37,12 @@ def __init__( Args: converters (List[PromptConverter], Optional): List of possible converters to run input through. """ + print_deprecation_message( + old_item="HumanInTheLoopConverter", + new_item="the React-based GUI (CoPyRIT); see https://azure.github.io/PyRIT/code/gui/0_gui.html", + removed_in="0.13.0", + ) + self._converters = converters or [] def _build_identifier(self) -> ConverterIdentifier: diff --git a/pyrit/score/human/human_in_the_loop_gradio.py b/pyrit/score/human/human_in_the_loop_gradio.py index 05031bd9bb..3da4df16d0 100644 --- a/pyrit/score/human/human_in_the_loop_gradio.py +++ b/pyrit/score/human/human_in_the_loop_gradio.py @@ -4,6 +4,7 @@ import asyncio from typing import Optional +from pyrit.common.deprecation import print_deprecation_message from pyrit.identifiers import ScorerIdentifier from pyrit.models import MessagePiece, Score from pyrit.score.scorer_prompt_validator import ScorerPromptValidator @@ -19,6 +20,10 @@ class HumanInTheLoopScorerGradio(TrueFalseScorer): Create scores from manual human input using Gradio and adds them to the database. In the future this will not be a TrueFalseScorer. However, it is all that is supported currently. + + .. deprecated:: + This Gradio-based scorer is deprecated and will be removed in v0.13.0. + Use the React-based GUI instead. """ _DEFAULT_VALIDATOR: ScorerPromptValidator = ScorerPromptValidator(supported_data_types=["text"]) @@ -40,6 +45,12 @@ def __init__( score_aggregator (TrueFalseAggregatorFunc): Aggregator for combining scores. Defaults to TrueFalseScoreAggregator.OR. """ + print_deprecation_message( + old_item="HumanInTheLoopScorerGradio (Gradio-based GUI)", + new_item="the React-based GUI (CoPyRIT); see https://azure.github.io/PyRIT/code/gui/0_gui.html", + removed_in="0.13.0", + ) + # Import here to avoid importing rpyc in the main module that might not be installed from pyrit.ui.rpc import AppRPCServer diff --git a/pyrit/ui/__init__.py b/pyrit/ui/__init__.py index b14b47650e..931d2b6a83 100644 --- a/pyrit/ui/__init__.py +++ b/pyrit/ui/__init__.py @@ -1,2 +1,10 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT license. + +from pyrit.common.deprecation import print_deprecation_message + +print_deprecation_message( + old_item="pyrit.ui module (Gradio-based GUI)", + new_item="the React-based GUI (CoPyRIT); see https://azure.github.io/PyRIT/code/gui/0_gui.html", + removed_in="0.13.0", +) From 8a272eb198a15af945f1652dfcb5f1c0f20f7f63 Mon Sep 17 00:00:00 2001 From: Roman Lutz Date: Mon, 23 Feb 2026 13:25:14 -0800 Subject: [PATCH 2/5] Add deprecation banners to HITL notebooks Add deprecation warning banners to the Human in the Loop converter and scorer notebooks indicating removal in PyRIT v0.13.0 and directing users to the React-based GUI (CoPyRIT). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- doc/code/converters/7_human_converter.ipynb | 3 +++ doc/code/converters/7_human_converter.py | 3 +++ doc/code/scoring/5_human_in_the_loop_scorer.ipynb | 3 +++ doc/code/scoring/5_human_in_the_loop_scorer.py | 3 +++ 4 files changed, 12 insertions(+) diff --git a/doc/code/converters/7_human_converter.ipynb b/doc/code/converters/7_human_converter.ipynb index 4107b20e97..b55646d515 100644 --- a/doc/code/converters/7_human_converter.ipynb +++ b/doc/code/converters/7_human_converter.ipynb @@ -5,6 +5,9 @@ "id": "0", "metadata": {}, "source": [ + "> ⚠️ **Deprecated:** The `HumanInTheLoopConverter` is deprecated and will be removed in PyRIT v0.13.0.\n", + "> Use the React-based GUI (CoPyRIT) instead. See the [GUI documentation](../gui/0_gui.md) for details.\n", + "\n", "# 7. Human in the Loop Converter\n", "\n", "The Human in the Loop Converter allows a user to review each prompt before sending it to a target, allowing for closer moderation of multi-turn conversations.\n", diff --git a/doc/code/converters/7_human_converter.py b/doc/code/converters/7_human_converter.py index ea67c61ad6..9da06433af 100644 --- a/doc/code/converters/7_human_converter.py +++ b/doc/code/converters/7_human_converter.py @@ -9,6 +9,9 @@ # --- # %% [markdown] +# > ⚠️ **Deprecated:** The `HumanInTheLoopConverter` is deprecated and will be removed in PyRIT v0.13.0. +# > Use the React-based GUI (CoPyRIT) instead. See the [GUI documentation](../gui/0_gui.md) for details. +# # # 7. Human in the Loop Converter # # The Human in the Loop Converter allows a user to review each prompt before sending it to a target, allowing for closer moderation of multi-turn conversations. diff --git a/doc/code/scoring/5_human_in_the_loop_scorer.ipynb b/doc/code/scoring/5_human_in_the_loop_scorer.ipynb index a7aee337dc..6026d49cd3 100644 --- a/doc/code/scoring/5_human_in_the_loop_scorer.ipynb +++ b/doc/code/scoring/5_human_in_the_loop_scorer.ipynb @@ -5,6 +5,9 @@ "id": "0", "metadata": {}, "source": [ + "> ⚠️ **Deprecated:** The `HumanInTheLoopScorerGradio` is deprecated and will be removed in PyRIT v0.13.0.\n", + "> Use the React-based GUI (CoPyRIT) instead. See the [GUI documentation](../gui/0_gui.md) for details.\n", + "\n", "# 5. Human in the Loop Scoring with Gradio\n", "This example shows how to use the Gradio UI to perform human-in-the-loop scoring. This is in beta but will be extended." ] diff --git a/doc/code/scoring/5_human_in_the_loop_scorer.py b/doc/code/scoring/5_human_in_the_loop_scorer.py index 9cc6f6e035..e8abf47a12 100644 --- a/doc/code/scoring/5_human_in_the_loop_scorer.py +++ b/doc/code/scoring/5_human_in_the_loop_scorer.py @@ -10,6 +10,9 @@ # --- # %% [markdown] +# > ⚠️ **Deprecated:** The `HumanInTheLoopScorerGradio` is deprecated and will be removed in PyRIT v0.13.0. +# > Use the React-based GUI (CoPyRIT) instead. See the [GUI documentation](../gui/0_gui.md) for details. +# # # 5. Human in the Loop Scoring with Gradio # This example shows how to use the Gradio UI to perform human-in-the-loop scoring. This is in beta but will be extended. From 6c722d2c090a6f95518f8fcdff73e023eba9dcf7 Mon Sep 17 00:00:00 2001 From: Roman Lutz Date: Mon, 23 Feb 2026 20:28:12 -0800 Subject: [PATCH 3/5] Fix stale ConverterIdentifier import to ComponentIdentifier Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pyrit/prompt_converter/human_in_the_loop_converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrit/prompt_converter/human_in_the_loop_converter.py b/pyrit/prompt_converter/human_in_the_loop_converter.py index 1b806a0e1e..7b98fa093e 100644 --- a/pyrit/prompt_converter/human_in_the_loop_converter.py +++ b/pyrit/prompt_converter/human_in_the_loop_converter.py @@ -5,7 +5,7 @@ from typing import Optional from pyrit.common.deprecation import print_deprecation_message -from pyrit.identifiers import ConverterIdentifier +from pyrit.identifiers import ComponentIdentifier from pyrit.models import PromptDataType from pyrit.prompt_converter.prompt_converter import ConverterResult, PromptConverter From b551899888818dcb7a5db94a143e0eca3efefedc Mon Sep 17 00:00:00 2001 From: Roman Lutz Date: Mon, 23 Feb 2026 20:53:01 -0800 Subject: [PATCH 4/5] Fix missing ComponentIdentifier import in human_in_the_loop_gradio.py Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pyrit/score/human/human_in_the_loop_gradio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrit/score/human/human_in_the_loop_gradio.py b/pyrit/score/human/human_in_the_loop_gradio.py index 23e802a725..9f01ec4824 100644 --- a/pyrit/score/human/human_in_the_loop_gradio.py +++ b/pyrit/score/human/human_in_the_loop_gradio.py @@ -5,7 +5,7 @@ from typing import Optional from pyrit.common.deprecation import print_deprecation_message -from pyrit.identifiers import ScorerIdentifier +from pyrit.identifiers import ComponentIdentifier from pyrit.models import MessagePiece, Score from pyrit.score.scorer_prompt_validator import ScorerPromptValidator from pyrit.score.true_false.true_false_score_aggregator import ( From 3afc45ea7fec70bbc0e7b8d90fc066b71c1f5b22 Mon Sep 17 00:00:00 2001 From: Roman Lutz Date: Mon, 23 Feb 2026 21:04:50 -0800 Subject: [PATCH 5/5] Fix UnicodeDecodeError in test_converter_documentation on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add encoding='utf-8' to read_text() since deprecation banner contains Unicode characters (⚠️) that fail with default cp1252 on Windows. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/unit/docs/test_converter_documentation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/docs/test_converter_documentation.py b/tests/unit/docs/test_converter_documentation.py index 9a4d1e25c3..8ce34657d3 100644 --- a/tests/unit/docs/test_converter_documentation.py +++ b/tests/unit/docs/test_converter_documentation.py @@ -32,7 +32,7 @@ def get_converters_mentioned_in_notebooks(): if notebook_file.name.startswith("_"): continue - content = notebook_file.read_text() + content = notebook_file.read_text(encoding="utf-8") # Look for converter imports and class names # Pattern 1: from pyrit.prompt_converter import ConverterName