Compare commits

...

3 Commits

Author SHA1 Message Date
Devin AI
031c2d165a fix(tests): Update task evaluator test assertion for agent arg
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-10 15:59:37 +00:00
Devin AI
2e5f0509bf fix: Resolve type errors identified by mypy
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-10 15:56:24 +00:00
Devin AI
44abceffaa fix: Respect use_system_prompt in Converter regeneration
Fixes #2571

Co-authored-by: Devin AI <devin-ai-integration[bot]@users.noreply.github.com>

Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-10 15:49:25 +00:00
52 changed files with 627 additions and 2470 deletions

View File

@@ -4,4 +4,6 @@ repos:
hooks:
- id: ruff
args: ["--fix"]
exclude: ^src/crewai/cli/templates/
- id: ruff-format
exclude: ^src/crewai/cli/templates/

View File

@@ -367,8 +367,12 @@ class Agent(BaseAgent):
"info", "Coding tools not available. Install crewai_tools. "
)
def get_output_converter(self, llm, text, model, instructions):
return Converter(llm=llm, text=text, model=model, instructions=instructions)
def get_output_converter(
self, agent, llm, text, model, instructions
): # Add agent parameter
return Converter(
agent=agent, llm=llm, text=text, model=model, instructions=instructions
)
def _training_handler(self, task_prompt: str) -> str:
"""Handle training data for the agent task prompt to improve output on Training."""

View File

@@ -153,8 +153,12 @@ class ToolCommand(BaseCommand, PlusAPIMixin):
login_response_json = login_response.json()
settings = Settings()
settings.tool_repository_username = login_response_json["credential"]["username"]
settings.tool_repository_password = login_response_json["credential"]["password"]
settings.tool_repository_username = login_response_json["credential"][
"username"
]
settings.tool_repository_password = login_response_json["credential"][
"password"
]
settings.dump()
console.print(
@@ -179,7 +183,7 @@ class ToolCommand(BaseCommand, PlusAPIMixin):
capture_output=False,
env=self._build_env_with_credentials(repository_handle),
text=True,
check=True
check=True,
)
if add_package_result.stderr:
@@ -204,7 +208,11 @@ class ToolCommand(BaseCommand, PlusAPIMixin):
settings = Settings()
env = os.environ.copy()
env[f"UV_INDEX_{repository_handle}_USERNAME"] = str(settings.tool_repository_username or "")
env[f"UV_INDEX_{repository_handle}_PASSWORD"] = str(settings.tool_repository_password or "")
env[f"UV_INDEX_{repository_handle}_USERNAME"] = str(
settings.tool_repository_username or ""
)
env[f"UV_INDEX_{repository_handle}_PASSWORD"] = str(
settings.tool_repository_password or ""
)
return env

View File

