Skip to content

FEAT add SATA masking converter - #2404

Open
Alireza Aminzadeh (alireza-aminzadeh) wants to merge 2 commits into
microsoft:mainfrom
alireza-aminzadeh:fix/issue-2354-sata-masking
Open

FEAT add SATA masking converter#2404
Alireza Aminzadeh (alireza-aminzadeh) wants to merge 2 commits into
microsoft:mainfrom
alireza-aminzadeh:fix/issue-2354-sata-masking

Conversation

@alireza-aminzadeh

@alireza-aminzadeh Alireza Aminzadeh (alireza-aminzadeh) commented Aug 17, 2026

Copy link
Copy Markdown

Summary

  • Fixes Add Simple Assistive Task Linkage (SATA) masking technique #2354 by adding the missing SATA mask/word-selection step.
  • Introduces SATAMaskingConverter and a reusable ContentWordSelectionStrategy that selects content words with a deterministic, dependency-free heuristic (no NLTK or POS-tagger download).
  • The converter composes with existing TaskFramingConverter via SATA_TASK_TEMPLATE (the wiki-infill prompt from the SATA paper). It also works with SelectiveTextConverter if you want to apply a different sub-converter to the same word selection.

I chose the dependency-free selector so this stays easy to test and does not add model-data downloads. Feedback welcome if maintainers would rather plug in an optional POS tagger later.

Test plan

  • pytest tests/unit/converter/test_sata_masking_converter.py tests/unit/converter/test_text_selection_strategy.py tests/unit/converter/test_task_framing_converter.py tests/unit/converter/test_selective_text_converter.py tests/unit/docs/test_converter_documentation.py (148 passed)
  • Review the short SATA example in doc/code/converters/1_text_to_text_converters.py
  • Confirm Microsoft CLA is signed on this PR

@alireza-aminzadeh

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Comment thread pyrit/converter/sata_masking_converter.py Outdated
Comment thread pyrit/converter/sata_masking_converter.py Outdated
Build the converter identifier with SATA masking parameters.

Returns:
ComponentIdentifier: The identifier for this converter.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This identifier can be misleading when a custom strategy is supplied: it still records num_masks and skip_first even though those values are ignored. It also omits task_template, so converters that produce different framed output can have identical identifiers. Please make the identifier describe the behavior actually in use, including the framing template when applicable.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The identifier now always records mask_token and the selection-strategy class. num_masks, skip_first, and min_word_length are included only for the default strategy, since a custom strategy ignores them. Framing is no longer applied inside this converter, so there is no template parameter to list.

Comment thread pyrit/converter/sata_masking_converter.py Outdated
Add a dependency-free converter that selects content words and replaces them with [MASK] so SATA can be composed with TaskFramingConverter.
Keep TaskFramingConverter composition outside this converter, reject mixed selection_strategy configuration, and identify only the parameters that affect output.
)

_WHITESPACE_RE = re.compile(r"(\s+)")
_WORD_AFFIX_RE = re.compile(r"^(\W*)(.*?)(\W*)$", re.UNICODE)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This pattern has quadratic backtracking for tokens with a long interior run of non-word characters. On the current branch, a 16K-character token takes roughly 3.5 seconds, and this runs synchronously inside convert_async, so one model-controlled token can stall the event loop. Could we split the leading and trailing \W* scans into separate anchored matches (or otherwise use a linear tokenizer) and add a regression case for a long token?

if self._uses_default_strategy:
params["num_masks"] = self._num_masks
params["skip_first"] = self._skip_first
params["min_word_length"] = self._min_word_length

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for removing the ignored default parameters for custom strategies. One collision remains for the internally-created strategy: stopwords and candidate_words both change which words are masked, but neither is represented here. For example, converters with different candidate_words produce different output while comparing equal by identifier. Please retain these values in a stable, order-independent form and include them in the identifier, with an inequality test.

sata_masked = await sata_mask.convert_async(prompt=prompt) # type: ignore
print("SATA Mask:", sata_masked)
sata_frame = TaskFramingConverter(task_template=SATA_TASK_TEMPLATE)
print("SATA Framed:", await sata_frame.convert_async(prompt=sata_masked.output_text)) # type: ignore

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could you re-execute this notebook before merge? The committed .ipynb contains this source but no SATA Mask or SATA Framed output. The converter modality notebook also needs regeneration so doc/code/converters/0_converters.ipynb includes SATAMaskingConverter, as required for new converters.

raise ValueError(f"Input type {input_type} not supported")

pieces, words = self._tokenize(prompt)
cores = [core for _, core, _ in words]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Passing only word cores changes the index space and matching behavior compared with SelectiveTextConverter, even though the class docstring says its strategies can be reused here. Empty tokens and punctuation-only tokens are dropped, so the same WordIndexSelectionStrategy can select a different word in the two converters. Could we either preserve the raw token/index stream expected by existing strategies, or explicitly document that these strategies are not index-compatible?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Simple Assistive Task Linkage (SATA) masking technique

2 participants