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
1 change: 1 addition & 0 deletions frontend/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1347,6 +1347,7 @@ export interface SeedRecord {
parameters: string[] | null
conditions: SeedCondition[] | null
response_json_schema: Record<string, unknown> | null
is_general_technique?: boolean
}

/** Wire shape of one logical example from `GET /api/datasets/seeds`. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

"""
Add is_general_technique flag to SeedPromptEntries.

Existing rows default to False. Downgrading removes the column.

Revision ID: e7a1b3c5d9f0
Revises: c8d3e5f7a901
Create Date: 2026-10-28 00:00:00.000000
"""

from collections.abc import Sequence # noqa: TC003

import sqlalchemy as sa
from alembic import op

revision: str = "e7a1b3c5d9f0"
down_revision: str | None = "c8d3e5f7a901"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
"""Add is_general_technique storage and default existing rows to False."""
with op.batch_alter_table("SeedPromptEntries") as batch_op:
batch_op.add_column(sa.Column("is_general_technique", sa.Boolean(), nullable=False, server_default=sa.false()))


def downgrade() -> None:
"""Remove is_general_technique column."""
with op.batch_alter_table("SeedPromptEntries") as batch_op:
batch_op.drop_column("is_general_technique", mssql_drop_default=True)
42 changes: 42 additions & 0 deletions pyrit/memory/memory_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -4397,6 +4397,7 @@ def _build_seed_filter_conditions(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand All @@ -4409,6 +4410,7 @@ def _build_seed_filter_conditions(

Args:
origin (SeedOrigin | None): Match the recorded ingestion origin.
is_general_technique (bool | None): Match whether the seed represents a general attack technique.
value (str): The value to match. By default this matches by substring; pass exact=True to
require full-string equality instead. If None, all values are returned.
exact (bool): When True, ``value`` is matched by full-string equality rather than substring,
Expand Down Expand Up @@ -4472,6 +4474,9 @@ def _build_seed_filter_conditions(
elif seed_type is not None:
conditions.append(SeedEntry.seed_type == seed_type)

if is_general_technique is not None:
conditions.append(SeedEntry.is_general_technique == is_general_technique)

self._add_list_conditions(
field=SeedEntry.harm_categories, values=harm_categories, conditions=conditions, exact=exact
)
Expand Down Expand Up @@ -4564,6 +4569,7 @@ def _execute_get_seeds(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand All @@ -4573,6 +4579,7 @@ def _execute_get_seeds(

Args:
origin (SeedOrigin | None): Match the recorded ingestion origin.
is_general_technique (bool | None): Match whether the seed represents a general attack technique.
value (str): The value to match by substring. If None, all values are returned.
value_sha256 (Sequence[str] | None): A list of SHA256 hashes of values to match.
If None, all values are returned.
Expand Down Expand Up @@ -4616,6 +4623,7 @@ def _execute_get_seeds(
source=source,
seed_type=seed_type,
origin=origin,
is_general_technique=is_general_technique,
parameters=parameters,
metadata=metadata,
prompt_group_ids=prompt_group_ids,
Expand Down Expand Up @@ -4647,6 +4655,7 @@ def _execute_remove_seeds_from_memory(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand All @@ -4664,6 +4673,7 @@ def _execute_remove_seeds_from_memory(

Args:
origin (SeedOrigin | None): Match the recorded ingestion origin.
is_general_technique (bool | None): Match whether the seed represents a general attack technique.
value (str): The value to match. For the remove methods this defaults to full-string equality
(exact=True) so a short or common value does not delete far more seeds than intended; pass
exact=False to match by substring instead. If None, all values are considered.
Expand Down Expand Up @@ -4718,6 +4728,7 @@ def _execute_remove_seeds_from_memory(
source=source,
seed_type=seed_type,
origin=origin,
is_general_technique=is_general_technique,
parameters=parameters,
metadata=metadata,
prompt_group_ids=prompt_group_ids,
Expand Down Expand Up @@ -4758,6 +4769,7 @@ def _execute_remove_seed_groups_from_memory(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand All @@ -4783,6 +4795,8 @@ def _execute_remove_seed_groups_from_memory(

Args:
origin (SeedOrigin | None): Match origin before expanding to complete groups.
is_general_technique (bool | None): Match whether the seed represents a general attack technique
before expanding to complete groups.
value (str): The value to match. For the remove methods this defaults to full-string equality
(exact=True) so a short or common value does not delete far more seeds than intended; pass
exact=False to match by substring instead. If None, all values are considered.
Expand Down Expand Up @@ -4837,6 +4851,7 @@ def _execute_remove_seed_groups_from_memory(
source=source,
seed_type=seed_type,
origin=origin,
is_general_technique=is_general_technique,
parameters=parameters,
metadata=metadata,
prompt_group_ids=prompt_group_ids,
Expand Down Expand Up @@ -5115,6 +5130,7 @@ def _seed_group_member_key(seed: Seed[Any]) -> str:
"authors": entry.authors or [],
"groups": entry.groups or [],
"source": entry.source,
"is_general_technique": entry.is_general_technique,
},
sort_keys=True,
separators=(",", ":"),
Expand Down Expand Up @@ -5778,6 +5794,7 @@ def _execute_get_seed_groups(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand All @@ -5788,6 +5805,8 @@ def _execute_get_seed_groups(

Args:
origin (SeedOrigin | None): Match origin before expanding to complete groups.
is_general_technique (bool | None, Optional): Match whether the seed represents a general attack technique
before expanding to complete groups.
value (str | None, Optional): The value to match by substring.
value_sha256 (Sequence[str] | None, Optional): SHA256 hash of value to filter seed groups by.
dataset_name (str | None, Optional): Name of the dataset to match exactly.
Expand Down Expand Up @@ -5828,6 +5847,7 @@ def _execute_get_seed_groups(
source=source,
seed_type=seed_type,
origin=origin,
is_general_technique=is_general_technique,
parameters=parameters,
metadata=metadata,
prompt_group_ids=prompt_group_ids,
Expand Down Expand Up @@ -10302,6 +10322,7 @@ def get_seeds(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand Down Expand Up @@ -10330,6 +10351,7 @@ def get_seeds(
source=source,
seed_type=seed_type,
origin=origin,
is_general_technique=is_general_technique,
parameters=parameters,
metadata=metadata,
prompt_group_ids=prompt_group_ids,
Expand All @@ -10351,6 +10373,7 @@ async def get_seeds_async(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand All @@ -10363,6 +10386,7 @@ async def get_seeds_async(

Args:
origin (SeedOrigin | None): Match the recorded ingestion origin.
is_general_technique (bool | None): Match whether the seed represents a general attack technique.
value (str): The value to match by substring. If None, all values are returned.
value_sha256 (Sequence[str] | None): A list of SHA256 hashes of values to match.
If None, all values are returned.
Expand Down Expand Up @@ -10407,6 +10431,7 @@ async def get_seeds_async(
source=source,
seed_type=seed_type,
origin=origin,
is_general_technique=is_general_technique,
parameters=parameters,
metadata=metadata,
prompt_group_ids=prompt_group_ids,
Expand All @@ -10428,6 +10453,7 @@ def remove_seeds_from_memory(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand Down Expand Up @@ -10459,6 +10485,7 @@ def remove_seeds_from_memory(
source=source,
seed_type=seed_type,
origin=origin,
is_general_technique=is_general_technique,
parameters=parameters,
metadata=metadata,
prompt_group_ids=prompt_group_ids,
Expand All @@ -10481,6 +10508,7 @@ async def remove_seeds_from_memory_async(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand All @@ -10498,6 +10526,7 @@ async def remove_seeds_from_memory_async(

Args:
origin (SeedOrigin | None): Match the recorded ingestion origin.
is_general_technique (bool | None): Match whether the seed represents a general attack technique.
value (str): The value to match. For the remove methods this defaults to full-string equality
(exact=True) so a short or common value does not delete far more seeds than intended; pass
exact=False to match by substring instead. If None, all values are considered.
Expand Down Expand Up @@ -10552,6 +10581,7 @@ async def remove_seeds_from_memory_async(
source=source,
seed_type=seed_type,
origin=origin,
is_general_technique=is_general_technique,
parameters=parameters,
metadata=metadata,
prompt_group_ids=prompt_group_ids,
Expand All @@ -10573,6 +10603,7 @@ def remove_seed_groups_from_memory(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand Down Expand Up @@ -10604,6 +10635,7 @@ def remove_seed_groups_from_memory(
source=source,
seed_type=seed_type,
origin=origin,
is_general_technique=is_general_technique,
parameters=parameters,
metadata=metadata,
prompt_group_ids=prompt_group_ids,
Expand All @@ -10626,6 +10658,7 @@ async def remove_seed_groups_from_memory_async(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand All @@ -10651,6 +10684,8 @@ async def remove_seed_groups_from_memory_async(

Args:
origin (SeedOrigin | None): Match origin before expanding to complete groups.
is_general_technique (bool | None): Match whether the seed represents a general attack technique
before expanding to complete groups.
value (str): The value to match. For the remove methods this defaults to full-string equality
(exact=True) so a short or common value does not delete far more seeds than intended; pass
exact=False to match by substring instead. If None, all values are considered.
Expand Down Expand Up @@ -10705,6 +10740,7 @@ async def remove_seed_groups_from_memory_async(
source=source,
seed_type=seed_type,
origin=origin,
is_general_technique=is_general_technique,
parameters=parameters,
metadata=metadata,
prompt_group_ids=prompt_group_ids,
Expand Down Expand Up @@ -10852,6 +10888,7 @@ def get_seed_groups(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand Down Expand Up @@ -10883,6 +10920,7 @@ def get_seed_groups(
source=source,
seed_type=seed_type,
origin=origin,
is_general_technique=is_general_technique,
parameters=parameters,
metadata=metadata,
prompt_group_ids=prompt_group_ids,
Expand All @@ -10905,6 +10943,7 @@ async def get_seed_groups_async(
source: str | None = None,
seed_type: SeedType | None = None,
origin: SeedOrigin | None = None,
is_general_technique: bool | None = None,
parameters: Sequence[str] | None = None,
metadata: dict[str, str | int] | None = None,
prompt_group_ids: Sequence[uuid.UUID] | None = None,
Expand All @@ -10915,6 +10954,8 @@ async def get_seed_groups_async(

Args:
origin (SeedOrigin | None): Match origin before expanding to complete groups.
is_general_technique (bool | None, Optional): Match whether the seed represents a general attack technique
before expanding to complete groups.
value (str | None, Optional): The value to match by substring.
value_sha256 (Sequence[str] | None, Optional): SHA256 hash of value to filter seed groups by.
dataset_name (str | None, Optional): Name of the dataset to match exactly.
Expand Down Expand Up @@ -10954,6 +10995,7 @@ async def get_seed_groups_async(
source=source,
seed_type=seed_type,
origin=origin,
is_general_technique=is_general_technique,
parameters=parameters,
metadata=metadata,
prompt_group_ids=prompt_group_ids,
Expand Down
5 changes: 5 additions & 0 deletions pyrit/memory/memory_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1697,6 +1697,7 @@ class SeedEntry(Base):
String(16), nullable=False, default=SeedOrigin.UNKNOWN.value, server_default="unknown", index=True
)
conditions: Mapped[list[dict[str, Any]] | None] = mapped_column(JSON, nullable=True)
is_general_technique: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, server_default="0")

def __init__(self, *, entry: Seed[Any]) -> None:
"""
Expand Down Expand Up @@ -1730,6 +1731,7 @@ def __init__(self, *, entry: Seed[Any]) -> None:
self.prompt_group_id = entry.prompt_group_id
self.seed_type = seed_type
self.origin = entry.origin.value
self.is_general_technique = bool(entry.is_general_technique)
self.conditions = (
entry.model_dump(mode="json", include={"conditions"})["conditions"] or None
if isinstance(entry, SeedObjective)
Expand Down Expand Up @@ -1856,6 +1858,7 @@ def get_seed_record(self) -> SeedRecord:
parameters=self.parameters,
conditions=self.conditions,
response_json_schema=response_json_schema,
is_general_technique=self.is_general_technique,
)

def get_seed(self) -> SeedPrompt | SeedObjective | SeedSimulatedConversation:
Expand Down Expand Up @@ -1930,6 +1933,7 @@ def get_seed(self) -> SeedPrompt | SeedObjective | SeedSimulatedConversation:
num_turns=config.get("num_turns", 3),
sequence=config.get("sequence", 0),
pyrit_version=config.get("pyrit_version"),
is_general_technique=self.is_general_technique,
**prompt_config,
)
except (OSError, ValueError) as exc:
Expand Down Expand Up @@ -1961,6 +1965,7 @@ def get_seed(self) -> SeedPrompt | SeedObjective | SeedSimulatedConversation:
prompt_group_id=self.prompt_group_id,
sequence=self.sequence or 0,
role=self.role,
is_general_technique=self.is_general_technique,
)


Expand Down
1 change: 1 addition & 0 deletions pyrit/models/seeds/seed_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ class SeedRecord(BaseModel):
parameters: list[str] | None
conditions: ConditionTuple | None
response_json_schema: JsonSchemaDefinition | None
is_general_technique: bool = False
Loading
Loading