mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-07 15:18:29 +00:00
Compare commits
3 Commits
lg-guardra
...
devin/1745
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90359dbbfb | ||
|
|
1133994ec7 | ||
|
|
aa1d04af41 |
@@ -255,11 +255,7 @@ custom_agent = Agent(
|
||||
- `response_template`: Formats agent responses
|
||||
|
||||
<Note>
|
||||
When using custom templates, ensure that both `system_template` and `prompt_template` are defined. The `response_template` is optional but recommended for consistent output formatting.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
When using custom templates, you can use variables like `{role}`, `{goal}`, and `{backstory}` in your templates. These will be automatically populated during execution.
|
||||
When using custom templates, you can use variables like `{role}`, `{goal}`, and `{input}` in your templates. These will be automatically populated during execution.
|
||||
</Note>
|
||||
|
||||
## Agent Tools
|
||||
|
||||
@@ -322,10 +322,6 @@ blog_task = Task(
|
||||
- On success: it returns a tuple of `(bool, Any)`. For example: `(True, validated_result)`
|
||||
- On Failure: it returns a tuple of `(bool, str)`. For example: `(False, "Error message explain the failure")`
|
||||
|
||||
### TaskGuardrail
|
||||
|
||||
The `TaskGuardrail` class offers a robust mechanism for validating task outputs
|
||||
|
||||
### Error Handling Best Practices
|
||||
|
||||
1. **Structured Error Responses**:
|
||||
@@ -754,8 +750,6 @@ Task guardrails provide a powerful way to validate, transform, or filter task ou
|
||||
|
||||
### Basic Usage
|
||||
|
||||
#### Define your own logic to validate
|
||||
|
||||
```python Code
|
||||
from typing import Tuple, Union
|
||||
from crewai import Task
|
||||
@@ -775,57 +769,6 @@ task = Task(
|
||||
)
|
||||
```
|
||||
|
||||
#### Leverage a no-code approach for validation
|
||||
|
||||
```python Code
|
||||
from crewai import Task
|
||||
|
||||
task = Task(
|
||||
description="Generate JSON data",
|
||||
expected_output="Valid JSON object",
|
||||
guardrail="Ensure the response is a valid JSON object"
|
||||
)
|
||||
```
|
||||
|
||||
#### Using YAML
|
||||
|
||||
```yaml
|
||||
research_task:
|
||||
...
|
||||
guardrail: make sure each bullet contains a minimum of 100 words
|
||||
...
|
||||
```
|
||||
|
||||
```python Code
|
||||
@CrewBase
|
||||
class InternalCrew:
|
||||
agents_config = "config/agents.yaml"
|
||||
tasks_config = "config/tasks.yaml"
|
||||
|
||||
...
|
||||
@task
|
||||
def research_task(self):
|
||||
return Task(config=self.tasks_config["research_task"]) # type: ignore[index]
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
#### Use custom models for code generation
|
||||
|
||||
```python Code
|
||||
from crewai import Task
|
||||
from crewai.llm import LLM
|
||||
|
||||
task = Task(
|
||||
description="Generate JSON data",
|
||||
expected_output="Valid JSON object",
|
||||
guardrail=TaskGuardrail(
|
||||
description="Ensure the response is a valid JSON object",
|
||||
llm=LLM(model="gpt-4o-mini"),
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
### How Guardrails Work
|
||||
|
||||
1. **Optional Attribute**: Guardrails are an optional attribute at the task level, allowing you to add validation only where needed.
|
||||
|
||||
@@ -190,6 +190,48 @@ def my_tool(question: str) -> str:
|
||||
return "Result from your custom tool"
|
||||
```
|
||||
|
||||
### Structured Tools
|
||||
|
||||
The `StructuredTool` class wraps functions as tools, providing flexibility and validation while reducing boilerplate. It supports custom schemas and dynamic logic for seamless integration of complex functionalities.
|
||||
|
||||
#### Example:
|
||||
Using `StructuredTool.from_function`, you can wrap a function that interacts with an external API or system, providing a structured interface. This enables robust validation and consistent execution, making it easier to integrate complex functionalities into your applications as demonstrated in the following example:
|
||||
|
||||
```python
|
||||
from crewai.tools.structured_tool import CrewStructuredTool
|
||||
from pydantic import BaseModel
|
||||
|
||||
# Define the schema for the tool's input using Pydantic
|
||||
class APICallInput(BaseModel):
|
||||
endpoint: str
|
||||
parameters: dict
|
||||
|
||||
# Wrapper function to execute the API call
|
||||
def tool_wrapper(*args, **kwargs):
|
||||
# Here, you would typically call the API using the parameters
|
||||
# For demonstration, we'll return a placeholder string
|
||||
return f"Call the API at {kwargs['endpoint']} with parameters {kwargs['parameters']}"
|
||||
|
||||
# Create and return the structured tool
|
||||
def create_structured_tool():
|
||||
return CrewStructuredTool.from_function(
|
||||
name='Wrapper API',
|
||||
description="A tool to wrap API calls with structured input.",
|
||||
args_schema=APICallInput,
|
||||
func=tool_wrapper,
|
||||
)
|
||||
|
||||
# Example usage
|
||||
structured_tool = create_structured_tool()
|
||||
|
||||
# Execute the tool with structured input
|
||||
result = structured_tool._run(**{
|
||||
"endpoint": "https://example.com/api",
|
||||
"parameters": {"key1": "value1", "key2": "value2"}
|
||||
})
|
||||
print(result) # Output: Call the API at https://example.com/api with parameters {'key1': 'value1', 'key2': 'value2'}
|
||||
```
|
||||
|
||||
### Custom Caching Mechanism
|
||||
|
||||
<Tip>
|
||||
|
||||
@@ -11,7 +11,7 @@ dependencies = [
|
||||
# Core Dependencies
|
||||
"pydantic>=2.4.2",
|
||||
"openai>=1.13.3",
|
||||
"litellm==1.67.1",
|
||||
"litellm==1.67.2",
|
||||
"instructor>=1.3.3",
|
||||
# Text Processing
|
||||
"pdfplumber>=0.11.4",
|
||||
@@ -45,7 +45,7 @@ Documentation = "https://docs.crewai.com"
|
||||
Repository = "https://github.com/crewAIInc/crewAI"
|
||||
|
||||
[project.optional-dependencies]
|
||||
tools = ["crewai-tools~=0.42.2"]
|
||||
tools = ["crewai-tools~=0.42.0"]
|
||||
embeddings = [
|
||||
"tiktoken~=0.7.0"
|
||||
]
|
||||
@@ -60,7 +60,7 @@ pandas = [
|
||||
openpyxl = [
|
||||
"openpyxl>=3.1.5",
|
||||
]
|
||||
mem0 = ["mem0ai>=0.1.94"]
|
||||
mem0 = ["mem0ai>=0.1.29"]
|
||||
docling = [
|
||||
"docling>=2.12.0",
|
||||
]
|
||||
|
||||
@@ -17,6 +17,7 @@ from crewai.security import Fingerprint
|
||||
from crewai.task import Task
|
||||
from crewai.tools import BaseTool
|
||||
from crewai.tools.agent_tools.agent_tools import AgentTools
|
||||
from crewai.tools.structured_tool import CrewStructuredTool
|
||||
from crewai.utilities import Converter, Prompts
|
||||
from crewai.utilities.agent_utils import (
|
||||
get_tool_names,
|
||||
@@ -185,7 +186,7 @@ class Agent(BaseAgent):
|
||||
self,
|
||||
task: Task,
|
||||
context: Optional[str] = None,
|
||||
tools: Optional[List[BaseTool]] = None
|
||||
tools: Optional[List[Union[BaseTool, CrewStructuredTool]]] = None
|
||||
) -> str:
|
||||
"""Execute a task with the agent.
|
||||
|
||||
@@ -406,14 +407,14 @@ class Agent(BaseAgent):
|
||||
)["output"]
|
||||
|
||||
def create_agent_executor(
|
||||
self, tools: Optional[List[BaseTool]] = None, task=None
|
||||
self, tools: Optional[List[Union[BaseTool, CrewStructuredTool]]] = None, task=None
|
||||
) -> None:
|
||||
"""Create an agent executor for the agent.
|
||||
|
||||
Returns:
|
||||
An instance of the CrewAgentExecutor class.
|
||||
"""
|
||||
raw_tools: List[BaseTool] = tools or self.tools or []
|
||||
raw_tools: List[Union[BaseTool, CrewStructuredTool]] = tools or self.tools or []
|
||||
parsed_tools = parse_tools(raw_tools)
|
||||
|
||||
prompt = Prompts(
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""LangGraph adapter for crewAI."""
|
||||
@@ -1 +0,0 @@
|
||||
"""OpenAI agent adapters for crewAI."""
|
||||
@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
|
||||
authors = [{ name = "Your Name", email = "you@example.com" }]
|
||||
requires-python = ">=3.10,<3.13"
|
||||
dependencies = [
|
||||
"crewai[tools]>=0.117.1,<1.0.0"
|
||||
"crewai[tools]>=0.117.0,<1.0.0"
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""Poem crew template."""
|
||||
@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
|
||||
authors = [{ name = "Your Name", email = "you@example.com" }]
|
||||
requires-python = ">=3.10,<3.13"
|
||||
dependencies = [
|
||||
"crewai[tools]>=0.117.1,<1.0.0",
|
||||
"crewai[tools]>=0.117.0,<1.0.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@@ -5,7 +5,7 @@ description = "Power up your crews with {{folder_name}}"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10,<3.13"
|
||||
dependencies = [
|
||||
"crewai[tools]>=0.117.1"
|
||||
"crewai[tools]>=0.117.0"
|
||||
]
|
||||
|
||||
[tool.crewai]
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""Knowledge utilities for crewAI."""
|
||||
@@ -483,7 +483,6 @@ class LLM(BaseLLM):
|
||||
full_response += chunk_content
|
||||
|
||||
# Emit the chunk event
|
||||
assert hasattr(crewai_event_bus, "emit")
|
||||
crewai_event_bus.emit(
|
||||
self,
|
||||
event=LLMStreamChunkEvent(chunk=chunk_content),
|
||||
@@ -612,7 +611,6 @@ class LLM(BaseLLM):
|
||||
return full_response
|
||||
|
||||
# Emit failed event and re-raise the exception
|
||||
assert hasattr(crewai_event_bus, "emit")
|
||||
crewai_event_bus.emit(
|
||||
self,
|
||||
event=LLMCallFailedEvent(error=str(e)),
|
||||
@@ -635,7 +633,7 @@ class LLM(BaseLLM):
|
||||
current_tool_accumulator.function.arguments += (
|
||||
tool_call.function.arguments
|
||||
)
|
||||
assert hasattr(crewai_event_bus, "emit")
|
||||
|
||||
crewai_event_bus.emit(
|
||||
self,
|
||||
event=LLMStreamChunkEvent(
|
||||
@@ -808,7 +806,6 @@ class LLM(BaseLLM):
|
||||
function_name, lambda: None
|
||||
) # Ensure fn is always a callable
|
||||
logging.error(f"Error executing function '{function_name}': {e}")
|
||||
assert hasattr(crewai_event_bus, "emit")
|
||||
crewai_event_bus.emit(
|
||||
self,
|
||||
event=LLMCallFailedEvent(error=f"Tool execution error: {str(e)}"),
|
||||
@@ -846,7 +843,6 @@ class LLM(BaseLLM):
|
||||
LLMContextLengthExceededException: If input exceeds model's context limit
|
||||
"""
|
||||
# --- 1) Emit call started event
|
||||
assert hasattr(crewai_event_bus, "emit")
|
||||
crewai_event_bus.emit(
|
||||
self,
|
||||
event=LLMCallStartedEvent(
|
||||
@@ -895,7 +891,6 @@ class LLM(BaseLLM):
|
||||
# whether to summarize the content or abort based on the respect_context_window flag
|
||||
raise
|
||||
except Exception as e:
|
||||
assert hasattr(crewai_event_bus, "emit")
|
||||
crewai_event_bus.emit(
|
||||
self,
|
||||
event=LLMCallFailedEvent(error=str(e)),
|
||||
@@ -910,7 +905,6 @@ class LLM(BaseLLM):
|
||||
response (str): The response from the LLM call.
|
||||
call_type (str): The type of call, either "tool_call" or "llm_call".
|
||||
"""
|
||||
assert hasattr(crewai_event_bus, "emit")
|
||||
crewai_event_bus.emit(
|
||||
self,
|
||||
event=LLMCallCompletedEvent(response=response, call_type=call_type),
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""LLM implementations for crewAI."""
|
||||
1
src/crewai/llms/third_party/__init__.py
vendored
1
src/crewai/llms/third_party/__init__.py
vendored
@@ -1 +0,0 @@
|
||||
"""Third-party LLM implementations for crewAI."""
|
||||
@@ -1 +0,0 @@
|
||||
"""Memory storage implementations for crewAI."""
|
||||
@@ -88,9 +88,7 @@ class Mem0Storage(Storage):
|
||||
}
|
||||
|
||||
if params:
|
||||
if isinstance(self.memory, MemoryClient):
|
||||
params["output_format"] = "v1.1"
|
||||
self.memory.add(value, **params)
|
||||
self.memory.add(value, **params | {"output_format": "v1.1"})
|
||||
|
||||
def search(
|
||||
self,
|
||||
@@ -98,7 +96,7 @@ class Mem0Storage(Storage):
|
||||
limit: int = 3,
|
||||
score_threshold: float = 0.35,
|
||||
) -> List[Any]:
|
||||
params = {"query": query, "limit": limit, "output_format": "v1.1"}
|
||||
params = {"query": query, "limit": limit}
|
||||
if user_id := self._get_user_id():
|
||||
params["user_id"] = user_id
|
||||
|
||||
@@ -118,11 +116,8 @@ class Mem0Storage(Storage):
|
||||
|
||||
# Discard the filters for now since we create the filters
|
||||
# automatically when the crew is created.
|
||||
if isinstance(self.memory, Memory):
|
||||
del params["metadata"], params["output_format"]
|
||||
|
||||
results = self.memory.search(**params)
|
||||
return [r for r in results["results"] if r["score"] >= score_threshold]
|
||||
return [r for r in results if r["score"] >= score_threshold]
|
||||
|
||||
def _get_user_id(self) -> str:
|
||||
return self._get_config().get("user_id", "")
|
||||
|
||||
@@ -8,6 +8,8 @@ from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
|
||||
T = TypeVar("T", bound=type)
|
||||
|
||||
"""Base decorator for creating crew classes with configuration and function management."""
|
||||
@@ -246,9 +248,6 @@ def CrewBase(cls: T) -> T:
|
||||
callback_functions[callback]() for callback in callbacks
|
||||
]
|
||||
|
||||
if guardrail := task_info.get("guardrail"):
|
||||
self.tasks_config[task_name]["guardrail"] = guardrail
|
||||
|
||||
# Include base class (qual)name in the wrapper class (qual)name.
|
||||
WrappedClass.__name__ = CrewBase.__name__ + "(" + cls.__name__ + ")"
|
||||
WrappedClass.__qualname__ = CrewBase.__qualname__ + "(" + cls.__name__ + ")"
|
||||
|
||||
@@ -40,6 +40,7 @@ from crewai.tasks.guardrail_result import GuardrailResult
|
||||
from crewai.tasks.output_format import OutputFormat
|
||||
from crewai.tasks.task_output import TaskOutput
|
||||
from crewai.tools.base_tool import BaseTool
|
||||
from crewai.tools.structured_tool import CrewStructuredTool
|
||||
from crewai.utilities.config import process_config
|
||||
from crewai.utilities.converter import Converter, convert_to_model
|
||||
from crewai.utilities.events import (
|
||||
@@ -72,7 +73,11 @@ class Task(BaseModel):
|
||||
security_config: Security configuration including fingerprinting.
|
||||
tools: List of tools/resources limited for task execution.
|
||||
"""
|
||||
|
||||
|
||||
model_config = {
|
||||
"arbitrary_types_allowed": True,
|
||||
}
|
||||
|
||||
__hash__ = object.__hash__ # type: ignore
|
||||
logger: ClassVar[logging.Logger] = logging.getLogger(__name__)
|
||||
used_tools: int = 0
|
||||
@@ -118,7 +123,7 @@ class Task(BaseModel):
|
||||
output: Optional[TaskOutput] = Field(
|
||||
description="Task output, it's final result after being executed", default=None
|
||||
)
|
||||
tools: Optional[List[BaseTool]] = Field(
|
||||
tools: Optional[List[Union[BaseTool, CrewStructuredTool]]] = Field(
|
||||
default_factory=list,
|
||||
description="Tools the agent is limited to use for this task.",
|
||||
)
|
||||
@@ -140,9 +145,9 @@ class Task(BaseModel):
|
||||
default=None,
|
||||
)
|
||||
processed_by_agents: Set[str] = Field(default_factory=set)
|
||||
guardrail: Optional[Union[Callable[[TaskOutput], Tuple[bool, Any]], str]] = Field(
|
||||
guardrail: Optional[Callable[[TaskOutput], Tuple[bool, Any]]] = Field(
|
||||
default=None,
|
||||
description="Function or string description of a guardrail to validate task output before proceeding to next task",
|
||||
description="Function to validate task output before proceeding to next task",
|
||||
)
|
||||
max_retries: int = Field(
|
||||
default=3, description="Maximum number of retries when guardrail fails"
|
||||
@@ -157,12 +162,8 @@ class Task(BaseModel):
|
||||
|
||||
@field_validator("guardrail")
|
||||
@classmethod
|
||||
def validate_guardrail_function(
|
||||
cls, v: Optional[str | Callable]
|
||||
) -> Optional[str | Callable]:
|
||||
"""
|
||||
If v is a callable, validate that the guardrail function has the correct signature and behavior.
|
||||
If v is a string, return it as is.
|
||||
def validate_guardrail_function(cls, v: Optional[Callable]) -> Optional[Callable]:
|
||||
"""Validate that the guardrail function has the correct signature and behavior.
|
||||
|
||||
While type hints provide static checking, this validator ensures runtime safety by:
|
||||
1. Verifying the function accepts exactly one parameter (the TaskOutput)
|
||||
@@ -175,16 +176,16 @@ class Task(BaseModel):
|
||||
- Clear error messages help users debug guardrail implementation issues
|
||||
|
||||
Args:
|
||||
v: The guardrail function to validate or a string describing the guardrail task
|
||||
v: The guardrail function to validate
|
||||
|
||||
Returns:
|
||||
The validated guardrail function or a string describing the guardrail task
|
||||
The validated guardrail function
|
||||
|
||||
Raises:
|
||||
ValueError: If the function signature is invalid or return annotation
|
||||
doesn't match Tuple[bool, Any]
|
||||
"""
|
||||
if v is not None and callable(v):
|
||||
if v is not None:
|
||||
sig = inspect.signature(v)
|
||||
positional_args = [
|
||||
param
|
||||
@@ -215,7 +216,6 @@ class Task(BaseModel):
|
||||
)
|
||||
return v
|
||||
|
||||
_guardrail: Optional[Callable] = PrivateAttr(default=None)
|
||||
_original_description: Optional[str] = PrivateAttr(default=None)
|
||||
_original_expected_output: Optional[str] = PrivateAttr(default=None)
|
||||
_original_output_file: Optional[str] = PrivateAttr(default=None)
|
||||
@@ -236,20 +236,6 @@ class Task(BaseModel):
|
||||
)
|
||||
return self
|
||||
|
||||
@model_validator(mode="after")
|
||||
def ensure_guardrail_is_callable(self) -> "Task":
|
||||
if callable(self.guardrail):
|
||||
self._guardrail = self.guardrail
|
||||
elif isinstance(self.guardrail, str):
|
||||
from crewai.tasks.task_guardrail import TaskGuardrail
|
||||
|
||||
assert self.agent is not None
|
||||
self._guardrail = TaskGuardrail(
|
||||
description=self.guardrail, llm=self.agent.llm
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
@field_validator("id", mode="before")
|
||||
@classmethod
|
||||
def _deny_user_set_id(cls, v: Optional[UUID4]) -> None:
|
||||
@@ -426,8 +412,10 @@ class Task(BaseModel):
|
||||
output_format=self._get_output_format(),
|
||||
)
|
||||
|
||||
if self._guardrail:
|
||||
guardrail_result = self._process_guardrail(task_output)
|
||||
if self.guardrail:
|
||||
guardrail_result = GuardrailResult.from_tuple(
|
||||
self.guardrail(task_output)
|
||||
)
|
||||
if not guardrail_result.success:
|
||||
if self.retry_count >= self.max_retries:
|
||||
raise Exception(
|
||||
@@ -481,46 +469,13 @@ class Task(BaseModel):
|
||||
)
|
||||
)
|
||||
self._save_file(content)
|
||||
crewai_event_bus.emit(
|
||||
self, TaskCompletedEvent(output=task_output, task=self)
|
||||
)
|
||||
crewai_event_bus.emit(self, TaskCompletedEvent(output=task_output, task=self))
|
||||
return task_output
|
||||
except Exception as e:
|
||||
self.end_time = datetime.datetime.now()
|
||||
crewai_event_bus.emit(self, TaskFailedEvent(error=str(e), task=self))
|
||||
raise e # Re-raise the exception after emitting the event
|
||||
|
||||
def _process_guardrail(self, task_output: TaskOutput) -> GuardrailResult:
|
||||
assert self._guardrail is not None
|
||||
|
||||
from crewai.utilities.events import (
|
||||
TaskGuardrailCompletedEvent,
|
||||
TaskGuardrailStartedEvent,
|
||||
)
|
||||
from crewai.utilities.events.crewai_event_bus import crewai_event_bus
|
||||
|
||||
result = self._guardrail(task_output)
|
||||
|
||||
crewai_event_bus.emit(
|
||||
self,
|
||||
TaskGuardrailStartedEvent(
|
||||
guardrail=self._guardrail, retry_count=self.retry_count
|
||||
),
|
||||
)
|
||||
|
||||
guardrail_result = GuardrailResult.from_tuple(result)
|
||||
|
||||
crewai_event_bus.emit(
|
||||
self,
|
||||
TaskGuardrailCompletedEvent(
|
||||
success=guardrail_result.success,
|
||||
result=guardrail_result.result,
|
||||
error=guardrail_result.error,
|
||||
retry_count=self.retry_count,
|
||||
),
|
||||
)
|
||||
return guardrail_result
|
||||
|
||||
def prompt(self) -> str:
|
||||
"""Prompt the task.
|
||||
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
from typing import Any, Optional, Tuple
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from crewai.agent import Agent, LiteAgentOutput
|
||||
from crewai.llm import LLM
|
||||
from crewai.task import Task
|
||||
from crewai.tasks.task_output import TaskOutput
|
||||
|
||||
|
||||
class TaskGuardrailResult(BaseModel):
|
||||
valid: bool = Field(
|
||||
description="Whether the task output complies with the guardrail"
|
||||
)
|
||||
feedback: str | None = Field(
|
||||
description="A feedback about the task output if it is not valid",
|
||||
default=None,
|
||||
)
|
||||
|
||||
|
||||
class TaskGuardrail:
|
||||
"""It validates the output of another task using an LLM.
|
||||
|
||||
This class is used to validate the output from a Task based on specified criteria.
|
||||
It uses an LLM to validate the output and provides a feedback if the output is not valid.
|
||||
|
||||
Args:
|
||||
description (str): The description of the validation criteria.
|
||||
llm (LLM, optional): The language model to use for code generation.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
description: str,
|
||||
llm: LLM,
|
||||
):
|
||||
self.description = description
|
||||
|
||||
self.llm: LLM = llm
|
||||
|
||||
def _validate_output(self, task_output: TaskOutput) -> LiteAgentOutput:
|
||||
agent = Agent(
|
||||
role="Guardrail Agent",
|
||||
goal="Validate the output of the task",
|
||||
backstory="You are a expert at validating the output of a task. By providing effective feedback if the output is not valid.",
|
||||
llm=self.llm,
|
||||
)
|
||||
|
||||
query = f"""
|
||||
Ensure the following task result complies with the given guardrail.
|
||||
|
||||
Task result:
|
||||
{task_output.raw}
|
||||
|
||||
Guardrail:
|
||||
{self.description}
|
||||
|
||||
Your task:
|
||||
- Confirm if the Task result complies with the guardrail.
|
||||
- If not, provide clear feedback explaining what is wrong (e.g., by how much it violates the rule, or what specific part fails).
|
||||
- Focus only on identifying issues — do not propose corrections.
|
||||
- If the Task result complies with the guardrail, saying that is valid
|
||||
"""
|
||||
|
||||
result = agent.kickoff(query, response_format=TaskGuardrailResult)
|
||||
|
||||
return result
|
||||
|
||||
def __call__(self, task_output: TaskOutput) -> Tuple[bool, Any]:
|
||||
"""Validates the output of a task based on specified criteria.
|
||||
|
||||
Args:
|
||||
task_output (TaskOutput): The output to be validated.
|
||||
|
||||
Returns:
|
||||
Tuple[bool, Any]: A tuple containing:
|
||||
- bool: True if validation passed, False otherwise
|
||||
- Any: The validation result or error message
|
||||
"""
|
||||
|
||||
try:
|
||||
result = self._validate_output(task_output)
|
||||
assert isinstance(
|
||||
result.pydantic, TaskGuardrailResult
|
||||
), "The guardrail result is not a valid pydantic model"
|
||||
|
||||
if result.pydantic.valid:
|
||||
return True, task_output.raw
|
||||
else:
|
||||
return False, result.pydantic.feedback
|
||||
except Exception as e:
|
||||
return False, f"Error while validating the task output: {str(e)}"
|
||||
@@ -1 +0,0 @@
|
||||
"""Agent tools for crewAI."""
|
||||
@@ -21,15 +21,17 @@ from crewai.utilities.exceptions.context_window_exceeding_exception import (
|
||||
)
|
||||
|
||||
|
||||
def parse_tools(tools: List[BaseTool]) -> List[CrewStructuredTool]:
|
||||
def parse_tools(tools: List[Union[BaseTool, CrewStructuredTool]]) -> List[CrewStructuredTool]:
|
||||
"""Parse tools to be used for the task."""
|
||||
tools_list = []
|
||||
|
||||
for tool in tools:
|
||||
if isinstance(tool, CrewAITool):
|
||||
tools_list.append(tool.to_structured_tool())
|
||||
elif isinstance(tool, CrewStructuredTool):
|
||||
tools_list.append(tool)
|
||||
else:
|
||||
raise ValueError("Tool is not a CrewStructuredTool or BaseTool")
|
||||
raise ValueError("Tool must be an instance of BaseTool or CrewStructuredTool")
|
||||
|
||||
return tools_list
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""Evaluators for crewAI."""
|
||||
@@ -9,10 +9,6 @@ from .crew_events import (
|
||||
CrewTestCompletedEvent,
|
||||
CrewTestFailedEvent,
|
||||
)
|
||||
from .task_guardrail_events import (
|
||||
TaskGuardrailCompletedEvent,
|
||||
TaskGuardrailStartedEvent,
|
||||
)
|
||||
from .agent_events import (
|
||||
AgentExecutionStartedEvent,
|
||||
AgentExecutionCompletedEvent,
|
||||
|
||||
@@ -34,10 +34,6 @@ from .task_events import (
|
||||
TaskFailedEvent,
|
||||
TaskStartedEvent,
|
||||
)
|
||||
from .task_guardrail_events import (
|
||||
TaskGuardrailCompletedEvent,
|
||||
TaskGuardrailStartedEvent,
|
||||
)
|
||||
from .tool_usage_events import (
|
||||
ToolUsageErrorEvent,
|
||||
ToolUsageFinishedEvent,
|
||||
@@ -72,6 +68,4 @@ EventTypes = Union[
|
||||
LLMCallCompletedEvent,
|
||||
LLMCallFailedEvent,
|
||||
LLMStreamChunkEvent,
|
||||
TaskGuardrailStartedEvent,
|
||||
TaskGuardrailCompletedEvent,
|
||||
]
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
from typing import Any, Callable, Optional, Union
|
||||
|
||||
from crewai.utilities.events.base_events import BaseEvent
|
||||
|
||||
|
||||
class TaskGuardrailStartedEvent(BaseEvent):
|
||||
"""Event emitted when a guardrail task starts
|
||||
|
||||
Attributes:
|
||||
guardrail: The guardrail callable or TaskGuardrail instance
|
||||
retry_count: The number of times the guardrail has been retried
|
||||
"""
|
||||
|
||||
type: str = "task_guardrail_started"
|
||||
guardrail: Union[str, Callable]
|
||||
retry_count: int
|
||||
|
||||
def __init__(self, **data):
|
||||
from inspect import getsource
|
||||
|
||||
from crewai.tasks.task_guardrail import TaskGuardrail
|
||||
|
||||
super().__init__(**data)
|
||||
|
||||
if isinstance(self.guardrail, TaskGuardrail):
|
||||
self.guardrail = self.guardrail.description.strip()
|
||||
elif isinstance(self.guardrail, Callable):
|
||||
self.guardrail = getsource(self.guardrail).strip()
|
||||
|
||||
|
||||
class TaskGuardrailCompletedEvent(BaseEvent):
|
||||
"""Event emitted when a guardrail task completes"""
|
||||
|
||||
type: str = "task_guardrail_completed"
|
||||
success: bool
|
||||
result: Any
|
||||
error: Optional[str] = None
|
||||
retry_count: int
|
||||
@@ -1 +0,0 @@
|
||||
"""Event utilities for crewAI."""
|
||||
@@ -1 +0,0 @@
|
||||
"""Exceptions for crewAI."""
|
||||
@@ -54,12 +54,10 @@ class Prompts(BaseModel):
|
||||
response_template=None,
|
||||
) -> str:
|
||||
"""Constructs a prompt string from specified components."""
|
||||
if not system_template or not prompt_template:
|
||||
# If any of the required templates are missing, fall back to the default format
|
||||
if not system_template and not prompt_template:
|
||||
prompt_parts = [self.i18n.slice(component) for component in components]
|
||||
prompt = "".join(prompt_parts)
|
||||
else:
|
||||
# All templates are provided, use them
|
||||
prompt_parts = [
|
||||
self.i18n.slice(component)
|
||||
for component in components
|
||||
@@ -69,12 +67,8 @@ class Prompts(BaseModel):
|
||||
prompt = prompt_template.replace(
|
||||
"{{ .Prompt }}", "".join(self.i18n.slice("task"))
|
||||
)
|
||||
# Handle missing response_template
|
||||
if response_template:
|
||||
response = response_template.split("{{ .Response }}")[0]
|
||||
prompt = f"{system}\n{prompt}\n{response}"
|
||||
else:
|
||||
prompt = f"{system}\n{prompt}"
|
||||
response = response_template.split("{{ .Response }}")[0]
|
||||
prompt = f"{system}\n{prompt}\n{response}"
|
||||
|
||||
prompt = (
|
||||
prompt.replace("{goal}", self.agent.goal)
|
||||
|
||||
@@ -72,54 +72,9 @@ def test_agent_creation():
|
||||
assert agent.role == "test role"
|
||||
assert agent.goal == "test goal"
|
||||
assert agent.backstory == "test backstory"
|
||||
|
||||
def test_agent_with_only_system_template():
|
||||
"""Test that an agent with only system_template works without errors."""
|
||||
agent = Agent(
|
||||
role="Test Role",
|
||||
goal="Test Goal",
|
||||
backstory="Test Backstory",
|
||||
allow_delegation=False,
|
||||
system_template="You are a test agent...",
|
||||
# prompt_template is intentionally missing
|
||||
)
|
||||
|
||||
assert agent.role == "Test Role"
|
||||
assert agent.goal == "Test Goal"
|
||||
assert agent.backstory == "Test Backstory"
|
||||
|
||||
def test_agent_with_only_prompt_template():
|
||||
"""Test that an agent with only system_template works without errors."""
|
||||
agent = Agent(
|
||||
role="Test Role",
|
||||
goal="Test Goal",
|
||||
backstory="Test Backstory",
|
||||
allow_delegation=False,
|
||||
prompt_template="You are a test agent...",
|
||||
# prompt_template is intentionally missing
|
||||
)
|
||||
|
||||
assert agent.role == "Test Role"
|
||||
assert agent.goal == "Test Goal"
|
||||
assert agent.backstory == "Test Backstory"
|
||||
assert agent.tools == []
|
||||
|
||||
|
||||
def test_agent_with_missing_response_template():
|
||||
"""Test that an agent with system_template and prompt_template but no response_template works without errors."""
|
||||
agent = Agent(
|
||||
role="Test Role",
|
||||
goal="Test Goal",
|
||||
backstory="Test Backstory",
|
||||
allow_delegation=False,
|
||||
system_template="You are a test agent...",
|
||||
prompt_template="This is a test prompt...",
|
||||
# response_template is intentionally missing
|
||||
)
|
||||
|
||||
assert agent.role == "Test Role"
|
||||
assert agent.goal == "Test Goal"
|
||||
assert agent.backstory == "Test Backstory"
|
||||
|
||||
def test_agent_default_values():
|
||||
agent = Agent(role="test role", goal="test goal", backstory="test backstory")
|
||||
assert agent.llm.model == "gpt-4o-mini"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""Tests for agent adapters."""
|
||||
@@ -1 +0,0 @@
|
||||
"""Tests for agent builder."""
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,713 +0,0 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"messages": [{"role": "system", "content": "You are Test Agent. Test Backstory\nYour
|
||||
personal goal is: Test Goal\nTo give my best complete final answer to the task
|
||||
respond using the exact following format:\n\nThought: I now can give a great
|
||||
answer\nFinal Answer: Your final answer must be the great and the most complete
|
||||
as possible, it must be outcome described.\n\nI MUST use these formats, my job
|
||||
depends on it!"}, {"role": "user", "content": "\nCurrent Task: Gather information
|
||||
about available books on the First World War\n\nThis is the expected criteria
|
||||
for your final answer: A list of available books on the First World War\nyou
|
||||
MUST return the actual complete content as the final answer, not a summary.\n\nBegin!
|
||||
This is VERY important to you, use the tools available and give your best Final
|
||||
Answer, your job depends on it!\n\nThought:"}], "model": "gpt-4o-mini", "stop":
|
||||
["\nObservation:"]}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '903'
|
||||
content-type:
|
||||
- application/json
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.68.2
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.68.2
|
||||
x-stainless-raw-response:
|
||||
- 'true'
|
||||
x-stainless-read-timeout:
|
||||
- '600.0'
|
||||
x-stainless-retry-count:
|
||||
- '0'
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.12.9
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/chat/completions
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
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
|
||||
7H3e+xcAAP//AwDV5F0jzwsAAA==
|
||||
headers:
|
||||
CF-RAY:
|
||||
- 937ec970ab837df5-GRU
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Tue, 29 Apr 2025 12:26:28 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Set-Cookie:
|
||||
- __cf_bm=lSQwOucDEe7UVr7Rj6WZvsTkBkgGT9q7hgVX9AzK42s-1745929588-1.0.1.1-6m0TeDAKI0Hgbl6.GmWHMBMkIpmnfhOu3jQKfjmcvWLHqWUWoE1O4xa9VCtZYXv6_9poUVQq_oCNtzy8eL1XDc8_J3aRMOG3LCvOyvqCawk;
|
||||
path=/; expires=Tue, 29-Apr-25 12:56:28 GMT; domain=.api.openai.com; HttpOnly;
|
||||
Secure; SameSite=None
|
||||
- _cfuvid=TeUS2y0sO.6zigvKZd5.0zRS7sujoYCd9.wMQJboxxo-1745929588265-0.0.1.1-604800000;
|
||||
path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
access-control-expose-headers:
|
||||
- X-Request-ID
|
||||
alt-svc:
|
||||
- h3=":443"; ma=86400
|
||||
cf-cache-status:
|
||||
- DYNAMIC
|
||||
openai-organization:
|
||||
- crewai-iuxna1
|
||||
openai-processing-ms:
|
||||
- '10782'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
x-ratelimit-limit-requests:
|
||||
- '30000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '150000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '29999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '149999808'
|
||||
x-ratelimit-reset-requests:
|
||||
- 2ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 0s
|
||||
x-request-id:
|
||||
- req_cbf6ad64d8b470c6d9eff91852f85e1c
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: '{"messages": [{"role": "system", "content": "You are Guardrail Agent. You
|
||||
are a expert at validating the output of a task. By providing effective feedback
|
||||
if the output is not valid.\nYour personal goal is: Validate the output of the
|
||||
task\n\nTo give my best complete final answer to the task respond using the
|
||||
exact following format:\n\nThought: I now can give a great answer\nFinal Answer:
|
||||
Your final answer must be the great and the most complete as possible, it must
|
||||
be outcome described.\n\nI MUST use these formats, my job depends on it!\nIMPORTANT:
|
||||
Your final answer MUST contain all the information requested in the following
|
||||
format: {\n \"valid\": bool,\n \"feedback\": str | None\n}\n\nIMPORTANT: Ensure
|
||||
the final output does not include any code block markers like ```json or ```python."},
|
||||
{"role": "user", "content": "\n Ensure the following task result complies
|
||||
with the given guardrail.\n\n Task result:\n Here is a list of
|
||||
notable books on the First World War, encompassing various perspectives and
|
||||
themes:\n\n1. **\"All Quiet on the Western Front\" by Erich Maria Remarque**
|
||||
- A novel depicting the experiences of German soldiers during World War I, highlighting
|
||||
the horrors of trench warfare.\n\n2. **\"The First World War\" by John Keegan**
|
||||
- A comprehensive overview of the war, analyzing its causes, major battles,
|
||||
and consequences.\n\n3. **\"A World Undone: The Story of the Great War, 1914
|
||||
to 1918\" by G.J. Meyer** - A narrative history that covers the entire conflict
|
||||
with a focus on key events and figures.\n\n4. **\"The Guns of August\" by Barbara
|
||||
W. Tuchman** - An acclaimed work detailing the events leading up to the war
|
||||
and the early stages of combat, emphasizing the decisions of leaders.\n\n5.
|
||||
**\"Goodbye to All That\" by Robert Graves** - An autobiography that captures
|
||||
the experience of trench warfare from a soldier''s perspective, along with the
|
||||
transition to post-war life.\n\n6. **\"With Our Backs to the Wall: Victory and
|
||||
Defeat in 1918\" by David Stevenson** - An analysis of the final year of the
|
||||
war, outlining both the military strategies and the socio-political contexts
|
||||
that shaped the outcome.\n\n7. **\"The Great War: A Combat History of the First
|
||||
World War\" by Peter Hart** - This book provides a battle-by-battle account,
|
||||
using personal diaries and accounts to bring the war''s events to life.\n\n8.
|
||||
**\"The War to End All Wars: The American Military Experience in World War I\"
|
||||
by Edward M. Coffman** - An exploration of American involvement in the war,
|
||||
discussing military strategies and impacts.\n\n9. **\"Over the Top: A Soldier\u2019s
|
||||
Diary of the First World War\" by Arthur Empey** - A firsthand account of trench
|
||||
warfare written by an American volunteer, offering a raw depiction of combat
|
||||
experiences.\n\n10. **\"The First World War: A New Illustrated History\" by
|
||||
Gordon Corrigan** - A richly illustrated book that presents a chronological
|
||||
history of the war, accessible for readers of all backgrounds.\n\nThis list
|
||||
provides a variety of insights and narratives that capture the complexity and
|
||||
significance of the First World War.\n\n Guardrail:\n Ensure the
|
||||
authors are from Italy\n \n Your task:\n - Confirm if the
|
||||
Task result complies with the guardrail.\n - If not, provide clear feedback
|
||||
explaining what is wrong (e.g., by how much it violates the rule, or what specific
|
||||
part fails).\n - Focus only on identifying issues \u2014 do not propose
|
||||
corrections.\n - If the Task result complies with the guardrail, saying
|
||||
that is valid\n "}], "model": "gpt-4o-mini", "stop": ["\nObservation:"]}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '3636'
|
||||
content-type:
|
||||
- application/json
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.68.2
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.68.2
|
||||
x-stainless-raw-response:
|
||||
- 'true'
|
||||
x-stainless-read-timeout:
|
||||
- '600.0'
|
||||
x-stainless-retry-count:
|
||||
- '0'
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.12.9
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/chat/completions
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAAwAAAP//jFPJbhsxDL37Kwidx4HjOrDjW4qiRZBb4m6oA4OWODNqNNREouwYgf+9
|
||||
0HhNF6CXEYaPyyP5+NoDUNaoKShdo+imdf3393SH+qv9/vLlefXw0MZw/222nn1No9sPQRU5wi9/
|
||||
kpZD1IX2TetIrOcdrAOhUM56OR5dXQ+vryaTDmi8IZfDqlb6I99vLNv+cDAc9Qfj/uVkH117qymq
|
||||
KfzoAQC8dt/Mkw29qCkMioOloRixIjU9OgGo4F22KIzRRkEWVZxA7VmIO+qz2qeqlincAvs1aGSo
|
||||
7IoAocr8ATmuKQDM+aNldHDT/U/hdc4Ac7VCZ81cTaFEF6nYGUsis0T9lO1zNasJBOMTBIrJCRhP
|
||||
EdgLdAPbwNpKDVITVAmDCWgdLEljigTsmcCXHepsFDKASWofImAgKINv4FbQbS7gxrkj1hDnNWTv
|
||||
g5exZUmBOFdNLMFSLMCydslYruAThQZ5U3SVPt/t34ebApANeKkpxALWtdU1rKx3KBQ7n0DPyQbK
|
||||
FUHqPK8DhxQFltTRs8gXczXn7fkOApUpYtYBJ+fOAGT2grmBbvuPe2R73LfzVRv8Mv4WqkrLNtaL
|
||||
QBg9591G8a3q0G0P4LHTVXojFdUG37SyEP9EXbnxaK8rdZLzGTreg+IF3ck+uTwAb/ItDAlaF8+U
|
||||
qTTqmswp9CRjTMb6M6B31vWfbP6We9e55ep/0p8ArakVMos2kLH6bccnt0D52v/ldpxyR1hFCiur
|
||||
aSGWQt6EoRKT292gipso1CxKyxWFNtjdIZbtYvDuejgZDgfXA9Xb9n4BAAD//wMAG/c/OJYEAAA=
|
||||
headers:
|
||||
CF-RAY:
|
||||
- 937ec9b72e717e0f-GRU
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Tue, 29 Apr 2025 12:26:30 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Set-Cookie:
|
||||
- __cf_bm=2Kv7JW0NnxXgvGH0KQnR1VcNF47nEYxhEB4bYlFvRfA-1745929590-1.0.1.1-gmQvNlZR_WoNPIkf.07YchEy.a13FU2sP7wZropzue.84PKf6DVY_clzo6DqmBOk8PtKtM3gV952vhWHuE0ygk7096hW9jQTST91FDi30Jc;
|
||||
path=/; expires=Tue, 29-Apr-25 12:56:30 GMT; domain=.api.openai.com; HttpOnly;
|
||||
Secure; SameSite=None
|
||||
- _cfuvid=HHxY6s22oZkfAHAh8HGGIeDkKOuavigZ5DkKL6.WyGc-1745929590485-0.0.1.1-604800000;
|
||||
path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
access-control-expose-headers:
|
||||
- X-Request-ID
|
||||
alt-svc:
|
||||
- h3=":443"; ma=86400
|
||||
cf-cache-status:
|
||||
- DYNAMIC
|
||||
openai-organization:
|
||||
- crewai-iuxna1
|
||||
openai-processing-ms:
|
||||
- '1744'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
x-ratelimit-limit-requests:
|
||||
- '30000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '150000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '29999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '149999140'
|
||||
x-ratelimit-reset-requests:
|
||||
- 2ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 0s
|
||||
x-request-id:
|
||||
- req_74247d0bd52dcebe834bd1cdb4b38470
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: '{"messages": [{"role": "system", "content": "You are Test Agent. Test Backstory\nYour
|
||||
personal goal is: Test Goal\nTo give my best complete final answer to the task
|
||||
respond using the exact following format:\n\nThought: I now can give a great
|
||||
answer\nFinal Answer: Your final answer must be the great and the most complete
|
||||
as possible, it must be outcome described.\n\nI MUST use these formats, my job
|
||||
depends on it!"}, {"role": "user", "content": "\nCurrent Task: Gather information
|
||||
about available books on the First World War\n\nThis is the expected criteria
|
||||
for your final answer: A list of available books on the First World War\nyou
|
||||
MUST return the actual complete content as the final answer, not a summary.\n\nThis
|
||||
is the context you''re working with:\n### Previous attempt failed validation:
|
||||
The task result does not comply with the guardrail because none of the listed
|
||||
authors are from Italy. All authors mentioned are from different countries,
|
||||
including Germany, the UK, the USA, and others, which violates the requirement
|
||||
that authors must be Italian.\n\n\n### Previous result:\nHere is a list of notable
|
||||
books on the First World War, encompassing various perspectives and themes:\n\n1.
|
||||
**\"All Quiet on the Western Front\" by Erich Maria Remarque** - A novel depicting
|
||||
the experiences of German soldiers during World War I, highlighting the horrors
|
||||
of trench warfare.\n\n2. **\"The First World War\" by John Keegan** - A comprehensive
|
||||
overview of the war, analyzing its causes, major battles, and consequences.\n\n3.
|
||||
**\"A World Undone: The Story of the Great War, 1914 to 1918\" by G.J. Meyer**
|
||||
- A narrative history that covers the entire conflict with a focus on key events
|
||||
and figures.\n\n4. **\"The Guns of August\" by Barbara W. Tuchman** - An acclaimed
|
||||
work detailing the events leading up to the war and the early stages of combat,
|
||||
emphasizing the decisions of leaders.\n\n5. **\"Goodbye to All That\" by Robert
|
||||
Graves** - An autobiography that captures the experience of trench warfare from
|
||||
a soldier''s perspective, along with the transition to post-war life.\n\n6.
|
||||
**\"With Our Backs to the Wall: Victory and Defeat in 1918\" by David Stevenson**
|
||||
- An analysis of the final year of the war, outlining both the military strategies
|
||||
and the socio-political contexts that shaped the outcome.\n\n7. **\"The Great
|
||||
War: A Combat History of the First World War\" by Peter Hart** - This book provides
|
||||
a battle-by-battle account, using personal diaries and accounts to bring the
|
||||
war''s events to life.\n\n8. **\"The War to End All Wars: The American Military
|
||||
Experience in World War I\" by Edward M. Coffman** - An exploration of American
|
||||
involvement in the war, discussing military strategies and impacts.\n\n9. **\"Over
|
||||
the Top: A Soldier\u2019s Diary of the First World War\" by Arthur Empey** -
|
||||
A firsthand account of trench warfare written by an American volunteer, offering
|
||||
a raw depiction of combat experiences.\n\n10. **\"The First World War: A New
|
||||
Illustrated History\" by Gordon Corrigan** - A richly illustrated book that
|
||||
presents a chronological history of the war, accessible for readers of all backgrounds.\n\nThis
|
||||
list provides a variety of insights and narratives that capture the complexity
|
||||
and significance of the First World War.\n\n\nTry again, making sure to address
|
||||
the validation error.\n\nBegin! This is VERY important to you, use the tools
|
||||
available and give your best Final Answer, your job depends on it!\n\nThought:"}],
|
||||
"model": "gpt-4o-mini", "stop": ["\nObservation:"]}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '3509'
|
||||
content-type:
|
||||
- application/json
|
||||
cookie:
|
||||
- __cf_bm=2Kv7JW0NnxXgvGH0KQnR1VcNF47nEYxhEB4bYlFvRfA-1745929590-1.0.1.1-gmQvNlZR_WoNPIkf.07YchEy.a13FU2sP7wZropzue.84PKf6DVY_clzo6DqmBOk8PtKtM3gV952vhWHuE0ygk7096hW9jQTST91FDi30Jc;
|
||||
_cfuvid=HHxY6s22oZkfAHAh8HGGIeDkKOuavigZ5DkKL6.WyGc-1745929590485-0.0.1.1-604800000
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.68.2
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.68.2
|
||||
x-stainless-raw-response:
|
||||
- 'true'
|
||||
x-stainless-read-timeout:
|
||||
- '600.0'
|
||||
x-stainless-retry-count:
|
||||
- '0'
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.12.9
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/chat/completions
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
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
|
||||
headers:
|
||||
CF-RAY:
|
||||
- 937ec9c4b8307e0f-GRU
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Tue, 29 Apr 2025 12:26:41 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
access-control-expose-headers:
|
||||
- X-Request-ID
|
||||
alt-svc:
|
||||
- h3=":443"; ma=86400
|
||||
cf-cache-status:
|
||||
- DYNAMIC
|
||||
openai-organization:
|
||||
- crewai-iuxna1
|
||||
openai-processing-ms:
|
||||
- '10386'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
x-ratelimit-limit-requests:
|
||||
- '30000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '150000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '29999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '149999169'
|
||||
x-ratelimit-reset-requests:
|
||||
- 2ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 0s
|
||||
x-request-id:
|
||||
- req_7e9c58909cf39af106866bae0c0cf7e1
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: '{"messages": [{"role": "system", "content": "You are Guardrail Agent. You
|
||||
are a expert at validating the output of a task. By providing effective feedback
|
||||
if the output is not valid.\nYour personal goal is: Validate the output of the
|
||||
task\n\nTo give my best complete final answer to the task respond using the
|
||||
exact following format:\n\nThought: I now can give a great answer\nFinal Answer:
|
||||
Your final answer must be the great and the most complete as possible, it must
|
||||
be outcome described.\n\nI MUST use these formats, my job depends on it!\nIMPORTANT:
|
||||
Your final answer MUST contain all the information requested in the following
|
||||
format: {\n \"valid\": bool,\n \"feedback\": str | None\n}\n\nIMPORTANT: Ensure
|
||||
the final output does not include any code block markers like ```json or ```python."},
|
||||
{"role": "user", "content": "\n Ensure the following task result complies
|
||||
with the given guardrail.\n\n Task result:\n Here is a list of
|
||||
notable books on the First World War written by Italian authors, incorporating
|
||||
various perspectives and themes:\n\n1. **\"Il mio nome \u00e8 nessuno\" by Dario
|
||||
Fo** - A unique narrative intertwining personal stories and historical facts
|
||||
about the impacts of World War I on Italian society.\n\n2. **\"La guerra dei
|
||||
nostri nonni\" by Mario avagliano and Marco Palmieri** - This book provides
|
||||
a detailed account of the experiences of Italian soldiers during the First World
|
||||
War, focusing on their motivations and struggles.\n\n3. **\"Sulle tracce della
|
||||
Grande Guerra\" by Sergio Staino** - A graphic novel that blends artistic expression
|
||||
with historical narrative to depict the life of soldiers in the trenches of
|
||||
the Great War.\n\n4. **\"L''intera storia della Prima Guerra Mondiale\" by Giuseppe
|
||||
De Lutiis** - A comprehensive overview that explores the geopolitical causes,
|
||||
major battles, and long-term effects of the war on Italy and beyond.\n\n5. **\"La
|
||||
Grande Guerra in Friuli\" by Paolo Cattaruzza** - This book emphasizes the regional
|
||||
impact of World War I in Friuli, highlighting the significant battles and the
|
||||
experiences of local civilians and soldiers.\n\n6. **\"Lettere di un soldato\"
|
||||
by Alessandro F. Brigante** - A collection of letters written by a soldier during
|
||||
the war, providing a personal and intimate perspective on the realities of combat.\n\n7.
|
||||
**\"Azzurri in trincea\" by Mario Isnenghi** - The book examines the experience
|
||||
of Italian soldiers in the front lines, focusing on their culture, morale, and
|
||||
the shared camaraderie among troops.\n\n8. **\"La guerra di Matteo\" by Franco
|
||||
Cardini** - A historical fiction that follows a young Italian man\u2019s journey
|
||||
through the war, offering insights into the emotional and psychological impacts
|
||||
of conflict.\n\n9. **\"1915-1918. La Grande Guerra\" by Andrea Nativi** - A
|
||||
scholarly work that analyzes the strategies and technological advancements employed
|
||||
by Italian forces during the First World War.\n\n10. **\"Il giorno della vittoria\"
|
||||
by Vincenzo Pardini** - A captivating exploration of the final offensives leading
|
||||
to the end of the war, examining how they shaped Italy\u2019s national identity.\n\nThis
|
||||
list highlights a range of Italian authors who offer diverse narratives and
|
||||
profound insights into the multifaceted experiences and legacies of the First
|
||||
World War.\n\n Guardrail:\n Ensure the authors are from Italy\n \n Your
|
||||
task:\n - Confirm if the Task result complies with the guardrail.\n -
|
||||
If not, provide clear feedback explaining what is wrong (e.g., by how much it
|
||||
violates the rule, or what specific part fails).\n - Focus only on identifying
|
||||
issues \u2014 do not propose corrections.\n - If the Task result complies
|
||||
with the guardrail, saying that is valid\n "}], "model": "gpt-4o-mini",
|
||||
"stop": ["\nObservation:"]}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '3829'
|
||||
content-type:
|
||||
- application/json
|
||||
cookie:
|
||||
- __cf_bm=2Kv7JW0NnxXgvGH0KQnR1VcNF47nEYxhEB4bYlFvRfA-1745929590-1.0.1.1-gmQvNlZR_WoNPIkf.07YchEy.a13FU2sP7wZropzue.84PKf6DVY_clzo6DqmBOk8PtKtM3gV952vhWHuE0ygk7096hW9jQTST91FDi30Jc;
|
||||
_cfuvid=HHxY6s22oZkfAHAh8HGGIeDkKOuavigZ5DkKL6.WyGc-1745929590485-0.0.1.1-604800000
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.68.2
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.68.2
|
||||
x-stainless-raw-response:
|
||||
- 'true'
|
||||
x-stainless-read-timeout:
|
||||
- '600.0'
|
||||
x-stainless-retry-count:
|
||||
- '0'
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.12.9
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/chat/completions
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAAwAAAP//jJJNb9swDIbv/hWEzvHgeFmT+NYNKFbstGLADnNhKBJtq5EpQZLTFUH+
|
||||
+yDHiZ19ALsYMB++FF+SxwSAKckKYKLlQXRWpx+f8Av5dXj8vH16kG+f9j6Xuxf5vf56nx3YIirM
|
||||
7gVFuKjeCdNZjUEZOmPhkAeMVZfr1Ydtvr3LlgPojEQdZY0N6cqknSKV5lm+SrN1utyM6tYogZ4V
|
||||
8CMBADgO39gnSfzJCsgWl0iH3vMGWXFNAmDO6Bhh3HvlA6fAFhMUhgLS0Pq31vRNGwp4BDKvIDhB
|
||||
ow4IHJrYP3Dyr+gASnpQxDXcD/8FHEsCKNmBayVLVkBwPS7OsRpR7rjYxzD1Wpd0mj/usO491yOc
|
||||
AU5kAo8DHGw/j+R0NapNY53Z+d+krFakfFs55N5QNOWDsWygpwTgeRhofzMjZp3pbKiC2ePw3Ppu
|
||||
HCib9jjRfDPCYALXM9XmAm7qVRIDV9rPVsIEFy3KSTrtj/dSmRlIZq7/7OZvtc/OFTX/U34CQqAN
|
||||
KCvrUCpx63hKcxjP/F9p1ykPDTOP7qAEVkGhi5uQWPNen4+P+TcfsKtqRQ0669T5AmtbZe+3+SbP
|
||||
s23GklPyCwAA//8DANS97/6PAwAA
|
||||
headers:
|
||||
CF-RAY:
|
||||
- 937eca0769737e0f-GRU
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Tue, 29 Apr 2025 12:26:42 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
access-control-expose-headers:
|
||||
- X-Request-ID
|
||||
alt-svc:
|
||||
- h3=":443"; ma=86400
|
||||
cf-cache-status:
|
||||
- DYNAMIC
|
||||
openai-organization:
|
||||
- crewai-iuxna1
|
||||
openai-processing-ms:
|
||||
- '924'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
x-ratelimit-limit-requests:
|
||||
- '30000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '150000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '29999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '149999094'
|
||||
x-ratelimit-reset-requests:
|
||||
- 2ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 0s
|
||||
x-request-id:
|
||||
- req_242f5797b2a0bf5867b01ab6027921fa
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: '{"messages": [{"role": "system", "content": "You are Test Agent. Test Backstory\nYour
|
||||
personal goal is: Test Goal\nTo give my best complete final answer to the task
|
||||
respond using the exact following format:\n\nThought: I now can give a great
|
||||
answer\nFinal Answer: Your final answer must be the great and the most complete
|
||||
as possible, it must be outcome described.\n\nI MUST use these formats, my job
|
||||
depends on it!"}, {"role": "user", "content": "\nCurrent Task: Test task\n\nThis
|
||||
is the expected criteria for your final answer: Output\nyou MUST return the
|
||||
actual complete content as the final answer, not a summary.\n\nBegin! This is
|
||||
VERY important to you, use the tools available and give your best Final Answer,
|
||||
your job depends on it!\n\nThought:"}], "model": "gpt-4o-mini", "stop": ["\nObservation:"]}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '807'
|
||||
content-type:
|
||||
- application/json
|
||||
cookie:
|
||||
- __cf_bm=2Kv7JW0NnxXgvGH0KQnR1VcNF47nEYxhEB4bYlFvRfA-1745929590-1.0.1.1-gmQvNlZR_WoNPIkf.07YchEy.a13FU2sP7wZropzue.84PKf6DVY_clzo6DqmBOk8PtKtM3gV952vhWHuE0ygk7096hW9jQTST91FDi30Jc;
|
||||
_cfuvid=HHxY6s22oZkfAHAh8HGGIeDkKOuavigZ5DkKL6.WyGc-1745929590485-0.0.1.1-604800000
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.68.2
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.68.2
|
||||
x-stainless-raw-response:
|
||||
- 'true'
|
||||
x-stainless-read-timeout:
|
||||
- '600.0'
|
||||
x-stainless-retry-count:
|
||||
- '0'
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.12.9
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/chat/completions
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAAwAAAP//jFNNTxsxEL3nV4x8TqIQICm5tYeqiAMSqoSqFq0ce3Z3wOvZ2rMbAuK/
|
||||
V/YGNrQcell5583He+Pn5wmAIqs2oEytxTStm325wSuOVw+if3wz14Iu7tZP29vLm+vb05Wapgre
|
||||
3qOR16q54aZ1KMR+gE1ALZi6nqzPzi+WF6vFMgMNW3SprGpldsazhjzNlovl2Wyxnp18OlTXTAaj
|
||||
2sDPCQDAc/4mnt7io9rAYvoaaTBGXaHavCUBqMAuRZSOkaJoL2o6goa9oM/UL8HzDoz2UFGPoKFK
|
||||
tEH7uMMA8Mt/Ja8dfM7/G/heI5guBPQCouMDkO/Z9RihDdyTJV+BBqk5cFfVoL0Fi6LJoYWAsWUf
|
||||
EbY6ogX2IDUCPrZoBC2YQIKBNDTo0xbRzuESduQctAFjnpimD2tOhywCdiQ1dwKxaxod6Il8NQX0
|
||||
sQuJjNRaAHsMe9AxTQKKYLjHgBaEoUEc+gb83VHANDwCliUaoR7dfp41cyeGG3ylk6QiGKcDyT6r
|
||||
TLQC1uhjWiP5kkOjk4yBQdm5kpyLedRgnJTHZQ6kTc6PLyhg2UWdTOI7544A7T1L7putcXdAXt7M
|
||||
4LhqA2/jX6WqJE+xLgLqyD5dfBRuVUZfJgB32XTdOx+pNnDTSiH8gHncyfnp0E+NXh/R1foACot2
|
||||
Y3y5PFj1fb9i8EU8sq0y2tRox9LR47qzxEfA5Ej1v2w+6j0oJ1/9T/sRMAZbQVu0AS2Z94rHtID3
|
||||
2cQfp71tORNWEUNPBgshDOkmLJa6c8MDVXEfBZuiJF9haAMNr7RsC7vVRq8WtlyoycvkDwAAAP//
|
||||
AwC4yvtmswQAAA==
|
||||
headers:
|
||||
CF-RAY:
|
||||
- 937eca0f18177e0f-GRU
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Tue, 29 Apr 2025 12:26:44 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
access-control-expose-headers:
|
||||
- X-Request-ID
|
||||
alt-svc:
|
||||
- h3=":443"; ma=86400
|
||||
cf-cache-status:
|
||||
- DYNAMIC
|
||||
openai-organization:
|
||||
- crewai-iuxna1
|
||||
openai-processing-ms:
|
||||
- '1988'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
x-ratelimit-limit-requests:
|
||||
- '30000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '150000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '29999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '149999832'
|
||||
x-ratelimit-reset-requests:
|
||||
- 2ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 0s
|
||||
x-request-id:
|
||||
- req_99b127ab59c932c0b46dbecc738df8ba
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
@@ -1,288 +0,0 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"messages": [{"role": "system", "content": "You are Test Agent. Test Backstory\nYour
|
||||
personal goal is: Test Goal\nTo give my best complete final answer to the task
|
||||
respond using the exact following format:\n\nThought: I now can give a great
|
||||
answer\nFinal Answer: Your final answer must be the great and the most complete
|
||||
as possible, it must be outcome described.\n\nI MUST use these formats, my job
|
||||
depends on it!"}, {"role": "user", "content": "\nCurrent Task: Gather information
|
||||
about available books on the First World War\n\nThis is the expected criteria
|
||||
for your final answer: A list of available books on the First World War\nyou
|
||||
MUST return the actual complete content as the final answer, not a summary.\n\nBegin!
|
||||
This is VERY important to you, use the tools available and give your best Final
|
||||
Answer, your job depends on it!\n\nThought:"}], "model": "gpt-4o-mini", "stop":
|
||||
["\nObservation:"]}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '903'
|
||||
content-type:
|
||||
- application/json
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.68.2
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.68.2
|
||||
x-stainless-raw-response:
|
||||
- 'true'
|
||||
x-stainless-read-timeout:
|
||||
- '600.0'
|
||||
x-stainless-retry-count:
|
||||
- '0'
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.12.9
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/chat/completions
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
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
|
||||
AAA=
|
||||
headers:
|
||||
CF-RAY:
|
||||
- 937ed42dee2e621f-GRU
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Tue, 29 Apr 2025 12:33:48 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Set-Cookie:
|
||||
- __cf_bm=mLRCnpdB3n_6medIZWHnUu8MNRGZsD6riaRhN47PK74-1745930028-1.0.1.1-M2lDM1_V9hNCK0MZrBnFalF3lndC3JkS8zhDOGww_LmOrgdpU9fZLpNZUmyinCQOnlCjDjDYJUECM82ffT1anqBiO1NoDeNp91EPKiK7s.8;
|
||||
path=/; expires=Tue, 29-Apr-25 13:03:48 GMT; domain=.api.openai.com; HttpOnly;
|
||||
Secure; SameSite=None
|
||||
- _cfuvid=eTrj_ZhCx2XuylS5vYROwUlPrJBwOyrbS2Ki.msl45E-1745930028010-0.0.1.1-604800000;
|
||||
path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
access-control-expose-headers:
|
||||
- X-Request-ID
|
||||
alt-svc:
|
||||
- h3=":443"; ma=86400
|
||||
cf-cache-status:
|
||||
- DYNAMIC
|
||||
openai-organization:
|
||||
- crewai-iuxna1
|
||||
openai-processing-ms:
|
||||
- '10856'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
x-ratelimit-limit-requests:
|
||||
- '30000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '150000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '29999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '149999807'
|
||||
x-ratelimit-reset-requests:
|
||||
- 2ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 0s
|
||||
x-request-id:
|
||||
- req_bc2d62d8325b2bdd3e98544a66389132
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: '{"messages": [{"role": "system", "content": "You are Guardrail Agent. You
|
||||
are a expert at validating the output of a task. By providing effective feedback
|
||||
if the output is not valid.\nYour personal goal is: Validate the output of the
|
||||
task\n\nTo give my best complete final answer to the task respond using the
|
||||
exact following format:\n\nThought: I now can give a great answer\nFinal Answer:
|
||||
Your final answer must be the great and the most complete as possible, it must
|
||||
be outcome described.\n\nI MUST use these formats, my job depends on it!\nIMPORTANT:
|
||||
Your final answer MUST contain all the information requested in the following
|
||||
format: {\n \"valid\": bool,\n \"feedback\": str | None\n}\n\nIMPORTANT: Ensure
|
||||
the final output does not include any code block markers like ```json or ```python."},
|
||||
{"role": "user", "content": "\n Ensure the following task result complies
|
||||
with the given guardrail.\n\n Task result:\n Here is a comprehensive
|
||||
list of available books on the First World War:\n\n1. **\"The Sleepwalkers:
|
||||
How Europe Went to War in 1914\" by Christopher Clark** \n This book delves
|
||||
into the complex factors that led to the outbreak of the war, offering insights
|
||||
into the political and social dynamics of early 20th century Europe.\n\n2. **\"A
|
||||
World Undone: The Story of the Great War, 1914 to 1918\" by G.J. Meyer** \n Meyer''s
|
||||
expansive narrative covers the entire war with a focus on both military strategies
|
||||
and the human experiences endured by soldiers and civilians alike.\n\n3. **\"All
|
||||
Quiet on the Western Front\" by Erich Maria Remarque** \n A poignant novel
|
||||
that captures the resilience and trauma experienced by German soldiers during
|
||||
World War I, based on the author''s own experiences.\n\n4. **\"The First World
|
||||
War\" by John Keegan** \n Keegan provides a detailed military history of
|
||||
the war, featuring insights on battles, strategies, and the overall impact on
|
||||
global affairs.\n\n5. **\"Goodbye to All That\" by Robert Graves** \n This
|
||||
autobiography recounts the author''s experiences as a soldier during the war,
|
||||
offering a personal and critical perspective on the conflicts and the post-war
|
||||
era.\n\n6. **\"Catastrophe 1914: Europe Goes to War\" by Max Hastings** \n Hastings
|
||||
chronicles the events leading up to World War I and the early battles, detailing
|
||||
the war''s initial impact on European societies.\n\n7. **\"The War That Ended
|
||||
Peace: The Road to 1914\" by Margaret MacMillan** \n MacMillan explores the
|
||||
political and historical factors that contributed to the outbreak of war, emphasizing
|
||||
the decisions made by leaders across Europe.\n\n8. **\"The First World War:
|
||||
A Complete History\" by Martin Gilbert** \n This complete history takes readers
|
||||
through the entirety of the war, from its causes to its aftermath, using a wide
|
||||
range of sources.\n\n9. **\"1914: The Year the World Ended\" by Paul Ham** \n Ham
|
||||
focuses on the pivotal year of 1914 and the early war''s devastation, analyzing
|
||||
its long-lasting effects on the world.\n\n10. **\"War Horse\" by Michael Morpurgo** \n This
|
||||
children''s novel tells the story of a horse and his experiences during the
|
||||
war, highlighting the bond between animals and humans amidst the chaos.\n\nEach
|
||||
of these books offers unique perspectives and rich details about the First World
|
||||
War, making them valuable resources for anyone interested in this pivotal period
|
||||
in history.\n\n Guardrail:\n Ensure the authors are from Italy\n \n Your
|
||||
task:\n - Confirm if the Task result complies with the guardrail.\n -
|
||||
If not, provide clear feedback explaining what is wrong (e.g., by how much it
|
||||
violates the rule, or what specific part fails).\n - Focus only on identifying
|
||||
issues \u2014 do not propose corrections.\n - If the Task result complies
|
||||
with the guardrail, saying that is valid\n "}], "model": "gpt-4o-mini",
|
||||
"stop": ["\nObservation:"]}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '3917'
|
||||
content-type:
|
||||
- application/json
|
||||
cookie:
|
||||
- __cf_bm=mLRCnpdB3n_6medIZWHnUu8MNRGZsD6riaRhN47PK74-1745930028-1.0.1.1-M2lDM1_V9hNCK0MZrBnFalF3lndC3JkS8zhDOGww_LmOrgdpU9fZLpNZUmyinCQOnlCjDjDYJUECM82ffT1anqBiO1NoDeNp91EPKiK7s.8;
|
||||
_cfuvid=eTrj_ZhCx2XuylS5vYROwUlPrJBwOyrbS2Ki.msl45E-1745930028010-0.0.1.1-604800000
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.68.2
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.68.2
|
||||
x-stainless-raw-response:
|
||||
- 'true'
|
||||
x-stainless-read-timeout:
|
||||
- '600.0'
|
||||
x-stainless-retry-count:
|
||||
- '0'
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.12.9
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/chat/completions
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAAwAAAP//jFPLbtswELz7KxY8y4HsJHWsW9wiQVq0hzx6aBUIa3IlMaFIlVw5NQL/
|
||||
e0Epiew+gF4EamZnuC8+TwCEViIDIWtk2bRmurqm29X1+/PNzYfL06+fFV8svz2sttuF+XHzUSRR
|
||||
4dYPJPlVdSRd0xpi7exAS0/IFF1ni5PT5XE6m896onGKTJRVLU9P3LTRVk/n6fxkmi6ms7MXde20
|
||||
pCAy+D4BAHjuvzFPq+inyCBNXpGGQsCKRPYWBCC8MxERGIIOjJZFMpLSWSbbp35bu66qOYMrsO4J
|
||||
JFqo9IYAoYr5A9rwRB4gtxfaooHz/j+D59wC5GKDRqtcZFCiCZQMYEmk1igfI56LL84SuBK4JsCO
|
||||
a+cDGB2YFGjbo4zhETyFzjCgJyi9a+CK0WyP4NyYA2VDNraY1BjpuCYP0nWWvaaQQOhkDRjgknyD
|
||||
dpv0BnefEkCrhvPNUS5yu9vviaeyCxjnYjtj9gi01jHGS/tp3L8wu7f+G1e13q3Db1JRaqtDXXjC
|
||||
4GzsdWDXip7dTQDu+zl3B6MTrXdNywW7R+qvWywXg58Y12tk370sgWDHaEb87PRVdeBXKGLUJuxt
|
||||
ipAoa1KjdFwr7JR2e8Rkr+o/s/mb91C5ttX/2I+ElNQyqaL1pLQ8rHgM8xRf37/C3rrcJywC+Y2W
|
||||
VLAmHyehqMTODG9ChG1gaopS24p86/XwMMq2SI+X87P5PF2mYrKb/AIAAP//AwD77a3iJgQAAA==
|
||||
headers:
|
||||
CF-RAY:
|
||||
- 937ed6bd68faa435-GRU
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Tue, 29 Apr 2025 12:35:23 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
access-control-expose-headers:
|
||||
- X-Request-ID
|
||||
alt-svc:
|
||||
- h3=":443"; ma=86400
|
||||
cf-cache-status:
|
||||
- DYNAMIC
|
||||
openai-organization:
|
||||
- crewai-iuxna1
|
||||
openai-processing-ms:
|
||||
- '1138'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
x-ratelimit-limit-requests:
|
||||
- '30000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '150000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '29999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '149999072'
|
||||
x-ratelimit-reset-requests:
|
||||
- 2ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 0s
|
||||
x-request-id:
|
||||
- req_2ba1be014a5974ba354aff564e26516a
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,250 +0,0 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"messages": [{"role": "system", "content": "You are Guardrail Agent. You
|
||||
are a expert at validating the output of a task. By providing effective feedback
|
||||
if the output is not valid.\nYour personal goal is: Validate the output of the
|
||||
task\n\nTo give my best complete final answer to the task respond using the
|
||||
exact following format:\n\nThought: I now can give a great answer\nFinal Answer:
|
||||
Your final answer must be the great and the most complete as possible, it must
|
||||
be outcome described.\n\nI MUST use these formats, my job depends on it!\nIMPORTANT:
|
||||
Your final answer MUST contain all the information requested in the following
|
||||
format: {\n \"valid\": bool,\n \"feedback\": str | None\n}\n\nIMPORTANT: Ensure
|
||||
the final output does not include any code block markers like ```json or ```python."},
|
||||
{"role": "user", "content": "\n Ensure the following task result complies
|
||||
with the given guardrail.\n\n Task result:\n \n Lorem Ipsum
|
||||
is simply dummy text of the printing and typesetting industry. Lorem Ipsum has
|
||||
been the industry''s standard dummy text ever\n \n\n Guardrail:\n Ensure
|
||||
the result has less than 10 words\n \n Your task:\n - Confirm
|
||||
if the Task result complies with the guardrail.\n - If not, provide clear
|
||||
feedback explaining what is wrong (e.g., by how much it violates the rule, or
|
||||
what specific part fails).\n - Focus only on identifying issues \u2014
|
||||
do not propose corrections.\n - If the Task result complies with the
|
||||
guardrail, saying that is valid\n "}], "model": "gpt-4o-mini", "stop":
|
||||
["\nObservation:"]}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '1629'
|
||||
content-type:
|
||||
- application/json
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.68.2
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.68.2
|
||||
x-stainless-raw-response:
|
||||
- 'true'
|
||||
x-stainless-read-timeout:
|
||||
- '600.0'
|
||||
x-stainless-retry-count:
|
||||
- '0'
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.12.9
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/chat/completions
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAAwAAAP//jFPLbtswELz7KxY824GkxLGtW4KiQB+XBmkRtAqENbmSmFAkQVJ2UsP/
|
||||
HlByLKdNgV4IcGdnOPvgbgLApGA5MN5g4K1Vs+ub718rm324+5z+/CLt1dXD5fU3s1jd3Wx//GbT
|
||||
yDDrB+LhlXXGTWsVBWn0AHNHGCiqpouL+XKVZum8B1ojSEVabcPswsxaqeUsS7KLWbKYpcsDuzGS
|
||||
k2c5/JoAAOz6M/rUgp5YDsn0NdKS91gTy49JAMwZFSMMvZc+oA5sOoLc6EC6t37bmK5uQg6fQJst
|
||||
cNRQyw0BQh39A2q/JQdQ6I9So4Kr/p7DrtAABdugkqJgOVSoPE2HYEUk1sgfY7xgtw1BQP8Ijnyn
|
||||
AsTHUWoP6SVsjRN+CvTEiYTUNYSGoO7QCYdSgZKtDGAqqCiaCA1qSJOBBetnOAicFazQ+9MCHVWd
|
||||
x9hk3Sl1AqDWJmAcUt/a+wOyPzZTmdo6s/Z/UFkltfRN6Qi90bFxPhjLenQ/Abjvh9a9mQOzzrQ2
|
||||
lME8Uv/ceTIf9Ni4KyM6Tw9gMAHVCWt+OX1HrxQUUCp/MnbGkTckRuq4I9gJaU6AyUnVf7t5T3uo
|
||||
XOr6f+RHgHOygURpHQnJ31Y8pjmKX+lfaccu94aZJ7eRnMogycVJCKqwU8OCM//sA7VlJXVNzjo5
|
||||
bHlly+R8lS2zLFklbLKfvAAAAP//AwCHe/Jh8wMAAA==
|
||||
headers:
|
||||
CF-RAY:
|
||||
- 937b20ddf9607def-GRU
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Tue, 29 Apr 2025 01:46:56 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Set-Cookie:
|
||||
- __cf_bm=nHa2kVJI_yO1RIsmZcEednJ1e9UVy1liv_sjBNtSj7Q-1745891216-1.0.1.1-jUH9kFawVBjnbq8sIL2.MQx.p7JvBZWUhqlkNKRlStWSgQxT0eZMPcgq9TCQoJAjuyNwhqfpK4HuX6x5n8UbQgAb6JrWJEG823e6GpGROEA;
|
||||
path=/; expires=Tue, 29-Apr-25 02:16:56 GMT; domain=.api.openai.com; HttpOnly;
|
||||
Secure; SameSite=None
|
||||
- _cfuvid=gg2UeahMCOOR8YhitRtzDwENMOnTOuQdyTMVJVHG0Mg-1745891216085-0.0.1.1-604800000;
|
||||
path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
access-control-expose-headers:
|
||||
- X-Request-ID
|
||||
alt-svc:
|
||||
- h3=":443"; ma=86400
|
||||
cf-cache-status:
|
||||
- DYNAMIC
|
||||
openai-organization:
|
||||
- crewai-iuxna1
|
||||
openai-processing-ms:
|
||||
- '896'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
x-ratelimit-limit-requests:
|
||||
- '30000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '150000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '29999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '149999631'
|
||||
x-ratelimit-reset-requests:
|
||||
- 2ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 0s
|
||||
x-request-id:
|
||||
- req_859221ed1aedb26cc9d335004ccf183e
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: '{"messages": [{"role": "system", "content": "You are Guardrail Agent. You
|
||||
are a expert at validating the output of a task. By providing effective feedback
|
||||
if the output is not valid.\nYour personal goal is: Validate the output of the
|
||||
task\n\nTo give my best complete final answer to the task respond using the
|
||||
exact following format:\n\nThought: I now can give a great answer\nFinal Answer:
|
||||
Your final answer must be the great and the most complete as possible, it must
|
||||
be outcome described.\n\nI MUST use these formats, my job depends on it!\nIMPORTANT:
|
||||
Your final answer MUST contain all the information requested in the following
|
||||
format: {\n \"valid\": bool,\n \"feedback\": str | None\n}\n\nIMPORTANT: Ensure
|
||||
the final output does not include any code block markers like ```json or ```python."},
|
||||
{"role": "user", "content": "\n Ensure the following task result complies
|
||||
with the given guardrail.\n\n Task result:\n \n Lorem Ipsum
|
||||
is simply dummy text of the printing and typesetting industry. Lorem Ipsum has
|
||||
been the industry''s standard dummy text ever\n \n\n Guardrail:\n Ensure
|
||||
the result has less than 500 words\n \n Your task:\n -
|
||||
Confirm if the Task result complies with the guardrail.\n - If not, provide
|
||||
clear feedback explaining what is wrong (e.g., by how much it violates the rule,
|
||||
or what specific part fails).\n - Focus only on identifying issues \u2014
|
||||
do not propose corrections.\n - If the Task result complies with the
|
||||
guardrail, saying that is valid\n "}], "model": "gpt-4o-mini", "stop":
|
||||
["\nObservation:"]}'
|
||||
headers:
|
||||
accept:
|
||||
- application/json
|
||||
accept-encoding:
|
||||
- gzip, deflate
|
||||
connection:
|
||||
- keep-alive
|
||||
content-length:
|
||||
- '1630'
|
||||
content-type:
|
||||
- application/json
|
||||
cookie:
|
||||
- __cf_bm=nHa2kVJI_yO1RIsmZcEednJ1e9UVy1liv_sjBNtSj7Q-1745891216-1.0.1.1-jUH9kFawVBjnbq8sIL2.MQx.p7JvBZWUhqlkNKRlStWSgQxT0eZMPcgq9TCQoJAjuyNwhqfpK4HuX6x5n8UbQgAb6JrWJEG823e6GpGROEA;
|
||||
_cfuvid=gg2UeahMCOOR8YhitRtzDwENMOnTOuQdyTMVJVHG0Mg-1745891216085-0.0.1.1-604800000
|
||||
host:
|
||||
- api.openai.com
|
||||
user-agent:
|
||||
- OpenAI/Python 1.68.2
|
||||
x-stainless-arch:
|
||||
- arm64
|
||||
x-stainless-async:
|
||||
- 'false'
|
||||
x-stainless-lang:
|
||||
- python
|
||||
x-stainless-os:
|
||||
- MacOS
|
||||
x-stainless-package-version:
|
||||
- 1.68.2
|
||||
x-stainless-raw-response:
|
||||
- 'true'
|
||||
x-stainless-read-timeout:
|
||||
- '600.0'
|
||||
x-stainless-retry-count:
|
||||
- '0'
|
||||
x-stainless-runtime:
|
||||
- CPython
|
||||
x-stainless-runtime-version:
|
||||
- 3.12.9
|
||||
method: POST
|
||||
uri: https://api.openai.com/v1/chat/completions
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAAAAAAAAAwAAAP//jJJNb9swDIbv/hWEzvHgfHRpfesOG3opsGE7LYXBSLStRZY0iU43BPnv
|
||||
g5wPu10H7GLAfPhSfEkeMgChlShByBZZdt7kH758e1wzbnfbO6o/f1osV3T/+BO7UNNDIWZJ4bY/
|
||||
SPJF9U66zhti7ewJy0DIlKrO16ub27v5srgZQOcUmSRrPOcrl3fa6nxRLFZ5sc7nt2d167SkKEr4
|
||||
ngEAHIZv6tMq+iVKKGaXSEcxYkOivCYBiOBMigiMUUdGy2I2Qukskx1a/9q6vmm5hAew7hkkWmj0
|
||||
ngChSf0D2vhMAWBjP2qLBu6H/xIOGwuwEXs0Wm1ECRx6mp1iNZHaotylsO2N2djj9PFAdR/RnOEE
|
||||
oLWOMQ1wsP10JserUeMaH9w2vpKKWlsd2yoQRmeTqcjOi4EeM4CnYaD9ixkJH1znuWK3o+G583KG
|
||||
4Vz2ONLF7RmyYzQT1XI5e6NepYhRmzhZiZAoW1KjdNwf9kq7Ccgmrv/u5q3aJ+faNv9TfgRSkmdS
|
||||
lQ+ktHzpeEwLlM78X2nXKQ8Ni0hhryVVrCmkTSiqsTen4xPxd2TqqlrbhoIP+nSBta/SueD7QtWF
|
||||
yI7ZHwAAAP//AwAiLXhqjwMAAA==
|
||||
headers:
|
||||
CF-RAY:
|
||||
- 937b2311ee091b1b-GRU
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Tue, 29 Apr 2025 01:48:26 GMT
|
||||
Server:
|
||||
- cloudflare
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
access-control-expose-headers:
|
||||
- X-Request-ID
|
||||
alt-svc:
|
||||
- h3=":443"; ma=86400
|
||||
cf-cache-status:
|
||||
- DYNAMIC
|
||||
openai-organization:
|
||||
- crewai-iuxna1
|
||||
openai-processing-ms:
|
||||
- '610'
|
||||
openai-version:
|
||||
- '2020-10-01'
|
||||
strict-transport-security:
|
||||
- max-age=31536000; includeSubDomains; preload
|
||||
x-ratelimit-limit-requests:
|
||||
- '30000'
|
||||
x-ratelimit-limit-tokens:
|
||||
- '150000000'
|
||||
x-ratelimit-remaining-requests:
|
||||
- '29999'
|
||||
x-ratelimit-remaining-tokens:
|
||||
- '149999631'
|
||||
x-ratelimit-reset-requests:
|
||||
- 2ms
|
||||
x-ratelimit-reset-tokens:
|
||||
- 0s
|
||||
x-request-id:
|
||||
- req_c136835c16be6bc1e4d820f239c4b620
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
@@ -1 +0,0 @@
|
||||
"""Tests for CLI deploy."""
|
||||
@@ -6,7 +6,6 @@ research_task:
|
||||
expected_output: >
|
||||
A list with 10 bullet points of the most relevant information about {topic}
|
||||
agent: researcher
|
||||
guardrail: ensure each bullet contains its source
|
||||
|
||||
reporting_task:
|
||||
description: >
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""Tests for memory."""
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
@@ -64,4 +65,4 @@ def test_save_and_search(user_memory):
|
||||
with patch.object(UserMemory, 'search', return_value=expected_result) as mock_search:
|
||||
find = UserMemory.search("test value", score_threshold=0.01)[0]
|
||||
mock_search.assert_called_once_with("test value", score_threshold=0.01)
|
||||
assert find == expected_result[0]
|
||||
assert find == expected_result[0]
|
||||
@@ -1,5 +1,4 @@
|
||||
from typing import List
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -143,15 +142,6 @@ def test_agent_function_calling_llm():
|
||||
), "agent's function_calling_llm is incorrect"
|
||||
|
||||
|
||||
def test_task_guardrail():
|
||||
crew = InternalCrew()
|
||||
research_task = crew.research_task()
|
||||
assert research_task.guardrail == "ensure each bullet contains its source"
|
||||
|
||||
reporting_task = crew.reporting_task()
|
||||
assert reporting_task.guardrail is None
|
||||
|
||||
|
||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||
def test_before_kickoff_modification():
|
||||
crew = InternalCrew()
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""Tests for storage."""
|
||||
@@ -15,7 +15,6 @@ from crewai.task import Task
|
||||
class MockCrew:
|
||||
def __init__(self, memory_config):
|
||||
self.memory_config = memory_config
|
||||
self.agents = [MagicMock(role="Test Agent")]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -108,13 +107,11 @@ def mem0_storage_with_memory_client_using_config_from_crew(mock_mem0_memory_clie
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mem0_storage_with_memory_client_using_explictly_config(mock_mem0_memory_client, mock_mem0_memory):
|
||||
def mem0_storage_with_memory_client_using_explictly_config(mock_mem0_memory_client):
|
||||
"""Fixture to create a Mem0Storage instance with mocked dependencies"""
|
||||
|
||||
# We need to patch both MemoryClient and Memory to prevent actual initialization
|
||||
with patch.object(MemoryClient, "__new__", return_value=mock_mem0_memory_client), \
|
||||
patch.object(Memory, "__new__", return_value=mock_mem0_memory):
|
||||
|
||||
# We need to patch the MemoryClient before it's instantiated
|
||||
with patch.object(MemoryClient, "__new__", return_value=mock_mem0_memory_client):
|
||||
crew = MockCrew(
|
||||
memory_config={
|
||||
"provider": "mem0",
|
||||
@@ -158,82 +155,3 @@ def test_mem0_storage_with_explict_config(
|
||||
mem0_storage_with_memory_client_using_explictly_config.memory_config
|
||||
== expected_config
|
||||
)
|
||||
|
||||
|
||||
def test_save_method_with_memory_oss(mem0_storage_with_mocked_config):
|
||||
"""Test save method for different memory types"""
|
||||
mem0_storage, _, _ = mem0_storage_with_mocked_config
|
||||
mem0_storage.memory.add = MagicMock()
|
||||
|
||||
# Test short_term memory type (already set in fixture)
|
||||
test_value = "This is a test memory"
|
||||
test_metadata = {"key": "value"}
|
||||
|
||||
mem0_storage.save(test_value, test_metadata)
|
||||
|
||||
mem0_storage.memory.add.assert_called_once_with(
|
||||
test_value,
|
||||
agent_id="Test_Agent",
|
||||
infer=False,
|
||||
metadata={"type": "short_term", "key": "value"},
|
||||
)
|
||||
|
||||
|
||||
def test_save_method_with_memory_client(mem0_storage_with_memory_client_using_config_from_crew):
|
||||
"""Test save method for different memory types"""
|
||||
mem0_storage = mem0_storage_with_memory_client_using_config_from_crew
|
||||
mem0_storage.memory.add = MagicMock()
|
||||
|
||||
# Test short_term memory type (already set in fixture)
|
||||
test_value = "This is a test memory"
|
||||
test_metadata = {"key": "value"}
|
||||
|
||||
mem0_storage.save(test_value, test_metadata)
|
||||
|
||||
mem0_storage.memory.add.assert_called_once_with(
|
||||
test_value,
|
||||
agent_id="Test_Agent",
|
||||
infer=False,
|
||||
metadata={"type": "short_term", "key": "value"},
|
||||
output_format="v1.1"
|
||||
)
|
||||
|
||||
|
||||
def test_search_method_with_memory_oss(mem0_storage_with_mocked_config):
|
||||
"""Test search method for different memory types"""
|
||||
mem0_storage, _, _ = mem0_storage_with_mocked_config
|
||||
mock_results = {"results": [{"score": 0.9, "content": "Result 1"}, {"score": 0.4, "content": "Result 2"}]}
|
||||
mem0_storage.memory.search = MagicMock(return_value=mock_results)
|
||||
|
||||
results = mem0_storage.search("test query", limit=5, score_threshold=0.5)
|
||||
|
||||
mem0_storage.memory.search.assert_called_once_with(
|
||||
query="test query",
|
||||
limit=5,
|
||||
agent_id="Test_Agent",
|
||||
user_id="test_user"
|
||||
)
|
||||
|
||||
assert len(results) == 1
|
||||
assert results[0]["content"] == "Result 1"
|
||||
|
||||
|
||||
def test_search_method_with_memory_client(mem0_storage_with_memory_client_using_config_from_crew):
|
||||
"""Test search method for different memory types"""
|
||||
mem0_storage = mem0_storage_with_memory_client_using_config_from_crew
|
||||
mock_results = {"results": [{"score": 0.9, "content": "Result 1"}, {"score": 0.4, "content": "Result 2"}]}
|
||||
mem0_storage.memory.search = MagicMock(return_value=mock_results)
|
||||
|
||||
results = mem0_storage.search("test query", limit=5, score_threshold=0.5)
|
||||
|
||||
mem0_storage.memory.search.assert_called_once_with(
|
||||
query="test query",
|
||||
limit=5,
|
||||
agent_id="Test_Agent",
|
||||
metadata={"type": "short_term"},
|
||||
user_id="test_user",
|
||||
output_format='v1.1'
|
||||
)
|
||||
|
||||
assert len(results) == 1
|
||||
assert results[0]["content"] == "Result 1"
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
from unittest.mock import ANY, Mock, patch
|
||||
"""Tests for task guardrails functionality."""
|
||||
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from crewai import Agent, Task
|
||||
from crewai.llm import LLM
|
||||
from crewai.tasks.task_guardrail import TaskGuardrail
|
||||
from crewai.task import Task
|
||||
from crewai.tasks.task_output import TaskOutput
|
||||
from crewai.utilities.events import (
|
||||
TaskGuardrailCompletedEvent,
|
||||
TaskGuardrailStartedEvent,
|
||||
)
|
||||
from crewai.utilities.events.crewai_event_bus import crewai_event_bus
|
||||
|
||||
|
||||
def test_task_without_guardrail():
|
||||
@@ -27,7 +22,7 @@ def test_task_without_guardrail():
|
||||
assert result.raw == "test result"
|
||||
|
||||
|
||||
def test_task_with_successful_guardrail_func():
|
||||
def test_task_with_successful_guardrail():
|
||||
"""Test that successful guardrail validation passes transformed result."""
|
||||
|
||||
def guardrail(result: TaskOutput):
|
||||
@@ -132,138 +127,3 @@ def test_guardrail_error_in_context():
|
||||
|
||||
assert "Task failed guardrail validation" in str(exc_info.value)
|
||||
assert "Expected JSON, got string" in str(exc_info.value)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_agent():
|
||||
return Agent(role="Test Agent", goal="Test Goal", backstory="Test Backstory")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def task_output():
|
||||
return TaskOutput(
|
||||
raw="""
|
||||
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever
|
||||
""",
|
||||
description="Test task",
|
||||
expected_output="Output",
|
||||
agent="Test Agent",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||
def test_task_guardrail_process_output(task_output):
|
||||
guardrail = TaskGuardrail(
|
||||
description="Ensure the result has less than 10 words", llm=LLM(model="gpt-4o")
|
||||
)
|
||||
|
||||
result = guardrail(task_output)
|
||||
assert result[0] is False
|
||||
|
||||
assert "exceeding the guardrail limit of fewer than" in result[1].lower()
|
||||
|
||||
guardrail = TaskGuardrail(
|
||||
description="Ensure the result has less than 500 words", llm=LLM(model="gpt-4o")
|
||||
)
|
||||
|
||||
result = guardrail(task_output)
|
||||
assert result[0] is True
|
||||
assert result[1] == task_output.raw
|
||||
|
||||
|
||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||
def test_guardrail_emits_events(sample_agent):
|
||||
started_guardrail = []
|
||||
completed_guardrail = []
|
||||
|
||||
with crewai_event_bus.scoped_handlers():
|
||||
|
||||
@crewai_event_bus.on(TaskGuardrailStartedEvent)
|
||||
def handle_guardrail_started(source, event):
|
||||
started_guardrail.append(
|
||||
{"guardrail": event.guardrail, "retry_count": event.retry_count}
|
||||
)
|
||||
|
||||
@crewai_event_bus.on(TaskGuardrailCompletedEvent)
|
||||
def handle_guardrail_completed(source, event):
|
||||
completed_guardrail.append(
|
||||
{
|
||||
"success": event.success,
|
||||
"result": event.result,
|
||||
"error": event.error,
|
||||
"retry_count": event.retry_count,
|
||||
}
|
||||
)
|
||||
|
||||
task = Task(
|
||||
description="Gather information about available books on the First World War",
|
||||
agent=sample_agent,
|
||||
expected_output="A list of available books on the First World War",
|
||||
guardrail="Ensure the authors are from Italy",
|
||||
)
|
||||
|
||||
result = task.execute_sync(agent=sample_agent)
|
||||
|
||||
def custom_guardrail(result: TaskOutput):
|
||||
return (True, "good result from callable function")
|
||||
|
||||
task = Task(
|
||||
description="Test task",
|
||||
expected_output="Output",
|
||||
guardrail=custom_guardrail,
|
||||
)
|
||||
|
||||
task.execute_sync(agent=sample_agent)
|
||||
|
||||
expected_started_events = [
|
||||
{"guardrail": "Ensure the authors are from Italy", "retry_count": 0},
|
||||
{"guardrail": "Ensure the authors are from Italy", "retry_count": 1},
|
||||
{
|
||||
"guardrail": """def custom_guardrail(result: TaskOutput):
|
||||
return (True, "good result from callable function")""",
|
||||
"retry_count": 0,
|
||||
},
|
||||
]
|
||||
|
||||
expected_completed_events = [
|
||||
{
|
||||
"success": False,
|
||||
"result": None,
|
||||
"error": "The task result does not comply with the guardrail because none of "
|
||||
"the listed authors are from Italy. All authors mentioned are from "
|
||||
"different countries, including Germany, the UK, the USA, and others, "
|
||||
"which violates the requirement that authors must be Italian.",
|
||||
"retry_count": 0,
|
||||
},
|
||||
{"success": True, "result": result.raw, "error": None, "retry_count": 1},
|
||||
{
|
||||
"success": True,
|
||||
"result": "good result from callable function",
|
||||
"error": None,
|
||||
"retry_count": 0,
|
||||
},
|
||||
]
|
||||
assert started_guardrail == expected_started_events
|
||||
assert completed_guardrail == expected_completed_events
|
||||
|
||||
|
||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||
def test_guardrail_when_an_error_occurs(sample_agent, task_output):
|
||||
with (
|
||||
patch(
|
||||
"crewai.Agent.kickoff",
|
||||
side_effect=Exception("Unexpected error"),
|
||||
),
|
||||
pytest.raises(
|
||||
Exception,
|
||||
match="Error while validating the task output: Unexpected error",
|
||||
),
|
||||
):
|
||||
task = Task(
|
||||
description="Gather information about available books on the First World War",
|
||||
agent=sample_agent,
|
||||
expected_output="A list of available books on the First World War",
|
||||
guardrail="Ensure the authors are from Italy",
|
||||
max_retries=0,
|
||||
)
|
||||
task.execute_sync(agent=sample_agent)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""Tests for tools."""
|
||||
62
tests/tools/test_task_with_structured_tool.py
Normal file
62
tests/tools/test_task_with_structured_tool.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import pytest
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from crewai.task import Task
|
||||
from crewai.tools.structured_tool import CrewStructuredTool
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def simple_tool_function():
|
||||
def test_func(param1: str, param2: int = 0) -> str:
|
||||
"""Test function with basic params."""
|
||||
return f"{param1} {param2}"
|
||||
|
||||
return test_func
|
||||
|
||||
|
||||
def test_task_with_structured_tool(simple_tool_function):
|
||||
"""Test that CrewStructuredTool can be used directly with Task."""
|
||||
tool = CrewStructuredTool.from_function(
|
||||
func=simple_tool_function,
|
||||
name="test_tool",
|
||||
description="Test tool description"
|
||||
)
|
||||
|
||||
task = Task(
|
||||
description="Test task description",
|
||||
expected_output="Expected output",
|
||||
tools=[tool]
|
||||
)
|
||||
|
||||
assert len(task.tools) == 1
|
||||
assert task.tools[0] == tool
|
||||
|
||||
|
||||
def test_mixed_tool_types(simple_tool_function):
|
||||
"""Test that both BaseTool and CrewStructuredTool can be used together with Task."""
|
||||
from crewai.tools import BaseTool
|
||||
|
||||
structured_tool = CrewStructuredTool.from_function(
|
||||
func=simple_tool_function,
|
||||
name="structured_tool",
|
||||
description="Structured tool description"
|
||||
)
|
||||
|
||||
class TestBaseTool(BaseTool):
|
||||
name: str = "base_tool"
|
||||
description: str = "Base tool description"
|
||||
|
||||
def _run(self, query: str) -> str:
|
||||
return f"Result for {query}"
|
||||
|
||||
base_tool = TestBaseTool()
|
||||
|
||||
task = Task(
|
||||
description="Test task description",
|
||||
expected_output="Expected output",
|
||||
tools=[structured_tool, base_tool]
|
||||
)
|
||||
|
||||
assert len(task.tools) == 2
|
||||
assert task.tools[0] == structured_tool
|
||||
assert isinstance(task.tools[1], BaseTool)
|
||||
@@ -1 +0,0 @@
|
||||
"""Tests for utilities."""
|
||||
@@ -1 +0,0 @@
|
||||
"""Tests for evaluators."""
|
||||
@@ -1 +0,0 @@
|
||||
"""Tests for events."""
|
||||
Reference in New Issue
Block a user