Skip to content
Draft
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
11 changes: 1 addition & 10 deletions pyrit/backend/mappers/attack_mappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,6 @@ def request_piece_to_pyrit_message_piece(
role: ChatMessageRole,
conversation_id: str,
sequence: int,
labels: Optional[dict[str, str]] = None,
) -> PyritMessagePiece:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just verifying; this is after labels are on AttackResult right?

"""
Convert a single request piece DTO to a PyRIT MessagePiece domain object.
Expand All @@ -422,7 +421,6 @@ def request_piece_to_pyrit_message_piece(
role: The message role.
conversation_id: The conversation/attack ID.
sequence: The message sequence number.
labels: Optional labels to attach to the piece.

Returns:
PyritMessagePiece domain object.
Expand All @@ -442,7 +440,6 @@ def request_piece_to_pyrit_message_piece(
conversation_id=conversation_id,
sequence=sequence,
prompt_metadata=metadata,
labels=labels or {},
original_prompt_id=original_prompt_id,
)

Expand All @@ -452,7 +449,6 @@ def request_to_pyrit_message(
request: AddMessageRequest,
conversation_id: str,
sequence: int,
labels: Optional[dict[str, str]] = None,
) -> PyritMessage:
"""
Build a PyRIT Message from an AddMessageRequest DTO.
Expand All @@ -461,18 +457,13 @@ def request_to_pyrit_message(
request: The inbound API request.
conversation_id: The conversation/attack ID.
sequence: The message sequence number.
labels: Optional labels to attach to each piece.

Returns:
PyritMessage ready to send to the target.
"""
pieces = [
request_piece_to_pyrit_message_piece(
piece=p,
role=request.role,
conversation_id=conversation_id,
sequence=sequence,
labels=labels,
piece=p, role=request.role, conversation_id=conversation_id, sequence=sequence
)
for p in request.pieces
]
Expand Down
13 changes: 0 additions & 13 deletions pyrit/backend/services/attack_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,6 @@ async def create_attack_async(self, *, request: CreateAttackRequest) -> CreateAt
conversation_id = self._duplicate_conversation_up_to(
source_conversation_id=request.source_conversation_id,
cutoff_index=request.cutoff_index,
labels_override=labels,
remap_assistant_to_simulated=True,
)
else:
Expand Down Expand Up @@ -319,7 +318,6 @@ async def create_attack_async(self, *, request: CreateAttackRequest) -> CreateAt
await self._store_prepended_messages(
conversation_id=conversation_id,
prepended=request.prepended_conversation,
labels=labels,
)

return CreateAttackResponse(
Expand Down Expand Up @@ -802,7 +800,6 @@ def _duplicate_conversation_up_to(
*,
source_conversation_id: str,
cutoff_index: int,
labels_override: Optional[dict[str, str]] = None,
remap_assistant_to_simulated: bool = False,
) -> str:
"""
Expand All @@ -815,9 +812,6 @@ def _duplicate_conversation_up_to(
Args:
source_conversation_id: The conversation to copy from.
cutoff_index: Include messages with sequence <= cutoff_index.
labels_override: When provided, the duplicated pieces' labels are
replaced with these values. Used when branching into a new
attack that belongs to a different operator.
remap_assistant_to_simulated: When True, pieces with role
``assistant`` are changed to ``simulated_assistant`` so the
branched context is inert and won't confuse the target.
Expand All @@ -832,8 +826,6 @@ def _duplicate_conversation_up_to(

# Apply optional overrides to the fresh pieces before persisting
for piece in all_pieces:
if labels_override is not None:
piece.labels = dict(labels_override)
if remap_assistant_to_simulated and piece.api_role == "assistant":
piece._role = "simulated_assistant"

Expand Down Expand Up @@ -924,7 +916,6 @@ async def _store_prepended_messages(
self,
conversation_id: str,
prepended: list[Any],
labels: Optional[dict[str, str]] = None,
) -> None:
"""Store prepended conversation messages in memory."""
for seq, msg in enumerate(prepended):
Expand All @@ -934,7 +925,6 @@ async def _store_prepended_messages(
role=msg.role,
conversation_id=conversation_id,
sequence=seq,
labels=labels,
)
self._memory.add_message_pieces_to_memory(message_pieces=[piece])

Expand All @@ -960,7 +950,6 @@ async def _send_and_store_message_async(
request=request,
conversation_id=conversation_id,
sequence=sequence,
labels=labels,
)

converter_configs = self._get_converter_configs(request)
Expand All @@ -971,7 +960,6 @@ async def _send_and_store_message_async(
target=target_obj,
conversation_id=conversation_id,
request_converter_configurations=converter_configs,
labels=labels,
)
# PromptNormalizer stores both request and response in memory automatically

Expand All @@ -991,7 +979,6 @@ async def _store_message_only_async(
role=request.role,
conversation_id=conversation_id,
sequence=sequence,
labels=labels,
)
self._memory.add_message_pieces_to_memory(message_pieces=[piece])

Expand Down
2 changes: 0 additions & 2 deletions pyrit/executor/attack/component/conversation_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ def get_adversarial_chat_messages(
conversation_id=adversarial_chat_conversation_id,
attack_identifier=attack_identifier,
prompt_target_identifier=adversarial_chat_target_identifier,
labels=labels,
)

result.append(adversarial_piece.to_message())
Expand Down Expand Up @@ -260,7 +259,6 @@ def set_system_prompt(
system_prompt=system_prompt,
conversation_id=conversation_id,
attack_identifier=self._attack_identifier,
labels=labels,
)

async def initialize_context_async(
Expand Down
1 change: 0 additions & 1 deletion pyrit/executor/attack/multi_turn/chunked_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,6 @@ async def _perform_async(self, *, context: ChunkedRequestAttackContext) -> Attac
conversation_id=context.session.conversation_id,
request_converter_configurations=self._request_converters,
response_converter_configurations=self._response_converters,
labels=context.memory_labels,
attack_identifier=self.get_identifier(),
)

Expand Down
3 changes: 0 additions & 3 deletions pyrit/executor/attack/multi_turn/crescendo.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,6 @@ async def _setup_async(self, *, context: CrescendoAttackContext) -> None:
system_prompt=system_prompt,
conversation_id=context.session.adversarial_chat_conversation_id,
attack_identifier=self.get_identifier(),
labels=context.memory_labels,
)

# Initialize backtrack count in context
Expand Down Expand Up @@ -534,7 +533,6 @@ async def _send_prompt_to_adversarial_chat_async(
conversation_id=context.session.adversarial_chat_conversation_id,
target=self._adversarial_chat,
attack_identifier=self.get_identifier(),
labels=context.memory_labels,
)

if not response:
Expand Down Expand Up @@ -620,7 +618,6 @@ async def _send_prompt_to_objective_target_async(
request_converter_configurations=self._request_converters,
response_converter_configurations=self._response_converters,
attack_identifier=self.get_identifier(),
labels=context.memory_labels,
)

if not response:
Expand Down
1 change: 0 additions & 1 deletion pyrit/executor/attack/multi_turn/multi_prompt_sending.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,6 @@ async def _send_prompt_to_objective_target_async(
conversation_id=context.session.conversation_id,
request_converter_configurations=self._request_converters,
response_converter_configurations=self._response_converters,
labels=context.memory_labels, # combined with strategy labels at _setup()
attack_identifier=self.get_identifier(),
)

Expand Down
3 changes: 0 additions & 3 deletions pyrit/executor/attack/multi_turn/red_teaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,6 @@ async def _setup_async(self, *, context: MultiTurnAttackContext[Any]) -> None:
system_prompt=adversarial_system_prompt,
conversation_id=context.session.adversarial_chat_conversation_id,
attack_identifier=self.get_identifier(),
labels=context.memory_labels,
)

async def _perform_async(self, *, context: MultiTurnAttackContext[Any]) -> AttackResult:
Expand Down Expand Up @@ -379,7 +378,6 @@ async def _generate_next_prompt_async(self, context: MultiTurnAttackContext[Any]
conversation_id=context.session.adversarial_chat_conversation_id,
target=self._adversarial_chat,
attack_identifier=self.get_identifier(),
labels=context.memory_labels,
)

# Check if the response is valid
Expand Down Expand Up @@ -543,7 +541,6 @@ async def _send_prompt_to_objective_target_async(
request_converter_configurations=self._request_converters,
response_converter_configurations=self._response_converters,
target=self._objective_target,
labels=context.memory_labels,
attack_identifier=self.get_identifier(),
)

Expand Down
4 changes: 0 additions & 4 deletions pyrit/executor/attack/multi_turn/tree_of_attacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,6 @@ async def _send_prompt_to_target_async(self, prompt: str) -> Message:
response_converter_configurations=self._response_converters,
conversation_id=self.objective_target_conversation_id,
target=self._objective_target,
labels=self._memory_labels,
attack_identifier=self._attack_id,
)

