Description
There is confusion and inconsistent behavior when using the guardrail argument in the Task class. The documentation and type hints suggest using a GuardrailResult return type, but this results in a ValueError. When switching to the expected tuple return type, a different runtime error occurs.
Environment
- Provider (select one):
- PraisonAI version:
- Operating System:
Full Code
from praisonaiagents import Agent, Task, GuardrailResult, PraisonAIAgents
import trafilatura
def validate_length(output: str) -> GuardrailResult:
"""Ensure output is between 100-500 characters"""
length = len(output)
if 100 <= length <= 500:
return GuardrailResult(
is_valid=True,
message="Output length is appropriate"
)
else:
return GuardrailResult(
is_valid=False,
message=f"Output must be 100-500 chars, got {length}"
)
def get_url_context(url):
downloaded = trafilatura.fetch_url(url)
if not downloaded:
return "Sorry, I couldn't fetch the content from that URL."
extracted = trafilatura.extract(
downloaded,
include_comments=False,
include_links=True,
output_format='json',
with_metadata=True,
url=url
)
if not extracted:
return "Sorry, I couldn't extract readable content from that page."
return extracted # returns JSON string with 'text', 'title', 'author', 'date', etc.
agent = Agent(
instructions="You are a helpful assistant",
llm="gemini/gemini-2.5-flash-lite-preview-06-17",
self_reflect=False,
verbose=True,
tools=get_url_context
)
task = Task(
name="summarise article",
description="get the context of this url: https://blog.google/technology/ai/dolphingemma/ and produce a summary below 500 characters",
agent=agent,
guardrail=validate_length,
expected_output="summary of the article below 500 characters"
)
agents = PraisonAIAgents(
agents=[agent],
tasks=[task]
)
agents.start()
or
from praisonaiagents import Agent, Task, GuardrailResult, PraisonAIAgents
import trafilatura
from typing import Tuple, Any
def validate_length(output: str) -> Tuple[bool, Any]:
"""Ensure output is between 100-500 characters"""
length = len(output)
if 100 <= length <= 500:
return True, "Output length is appropriate"
else:
return False, f"Output must be 100-500 chars, got {length}"
def get_url_context(url):
downloaded = trafilatura.fetch_url(url)
if not downloaded:
return "Sorry, I couldn't fetch the content from that URL."
extracted = trafilatura.extract(
downloaded,
include_comments=False,
include_links=True,
output_format='json',
with_metadata=True,
url=url
)
if not extracted:
return "Sorry, I couldn't extract readable content from that page."
return extracted # returns JSON string with 'text', 'title', 'author', 'date', etc.
agent = Agent(
instructions="You are a helpful assistant",
llm="gemini/gemini-2.5-flash-lite-preview-06-17",
self_reflect=False,
verbose=True,
tools=get_url_context
)
task = Task(
name="summarise article",
description="get the context of this url: https://blog.google/technology/ai/dolphingemma/ and produce a summary below 500 characters",
agent=agent,
guardrail=validate_length,
expected_output="summary of the article below 500 characters"
)
agents = PraisonAIAgents(
agents=[agent],
tasks=[task]
)
agents.start()
Steps to Reproduce
- install the library
2.copy the scripts above
- run the scripts
Expected Behavior
According to the official documentation, a function guardrail should return a GuardrailResult object, and this should be accepted and work without error.
The library should not raise a ValueError when using the documented return type.
If an alternative return type (such as Tuple[bool, Any]) is supported, it should be clearly documented and function correctly without runtime errors.
The guardrail mechanism should validate outputs as intended and provide clear, actionable error messages if validation fails.
Actual Behavior
When using a function guardrail that returns a GuardrailResult (as shown in the official documentation), running the code results in a ValueError stating:
"If return type is annotated, it must be Tuple[bool, Any]"
When switching the guardrail function to return a Tuple[bool, Any] (as the error message suggests), running the code results in repeated runtime errors:
"'function' object is not iterable"
The process hangs and does not complete the task.
Additional Context
The errors:
ValueError: If return type is annotated, it must be Tuple[bool, Any]
and
Error in get_response: 'function' object is not iterable
Error in LLM chat: 'function' object is not iterable
Description
There is confusion and inconsistent behavior when using the guardrail argument in the Task class. The documentation and type hints suggest using a GuardrailResult return type, but this results in a ValueError. When switching to the expected tuple return type, a different runtime error occurs.
Environment
Full Code
or
Steps to Reproduce
2.copy the scripts above
Expected Behavior
According to the official documentation, a function guardrail should return a GuardrailResult object, and this should be accepted and work without error.
The library should not raise a ValueError when using the documented return type.
If an alternative return type (such as Tuple[bool, Any]) is supported, it should be clearly documented and function correctly without runtime errors.
The guardrail mechanism should validate outputs as intended and provide clear, actionable error messages if validation fails.
Actual Behavior
When using a function guardrail that returns a GuardrailResult (as shown in the official documentation), running the code results in a ValueError stating:
"If return type is annotated, it must be Tuple[bool, Any]"
When switching the guardrail function to return a Tuple[bool, Any] (as the error message suggests), running the code results in repeated runtime errors:
"'function' object is not iterable"
The process hangs and does not complete the task.
Additional Context
The errors:
ValueError: If return type is annotated, it must be Tuple[bool, Any]
and
Error in get_response: 'function' object is not iterable
Error in LLM chat: 'function' object is not iterable