todoagent / guardrails.py
Abdullahcoder54's picture
push
a67367b
"""Guardrails for the TodoAgent."""
from agents import (
Agent,
OpenAIChatCompletionsModel,
input_guardrail,
output_guardrail,
GuardrailFunctionOutput,
RunContextWrapper, # Needed for guardrail function signature
Runner, # Needed to run topic_checker_agent
TResponseInputItem # Correct type for input content in guardrail functions
)
from config.config import settings
from openai import AsyncOpenAI
import logging
from typing import Any # Needed for RunContextWrapper[Any]
from pydantic import BaseModel
logger = logging.getLogger(__name__)
class todo(BaseModel):
reasoning: str
is_not_todo: bool
user_friendly_response: str
# A simple, low-cost model to act as a topic checker.
guardrail_client = AsyncOpenAI(
api_key=settings.GEMINI_API_KEY,
base_url="https://openrouter.ai/api/v1"
)
guardrail_model = OpenAIChatCompletionsModel(
model="arcee-ai/trinity-large-preview:free", # Using a common model for topic checking
openai_client=guardrail_client
)
# This is the "topic checker" agent.
guardrail_agent = Agent(
name="TopicChecker",
model=guardrail_model,
output_type=todo,
instructions="""
Your job is to check whether the user's message is related to managing a to-do list.
If the message IS related to task management:
- Adding a task
- Deleting a task
- Updating a task
- Listing tasks
- Completing tasks
- Asking about existing tasks
- Any clear todo/task management request
If the message is NOT related to task management
(e.g., math questions, weather, casual conversation, general knowledge):
- Respond politely and briefly.
- Explain that you can help only with managing tasks.
- Guide the user to ask a task-related question.
Your response MUST be friendly, clear, and short.
Example response for non-task queries:
"I’m here to help with your to-do list. You can ask me to add, remove, update, or list your tasks."
"""
)
@input_guardrail(name="TodoInputGuardrail")
async def is_task_related(
ctx: RunContextWrapper[Any], # Context provided by Runner
agent: Agent, # The agent running this guardrail
user_input: str | list[TResponseInputItem] # The user's input
) -> GuardrailFunctionOutput:
"""
Input guardrail to check if the user's query is related to task management.
"""
try:
logger.info(f"Checking topic for query: '{user_input}'")
# Run the topic checker agent. Pass the input directly, and context for traceability.
result = await Runner.run(guardrail_agent, input=user_input, context=ctx.context)
logger.info(f"Topic checker result: is_todo={result.final_output.is_not_todo}, reasoning='{result.final_output.reasoning}'")
return GuardrailFunctionOutput(
output_info=result.final_output.user_friendly_response,
tripwire_triggered=result.final_output.is_not_todo,
)
except Exception as e:
logger.error(f"Error in input guardrail: {e}")
return GuardrailFunctionOutput(
tripwire_triggered=False,
output_info="An error occurred while checking your query.",
)
@output_guardrail(name="TodoOutputGuardrail")
async def is_response_appropriate(
ctx: RunContextWrapper[Any], # Context provided by Runner
agent: Agent, # The agent running this guardrail
response_content: str | list[TResponseInputItem] # The agent's output
) -> GuardrailFunctionOutput:
"""
Output guardrail to check if the agent's response is appropriate.
(Placeholder - currently allows all responses.)
"""
# In a real implementation, you might check for profanity, sensitive data, etc.
return GuardrailFunctionOutput(
tripwire_triggered=False,
output_info=None,
)