Expand Down Expand Up @@ -596,7 +595,6 @@ async def _send_initial_prompt_to_target_async(self) -> Message:
response_converter_configurations=self._response_converters,
conversation_id=self.objective_target_conversation_id,
target=self._objective_target,
labels=self._memory_labels,
attack_identifier=self._attack_id,
)

Expand Down Expand Up @@ -982,7 +980,6 @@ async def _generate_first_turn_prompt_async(self, objective: str) -> str:
system_prompt=system_prompt,
conversation_id=self.adversarial_chat_conversation_id,
attack_identifier=self._attack_id,
labels=self._memory_labels,
)

logger.debug(f"Node {self.node_id}: Using initial seed prompt for first turn")
Expand Down Expand Up @@ -1107,7 +1104,6 @@ async def _send_to_adversarial_chat_async(self, prompt_text: str) -> str:
message=message,
conversation_id=self.adversarial_chat_conversation_id,
target=self._adversarial_chat,
labels=self._memory_labels,
attack_identifier=self._attack_id,
)

Expand Down
3 changes: 0 additions & 3 deletions pyrit/executor/attack/single_turn/context_compliance.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,6 @@ async def _get_objective_as_benign_question_async(
message=message,
target=self._adversarial_chat,
attack_identifier=self.get_identifier(),
labels=context.memory_labels,
)

