Context and Input Guardrail System
1. Context Model Definition
models.py Lines 5-9
class UserAccountContext(BaseModel):
customer_id: int
name: str
tier: str = "basic"
email: Optional[str] = None # premium enterprise
- UserAccountContext: Pydantic model containing customer account information
- Fields:
- customer_id: Customer ID
- name: Customer name
- tier: Tier (default "basic", can be "premium", "enterprise")
- email: Email (optional)
2. Context Instance Creation and Passing
main.py Lines 13-17
user_account_ctx = UserAccountContext(
customer_id=1,
name="nico",
tier="basic",
)
- user_account_ctx: Creates a customer information instance
main.py Lines 53-58
stream = Runner.run_streamed(
triage_agent,
message,
session=session,
context=user_account_ctx,
)
- Passes context=user_account_ctx to Runner.run_streamed()
- This context is passed when the agent runs
3. Accessing Context via RunContextWrapper
A. Using Context in Guardrail Function
triage_agent.py Lines 20-35
@input_guardrail
async def off_topic_guardrail(
wrapper: RunContextWrapper[UserAccountContext],
agent: Agent[UserAccountContext],
input: str,
):
result = await Runner.run(
input_guardrail_agent,
input,
context=wrapper.context,
)
return GuardrailFunctionOutput(
output_info=result.final_output,
tripwire_triggered=result.final_output.is_off_topic,
)
- wrapper: RunContextWrapper[UserAccountContext]: Wrapper object for context
- wrapper.context: Access to the actual UserAccountContext instance
- The same context is passed to the guardrail agent (line 29)
- you should use @input_gaurdrail decorater to registers this function as input guardrail.
B. Using Context in Dynamic Prompt
triage_agent.py Lines 38-48
def dynamic_triage_agent_instructions(
wrapper: RunContextWrapper[UserAccountContext],
agent: Agent[UserAccountContext],
):
return f"""
You are a customer support agent. You ONLY help customers with their questions about their User Account, Billing, Orders, or Technical Support.
You call customers by their name.
The customer's name is {wrapper.context.name}.
The customer's email is {wrapper.context.email}.
The customer's tier is {wrapper.context.tier}.
- dynamic_triage_agent_instructions: Function called at runtime
- Inserts customer information into the prompt using wrapper.context.name, wrapper.context.email, wrapper.context.tier
- The prompt is generated based on context for each execution
4. Input Guardrail System
A. Guardrail Output Model
models.py Lines 12-15
class InputGuardRailOutput(BaseModel):
is_off_topic: bool
reason: str
- InputGuardRailOutput: Model for guardrail validation results
- is_off_topic: Whether the request is off-topic (True blocks the request)
- reason: Reason for blocking
B. Guardrail Dedicated Agent
triage_agent.py Lines 10-18
input_guardrail_agent = Agent(
name="Input Guardrail Agent",
instructions="""
Ensure the user's request specifically pertains to User Account details, Billing inquiries, Order information, or Technical Support issues, and is not off-topic.
If the request is off-topic, return a reason for the tripwire.You can make small conversation with the user, specially at the beginning of the conversation,
but don't help with requests that are not related to User Account details, Billing inquiries, Order information, or Technical Support issues.
""",
output_type=InputGuardRailOutput,
)
- Purpose: Determines if user input is within allowed scope (Account/Billing/Orders/Technical Support)
- Output: Returns InputGuardRailOutput format
- Rules: Allows brief greetings at conversation start, but blocks requests that are fundamentally off-topic
C. Guardrail Function Implementation
triage_agent.py Lines 20-35
@input_guardrail
async def off_topic_guardrail(
wrapper: RunContextWrapper[UserAccountContext],
agent: Agent[UserAccountContext],
input: str,
):
result = await Runner.run(
input_guardrail_agent,
input,
context=wrapper.context,
)
return GuardrailFunctionOutput(
output_info=result.final_output,
tripwire_triggered=result.final_output.is_off_topic,
)
- @input_guardrail: Decorator that registers the function as a guardrail
- Parameters:
- wrapper: Execution context wrapper (access UserAccountContext via wrapper.context)
- agent: Current agent instance (for extensibility/logging)
- input: User input string to validate
- Behavior:
- Runs input validation with input_guardrail_agent (passes context=wrapper.context on line 29)
- Returns GuardrailFunctionOutput
- tripwire_triggered: True if is_off_topic is True
D. Registering Guardrail with Main Agent
triage_agent.py Lines 96-102
triage_agent = Agent(
name="Triage Agent",
instructions=dynamic_triage_agent_instructions,
input_guardrails=[
off_topic_guardrail,
],
)
- input_guardrails: List to register multiple guardrails
- Execution order: User input → Guardrail validation → Main agent execution (if passed)
E. Guardrail Exception Handling
main.py Lines 51-67
try:
stream = Runner.run_streamed(
triage_agent,
message,
session=session,
context=user_account_ctx,
)
async for event in stream.stream_events():
if event.type == "raw_response_event":
if event.data.type == "response.output_text.delta":
response += event.data.delta
text_placeholder.write(response.replace("$", "\$"))
except InputGuardrailTripwireTriggered:
st.write("I can't help you with that.")
- InputGuardrailTripwireTriggered: Exception raised when guardrail is triggered
- Handling: Displays "I can't help you with that." when blocked
5. Integrated Usage of Context and Guardrail
How Context is Passed to Guardrail
- In main.py: Pass context=user_account_ctx
- Inside Runner.run_streamed(): Wrap user_account_ctx with RunContextWrapper
- Call off_topic_guardrail() function: Access via wrapper.context
- Execute input_guardrail_agent: Pass context=wrapper.context (line 29) -> Guardrail agent can also access customer information
How Context is Used in Dynamic Prompt
- Inside Runner.run_streamed(): Call dynamic_triage_agent_instructions(wrapper, agent)
- Access wrapper.context.name, email, tier
- Insert customer information into prompt:
- "The customer's name is nico."
- "The customer's tier is basic."
- Call LLM with personalized prompt
6. Complete Execution Flow (Context + Guardrail)
[Step 1] Context Creation
- Create user_account_ctx in main.py
- UserAccountContext(customer_id=1, name="nico", tier="basic")[Step 2] User Input
- ↓
- User: "What's the weather like today?"[Step 3] Call Runner.run_streamed()
- ↓
- Runner.run_streamed(triage_agent, "What's the weather like today?", context=user_account_ctx) ← Pass Context[Step 4] Context Wrapping
- ↓
- Wrap user_account_ctx with RunContextWrapper
- Accessible via wrapper.context[Step 5] Input Guardrail Validation Starts
- ↓
- Check triage_agent's input_guardrails list
- → Find off_topic_guardrail function[Step 6] Execute off_topic_guardrail()
- ↓
- @input_guardrail decorator calls the function
- wrapper: RunContextWrapper[UserAccountContext] (includes context)
- agent: triage_agent instance
- input: "What's the weather like today?"[Step 7] Execute Guardrail Agent (with Context)
- ↓
- Runner.run(input_guardrail_agent, "What's the weather like today?", context=wrapper.context) ← Pass Context
- → input_guardrail_agent analyzes input with LLM
- → Determines "weather question is off-topic"
- → Returns InputGuardRailOutput(is_off_topic=True, reason="...")[Step 8] Create GuardrailFunctionOutput
- ↓
- return GuardrailFunctionOutput(output_info=InputGuardRailOutput(...), tripwire_triggered=True)[Step 9] Exception Raised
- ↓
- Since tripwire_triggered=True
- → InputGuardrailTripwireTriggered exception raised[Step 10] Exception Handling
- ↓
- Caught in except block in main.py
- → Display "I can't help you with that."[Step 11] Main Agent Not Executed
- ↓
- triage_agent is not executed (cost savings)
Example with Allowed Input (Context Usage)
[Steps 1-6] Same
↓
[Step 7] Execute Guardrail Agent
- Input: "Check my account information"
- → Determines "account-related request"
- → Returns InputGuardRailOutput(is_off_topic=False, reason="")[Step 8] Guardrail Passed
- ↓
- tripwire_triggered=False
- → No exception raised[Step 9] Execute Main Agent
- ↓
- Call dynamic_triage_agent_instructions(wrapper, agent)
- → Access wrapper.context.name, email, tier
- → Generate prompt:
- "The customer's name is nico."
- "The customer's tier is basic."
- → Call LLM with personalized prompt
- → "Hello nico, I'll check your account information..."
7. Key Concepts Summary
Context Related
| Concept | Description |
| UserAccountContext | Pydantic model containing customer account information |
| RunContextWrapper | Object that wraps context at execution time |
| wrapper.context | Access to actual UserAccountContext instance |
| context=user_account_ctx | Pass context to Runner |
Input Guardrail Related
| Concept | Description |
| @input_guardrail | Decorator that registers function as guardrail |
| input_guardrails | List that connects guardrails to agent |
| GuardrailFunctionOutput | Object that returns validation result and trigger status |
| InputGuardrailTripwireTriggered | Exception raised when blocked |
| tripwire_triggered | Whether guardrail was triggered |
8. Interaction Between Context and Guardrail
- Context Passing Path: main.py → Runner.run_streamed() → RunContextWrapper → wrapper.context
- Using Context in Guardrail:
- Access customer information via wrapper.context
- Pass context=wrapper.context to guardrail agent
- Using Context in Main Agent:
- Insert into prompt using wrapper.context in dynamic_triage_agent_instructions
- Personalization:
- Personalize responses using customer name, tier, etc.
This structure validates user input before processing and uses context to generate personalized responses.