Skip to content

API Reference — Drivers

Drivers generate prompts for agent interaction. They decide what to send; the execution strategy handles the session, evaluation, and result.

drivers

Driver implementations.

StaticDriver

Python
StaticDriver(*, prompts)

Sends a fixed sequence of prompts.

Derives its position from the history length — no mutable state. Safe to reuse across tests.

Parameters:

Name Type Description Default
prompts list[str] | list[Request]

The prompts to send in order. Strings are wrapped in Request objects automatically.

required

Initialize with a list of prompts or Request objects.

Source code in rampart/drivers/static.py
Python
def __init__(self, *, prompts: list[str] | list[Request]) -> None:
    """Initialize with a list of prompts or Request objects."""
    self._requests: list[Request] = [
        Request(prompt=p) if isinstance(p, str) else p for p in prompts
    ]

next_prompt_async async

Python
next_prompt_async(*, history)

Return the next prompt in sequence, or None when exhausted.

Parameters:

Name Type Description Default
history list[Turn]

All turns so far (empty on first call).

required

Returns:

Type Description
PromptDecision | None

PromptDecision | None: The next decision, or None when all prompts have been sent.

Source code in rampart/drivers/static.py
Python
async def next_prompt_async(
    self,
    *,
    history: list[Turn],
) -> PromptDecision | None:
    """Return the next prompt in sequence, or None when exhausted.

    Args:
        history (list[Turn]): All turns so far (empty on first call).

    Returns:
        PromptDecision | None: The next decision, or None when all
            prompts have been sent.
    """
    index = len(history)
    if index >= len(self._requests):
        return None
    return PromptDecision(request=self._requests[index])

LLMDriver

Python
LLMDriver(
    *,
    persona,
    llm=None,
    target=None,
    objective=None,
    injections=None,
)

LLM-backed prompt driver.

Wraps a PyRIT PromptChatTarget to generate the next user prompt on each turn. The LLM responds with plain text — its response is the next prompt to send to the target agent.

The driver maintains two related conversations:

  • The driver-side conversation with the driving LLM, stored in PyRIT's CentralMemory keyed by self._conversation_id.

  • The agent-side conversation with the agent under test, represented by history: list[Turn] passed into next_prompt_async.

Termination is handled externally: the evaluator's early-stop (on detection) or the execution loop's max_turns budget. The driver never self-terminates — empty LLM responses raise DriverError rather than returning None.

One driver instance = one driver-side conversation. Construct a new driver per test. Use from_target for custom targets.

Initialize with LLM config or pre-configured target.

Parameters:

Name Type Description Default
persona Persona

System-prompt identity for the LLM.

required
llm LLMConfig | None

LLM configuration. Required unless target is provided.

None
target PromptChatTarget | None

Pre-configured PromptChatTarget. Mutually exclusive with llm — provide one or the other.

None
objective str | None

Per-test goal as a natural-language string.

None
injections list[Payload] | None

Payloads placed in the agent's data sources.

None

Raises:

Type Description
TypeError

If both or neither of llm and target are provided.

Source code in rampart/drivers/llm.py
Python
def __init__(
    self,
    *,
    persona: Persona,
    llm: LLMConfig | None = None,
    target: PromptChatTarget | None = None,
    objective: str | None = None,
    injections: list[Payload] | None = None,
) -> None:
    """Initialize with LLM config or pre-configured target.

    Args:
        persona: System-prompt identity for the LLM.
        llm: LLM configuration. Required unless ``target`` is provided.
        target: Pre-configured PromptChatTarget. Mutually exclusive
            with ``llm`` — provide one or the other.
        objective: Per-test goal as a natural-language string.
        injections: Payloads placed in the agent's data sources.

    Raises:
        TypeError: If both or neither of ``llm`` and ``target`` are provided.
    """
    if llm is not None and target is not None:
        msg = "Provide either 'llm' or 'target', not both."
        raise TypeError(msg)
    if llm is None and target is None:
        msg = "Provide either 'llm' or 'target'."
        raise TypeError(msg)

    self._llm = llm
    self._persona = persona
    self._objective = objective
    self._injections = injections or []

    self._conversation_id = str(uuid.uuid4())
    self._target = target
    self._normalizer: PromptNormalizer | None = None
    self._initialized = False

from_target classmethod

Python
from_target(
    *, target, persona, objective=None, injections=None
)

Construct an LLMDriver from a pre-configured PromptChatTarget.

Use this when you need a target type not covered by create_prompt_target (custom subclass, non-OpenAI provider, test double). The system prompt is still assembled from persona/objective/injections and set on the given target at first use, so do not call set_system_prompt on the target yourself before passing it in.

Parameters:

Name Type Description Default
target PromptChatTarget

A pre-configured PromptChatTarget. CentralMemory must be initialized before the driver's first next_prompt_async call (not at construction time).

required
persona Persona

System-prompt identity.

required
objective str | None

Optional per-test goal.

None
injections list[Payload] | None

Optional injection metadata for the system prompt.

None
Source code in rampart/drivers/llm.py
Python
@classmethod
def from_target(
    cls,
    *,
    target: PromptChatTarget,
    persona: Persona,
    objective: str | None = None,
    injections: list[Payload] | None = None,
) -> LLMDriver:
    """Construct an LLMDriver from a pre-configured PromptChatTarget.

    Use this when you need a target type not covered by
    ``create_prompt_target`` (custom subclass, non-OpenAI provider,
    test double). The system prompt is still assembled from
    persona/objective/injections and set on the given target at
    first use, so do not call ``set_system_prompt`` on the target
    yourself before passing it in.

    Args:
        target: A pre-configured PromptChatTarget. CentralMemory
            must be initialized before the driver's first
            ``next_prompt_async`` call (not at construction time).
        persona: System-prompt identity.
        objective: Optional per-test goal.
        injections: Optional injection metadata for the system prompt.
    """
    return cls(
        target=target,
        persona=persona,
        objective=objective,
        injections=injections,
    )

next_prompt_async async

Python
next_prompt_async(*, history)

Generate the next prompt decision based on conversation history.

Sends the latest agent-side turn data to the driving LLM and returns its plain-text response as the next prompt.

Parameters:

Name Type Description Default
history list[Turn]

All agent-side turns so far (empty on first call).

required

Returns:

Type Description
PromptDecision | None

The next prompt decision.

Raises:

Type Description
DriverError

If the LLM call fails or returns an empty response.

Source code in rampart/drivers/llm.py
Python
async def next_prompt_async(
    self,
    *,
    history: list[Turn],
) -> PromptDecision | None:
    """Generate the next prompt decision based on conversation history.

    Sends the latest agent-side turn data to the driving LLM and
    returns its plain-text response as the next prompt.

    Args:
        history: All agent-side turns so far (empty on first call).

    Returns:
        The next prompt decision.

    Raises:
        DriverError: If the LLM call fails or returns an empty
            response.
    """
    self._ensure_initialized()
    self._assert_conversations_consistent(history)

    user_message = self._build_user_message(history=history)

    try:
        prompt_text = await self._send_async(user_message)
    except EmptyResponseException as exc:
        msg = (
            "LLMDriver: driving LLM returned empty response after retries. "
            f"conversation_id={self._conversation_id}"
        )
        raise DriverError(msg) from exc
    except Exception as exc:
        msg = f"LLMDriver: send_user_turn_async failed: {exc}"
        raise DriverError(msg) from exc

    prompt_text = prompt_text.strip()
    if not prompt_text:
        msg = (
            "LLMDriver: driving LLM returned empty response. "
            "This typically indicates a provider hiccup, a safety filter "
            "trigger on the driver itself, or a misconfigured model. "
            f"conversation_id={self._conversation_id}"
        )
        raise DriverError(msg)

    # Attach injection payloads on the first turn so the agent
    # receives the actual files alongside the prompt — mirroring
    # how static requests deliver attachments.  Subsequent turns
    # carry only the LLM-generated text.
    attachments = self._injections if not history else []

    return PromptDecision(
        request=Request(prompt=prompt_text, attachments=attachments),
    )