Skip to content

Inconsistent Guardrail API: ValueError with GuardrailResult, "'function' object is not iterable" with Tuple[bool, Any] #875

@mzazakeith

Description

@mzazakeith

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):
    • Anthropic
    • OpenAI
    • [X ] Google Vertex AI
    • AWS Bedrock
    • Other:
  • 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

  1. install the library
    2.copy the scripts above
  2. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions