/ examples / guardrail_example_fixed.py
guardrail_example_fixed.py
  1  #!/usr/bin/env python3
  2  """
  3  Fixed example demonstrating proper guardrail usage with PraisonAI Agents.
  4  This addresses the issues reported in issue #875.
  5  """
  6  
  7  from praisonaiagents import Agent, Task, GuardrailResult, AgentTeam, TaskOutput
  8  from typing import Tuple, Any
  9  import trafilatura
 10  
 11  # Example 1: Using GuardrailResult return type (now supported!)
 12  def validate_length_guardrailresult(output: TaskOutput) -> GuardrailResult:
 13      """Ensure output is between 100-500 characters using GuardrailResult"""
 14      # Extract the raw text from the TaskOutput object
 15      text = output.raw if hasattr(output, 'raw') else str(output)
 16      length = len(text)
 17      
 18      if 100 <= length <= 500:
 19          return GuardrailResult(
 20              success=True,
 21              result=output,  # Pass through the original output
 22              error=""
 23          )
 24      else:
 25          return GuardrailResult(
 26              success=False,
 27              result=None,
 28              error=f"Output must be 100-500 chars, got {length}"
 29          )
 30  
 31  # Example 2: Using Tuple[bool, Any] return type (original method)
 32  def validate_length_tuple(output: TaskOutput) -> Tuple[bool, Any]:
 33      """Ensure output is between 100-500 characters using tuple"""
 34      text = output.raw if hasattr(output, 'raw') else str(output)
 35      length = len(text)
 36      
 37      if 100 <= length <= 500:
 38          return True, output
 39      else:
 40          return False, f"Output must be 100-500 chars, got {length}"
 41  
 42  # Tool function
 43  def get_url_context(url):
 44      """Fetch and extract content from a URL"""
 45      downloaded = trafilatura.fetch_url(url)
 46      if not downloaded:
 47          return "Sorry, I couldn't fetch the content from that URL."
 48  
 49      extracted = trafilatura.extract(
 50          downloaded,
 51          include_comments=False,
 52          include_links=True,
 53          output_format='json',
 54          with_metadata=True,
 55          url=url
 56      )
 57  
 58      if not extracted:
 59          return "Sorry, I couldn't extract readable content from that page."
 60  
 61      return extracted  # returns JSON string
 62  
 63  # Create agent with FIXED tools parameter (must be a list!)
 64  agent = Agent(
 65      name="Content Summarizer",
 66      role="Content Analysis Expert",
 67      goal="Summarize web content concisely",
 68      instructions="You are a helpful assistant that summarizes web content",
 69      llm="gemini/gemini-2.5-flash-lite-preview-06-17",
 70      reflection=False,
 71      output="verbose",  # Use new consolidated param
 72      tools=[get_url_context]  # FIX: tools must be a list, not a single function
 73  )
 74  
 75  # Create task with GuardrailResult guardrail
 76  task_with_guardrailresult = Task(
 77      name="summarise article with GuardrailResult",
 78      description="get the context of this url: https://blog.google/technology/ai/dolphingemma/ and produce a summary below 500 characters",
 79      agent=agent,
 80      guardrails=validate_length_guardrailresult,  # Using GuardrailResult
 81      expected_output="summary of the article below 500 characters",
 82      max_retries=3  # Will retry up to 3 times if guardrail fails
 83  )
 84  
 85  # Alternative: Create task with tuple guardrail
 86  task_with_tuple = Task(
 87      name="summarise article with tuple",
 88      description="get the context of this url: https://blog.google/technology/ai/dolphingemma/ and produce a summary below 500 characters",
 89      agent=agent,
 90      guardrails=validate_length_tuple,  # Using Tuple[bool, Any]
 91      expected_output="summary of the article below 500 characters",
 92      max_retries=3
 93  )
 94  
 95  # Example with string-based LLM guardrail
 96  task_with_llm_guardrail = Task(
 97      name="summarise with LLM guardrail",
 98      description="get the context of this url: https://blog.google/technology/ai/dolphingemma/ and produce a summary",
 99      agent=agent,
100      guardrails="Ensure the summary is professional, factual, and between 100-500 characters",
101      expected_output="professional summary of the article"
102  )
103  
104  # Run with GuardrailResult example
105  print("=== Running with GuardrailResult guardrail ===")
106  agents_gr = AgentTeam(
107      agents=[agent],
108      tasks=[task_with_guardrailresult]
109  )
110  
111  # Uncomment to run:
112  # result_gr = agents_gr.start()
113  
114  # Run with Tuple example
115  print("\n=== Running with Tuple[bool, Any] guardrail ===")
116  agents_tuple = AgentTeam(
117      agents=[agent],
118      tasks=[task_with_tuple]
119  )
120  
121  # Uncomment to run:
122  # result_tuple = agents_tuple.start()
123  
124  # Run with LLM guardrail example
125  print("\n=== Running with LLM-based guardrail ===")
126  agents_llm = AgentTeam(
127      agents=[agent],
128      tasks=[task_with_llm_guardrail]
129  )
130  
131  # Uncomment to run:
132  # result_llm = agents_llm.start()
133  
134  print("""
135  Key fixes applied:
136  1. GuardrailResult is now accepted as a valid return type annotation
137  2. tools parameter must be a list: tools=[get_url_context] not tools=get_url_context
138  3. Both GuardrailResult and Tuple[bool, Any] return types are supported
139  4. String-based LLM guardrails are also supported
140  
141  The guardrail will automatically retry (up to max_retries times) if validation fails.
142  """)