return response.get_value()
Expand All @@ -262,7 +261,6 @@ async def _get_benign_question_answer_async(
message=message,
target=self._adversarial_chat,
attack_identifier=self.get_identifier(),
labels=context.memory_labels,
)

return response.get_value()
Expand All @@ -287,7 +285,6 @@ async def _get_objective_as_question_async(self, *, objective: str, context: Sin
message=message,
target=self._adversarial_chat,
attack_identifier=self.get_identifier(),
labels=context.memory_labels,
)

return response.get_value()
Expand Down
1 change: 0 additions & 1 deletion pyrit/executor/attack/single_turn/prompt_sending.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,6 @@ async def _send_prompt_to_objective_target_async(
conversation_id=context.conversation_id,
request_converter_configurations=self._request_converters,
response_converter_configurations=self._response_converters,
labels=context.memory_labels, # combined with strategy labels at _setup()
attack_identifier=self.get_identifier(),
)

Expand Down
4 changes: 0 additions & 4 deletions pyrit/executor/promptgen/anecdoctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ async def _setup_async(self, *, context: AnecdoctorContext) -> None:
system_prompt=system_prompt,
conversation_id=context.conversation_id,
attack_identifier=self.get_identifier(),
labels=context.memory_labels,
)

async def _perform_async(self, *, context: AnecdoctorContext) -> AnecdoctorResult:
Expand Down Expand Up @@ -305,7 +304,6 @@ async def _send_examples_to_target_async(
conversation_id=context.conversation_id,
request_converter_configurations=self._request_converters,
response_converter_configurations=self._response_converters,
labels=context.memory_labels,
attack_identifier=self.get_identifier(),
)

