BUG: multimodal router drops media metadata when forwarding seeds and responses
I maintainer di solito rispondono entro 2 giorni
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 35/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Ferma
- Stack tecnologico
- python
- Ambito
- backend-api-design
Direzione di ricerca
Start with pyrit/executor/attack/component/modality_router.py, especially _ModalityFeedbackRouter._build_multimodal_message(), and inspect how it creates media pieces from converted values. Read the message formatting helper and existing modality router tests, then run the focused tests. Done means all three forwarding paths retain the agreed media metadata, transient metadata is handled as specified, and tests confirm source metadata is unchanged and copied metadata is independently owned.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Describe the bug
_ModalityFeedbackRouter._build_multimodal_message() creates fresh media pieces from each source piece's converted_value and converted_value_data_type, but discards its prompt_metadata entirely.
This affects media forwarded from a seed to the adversarial chat, from an objective response to the adversarial chat, and from an objective response into the next objective request. For example, a media piece's context_description is lost. format_message_piece_for_context() reads this metadata when formatting non-text content, so the copied piece produces only a generic modality placeholder instead of retaining its description.
Related: #3301 and #3302 concern fill_adversarial_placeholders(). This is a separate follow-up for the shared multimodal builder; that builder is unchanged by #3302. The router was introduced in #1377.
The converted media payload is already forwarded correctly. This issue is not asking to change that behavior or make the builder preserve the previous turn's original/converted lineage wholesale.
Steps/Code to Reproduce
Run in a PyRIT environment. No files, providers, credentials, or database initialization are needed.
from unittest.mock import MagicMock
from pyrit.executor.attack.component.modality_router import _ModalityFeedbackRouter
from pyrit.message_normalizer._helpers import format_message_piece_for_context
from pyrit.models import Message, MessagePiece
from pyrit.prompt_target import PromptTarget
from pyrit.prompt_target.common.target_capabilities import TargetCapabilities
from pyrit.prompt_target.common.target_configuration import TargetConfiguration
def target():
mocked = MagicMock(spec=PromptTarget)
mocked.configuration = TargetConfiguration(
capabilities=TargetCapabilities(
input_modalities=frozenset({
frozenset({"text"}),
frozenset({"text", "image_path"}),
})
)
)
return mocked
router = _ModalityFeedbackRouter(
adversarial_chat=target(), objective_target=target()
)
media = MessagePiece(
role="assistant",
original_value="source.png",
original_value_data_type="image_path",
converted_value="resized.png",
converted_value_data_type="image_path",
prompt_metadata={"context_description": "A blue square"},
)
response = media.to_message()
seed = Message(message_pieces=[
MessagePiece.adversarial_placeholder(),
media.model_copy(update={"role": "user"}),
])
print("source:", format_message_piece_for_context(piece=media))
forwarded_messages = {
"adversarial response": router.build_adversarial_input_message(
text="feedback", last_response=response
),
"adversarial seed": router.build_adversarial_input_message(
text="feedback", last_response=None, seed_message=seed
),
"objective response": router.build_objective_input_message(
text="edit", last_response=response, turn_index=1
),
}
for direction, message in forwarded_messages.items():
copied = message.get_piece(1)
print(direction, copied.converted_value, copied.prompt_metadata,
format_message_piece_for_context(piece=copied))
Expected Results
Media-scoped metadata that is still meaningful for the forwarded payload, such as context_description, survives forwarding. The copied media still points to resized.png, and formatting it retains [Image_path - A blue square].
Define the metadata-copying contract explicitly rather than blindly carrying previous-request or response-only state into a fresh request. Preserve independent ownership of mutable metadata and fresh message-piece/conversation IDs.
Add regression coverage for seed-to-adversarial forwarding and response forwarding in both directions, including source immutability and the treatment of transient metadata.
Actual Results
source: [Image_path - A blue square]
adversarial response resized.png {} [Image_path]
adversarial seed resized.png {} [Image_path]
objective response resized.png {} [Image_path]
The converted value survives, but the media copy's metadata is empty in all three paths. The source piece's metadata is unchanged.
Screenshots
N/A. This is an SDK/message-construction issue.
Versions
- OS: Windows 11.
- Browser: N/A.
- Python: 3.14.4.
- PyRIT: 1.2.0.dev0, editable checkout at
5343d3075e5b0a0abc91ee90413d6833e4e0ab26(PR #3302). The affected builder is unchanged from its basef4fb86808c41210a164b2c8983c10919c051e7a1. - Reproduced offline through all three public routing paths.
pyrit.show_versions() output, with the local executable path omitted:
System:
python: 3.14.4 (main, Apr 14 2026, 14:30:57) [MSC v.1944 64 bit (AMD64)]
machine: Windows-11-10.0.26300-SP0
Python dependencies:
pyrit: 1.2.0.dev0
Cython: None
numpy: 2.4.6
openai: 2.54.0
packaging: 25.0
pip: None
scipy: 1.17.1
setuptools: 84.0.0
sqlite3: None
torch: None
transformers: 5.19.0
- Lingua principale
- Python
- Stelle
- 4.6k
- Fork
- 962
- Merge medio
- 2g 16h
- PR unite (30g)
- 354
Preparare l'ambiente
Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Nessuna guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di microsoft/PyRIT
-
Bug: triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 2 giorni
-
BUG: Video scorers block the event loop while decoding frames and audioForse già presa @Shizoqua l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 35/100
I maintainer di solito rispondono entro 2 giorni
-
BUG: HTTPTarget turns CRLF into LF in the request bodyForse già presa @nniiovoo l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 25/100
I maintainer di solito rispondono entro 2 giorni
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
I maintainer di solito rispondono entro 2 giorni
-
Bug: triage
Difficoltà 3/5 1-2 giorni Idoneità per principianti 57/100
I maintainer di solito rispondono entro 2 giorni
Tutte le issue di microsoft/PyRIT
Issue simili
-
good first issue tools
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
bug deferred domain:ci P1
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 1 giorno
-
get_page_thumbnail modifies cached page images, affecting later thumbnails and picture exportsAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
docling-project/docling-mcp#147 ·
-
issue: A pipe model's Valves button ignores the Allow Chat Valves permissionForse già presa Una pull request collegata a questa issue è aperta o già unita. Apertabug confirmed issue
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
open-webui/open-webui#32771 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Scheduled Security Scan is failing on mainForse già presa @pkupt l’ha presa oggi. Apertasecurity-scan-failure
Difficoltà 1/5 1-3 ore Idoneità per principianti 74/100
semantica-agi/semantica#2045 ·
I maintainer di solito rispondono entro 2 giorni