mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-09 16:18:30 +00:00
Merge branch 'main' into lg-few-docs-update
This commit is contained in:
@@ -110,6 +110,8 @@ crewai reset-memories [OPTIONS]
|
|||||||
- `-s, --short`: Reset SHORT TERM memory
|
- `-s, --short`: Reset SHORT TERM memory
|
||||||
- `-e, --entities`: Reset ENTITIES memory
|
- `-e, --entities`: Reset ENTITIES memory
|
||||||
- `-k, --kickoff-outputs`: Reset LATEST KICKOFF TASK OUTPUTS
|
- `-k, --kickoff-outputs`: Reset LATEST KICKOFF TASK OUTPUTS
|
||||||
|
- `-kn, --knowledge`: Reset KNOWLEDGE storage
|
||||||
|
- `-akn, --agent-knowledge`: Reset AGENT KNOWLEDGE storage
|
||||||
- `-a, --all`: Reset ALL memories
|
- `-a, --all`: Reset ALL memories
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|||||||
@@ -497,6 +497,13 @@ crew = Crew(
|
|||||||
result = crew.kickoff(
|
result = crew.kickoff(
|
||||||
inputs={"question": "What is the storage capacity of the XPS 13?"}
|
inputs={"question": "What is the storage capacity of the XPS 13?"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Resetting the agent specific knowledge via crew object
|
||||||
|
crew.reset_memories(command_type = 'agent_knowledge')
|
||||||
|
|
||||||
|
# Resetting the agent specific knowledge via CLI
|
||||||
|
crewai reset-memories --agent-knowledge
|
||||||
|
crewai reset-memories -akn
|
||||||
```
|
```
|
||||||
|
|
||||||
<Info>
|
<Info>
|
||||||
|
|||||||
@@ -679,6 +679,7 @@ crewai reset-memories [OPTIONS]
|
|||||||
| `-e`, `--entities` | Reset ENTITIES memory. | Flag (boolean) | False |
|
| `-e`, `--entities` | Reset ENTITIES memory. | Flag (boolean) | False |
|
||||||
| `-k`, `--kickoff-outputs` | Reset LATEST KICKOFF TASK OUTPUTS. | Flag (boolean) | False |
|
| `-k`, `--kickoff-outputs` | Reset LATEST KICKOFF TASK OUTPUTS. | Flag (boolean) | False |
|
||||||
| `-kn`, `--knowledge` | Reset KNOWLEDEGE storage | Flag (boolean) | False |
|
| `-kn`, `--knowledge` | Reset KNOWLEDEGE storage | Flag (boolean) | False |
|
||||||
|
| `-akn`, `--agent-knowledge` | Reset AGENT KNOWLEDGE storage | Flag (boolean) | False |
|
||||||
| `-a`, `--all` | Reset ALL memories. | Flag (boolean) | False |
|
| `-a`, `--all` | Reset ALL memories. | Flag (boolean) | False |
|
||||||
|
|
||||||
Note: To use the cli command you need to have your crew in a file called crew.py in the same directory.
|
Note: To use the cli command you need to have your crew in a file called crew.py in the same directory.
|
||||||
@@ -716,9 +717,11 @@ my_crew.reset_memories(command_type = 'all') # Resets all the memory
|
|||||||
| `entities` | Reset ENTITIES memory. |
|
| `entities` | Reset ENTITIES memory. |
|
||||||
| `kickoff_outputs` | Reset LATEST KICKOFF TASK OUTPUTS. |
|
| `kickoff_outputs` | Reset LATEST KICKOFF TASK OUTPUTS. |
|
||||||
| `knowledge` | Reset KNOWLEDGE memory. |
|
| `knowledge` | Reset KNOWLEDGE memory. |
|
||||||
|
| `agent_knowledge` | Reset AGENT KNOWLEDGE memory. |
|
||||||
| `all` | Reset ALL memories. |
|
| `all` | Reset ALL memories. |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Benefits of Using CrewAI's Memory System
|
## Benefits of Using CrewAI's Memory System
|
||||||
|
|
||||||
- 🦾 **Adaptive Learning:** Crews become more efficient over time, adapting to new information and refining their approach to tasks.
|
- 🦾 **Adaptive Learning:** Crews become more efficient over time, adapting to new information and refining their approach to tasks.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "crewai"
|
name = "crewai"
|
||||||
version = "0.119.0"
|
version = "0.120.1"
|
||||||
description = "Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks."
|
description = "Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10,<3.13"
|
requires-python = ">=3.10,<3.13"
|
||||||
@@ -45,7 +45,7 @@ Documentation = "https://docs.crewai.com"
|
|||||||
Repository = "https://github.com/crewAIInc/crewAI"
|
Repository = "https://github.com/crewAIInc/crewAI"
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
tools = ["crewai-tools~=0.44.0"]
|
tools = ["crewai-tools~=0.45.0"]
|
||||||
embeddings = [
|
embeddings = [
|
||||||
"tiktoken~=0.7.0"
|
"tiktoken~=0.7.0"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ warnings.filterwarnings(
|
|||||||
category=UserWarning,
|
category=UserWarning,
|
||||||
module="pydantic.main",
|
module="pydantic.main",
|
||||||
)
|
)
|
||||||
__version__ = "0.119.0"
|
__version__ = "0.120.1"
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"Agent",
|
"Agent",
|
||||||
"Crew",
|
"Crew",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import os
|
|
||||||
from importlib.metadata import version as get_version
|
from importlib.metadata import version as get_version
|
||||||
from typing import Optional, Tuple
|
from typing import Optional
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
@@ -138,12 +137,8 @@ def log_tasks_outputs() -> None:
|
|||||||
@click.option("-s", "--short", is_flag=True, help="Reset SHORT TERM memory")
|
@click.option("-s", "--short", is_flag=True, help="Reset SHORT TERM memory")
|
||||||
@click.option("-e", "--entities", is_flag=True, help="Reset ENTITIES memory")
|
@click.option("-e", "--entities", is_flag=True, help="Reset ENTITIES memory")
|
||||||
@click.option("-kn", "--knowledge", is_flag=True, help="Reset KNOWLEDGE storage")
|
@click.option("-kn", "--knowledge", is_flag=True, help="Reset KNOWLEDGE storage")
|
||||||
@click.option(
|
@click.option("-akn", "--agent-knowledge", is_flag=True, help="Reset AGENT KNOWLEDGE storage")
|
||||||
"-k",
|
@click.option("-k","--kickoff-outputs",is_flag=True,help="Reset LATEST KICKOFF TASK OUTPUTS")
|
||||||
"--kickoff-outputs",
|
|
||||||
is_flag=True,
|
|
||||||
help="Reset LATEST KICKOFF TASK OUTPUTS",
|
|
||||||
)
|
|
||||||
@click.option("-a", "--all", is_flag=True, help="Reset ALL memories")
|
@click.option("-a", "--all", is_flag=True, help="Reset ALL memories")
|
||||||
def reset_memories(
|
def reset_memories(
|
||||||
long: bool,
|
long: bool,
|
||||||
@@ -151,18 +146,20 @@ def reset_memories(
|
|||||||
entities: bool,
|
entities: bool,
|
||||||
knowledge: bool,
|
knowledge: bool,
|
||||||
kickoff_outputs: bool,
|
kickoff_outputs: bool,
|
||||||
|
agent_knowledge: bool,
|
||||||
all: bool,
|
all: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Reset the crew memories (long, short, entity, latest_crew_kickoff_ouputs). This will delete all the data saved.
|
Reset the crew memories (long, short, entity, latest_crew_kickoff_ouputs, knowledge, agent_knowledge). This will delete all the data saved.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if not all and not (long or short or entities or knowledge or kickoff_outputs):
|
memory_types = [long, short, entities, knowledge, agent_knowledge, kickoff_outputs, all]
|
||||||
|
if not any(memory_types):
|
||||||
click.echo(
|
click.echo(
|
||||||
"Please specify at least one memory type to reset using the appropriate flags."
|
"Please specify at least one memory type to reset using the appropriate flags."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
reset_memories_command(long, short, entities, knowledge, kickoff_outputs, all)
|
reset_memories_command(long, short, entities, knowledge, agent_knowledge, kickoff_outputs, all)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
click.echo(f"An error occurred while resetting memories: {e}", err=True)
|
click.echo(f"An error occurred while resetting memories: {e}", err=True)
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ def reset_memories_command(
|
|||||||
short,
|
short,
|
||||||
entity,
|
entity,
|
||||||
knowledge,
|
knowledge,
|
||||||
|
agent_knowledge,
|
||||||
kickoff_outputs,
|
kickoff_outputs,
|
||||||
all,
|
all,
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -23,10 +24,11 @@ def reset_memories_command(
|
|||||||
kickoff_outputs (bool): Whether to reset the latest kickoff task outputs.
|
kickoff_outputs (bool): Whether to reset the latest kickoff task outputs.
|
||||||
all (bool): Whether to reset all memories.
|
all (bool): Whether to reset all memories.
|
||||||
knowledge (bool): Whether to reset the knowledge.
|
knowledge (bool): Whether to reset the knowledge.
|
||||||
|
agent_knowledge (bool): Whether to reset the agents knowledge.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not any([long, short, entity, kickoff_outputs, knowledge, all]):
|
if not any([long, short, entity, kickoff_outputs, knowledge, agent_knowledge, all]):
|
||||||
click.echo(
|
click.echo(
|
||||||
"No memory type specified. Please specify at least one type to reset."
|
"No memory type specified. Please specify at least one type to reset."
|
||||||
)
|
)
|
||||||
@@ -67,6 +69,11 @@ def reset_memories_command(
|
|||||||
click.echo(
|
click.echo(
|
||||||
f"[Crew ({crew.name if crew.name else crew.id})] Knowledge has been reset."
|
f"[Crew ({crew.name if crew.name else crew.id})] Knowledge has been reset."
|
||||||
)
|
)
|
||||||
|
if agent_knowledge:
|
||||||
|
crew.reset_memories(command_type="agent_knowledge")
|
||||||
|
click.echo(
|
||||||
|
f"[Crew ({crew.name if crew.name else crew.id})] Agents knowledge has been reset."
|
||||||
|
)
|
||||||
|
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
click.echo(f"An error occurred while resetting the memories: {e}", err=True)
|
click.echo(f"An error occurred while resetting the memories: {e}", err=True)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
|
|||||||
authors = [{ name = "Your Name", email = "you@example.com" }]
|
authors = [{ name = "Your Name", email = "you@example.com" }]
|
||||||
requires-python = ">=3.10,<3.13"
|
requires-python = ">=3.10,<3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crewai[tools]>=0.119.0,<1.0.0"
|
"crewai[tools]>=0.120.1,<1.0.0"
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
|
|||||||
authors = [{ name = "Your Name", email = "you@example.com" }]
|
authors = [{ name = "Your Name", email = "you@example.com" }]
|
||||||
requires-python = ">=3.10,<3.13"
|
requires-python = ">=3.10,<3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crewai[tools]>=0.119.0,<1.0.0",
|
"crewai[tools]>=0.120.1,<1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ description = "Power up your crews with {{folder_name}}"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10,<3.13"
|
requires-python = ">=3.10,<3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crewai[tools]>=0.119.0"
|
"crewai[tools]>=0.120.1"
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.crewai]
|
[tool.crewai]
|
||||||
|
|||||||
@@ -1356,7 +1356,7 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
command_type: Type of memory to reset.
|
command_type: Type of memory to reset.
|
||||||
Valid options: 'long', 'short', 'entity', 'knowledge',
|
Valid options: 'long', 'short', 'entity', 'knowledge', 'agent_knowledge'
|
||||||
'kickoff_outputs', or 'all'
|
'kickoff_outputs', or 'all'
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
@@ -1369,6 +1369,7 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
"short",
|
"short",
|
||||||
"entity",
|
"entity",
|
||||||
"knowledge",
|
"knowledge",
|
||||||
|
"agent_knowledge",
|
||||||
"kickoff_outputs",
|
"kickoff_outputs",
|
||||||
"all",
|
"all",
|
||||||
"external",
|
"external",
|
||||||
@@ -1393,19 +1394,14 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
|
|
||||||
def _reset_all_memories(self) -> None:
|
def _reset_all_memories(self) -> None:
|
||||||
"""Reset all available memory systems."""
|
"""Reset all available memory systems."""
|
||||||
memory_systems = [
|
memory_systems = self._get_memory_systems()
|
||||||
("short term", getattr(self, "_short_term_memory", None)),
|
|
||||||
("entity", getattr(self, "_entity_memory", None)),
|
|
||||||
("external", getattr(self, "_external_memory", None)),
|
|
||||||
("long term", getattr(self, "_long_term_memory", None)),
|
|
||||||
("task output", getattr(self, "_task_output_handler", None)),
|
|
||||||
("knowledge", getattr(self, "knowledge", None)),
|
|
||||||
]
|
|
||||||
|
|
||||||
for name, system in memory_systems:
|
for memory_type, config in memory_systems.items():
|
||||||
if system is not None:
|
if (system := config.get('system')) is not None:
|
||||||
|
name = config.get('name')
|
||||||
try:
|
try:
|
||||||
system.reset()
|
reset_fn: Callable = cast(Callable, config.get('reset'))
|
||||||
|
reset_fn(system)
|
||||||
self._logger.log(
|
self._logger.log(
|
||||||
"info",
|
"info",
|
||||||
f"[Crew ({self.name if self.name else self.id})] {name} memory has been reset",
|
f"[Crew ({self.name if self.name else self.id})] {name} memory has been reset",
|
||||||
@@ -1424,24 +1420,17 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
Raises:
|
Raises:
|
||||||
RuntimeError: If the specified memory system fails to reset
|
RuntimeError: If the specified memory system fails to reset
|
||||||
"""
|
"""
|
||||||
reset_functions = {
|
memory_systems = self._get_memory_systems()
|
||||||
"long": (getattr(self, "_long_term_memory", None), "long term"),
|
config = memory_systems[memory_type]
|
||||||
"short": (getattr(self, "_short_term_memory", None), "short term"),
|
system = config.get('system')
|
||||||
"entity": (getattr(self, "_entity_memory", None), "entity"),
|
name = config.get('name')
|
||||||
"knowledge": (getattr(self, "knowledge", None), "knowledge"),
|
|
||||||
"kickoff_outputs": (
|
|
||||||
getattr(self, "_task_output_handler", None),
|
|
||||||
"task output",
|
|
||||||
),
|
|
||||||
"external": (getattr(self, "_external_memory", None), "external"),
|
|
||||||
}
|
|
||||||
|
|
||||||
memory_system, name = reset_functions[memory_type]
|
if system is None:
|
||||||
if memory_system is None:
|
|
||||||
raise RuntimeError(f"{name} memory system is not initialized")
|
raise RuntimeError(f"{name} memory system is not initialized")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
memory_system.reset()
|
reset_fn: Callable = cast(Callable, config.get('reset'))
|
||||||
|
reset_fn(system)
|
||||||
self._logger.log(
|
self._logger.log(
|
||||||
"info",
|
"info",
|
||||||
f"[Crew ({self.name if self.name else self.id})] {name} memory has been reset",
|
f"[Crew ({self.name if self.name else self.id})] {name} memory has been reset",
|
||||||
@@ -1450,3 +1439,64 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"[Crew ({self.name if self.name else self.id})] Failed to reset {name} memory: {str(e)}"
|
f"[Crew ({self.name if self.name else self.id})] Failed to reset {name} memory: {str(e)}"
|
||||||
) from e
|
) from e
|
||||||
|
|
||||||
|
def _get_memory_systems(self):
|
||||||
|
"""Get all available memory systems with their configuration.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict containing all memory systems with their reset functions and display names.
|
||||||
|
"""
|
||||||
|
def default_reset(memory):
|
||||||
|
return memory.reset()
|
||||||
|
def knowledge_reset(memory):
|
||||||
|
return self.reset_knowledge(memory)
|
||||||
|
|
||||||
|
# Get knowledge for agents
|
||||||
|
agent_knowledges = [getattr(agent, "knowledge", None) for agent in self.agents
|
||||||
|
if getattr(agent, "knowledge", None) is not None]
|
||||||
|
# Get knowledge for crew and agents
|
||||||
|
crew_knowledge = getattr(self, "knowledge", None)
|
||||||
|
crew_and_agent_knowledges = ([crew_knowledge] if crew_knowledge is not None else []) + agent_knowledges
|
||||||
|
|
||||||
|
return {
|
||||||
|
'short': {
|
||||||
|
'system': getattr(self, "_short_term_memory", None),
|
||||||
|
'reset': default_reset,
|
||||||
|
'name': 'Short Term'
|
||||||
|
},
|
||||||
|
'entity': {
|
||||||
|
'system': getattr(self, "_entity_memory", None),
|
||||||
|
'reset': default_reset,
|
||||||
|
'name': 'Entity'
|
||||||
|
},
|
||||||
|
'external': {
|
||||||
|
'system': getattr(self, "_external_memory", None),
|
||||||
|
'reset': default_reset,
|
||||||
|
'name': 'External'
|
||||||
|
},
|
||||||
|
'long': {
|
||||||
|
'system': getattr(self, "_long_term_memory", None),
|
||||||
|
'reset': default_reset,
|
||||||
|
'name': 'Long Term'
|
||||||
|
},
|
||||||
|
'kickoff_outputs': {
|
||||||
|
'system': getattr(self, "_task_output_handler", None),
|
||||||
|
'reset': default_reset,
|
||||||
|
'name': 'Task Output'
|
||||||
|
},
|
||||||
|
'knowledge': {
|
||||||
|
'system': crew_and_agent_knowledges if crew_and_agent_knowledges else None,
|
||||||
|
'reset': knowledge_reset,
|
||||||
|
'name': 'Crew Knowledge and Agent Knowledge'
|
||||||
|
},
|
||||||
|
'agent_knowledge': {
|
||||||
|
'system': agent_knowledges if agent_knowledges else None,
|
||||||
|
'reset': knowledge_reset,
|
||||||
|
'name': 'Agent Knowledge'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def reset_knowledge(self, knowledges: List[Knowledge]) -> None:
|
||||||
|
"""Reset crew and agent knowledge storage."""
|
||||||
|
for ks in knowledges:
|
||||||
|
ks.reset()
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ def interpolate_only(
|
|||||||
# The regex pattern to find valid variable placeholders
|
# The regex pattern to find valid variable placeholders
|
||||||
# Matches {variable_name} where variable_name starts with a letter/underscore
|
# Matches {variable_name} where variable_name starts with a letter/underscore
|
||||||
# and contains only letters, numbers, and underscores
|
# and contains only letters, numbers, and underscores
|
||||||
pattern = r"\{([A-Za-z_][A-Za-z0-9_]*)\}"
|
pattern = r"\{([A-Za-z_][A-Za-z0-9_\-]*)\}"
|
||||||
|
|
||||||
# Find all matching variables in the input string
|
# Find all matching variables in the input string
|
||||||
variables = re.findall(pattern, input_string)
|
variables = re.findall(pattern, input_string)
|
||||||
|
|||||||
121
tests/cassettes/test_task_interpolation_with_hyphens.yaml
Normal file
121
tests/cassettes/test_task_interpolation_with_hyphens.yaml
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
interactions:
|
||||||
|
- request:
|
||||||
|
body: '{"messages": [{"role": "system", "content": "You are Researcher. You''re
|
||||||
|
an expert researcher, specialized in technology, software engineering, AI and
|
||||||
|
startups. You work as a freelancer and is now working on doing research and
|
||||||
|
analysis for a new customer.\nYour personal goal is: be an assistant that responds
|
||||||
|
with say hello world\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: be an assistant that responds
|
||||||
|
with say hello world\n\nThis is the expected criteria for your final answer:
|
||||||
|
The response should be addressing: say hello world\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, zstd
|
||||||
|
connection:
|
||||||
|
- keep-alive
|
||||||
|
content-length:
|
||||||
|
- '1108'
|
||||||
|
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 |
|
||||||
|
H4sIAAAAAAAAA4xSTW/UMBC951cMPicoScMu3RuIooUDcOOrVeS1J4mp4zG2sy2q9r9XTrqbtBSJ
|
||||||
|
iyX7zXt+b2buEgCmJNsAEx0Porc6e/vt4nf3xVxweVZ+3v/Q17fF9+pjs92+O//0iqWRQbtfKMKR
|
||||||
|
9VJQbzUGRWaChUMeMKoW62pdropVfjYCPUnUkdbakFWU9cqorMzLKsvXWfH6gd2REujZBn4mAAB3
|
||||||
|
4xl9Gom3bAN5enzp0XveItucigCYIx1fGPde+cBNYOkMCjIBzWj9Axi6AcENtGqPwKGNtoEbf4MO
|
||||||
|
4NK8V4ZreDPeN7BFrSmFr+S0fLGUdNgMnsdYZtB6AXBjKPDYljHM1QNyONnX1FpHO/+EyhpllO9q
|
||||||
|
h9yTiVZ9IMtG9JAAXI1tGh4lZ9ZRb0Md6BrH78p8NemxeTozWhzBQIHrBass02f0aomBK+0XjWaC
|
||||||
|
iw7lTJ2nwgepaAEki9R/u3lOe0quTPs/8jMgBNqAsrYOpRKPE89lDuPy/qvs1OXRMPPo9kpgHRS6
|
||||||
|
OAmJDR/0tFLM//EB+7pRpkVnnZr2qrH1utjl5bo6bzhLDsk9AAAA//8DAAxaM/dlAwAA
|
||||||
|
headers:
|
||||||
|
CF-RAY:
|
||||||
|
- 93fdd19cdbfb6428-SJC
|
||||||
|
Connection:
|
||||||
|
- keep-alive
|
||||||
|
Content-Encoding:
|
||||||
|
- gzip
|
||||||
|
Content-Type:
|
||||||
|
- application/json
|
||||||
|
Date:
|
||||||
|
- Wed, 14 May 2025 22:26:43 GMT
|
||||||
|
Server:
|
||||||
|
- cloudflare
|
||||||
|
Set-Cookie:
|
||||||
|
- __cf_bm=eCtOgOCsKt_ybdNPdtFAocCmuQbNltR52chaHVe7Y_Q-1747261603-1.0.1.1-827eoA7wHS5SOkTsTqoMq6OSioi0VznQBVjvmabNSVX1bf5PpWZvblw58iggZ_wyKDB0EuVoeLKFspgBJa0kuQYR17hu43Y2C14sgdvOXIE;
|
||||||
|
path=/; expires=Wed, 14-May-25 22:56:43 GMT; domain=.api.openai.com; HttpOnly;
|
||||||
|
Secure; SameSite=None
|
||||||
|
- _cfuvid=QUa5MnypdaVxO826bwdQaN4G6CBEV8HYVV.7OLF.qvQ-1747261603742-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:
|
||||||
|
- '307'
|
||||||
|
openai-version:
|
||||||
|
- '2020-10-01'
|
||||||
|
strict-transport-security:
|
||||||
|
- max-age=31536000; includeSubDomains; preload
|
||||||
|
x-envoy-upstream-service-time:
|
||||||
|
- '309'
|
||||||
|
x-ratelimit-limit-requests:
|
||||||
|
- '30000'
|
||||||
|
x-ratelimit-limit-tokens:
|
||||||
|
- '150000000'
|
||||||
|
x-ratelimit-remaining-requests:
|
||||||
|
- '29999'
|
||||||
|
x-ratelimit-remaining-tokens:
|
||||||
|
- '149999757'
|
||||||
|
x-ratelimit-reset-requests:
|
||||||
|
- 2ms
|
||||||
|
x-ratelimit-reset-tokens:
|
||||||
|
- 0s
|
||||||
|
x-request-id:
|
||||||
|
- req_61d9066e0258b7095517f9f9c01d38e9
|
||||||
|
status:
|
||||||
|
code: 200
|
||||||
|
message: OK
|
||||||
|
version: 1
|
||||||
@@ -162,8 +162,18 @@ def test_reset_knowledge(mock_get_crews, runner):
|
|||||||
assert call_count == 1, "reset_memories should have been called once"
|
assert call_count == 1, "reset_memories should have been called once"
|
||||||
|
|
||||||
|
|
||||||
def test_reset_memory_from_many_crews(mock_get_crews, runner):
|
def test_reset_agent_knowledge(mock_get_crews, runner):
|
||||||
|
result = runner.invoke(reset_memories, ["--agent-knowledge"])
|
||||||
|
call_count = 0
|
||||||
|
for crew in mock_get_crews.return_value:
|
||||||
|
crew.reset_memories.assert_called_once_with(command_type="agent_knowledge")
|
||||||
|
assert f"[Crew ({crew.name})] Agents knowledge has been reset." in result.output
|
||||||
|
call_count += 1
|
||||||
|
|
||||||
|
assert call_count == 1, "reset_memories should have been called once"
|
||||||
|
|
||||||
|
|
||||||
|
def test_reset_memory_from_many_crews(mock_get_crews, runner):
|
||||||
crews = []
|
crews = []
|
||||||
for crew_id in ["id-1234", "id-5678"]:
|
for crew_id in ["id-1234", "id-5678"]:
|
||||||
mock_crew = mock.Mock(spec=Crew)
|
mock_crew = mock.Mock(spec=Crew)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from crewai.agents import CacheHandler
|
|||||||
from crewai.crew import Crew
|
from crewai.crew import Crew
|
||||||
from crewai.crews.crew_output import CrewOutput
|
from crewai.crews.crew_output import CrewOutput
|
||||||
from crewai.flow import Flow, start
|
from crewai.flow import Flow, start
|
||||||
|
from crewai.knowledge.knowledge import Knowledge
|
||||||
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource
|
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource
|
||||||
from crewai.llm import LLM
|
from crewai.llm import LLM
|
||||||
from crewai.memory.contextual.contextual_memory import ContextualMemory
|
from crewai.memory.contextual.contextual_memory import ContextualMemory
|
||||||
@@ -4403,3 +4404,165 @@ def test_sets_parent_flow_when_inside_flow(researcher, writer):
|
|||||||
flow = MyFlow()
|
flow = MyFlow()
|
||||||
result = flow.kickoff()
|
result = flow.kickoff()
|
||||||
assert result.parent_flow is flow
|
assert result.parent_flow is flow
|
||||||
|
|
||||||
|
|
||||||
|
def test_reset_knowledge_with_no_crew_knowledge(researcher,writer):
|
||||||
|
crew = Crew(
|
||||||
|
agents=[researcher, writer],
|
||||||
|
process=Process.sequential,
|
||||||
|
tasks=[
|
||||||
|
Task(description="Task 1", expected_output="output", agent=researcher),
|
||||||
|
Task(description="Task 2", expected_output="output", agent=writer),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
|
crew.reset_memories(command_type='knowledge')
|
||||||
|
|
||||||
|
# Optionally, you can also check the error message
|
||||||
|
assert "Crew Knowledge and Agent Knowledge memory system is not initialized" in str(excinfo.value) # Replace with the expected message
|
||||||
|
|
||||||
|
|
||||||
|
def test_reset_knowledge_with_only_crew_knowledge(researcher,writer):
|
||||||
|
mock_ks = MagicMock(spec=Knowledge)
|
||||||
|
|
||||||
|
with patch.object(Crew,'reset_knowledge') as mock_reset_agent_knowledge:
|
||||||
|
crew = Crew(
|
||||||
|
agents=[researcher, writer],
|
||||||
|
process=Process.sequential,
|
||||||
|
tasks=[
|
||||||
|
Task(description="Task 1", expected_output="output", agent=researcher),
|
||||||
|
Task(description="Task 2", expected_output="output", agent=writer),
|
||||||
|
],
|
||||||
|
knowledge=mock_ks
|
||||||
|
)
|
||||||
|
|
||||||
|
crew.reset_memories(command_type='knowledge')
|
||||||
|
mock_reset_agent_knowledge.assert_called_once_with([mock_ks])
|
||||||
|
|
||||||
|
|
||||||
|
def test_reset_knowledge_with_crew_and_agent_knowledge(researcher,writer):
|
||||||
|
mock_ks_crew = MagicMock(spec=Knowledge)
|
||||||
|
mock_ks_research = MagicMock(spec=Knowledge)
|
||||||
|
mock_ks_writer = MagicMock(spec=Knowledge)
|
||||||
|
|
||||||
|
researcher.knowledge = mock_ks_research
|
||||||
|
writer.knowledge = mock_ks_writer
|
||||||
|
|
||||||
|
with patch.object(Crew,'reset_knowledge') as mock_reset_agent_knowledge:
|
||||||
|
crew = Crew(
|
||||||
|
agents=[researcher, writer],
|
||||||
|
process=Process.sequential,
|
||||||
|
tasks=[
|
||||||
|
Task(description="Task 1", expected_output="output", agent=researcher),
|
||||||
|
Task(description="Task 2", expected_output="output", agent=writer),
|
||||||
|
],
|
||||||
|
knowledge=mock_ks_crew
|
||||||
|
)
|
||||||
|
|
||||||
|
crew.reset_memories(command_type='knowledge')
|
||||||
|
mock_reset_agent_knowledge.assert_called_once_with([mock_ks_crew,mock_ks_research,mock_ks_writer])
|
||||||
|
|
||||||
|
|
||||||
|
def test_reset_knowledge_with_only_agent_knowledge(researcher,writer):
|
||||||
|
mock_ks_research = MagicMock(spec=Knowledge)
|
||||||
|
mock_ks_writer = MagicMock(spec=Knowledge)
|
||||||
|
|
||||||
|
researcher.knowledge = mock_ks_research
|
||||||
|
writer.knowledge = mock_ks_writer
|
||||||
|
|
||||||
|
with patch.object(Crew,'reset_knowledge') as mock_reset_agent_knowledge:
|
||||||
|
crew = Crew(
|
||||||
|
agents=[researcher, writer],
|
||||||
|
process=Process.sequential,
|
||||||
|
tasks=[
|
||||||
|
Task(description="Task 1", expected_output="output", agent=researcher),
|
||||||
|
Task(description="Task 2", expected_output="output", agent=writer),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
crew.reset_memories(command_type='knowledge')
|
||||||
|
mock_reset_agent_knowledge.assert_called_once_with([mock_ks_research,mock_ks_writer])
|
||||||
|
|
||||||
|
|
||||||
|
def test_reset_agent_knowledge_with_no_agent_knowledge(researcher,writer):
|
||||||
|
crew = Crew(
|
||||||
|
agents=[researcher, writer],
|
||||||
|
process=Process.sequential,
|
||||||
|
tasks=[
|
||||||
|
Task(description="Task 1", expected_output="output", agent=researcher),
|
||||||
|
Task(description="Task 2", expected_output="output", agent=writer),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
|
crew.reset_memories(command_type='agent_knowledge')
|
||||||
|
|
||||||
|
# Optionally, you can also check the error message
|
||||||
|
assert "Agent Knowledge memory system is not initialized" in str(excinfo.value) # Replace with the expected message
|
||||||
|
|
||||||
|
|
||||||
|
def test_reset_agent_knowledge_with_only_crew_knowledge(researcher,writer):
|
||||||
|
mock_ks = MagicMock(spec=Knowledge)
|
||||||
|
|
||||||
|
crew = Crew(
|
||||||
|
agents=[researcher, writer],
|
||||||
|
process=Process.sequential,
|
||||||
|
tasks=[
|
||||||
|
Task(description="Task 1", expected_output="output", agent=researcher),
|
||||||
|
Task(description="Task 2", expected_output="output", agent=writer),
|
||||||
|
],
|
||||||
|
knowledge=mock_ks
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
|
crew.reset_memories(command_type='agent_knowledge')
|
||||||
|
|
||||||
|
# Optionally, you can also check the error message
|
||||||
|
assert "Agent Knowledge memory system is not initialized" in str(excinfo.value) # Replace with the expected message
|
||||||
|
|
||||||
|
|
||||||
|
def test_reset_agent_knowledge_with_crew_and_agent_knowledge(researcher,writer):
|
||||||
|
mock_ks_crew = MagicMock(spec=Knowledge)
|
||||||
|
mock_ks_research = MagicMock(spec=Knowledge)
|
||||||
|
mock_ks_writer = MagicMock(spec=Knowledge)
|
||||||
|
|
||||||
|
researcher.knowledge = mock_ks_research
|
||||||
|
writer.knowledge = mock_ks_writer
|
||||||
|
|
||||||
|
with patch.object(Crew,'reset_knowledge') as mock_reset_agent_knowledge:
|
||||||
|
crew = Crew(
|
||||||
|
agents=[researcher, writer],
|
||||||
|
process=Process.sequential,
|
||||||
|
tasks=[
|
||||||
|
Task(description="Task 1", expected_output="output", agent=researcher),
|
||||||
|
Task(description="Task 2", expected_output="output", agent=writer),
|
||||||
|
],
|
||||||
|
knowledge=mock_ks_crew
|
||||||
|
)
|
||||||
|
|
||||||
|
crew.reset_memories(command_type='agent_knowledge')
|
||||||
|
mock_reset_agent_knowledge.assert_called_once_with([mock_ks_research,mock_ks_writer])
|
||||||
|
|
||||||
|
|
||||||
|
def test_reset_agent_knowledge_with_only_agent_knowledge(researcher,writer):
|
||||||
|
mock_ks_research = MagicMock(spec=Knowledge)
|
||||||
|
mock_ks_writer = MagicMock(spec=Knowledge)
|
||||||
|
|
||||||
|
researcher.knowledge = mock_ks_research
|
||||||
|
writer.knowledge = mock_ks_writer
|
||||||
|
|
||||||
|
with patch.object(Crew,'reset_knowledge') as mock_reset_agent_knowledge:
|
||||||
|
crew = Crew(
|
||||||
|
agents=[researcher, writer],
|
||||||
|
process=Process.sequential,
|
||||||
|
tasks=[
|
||||||
|
Task(description="Task 1", expected_output="output", agent=researcher),
|
||||||
|
Task(description="Task 2", expected_output="output", agent=writer),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
crew.reset_memories(command_type='agent_knowledge')
|
||||||
|
mock_reset_agent_knowledge.assert_called_once_with([mock_ks_research,mock_ks_writer])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -837,9 +837,6 @@ def test_interpolate_inputs():
|
|||||||
|
|
||||||
def test_interpolate_only():
|
def test_interpolate_only():
|
||||||
"""Test the interpolate_only method for various scenarios including JSON structure preservation."""
|
"""Test the interpolate_only method for various scenarios including JSON structure preservation."""
|
||||||
task = Task(
|
|
||||||
description="Unused in this test", expected_output="Unused in this test"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test JSON structure preservation
|
# Test JSON structure preservation
|
||||||
json_string = '{"info": "Look at {placeholder}", "nested": {"val": "{nestedVal}"}}'
|
json_string = '{"info": "Look at {placeholder}", "nested": {"val": "{nestedVal}"}}'
|
||||||
@@ -871,10 +868,6 @@ def test_interpolate_only():
|
|||||||
|
|
||||||
def test_interpolate_only_with_dict_inside_expected_output():
|
def test_interpolate_only_with_dict_inside_expected_output():
|
||||||
"""Test the interpolate_only method for various scenarios including JSON structure preservation."""
|
"""Test the interpolate_only method for various scenarios including JSON structure preservation."""
|
||||||
task = Task(
|
|
||||||
description="Unused in this test",
|
|
||||||
expected_output="Unused in this test: {questions}",
|
|
||||||
)
|
|
||||||
|
|
||||||
json_string = '{"questions": {"main_question": "What is the user\'s name?", "secondary_question": "What is the user\'s age?"}}'
|
json_string = '{"questions": {"main_question": "What is the user\'s name?", "secondary_question": "What is the user\'s age?"}}'
|
||||||
result = interpolate_only(
|
result = interpolate_only(
|
||||||
@@ -1094,11 +1087,6 @@ def test_task_execution_times():
|
|||||||
|
|
||||||
|
|
||||||
def test_interpolate_with_list_of_strings():
|
def test_interpolate_with_list_of_strings():
|
||||||
task = Task(
|
|
||||||
description="Test list interpolation",
|
|
||||||
expected_output="List: {items}",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test simple list of strings
|
# Test simple list of strings
|
||||||
input_str = "Available items: {items}"
|
input_str = "Available items: {items}"
|
||||||
inputs = {"items": ["apple", "banana", "cherry"]}
|
inputs = {"items": ["apple", "banana", "cherry"]}
|
||||||
@@ -1112,11 +1100,6 @@ def test_interpolate_with_list_of_strings():
|
|||||||
|
|
||||||
|
|
||||||
def test_interpolate_with_list_of_dicts():
|
def test_interpolate_with_list_of_dicts():
|
||||||
task = Task(
|
|
||||||
description="Test list of dicts interpolation",
|
|
||||||
expected_output="People: {people}",
|
|
||||||
)
|
|
||||||
|
|
||||||
input_data = {
|
input_data = {
|
||||||
"people": [
|
"people": [
|
||||||
{"name": "Alice", "age": 30, "skills": ["Python", "AI"]},
|
{"name": "Alice", "age": 30, "skills": ["Python", "AI"]},
|
||||||
@@ -1137,11 +1120,6 @@ def test_interpolate_with_list_of_dicts():
|
|||||||
|
|
||||||
|
|
||||||
def test_interpolate_with_nested_structures():
|
def test_interpolate_with_nested_structures():
|
||||||
task = Task(
|
|
||||||
description="Test nested structures",
|
|
||||||
expected_output="Company: {company}",
|
|
||||||
)
|
|
||||||
|
|
||||||
input_data = {
|
input_data = {
|
||||||
"company": {
|
"company": {
|
||||||
"name": "TechCorp",
|
"name": "TechCorp",
|
||||||
@@ -1165,11 +1143,6 @@ def test_interpolate_with_nested_structures():
|
|||||||
|
|
||||||
|
|
||||||
def test_interpolate_with_special_characters():
|
def test_interpolate_with_special_characters():
|
||||||
task = Task(
|
|
||||||
description="Test special characters in dicts",
|
|
||||||
expected_output="Data: {special_data}",
|
|
||||||
)
|
|
||||||
|
|
||||||
input_data = {
|
input_data = {
|
||||||
"special_data": {
|
"special_data": {
|
||||||
"quotes": """This has "double" and 'single' quotes""",
|
"quotes": """This has "double" and 'single' quotes""",
|
||||||
@@ -1188,11 +1161,6 @@ def test_interpolate_with_special_characters():
|
|||||||
|
|
||||||
|
|
||||||
def test_interpolate_mixed_types():
|
def test_interpolate_mixed_types():
|
||||||
task = Task(
|
|
||||||
description="Test mixed type interpolation",
|
|
||||||
expected_output="Mixed: {data}",
|
|
||||||
)
|
|
||||||
|
|
||||||
input_data = {
|
input_data = {
|
||||||
"data": {
|
"data": {
|
||||||
"name": "Test Dataset",
|
"name": "Test Dataset",
|
||||||
@@ -1214,11 +1182,6 @@ def test_interpolate_mixed_types():
|
|||||||
|
|
||||||
|
|
||||||
def test_interpolate_complex_combination():
|
def test_interpolate_complex_combination():
|
||||||
task = Task(
|
|
||||||
description="Test complex combination",
|
|
||||||
expected_output="Report: {report}",
|
|
||||||
)
|
|
||||||
|
|
||||||
input_data = {
|
input_data = {
|
||||||
"report": [
|
"report": [
|
||||||
{
|
{
|
||||||
@@ -1243,11 +1206,6 @@ def test_interpolate_complex_combination():
|
|||||||
|
|
||||||
|
|
||||||
def test_interpolate_invalid_type_validation():
|
def test_interpolate_invalid_type_validation():
|
||||||
task = Task(
|
|
||||||
description="Test invalid type validation",
|
|
||||||
expected_output="Should never reach here",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test with invalid top-level type
|
# Test with invalid top-level type
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
interpolate_only("{data}", {"data": set()}) # type: ignore we are purposely testing this failure
|
interpolate_only("{data}", {"data": set()}) # type: ignore we are purposely testing this failure
|
||||||
@@ -1268,11 +1226,6 @@ def test_interpolate_invalid_type_validation():
|
|||||||
|
|
||||||
|
|
||||||
def test_interpolate_custom_object_validation():
|
def test_interpolate_custom_object_validation():
|
||||||
task = Task(
|
|
||||||
description="Test custom object rejection",
|
|
||||||
expected_output="Should never reach here",
|
|
||||||
)
|
|
||||||
|
|
||||||
class CustomObject:
|
class CustomObject:
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = value
|
self.value = value
|
||||||
@@ -1304,11 +1257,6 @@ def test_interpolate_custom_object_validation():
|
|||||||
|
|
||||||
|
|
||||||
def test_interpolate_valid_complex_types():
|
def test_interpolate_valid_complex_types():
|
||||||
task = Task(
|
|
||||||
description="Test valid complex types",
|
|
||||||
expected_output="Validation should pass",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Valid complex structure
|
# Valid complex structure
|
||||||
valid_data = {
|
valid_data = {
|
||||||
"name": "Valid Dataset",
|
"name": "Valid Dataset",
|
||||||
@@ -1328,11 +1276,6 @@ def test_interpolate_valid_complex_types():
|
|||||||
|
|
||||||
|
|
||||||
def test_interpolate_edge_cases():
|
def test_interpolate_edge_cases():
|
||||||
task = Task(
|
|
||||||
description="Test edge cases",
|
|
||||||
expected_output="Edge case handling",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test empty dict and list
|
# Test empty dict and list
|
||||||
assert interpolate_only("{}", {"data": {}}) == "{}"
|
assert interpolate_only("{}", {"data": {}}) == "{}"
|
||||||
assert interpolate_only("[]", {"data": []}) == "[]"
|
assert interpolate_only("[]", {"data": []}) == "[]"
|
||||||
@@ -1347,11 +1290,6 @@ def test_interpolate_edge_cases():
|
|||||||
|
|
||||||
|
|
||||||
def test_interpolate_valid_types():
|
def test_interpolate_valid_types():
|
||||||
task = Task(
|
|
||||||
description="Test valid types including null and boolean",
|
|
||||||
expected_output="Should pass validation",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test with boolean and null values (valid JSON types)
|
# Test with boolean and null values (valid JSON types)
|
||||||
valid_data = {
|
valid_data = {
|
||||||
"name": "Test",
|
"name": "Test",
|
||||||
@@ -1373,11 +1311,11 @@ def test_interpolate_valid_types():
|
|||||||
|
|
||||||
def test_task_with_no_max_execution_time():
|
def test_task_with_no_max_execution_time():
|
||||||
researcher = Agent(
|
researcher = Agent(
|
||||||
role="Researcher",
|
role="Researcher",
|
||||||
goal="Make the best research and analysis on content about AI and AI agents",
|
goal="Make the best research and analysis on content about AI and AI agents",
|
||||||
backstory="You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.",
|
backstory="You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.",
|
||||||
allow_delegation=False,
|
allow_delegation=False,
|
||||||
max_execution_time=None
|
max_execution_time=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
task = Task(
|
task = Task(
|
||||||
@@ -1386,7 +1324,7 @@ def test_task_with_no_max_execution_time():
|
|||||||
agent=researcher,
|
agent=researcher,
|
||||||
)
|
)
|
||||||
|
|
||||||
with patch.object(Agent, "_execute_without_timeout", return_value = "ok") as execute:
|
with patch.object(Agent, "_execute_without_timeout", return_value="ok") as execute:
|
||||||
result = task.execute_sync(agent=researcher)
|
result = task.execute_sync(agent=researcher)
|
||||||
assert result.raw == "ok"
|
assert result.raw == "ok"
|
||||||
execute.assert_called_once()
|
execute.assert_called_once()
|
||||||
@@ -1395,6 +1333,7 @@ def test_task_with_no_max_execution_time():
|
|||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
def test_task_with_max_execution_time():
|
def test_task_with_max_execution_time():
|
||||||
from crewai.tools import tool
|
from crewai.tools import tool
|
||||||
|
|
||||||
"""Test that execution raises TimeoutError when max_execution_time is exceeded."""
|
"""Test that execution raises TimeoutError when max_execution_time is exceeded."""
|
||||||
|
|
||||||
@tool("what amazing tool", result_as_answer=True)
|
@tool("what amazing tool", result_as_answer=True)
|
||||||
@@ -1412,7 +1351,7 @@ def test_task_with_max_execution_time():
|
|||||||
),
|
),
|
||||||
allow_delegation=False,
|
allow_delegation=False,
|
||||||
tools=[my_tool],
|
tools=[my_tool],
|
||||||
max_execution_time=4
|
max_execution_time=4,
|
||||||
)
|
)
|
||||||
|
|
||||||
task = Task(
|
task = Task(
|
||||||
@@ -1428,6 +1367,7 @@ def test_task_with_max_execution_time():
|
|||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
def test_task_with_max_execution_time_exceeded():
|
def test_task_with_max_execution_time_exceeded():
|
||||||
from crewai.tools import tool
|
from crewai.tools import tool
|
||||||
|
|
||||||
"""Test that execution raises TimeoutError when max_execution_time is exceeded."""
|
"""Test that execution raises TimeoutError when max_execution_time is exceeded."""
|
||||||
|
|
||||||
@tool("what amazing tool", result_as_answer=True)
|
@tool("what amazing tool", result_as_answer=True)
|
||||||
@@ -1445,7 +1385,7 @@ def test_task_with_max_execution_time_exceeded():
|
|||||||
),
|
),
|
||||||
allow_delegation=False,
|
allow_delegation=False,
|
||||||
tools=[my_tool],
|
tools=[my_tool],
|
||||||
max_execution_time=1
|
max_execution_time=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
task = Task(
|
task = Task(
|
||||||
@@ -1455,4 +1395,28 @@ def test_task_with_max_execution_time_exceeded():
|
|||||||
)
|
)
|
||||||
|
|
||||||
with pytest.raises(TimeoutError):
|
with pytest.raises(TimeoutError):
|
||||||
task.execute_sync(agent=researcher)
|
task.execute_sync(agent=researcher)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
|
def test_task_interpolation_with_hyphens():
|
||||||
|
agent = Agent(
|
||||||
|
role="Researcher",
|
||||||
|
goal="be an assistant that responds with {interpolation-with-hyphens}",
|
||||||
|
backstory="You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.",
|
||||||
|
allow_delegation=False,
|
||||||
|
)
|
||||||
|
task = Task(
|
||||||
|
description="be an assistant that responds with {interpolation-with-hyphens}",
|
||||||
|
expected_output="The response should be addressing: {interpolation-with-hyphens}",
|
||||||
|
agent=agent,
|
||||||
|
)
|
||||||
|
crew = Crew(
|
||||||
|
agents=[agent],
|
||||||
|
tasks=[task],
|
||||||
|
verbose=True,
|
||||||
|
)
|
||||||
|
result = crew.kickoff(inputs={"interpolation-with-hyphens": "say hello world"})
|
||||||
|
assert "say hello world" in task.prompt()
|
||||||
|
|
||||||
|
assert result.raw == "Hello, World!"
|
||||||
|
|||||||
10
uv.lock
generated
10
uv.lock
generated
@@ -738,7 +738,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crewai"
|
name = "crewai"
|
||||||
version = "0.119.0"
|
version = "0.120.1"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "appdirs" },
|
{ name = "appdirs" },
|
||||||
@@ -828,7 +828,7 @@ requires-dist = [
|
|||||||
{ name = "blinker", specifier = ">=1.9.0" },
|
{ name = "blinker", specifier = ">=1.9.0" },
|
||||||
{ name = "chromadb", specifier = ">=0.5.23" },
|
{ name = "chromadb", specifier = ">=0.5.23" },
|
||||||
{ name = "click", specifier = ">=8.1.7" },
|
{ name = "click", specifier = ">=8.1.7" },
|
||||||
{ name = "crewai-tools", marker = "extra == 'tools'", specifier = "~=0.44.0" },
|
{ name = "crewai-tools", marker = "extra == 'tools'", specifier = "~=0.45.0" },
|
||||||
{ name = "docling", marker = "extra == 'docling'", specifier = ">=2.12.0" },
|
{ name = "docling", marker = "extra == 'docling'", specifier = ">=2.12.0" },
|
||||||
{ name = "fastembed", marker = "extra == 'fastembed'", specifier = ">=0.4.1" },
|
{ name = "fastembed", marker = "extra == 'fastembed'", specifier = ">=0.4.1" },
|
||||||
{ name = "instructor", specifier = ">=1.3.3" },
|
{ name = "instructor", specifier = ">=1.3.3" },
|
||||||
@@ -879,7 +879,7 @@ dev = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crewai-tools"
|
name = "crewai-tools"
|
||||||
version = "0.44.0"
|
version = "0.45.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "chromadb" },
|
{ name = "chromadb" },
|
||||||
@@ -894,9 +894,9 @@ dependencies = [
|
|||||||
{ name = "pytube" },
|
{ name = "pytube" },
|
||||||
{ name = "requests" },
|
{ name = "requests" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/b8/1f/2977dc72628c1225bf5788ae22a65e5a53df384d19b197646d2c4760684e/crewai_tools-0.44.0.tar.gz", hash = "sha256:44e0c26079396503a326efdd9ff34bf369d410cbf95c362cc523db65b18f3c3a", size = 892004 }
|
sdist = { url = "https://files.pythonhosted.org/packages/e9/3a/7070dcacef56702c5d83ad1a87021b1666ff1850ff80b3aa7540892406e7/crewai_tools-0.45.0.tar.gz", hash = "sha256:1b2e4eff3f928ce5fac308d6e648719a0e4718a1228ae98980aa0d74fc16bfc7", size = 909723 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ba/80/b91aa837d06edbb472445ea3c92d7619518894fd3049d480e5fffbf0c21b/crewai_tools-0.44.0-py3-none-any.whl", hash = "sha256:119e2365fe66ee16e18a5e8e222994b19f76bafcc8c1bb87f61609c1e39b2463", size = 583462 },
|
{ url = "https://files.pythonhosted.org/packages/6e/72/db45626973027c992df75cbc7ef391f18393d631be3bceb6388c1b9f01e1/crewai_tools-0.45.0-py3-none-any.whl", hash = "sha256:9dd34e4792c075ee7a72134aedaab268e78d0e350114fd7fe2426e691c5f52a3", size = 602659 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
Reference in New Issue
Block a user