Repository navigation
FIX: persist LLMGenericTextConverter target exchanges through the normalizer - #3795
Open
Aditya Malkar (adimalkar) wants to merge 1 commit into
Open
Aditya Malkar (adimalkar) wants to merge 1 commit into
Aditya Malkar (adimalkar) wants to merge 1 commit into
Conversation
…malizer LLMGenericTextConverter called its converter target directly, so the only persisted piece of the exchange was the system prompt the target writes itself; the request, the response and any retry attempts were lost. - Each attempt is sent through PromptNormalizer.send_prompt_async, which persists the request and the response (or the error response when the target raises). - Each attempt uses its own conversation (with the system prompt set on it), so a retry never replays the failed turn and every attempt is kept. - The target's own error is raised instead of the normalizer's wrapper, so retry_exceptions and callers see the same exception types as before; an empty reply still raises EmptyResponseException. Fixes microsoft#3718
Contributor
Author
|
The one red job ( |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #3718.
LLMGenericTextConverter._send_with_retries_asynccalledself._converter_target.send_prompt_asyncdirectly, so nothing persisted the exchange. Onmain(f3a88daf), with in-memory SQLite and a localMockPromptTarget, aconvert_asynccall leaves one piece in the converter's conversation:['system']. That's the system prompt, which the target writes itself. The request, the response and every retry attempt are lost. With this change the same call persists['system', 'user', 'assistant'].What changed (in
pyrit/converter/llm_generic_text_converter.py)PromptNormalizer.send_prompt_async, which persists the request and the response. When the target raises, the normalizer persists the request and its error response. APromptNormalizeris created per call, so converters can still be constructed before memory is initialized._process_responseand the retry policy stay in the converter.send_json_with_retry_asyncdoes, would drop the retry exchanges the issue asks to keep. Retries sendrequest.duplicate(), so persisted piece IDs stay unique.Exception("Error sending prompt ...") from error. After the failed exchange is persisted, the converter raises the target's own exception, soretry_exceptions(e.g.TranslationConverter's, or a user's(ConnectionError,)) and callers see the same exception types as before. The normalizer turns anEmptyResponseExceptioninto an empty response withresponse_error="empty". The converter raisesEmptyResponseExceptionfor that, instead of returning"".The normalizer records the converter conversation under the current attack-result ID (
get_current_attack_result_id()), as it does for scorer exchanges. Theattack_result_scopedocstring lists converters as one of the conversation creators meant to register that ownership.Tests and Documentation
New tests in
tests/unit/converter/test_generic_llm_converter.pyuse real in-memory SQLite and a localMockPromptTargetsubclass. All five fail onmain.test_convert_async_persists_the_target_exchange: checks the system, user and assistant pieces. The user piece keeps the raw prompt asoriginal_valueand the rendered template asconverted_value.test_each_retry_attempt_is_persisted_in_its_own_conversation: two conversations, each with all three pieces. The target sees only[system, user]on both attempts.test_failed_target_call_is_persisted_and_raises_the_target_error: the originalValueErroris raised, and the request andresponse_error="processing"piece are kept.test_retry_on_target_error_matches_the_unwrapped_error:retry_exceptions=(ConnectionError,)still retries, and both failed exchanges are kept.test_empty_target_response_raises_empty_response_exception: an empty reply still raises, and theresponse_error="empty"piece is kept.Existing converter tests:
patch_central_database(module-levelpytestmark), since the exchange is persisted.response.duplicate()per call instead of one sharedMessageobject, which would collide on primary keys once persisted. A real target builds new pieces for every call.tests/unithas the same failures onmainand on this branch (55 failed / 89 errors locally, alllitellm-dependent or otherwise environmental), plus 5 new passing tests.ruffandty check pyrit(lockfile versions) report nothing new.