Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 44 additions & 11 deletions doc/code/output/0_output.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,39 @@
"cell_type": "markdown",
"id": "13",
"metadata": {},
"source": [
"## Including Reasoning Summaries\n",
"\n",
"Reasoning-summary output is opt in: the conversation, attack-result, and scenario-result\n",
"helpers hide reasoning by default. For OpenAI Responses targets, PyRIT renders\n",
"provider-generated reasoning summaries exposed by OpenAI, not raw hidden chain-of-thought.\n",
"\n",
"- Pretty output shows the `<reasoning-summary>` and `</reasoning-summary>` tags in subdued gray.\n",
"- Attack Markdown output shows visible escaped `\\<reasoning-summary\\>` and\n",
" `\\</reasoning-summary\\>` tags.\n",
"\n",
"```python\n",
"from pyrit.output import output_attack_async, output_conversation_async, output_scenario_async\n",
"\n",
"# Direct conversation\n",
"await output_conversation_async(messages=conversation, include_reasoning_trace=True)\n",
"\n",
"# Attack result (Pretty or Markdown)\n",
"await output_attack_async(attack_result, include_reasoning_trace=True)\n",
"await output_attack_async(attack_result, format=\"markdown\", include_reasoning_trace=True)\n",
"\n",
"# Existing scenario result (Pretty only)\n",
"await output_scenario_async(scenario_result, include_reasoning_trace=True)\n",
"```\n",
"\n",
"For a scenario, enabling reasoning expands every contained attack result so its summaries\n",
"can be rendered. This can produce verbose output for large scenario runs."
]
},
{
"cell_type": "markdown",
"id": "14",
"metadata": {},
"source": [
"## Printing Scores\n",
"\n",
Expand All @@ -524,7 +557,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "14",
"id": "15",
"metadata": {},
"outputs": [
{
Expand All @@ -551,7 +584,7 @@
},
{
"cell_type": "markdown",
"id": "15",
"id": "16",
"metadata": {},
"source": [
"## Sinks — Redirecting Output\n",
Expand All @@ -565,7 +598,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "16",
"id": "17",
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -604,7 +637,7 @@
},
{
"cell_type": "markdown",
"id": "17",
"id": "18",
"metadata": {},
"source": [
"### Available Sinks\n",
Expand All @@ -621,7 +654,7 @@
},
{
"cell_type": "markdown",
"id": "18",
"id": "19",
"metadata": {},
"source": [
"## Using Printers Directly\n",
Expand All @@ -634,7 +667,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "19",
"id": "20",
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -675,7 +708,7 @@
},
{
"cell_type": "markdown",
"id": "20",
"id": "21",
"metadata": {},
"source": [
"### `render_async` vs `write_async`\n",
Expand All @@ -689,7 +722,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "21",
"id": "22",
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -728,7 +761,7 @@
},
{
"cell_type": "markdown",
"id": "22",
"id": "23",
"metadata": {},
"source": [
"## Architecture Overview\n",
Expand Down Expand Up @@ -785,7 +818,7 @@
},
{
"cell_type": "markdown",
"id": "23",
"id": "24",
"metadata": {},
"source": [
"## Convenience Functions Reference\n",
Expand All @@ -805,7 +838,7 @@
},
{
"cell_type": "markdown",
"id": "24",
"id": "25",
"metadata": {},
"source": [
"## Extending the Printer Module\n",
Expand Down
28 changes: 28 additions & 0 deletions doc/code/output/0_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,34 @@
# print the conversation using the print conversation helper
await output_conversation_async(messages=conversation) # type: ignore

# %% [markdown]
# ## Including Reasoning Summaries
#
# Reasoning-summary output is opt in: the conversation, attack-result, and scenario-result
# helpers hide reasoning by default. For OpenAI Responses targets, PyRIT renders
# provider-generated reasoning summaries exposed by OpenAI, not raw hidden chain-of-thought.
#
# - Pretty output shows the `<reasoning-summary>` and `</reasoning-summary>` tags in subdued gray.
# - Attack Markdown output shows visible escaped `\<reasoning-summary\>` and
# `\</reasoning-summary\>` tags.
#
# ```python
# from pyrit.output import output_attack_async, output_conversation_async, output_scenario_async
#
# # Direct conversation
# await output_conversation_async(messages=conversation, include_reasoning_trace=True)
#
# # Attack result (Pretty or Markdown)
# await output_attack_async(attack_result, include_reasoning_trace=True)
# await output_attack_async(attack_result, format="markdown", include_reasoning_trace=True)
#
# # Existing scenario result (Pretty only)
# await output_scenario_async(scenario_result, include_reasoning_trace=True)
# ```
#
# For a scenario, enabling reasoning expands every contained attack result so its summaries
# can be rendered. This can produce verbose output for large scenario runs.

# %% [markdown]
# ## Printing Scores
#
Expand Down
27 changes: 26 additions & 1 deletion pyrit/output/attack_result/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from abc import abstractmethod

from pyrit.models import AttackOutcome, Message, Score
from pyrit.models import AttackOutcome, AttackResult, Message, Score
from pyrit.output.base import PrinterBase


Expand All @@ -18,6 +18,31 @@ class AttackResultPrinterBase(PrinterBase):
Thin-client implementations can fetch data via REST endpoints.
"""

@abstractmethod
async def render_async(
self,
result: AttackResult,
*,
include_auxiliary_scores: bool = False,
include_pruned_conversations: bool = False,
include_adversarial_conversation: bool = False,
include_reasoning_trace: bool = False,
) -> str:
"""
Render an attack result.

Args:
result (AttackResult): The attack result to render.
include_auxiliary_scores (bool): Whether to include auxiliary scores. Defaults to False.
include_pruned_conversations (bool): Whether to include pruned conversations. Defaults to False.
include_adversarial_conversation (bool): Whether to include the adversarial conversation.
Defaults to False.
include_reasoning_trace (bool): Whether to include reasoning traces. Defaults to False.

Returns:
str: The rendered attack result.
"""

@abstractmethod
async def _get_conversation_async(self, conversation_id: str) -> list[Message]:
"""
Expand Down
Loading