Skip to content

[FEAT] Implement the documented converter_bridge (PyRIT PromptConverter to RAMPART PayloadConverter) #69

@Raulster24

Description

@Raulster24

Summary

The module docstring in rampart/core/converter.py says a bridge file, pyrit_bridge/converter_bridge.py, will adapt PyRIT PromptConverters to RAMPART's PayloadConverter protocol, but that file isn't there yet. This proposes adding it, so RAMPART can reuse PyRIT's existing converters instead of hand-writing each one.

Motivation

rampart/core/converter.py contains this line: "The PyRIT bridge in pyrit_bridge/converter_bridge.py will adapt PromptConverter to this protocol." Right now, rampart/pyrit_bridge/ only has llm_bridge.py, so the converter bridge hasn't been written.

Today, rampart/converters/ has one converter, DocxConverter, which is a hand-written wrapper around PyRIT's WordDocConverter (described in docs/concepts/pyrit.md). PyRIT is already a pinned dependency (pyrit==0.13.0) and ships more than 70 prompt converters, including Base64, Atbash, ASCII-art, Bidi, Binary, and LLM-backed ones like translation. A generic bridge would make all of those usable from RAMPART in one place, and it would follow the same pattern DocxConverter already uses.

Proposed solution

Add rampart/pyrit_bridge/converter_bridge.py that adapts a PyRIT PromptConverter to RAMPART's PayloadConverter protocol (convert_async(*, payload: Payload) -> Payload). It would run the PyRIT converter on payload.content with convert_async(prompt=..., input_type="text"), then return a new Payload whose content is the transformed text (result.output_text), with format kept as TEXT and artifact left as None. The original id and metadata carry forward, plus a converter tag. This follows the "text transforms modify content" branch described in the PayloadConverter docstring. It is the text analog of DocxConverter, which takes the other branch as a format renderer that preserves content and sets an artifact instead.

For a first version, I would scope it to text converters (output_type of "text" maps to PayloadFormat.TEXT). Converters that produce images or audio need artifact handling, so those would come in a follow-up.

There is one open question on the public API, since RAMPART keeps PyRIT types out of its public surface:

Option A is a generic adapter such as pyrit_bridge.adapt_converter(pyrit_converter) that wraps any PyRIT converter. This does expose a PyRIT type at the boundary, but it matches the exception you already make for LLMDriver.from_target(), which accepts a PyRIT PromptChatTarget. It makes the whole library available at once.

Option B is per-converter wrappers in rampart/converters/ (for example, Base64Converter) that build the PyRIT converter internally and expose no PyRIT types, the same way DocxConverter does. This hides PyRIT fully but needs one small class per converter.

I would lean toward A, optionally with a few named wrappers for common converters on top, but I am happy to go with whichever you prefer.

It would ship with unit tests that mirror the source location, so tests/unit/pyrit_bridge/test_converter_bridge.py for the bridge in Option A, or tests/unit/converters/ for named wrappers in Option B, using deterministic converters such as Base64 and Atbash, so the tests need no API keys. It would also add a docs page and an mkdocs.yml nav entry, following the Extending RAMPART guide and the code-style rules.

Alternatives considered

One option is to keep hand-writing individual converters in rampart/converters/ (Base64, ROT13, Unicode, and so on). That duplicates PyRIT, adds maintenance, and does not scale. Another is to leave each consumer to wrap PyRIT converters themselves, but that repeats work and loses the type and boundary guarantees the bridge would give.

Additional context

References: rampart/core/converter.py for the docstring that names the bridge, docs/concepts/pyrit.md for the DocxConverter to WordDocConverter precedent and the PyRIT boundary rule, and PyRIT's PromptConverter and ConverterResult API.

I'm happy to implement this fully (code, tests, docs) and sign the CLA. Before I start, two questions. Is a converter bridge already planned or in progress internally, and would you welcome a community PR for it? And do you have a preference between Option A and Option B?

@nina-msft @bashirpartovi

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions