Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

2. OpenAI Responses Target

In this demo, we show an example of the OpenAIResponseTarget. Responses is a newer protocol than chat completions and provides additional functionality with a somewhat modified API. The allowed input types include text, image, web search, file search, functions, reasoning, and computer use.

OpenAI Configuration

Like most targets, all OpenAITargets need an endpoint and often also needs a model and a key. These can be passed into the constructor or configured with environment variables (or in .env).

  • endpoint: The API endpoint (OPENAI_RESPONSES_ENDPOINT environment variable). For OpenAI, these are just “https://api.openai.com/v1/responses”.

  • auth: The API key for authentication (OPENAI_RESPONSES_KEY environment variable).

  • model_name: The model to use (OPENAI_RESPONSES_MODEL environment variable). For OpenAI, these are any available model name and are listed here: “https://platform.openai.com/docs/models”.

import os

from pyrit.auth import get_azure_openai_auth
from pyrit.executor.attack import PromptSendingAttack
from pyrit.output import output_attack_async
from pyrit.prompt_target import OpenAIResponseTarget
from pyrit.setup import IN_MEMORY, initialize_pyrit_async

await initialize_pyrit_async(memory_db_type=IN_MEMORY)  # type: ignore

# For Azure OpenAI with Entra ID authentication (no API key needed, run `az login` first):
endpoint = os.environ["OPENAI_RESPONSES_ENDPOINT"]
target = OpenAIResponseTarget(
    endpoint=endpoint,
    api_key=get_azure_openai_auth(endpoint),
)

attack = PromptSendingAttack(objective_target=target)

result = await attack.execute_async(objective="Tell me a joke")  # type: ignore
await output_attack_async(result)
Found default environment files: ['./.pyrit/.env', './.pyrit/.env.local']
Loaded environment file: ./.pyrit/.env
Loaded environment file: ./.pyrit/.env.local
No new upgrade operations detected.

════════════════════════════════════════════════════════════════════════════════════════════════════
                                  ❓ ATTACK RESULT: UNDETERMINED ❓                                   
════════════════════════════════════════════════════════════════════════════════════════════════════

 Attack Summary 
────────────────────────────────────────────────────────────────────────────────────────────────────
  📋 Basic Information
    • Objective: Tell me a joke
    • Attack Type: PromptSendingAttack
    • Conversation ID: 45158f17-7501-4446-ada9-5fb1ee31257f

  ⚡ Execution Metrics
    • Turns Executed: 1
    • Execution Time: 10.07s

  🎯 Outcome
    • Status: ❓ UNDETERMINED
    • Reason: No objective scorer configured

 Conversation History with Objective Target 
────────────────────────────────────────────────────────────────────────────────────────────────────

────────────────────────────────────────────────────────────────────────────────────────────────────
🔹 Turn 1 - USER
────────────────────────────────────────────────────────────────────────────────────────────────────
  Tell me a joke

────────────────────────────────────────────────────────────────────────────────────────────────────
🔸 ASSISTANT
────────────────────────────────────────────────────────────────────────────────────────────────────
  Why don’t scientists trust atoms?
    Because they make up everything!

────────────────────────────────────────────────────────────────────────────────────────────────────

────────────────────────────────────────────────────────────────────────────────────────────────────
                            Report generated at: 2026-05-21 23:04:35 UTC                            

Reasoning Configuration

Reasoning models (e.g., o1, o3, o4-mini, GPT-5) support a reasoning parameter that controls how much internal reasoning the model performs before responding. You can configure this with two parameters:

  • reasoning_effort: Controls the depth of reasoning. Accepts "minimal", "low", "medium", or "high". Lower effort favors speed and lower cost; higher effort favors thoroughness. The default (when not set) is typically "medium".

  • reasoning_summary: Controls whether a summary of the model’s internal reasoning is included in the response. Accepts "auto", "concise", or "detailed". By default, no summary is included.

For more information, see the OpenAI reasoning guide.

import os

from pyrit.auth import get_azure_openai_auth
from pyrit.executor.attack import PromptSendingAttack
from pyrit.prompt_target import OpenAIResponseTarget
from pyrit.setup import IN_MEMORY, initialize_pyrit_async

await initialize_pyrit_async(memory_db_type=IN_MEMORY)  # type: ignore

endpoint = os.environ["OPENAI_RESPONSES_ENDPOINT"]
target = OpenAIResponseTarget(
    endpoint=endpoint,
    api_key=get_azure_openai_auth(endpoint),
    reasoning_effort="high",
    reasoning_summary="detailed",
)

attack = PromptSendingAttack(objective_target=target)
result = await attack.execute_async(objective="What are the most dangerous items in a household?")  # type: ignore
await output_attack_async(result)
Found default environment files: ['./.pyrit/.env', './.pyrit/.env.local']
Loaded environment file: ./.pyrit/.env
Loaded environment file: ./.pyrit/.env.local

════════════════════════════════════════════════════════════════════════════════════════════════════
                                  ❓ ATTACK RESULT: UNDETERMINED ❓                                   
════════════════════════════════════════════════════════════════════════════════════════════════════

 Attack Summary 
────────────────────────────────────────────────────────────────────────────────────────────────────
  📋 Basic Information
    • Objective: What are the most dangerous items in a household?
    • Attack Type: PromptSendingAttack
    • Conversation ID: 6b4f0dc0-cdd9-4bc7-a8b7-168616d1fd2b

  ⚡ Execution Metrics
    • Turns Executed: 1
    • Execution Time: 31.13s

  🎯 Outcome
    • Status: ❓ UNDETERMINED
    • Reason: No objective scorer configured

 Conversation History with Objective Target 
────────────────────────────────────────────────────────────────────────────────────────────────────

────────────────────────────────────────────────────────────────────────────────────────────────────
🔹 Turn 1 - USER
────────────────────────────────────────────────────────────────────────────────────────────────────
  What are the most dangerous items in a household?

────────────────────────────────────────────────────────────────────────────────────────────────────
🔸 ASSISTANT
────────────────────────────────────────────────────────────────────────────────────────────────────
  Here are some of the most hazardous items you’re likely to find around the home, grouped by type
      of risk. Wherever possible, store them securely (ideally locked and/or up high), keep them in
      their original, clearly-labeled containers, and follow all manufacturer safety instructions.
  
    1. Toxic Chemicals and Poisons
     • Bleach, ammonia, drain and oven cleaners (highly corrosive; can cause severe burns if spilled
      or inhaled)
     • Pesticides, rodenticides, herbicides (neurotoxins; accidental ingestion can be life-
      threatening)
     • Paints, paint thinners, solvents, turpentine (flammable and toxic vapors)
     • Antifreeze (ethylene glycol is sweet-tasting but severely toxic if swallowed)
  
    2. Medications and Supplements
     • Prescription drugs (especially opioids, antidepressants, heart medications)
     • Over-the-counter painkillers, cold medicines (risk of overdose or dangerous interactions)
     • Vitamins and iron supplements (iron poisoning is a leading cause of fatal pediatric poisoning)
  
    3. Small Objects and Batteries (Choking/Ingestion Hazards)
     • Button (“coin”) batteries (can cause severe internal burns if lodged in the esophagus)
     • Small toy parts, marbles, magnets (high risk of choking or intestinal damage)
  
    4. Sharp Tools and Cutters
     • Kitchen knives, utility knives, box cutters, broken glass
     • Scissors, woodworking tools (saws, chisels)
     • Razor blades, carpet knives
  
    5. Fire and Burn Risks
     • Portable space heaters, electric blankets (tip-over or overheating can ignite fires)
     • Candles, lighters, matches
     • Hot cooking oil (splatter burns and grease fires on stovetops)
  
    6. Electricity and Electrical Devices
     • Extension cords (tripping hazard; overloads can ignite fires)
     • Frayed appliance cords, exposed wiring
     • DIY electrical tools (soldering irons, hot glue guns)
  
    7. Heavy or Unstable Objects
     • Tall bookshelves, dressers, televisions (can tip over and crush)
     • Large containers of liquid (if spilled, create slip hazards)
  
    8. Power Tools and Garden Equipment
     • Circular saws, drills, angle grinders (risk of laceration or eye injury)
     • Lawn mowers, hedge trimmers (entanglement, amputation risk)
     • Gasoline for yard equipment (flammable vapors)
  
    9. Gas-Producing Appliances
     • Gas stove, space heater, water heater (carbon monoxide poisoning if poorly ventilated)
     • Propane cylinders (explosive if ruptured or leaked)
  
    10. Water Hazards
     • Buckets, wading pools (drowning risk—even a few inches of water)
     • Bathtubs and toilets (especially for toddlers)
  
    Safety Tips:
    • Keep all chemicals and medicines locked up, out of children’s reach.
    • Never mix cleaning products (e.g., bleach + ammonia produces toxic chloramine gas).
    • Store sharp tools with blade covers and in locked cabinets if children are present.
    • Install smoke and carbon monoxide detectors; check batteries regularly.
    • Anchor tall furniture to walls; use non-slip mats in wet areas.
    • Supervise children around water and heat sources at all times.
    • Dispose of expired medications and batteries safely (household hazardous-waste programs).

────────────────────────────────────────────────────────────────────────────────────────────────────

────────────────────────────────────────────────────────────────────────────────────────────────────
                            Report generated at: 2026-05-21 23:05:06 UTC                            

JSON Generation

We can use the OpenAI Responses API with a JSON schema to produce structured JSON output. In this example, we define a simple JSON schema that describes a person with name and age properties.

For more information about structured outputs with OpenAI, see the OpenAI documentation.

import json
import os

import jsonschema

from pyrit.auth import get_azure_openai_auth
from pyrit.models import Message, MessagePiece
from pyrit.prompt_target import OpenAIResponseTarget
from pyrit.setup import IN_MEMORY, initialize_pyrit_async

await initialize_pyrit_async(memory_db_type=IN_MEMORY)  # type: ignore

# Define a simple JSON schema for a person
person_schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer", "minimum": 0, "maximum": 150},
    },
    "required": ["name", "age"],
    "additionalProperties": False,
}

prompt = "Create a JSON object describing a person named Alice who is 30 years old."
# Create the message piece and message
message_piece = MessagePiece(
    role="user",
    original_value=prompt,
    original_value_data_type="text",
    prompt_metadata={
        "response_format": "json",
        "json_schema": json.dumps(person_schema),
    },
)
message = Message(message_pieces=[message_piece])

# Create the OpenAI Responses target
endpoint = os.environ["OPENAI_RESPONSES_ENDPOINT"]
target = OpenAIResponseTarget(
    endpoint=endpoint,
    api_key=get_azure_openai_auth(endpoint),
)

# Send the prompt, requesting JSON output
response = await target.send_prompt_async(message=message)  # type: ignore

# Validate and print the response
response_json = json.loads(response[0].message_pieces[1].converted_value)
print(json.dumps(response_json, indent=2))
jsonschema.validate(instance=response_json, schema=person_schema)
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x000002A3EE48E420>
Found default environment files: ['./.pyrit/.env', './.pyrit/.env.local']
Loaded environment file: ./.pyrit/.env
Loaded environment file: ./.pyrit/.env.local
{
  "name": "Alice",
  "age": 30
}

Tool Use with Custom Functions

In this example, we demonstrate how the OpenAI Responses API can be used to invoke a custom-defined Python function during a conversation. This is part of OpenAI’s support for “function calling”, where the model decides to call a registered function, and the application executes it and passes the result back into the conversation loop.

We define a simple tool called get_current_weather, which simulates weather information retrieval. A corresponding OpenAI tool schema describes the function name, parameters, and expected input format.

The function is registered in the custom_functions argument of OpenAIResponseTarget. The extra_body_parameters include:

  • tools: the full OpenAI tool schema for get_current_weather.

  • tool_choice: "auto": instructs the model to decide when to call the function.

The user prompt explicitly asks the model to use the get_current_weather function. Once the model responds with a function_call, PyRIT executes the function, wraps the output, and the conversation continues until a final answer is produced.

This showcases how agentic function execution works with PyRIT + OpenAI Responses API.

import os

from pyrit.auth import get_azure_openai_auth
from pyrit.models import Message, MessagePiece
from pyrit.prompt_target import OpenAIResponseTarget
from pyrit.setup import IN_MEMORY, initialize_pyrit_async

await initialize_pyrit_async(memory_db_type=IN_MEMORY)  # type: ignore


async def get_current_weather(args):
    return {
        "weather": "Sunny",
        "temp_c": 22,
        "location": args["location"],
        "unit": args["unit"],
    }


# Responses API function tool schema (flat, no nested "function" key)
function_tool = {
    "type": "function",
    "name": "get_current_weather",
    "description": "Get the current weather in a given location",
    "parameters": {
        "type": "object",
        "properties": {
            "location": {"type": "string", "description": "City and state"},
            "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
        },
        "required": ["location", "unit"],
        "additionalProperties": False,
    },
    "strict": True,
}

endpoint = os.environ["OPENAI_RESPONSES_ENDPOINT"]
# Let the model auto-select tools
target = OpenAIResponseTarget(
    endpoint=endpoint,
    api_key=get_azure_openai_auth(endpoint),
    custom_functions={"get_current_weather": get_current_weather},
    extra_body_parameters={
        "tools": [function_tool],
        "tool_choice": "auto",
    },
    httpx_client_kwargs={"timeout": 60.0},
)

# Build the user prompt
message_piece = MessagePiece(
    role="user",
    original_value="What is the weather in Boston in celsius? Use the get_current_weather function.",
    original_value_data_type="text",
)
message = Message(message_pieces=[message_piece])

response = await target.send_prompt_async(message=message)  # type: ignore

for response_msg in response:
    for idx, piece in enumerate(response_msg.message_pieces):
        print(f"{idx} | {piece.api_role}: {piece.original_value}")
Found default environment files: ['./.pyrit/.env', './.pyrit/.env.local']
Loaded environment file: ./.pyrit/.env
Loaded environment file: ./.pyrit/.env.local
0 | assistant: {"id":"rs_002694f8abc75dfa006a0f8faf7e8481959710f98f7f6ce26d","summary":[],"type":"reasoning","content":null,"encrypted_content":null,"status":null}
1 | assistant: {"type":"function_call","call_id":"call_4yoMeaoTWrKFqFeTO0U57ERn","name":"get_current_weather","arguments":"{\"location\":\"Boston\",\"unit\":\"celsius\"}"}
0 | tool: {"type":"function_call_output","call_id":"call_4yoMeaoTWrKFqFeTO0U57ERn","output":"{\"weather\":\"Sunny\",\"temp_c\":22,\"location\":\"Boston\",\"unit\":\"celsius\"}"}
0 | assistant: The current weather in Boston is Sunny with a temperature of 22°C.

Using the Built-in Web Search Tool

In this example, we use a built-in PyRIT helper function web_search_tool() to register a web search tool with OpenAI’s Responses API. This allows the model to issue web search queries during a conversation to supplement its responses with fresh information.

The tool is added to the extra_body_parameters passed into the OpenAIResponseTarget. As before, tool_choice="auto" enables the model to decide when to invoke the tool.

The user prompt asks for a recent positive news story — an open-ended question that may prompt the model to issue a web search tool call. PyRIT will automatically execute the tool and return the output to the model as part of the response.

This example demonstrates how retrieval-augmented generation (RAG) can be enabled in PyRIT through OpenAI’s Responses API and integrated tool schema.

NOTE that web search is NOT supported through an Azure OpenAI endpoint, only through the OpenAI platform endpoint (i.e. api.openai.com)

import os

from pyrit.auth import get_azure_openai_auth
from pyrit.common.tool_configs import web_search_tool
from pyrit.models import Message, MessagePiece
from pyrit.prompt_target import OpenAIResponseTarget
from pyrit.setup import IN_MEMORY, initialize_pyrit_async

await initialize_pyrit_async(memory_db_type=IN_MEMORY)  # type: ignore

# Note: web search is only supported on a limited set of models.
responses_endpoint = os.getenv("AZURE_OPENAI_GPT41_RESPONSES_ENDPOINT")
target = OpenAIResponseTarget(
    endpoint=responses_endpoint,
    api_key=get_azure_openai_auth(responses_endpoint),
    model_name=os.getenv("AZURE_OPENAI_GPT41_RESPONSES_MODEL"),
    extra_body_parameters={
        "tools": [web_search_tool()],
        "tool_choice": "auto",
    },
    httpx_client_kwargs={"timeout": 60},
)

message_piece = MessagePiece(
    role="user", original_value="Briefly, what is one positive news story from today?", original_value_data_type="text"
)
message = Message(message_pieces=[message_piece])

response = await target.send_prompt_async(message=message)  # type: ignore

for response_msg in response:
    for idx, piece in enumerate(response_msg.message_pieces):
        print(f"{idx} | {piece.api_role}: {piece.original_value}")
Found default environment files: ['./.pyrit/.env', './.pyrit/.env.local']
Loaded environment file: ./.pyrit/.env
Loaded environment file: ./.pyrit/.env.local
0 | assistant: {"type":"web_search_call","id":"ws_0db40da20253fe01006a0f8fb96c3881969cab1732ee640ef8"}
1 | assistant: One positive news story from today is about a Tennessee police officer who is being praised for his courage after he rushed into a burning apartment building and saved a trapped family, including a mother and her children. His quick-thinking and bravery were captured in body camera footage, and he is being celebrated as a hero in his community [Sunny Skyz](https://www.sunnyskyz.com/good-news).