Expand Down Expand Up @@ -374,7 +372,6 @@ async def _extract_knowledge_graph_async(self, *, context: AnecdoctorContext) ->
system_prompt=kg_system_prompt,
conversation_id=kg_conversation_id,
attack_identifier=self.get_identifier(),
labels=self._memory_labels,
)

# Format examples for knowledge graph extraction using few-shot format
Expand All @@ -390,7 +387,6 @@ async def _extract_knowledge_graph_async(self, *, context: AnecdoctorContext) ->
conversation_id=kg_conversation_id,
request_converter_configurations=self._request_converters,
response_converter_configurations=self._response_converters,
labels=self._memory_labels,
attack_identifier=self.get_identifier(),
)

Expand Down
2 changes: 0 additions & 2 deletions pyrit/executor/workflow/xpia.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@ async def _setup_attack_async(self, *, context: XPIAContext) -> str:
request_converter_configurations=self._request_converters,
response_converter_configurations=self._response_converters,
target=self._attack_setup_target,
labels=context.memory_labels,
attack_identifier=self.get_identifier(),
conversation_id=context.attack_setup_target_conversation_id,
)
Expand Down Expand Up @@ -566,7 +565,6 @@ async def process_async() -> str:
target=self._processing_target,
request_converter_configurations=self._request_converters,
response_converter_configurations=self._response_converters,
labels=context.memory_labels,
attack_identifier=self.get_identifier(),
conversation_id=context.processing_conversation_id,
)
Expand Down
24 changes: 2 additions & 22 deletions pyrit/memory/azure_sql_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from datetime import datetime, timedelta, timezone
from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union

from sqlalchemy import and_, create_engine, event, exists, or_, text
from sqlalchemy import and_, create_engine, event, exists, text
from sqlalchemy.engine.base import Engine
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import InstrumentedAttribute, joinedload, sessionmaker
Expand Down Expand Up @@ -449,7 +449,6 @@ def _get_attack_result_label_condition(self, *, labels: dict[str, str]) -> Any:
Get the SQL Azure implementation for filtering AttackResults by labels.

Matches if the labels are found on the AttackResultEntry directly
OR on an associated PromptMemoryEntry (via conversation_id).

Uses JSON_VALUE() function specific to SQL Azure with parameterized queries.

Expand All @@ -470,30 +469,11 @@ def _get_attack_result_label_condition(self, *, labels: dict[str, str]) -> Any:
ar_bindparams[value_param] = str(value)

ar_combined = " AND ".join(ar_label_conditions)
direct_condition = and_(
return and_(
AttackResultEntry.labels.isnot(None),
text(f'ISJSON("AttackResultEntries".labels) = 1 AND {ar_combined}').bindparams(**ar_bindparams),
)

# --- Conversation-level match on PromptMemoryEntry.labels ---
pme_label_conditions = []
pme_bindparams: dict[str, str] = {}
for key, value in labels.items():
param_name = f"pme_label_{key}"
pme_label_conditions.append(f"JSON_VALUE(labels, '$.{key}') = :{param_name}")
pme_bindparams[param_name] = str(value)

pme_combined = " AND ".join(pme_label_conditions)
conversation_condition = exists().where(
and_(
PromptMemoryEntry.conversation_id == AttackResultEntry.conversation_id,
PromptMemoryEntry.labels.isnot(None),
text(f"ISJSON(labels) = 1 AND {pme_combined}").bindparams(**pme_bindparams),
)
)

return or_(direct_condition, conversation_condition)

def get_unique_attack_class_names(self) -> list[str]:
"""
Azure SQL implementation: extract unique class_name values from
Expand Down
Loading