@@ -297,9 +297,7 @@ class Crew(BaseModel):
)
self._external_memory = (
# External memory doesnt support a default value since it was designed to be managed entirely externally
self.external_memory.set_crew(self)
if self.external_memory
else None
self.external_memory.set_crew(self) if self.external_memory else None
)
if (
self.memory_config

View File

@@ -34,13 +34,13 @@ class FlowPlot:
ValueError
If flow object is invalid or missing required attributes.
"""
if not hasattr(flow, '_methods'):
if not hasattr(flow, "_methods"):
raise ValueError("Invalid flow object: missing '_methods' attribute")
if not hasattr(flow, '_listeners'):
if not hasattr(flow, "_listeners"):
raise ValueError("Invalid flow object: missing '_listeners' attribute")
if not hasattr(flow, '_start_methods'):
if not hasattr(flow, "_start_methods"):
raise ValueError("Invalid flow object: missing '_start_methods' attribute")
self.flow = flow
self.colors = COLORS
self.node_styles = NODE_STYLES
@@ -65,7 +65,7 @@ class FlowPlot:
"""
if not filename or not isinstance(filename, str):
raise ValueError("Filename must be a non-empty string")
try:
# Initialize network
net = Network(
@@ -121,7 +121,9 @@ class FlowPlot:
network_html = net.generate_html()
final_html_content = self._generate_final_html(network_html)
except Exception as e:
raise RuntimeError(f"Failed to generate network visualization: {str(e)}")
raise RuntimeError(
f"Failed to generate network visualization: {str(e)}"
)
# Save the final HTML content to the file
try:
@@ -129,7 +131,9 @@ class FlowPlot:
f.write(final_html_content)
print(f"Plot saved as {filename}.html")
except IOError as e:
raise IOError(f"Failed to save flow visualization to {filename}.html: {str(e)}")
raise IOError(
f"Failed to save flow visualization to {filename}.html: {str(e)}"
)
except (ValueError, RuntimeError, IOError) as e:
raise e
@@ -165,7 +169,9 @@ class FlowPlot:
try:
# Extract just the body content from the generated HTML
current_dir = os.path.dirname(__file__)
template_path = safe_path_join("assets", "crewai_flow_visual_template.html", root=current_dir)
template_path = safe_path_join(
"assets", "crewai_flow_visual_template.html", root=current_dir
)
logo_path = safe_path_join("assets", "crewai_logo.svg", root=current_dir)
if not os.path.exists(template_path):
@@ -197,6 +203,7 @@ class FlowPlot:
lib_folder = safe_path_join("lib", root=os.getcwd())
if os.path.exists(lib_folder) and os.path.isdir(lib_folder):
import shutil
shutil.rmtree(lib_folder)
except ValueError as e:
print(f"Error validating lib folder path: {e}")

View File

@@ -1,4 +1,3 @@
def get_legend_items(colors):
return [
{"label": "Start Method", "color": colors["start"]},

View File

@@ -43,18 +43,18 @@ def safe_path_join(*parts: str, root: Union[str, Path, None] = None) -> str:
# Establish root directory
root_path = Path(root).resolve() if root else Path.cwd()
# Join and resolve the full path
full_path = Path(root_path, *clean_parts).resolve()
# Check if the resolved path is within root
if not str(full_path).startswith(str(root_path)):
raise ValueError(
f"Invalid path: Potential directory traversal. Path must be within {root_path}"
)
return str(full_path)
except Exception as e:
if isinstance(e, ValueError):
raise
@@ -84,17 +84,17 @@ def validate_path_exists(path: Union[str, Path], file_type: str = "file") -> str
"""
try:
path_obj = Path(path).resolve()
if not path_obj.exists():
raise ValueError(f"Path does not exist: {path}")
if file_type == "file" and not path_obj.is_file():
raise ValueError(f"Path is not a file: {path}")
elif file_type == "directory" and not path_obj.is_dir():
raise ValueError(f"Path is not a directory: {path}")
return str(path_obj)
except Exception as e:
if isinstance(e, ValueError):
raise
@@ -126,9 +126,9 @@ def list_files(directory: Union[str, Path], pattern: str = "*") -> List[str]:
dir_path = Path(directory).resolve()
if not dir_path.is_dir():
raise ValueError(f"Not a directory: {directory}")
return [str(p) for p in dir_path.glob(pattern) if p.is_file()]
except Exception as e:
if isinstance(e, ValueError):
raise

View File

@@ -8,45 +8,45 @@ from pydantic import BaseModel
class FlowPersistence(abc.ABC):
"""Abstract base class for flow state persistence.
This class defines the interface that all persistence implementations must follow.
It supports both structured (Pydantic BaseModel) and unstructured (dict) states.
"""
@abc.abstractmethod
def init_db(self) -> None:
"""Initialize the persistence backend.
This method should handle any necessary setup, such as:
- Creating tables
- Establishing connections
- Setting up indexes
"""
pass
@abc.abstractmethod
def save_state(
self,
flow_uuid: str,
method_name: str,
state_data: Union[Dict[str, Any], BaseModel]
state_data: Union[Dict[str, Any], BaseModel],
) -> None:
"""Persist the flow state after method completion.
Args:
flow_uuid: Unique identifier for the flow instance
method_name: Name of the method that just completed
state_data: Current state data (either dict or Pydantic model)
"""
pass
@abc.abstractmethod
def load_state(self, flow_uuid: str) -> Optional[Dict[str, Any]]:
"""Load the most recent state for a given flow UUID.
Args:
flow_uuid: Unique identifier for the flow instance
Returns:
The most recent state as a dictionary, or None if no state exists
"""

View File

@@ -48,7 +48,7 @@ LOG_MESSAGES = {
"save_state": "Saving flow state to memory for ID: {}",
"save_error": "Failed to persist state for method {}: {}",
"state_missing": "Flow instance has no state",
"id_missing": "Flow state must have an 'id' field for persistence"
"id_missing": "Flow state must have an 'id' field for persistence",
}
@@ -58,7 +58,13 @@ class PersistenceDecorator:
_printer = Printer() # Class-level printer instance
@classmethod
def persist_state(cls, flow_instance: Any, method_name: str, persistence_instance: FlowPersistence, verbose: bool = False) -> None:
def persist_state(
cls,
flow_instance: Any,
method_name: str,
persistence_instance: FlowPersistence,
verbose: bool = False,
) -> None:
"""Persist flow state with proper error handling and logging.
This method handles the persistence of flow state data, including proper
@@ -76,22 +82,24 @@ class PersistenceDecorator:
AttributeError: If flow instance lacks required state attributes
"""
try:
state = getattr(flow_instance, 'state', None)
state = getattr(flow_instance, "state", None)
if state is None:
raise ValueError("Flow instance has no state")
flow_uuid: Optional[str] = None
if isinstance(state, dict):
flow_uuid = state.get('id')
flow_uuid = state.get("id")
elif isinstance(state, BaseModel):
flow_uuid = getattr(state, 'id', None)
flow_uuid = getattr(state, "id", None)
if not flow_uuid:
raise ValueError("Flow state must have an 'id' field for persistence")
# Log state saving only if verbose is True
if verbose:
cls._printer.print(LOG_MESSAGES["save_state"].format(flow_uuid), color="cyan")
cls._printer.print(
LOG_MESSAGES["save_state"].format(flow_uuid), color="cyan"
)
logger.info(LOG_MESSAGES["save_state"].format(flow_uuid))
try:
@@ -144,7 +152,10 @@ def persist(persistence: Optional[FlowPersistence] = None, verbose: bool = False
def begin(self):
pass
"""
def decorator(target: Union[Type, Callable[..., T]]) -> Union[Type, Callable[..., T]]:
def decorator(
target: Union[Type, Callable[..., T]],
) -> Union[Type, Callable[..., T]]:
"""Decorator that handles both class and method decoration."""
actual_persistence = persistence or SQLiteFlowPersistence()
@@ -154,8 +165,8 @@ def persist(persistence: Optional[FlowPersistence] = None, verbose: bool = False
@functools.wraps(original_init)
def new_init(self: Any, *args: Any, **kwargs: Any) -> None:
if 'persistence' not in kwargs:
kwargs['persistence'] = actual_persistence
if "persistence" not in kwargs:
kwargs["persistence"] = actual_persistence
original_init(self, *args, **kwargs)
setattr(target, "__init__", new_init)
@@ -165,11 +176,11 @@ def persist(persistence: Optional[FlowPersistence] = None, verbose: bool = False
for name, method in target.__dict__.items():
if callable(method) and (
hasattr(method, "__is_start_method__") or
hasattr(method, "__trigger_methods__") or
hasattr(method, "__condition_type__") or
hasattr(method, "__is_flow_method__") or
hasattr(method, "__is_router__")
hasattr(method, "__is_start_method__")
or hasattr(method, "__trigger_methods__")
or hasattr(method, "__condition_type__")
or hasattr(method, "__is_flow_method__")
or hasattr(method, "__is_router__")
):
original_methods[name] = method
@@ -177,18 +188,30 @@ def persist(persistence: Optional[FlowPersistence] = None, verbose: bool = False
for name, method in original_methods.items():
if asyncio.iscoroutinefunction(method):
# Create a closure to capture the current name and method
def create_async_wrapper(method_name: str, original_method: Callable):
def create_async_wrapper(
method_name: str, original_method: Callable
):
@functools.wraps(original_method)
async def method_wrapper(self: Any, *args: Any, **kwargs: Any) -> Any:
async def method_wrapper(
self: Any, *args: Any, **kwargs: Any
) -> Any:
result = await original_method(self, *args, **kwargs)
PersistenceDecorator.persist_state(self, method_name, actual_persistence, verbose)
PersistenceDecorator.persist_state(
self, method_name, actual_persistence, verbose
)
return result
return method_wrapper
wrapped = create_async_wrapper(name, method)
# Preserve all original decorators and attributes
for attr in ["__is_start_method__", "__trigger_methods__", "__condition_type__", "__is_router__"]:
for attr in [
"__is_start_method__",
"__trigger_methods__",
"__condition_type__",
"__is_router__",
]:
if hasattr(method, attr):
setattr(wrapped, attr, getattr(method, attr))
setattr(wrapped, "__is_flow_method__", True)
@@ -197,18 +220,28 @@ def persist(persistence: Optional[FlowPersistence] = None, verbose: bool = False
setattr(target, name, wrapped)
else:
# Create a closure to capture the current name and method
def create_sync_wrapper(method_name: str, original_method: Callable):
def create_sync_wrapper(
method_name: str, original_method: Callable
):
@functools.wraps(original_method)
def method_wrapper(self: Any, *args: Any, **kwargs: Any) -> Any:
result = original_method(self, *args, **kwargs)
PersistenceDecorator.persist_state(self, method_name, actual_persistence, verbose)
PersistenceDecorator.persist_state(
self, method_name, actual_persistence, verbose
)
return result
return method_wrapper
wrapped = create_sync_wrapper(name, method)
# Preserve all original decorators and attributes
for attr in ["__is_start_method__", "__trigger_methods__", "__condition_type__", "__is_router__"]:
for attr in [
"__is_start_method__",
"__trigger_methods__",
"__condition_type__",
"__is_router__",
]:
if hasattr(method, attr):
setattr(wrapped, attr, getattr(method, attr))
setattr(wrapped, "__is_flow_method__", True)
@@ -223,29 +256,49 @@ def persist(persistence: Optional[FlowPersistence] = None, verbose: bool = False
setattr(method, "__is_flow_method__", True)
if asyncio.iscoroutinefunction(method):
@functools.wraps(method)
async def method_async_wrapper(flow_instance: Any, *args: Any, **kwargs: Any) -> T:
async def method_async_wrapper(
flow_instance: Any, *args: Any, **kwargs: Any
) -> T:
method_coro = method(flow_instance, *args, **kwargs)
if asyncio.iscoroutine(method_coro):
result = await method_coro
else:
result = method_coro
PersistenceDecorator.persist_state(flow_instance, method.__name__, actual_persistence, verbose)
PersistenceDecorator.persist_state(
flow_instance, method.__name__, actual_persistence, verbose
)
return result
for attr in ["__is_start_method__", "__trigger_methods__", "__condition_type__", "__is_router__"]:
for attr in [
"__is_start_method__",
"__trigger_methods__",
"__condition_type__",
"__is_router__",
]:
if hasattr(method, attr):
setattr(method_async_wrapper, attr, getattr(method, attr))
setattr(method_async_wrapper, "__is_flow_method__", True)
return cast(Callable[..., T], method_async_wrapper)
else:
@functools.wraps(method)
def method_sync_wrapper(flow_instance: Any, *args: Any, **kwargs: Any) -> T:
def method_sync_wrapper(
flow_instance: Any, *args: Any, **kwargs: Any
) -> T:
result = method(flow_instance, *args, **kwargs)
PersistenceDecorator.persist_state(flow_instance, method.__name__, actual_persistence, verbose)
PersistenceDecorator.persist_state(
flow_instance, method.__name__, actual_persistence, verbose
)
return result
for attr in ["__is_start_method__", "__trigger_methods__", "__condition_type__", "__is_router__"]:
for attr in [
"__is_start_method__",
"__trigger_methods__",
"__condition_type__",
"__is_router__",
]:
if hasattr(method, attr):
setattr(method_sync_wrapper, attr, getattr(method, attr))
setattr(method_sync_wrapper, "__is_flow_method__", True)

View File

@@ -56,6 +56,7 @@ def method_calls_crew(method: Any) -> bool:
class CrewCallVisitor(ast.NodeVisitor):
"""AST visitor to detect .crew() method calls."""
def __init__(self):
self.found = False
@@ -74,7 +75,7 @@ def add_nodes_to_network(
net: Any,
flow: Any,
node_positions: Dict[str, Tuple[float, float]],
node_styles: Dict[str, Dict[str, Any]]
node_styles: Dict[str, Dict[str, Any]],
) -> None:
"""
Add nodes to the network visualization with appropriate styling.
@@ -98,6 +99,7 @@ def add_nodes_to_network(
- Crew methods
- Regular methods
"""
def human_friendly_label(method_name):
return method_name.replace("_", " ").title()
@@ -140,7 +142,7 @@ def compute_positions(
flow: Any,
node_levels: Dict[str, int],
y_spacing: float = 150,
x_spacing: float = 150
x_spacing: float = 150,
) -> Dict[str, Tuple[float, float]]:
"""
Compute the (x, y) positions for each node in the flow graph.
@@ -181,7 +183,7 @@ def add_edges(
net: Any,
flow: Any,
node_positions: Dict[str, Tuple[float, float]],
colors: Dict[str, str]
colors: Dict[str, str],
) -> None:
edge_smooth: Dict[str, Union[str, float]] = {"type": "continuous"} # Default value
"""

View File

@@ -18,9 +18,7 @@ class KickoffTaskOutputsSQLiteStorage:
An updated SQLite storage class for kickoff task outputs storage.
"""
def __init__(
self, db_path: Optional[str] = None
) -> None:
def __init__(self, db_path: Optional[str] = None) -> None:
if db_path is None:
# Get the parent directory of the default db path and create our db file there
db_path = str(Path(db_storage_path()) / "latest_kickoff_task_outputs.db")
@@ -146,7 +144,9 @@ class KickoffTaskOutputsSQLiteStorage:
conn.commit()
if cursor.rowcount == 0:
logger.warning(f"No row found with task_index {task_index}. No update performed.")
logger.warning(
f"No row found with task_index {task_index}. No update performed."
)
except sqlite3.Error as e:
error_msg = DatabaseError.format_error(DatabaseError.UPDATE_ERROR, e)
logger.error(error_msg)

View File

@@ -12,9 +12,7 @@ class LTMSQLiteStorage:
An updated SQLite storage class for LTM data storage.
"""
def __init__(
self, db_path: Optional[str] = None
) -> None:
def __init__(self, db_path: Optional[str] = None) -> None:
if db_path is None:
# Get the parent directory of the default db path and create our db file there
db_path = str(Path(db_storage_path()) / "long_term_memory_storage.db")

View File

@@ -170,9 +170,13 @@ def CrewBase(cls: T) -> T:
if function_calling_llm := agent_info.get("function_calling_llm"):
try:
self.agents_config[agent_name]["function_calling_llm"] = llms[function_calling_llm]()
self.agents_config[agent_name]["function_calling_llm"] = llms[
function_calling_llm
]()
except KeyError:
self.agents_config[agent_name]["function_calling_llm"] = function_calling_llm
self.agents_config[agent_name]["function_calling_llm"] = (
function_calling_llm
)
if step_callback := agent_info.get("step_callback"):
self.agents_config[agent_name]["step_callback"] = callbacks[

View File

@@ -26,46 +26,55 @@ class Fingerprint(BaseModel):
metadata (Dict[str, Any]): Additional metadata associated with this fingerprint
"""
uuid_str: str = Field(default_factory=lambda: str(uuid.uuid4()), description="String representation of the UUID")
created_at: datetime = Field(default_factory=datetime.now, description="When this fingerprint was created")
metadata: Dict[str, Any] = Field(default_factory=dict, description="Additional metadata for this fingerprint")
uuid_str: str = Field(
default_factory=lambda: str(uuid.uuid4()),
description="String representation of the UUID",
)
created_at: datetime = Field(
default_factory=datetime.now, description="When this fingerprint was created"
)
metadata: Dict[str, Any] = Field(
default_factory=dict, description="Additional metadata for this fingerprint"
)
model_config = ConfigDict(arbitrary_types_allowed=True)
@field_validator('metadata')
@field_validator("metadata")
@classmethod
def validate_metadata(cls, v):
"""Validate that metadata is a dictionary with string keys and valid values."""
if not isinstance(v, dict):
raise ValueError("Metadata must be a dictionary")
# Validate that all keys are strings
for key, value in v.items():
if not isinstance(key, str):
raise ValueError(f"Metadata keys must be strings, got {type(key)}")
# Validate nested dictionaries (prevent deeply nested structures)
if isinstance(value, dict):
# Check for nested dictionaries (limit depth to 1)
for nested_key, nested_value in value.items():
if not isinstance(nested_key, str):
raise ValueError(f"Nested metadata keys must be strings, got {type(nested_key)}")
raise ValueError(
f"Nested metadata keys must be strings, got {type(nested_key)}"
)
if isinstance(nested_value, dict):
raise ValueError("Metadata can only be nested one level deep")
# Check for maximum metadata size (prevent DoS)
if len(str(v)) > 10000: # Limit metadata size to 10KB
raise ValueError("Metadata size exceeds maximum allowed (10KB)")
return v
def __init__(self, **data):
"""Initialize a Fingerprint with auto-generated uuid_str and created_at."""
# Remove uuid_str and created_at from data to ensure they're auto-generated
if 'uuid_str' in data:
data.pop('uuid_str')
if 'created_at' in data:
data.pop('created_at')
if "uuid_str" in data:
data.pop("uuid_str")
if "created_at" in data:
data.pop("created_at")
# Call the parent constructor with the modified data
super().__init__(**data)
@@ -88,19 +97,21 @@ class Fingerprint(BaseModel):
"""
if not isinstance(seed, str):
raise ValueError("Seed must be a string")
if not seed.strip():
raise ValueError("Seed cannot be empty or whitespace")
# Create a deterministic UUID using v5 (SHA-1)
# Custom namespace for CrewAI to enhance security
# Using a unique namespace specific to CrewAI to reduce collision risks
CREW_AI_NAMESPACE = uuid.UUID('f47ac10b-58cc-4372-a567-0e02b2c3d479')
CREW_AI_NAMESPACE = uuid.UUID("f47ac10b-58cc-4372-a567-0e02b2c3d479")
return str(uuid.uuid5(CREW_AI_NAMESPACE, seed))
@classmethod
def generate(cls, seed: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None) -> 'Fingerprint':
def generate(
cls, seed: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None
) -> "Fingerprint":
"""
Static factory method to create a new Fingerprint.
@@ -115,7 +126,7 @@ class Fingerprint(BaseModel):
fingerprint = cls(metadata=metadata or {})
if seed:
# For seed-based generation, we need to manually set the uuid_str after creation
object.__setattr__(fingerprint, 'uuid_str', cls._generate_uuid(seed))
object.__setattr__(fingerprint, "uuid_str", cls._generate_uuid(seed))
return fingerprint
def __str__(self) -> str:
@@ -142,11 +153,11 @@ class Fingerprint(BaseModel):
return {
"uuid_str": self.uuid_str,
"created_at": self.created_at.isoformat(),
"metadata": self.metadata
"metadata": self.metadata,
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'Fingerprint':
def from_dict(cls, data: Dict[str, Any]) -> "Fingerprint":
"""
Create a Fingerprint from a dictionary representation.
@@ -163,8 +174,10 @@ class Fingerprint(BaseModel):
# For consistency with existing stored fingerprints, we need to manually set these
if "uuid_str" in data:
object.__setattr__(fingerprint, 'uuid_str', data["uuid_str"])
object.__setattr__(fingerprint, "uuid_str", data["uuid_str"])
if "created_at" in data and isinstance(data["created_at"], str):
object.__setattr__(fingerprint, 'created_at', datetime.fromisoformat(data["created_at"]))
object.__setattr__(
fingerprint, "created_at", datetime.fromisoformat(data["created_at"])
)
return fingerprint

View File

@@ -38,29 +38,27 @@ class SecurityConfig(BaseModel):
)
version: str = Field(
default="1.0.0",
description="Version of the security configuration"
default="1.0.0", description="Version of the security configuration"
)
fingerprint: Fingerprint = Field(
default_factory=Fingerprint,
description="Unique identifier for the component"
default_factory=Fingerprint, description="Unique identifier for the component"
)
def is_compatible(self, min_version: str) -> bool:
"""
Check if this security configuration is compatible with the minimum required version.
Args:
min_version (str): Minimum required version in semver format (e.g., "1.0.0")
Returns:
bool: True if this configuration is compatible, False otherwise
"""
# Simple version comparison (can be enhanced with packaging.version if needed)
current = [int(x) for x in self.version.split(".")]
minimum = [int(x) for x in min_version.split(".")]
# Compare major, minor, patch versions
for c, m in zip(current, minimum):
if c > m:
@@ -69,19 +67,19 @@ class SecurityConfig(BaseModel):
return False
return True
@model_validator(mode='before')
@model_validator(mode="before")
@classmethod
def validate_fingerprint(cls, values):
"""Ensure fingerprint is properly initialized."""
if isinstance(values, dict):
# Handle case where fingerprint is not provided or is None
if 'fingerprint' not in values or values['fingerprint'] is None:
values['fingerprint'] = Fingerprint()
if "fingerprint" not in values or values["fingerprint"] is None:
values["fingerprint"] = Fingerprint()
# Handle case where fingerprint is a string (seed)
elif isinstance(values['fingerprint'], str):
if not values['fingerprint'].strip():
elif isinstance(values["fingerprint"], str):
if not values["fingerprint"].strip():
raise ValueError("Fingerprint seed cannot be empty")
values['fingerprint'] = Fingerprint.generate(seed=values['fingerprint'])
values["fingerprint"] = Fingerprint.generate(seed=values["fingerprint"])
return values
def to_dict(self) -> Dict[str, Any]:
@@ -91,13 +89,11 @@ class SecurityConfig(BaseModel):
Returns:
Dict[str, Any]: Dictionary representation of the security config
"""
result = {
"fingerprint": self.fingerprint.to_dict()
}
result = {"fingerprint": self.fingerprint.to_dict()}
return result
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'SecurityConfig':
def from_dict(cls, data: Dict[str, Any]) -> "SecurityConfig":
"""
Create a SecurityConfig from a dictionary.
@@ -111,6 +107,10 @@ class SecurityConfig(BaseModel):
data_copy = data.copy()
fingerprint_data = data_copy.pop("fingerprint", None)
fingerprint = Fingerprint.from_dict(fingerprint_data) if fingerprint_data else Fingerprint()
fingerprint = (
Fingerprint.from_dict(fingerprint_data)
if fingerprint_data
else Fingerprint()
)
return cls(fingerprint=fingerprint)

View File

@@ -193,7 +193,6 @@ class Task(BaseModel):
# Check return annotation if present, but don't require it
return_annotation = sig.return_annotation
if return_annotation != inspect.Signature.empty:
return_annotation_args = get_args(return_annotation)
if not (
get_origin(return_annotation) is tuple
@@ -464,7 +463,9 @@ 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()

View File

@@ -22,6 +22,7 @@ class GuardrailResult(BaseModel):
result (Any, optional): The validated/transformed result if successful
error (str, optional): Error message if validation failed
"""
success: bool
result: Optional[Any] = None
error: Optional[str] = None
@@ -32,9 +33,13 @@ class GuardrailResult(BaseModel):
values = info.data
if "success" in values:
if values["success"] and v and "error" in values and values["error"]:
raise ValueError("Cannot have both result and error when success is True")
raise ValueError(
"Cannot have both result and error when success is True"
)
if not values["success"] and v and "result" in values and values["result"]:
raise ValueError("Cannot have both result and error when success is False")
raise ValueError(
"Cannot have both result and error when success is False"
)
return v
@classmethod
@@ -52,5 +57,5 @@ class GuardrailResult(BaseModel):
return cls(
success=success,
result=data if success else None,
error=data if not success else None
error=data if not success else None,
)

View File

@@ -75,12 +75,12 @@ class Telemetry:
):
raise # Re-raise the exception to not interfere with system signals
self.ready = False
def _is_telemetry_disabled(self) -> bool:
"""Check if telemetry should be disabled based on environment variables."""
return (
os.getenv("OTEL_SDK_DISABLED", "false").lower() == "true" or
os.getenv("CREWAI_DISABLE_TELEMETRY", "false").lower() == "true"
os.getenv("OTEL_SDK_DISABLED", "false").lower() == "true"
or os.getenv("CREWAI_DISABLE_TELEMETRY", "false").lower() == "true"
)
def set_tracer(self):

View File

@@ -7,6 +7,19 @@ from crewai.utilities import I18N
i18n = I18N()
def _get_add_image_tool_name() -> str:
"""Safely get the tool name from i18n."""
tool_info = i18n.tools("add_image")
if isinstance(tool_info, dict):
return tool_info.get("name", "Add Image")
return "Add Image" # Default name if not a dict
def _get_add_image_tool_description() -> str:
"""Safely get the tool description from i18n."""
tool_info = i18n.tools("add_image")
if isinstance(tool_info, dict):
return tool_info.get("description", "Tool for adding images to the content")
return "Tool for adding images to the content" # Default description if not a dict
class AddImageToolSchema(BaseModel):
image_url: str = Field(..., description="The URL or path of the image to add")
@@ -18,8 +31,8 @@ class AddImageToolSchema(BaseModel):
class AddImageTool(BaseTool):
"""Tool for adding images to the content"""
name: str = Field(default_factory=lambda: i18n.tools("add_image")["name"]) # type: ignore
description: str = Field(default_factory=lambda: i18n.tools("add_image")["description"]) # type: ignore
name: str = Field(default_factory=_get_add_image_tool_name)
description: str = Field(default_factory=_get_add_image_tool_description)
args_schema: type[BaseModel] = AddImageToolSchema
def _run(

View File

@@ -47,10 +47,7 @@ class BaseAgentTool(BaseTool):
return coworker
def _execute(
self,
agent_name: Optional[str],
task: str,
context: Optional[str] = None
self, agent_name: Optional[str], task: str, context: Optional[str] = None
) -> str:
"""
Execute delegation to an agent with case-insensitive and whitespace-tolerant matching.
@@ -77,36 +74,46 @@ class BaseAgentTool(BaseTool):
# when it should look like this:
# {"task": "....", "coworker": "...."}
sanitized_name = self.sanitize_agent_name(agent_name)
logger.debug(f"Sanitized agent name from '{agent_name}' to '{sanitized_name}'")
logger.debug(
f"Sanitized agent name from '{agent_name}' to '{sanitized_name}'"
)
available_agents = [agent.role for agent in self.agents]
logger.debug(f"Available agents: {available_agents}")
agent = [ # type: ignore # Incompatible types in assignment (expression has type "list[BaseAgent]", variable has type "str | None")
matching_agents = [
available_agent
for available_agent in self.agents
if self.sanitize_agent_name(available_agent.role) == sanitized_name
]
logger.debug(f"Found {len(agent)} matching agents for role '{sanitized_name}'")
logger.debug(
f"Found {len(matching_agents)} matching agents for role '{sanitized_name}'"
)
except (AttributeError, ValueError) as e:
# Handle specific exceptions that might occur during role name processing
return self.i18n.errors("agent_tool_unexisting_coworker").format(
coworkers="\n".join(
[f"- {self.sanitize_agent_name(agent.role)}" for agent in self.agents]
[
f"- {self.sanitize_agent_name(agent.role)}"
for agent in self.agents
]
),
error=str(e)
error=str(e),
)
if not agent:
if not matching_agents:
# No matching agent found after sanitization
return self.i18n.errors("agent_tool_unexisting_coworker").format(
coworkers="\n".join(
[f"- {self.sanitize_agent_name(agent.role)}" for agent in self.agents]
[
f"- {self.sanitize_agent_name(agent.role)}"
for agent in self.agents
]
),
error=f"No agent found with role '{sanitized_name}'"
error=f"No agent found with role '{sanitized_name}'",
)
agent = agent[0]
agent: BaseAgent = matching_agents[0]
try:
task_with_assigned_agent = Task(
description=task,
@@ -114,11 +121,12 @@ class BaseAgentTool(BaseTool):
expected_output=agent.i18n.slice("manager_request"),
i18n=agent.i18n,
)
logger.debug(f"Created task for agent '{self.sanitize_agent_name(agent.role)}': {task}")
logger.debug(
f"Created task for agent '{self.sanitize_agent_name(agent.role)}': {task}"
)
return agent.execute_task(task_with_assigned_agent, context)
except Exception as e:
# Handle task creation or execution errors
return self.i18n.errors("agent_tool_execution_error").format(
agent_role=self.sanitize_agent_name(agent.role),
error=str(e)
agent_role=self.sanitize_agent_name(agent.role), error=str(e)
)

View File

@@ -247,7 +247,7 @@ def to_langchain(
def tool(*args, result_as_answer=False):
"""
Decorator to create a tool from a function.
Args:
*args: Positional arguments, either the function to decorate or the tool name.
result_as_answer: Flag to indicate if the tool result should be used as the final agent answer.

View File

@@ -380,6 +380,7 @@ class ToolUsage:
else ToolCalling
)
converter = Converter(
agent=None, # Agent not needed here as function calling is supported/used
text=f"Only tools available:\n###\n{self._render()}\n\nReturn a valid schema for the tool, the tool name must be exactly equal one of the options, use this text to inform the valid output schema:\n\n### TEXT \n{tool_string}",
llm=self.function_calling_llm,
model=model,

View File

@@ -2,7 +2,7 @@ import json
import re
from typing import Any, Optional, Type, Union, get_args, get_origin
from pydantic import BaseModel, ValidationError
from pydantic import BaseModel, Field, ValidationError
from crewai.agents.agent_builder.utilities.base_output_converter import OutputConverter
from crewai.utilities.printer import Printer
@@ -20,18 +20,27 @@ class ConverterError(Exception):
class Converter(OutputConverter):
"""Class that converts text into either pydantic or json."""
agent: Any = Field(description="The agent instance associated with this converter.")
def to_pydantic(self, current_attempt=1) -> BaseModel:
"""Convert text to pydantic."""
try:
if self.llm.supports_function_calling():
result = self._create_instructor().to_pydantic()
else:
response = self.llm.call(
[
{"role": "system", "content": self.instructions},
{"role": "user", "content": self.text},
]
)
messages = []
if self.agent and getattr(self.agent, "use_system_prompt", True):
messages.append({"role": "system", "content": self.instructions})
messages.append({"role": "user", "content": self.text})
else:
messages.append(
{
"role": "user",
"content": f"{self.instructions}\n\n{self.text}",
}
)
response = self.llm.call(messages) # Assign the result to 'response'
try:
# Try to directly validate the response JSON
result = self.model.model_validate_json(response)
@@ -74,14 +83,20 @@ class Converter(OutputConverter):
if self.llm.supports_function_calling():
return self._create_instructor().to_json()
else:
return json.dumps(
self.llm.call(
[
{"role": "system", "content": self.instructions},
{"role": "user", "content": self.text},
]
messages = []
if self.agent and getattr(self.agent, "use_system_prompt", True):
messages.append({"role": "system", "content": self.instructions})
messages.append({"role": "user", "content": self.text})
else:
messages.append(
{
"role": "user",
"content": f"{self.instructions}\n\n{self.text}",
}
)
)
llm_result = self.llm.call(messages)
return json.dumps(llm_result)
except Exception as e:
if current_attempt < self.max_attempts:
return self.to_json(current_attempt + 1)
@@ -239,11 +254,11 @@ def create_converter(
) -> Converter:
if agent and not converter_cls:
if hasattr(agent, "get_output_converter"):
converter = agent.get_output_converter(*args, **kwargs)
converter = agent.get_output_converter(agent=agent, *args, **kwargs)
else:
raise AttributeError("Agent does not have a 'get_output_converter' method")
elif converter_cls:
converter = converter_cls(*args, **kwargs)
converter = converter_cls(agent=agent, *args, **kwargs)
else:
raise ValueError("Either agent or converter_cls must be provided")

View File

@@ -11,6 +11,7 @@ from pydantic import BaseModel
class CrewJSONEncoder(json.JSONEncoder):
"""Custom JSON encoder for CrewAI objects and special types."""
def default(self, obj):
if isinstance(obj, BaseModel):
return self._handle_pydantic_model(obj)

View File

@@ -8,6 +8,7 @@ from crewai.agents.parser import OutputParserException
"""Parser for converting text outputs into Pydantic models."""
class CrewPydanticOutputParser:
"""Parses text outputs into specified Pydantic models."""

View File

@@ -1,4 +1,5 @@
"""Error message definitions for CrewAI database operations."""
from typing import Optional

View File

@@ -65,13 +65,18 @@ class TaskEvaluator:
instructions = f"{instructions}\n\nReturn only valid JSON with the following schema:\n```json\n{model_schema}\n```"
converter = Converter(
agent=self.original_agent, # Pass agent
llm=self.llm,
text=evaluation_query,
model=TaskEvaluation,
instructions=instructions,
)
return converter.to_pydantic()
result = converter.to_pydantic()
if isinstance(result, TaskEvaluation):
return result
else:
raise TypeError(f"Expected TaskEvaluation, got {type(result)}")
def evaluate_training_data(
self, training_data: dict, agent_id: str
@@ -134,6 +139,7 @@ class TaskEvaluator:
instructions = f"{instructions}\n\nThe json should have the following structure, with the following keys:\n{model_schema}"
converter = Converter(
agent=self.original_agent, # Pass agent
llm=self.llm,
text=evaluation_query,
model=TrainingTaskEvaluation,
@@ -141,4 +147,7 @@ class TaskEvaluator:
)
pydantic_result = converter.to_pydantic()
return pydantic_result
if isinstance(pydantic_result, TrainingTaskEvaluation):
return pydantic_result
else:
raise TypeError(f"Expected TrainingTaskEvaluation, got {type(pydantic_result)}")

View File

@@ -7,27 +7,33 @@ from typing import Union
class FileHandler:
"""Handler for file operations supporting both JSON and text-based logging.
Args:
file_path (Union[bool, str]): Path to the log file or boolean flag
"""
def __init__(self, file_path: Union[bool, str]):
self._initialize_path(file_path)
def _initialize_path(self, file_path: Union[bool, str]):
if file_path is True: # File path is boolean True
self._path = os.path.join(os.curdir, "logs.txt")
elif isinstance(file_path, str): # File path is a string
if file_path.endswith((".json", ".txt")):
self._path = file_path # No modification if the file ends with .json or .txt
self._path = (
file_path # No modification if the file ends with .json or .txt
)
else:
self._path = file_path + ".txt" # Append .txt if the file doesn't end with .json or .txt
self._path = (
file_path + ".txt"
) # Append .txt if the file doesn't end with .json or .txt
else:
raise ValueError("file_path must be a string or boolean.") # Handle the case where file_path isn't valid
raise ValueError(
"file_path must be a string or boolean."
) # Handle the case where file_path isn't valid
def log(self, **kwargs):
try:
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@@ -45,20 +51,25 @@ class FileHandler:
except (json.JSONDecodeError, FileNotFoundError):
# If no valid JSON or file doesn't exist, start with an empty list
existing_data = [log_entry]
with open(self._path, "w", encoding="utf-8") as write_file:
json.dump(existing_data, write_file, indent=4)
write_file.write("\n")
else:
# Append log in plain text format
message = f"{now}: " + ", ".join([f"{key}=\"{value}\"" for key, value in kwargs.items()]) + "\n"
message = (
f"{now}: "
+ ", ".join([f'{key}="{value}"' for key, value in kwargs.items()])
+ "\n"
)
with open(self._path, "a", encoding="utf-8") as file:
file.write(message)
except Exception as e:
raise ValueError(f"Failed to log message: {str(e)}")
class PickleHandler:
def __init__(self, file_name: str) -> None:
"""

View File

@@ -6,8 +6,10 @@ from pydantic import BaseModel, Field, PrivateAttr, model_validator
"""Internationalization support for CrewAI prompts and messages."""
class I18N(BaseModel):
"""Handles loading and retrieving internationalized prompts."""
_prompts: Dict[str, Dict[str, str]] = PrivateAttr()
prompt_file: Optional[str] = Field(
default=None,

View File

@@ -5,6 +5,7 @@ import appdirs
"""Path management utilities for CrewAI storage and configuration."""
def db_storage_path() -> str:
"""Returns the path for SQLite database storage.
@@ -28,4 +29,4 @@ def get_project_directory_name():
else:
cwd = Path.cwd()
project_directory_name = cwd.name
return project_directory_name
return project_directory_name

View File

@@ -9,8 +9,10 @@ from crewai.task import Task
"""Handles planning and coordination of crew tasks."""
logger = logging.getLogger(__name__)
class PlanPerTask(BaseModel):
"""Represents a plan for a specific task."""
task: str = Field(..., description="The task for which the plan is created")
plan: str = Field(
...,
@@ -20,6 +22,7 @@ class PlanPerTask(BaseModel):
class PlannerTaskPydanticOutput(BaseModel):
"""Output format for task planning results."""
list_of_plans_per_task: List[PlanPerTask] = Field(
...,
description="Step by step plan on how the agents can execute their tasks using the available tools with mastery",
@@ -28,6 +31,7 @@ class PlannerTaskPydanticOutput(BaseModel):
class CrewPlanner:
"""Plans and coordinates the execution of crew tasks."""
def __init__(self, tasks: List[Task], planning_agent_llm: Optional[Any] = None):
self.tasks = tasks
@@ -97,8 +101,12 @@ class CrewPlanner:
for idx, task in enumerate(self.tasks):
knowledge_list = self._get_agent_knowledge(task)
agent_tools = (
f"[{', '.join(str(tool) for tool in task.agent.tools)}]" if task.agent and task.agent.tools else '"agent has no tools"',
f',\n "agent_knowledge": "[\\"{knowledge_list[0]}\\"]"' if knowledge_list and str(knowledge_list) != "None" else ""
f"[{', '.join(str(tool) for tool in task.agent.tools)}]"
if task.agent and task.agent.tools
else '"agent has no tools"',
f',\n "agent_knowledge": "[\\"{knowledge_list[0]}\\"]"'
if knowledge_list and str(knowledge_list) != "None"
else "",
)
task_summary = f"""
Task Number {idx + 1} - {task.description}

View File

@@ -10,8 +10,10 @@ from crewai.task import Task
"""Handles storage and retrieval of task execution outputs."""
class ExecutionLog(BaseModel):
"""Represents a log entry for task execution."""
task_id: str
expected_output: Optional[str] = None
output: Dict[str, Any]
@@ -26,6 +28,7 @@ class ExecutionLog(BaseModel):
"""Manages storage and retrieval of task outputs."""
class TaskOutputStorageHandler:
def __init__(self) -> None:
self.storage = KickoffTaskOutputsSQLiteStorage()

View File

@@ -259,7 +259,9 @@ def test_cache_hitting():
def handle_tool_end(source, event):
received_events.append(event)
with (patch.object(CacheHandler, "read") as read,):
with (
patch.object(CacheHandler, "read") as read,
):
read.return_value = "0"
task = Task(
description="What is 2 times 6? Ignore correctness and just return the result of the multiplication tool, you must use the tool.",

View File

@@ -8,6 +8,7 @@ from dotenv import load_dotenv
load_result = load_dotenv(override=True)
@pytest.fixture(autouse=True)
def setup_test_environment():
"""Set up test environment with a temporary directory for SQLite storage."""
@@ -15,11 +16,13 @@ def setup_test_environment():
# Create the directory with proper permissions
storage_dir = Path(temp_dir) / "crewai_test_storage"
storage_dir.mkdir(parents=True, exist_ok=True)
# Validate that the directory was created successfully
if not storage_dir.exists() or not storage_dir.is_dir():
raise RuntimeError(f"Failed to create test storage directory: {storage_dir}")
raise RuntimeError(
f"Failed to create test storage directory: {storage_dir}"
)
# Verify directory permissions
try:
# Try to create a test file to verify write permissions
@@ -27,11 +30,13 @@ def setup_test_environment():
test_file.touch()
test_file.unlink()
except (OSError, IOError) as e:
raise RuntimeError(f"Test storage directory {storage_dir} is not writable: {e}")
raise RuntimeError(
f"Test storage directory {storage_dir} is not writable: {e}"
)
# Set environment variable to point to the test storage directory
os.environ["CREWAI_STORAGE_DIR"] = str(storage_dir)
yield
# Cleanup is handled automatically when tempfile context exits

View File

@@ -2157,7 +2157,6 @@ def test_tools_with_custom_caching():
with patch.object(
CacheHandler, "add", wraps=crew._cache_handler.add
) as add_to_cache:
result = crew.kickoff()
# Check that add_to_cache was called exactly twice

View File

@@ -4,12 +4,12 @@
def test_task_output_import():
"""Test that TaskOutput can be imported from crewai."""
from crewai import TaskOutput
assert TaskOutput is not None
def test_crew_output_import():
"""Test that CrewOutput can be imported from crewai."""
from crewai import CrewOutput
assert CrewOutput is not None

View File

@@ -1,4 +1,3 @@
from unittest.mock import MagicMock, patch
import pytest
@@ -12,6 +11,7 @@ class MockCrew:
def __init__(self, memory_config):
self.memory_config = memory_config
@pytest.fixture
def user_memory():
"""Fixture to create a UserMemory instance"""
@@ -19,17 +19,18 @@ def user_memory():
memory_config={
"provider": "mem0",
"config": {"user_id": "john"},
"user_memory" : {}
"user_memory": {},
}
)
user_memory = MagicMock(spec=UserMemory)
with patch.object(Memory,'__new__',return_value=user_memory):
with patch.object(Memory, "__new__", return_value=user_memory):
user_memory_instance = UserMemory(crew=crew)
return user_memory_instance
def test_save_and_search(user_memory):
memory = UserMemoryItem(
data="""test value test value test value test value test value test value
@@ -40,16 +41,10 @@ def test_save_and_search(user_memory):
)
with patch.object(UserMemory, "save") as mock_save:
user_memory.save(
value=memory.data,
metadata=memory.metadata,
user=memory.user
)
user_memory.save(value=memory.data, metadata=memory.metadata, user=memory.user)
mock_save.assert_called_once_with(
value=memory.data,
metadata=memory.metadata,
user=memory.user
value=memory.data, metadata=memory.metadata, user=memory.user
)
expected_result = [
@@ -62,7 +57,9 @@ def test_save_and_search(user_memory):
expected_result = ["mocked_result"]
# Use patch.object to mock UserMemory's search method
with patch.object(UserMemory, 'search', return_value=expected_result) as mock_search:
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]

View File

@@ -43,9 +43,10 @@ class InternalCrew:
@llm
def local_llm(self):
return LLM(
model='openai/model_name',
model="openai/model_name",
api_key="None",
base_url="http://xxx.xxx.xxx.xxx:8000/v1")
base_url="http://xxx.xxx.xxx.xxx:8000/v1",
)
@agent
def researcher(self):

View File

@@ -54,7 +54,7 @@ def test_agent_with_deterministic_fingerprint():
role="Researcher",
goal="Research quantum computing",
backstory="Expert in quantum physics",
security_config=security_config
security_config=security_config,
)
# Create another agent with the same security config
@@ -62,7 +62,7 @@ def test_agent_with_deterministic_fingerprint():
role="Completely different role",
goal="Different goal",
backstory="Different backstory",
security_config=security_config
security_config=security_config,
)
# Both agents should have the same fingerprint UUID
@@ -84,9 +84,7 @@ def test_task_with_deterministic_fingerprint():
# Create an agent first (required for tasks)
agent = Agent(
role="Assistant",
goal="Help with tasks",
backstory="Helpful AI assistant"
role="Assistant", goal="Help with tasks", backstory="Helpful AI assistant"
)
# Create a task with the deterministic fingerprint
@@ -94,7 +92,7 @@ def test_task_with_deterministic_fingerprint():
description="Analyze data",
expected_output="Data analysis report",
agent=agent,
security_config=security_config
security_config=security_config,
)
# Create another task with the same security config
@@ -102,7 +100,7 @@ def test_task_with_deterministic_fingerprint():
description="Different task description",
expected_output="Different expected output",
agent=agent,
security_config=security_config
security_config=security_config,
)
# Both tasks should have the same fingerprint UUID
@@ -119,36 +117,18 @@ def test_crew_with_deterministic_fingerprint():
# Create agents for the crew
agent1 = Agent(
role="Researcher",
goal="Research information",
backstory="Expert researcher"
role="Researcher", goal="Research information", backstory="Expert researcher"
)
agent2 = Agent(
role="Writer",
goal="Write reports",
backstory="Expert writer"
)
agent2 = Agent(role="Writer", goal="Write reports", backstory="Expert writer")
# Create a crew with the deterministic fingerprint
crew1 = Crew(
agents=[agent1, agent2],
tasks=[],
security_config=security_config
)
crew1 = Crew(agents=[agent1, agent2], tasks=[], security_config=security_config)
# Create another crew with the same security config but different agents
agent3 = Agent(
role="Analyst",
goal="Analyze data",
backstory="Expert analyst"
)
agent3 = Agent(role="Analyst", goal="Analyze data", backstory="Expert analyst")
crew2 = Crew(
agents=[agent3],
tasks=[],
security_config=security_config
)
crew2 = Crew(agents=[agent3], tasks=[], security_config=security_config)
# Both crews should have the same fingerprint UUID
assert crew1.fingerprint.uuid_str == crew2.fingerprint.uuid_str
@@ -168,7 +148,7 @@ def test_recreating_components_with_same_seed():
role="Researcher",
goal="Research topic",
backstory="Expert researcher",
security_config=security_config1
security_config=security_config1,
)
uuid_from_first_session = agent1.fingerprint.uuid_str
@@ -181,7 +161,7 @@ def test_recreating_components_with_same_seed():
role="Researcher",
goal="Research topic",
backstory="Expert researcher",
security_config=security_config2
security_config=security_config2,
)
# Should have same UUID across sessions
@@ -209,7 +189,7 @@ def test_security_config_with_seed_string():
role="Tester",
goal="Test fingerprints",
backstory="Expert tester",
security_config=security_config
security_config=security_config,
)
# Agent should have the same fingerprint UUID
@@ -236,7 +216,7 @@ def test_complex_component_hierarchy_with_deterministic_fingerprints():
role="Complex Test Agent",
goal="Test complex fingerprint scenarios",
backstory="Expert in testing",
security_config=agent_config
security_config=agent_config,
)
# Create a task
@@ -244,15 +224,11 @@ def test_complex_component_hierarchy_with_deterministic_fingerprints():
description="Test complex fingerprinting",
expected_output="Verification of fingerprint stability",
agent=agent,
security_config=task_config
security_config=task_config,
)
# Create a crew
crew = Crew(
agents=[agent],
tasks=[task],
security_config=crew_config
)
crew = Crew(agents=[agent], tasks=[task], security_config=crew_config)
# Each component should have its own deterministic fingerprint
assert agent.fingerprint.uuid_str == agent_fingerprint.uuid_str
@@ -271,4 +247,4 @@ def test_complex_component_hierarchy_with_deterministic_fingerprints():
assert agent_fingerprint.uuid_str == agent_fingerprint2.uuid_str
assert task_fingerprint.uuid_str == task_fingerprint2.uuid_str
assert crew_fingerprint.uuid_str == crew_fingerprint2.uuid_str
assert crew_fingerprint.uuid_str == crew_fingerprint2.uuid_str

View File

@@ -170,7 +170,7 @@ def test_fingerprint_from_dict():
fingerprint_dict = {
"uuid_str": uuid_str,
"created_at": created_at_iso,
"metadata": metadata
"metadata": metadata,
}
fingerprint = Fingerprint.from_dict(fingerprint_dict)
@@ -207,11 +207,7 @@ def test_invalid_uuid_str():
uuid_str = "not-a-valid-uuid"
created_at = datetime.now().isoformat()
fingerprint_dict = {
"uuid_str": uuid_str,
"created_at": created_at,
"metadata": {}
}
fingerprint_dict = {"uuid_str": uuid_str, "created_at": created_at, "metadata": {}}
# The Fingerprint.from_dict method accepts even invalid UUIDs
# This seems to be the current behavior
@@ -243,7 +239,7 @@ def test_fingerprint_metadata_mutation():
expected_metadata = {
"version": "1.0",
"status": "published",
"author": "Test Author"
"author": "Test Author",
}
assert fingerprint.metadata == expected_metadata
@@ -260,4 +256,4 @@ def test_fingerprint_metadata_mutation():
# Ensure immutable fields remain unchanged
assert fingerprint.uuid_str == uuid_str
assert fingerprint.created_at == created_at
assert fingerprint.created_at == created_at

View File

@@ -15,7 +15,7 @@ def test_agent_with_security_config():
role="Tester",
goal="Test fingerprinting",
backstory="Testing fingerprinting",
security_config=security_config
security_config=security_config,
)
assert agent.security_config is not None
@@ -28,9 +28,7 @@ def test_agent_fingerprint_property():
"""Test the fingerprint property on Agent."""
# Create agent without security_config
agent = Agent(
role="Tester",
goal="Test fingerprinting",
backstory="Testing fingerprinting"
role="Tester", goal="Test fingerprinting", backstory="Testing fingerprinting"
)
# Fingerprint should be automatically generated
@@ -45,21 +43,14 @@ def test_crew_with_security_config():
security_config = SecurityConfig()
agent1 = Agent(
role="Tester1",
goal="Test fingerprinting",
backstory="Testing fingerprinting"
role="Tester1", goal="Test fingerprinting", backstory="Testing fingerprinting"
)
agent2 = Agent(
role="Tester2",
goal="Test fingerprinting",
backstory="Testing fingerprinting"
role="Tester2", goal="Test fingerprinting", backstory="Testing fingerprinting"
)
crew = Crew(
agents=[agent1, agent2],
security_config=security_config
)
crew = Crew(agents=[agent1, agent2], security_config=security_config)
assert crew.security_config is not None
assert crew.security_config == security_config
@@ -71,15 +62,11 @@ def test_crew_fingerprint_property():
"""Test the fingerprint property on Crew."""
# Create crew without security_config
agent1 = Agent(
role="Tester1",
goal="Test fingerprinting",
backstory="Testing fingerprinting"
role="Tester1", goal="Test fingerprinting", backstory="Testing fingerprinting"
)
agent2 = Agent(
role="Tester2",
goal="Test fingerprinting",
backstory="Testing fingerprinting"
role="Tester2", goal="Test fingerprinting", backstory="Testing fingerprinting"
)
crew = Crew(agents=[agent1, agent2])
@@ -96,16 +83,14 @@ def test_task_with_security_config():
security_config = SecurityConfig()
agent = Agent(
role="Tester",
goal="Test fingerprinting",
backstory="Testing fingerprinting"
role="Tester", goal="Test fingerprinting", backstory="Testing fingerprinting"
)
task = Task(
description="Test task",
expected_output="Testing output",
agent=agent,
security_config=security_config
security_config=security_config,
)
assert task.security_config is not None
@@ -118,16 +103,10 @@ def test_task_fingerprint_property():
"""Test the fingerprint property on Task."""
# Create task without security_config
agent = Agent(
role="Tester",
goal="Test fingerprinting",
backstory="Testing fingerprinting"
role="Tester", goal="Test fingerprinting", backstory="Testing fingerprinting"
)
task = Task(
description="Test task",
expected_output="Testing output",
agent=agent
)
task = Task(description="Test task", expected_output="Testing output", agent=agent)
# Fingerprint should be automatically generated
assert task.fingerprint is not None
@@ -139,33 +118,20 @@ def test_end_to_end_fingerprinting():
"""Test end-to-end fingerprinting across Agent, Crew, and Task."""
# Create components with auto-generated fingerprints
agent1 = Agent(
role="Researcher",
goal="Research information",
backstory="Expert researcher"
role="Researcher", goal="Research information", backstory="Expert researcher"
)
agent2 = Agent(
role="Writer",
goal="Write content",
backstory="Expert writer"
)
agent2 = Agent(role="Writer", goal="Write content", backstory="Expert writer")
task1 = Task(
description="Research topic",
expected_output="Research findings",
agent=agent1
description="Research topic", expected_output="Research findings", agent=agent1
)
task2 = Task(
description="Write article",
expected_output="Written article",
agent=agent2
description="Write article", expected_output="Written article", agent=agent2
)
crew = Crew(
agents=[agent1, agent2],
tasks=[task1, task2]
)
crew = Crew(agents=[agent1, agent2], tasks=[task1, task2])
# Verify all fingerprints were automatically generated
assert agent1.fingerprint is not None
@@ -180,18 +146,18 @@ def test_end_to_end_fingerprinting():
agent2.fingerprint.uuid_str,
task1.fingerprint.uuid_str,
task2.fingerprint.uuid_str,
crew.fingerprint.uuid_str
crew.fingerprint.uuid_str,
]
assert len(fingerprints) == len(set(fingerprints)), "All fingerprints should be unique"
assert len(fingerprints) == len(
set(fingerprints)
), "All fingerprints should be unique"
def test_fingerprint_persistence():
"""Test that fingerprints persist and don't change."""
# Create an agent and check its fingerprint
agent = Agent(
role="Tester",
goal="Test fingerprinting",
backstory="Testing fingerprinting"
role="Tester", goal="Test fingerprinting", backstory="Testing fingerprinting"
)
# Get initial fingerprint
@@ -201,11 +167,7 @@ def test_fingerprint_persistence():
assert agent.fingerprint.uuid_str == initial_fingerprint
# Create a task with the agent
task = Task(
description="Test task",
expected_output="Testing output",
agent=agent
)
task = Task(description="Test task", expected_output="Testing output", agent=agent)
# Check that task has its own unique fingerprint
assert task.fingerprint is not None
@@ -223,27 +185,25 @@ def test_shared_security_config_fingerprints():
role="Researcher",
goal="Research information",
backstory="Expert researcher",
security_config=shared_security_config
security_config=shared_security_config,
)
agent2 = Agent(
role="Writer",
goal="Write content",
backstory="Expert writer",
security_config=shared_security_config
security_config=shared_security_config,
)
task = Task(
description="Write article",
expected_output="Written article",
agent=agent1,
security_config=shared_security_config
security_config=shared_security_config,
)
crew = Crew(
agents=[agent1, agent2],
tasks=[task],
security_config=shared_security_config
agents=[agent1, agent2], tasks=[task], security_config=shared_security_config
)
# Verify all components have the same fingerprint UUID
@@ -256,4 +216,4 @@ def test_shared_security_config_fingerprints():
assert agent1.fingerprint is shared_security_config.fingerprint
assert agent2.fingerprint is shared_security_config.fingerprint
assert task.fingerprint is shared_security_config.fingerprint
assert crew.fingerprint is shared_security_config.fingerprint
assert crew.fingerprint is shared_security_config.fingerprint

View File

@@ -63,13 +63,11 @@ def test_security_config_from_dict():
fingerprint_dict = {
"uuid_str": "b723c6ff-95de-5e87-860b-467b72282bd8",
"created_at": datetime.now().isoformat(),
"metadata": {"version": "1.0"}
"metadata": {"version": "1.0"},
}
# Create a config dict with just the fingerprint
config_dict = {
"fingerprint": fingerprint_dict
}
config_dict = {"fingerprint": fingerprint_dict}
# Create config manually since from_dict has a specific implementation
config = SecurityConfig()
@@ -115,4 +113,4 @@ def test_security_config_json_serialization():
new_config.fingerprint = new_fingerprint
# Check the new config has the same fingerprint metadata
assert new_config.fingerprint.metadata == {"version": "1.0"}
assert new_config.fingerprint.metadata == {"version": "1.0"}

View File

@@ -6,14 +6,17 @@ import pytest
from crewai.telemetry import Telemetry
@pytest.mark.parametrize("env_var,value,expected_ready", [
("OTEL_SDK_DISABLED", "true", False),
("OTEL_SDK_DISABLED", "TRUE", False),
("CREWAI_DISABLE_TELEMETRY", "true", False),
("CREWAI_DISABLE_TELEMETRY", "TRUE", False),
("OTEL_SDK_DISABLED", "false", True),
("CREWAI_DISABLE_TELEMETRY", "false", True),
])
@pytest.mark.parametrize(
"env_var,value,expected_ready",
[
("OTEL_SDK_DISABLED", "true", False),
("OTEL_SDK_DISABLED", "TRUE", False),
("CREWAI_DISABLE_TELEMETRY", "true", False),
("CREWAI_DISABLE_TELEMETRY", "TRUE", False),
("OTEL_SDK_DISABLED", "false", True),
("CREWAI_DISABLE_TELEMETRY", "false", True),
],
)
def test_telemetry_environment_variables(env_var, value, expected_ready):
"""Test telemetry state with different environment variable configurations."""
with patch.dict(os.environ, {env_var: value}):

View File

@@ -6,6 +6,7 @@ from crewai.flow.persistence import persist
class PoemState(FlowState):
"""Test state model with default values that should be overridden."""
sentence_count: int = 1000 # Default that should be overridden
has_set_count: bool = False # Track whether we've set the count
poem_type: str = ""
@@ -46,11 +47,13 @@ def test_default_value_override():
# Fourth run - explicit override should work
flow3 = PoemFlow()
flow3.kickoff(inputs={
"id": original_uuid,
"has_set_count": True,
"sentence_count": 5, # Override persisted value
})
flow3.kickoff(
inputs={
"id": original_uuid,
"has_set_count": True,
"sentence_count": 5, # Override persisted value
}
)
assert flow3.state.sentence_count == 5 # Should use override value
# Third run - should not load sentence_count=2 instead of default 1000
@@ -96,17 +99,12 @@ def test_multi_step_default_override():
# Second run - should load persisted state and update poem type
flow2 = MultiStepPoemFlow()
flow2.kickoff(inputs={
"id": original_uuid,
"sentence_count": 5
})
flow2.kickoff(inputs={"id": original_uuid, "sentence_count": 5})
assert flow2.state.sentence_count == 5
assert flow2.state.poem_type == "limerick"
# Third run - new flow without persisted state should use defaults
flow3 = MultiStepPoemFlow()
flow3.kickoff(inputs={
"id": original_uuid
})
flow3.kickoff(inputs={"id": original_uuid})
assert flow3.state.sentence_count == 5
assert flow3.state.poem_type == "limerick"
assert flow3.state.poem_type == "limerick"

View File

@@ -18,7 +18,7 @@ def test_multimodal_agent_with_image_url():
llm = LLM(
model="openai/gpt-4o", # model with vision capabilities
api_key=OPENAI_API_KEY,
temperature=0.7
temperature=0.7,
)
expert_analyst = Agent(
@@ -28,7 +28,7 @@ def test_multimodal_agent_with_image_url():
llm=llm,
verbose=True,
allow_delegation=False,
multimodal=True
multimodal=True,
)
inspection_task = Task(
@@ -40,7 +40,7 @@ def test_multimodal_agent_with_image_url():
Provide a detailed report highlighting any issues found.
""",
expected_output="A detailed report highlighting any issues found",
agent=expert_analyst
agent=expert_analyst,
)
crew = Crew(agents=[expert_analyst], tasks=[inspection_task])

View File

@@ -107,18 +107,18 @@ def test_result_as_answer_in_tool_decorator():
def my_tool_with_result_as_answer(question: str) -> str:
"""This tool will return its result as the final answer."""
return question
assert my_tool_with_result_as_answer.result_as_answer is True
converted_tool = my_tool_with_result_as_answer.to_structured_tool()
assert converted_tool.result_as_answer is True
@tool("Tool with default result_as_answer")
def my_tool_with_default(question: str) -> str:
"""This tool uses the default result_as_answer value."""
return question
assert my_tool_with_default.result_as_answer is False
converted_tool = my_tool_with_default.to_structured_tool()
assert converted_tool.result_as_answer is False

View File

@@ -1,864 +0,0 @@
interactions:
- request:
body: '{"model": "llama3.2:3b", "prompt": "### System:\nPlease convert the following
text into valid JSON.\n\nOutput ONLY the valid JSON and nothing else.\n\nThe
JSON must follow this format exactly:\n{\n \"name\": str,\n \"age\": int\n}\n\n###
User:\nName: Alice Llama, Age: 30\n\n", "options": {"stop": []}, "stream": false}'
headers:
accept:
- '*/*'
accept-encoding:
- gzip, deflate
connection:
- keep-alive
content-length:
- '321'
host:
- localhost:11434
user-agent:
- litellm/1.60.2
method: POST
uri: http://localhost:11434/api/generate
response:
content: '{"model":"llama3.2:3b","created_at":"2025-02-21T02:57:55.059392Z","response":"{\"name\":
\"Alice Llama\", \"age\": 30}","done":true,"done_reason":"stop","context":[128006,9125,128007,271,38766,1303,33025,2696,25,6790,220,2366,18,271,128009,128006,882,128007,271,14711,744,512,5618,5625,279,2768,1495,1139,2764,4823,382,5207,27785,279,2764,4823,323,4400,775,382,791,4823,2011,1833,420,3645,7041,512,517,220,330,609,794,610,345,220,330,425,794,528,198,633,14711,2724,512,678,25,30505,445,81101,11,13381,25,220,966,271,128009,128006,78191,128007,271,5018,609,794,330,62786,445,81101,498,330,425,794,220,966,92],"total_duration":4675906000,"load_duration":836091458,"prompt_eval_count":82,"prompt_eval_duration":3561000000,"eval_count":15,"eval_duration":275000000}'
headers:
Content-Length:
- '761'
Content-Type:
- application/json; charset=utf-8
Date:
- Fri, 21 Feb 2025 02:57:55 GMT
http_version: HTTP/1.1
status_code: 200
- request:
body: '{"name": "llama3.2:3b"}'
headers:
accept:
- '*/*'
accept-encoding:
- gzip, deflate
connection:
- keep-alive
content-length:
- '23'
content-type:
- application/json
host:
- localhost:11434
user-agent:
- litellm/1.60.2
method: POST
uri: http://localhost:11434/api/show
response:
content: "{\"license\":\"LLAMA 3.2 COMMUNITY LICENSE AGREEMENT\\nLlama 3.2 Version
Release Date: September 25, 2024\\n\\n\u201CAgreement\u201D means the terms
and conditions for use, reproduction, distribution \\nand modification of the
Llama Materials set forth herein.\\n\\n\u201CDocumentation\u201D means the specifications,
manuals and documentation accompanying Llama 3.2\\ndistributed by Meta at https://llama.meta.com/doc/overview.\\n\\n\u201CLicensee\u201D
or \u201Cyou\u201D means you, or your employer or any other person or entity
(if you are \\nentering into this Agreement on such person or entity\u2019s
behalf), of the age required under\\napplicable laws, rules or regulations to
provide legal consent and that has legal authority\\nto bind your employer or
such other person or entity if you are entering in this Agreement\\non their
behalf.\\n\\n\u201CLlama 3.2\u201D means the foundational large language models
and software and algorithms, including\\nmachine-learning model code, trained
model weights, inference-enabling code, training-enabling code,\\nfine-tuning
enabling code and other elements of the foregoing distributed by Meta at \\nhttps://www.llama.com/llama-downloads.\\n\\n\u201CLlama
Materials\u201D means, collectively, Meta\u2019s proprietary Llama 3.2 and Documentation
(and \\nany portion thereof) made available under this Agreement.\\n\\n\u201CMeta\u201D
or \u201Cwe\u201D means Meta Platforms Ireland Limited (if you are located in
or, \\nif you are an entity, your principal place of business is in the EEA
or Switzerland) \\nand Meta Platforms, Inc. (if you are located outside of the
EEA or Switzerland). \\n\\n\\nBy clicking \u201CI Accept\u201D below or by using
or distributing any portion or element of the Llama Materials,\\nyou agree to
be bound by this Agreement.\\n\\n\\n1. License Rights and Redistribution.\\n\\n
\ a. Grant of Rights. You are granted a non-exclusive, worldwide, \\nnon-transferable
and royalty-free limited license under Meta\u2019s intellectual property or
other rights \\nowned by Meta embodied in the Llama Materials to use, reproduce,
distribute, copy, create derivative works \\nof, and make modifications to the
Llama Materials. \\n\\n b. Redistribution and Use. \\n\\n i. If
you distribute or make available the Llama Materials (or any derivative works
thereof), \\nor a product or service (including another AI model) that contains
any of them, you shall (A) provide\\na copy of this Agreement with any such
Llama Materials; and (B) prominently display \u201CBuilt with Llama\u201D\\non
a related website, user interface, blogpost, about page, or product documentation.
If you use the\\nLlama Materials or any outputs or results of the Llama Materials
to create, train, fine tune, or\\notherwise improve an AI model, which is distributed
or made available, you shall also include \u201CLlama\u201D\\nat the beginning
of any such AI model name.\\n\\n ii. If you receive Llama Materials,
or any derivative works thereof, from a Licensee as part\\nof an integrated
end user product, then Section 2 of this Agreement will not apply to you. \\n\\n
\ iii. You must retain in all copies of the Llama Materials that you distribute
the \\nfollowing attribution notice within a \u201CNotice\u201D text file distributed
as a part of such copies: \\n\u201CLlama 3.2 is licensed under the Llama 3.2
Community License, Copyright \xA9 Meta Platforms,\\nInc. All Rights Reserved.\u201D\\n\\n
\ iv. Your use of the Llama Materials must comply with applicable laws
and regulations\\n(including trade compliance laws and regulations) and adhere
to the Acceptable Use Policy for\\nthe Llama Materials (available at https://www.llama.com/llama3_2/use-policy),
which is hereby \\nincorporated by reference into this Agreement.\\n \\n2.
Additional Commercial Terms. If, on the Llama 3.2 version release date, the
monthly active users\\nof the products or services made available by or for
Licensee, or Licensee\u2019s affiliates, \\nis greater than 700 million monthly
active users in the preceding calendar month, you must request \\na license
from Meta, which Meta may grant to you in its sole discretion, and you are not
authorized to\\nexercise any of the rights under this Agreement unless or until
Meta otherwise expressly grants you such rights.\\n\\n3. Disclaimer of Warranty.
UNLESS REQUIRED BY APPLICABLE LAW, THE LLAMA MATERIALS AND ANY OUTPUT AND \\nRESULTS
THEREFROM ARE PROVIDED ON AN \u201CAS IS\u201D BASIS, WITHOUT WARRANTIES OF
ANY KIND, AND META DISCLAIMS\\nALL WARRANTIES OF ANY KIND, BOTH EXPRESS AND
IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES\\nOF TITLE, NON-INFRINGEMENT,
MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. YOU ARE SOLELY RESPONSIBLE\\nFOR
DETERMINING THE APPROPRIATENESS OF USING OR REDISTRIBUTING THE LLAMA MATERIALS
AND ASSUME ANY RISKS ASSOCIATED\\nWITH YOUR USE OF THE LLAMA MATERIALS AND ANY
OUTPUT AND RESULTS.\\n\\n4. Limitation of Liability. IN NO EVENT WILL META OR
ITS AFFILIATES BE LIABLE UNDER ANY THEORY OF LIABILITY, \\nWHETHER IN CONTRACT,
TORT, NEGLIGENCE, PRODUCTS LIABILITY, OR OTHERWISE, ARISING OUT OF THIS AGREEMENT,
\\nFOR ANY LOST PROFITS OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL,
EXEMPLARY OR PUNITIVE DAMAGES, EVEN \\nIF META OR ITS AFFILIATES HAVE BEEN ADVISED
OF THE POSSIBILITY OF ANY OF THE FOREGOING.\\n\\n5. Intellectual Property.\\n\\n
\ a. No trademark licenses are granted under this Agreement, and in connection
with the Llama Materials, \\nneither Meta nor Licensee may use any name or mark
owned by or associated with the other or any of its affiliates, \\nexcept as
required for reasonable and customary use in describing and redistributing the
Llama Materials or as \\nset forth in this Section 5(a). Meta hereby grants
you a license to use \u201CLlama\u201D (the \u201CMark\u201D) solely as required
\\nto comply with the last sentence of Section 1.b.i. You will comply with Meta\u2019s
brand guidelines (currently accessible \\nat https://about.meta.com/brand/resources/meta/company-brand/).
All goodwill arising out of your use of the Mark \\nwill inure to the benefit
of Meta.\\n\\n b. Subject to Meta\u2019s ownership of Llama Materials and
derivatives made by or for Meta, with respect to any\\n derivative works
and modifications of the Llama Materials that are made by you, as between you
and Meta,\\n you are and will be the owner of such derivative works and modifications.\\n\\n
\ c. If you institute litigation or other proceedings against Meta or any
entity (including a cross-claim or\\n counterclaim in a lawsuit) alleging
that the Llama Materials or Llama 3.2 outputs or results, or any portion\\n
\ of any of the foregoing, constitutes infringement of intellectual property
or other rights owned or licensable\\n by you, then any licenses granted
to you under this Agreement shall terminate as of the date such litigation or\\n
\ claim is filed or instituted. You will indemnify and hold harmless Meta
from and against any claim by any third\\n party arising out of or related
to your use or distribution of the Llama Materials.\\n\\n6. Term and Termination.
The term of this Agreement will commence upon your acceptance of this Agreement
or access\\nto the Llama Materials and will continue in full force and effect
until terminated in accordance with the terms\\nand conditions herein. Meta
may terminate this Agreement if you are in breach of any term or condition of
this\\nAgreement. Upon termination of this Agreement, you shall delete and cease
use of the Llama Materials. Sections 3,\\n4 and 7 shall survive the termination
of this Agreement. \\n\\n7. Governing Law and Jurisdiction. This Agreement will
be governed and construed under the laws of the State of \\nCalifornia without
regard to choice of law principles, and the UN Convention on Contracts for the
International\\nSale of Goods does not apply to this Agreement. The courts of
California shall have exclusive jurisdiction of\\nany dispute arising out of
this Agreement.\\n**Llama 3.2** **Acceptable Use Policy**\\n\\nMeta is committed
to promoting safe and fair use of its tools and features, including Llama 3.2.
If you access or use Llama 3.2, you agree to this Acceptable Use Policy (\u201C**Policy**\u201D).
The most recent copy of this policy can be found at [https://www.llama.com/llama3_2/use-policy](https://www.llama.com/llama3_2/use-policy).\\n\\n**Prohibited
Uses**\\n\\nWe want everyone to use Llama 3.2 safely and responsibly. You agree
you will not use, or allow others to use, Llama 3.2 to:\\n\\n\\n\\n1. Violate
the law or others\u2019 rights, including to:\\n 1. Engage in, promote, generate,
contribute to, encourage, plan, incite, or further illegal or unlawful activity
or content, such as:\\n 1. Violence or terrorism\\n 2. Exploitation
or harm to children, including the solicitation, creation, acquisition, or dissemination
of child exploitative content or failure to report Child Sexual Abuse Material\\n
\ 3. Human trafficking, exploitation, and sexual violence\\n 4.
The illegal distribution of information or materials to minors, including obscene
materials, or failure to employ legally required age-gating in connection with
such information or materials.\\n 5. Sexual solicitation\\n 6.
Any other criminal activity\\n 1. Engage in, promote, incite, or facilitate
the harassment, abuse, threatening, or bullying of individuals or groups of
individuals\\n 2. Engage in, promote, incite, or facilitate discrimination
or other unlawful or harmful conduct in the provision of employment, employment
benefits, credit, housing, other economic benefits, or other essential goods
and services\\n 3. Engage in the unauthorized or unlicensed practice of any
profession including, but not limited to, financial, legal, medical/health,
or related professional practices\\n 4. Collect, process, disclose, generate,
or infer private or sensitive information about individuals, including information
about individuals\u2019 identity, health, or demographic information, unless
you have obtained the right to do so in accordance with applicable law\\n 5.
Engage in or facilitate any action or generate any content that infringes, misappropriates,
or otherwise violates any third-party rights, including the outputs or results
of any products or services using the Llama Materials\\n 6. Create, generate,
or facilitate the creation of malicious code, malware, computer viruses or do
anything else that could disable, overburden, interfere with or impair the proper
working, integrity, operation or appearance of a website or computer system\\n
\ 7. Engage in any action, or facilitate any action, to intentionally circumvent
or remove usage restrictions or other safety measures, or to enable functionality
disabled by Meta\\n2. Engage in, promote, incite, facilitate, or assist in the
planning or development of activities that present a risk of death or bodily
harm to individuals, including use of Llama 3.2 related to the following:\\n
\ 8. Military, warfare, nuclear industries or applications, espionage, use
for materials or activities that are subject to the International Traffic Arms
Regulations (ITAR) maintained by the United States Department of State or to
the U.S. Biological Weapons Anti-Terrorism Act of 1989 or the Chemical Weapons
Convention Implementation Act of 1997\\n 9. Guns and illegal weapons (including
weapon development)\\n 10. Illegal drugs and regulated/controlled substances\\n
\ 11. Operation of critical infrastructure, transportation technologies, or
heavy machinery\\n 12. Self-harm or harm to others, including suicide, cutting,
and eating disorders\\n 13. Any content intended to incite or promote violence,
abuse, or any infliction of bodily harm to an individual\\n3. Intentionally
deceive or mislead others, including use of Llama 3.2 related to the following:\\n
\ 14. Generating, promoting, or furthering fraud or the creation or promotion
of disinformation\\n 15. Generating, promoting, or furthering defamatory
content, including the creation of defamatory statements, images, or other content\\n
\ 16. Generating, promoting, or further distributing spam\\n 17. Impersonating
another individual without consent, authorization, or legal right\\n 18.
Representing that the use of Llama 3.2 or outputs are human-generated\\n 19.
Generating or facilitating false online engagement, including fake reviews and
other means of fake online engagement\\n4. Fail to appropriately disclose to
end users any known dangers of your AI system\\n5. Interact with third party
tools, models, or software designed to generate unlawful content or engage in
unlawful or harmful conduct and/or represent that the outputs of such tools,
models, or software are associated with Meta or Llama 3.2\\n\\nWith respect
to any multimodal models included in Llama 3.2, the rights granted under Section
1(a) of the Llama 3.2 Community License Agreement are not being granted to you
if you are an individual domiciled in, or a company with a principal place of
business in, the European Union. This restriction does not apply to end users
of a product or service that incorporates any such multimodal models.\\n\\nPlease
report any violation of this Policy, software \u201Cbug,\u201D or other problems
that could lead to a violation of this Policy through one of the following means:\\n\\n\\n\\n*
Reporting issues with the model: [https://github.com/meta-llama/llama-models/issues](https://l.workplace.com/l.php?u=https%3A%2F%2Fgithub.com%2Fmeta-llama%2Fllama-models%2Fissues\\u0026h=AT0qV8W9BFT6NwihiOHRuKYQM_UnkzN_NmHMy91OT55gkLpgi4kQupHUl0ssR4dQsIQ8n3tfd0vtkobvsEvt1l4Ic6GXI2EeuHV8N08OG2WnbAmm0FL4ObkazC6G_256vN0lN9DsykCvCqGZ)\\n*
Reporting risky content generated by the model: [developers.facebook.com/llama_output_feedback](http://developers.facebook.com/llama_output_feedback)\\n*
Reporting bugs and security concerns: [facebook.com/whitehat/info](http://facebook.com/whitehat/info)\\n*
Reporting violations of the Acceptable Use Policy or unlicensed uses of Llama
3.2: LlamaUseReport@meta.com\",\"modelfile\":\"# Modelfile generated by \\\"ollama
show\\\"\\n# To build a new Modelfile based on this, replace FROM with:\\n#
FROM llama3.2:3b\\n\\nFROM /Users/joaomoura/.ollama/models/blobs/sha256-dde5aa3fc5ffc17176b5e8bdc82f587b24b2678c6c66101bf7da77af9f7ccdff\\nTEMPLATE
\\\"\\\"\\\"\\u003c|start_header_id|\\u003esystem\\u003c|end_header_id|\\u003e\\n\\nCutting
Knowledge Date: December 2023\\n\\n{{ if .System }}{{ .System }}\\n{{- end }}\\n{{-
if .Tools }}When you receive a tool call response, use the output to format
an answer to the orginal user question.\\n\\nYou are a helpful assistant with
tool calling capabilities.\\n{{- end }}\\u003c|eot_id|\\u003e\\n{{- range $i,
$_ := .Messages }}\\n{{- $last := eq (len (slice $.Messages $i)) 1 }}\\n{{-
if eq .Role \\\"user\\\" }}\\u003c|start_header_id|\\u003euser\\u003c|end_header_id|\\u003e\\n{{-
if and $.Tools $last }}\\n\\nGiven the following functions, please respond with
a JSON for a function call with its proper arguments that best answers the given
prompt.\\n\\nRespond in the format {\\\"name\\\": function name, \\\"parameters\\\":
dictionary of argument name and its value}. Do not use variables.\\n\\n{{ range
$.Tools }}\\n{{- . }}\\n{{ end }}\\n{{ .Content }}\\u003c|eot_id|\\u003e\\n{{-
else }}\\n\\n{{ .Content }}\\u003c|eot_id|\\u003e\\n{{- end }}{{ if $last }}\\u003c|start_header_id|\\u003eassistant\\u003c|end_header_id|\\u003e\\n\\n{{
end }}\\n{{- else if eq .Role \\\"assistant\\\" }}\\u003c|start_header_id|\\u003eassistant\\u003c|end_header_id|\\u003e\\n{{-
if .ToolCalls }}\\n{{ range .ToolCalls }}\\n{\\\"name\\\": \\\"{{ .Function.Name
}}\\\", \\\"parameters\\\": {{ .Function.Arguments }}}{{ end }}\\n{{- else }}\\n\\n{{
.Content }}\\n{{- end }}{{ if not $last }}\\u003c|eot_id|\\u003e{{ end }}\\n{{-
else if eq .Role \\\"tool\\\" }}\\u003c|start_header_id|\\u003eipython\\u003c|end_header_id|\\u003e\\n\\n{{
.Content }}\\u003c|eot_id|\\u003e{{ if $last }}\\u003c|start_header_id|\\u003eassistant\\u003c|end_header_id|\\u003e\\n\\n{{
end }}\\n{{- end }}\\n{{- end }}\\\"\\\"\\\"\\nPARAMETER stop \\u003c|start_header_id|\\u003e\\nPARAMETER
stop \\u003c|end_header_id|\\u003e\\nPARAMETER stop \\u003c|eot_id|\\u003e\\nLICENSE
\\\"LLAMA 3.2 COMMUNITY LICENSE AGREEMENT\\nLlama 3.2 Version Release Date:
September 25, 2024\\n\\n\u201CAgreement\u201D means the terms and conditions
for use, reproduction, distribution \\nand modification of the Llama Materials
set forth herein.\\n\\n\u201CDocumentation\u201D means the specifications, manuals
and documentation accompanying Llama 3.2\\ndistributed by Meta at https://llama.meta.com/doc/overview.\\n\\n\u201CLicensee\u201D
or \u201Cyou\u201D means you, or your employer or any other person or entity
(if you are \\nentering into this Agreement on such person or entity\u2019s
behalf), of the age required under\\napplicable laws, rules or regulations to
provide legal consent and that has legal authority\\nto bind your employer or
such other person or entity if you are entering in this Agreement\\non their
behalf.\\n\\n\u201CLlama 3.2\u201D means the foundational large language models
and software and algorithms, including\\nmachine-learning model code, trained
model weights, inference-enabling code, training-enabling code,\\nfine-tuning
enabling code and other elements of the foregoing distributed by Meta at \\nhttps://www.llama.com/llama-downloads.\\n\\n\u201CLlama
Materials\u201D means, collectively, Meta\u2019s proprietary Llama 3.2 and Documentation
(and \\nany portion thereof) made available under this Agreement.\\n\\n\u201CMeta\u201D
or \u201Cwe\u201D means Meta Platforms Ireland Limited (if you are located in
or, \\nif you are an entity, your principal place of business is in the EEA
or Switzerland) \\nand Meta Platforms, Inc. (if you are located outside of the
EEA or Switzerland). \\n\\n\\nBy clicking \u201CI Accept\u201D below or by using
or distributing any portion or element of the Llama Materials,\\nyou agree to
be bound by this Agreement.\\n\\n\\n1. License Rights and Redistribution.\\n\\n
\ a. Grant of Rights. You are granted a non-exclusive, worldwide, \\nnon-transferable
and royalty-free limited license under Meta\u2019s intellectual property or
other rights \\nowned by Meta embodied in the Llama Materials to use, reproduce,
distribute, copy, create derivative works \\nof, and make modifications to the
Llama Materials. \\n\\n b. Redistribution and Use. \\n\\n i. If
you distribute or make available the Llama Materials (or any derivative works
thereof), \\nor a product or service (including another AI model) that contains
any of them, you shall (A) provide\\na copy of this Agreement with any such
Llama Materials; and (B) prominently display \u201CBuilt with Llama\u201D\\non
a related website, user interface, blogpost, about page, or product documentation.
If you use the\\nLlama Materials or any outputs or results of the Llama Materials
to create, train, fine tune, or\\notherwise improve an AI model, which is distributed
or made available, you shall also include \u201CLlama\u201D\\nat the beginning
of any such AI model name.\\n\\n ii. If you receive Llama Materials,
or any derivative works thereof, from a Licensee as part\\nof an integrated
end user product, then Section 2 of this Agreement will not apply to you. \\n\\n
\ iii. You must retain in all copies of the Llama Materials that you distribute
the \\nfollowing attribution notice within a \u201CNotice\u201D text file distributed
as a part of such copies: \\n\u201CLlama 3.2 is licensed under the Llama 3.2
Community License, Copyright \xA9 Meta Platforms,\\nInc. All Rights Reserved.\u201D\\n\\n
\ iv. Your use of the Llama Materials must comply with applicable laws
and regulations\\n(including trade compliance laws and regulations) and adhere
to the Acceptable Use Policy for\\nthe Llama Materials (available at https://www.llama.com/llama3_2/use-policy),
which is hereby \\nincorporated by reference into this Agreement.\\n \\n2.
Additional Commercial Terms. If, on the Llama 3.2 version release date, the
monthly active users\\nof the products or services made available by or for
Licensee, or Licensee\u2019s affiliates, \\nis greater than 700 million monthly
active users in the preceding calendar month, you must request \\na license
from Meta, which Meta may grant to you in its sole discretion, and you are not
authorized to\\nexercise any of the rights under this Agreement unless or until
Meta otherwise expressly grants you such rights.\\n\\n3. Disclaimer of Warranty.
UNLESS REQUIRED BY APPLICABLE LAW, THE LLAMA MATERIALS AND ANY OUTPUT AND \\nRESULTS
THEREFROM ARE PROVIDED ON AN \u201CAS IS\u201D BASIS, WITHOUT WARRANTIES OF
ANY KIND, AND META DISCLAIMS\\nALL WARRANTIES OF ANY KIND, BOTH EXPRESS AND
IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES\\nOF TITLE, NON-INFRINGEMENT,
MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. YOU ARE SOLELY RESPONSIBLE\\nFOR
DETERMINING THE APPROPRIATENESS OF USING OR REDISTRIBUTING THE LLAMA MATERIALS
AND ASSUME ANY RISKS ASSOCIATED\\nWITH YOUR USE OF THE LLAMA MATERIALS AND ANY
OUTPUT AND RESULTS.\\n\\n4. Limitation of Liability. IN NO EVENT WILL META OR
ITS AFFILIATES BE LIABLE UNDER ANY THEORY OF LIABILITY, \\nWHETHER IN CONTRACT,
TORT, NEGLIGENCE, PRODUCTS LIABILITY, OR OTHERWISE, ARISING OUT OF THIS AGREEMENT,
\\nFOR ANY LOST PROFITS OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL,
EXEMPLARY OR PUNITIVE DAMAGES, EVEN \\nIF META OR ITS AFFILIATES HAVE BEEN ADVISED
OF THE POSSIBILITY OF ANY OF THE FOREGOING.\\n\\n5. Intellectual Property.\\n\\n
\ a. No trademark licenses are granted under this Agreement, and in connection
with the Llama Materials, \\nneither Meta nor Licensee may use any name or mark
owned by or associated with the other or any of its affiliates, \\nexcept as
required for reasonable and customary use in describing and redistributing the
Llama Materials or as \\nset forth in this Section 5(a). Meta hereby grants
you a license to use \u201CLlama\u201D (the \u201CMark\u201D) solely as required
\\nto comply with the last sentence of Section 1.b.i. You will comply with Meta\u2019s
brand guidelines (currently accessible \\nat https://about.meta.com/brand/resources/meta/company-brand/).
All goodwill arising out of your use of the Mark \\nwill inure to the benefit
of Meta.\\n\\n b. Subject to Meta\u2019s ownership of Llama Materials and
derivatives made by or for Meta, with respect to any\\n derivative works
and modifications of the Llama Materials that are made by you, as between you
and Meta,\\n you are and will be the owner of such derivative works and modifications.\\n\\n
\ c. If you institute litigation or other proceedings against Meta or any
entity (including a cross-claim or\\n counterclaim in a lawsuit) alleging
that the Llama Materials or Llama 3.2 outputs or results, or any portion\\n
\ of any of the foregoing, constitutes infringement of intellectual property
or other rights owned or licensable\\n by you, then any licenses granted
to you under this Agreement shall terminate as of the date such litigation or\\n
\ claim is filed or instituted. You will indemnify and hold harmless Meta
from and against any claim by any third\\n party arising out of or related
to your use or distribution of the Llama Materials.\\n\\n6. Term and Termination.
The term of this Agreement will commence upon your acceptance of this Agreement
or access\\nto the Llama Materials and will continue in full force and effect
until terminated in accordance with the terms\\nand conditions herein. Meta
may terminate this Agreement if you are in breach of any term or condition of
this\\nAgreement. Upon termination of this Agreement, you shall delete and cease
use of the Llama Materials. Sections 3,\\n4 and 7 shall survive the termination
of this Agreement. \\n\\n7. Governing Law and Jurisdiction. This Agreement will
be governed and construed under the laws of the State of \\nCalifornia without
regard to choice of law principles, and the UN Convention on Contracts for the
International\\nSale of Goods does not apply to this Agreement. The courts of
California shall have exclusive jurisdiction of\\nany dispute arising out of
this Agreement.\\\"\\nLICENSE \\\"**Llama 3.2** **Acceptable Use Policy**\\n\\nMeta
is committed to promoting safe and fair use of its tools and features, including
Llama 3.2. If you access or use Llama 3.2, you agree to this Acceptable Use
Policy (\u201C**Policy**\u201D). The most recent copy of this policy can be
found at [https://www.llama.com/llama3_2/use-policy](https://www.llama.com/llama3_2/use-policy).\\n\\n**Prohibited
Uses**\\n\\nWe want everyone to use Llama 3.2 safely and responsibly. You agree
you will not use, or allow others to use, Llama 3.2 to:\\n\\n\\n\\n1. Violate
the law or others\u2019 rights, including to:\\n 1. Engage in, promote, generate,
contribute to, encourage, plan, incite, or further illegal or unlawful activity
or content, such as:\\n 1. Violence or terrorism\\n 2. Exploitation
or harm to children, including the solicitation, creation, acquisition, or dissemination
of child exploitative content or failure to report Child Sexual Abuse Material\\n
\ 3. Human trafficking, exploitation, and sexual violence\\n 4.
The illegal distribution of information or materials to minors, including obscene
materials, or failure to employ legally required age-gating in connection with
such information or materials.\\n 5. Sexual solicitation\\n 6.
Any other criminal activity\\n 1. Engage in, promote, incite, or facilitate
the harassment, abuse, threatening, or bullying of individuals or groups of
individuals\\n 2. Engage in, promote, incite, or facilitate discrimination
or other unlawful or harmful conduct in the provision of employment, employment
benefits, credit, housing, other economic benefits, or other essential goods
and services\\n 3. Engage in the unauthorized or unlicensed practice of any
profession including, but not limited to, financial, legal, medical/health,
or related professional practices\\n 4. Collect, process, disclose, generate,
or infer private or sensitive information about individuals, including information
about individuals\u2019 identity, health, or demographic information, unless
you have obtained the right to do so in accordance with applicable law\\n 5.
Engage in or facilitate any action or generate any content that infringes, misappropriates,
or otherwise violates any third-party rights, including the outputs or results
of any products or services using the Llama Materials\\n 6. Create, generate,
or facilitate the creation of malicious code, malware, computer viruses or do
anything else that could disable, overburden, interfere with or impair the proper
working, integrity, operation or appearance of a website or computer system\\n
\ 7. Engage in any action, or facilitate any action, to intentionally circumvent
or remove usage restrictions or other safety measures, or to enable functionality
disabled by Meta\\n2. Engage in, promote, incite, facilitate, or assist in the
planning or development of activities that present a risk of death or bodily
harm to individuals, including use of Llama 3.2 related to the following:\\n
\ 8. Military, warfare, nuclear industries or applications, espionage, use
for materials or activities that are subject to the International Traffic Arms
Regulations (ITAR) maintained by the United States Department of State or to
the U.S. Biological Weapons Anti-Terrorism Act of 1989 or the Chemical Weapons
Convention Implementation Act of 1997\\n 9. Guns and illegal weapons (including
weapon development)\\n 10. Illegal drugs and regulated/controlled substances\\n
\ 11. Operation of critical infrastructure, transportation technologies, or
heavy machinery\\n 12. Self-harm or harm to others, including suicide, cutting,
and eating disorders\\n 13. Any content intended to incite or promote violence,
abuse, or any infliction of bodily harm to an individual\\n3. Intentionally
deceive or mislead others, including use of Llama 3.2 related to the following:\\n
\ 14. Generating, promoting, or furthering fraud or the creation or promotion
of disinformation\\n 15. Generating, promoting, or furthering defamatory
content, including the creation of defamatory statements, images, or other content\\n
\ 16. Generating, promoting, or further distributing spam\\n 17. Impersonating
another individual without consent, authorization, or legal right\\n 18.
Representing that the use of Llama 3.2 or outputs are human-generated\\n 19.
Generating or facilitating false online engagement, including fake reviews and
other means of fake online engagement\\n4. Fail to appropriately disclose to
end users any known dangers of your AI system\\n5. Interact with third party
tools, models, or software designed to generate unlawful content or engage in
unlawful or harmful conduct and/or represent that the outputs of such tools,
models, or software are associated with Meta or Llama 3.2\\n\\nWith respect
to any multimodal models included in Llama 3.2, the rights granted under Section
1(a) of the Llama 3.2 Community License Agreement are not being granted to you
if you are an individual domiciled in, or a company with a principal place of
business in, the European Union. This restriction does not apply to end users
of a product or service that incorporates any such multimodal models.\\n\\nPlease
report any violation of this Policy, software \u201Cbug,\u201D or other problems
that could lead to a violation of this Policy through one of the following means:\\n\\n\\n\\n*
Reporting issues with the model: [https://github.com/meta-llama/llama-models/issues](https://l.workplace.com/l.php?u=https%3A%2F%2Fgithub.com%2Fmeta-llama%2Fllama-models%2Fissues\\u0026h=AT0qV8W9BFT6NwihiOHRuKYQM_UnkzN_NmHMy91OT55gkLpgi4kQupHUl0ssR4dQsIQ8n3tfd0vtkobvsEvt1l4Ic6GXI2EeuHV8N08OG2WnbAmm0FL4ObkazC6G_256vN0lN9DsykCvCqGZ)\\n*
Reporting risky content generated by the model: [developers.facebook.com/llama_output_feedback](http://developers.facebook.com/llama_output_feedback)\\n*
Reporting bugs and security concerns: [facebook.com/whitehat/info](http://facebook.com/whitehat/info)\\n*
Reporting violations of the Acceptable Use Policy or unlicensed uses of Llama
3.2: LlamaUseReport@meta.com\\\"\\n\",\"parameters\":\"stop \\\"\\u003c|start_header_id|\\u003e\\\"\\nstop
\ \\\"\\u003c|end_header_id|\\u003e\\\"\\nstop \\\"\\u003c|eot_id|\\u003e\\\"\",\"template\":\"\\u003c|start_header_id|\\u003esystem\\u003c|end_header_id|\\u003e\\n\\nCutting
Knowledge Date: December 2023\\n\\n{{ if .System }}{{ .System }}\\n{{- end }}\\n{{-
if .Tools }}When you receive a tool call response, use the output to format
an answer to the orginal user question.\\n\\nYou are a helpful assistant with
tool calling capabilities.\\n{{- end }}\\u003c|eot_id|\\u003e\\n{{- range $i,
$_ := .Messages }}\\n{{- $last := eq (len (slice $.Messages $i)) 1 }}\\n{{-
if eq .Role \\\"user\\\" }}\\u003c|start_header_id|\\u003euser\\u003c|end_header_id|\\u003e\\n{{-
if and $.Tools $last }}\\n\\nGiven the following functions, please respond with
a JSON for a function call with its proper arguments that best answers the given
prompt.\\n\\nRespond in the format {\\\"name\\\": function name, \\\"parameters\\\":
dictionary of argument name and its value}. Do not use variables.\\n\\n{{ range
$.Tools }}\\n{{- . }}\\n{{ end }}\\n{{ .Content }}\\u003c|eot_id|\\u003e\\n{{-
else }}\\n\\n{{ .Content }}\\u003c|eot_id|\\u003e\\n{{- end }}{{ if $last }}\\u003c|start_header_id|\\u003eassistant\\u003c|end_header_id|\\u003e\\n\\n{{
end }}\\n{{- else if eq .Role \\\"assistant\\\" }}\\u003c|start_header_id|\\u003eassistant\\u003c|end_header_id|\\u003e\\n{{-
if .ToolCalls }}\\n{{ range .ToolCalls }}\\n{\\\"name\\\": \\\"{{ .Function.Name
}}\\\", \\\"parameters\\\": {{ .Function.Arguments }}}{{ end }}\\n{{- else }}\\n\\n{{
.Content }}\\n{{- end }}{{ if not $last }}\\u003c|eot_id|\\u003e{{ end }}\\n{{-
else if eq .Role \\\"tool\\\" }}\\u003c|start_header_id|\\u003eipython\\u003c|end_header_id|\\u003e\\n\\n{{
.Content }}\\u003c|eot_id|\\u003e{{ if $last }}\\u003c|start_header_id|\\u003eassistant\\u003c|end_header_id|\\u003e\\n\\n{{
end }}\\n{{- end }}\\n{{- end }}\",\"details\":{\"parent_model\":\"\",\"format\":\"gguf\",\"family\":\"llama\",\"families\":[\"llama\"],\"parameter_size\":\"3.2B\",\"quantization_level\":\"Q4_K_M\"},\"model_info\":{\"general.architecture\":\"llama\",\"general.basename\":\"Llama-3.2\",\"general.file_type\":15,\"general.finetune\":\"Instruct\",\"general.languages\":[\"en\",\"de\",\"fr\",\"it\",\"pt\",\"hi\",\"es\",\"th\"],\"general.parameter_count\":3212749888,\"general.quantization_version\":2,\"general.size_label\":\"3B\",\"general.tags\":[\"facebook\",\"meta\",\"pytorch\",\"llama\",\"llama-3\",\"text-generation\"],\"general.type\":\"model\",\"llama.attention.head_count\":24,\"llama.attention.head_count_kv\":8,\"llama.attention.key_length\":128,\"llama.attention.layer_norm_rms_epsilon\":0.00001,\"llama.attention.value_length\":128,\"llama.block_count\":28,\"llama.context_length\":131072,\"llama.embedding_length\":3072,\"llama.feed_forward_length\":8192,\"llama.rope.dimension_count\":128,\"llama.rope.freq_base\":500000,\"llama.vocab_size\":128256,\"tokenizer.ggml.bos_token_id\":128000,\"tokenizer.ggml.eos_token_id\":128009,\"tokenizer.ggml.merges\":null,\"tokenizer.ggml.model\":\"gpt2\",\"tokenizer.ggml.pre\":\"llama-bpe\",\"tokenizer.ggml.token_type\":null,\"tokenizer.ggml.tokens\":null},\"modified_at\":\"2025-02-20T18:55:09.150577031-08:00\"}"
headers:
Content-Type:
- application/json; charset=utf-8
Date:
- Fri, 21 Feb 2025 02:57:55 GMT
Transfer-Encoding:
- chunked
http_version: HTTP/1.1
status_code: 200
- request:
body: '{"name": "llama3.2:3b"}'
headers:
accept:
- '*/*'
accept-encoding:
- gzip, deflate
connection:
- keep-alive
content-length:
- '23'
content-type:
- application/json
host:
- localhost:11434
user-agent:
- litellm/1.60.2
method: POST
uri: http://localhost:11434/api/show
response:
content: "{\"license\":\"LLAMA 3.2 COMMUNITY LICENSE AGREEMENT\\nLlama 3.2 Version
Release Date: September 25, 2024\\n\\n\u201CAgreement\u201D means the terms
and conditions for use, reproduction, distribution \\nand modification of the
Llama Materials set forth herein.\\n\\n\u201CDocumentation\u201D means the specifications,
manuals and documentation accompanying Llama 3.2\\ndistributed by Meta at https://llama.meta.com/doc/overview.\\n\\n\u201CLicensee\u201D
or \u201Cyou\u201D means you, or your employer or any other person or entity
(if you are \\nentering into this Agreement on such person or entity\u2019s
behalf), of the age required under\\napplicable laws, rules or regulations to
provide legal consent and that has legal authority\\nto bind your employer or
such other person or entity if you are entering in this Agreement\\non their
behalf.\\n\\n\u201CLlama 3.2\u201D means the foundational large language models
and software and algorithms, including\\nmachine-learning model code, trained
model weights, inference-enabling code, training-enabling code,\\nfine-tuning
enabling code and other elements of the foregoing distributed by Meta at \\nhttps://www.llama.com/llama-downloads.\\n\\n\u201CLlama
Materials\u201D means, collectively, Meta\u2019s proprietary Llama 3.2 and Documentation
(and \\nany portion thereof) made available under this Agreement.\\n\\n\u201CMeta\u201D
or \u201Cwe\u201D means Meta Platforms Ireland Limited (if you are located in
or, \\nif you are an entity, your principal place of business is in the EEA
or Switzerland) \\nand Meta Platforms, Inc. (if you are located outside of the
EEA or Switzerland). \\n\\n\\nBy clicking \u201CI Accept\u201D below or by using
or distributing any portion or element of the Llama Materials,\\nyou agree to
be bound by this Agreement.\\n\\n\\n1. License Rights and Redistribution.\\n\\n
\ a. Grant of Rights. You are granted a non-exclusive, worldwide, \\nnon-transferable
and royalty-free limited license under Meta\u2019s intellectual property or
other rights \\nowned by Meta embodied in the Llama Materials to use, reproduce,
distribute, copy, create derivative works \\nof, and make modifications to the
Llama Materials. \\n\\n b. Redistribution and Use. \\n\\n i. If
you distribute or make available the Llama Materials (or any derivative works
thereof), \\nor a product or service (including another AI model) that contains
any of them, you shall (A) provide\\na copy of this Agreement with any such
Llama Materials; and (B) prominently display \u201CBuilt with Llama\u201D\\non
a related website, user interface, blogpost, about page, or product documentation.
If you use the\\nLlama Materials or any outputs or results of the Llama Materials
to create, train, fine tune, or\\notherwise improve an AI model, which is distributed
or made available, you shall also include \u201CLlama\u201D\\nat the beginning
of any such AI model name.\\n\\n ii. If you receive Llama Materials,
or any derivative works thereof, from a Licensee as part\\nof an integrated
end user product, then Section 2 of this Agreement will not apply to you. \\n\\n
\ iii. You must retain in all copies of the Llama Materials that you distribute
the \\nfollowing attribution notice within a \u201CNotice\u201D text file distributed
as a part of such copies: \\n\u201CLlama 3.2 is licensed under the Llama 3.2
Community License, Copyright \xA9 Meta Platforms,\\nInc. All Rights Reserved.\u201D\\n\\n
\ iv. Your use of the Llama Materials must comply with applicable laws
and regulations\\n(including trade compliance laws and regulations) and adhere
to the Acceptable Use Policy for\\nthe Llama Materials (available at https://www.llama.com/llama3_2/use-policy),
which is hereby \\nincorporated by reference into this Agreement.\\n \\n2.
Additional Commercial Terms. If, on the Llama 3.2 version release date, the
monthly active users\\nof the products or services made available by or for
Licensee, or Licensee\u2019s affiliates, \\nis greater than 700 million monthly
active users in the preceding calendar month, you must request \\na license
from Meta, which Meta may grant to you in its sole discretion, and you are not
authorized to\\nexercise any of the rights under this Agreement unless or until
Meta otherwise expressly grants you such rights.\\n\\n3. Disclaimer of Warranty.
UNLESS REQUIRED BY APPLICABLE LAW, THE LLAMA MATERIALS AND ANY OUTPUT AND \\nRESULTS
THEREFROM ARE PROVIDED ON AN \u201CAS IS\u201D BASIS, WITHOUT WARRANTIES OF
ANY KIND, AND META DISCLAIMS\\nALL WARRANTIES OF ANY KIND, BOTH EXPRESS AND
IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES\\nOF TITLE, NON-INFRINGEMENT,
MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. YOU ARE SOLELY RESPONSIBLE\\nFOR
DETERMINING THE APPROPRIATENESS OF USING OR REDISTRIBUTING THE LLAMA MATERIALS
AND ASSUME ANY RISKS ASSOCIATED\\nWITH YOUR USE OF THE LLAMA MATERIALS AND ANY
OUTPUT AND RESULTS.\\n\\n4. Limitation of Liability. IN NO EVENT WILL META OR
ITS AFFILIATES BE LIABLE UNDER ANY THEORY OF LIABILITY, \\nWHETHER IN CONTRACT,
TORT, NEGLIGENCE, PRODUCTS LIABILITY, OR OTHERWISE, ARISING OUT OF THIS AGREEMENT,
\\nFOR ANY LOST PROFITS OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL,
EXEMPLARY OR PUNITIVE DAMAGES, EVEN \\nIF META OR ITS AFFILIATES HAVE BEEN ADVISED
OF THE POSSIBILITY OF ANY OF THE FOREGOING.\\n\\n5. Intellectual Property.\\n\\n
\ a. No trademark licenses are granted under this Agreement, and in connection
with the Llama Materials, \\nneither Meta nor Licensee may use any name or mark
owned by or associated with the other or any of its affiliates, \\nexcept as
required for reasonable and customary use in describing and redistributing the
Llama Materials or as \\nset forth in this Section 5(a). Meta hereby grants
you a license to use \u201CLlama\u201D (the \u201CMark\u201D) solely as required
\\nto comply with the last sentence of Section 1.b.i. You will comply with Meta\u2019s
brand guidelines (currently accessible \\nat https://about.meta.com/brand/resources/meta/company-brand/).
All goodwill arising out of your use of the Mark \\nwill inure to the benefit
of Meta.\\n\\n b. Subject to Meta\u2019s ownership of Llama Materials and
derivatives made by or for Meta, with respect to any\\n derivative works
and modifications of the Llama Materials that are made by you, as between you
and Meta,\\n you are and will be the owner of such derivative works and modifications.\\n\\n
\ c. If you institute litigation or other proceedings against Meta or any
entity (including a cross-claim or\\n counterclaim in a lawsuit) alleging
that the Llama Materials or Llama 3.2 outputs or results, or any portion\\n
\ of any of the foregoing, constitutes infringement of intellectual property
or other rights owned or licensable\\n by you, then any licenses granted
to you under this Agreement shall terminate as of the date such litigation or\\n
\ claim is filed or instituted. You will indemnify and hold harmless Meta
from and against any claim by any third\\n party arising out of or related
to your use or distribution of the Llama Materials.\\n\\n6. Term and Termination.
The term of this Agreement will commence upon your acceptance of this Agreement
or access\\nto the Llama Materials and will continue in full force and effect
until terminated in accordance with the terms\\nand conditions herein. Meta
may terminate this Agreement if you are in breach of any term or condition of
this\\nAgreement. Upon termination of this Agreement, you shall delete and cease
use of the Llama Materials. Sections 3,\\n4 and 7 shall survive the termination
of this Agreement. \\n\\n7. Governing Law and Jurisdiction. This Agreement will
be governed and construed under the laws of the State of \\nCalifornia without
regard to choice of law principles, and the UN Convention on Contracts for the
International\\nSale of Goods does not apply to this Agreement. The courts of
California shall have exclusive jurisdiction of\\nany dispute arising out of
this Agreement.\\n**Llama 3.2** **Acceptable Use Policy**\\n\\nMeta is committed
to promoting safe and fair use of its tools and features, including Llama 3.2.
If you access or use Llama 3.2, you agree to this Acceptable Use Policy (\u201C**Policy**\u201D).
The most recent copy of this policy can be found at [https://www.llama.com/llama3_2/use-policy](https://www.llama.com/llama3_2/use-policy).\\n\\n**Prohibited
Uses**\\n\\nWe want everyone to use Llama 3.2 safely and responsibly. You agree
you will not use, or allow others to use, Llama 3.2 to:\\n\\n\\n\\n1. Violate
the law or others\u2019 rights, including to:\\n 1. Engage in, promote, generate,
contribute to, encourage, plan, incite, or further illegal or unlawful activity
or content, such as:\\n 1. Violence or terrorism\\n 2. Exploitation
or harm to children, including the solicitation, creation, acquisition, or dissemination
of child exploitative content or failure to report Child Sexual Abuse Material\\n
\ 3. Human trafficking, exploitation, and sexual violence\\n 4.
The illegal distribution of information or materials to minors, including obscene
materials, or failure to employ legally required age-gating in connection with
such information or materials.\\n 5. Sexual solicitation\\n 6.
Any other criminal activity\\n 1. Engage in, promote, incite, or facilitate
the harassment, abuse, threatening, or bullying of individuals or groups of
individuals\\n 2. Engage in, promote, incite, or facilitate discrimination
or other unlawful or harmful conduct in the provision of employment, employment
benefits, credit, housing, other economic benefits, or other essential goods
and services\\n 3. Engage in the unauthorized or unlicensed practice of any
profession including, but not limited to, financial, legal, medical/health,
or related professional practices\\n 4. Collect, process, disclose, generate,
or infer private or sensitive information about individuals, including information
about individuals\u2019 identity, health, or demographic information, unless
you have obtained the right to do so in accordance with applicable law\\n 5.
Engage in or facilitate any action or generate any content that infringes, misappropriates,
or otherwise violates any third-party rights, including the outputs or results
of any products or services using the Llama Materials\\n 6. Create, generate,
or facilitate the creation of malicious code, malware, computer viruses or do
anything else that could disable, overburden, interfere with or impair the proper
working, integrity, operation or appearance of a website or computer system\\n
\ 7. Engage in any action, or facilitate any action, to intentionally circumvent
or remove usage restrictions or other safety measures, or to enable functionality
disabled by Meta\\n2. Engage in, promote, incite, facilitate, or assist in the
planning or development of activities that present a risk of death or bodily
harm to individuals, including use of Llama 3.2 related to the following:\\n
\ 8. Military, warfare, nuclear industries or applications, espionage, use
for materials or activities that are subject to the International Traffic Arms
Regulations (ITAR) maintained by the United States Department of State or to
the U.S. Biological Weapons Anti-Terrorism Act of 1989 or the Chemical Weapons
Convention Implementation Act of 1997\\n 9. Guns and illegal weapons (including
weapon development)\\n 10. Illegal drugs and regulated/controlled substances\\n
\ 11. Operation of critical infrastructure, transportation technologies, or
heavy machinery\\n 12. Self-harm or harm to others, including suicide, cutting,
and eating disorders\\n 13. Any content intended to incite or promote violence,
abuse, or any infliction of bodily harm to an individual\\n3. Intentionally
deceive or mislead others, including use of Llama 3.2 related to the following:\\n
\ 14. Generating, promoting, or furthering fraud or the creation or promotion
of disinformation\\n 15. Generating, promoting, or furthering defamatory
content, including the creation of defamatory statements, images, or other content\\n
\ 16. Generating, promoting, or further distributing spam\\n 17. Impersonating
another individual without consent, authorization, or legal right\\n 18.
Representing that the use of Llama 3.2 or outputs are human-generated\\n 19.
Generating or facilitating false online engagement, including fake reviews and
other means of fake online engagement\\n4. Fail to appropriately disclose to
end users any known dangers of your AI system\\n5. Interact with third party
tools, models, or software designed to generate unlawful content or engage in
unlawful or harmful conduct and/or represent that the outputs of such tools,
models, or software are associated with Meta or Llama 3.2\\n\\nWith respect
to any multimodal models included in Llama 3.2, the rights granted under Section
1(a) of the Llama 3.2 Community License Agreement are not being granted to you
if you are an individual domiciled in, or a company with a principal place of
business in, the European Union. This restriction does not apply to end users
of a product or service that incorporates any such multimodal models.\\n\\nPlease
report any violation of this Policy, software \u201Cbug,\u201D or other problems
that could lead to a violation of this Policy through one of the following means:\\n\\n\\n\\n*
Reporting issues with the model: [https://github.com/meta-llama/llama-models/issues](https://l.workplace.com/l.php?u=https%3A%2F%2Fgithub.com%2Fmeta-llama%2Fllama-models%2Fissues\\u0026h=AT0qV8W9BFT6NwihiOHRuKYQM_UnkzN_NmHMy91OT55gkLpgi4kQupHUl0ssR4dQsIQ8n3tfd0vtkobvsEvt1l4Ic6GXI2EeuHV8N08OG2WnbAmm0FL4ObkazC6G_256vN0lN9DsykCvCqGZ)\\n*
Reporting risky content generated by the model: [developers.facebook.com/llama_output_feedback](http://developers.facebook.com/llama_output_feedback)\\n*
Reporting bugs and security concerns: [facebook.com/whitehat/info](http://facebook.com/whitehat/info)\\n*
Reporting violations of the Acceptable Use Policy or unlicensed uses of Llama
3.2: LlamaUseReport@meta.com\",\"modelfile\":\"# Modelfile generated by \\\"ollama
show\\\"\\n# To build a new Modelfile based on this, replace FROM with:\\n#
FROM llama3.2:3b\\n\\nFROM /Users/joaomoura/.ollama/models/blobs/sha256-dde5aa3fc5ffc17176b5e8bdc82f587b24b2678c6c66101bf7da77af9f7ccdff\\nTEMPLATE
\\\"\\\"\\\"\\u003c|start_header_id|\\u003esystem\\u003c|end_header_id|\\u003e\\n\\nCutting
Knowledge Date: December 2023\\n\\n{{ if .System }}{{ .System }}\\n{{- end }}\\n{{-
if .Tools }}When you receive a tool call response, use the output to format
an answer to the orginal user question.\\n\\nYou are a helpful assistant with
tool calling capabilities.\\n{{- end }}\\u003c|eot_id|\\u003e\\n{{- range $i,
$_ := .Messages }}\\n{{- $last := eq (len (slice $.Messages $i)) 1 }}\\n{{-
if eq .Role \\\"user\\\" }}\\u003c|start_header_id|\\u003euser\\u003c|end_header_id|\\u003e\\n{{-
if and $.Tools $last }}\\n\\nGiven the following functions, please respond with
a JSON for a function call with its proper arguments that best answers the given
prompt.\\n\\nRespond in the format {\\\"name\\\": function name, \\\"parameters\\\":
dictionary of argument name and its value}. Do not use variables.\\n\\n{{ range
$.Tools }}\\n{{- . }}\\n{{ end }}\\n{{ .Content }}\\u003c|eot_id|\\u003e\\n{{-
else }}\\n\\n{{ .Content }}\\u003c|eot_id|\\u003e\\n{{- end }}{{ if $last }}\\u003c|start_header_id|\\u003eassistant\\u003c|end_header_id|\\u003e\\n\\n{{
end }}\\n{{- else if eq .Role \\\"assistant\\\" }}\\u003c|start_header_id|\\u003eassistant\\u003c|end_header_id|\\u003e\\n{{-
if .ToolCalls }}\\n{{ range .ToolCalls }}\\n{\\\"name\\\": \\\"{{ .Function.Name
}}\\\", \\\"parameters\\\": {{ .Function.Arguments }}}{{ end }}\\n{{- else }}\\n\\n{{
.Content }}\\n{{- end }}{{ if not $last }}\\u003c|eot_id|\\u003e{{ end }}\\n{{-
else if eq .Role \\\"tool\\\" }}\\u003c|start_header_id|\\u003eipython\\u003c|end_header_id|\\u003e\\n\\n{{
.Content }}\\u003c|eot_id|\\u003e{{ if $last }}\\u003c|start_header_id|\\u003eassistant\\u003c|end_header_id|\\u003e\\n\\n{{
end }}\\n{{- end }}\\n{{- end }}\\\"\\\"\\\"\\nPARAMETER stop \\u003c|start_header_id|\\u003e\\nPARAMETER
stop \\u003c|end_header_id|\\u003e\\nPARAMETER stop \\u003c|eot_id|\\u003e\\nLICENSE
\\\"LLAMA 3.2 COMMUNITY LICENSE AGREEMENT\\nLlama 3.2 Version Release Date:
September 25, 2024\\n\\n\u201CAgreement\u201D means the terms and conditions
for use, reproduction, distribution \\nand modification of the Llama Materials
set forth herein.\\n\\n\u201CDocumentation\u201D means the specifications, manuals
and documentation accompanying Llama 3.2\\ndistributed by Meta at https://llama.meta.com/doc/overview.\\n\\n\u201CLicensee\u201D
or \u201Cyou\u201D means you, or your employer or any other person or entity
(if you are \\nentering into this Agreement on such person or entity\u2019s
behalf), of the age required under\\napplicable laws, rules or regulations to
provide legal consent and that has legal authority\\nto bind your employer or
such other person or entity if you are entering in this Agreement\\non their
behalf.\\n\\n\u201CLlama 3.2\u201D means the foundational large language models
and software and algorithms, including\\nmachine-learning model code, trained
model weights, inference-enabling code, training-enabling code,\\nfine-tuning
enabling code and other elements of the foregoing distributed by Meta at \\nhttps://www.llama.com/llama-downloads.\\n\\n\u201CLlama
Materials\u201D means, collectively, Meta\u2019s proprietary Llama 3.2 and Documentation
(and \\nany portion thereof) made available under this Agreement.\\n\\n\u201CMeta\u201D
or \u201Cwe\u201D means Meta Platforms Ireland Limited (if you are located in
or, \\nif you are an entity, your principal place of business is in the EEA
or Switzerland) \\nand Meta Platforms, Inc. (if you are located outside of the
EEA or Switzerland). \\n\\n\\nBy clicking \u201CI Accept\u201D below or by using
or distributing any portion or element of the Llama Materials,\\nyou agree to
be bound by this Agreement.\\n\\n\\n1. License Rights and Redistribution.\\n\\n
\ a. Grant of Rights. You are granted a non-exclusive, worldwide, \\nnon-transferable
and royalty-free limited license under Meta\u2019s intellectual property or
other rights \\nowned by Meta embodied in the Llama Materials to use, reproduce,
distribute, copy, create derivative works \\nof, and make modifications to the
Llama Materials. \\n\\n b. Redistribution and Use. \\n\\n i. If
you distribute or make available the Llama Materials (or any derivative works
thereof), \\nor a product or service (including another AI model) that contains
any of them, you shall (A) provide\\na copy of this Agreement with any such
Llama Materials; and (B) prominently display \u201CBuilt with Llama\u201D\\non
a related website, user interface, blogpost, about page, or product documentation.
If you use the\\nLlama Materials or any outputs or results of the Llama Materials
to create, train, fine tune, or\\notherwise improve an AI model, which is distributed
or made available, you shall also include \u201CLlama\u201D\\nat the beginning
of any such AI model name.\\n\\n ii. If you receive Llama Materials,
or any derivative works thereof, from a Licensee as part\\nof an integrated
end user product, then Section 2 of this Agreement will not apply to you. \\n\\n
\ iii. You must retain in all copies of the Llama Materials that you distribute
the \\nfollowing attribution notice within a \u201CNotice\u201D text file distributed
as a part of such copies: \\n\u201CLlama 3.2 is licensed under the Llama 3.2
Community License, Copyright \xA9 Meta Platforms,\\nInc. All Rights Reserved.\u201D\\n\\n
\ iv. Your use of the Llama Materials must comply with applicable laws
and regulations\\n(including trade compliance laws and regulations) and adhere
to the Acceptable Use Policy for\\nthe Llama Materials (available at https://www.llama.com/llama3_2/use-policy),
which is hereby \\nincorporated by reference into this Agreement.\\n \\n2.
Additional Commercial Terms. If, on the Llama 3.2 version release date, the
monthly active users\\nof the products or services made available by or for
Licensee, or Licensee\u2019s affiliates, \\nis greater than 700 million monthly
active users in the preceding calendar month, you must request \\na license
from Meta, which Meta may grant to you in its sole discretion, and you are not
authorized to\\nexercise any of the rights under this Agreement unless or until
Meta otherwise expressly grants you such rights.\\n\\n3. Disclaimer of Warranty.
UNLESS REQUIRED BY APPLICABLE LAW, THE LLAMA MATERIALS AND ANY OUTPUT AND \\nRESULTS
THEREFROM ARE PROVIDED ON AN \u201CAS IS\u201D BASIS, WITHOUT WARRANTIES OF
ANY KIND, AND META DISCLAIMS\\nALL WARRANTIES OF ANY KIND, BOTH EXPRESS AND
IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES\\nOF TITLE, NON-INFRINGEMENT,
MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. YOU ARE SOLELY RESPONSIBLE\\nFOR
DETERMINING THE APPROPRIATENESS OF USING OR REDISTRIBUTING THE LLAMA MATERIALS
AND ASSUME ANY RISKS ASSOCIATED\\nWITH YOUR USE OF THE LLAMA MATERIALS AND ANY
OUTPUT AND RESULTS.\\n\\n4. Limitation of Liability. IN NO EVENT WILL META OR
ITS AFFILIATES BE LIABLE UNDER ANY THEORY OF LIABILITY, \\nWHETHER IN CONTRACT,
TORT, NEGLIGENCE, PRODUCTS LIABILITY, OR OTHERWISE, ARISING OUT OF THIS AGREEMENT,
\\nFOR ANY LOST PROFITS OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL,
EXEMPLARY OR PUNITIVE DAMAGES, EVEN \\nIF META OR ITS AFFILIATES HAVE BEEN ADVISED
OF THE POSSIBILITY OF ANY OF THE FOREGOING.\\n\\n5. Intellectual Property.\\n\\n
\ a. No trademark licenses are granted under this Agreement, and in connection
with the Llama Materials, \\nneither Meta nor Licensee may use any name or mark
owned by or associated with the other or any of its affiliates, \\nexcept as
required for reasonable and customary use in describing and redistributing the
Llama Materials or as \\nset forth in this Section 5(a). Meta hereby grants
you a license to use \u201CLlama\u201D (the \u201CMark\u201D) solely as required
\\nto comply with the last sentence of Section 1.b.i. You will comply with Meta\u2019s
brand guidelines (currently accessible \\nat https://about.meta.com/brand/resources/meta/company-brand/).
All goodwill arising out of your use of the Mark \\nwill inure to the benefit
of Meta.\\n\\n b. Subject to Meta\u2019s ownership of Llama Materials and
derivatives made by or for Meta, with respect to any\\n derivative works
and modifications of the Llama Materials that are made by you, as between you
and Meta,\\n you are and will be the owner of such derivative works and modifications.\\n\\n
\ c. If you institute litigation or other proceedings against Meta or any
entity (including a cross-claim or\\n counterclaim in a lawsuit) alleging
that the Llama Materials or Llama 3.2 outputs or results, or any portion\\n
\ of any of the foregoing, constitutes infringement of intellectual property
or other rights owned or licensable\\n by you, then any licenses granted
to you under this Agreement shall terminate as of the date such litigation or\\n
\ claim is filed or instituted. You will indemnify and hold harmless Meta
from and against any claim by any third\\n party arising out of or related
to your use or distribution of the Llama Materials.\\n\\n6. Term and Termination.
The term of this Agreement will commence upon your acceptance of this Agreement
or access\\nto the Llama Materials and will continue in full force and effect
until terminated in accordance with the terms\\nand conditions herein. Meta
may terminate this Agreement if you are in breach of any term or condition of
this\\nAgreement. Upon termination of this Agreement, you shall delete and cease
use of the Llama Materials. Sections 3,\\n4 and 7 shall survive the termination
of this Agreement. \\n\\n7. Governing Law and Jurisdiction. This Agreement will
be governed and construed under the laws of the State of \\nCalifornia without
regard to choice of law principles, and the UN Convention on Contracts for the
International\\nSale of Goods does not apply to this Agreement. The courts of
California shall have exclusive jurisdiction of\\nany dispute arising out of
this Agreement.\\\"\\nLICENSE \\\"**Llama 3.2** **Acceptable Use Policy**\\n\\nMeta
is committed to promoting safe and fair use of its tools and features, including
Llama 3.2. If you access or use Llama 3.2, you agree to this Acceptable Use
Policy (\u201C**Policy**\u201D). The most recent copy of this policy can be
found at [https://www.llama.com/llama3_2/use-policy](https://www.llama.com/llama3_2/use-policy).\\n\\n**Prohibited
Uses**\\n\\nWe want everyone to use Llama 3.2 safely and responsibly. You agree
you will not use, or allow others to use, Llama 3.2 to:\\n\\n\\n\\n1. Violate
the law or others\u2019 rights, including to:\\n 1. Engage in, promote, generate,
contribute to, encourage, plan, incite, or further illegal or unlawful activity
or content, such as:\\n 1. Violence or terrorism\\n 2. Exploitation
or harm to children, including the solicitation, creation, acquisition, or dissemination
of child exploitative content or failure to report Child Sexual Abuse Material\\n
\ 3. Human trafficking, exploitation, and sexual violence\\n 4.
The illegal distribution of information or materials to minors, including obscene
materials, or failure to employ legally required age-gating in connection with
such information or materials.\\n 5. Sexual solicitation\\n 6.
Any other criminal activity\\n 1. Engage in, promote, incite, or facilitate
the harassment, abuse, threatening, or bullying of individuals or groups of
individuals\\n 2. Engage in, promote, incite, or facilitate discrimination
or other unlawful or harmful conduct in the provision of employment, employment
benefits, credit, housing, other economic benefits, or other essential goods
and services\\n 3. Engage in the unauthorized or unlicensed practice of any
profession including, but not limited to, financial, legal, medical/health,
or related professional practices\\n 4. Collect, process, disclose, generate,
or infer private or sensitive information about individuals, including information
about individuals\u2019 identity, health, or demographic information, unless
you have obtained the right to do so in accordance with applicable law\\n 5.
Engage in or facilitate any action or generate any content that infringes, misappropriates,
or otherwise violates any third-party rights, including the outputs or results
of any products or services using the Llama Materials\\n 6. Create, generate,
or facilitate the creation of malicious code, malware, computer viruses or do
anything else that could disable, overburden, interfere with or impair the proper
working, integrity, operation or appearance of a website or computer system\\n
\ 7. Engage in any action, or facilitate any action, to intentionally circumvent
or remove usage restrictions or other safety measures, or to enable functionality
disabled by Meta\\n2. Engage in, promote, incite, facilitate, or assist in the
planning or development of activities that present a risk of death or bodily
harm to individuals, including use of Llama 3.2 related to the following:\\n
\ 8. Military, warfare, nuclear industries or applications, espionage, use
for materials or activities that are subject to the International Traffic Arms
Regulations (ITAR) maintained by the United States Department of State or to
the U.S. Biological Weapons Anti-Terrorism Act of 1989 or the Chemical Weapons
Convention Implementation Act of 1997\\n 9. Guns and illegal weapons (including
weapon development)\\n 10. Illegal drugs and regulated/controlled substances\\n
\ 11. Operation of critical infrastructure, transportation technologies, or
heavy machinery\\n 12. Self-harm or harm to others, including suicide, cutting,
and eating disorders\\n 13. Any content intended to incite or promote violence,
abuse, or any infliction of bodily harm to an individual\\n3. Intentionally
deceive or mislead others, including use of Llama 3.2 related to the following:\\n
\ 14. Generating, promoting, or furthering fraud or the creation or promotion
of disinformation\\n 15. Generating, promoting, or furthering defamatory
content, including the creation of defamatory statements, images, or other content\\n
\ 16. Generating, promoting, or further distributing spam\\n 17. Impersonating
another individual without consent, authorization, or legal right\\n 18.
Representing that the use of Llama 3.2 or outputs are human-generated\\n 19.
Generating or facilitating false online engagement, including fake reviews and
other means of fake online engagement\\n4. Fail to appropriately disclose to
end users any known dangers of your AI system\\n5. Interact with third party
tools, models, or software designed to generate unlawful content or engage in
unlawful or harmful conduct and/or represent that the outputs of such tools,
models, or software are associated with Meta or Llama 3.2\\n\\nWith respect
to any multimodal models included in Llama 3.2, the rights granted under Section
1(a) of the Llama 3.2 Community License Agreement are not being granted to you
if you are an individual domiciled in, or a company with a principal place of
business in, the European Union. This restriction does not apply to end users
of a product or service that incorporates any such multimodal models.\\n\\nPlease
report any violation of this Policy, software \u201Cbug,\u201D or other problems
that could lead to a violation of this Policy through one of the following means:\\n\\n\\n\\n*
Reporting issues with the model: [https://github.com/meta-llama/llama-models/issues](https://l.workplace.com/l.php?u=https%3A%2F%2Fgithub.com%2Fmeta-llama%2Fllama-models%2Fissues\\u0026h=AT0qV8W9BFT6NwihiOHRuKYQM_UnkzN_NmHMy91OT55gkLpgi4kQupHUl0ssR4dQsIQ8n3tfd0vtkobvsEvt1l4Ic6GXI2EeuHV8N08OG2WnbAmm0FL4ObkazC6G_256vN0lN9DsykCvCqGZ)\\n*
Reporting risky content generated by the model: [developers.facebook.com/llama_output_feedback](http://developers.facebook.com/llama_output_feedback)\\n*
Reporting bugs and security concerns: [facebook.com/whitehat/info](http://facebook.com/whitehat/info)\\n*
Reporting violations of the Acceptable Use Policy or unlicensed uses of Llama
3.2: LlamaUseReport@meta.com\\\"\\n\",\"parameters\":\"stop \\\"\\u003c|start_header_id|\\u003e\\\"\\nstop
\ \\\"\\u003c|end_header_id|\\u003e\\\"\\nstop \\\"\\u003c|eot_id|\\u003e\\\"\",\"template\":\"\\u003c|start_header_id|\\u003esystem\\u003c|end_header_id|\\u003e\\n\\nCutting
Knowledge Date: December 2023\\n\\n{{ if .System }}{{ .System }}\\n{{- end }}\\n{{-
if .Tools }}When you receive a tool call response, use the output to format
an answer to the orginal user question.\\n\\nYou are a helpful assistant with
tool calling capabilities.\\n{{- end }}\\u003c|eot_id|\\u003e\\n{{- range $i,
$_ := .Messages }}\\n{{- $last := eq (len (slice $.Messages $i)) 1 }}\\n{{-
if eq .Role \\\"user\\\" }}\\u003c|start_header_id|\\u003euser\\u003c|end_header_id|\\u003e\\n{{-
if and $.Tools $last }}\\n\\nGiven the following functions, please respond with
a JSON for a function call with its proper arguments that best answers the given
prompt.\\n\\nRespond in the format {\\\"name\\\": function name, \\\"parameters\\\":
dictionary of argument name and its value}. Do not use variables.\\n\\n{{ range
$.Tools }}\\n{{- . }}\\n{{ end }}\\n{{ .Content }}\\u003c|eot_id|\\u003e\\n{{-
else }}\\n\\n{{ .Content }}\\u003c|eot_id|\\u003e\\n{{- end }}{{ if $last }}\\u003c|start_header_id|\\u003eassistant\\u003c|end_header_id|\\u003e\\n\\n{{
end }}\\n{{- else if eq .Role \\\"assistant\\\" }}\\u003c|start_header_id|\\u003eassistant\\u003c|end_header_id|\\u003e\\n{{-
if .ToolCalls }}\\n{{ range .ToolCalls }}\\n{\\\"name\\\": \\\"{{ .Function.Name
}}\\\", \\\"parameters\\\": {{ .Function.Arguments }}}{{ end }}\\n{{- else }}\\n\\n{{
.Content }}\\n{{- end }}{{ if not $last }}\\u003c|eot_id|\\u003e{{ end }}\\n{{-
else if eq .Role \\\"tool\\\" }}\\u003c|start_header_id|\\u003eipython\\u003c|end_header_id|\\u003e\\n\\n{{
.Content }}\\u003c|eot_id|\\u003e{{ if $last }}\\u003c|start_header_id|\\u003eassistant\\u003c|end_header_id|\\u003e\\n\\n{{
end }}\\n{{- end }}\\n{{- end }}\",\"details\":{\"parent_model\":\"\",\"format\":\"gguf\",\"family\":\"llama\",\"families\":[\"llama\"],\"parameter_size\":\"3.2B\",\"quantization_level\":\"Q4_K_M\"},\"model_info\":{\"general.architecture\":\"llama\",\"general.basename\":\"Llama-3.2\",\"general.file_type\":15,\"general.finetune\":\"Instruct\",\"general.languages\":[\"en\",\"de\",\"fr\",\"it\",\"pt\",\"hi\",\"es\",\"th\"],\"general.parameter_count\":3212749888,\"general.quantization_version\":2,\"general.size_label\":\"3B\",\"general.tags\":[\"facebook\",\"meta\",\"pytorch\",\"llama\",\"llama-3\",\"text-generation\"],\"general.type\":\"model\",\"llama.attention.head_count\":24,\"llama.attention.head_count_kv\":8,\"llama.attention.key_length\":128,\"llama.attention.layer_norm_rms_epsilon\":0.00001,\"llama.attention.value_length\":128,\"llama.block_count\":28,\"llama.context_length\":131072,\"llama.embedding_length\":3072,\"llama.feed_forward_length\":8192,\"llama.rope.dimension_count\":128,\"llama.rope.freq_base\":500000,\"llama.vocab_size\":128256,\"tokenizer.ggml.bos_token_id\":128000,\"tokenizer.ggml.eos_token_id\":128009,\"tokenizer.ggml.merges\":null,\"tokenizer.ggml.model\":\"gpt2\",\"tokenizer.ggml.pre\":\"llama-bpe\",\"tokenizer.ggml.token_type\":null,\"tokenizer.ggml.tokens\":null},\"modified_at\":\"2025-02-20T18:55:09.150577031-08:00\"}"
headers:
Content-Type:
- application/json; charset=utf-8
Date:
- Fri, 21 Feb 2025 02:57:55 GMT
Transfer-Encoding:
- chunked
http_version: HTTP/1.1
status_code: 200
version: 1

View File

@@ -46,6 +46,7 @@ def test_evaluate_training_data(converter_mock):
converter_mock.assert_has_calls(
[
mock.call(
agent=original_agent, # Add agent argument
llm=original_agent.llm,
text="Assess the quality of the training data based on the llm output, human feedback , and llm "
"output improved result.\n\nIteration: data1\nInitial Output:\nInitial output 1\n\nHuman Feedback:\nHuman feedback "

View File

@@ -197,6 +197,101 @@ def test_convert_with_instructions_success(
assert output.age == 50
@patch("crewai.utilities.converter.get_conversion_instructions")
@patch("crewai.utilities.converter.create_converter")
def test_convert_with_instructions_respects_use_system_prompt_false(
mock_create_converter, mock_get_instructions, mock_agent
):
"""
Test that convert_with_instructions does not use a system prompt
when agent.use_system_prompt is False and the LLM doesn't support function calling.
"""
mock_agent.use_system_prompt = False
mock_llm = MagicMock()
mock_llm.supports_function_calling.return_value = False
mock_agent.llm = mock_llm
mock_agent.function_calling_llm = None # Ensure fallback to agent.llm
mock_get_instructions.return_value = "Test Instructions"
mock_converter_instance = MagicMock(spec=Converter)
mock_converter_instance.agent = mock_agent # Set the agent on the mock converter
mock_converter_instance.llm = mock_llm
mock_converter_instance.instructions = "Test Instructions"
mock_converter_instance.text = "Some text"
mock_converter_instance.model = SimpleModel
converter = Converter(
agent=mock_agent,
llm=mock_llm,
text="Some text",
model=SimpleModel,
instructions="Test Instructions",
)
mock_create_converter.return_value = (
converter # This instance will be used by convert_with_instructions
)
converter.llm.call = MagicMock(return_value='{"name": "Mock Name", "age": 99}')
convert_with_instructions("Some text", SimpleModel, False, mock_agent)
converter.llm.call.assert_called_once()
call_args = converter.llm.call.call_args[0][0] # Get the 'messages' list argument
assert not any(msg.get("role") == "system" for msg in call_args)
user_message = next((msg for msg in call_args if msg.get("role") == "user"), None)
assert user_message is not None
assert "Test Instructions" in user_message["content"]
assert "Some text" in user_message["content"]
assert user_message["content"].startswith("Test Instructions\n\n")
@patch("crewai.utilities.converter.get_conversion_instructions")
@patch("crewai.utilities.converter.create_converter")
def test_convert_with_instructions_respects_use_system_prompt_true(
mock_create_converter, mock_get_instructions, mock_agent
):
"""
Test that convert_with_instructions uses a system prompt
when agent.use_system_prompt is True and the LLM doesn't support function calling.
"""
mock_agent.use_system_prompt = True # Explicitly True
mock_llm = MagicMock()
mock_llm.supports_function_calling.return_value = False
mock_agent.llm = mock_llm
mock_agent.function_calling_llm = None
mock_get_instructions.return_value = "Test Instructions"
converter = Converter(
agent=mock_agent,
llm=mock_llm,
text="Some text",
model=SimpleModel,
instructions="Test Instructions",
)
mock_create_converter.return_value = (
converter # This instance will be used by convert_with_instructions
)
converter.llm.call = MagicMock(return_value='{"name": "Mock Name", "age": 99}')
convert_with_instructions("Some text", SimpleModel, False, mock_agent)
converter.llm.call.assert_called_once()
call_args = converter.llm.call.call_args[0][0]
system_message = next(
(msg for msg in call_args if msg.get("role") == "system"), None
)
assert system_message is not None
assert system_message["content"] == "Test Instructions"
user_message = next((msg for msg in call_args if msg.get("role") == "user"), None)
assert user_message is not None
assert user_message["content"] == "Some text"
@patch("crewai.utilities.converter.create_converter")
@patch("crewai.utilities.converter.get_conversion_instructions")
def test_convert_with_instructions_failure(
@@ -334,7 +429,10 @@ def test_convert_with_instructions():
sample_text = "Name: Alice, Age: 30"
instructions = get_conversion_instructions(SimpleModel, llm)
mock_agent = Mock() # Add mock agent if not available
mock_agent.use_system_prompt = True # Default or set as needed
converter = Converter(
agent=mock_agent, # Add agent argument
llm=llm,
text=sample_text,
model=SimpleModel,
@@ -362,7 +460,10 @@ def test_converter_with_llama3_2_model():
llm = LLM(model="ollama/llama3.2:3b", base_url="http://localhost:11434")
sample_text = "Name: Alice Llama, Age: 30"
instructions = get_conversion_instructions(SimpleModel, llm)
mock_agent = Mock() # Add mock agent if not available
mock_agent.use_system_prompt = True # Default or set as needed
converter = Converter(
agent=mock_agent, # Add agent argument
llm=llm,
text=sample_text,
model=SimpleModel,
@@ -380,7 +481,10 @@ def test_converter_with_llama3_1_model():
llm = LLM(model="ollama/llama3.1", base_url="http://localhost:11434")
sample_text = "Name: Alice Llama, Age: 30"
instructions = get_conversion_instructions(SimpleModel, llm)
mock_agent = Mock() # Add mock agent if not available
mock_agent.use_system_prompt = True # Default or set as needed
converter = Converter(
agent=mock_agent, # Add agent argument
llm=llm,
text=sample_text,
model=SimpleModel,
@@ -405,7 +509,11 @@ def test_converter_with_nested_model():
sample_text = "Name: John Doe\nAge: 30\nAddress: 123 Main St, Anytown, 12345"
instructions = get_conversion_instructions(Person, llm)
mock_agent = Mock()
mock_agent.use_system_prompt = True
converter = Converter(
agent=mock_agent,
llm=llm,
text=sample_text,
model=Person,
@@ -431,7 +539,10 @@ def test_converter_error_handling():
sample_text = "Name: Alice, Age: 30"
instructions = get_conversion_instructions(SimpleModel, llm)
mock_agent = Mock() # Add mock agent if not available
mock_agent.use_system_prompt = True # Default or set as needed
converter = Converter(
agent=mock_agent, # Add agent argument
llm=llm,
text=sample_text,
model=SimpleModel,
@@ -456,7 +567,11 @@ def test_converter_retry_logic():
sample_text = "Name: Retry Alice, Age: 30"
instructions = get_conversion_instructions(SimpleModel, llm)
mock_agent = Mock()
mock_agent.use_system_prompt = True
converter = Converter(
agent=mock_agent,
llm=llm,
text=sample_text,
model=SimpleModel,
@@ -485,7 +600,11 @@ def test_converter_with_optional_fields():
sample_text = "Name: Bob, age: None"
instructions = get_conversion_instructions(OptionalModel, llm)
mock_agent = Mock()
mock_agent.use_system_prompt = True
converter = Converter(
agent=mock_agent,
llm=llm,
text=sample_text,
model=OptionalModel,
@@ -510,7 +629,11 @@ def test_converter_with_list_field():
sample_text = "Items: 1, 2, 3"
instructions = get_conversion_instructions(ListModel, llm)
mock_agent = Mock()
mock_agent.use_system_prompt = True
converter = Converter(
agent=mock_agent,
llm=llm,
text=sample_text,
model=ListModel,
@@ -543,7 +666,11 @@ def test_converter_with_enum():
sample_text = "Name: Alice, Color: Red"
instructions = get_conversion_instructions(EnumModel, llm)
mock_agent = Mock()
mock_agent.use_system_prompt = True
converter = Converter(
agent=mock_agent,
llm=llm,
text=sample_text,
model=EnumModel,
@@ -565,7 +692,11 @@ def test_converter_with_ambiguous_input():
sample_text = "Charlie is thirty years old"
instructions = get_conversion_instructions(SimpleModel, llm)
mock_agent = Mock()
mock_agent.use_system_prompt = True
converter = Converter(
agent=mock_agent,
llm=llm,
text=sample_text,
model=SimpleModel,
@@ -586,7 +717,11 @@ def test_converter_with_function_calling():
instructor = Mock()
instructor.to_pydantic.return_value = SimpleModel(name="Eve", age=35)
mock_agent = Mock()
mock_agent.use_system_prompt = True
converter = Converter(
agent=mock_agent,
llm=llm,
text="Name: Eve, Age: 35",
model=SimpleModel,

View File

@@ -29,13 +29,14 @@ def mock_knowledge_source():
"""
return StringKnowledgeSource(content=content)
@patch('crewai.knowledge.storage.knowledge_storage.chromadb')
@patch("crewai.knowledge.storage.knowledge_storage.chromadb")
def test_knowledge_included_in_planning(mock_chroma):
"""Test that verifies knowledge sources are properly included in planning."""
# Mock ChromaDB collection
mock_collection = mock_chroma.return_value.get_or_create_collection.return_value
mock_collection.add.return_value = None
# Create an agent with knowledge
agent = Agent(
role="AI Researcher",
@@ -45,14 +46,14 @@ def test_knowledge_included_in_planning(mock_chroma):
StringKnowledgeSource(
content="AI systems require careful training and validation."
)
]
],
)
# Create a task for the agent
task = Task(
description="Explain the basics of AI systems",
expected_output="A clear explanation of AI fundamentals",
agent=agent
agent=agent,
)
# Create a crew planner
@@ -62,23 +63,29 @@ def test_knowledge_included_in_planning(mock_chroma):
task_summary = planner._create_tasks_summary()
# Verify that knowledge is included in planning when present
assert "AI systems require careful training" in task_summary, \
"Knowledge content should be present in task summary when knowledge exists"
assert '"agent_knowledge"' in task_summary, \
"agent_knowledge field should be present in task summary when knowledge exists"
assert (
"AI systems require careful training" in task_summary
), "Knowledge content should be present in task summary when knowledge exists"
assert (
'"agent_knowledge"' in task_summary
), "agent_knowledge field should be present in task summary when knowledge exists"
# Verify that knowledge is properly formatted
assert isinstance(task.agent.knowledge_sources, list), \
"Knowledge sources should be stored in a list"
assert len(task.agent.knowledge_sources) > 0, \
"At least one knowledge source should be present"
assert task.agent.knowledge_sources[0].content in task_summary, \
"Knowledge source content should be included in task summary"
assert isinstance(
task.agent.knowledge_sources, list
), "Knowledge sources should be stored in a list"
assert (
len(task.agent.knowledge_sources) > 0
), "At least one knowledge source should be present"
assert (
task.agent.knowledge_sources[0].content in task_summary
), "Knowledge source content should be included in task summary"
# Verify that other expected components are still present
assert task.description in task_summary, \
"Task description should be present in task summary"
assert task.expected_output in task_summary, \
"Expected output should be present in task summary"
assert agent.role in task_summary, \
"Agent role should be present in task summary"
assert (
task.description in task_summary
), "Task description should be present in task summary"
assert (
task.expected_output in task_summary
), "Expected output should be present in task summary"
assert agent.role in task_summary, "Agent role should be present in task summary"

View File

@@ -100,7 +100,7 @@ class InternalCrewPlanner:
# Knowledge field should not be present when empty
assert '"agent_knowledge"' not in tasks_summary
@patch('crewai.knowledge.storage.knowledge_storage.chromadb')
@patch("crewai.knowledge.storage.knowledge_storage.chromadb")
def test_create_tasks_summary_with_knowledge_and_tools(self, mock_chroma):
"""Test task summary generation with both knowledge and tools present."""
# Mock ChromaDB collection
@@ -146,8 +146,8 @@ class InternalCrewPlanner:
tools=[tool1, tool2],
knowledge_sources=[
StringKnowledgeSource(content="Test knowledge content")
]
)
],
),
)
# Create planner with the new task