Repository navigation
FEAT: Support nested and multiple conversion markers - #3002
Merged
Richard Lundeen (richlundeen) merged 5 commits intoOct 6, 2026
Merged
Richard Lundeen (richlundeen) merged 5 commits into
Richard Lundeen (richlundeen) merged 5 commits into
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
varunj-msft
approved these changes
Oct 5, 2026
Preserve upstream request limits alongside configurable converter markers. Replace common ASCII documentation markers with longer delimiters and cover reply redirection and prompt syntax. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Richard Lundeen (richlundeen)
enabled auto-merge
October 6, 2026 17:05
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 6, 2026
Update the selective-conversion guide with executable local examples and acknowledge Utkarsh Bahuguna (u7k4rs6) for the original marker-preservation work. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Utkarsh Bahuguna <85474312+u7k4rs6@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Richard Lundeen (richlundeen)
enabled auto-merge
October 6, 2026 19:00
Richard Lundeen (richlundeen)
deleted the
richlundeen-nested-conversion-markers
branch
October 6, 2026 19:51
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
Support nested and multiple marked text regions across direct converter calls, attack pipelines, API previews, and GUI editing. Each stage transforms all innermost regions and leaves surrounding text unchanged. Consuming stages remove the selected pairs; outer pairs remain for later stages. Once no markers remain, later converters retain the existing whole-value behavior.
For Translate to French -> Base64 -> ROT13, three layers keep the instruction prefix unchanged through all three stages:
Add
keep_tokens=Falsetoconvert_tokens_async. Direct callers can retain each selected pair withTrue; unmarked text results are wrapped, while non-text outputs remain unchanged.SelectiveTextConverteruses the same shared retention logic throughpreserve_tokens. Native token wrappers that select the same region retain one boundary pair rather than adding duplicate layers. Explicit input nesting and separate selections remain intact.Preserve selective-subclass
convert_asyncoverrides, including subclasses that callsuper(). Resolve nested selections using the active per-call marker pair, not constructor defaults. A per-call text callback reuses the shared parser without storing mutable call state on converter instances. Seeded conversion and concurrent calls with different markers are covered.Keep older custom
convert_tokens_asyncoverrides callable without new arguments when preservation is disabled. Unsupported preservation raises before invoking the override instead of bypassing it or wrapping unselected text. Request and response APIs accept custom markers, and the normalizer rejects empty markers at construction. Longer ASCII examples document the risk of marker collisions in target replies.The GUI supports selections inside existing regions or around complete regions, rejects partial boundary crossings, and keeps all marker characters visible. Its selection button retains the Unicode defaults. Preconverted pieces are sent unchanged without rerunning request converters.
Tests and Documentation
Rewrite the paired selective-conversion guide as a credential-free, executable first-read tutorial. It covers marked text, direct
keep_tokenscalls, preserving chains, explicit nesting, programmatic selection, attack wiring, custom markers, wrapper composition, and compatibility limits. Include an executed mixed-marker example. All 26 paired cell sources match, and eleven cells retain their executed outputs.Add regressions for top-level selective subclasses,
super()delegation, inherited selection, custom token overrides, subclass random scopes, active-marker composition, and concurrent mixed-marker calls. Existing tests cover multiple regions, empty/multiline input, generated marker text, media outputs, API persistence, and single-/multi-turn attacks.Validation from the repository root:
$env:UV_NO_SYNC='1'; uv run --no-sync pre-commit run --all-files— passed all 18 hooks after notebook metadata and path normalization.uv run --no-sync pytest tests\unit\converter\test_converter.py tests\unit\converter\test_selective_text_converter.py tests\unit\common\test_random_context.py tests\unit\backend\test_converter_service.py::TestPreviewConversion tests\unit\backend\test_message_send_service.py::TestNormalizerPersistence tests\unit\executor\attack\single_turn\test_prompt_sending.py::test_attack_marker_pipelines_cover_history_request_response_async tests\unit\executor\attack\multi_turn\test_multi_prompt_sending.py::test_attack_marker_pipelines_cover_multiple_messages_async tests\unit\prompt_normalizer\test_prompt_normalizer.py -q— 402 passed.uv run --no-sync jupytext --to ipynb --execute --set-kernel python3 doc\code\converters\6_selectively_converting.py— passed; all code examples executed locally without LLM credentials and outputs are retained.git diff --check— passed.The affected GUI suites passed earlier (69 tests), along with the frontend type check. Full unit and integration suites were not run locally.