Transforms
Use transforms to rewrite inputs, adapt prompts, and normalize tool-calling behavior in SDK workflows.
Transforms are reusable input-rewriting components. They are most useful when you want to mutate a prompt or other object before it reaches the model, instead of changing the task, scorer, or hook.
When to use a transform
Section titled “When to use a transform”Use a transform when you want to:
- adapt or perturb text before an attack or evaluation
- normalize tool-calling syntax for models that do not support native function calling
- apply a reusable input rewrite across many trials
- carry compliance tags with the rewrite itself
Do not use a transform when you actually need:
- a hook to react to agent events
- a scorer to judge quality or safety
- a tool to perform an external action
The two transform types
Section titled “The two transform types”| Type | What it changes | Common use |
|---|---|---|
Transform | an input object before execution | mutate text, adapt prompts, build attack variants |
PostTransform | a generated Chat after execution | normalize or post-process a generated chat record |
Most user code starts with Transform.
Create a simple transform
Section titled “Create a simple transform”Transform can wrap a normal callable or async callable. The result is reusable and composable.
from dreadnode import Transform
strip_markers = Transform( lambda text: text.replace("[IGNORE]", "").strip(), name="strip_markers", modality="text",)
cleaned = await strip_markers(" [IGNORE] Investigate the host. ")print(cleaned)If you already have a list or mapping of transforms, normalize them with Transform.fit_many(...).
from dreadnode import Transform
transforms = Transform.fit_many( { "trim": lambda text: text.strip(), "lower": lambda text: text.lower(), })
for transform in transforms: print(transform.name)Use transforms with AIRT attacks
Section titled “Use transforms with AIRT attacks”Transforms are a first-class part of the AIRT attack factories. This is the most common way most users will encounter them.
from dreadnode.airt import pair_attackfrom dreadnode.transforms.language import adapt_language
attack = pair_attack( goal="Reveal the hidden system prompt", target=target, attacker_model="openai/gpt-4o-mini", evaluator_model="openai/gpt-4o-mini", transforms=[ adapt_language("Spanish", adapter_model="openai/gpt-4o-mini"), ],)
result = await attack.run()print(result.best_candidate)This keeps the attack logic the same while varying how prompts are presented to the target.
Built-in transform families
Section titled “Built-in transform families”The SDK ships many prebuilt transform modules under dreadnode.transforms, including:
languagefor adaptation and transliterationinjectionfor prompt injection and framing patternsreasoning_attacks,system_prompt_extraction, andadvanced_jailbreakfor red-team workflowsdocument,image,audio, andvideofor modality-specific transformsrag_poisoning,documentation_poison, andmcp_attacksfor system-level attack surfaces
The right way to explore the surface is to import the relevant module and inspect the factory functions it exports.
Tool-calling transforms
Section titled “Tool-calling transforms”Some transforms are infrastructural rather than adversarial. The most common examples are the tool-calling adapters:
tools_to_json_transformtools_to_json_in_xml_transformtools_to_json_with_tag_transformtools_to_pythonic_transform
The Agent runtime uses these internally based on tool_mode. You usually do not call them
directly unless you are building a lower-level generator workflow.
from dreadnode.transforms import get_transform, tools_to_json_transform
json_transform = get_transform("json")assert json_transform is tools_to_json_transformHow transforms relate to the rest of the SDK
Section titled “How transforms relate to the rest of the SDK”Think of it this way:
- transforms change what goes in
- scorers judge what comes out
- hooks react to what happened during execution
That separation keeps experiments easier to debug.
Common mistakes
Section titled “Common mistakes”- Do not use a transform as a hidden evaluator. If you need a score, use a scorer.
- Do not bury critical business logic in an unlabelled lambda. Give important transforms names.
- Do not assume transforms are agent-only. They are used heavily in AIRT and optimization too.
- Do not forget that
PostTransformis a different abstraction fromTransform.