mirror of
https://github.com/crewAIInc/crewAI.git
synced 2025-12-17 12:58:31 +00:00
Compare commits
4 Commits
lg-memory-
...
memory_pat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50508297c9 | ||
|
|
58b2ba4d90 | ||
|
|
4274cde583 | ||
|
|
12245d66a7 |
@@ -294,14 +294,7 @@ class Agent(BaseAgent):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if self.crew and self.crew.memory:
|
if self.crew and self.crew.memory:
|
||||||
contextual_memory = ContextualMemory(
|
memory = self.crew.contextual_memory.build_context_for_task(task, context)
|
||||||
self.crew.memory_config,
|
|
||||||
self.crew._short_term_memory,
|
|
||||||
self.crew._long_term_memory,
|
|
||||||
self.crew._entity_memory,
|
|
||||||
self.crew._user_memory,
|
|
||||||
)
|
|
||||||
memory = contextual_memory.build_context_for_task(task, context)
|
|
||||||
if memory.strip() != "":
|
if memory.strip() != "":
|
||||||
task_prompt += self.i18n.slice("memory").format(memory=memory)
|
task_prompt += self.i18n.slice("memory").format(memory=memory)
|
||||||
|
|
||||||
|
|||||||
@@ -358,9 +358,9 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
if self.crew is not None and hasattr(self.crew, "_train_iteration"):
|
if self.crew is not None and hasattr(self.crew, "_train_iteration"):
|
||||||
train_iteration = self.crew._train_iteration
|
train_iteration = self.crew._train_iteration
|
||||||
if agent_id in training_data and isinstance(train_iteration, int):
|
if agent_id in training_data and isinstance(train_iteration, int):
|
||||||
training_data[agent_id][train_iteration][
|
training_data[agent_id][train_iteration]["improved_output"] = (
|
||||||
"improved_output"
|
result.output
|
||||||
] = result.output
|
)
|
||||||
training_handler.save(training_data)
|
training_handler.save(training_data)
|
||||||
else:
|
else:
|
||||||
self._printer.print(
|
self._printer.print(
|
||||||
|
|||||||
@@ -153,8 +153,12 @@ class ToolCommand(BaseCommand, PlusAPIMixin):
|
|||||||
login_response_json = login_response.json()
|
login_response_json = login_response.json()
|
||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
settings.tool_repository_username = login_response_json["credential"]["username"]
|
settings.tool_repository_username = login_response_json["credential"][
|
||||||
settings.tool_repository_password = login_response_json["credential"]["password"]
|
"username"
|
||||||
|
]
|
||||||
|
settings.tool_repository_password = login_response_json["credential"][
|
||||||
|
"password"
|
||||||
|
]
|
||||||
settings.dump()
|
settings.dump()
|
||||||
|
|
||||||
console.print(
|
console.print(
|
||||||
@@ -179,7 +183,7 @@ class ToolCommand(BaseCommand, PlusAPIMixin):
|
|||||||
capture_output=False,
|
capture_output=False,
|
||||||
env=self._build_env_with_credentials(repository_handle),
|
env=self._build_env_with_credentials(repository_handle),
|
||||||
text=True,
|
text=True,
|
||||||
check=True
|
check=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
if add_package_result.stderr:
|
if add_package_result.stderr:
|
||||||
@@ -204,7 +208,11 @@ class ToolCommand(BaseCommand, PlusAPIMixin):
|
|||||||
settings = Settings()
|
settings = Settings()
|
||||||
|
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env[f"UV_INDEX_{repository_handle}_USERNAME"] = str(settings.tool_repository_username or "")
|
env[f"UV_INDEX_{repository_handle}_USERNAME"] = str(
|
||||||
env[f"UV_INDEX_{repository_handle}_PASSWORD"] = str(settings.tool_repository_password or "")
|
settings.tool_repository_username or ""
|
||||||
|
)
|
||||||
|
env[f"UV_INDEX_{repository_handle}_PASSWORD"] = str(
|
||||||
|
settings.tool_repository_password or ""
|
||||||
|
)
|
||||||
|
|
||||||
return env
|
return env
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from crewai.crews.crew_output import CrewOutput
|
|||||||
from crewai.knowledge.knowledge import Knowledge
|
from crewai.knowledge.knowledge import Knowledge
|
||||||
from crewai.knowledge.source.base_knowledge_source import BaseKnowledgeSource
|
from crewai.knowledge.source.base_knowledge_source import BaseKnowledgeSource
|
||||||
from crewai.llm import LLM
|
from crewai.llm import LLM
|
||||||
|
from crewai.memory.contextual.contextual_memory import ContextualMemory
|
||||||
from crewai.memory.entity.entity_memory import EntityMemory
|
from crewai.memory.entity.entity_memory import EntityMemory
|
||||||
from crewai.memory.long_term.long_term_memory import LongTermMemory
|
from crewai.memory.long_term.long_term_memory import LongTermMemory
|
||||||
from crewai.memory.short_term.short_term_memory import ShortTermMemory
|
from crewai.memory.short_term.short_term_memory import ShortTermMemory
|
||||||
@@ -278,6 +279,13 @@ class Crew(BaseModel):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._user_memory = None
|
self._user_memory = None
|
||||||
|
self.contextual_memory = ContextualMemory(
|
||||||
|
memory_config=self.memory_config,
|
||||||
|
stm=self._short_term_memory,
|
||||||
|
ltm=self._long_term_memory,
|
||||||
|
em=self._entity_memory,
|
||||||
|
um=self._user_memory,
|
||||||
|
)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
from crewai.task import Task
|
||||||
|
|
||||||
from crewai.memory import EntityMemory, LongTermMemory, ShortTermMemory, UserMemory
|
from crewai.memory import EntityMemory, LongTermMemory, ShortTermMemory, UserMemory
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ class ContextualMemory:
|
|||||||
stm: ShortTermMemory,
|
stm: ShortTermMemory,
|
||||||
ltm: LongTermMemory,
|
ltm: LongTermMemory,
|
||||||
em: EntityMemory,
|
em: EntityMemory,
|
||||||
um: UserMemory,
|
um: Optional[UserMemory],
|
||||||
):
|
):
|
||||||
if memory_config is not None:
|
if memory_config is not None:
|
||||||
self.memory_provider = memory_config.get("provider")
|
self.memory_provider = memory_config.get("provider")
|
||||||
@@ -21,7 +22,7 @@ class ContextualMemory:
|
|||||||
self.em = em
|
self.em = em
|
||||||
self.um = um
|
self.um = um
|
||||||
|
|
||||||
def build_context_for_task(self, task, context) -> str:
|
def build_context_for_task(self, task: Task, context: str) -> str:
|
||||||
"""
|
"""
|
||||||
Automatically builds a minimal, highly relevant set of contextual information
|
Automatically builds a minimal, highly relevant set of contextual information
|
||||||
for a given task.
|
for a given task.
|
||||||
@@ -39,7 +40,7 @@ class ContextualMemory:
|
|||||||
context.append(self._fetch_user_context(query))
|
context.append(self._fetch_user_context(query))
|
||||||
return "\n".join(filter(None, context))
|
return "\n".join(filter(None, context))
|
||||||
|
|
||||||
def _fetch_stm_context(self, query) -> str:
|
def _fetch_stm_context(self, query: str) -> str:
|
||||||
"""
|
"""
|
||||||
Fetches recent relevant insights from STM related to the task's description and expected_output,
|
Fetches recent relevant insights from STM related to the task's description and expected_output,
|
||||||
formatted as bullet points.
|
formatted as bullet points.
|
||||||
@@ -53,7 +54,7 @@ class ContextualMemory:
|
|||||||
)
|
)
|
||||||
return f"Recent Insights:\n{formatted_results}" if stm_results else ""
|
return f"Recent Insights:\n{formatted_results}" if stm_results else ""
|
||||||
|
|
||||||
def _fetch_ltm_context(self, task) -> Optional[str]:
|
def _fetch_ltm_context(self, task: str) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Fetches historical data or insights from LTM that are relevant to the task's description and expected_output,
|
Fetches historical data or insights from LTM that are relevant to the task's description and expected_output,
|
||||||
formatted as bullet points.
|
formatted as bullet points.
|
||||||
@@ -72,7 +73,7 @@ class ContextualMemory:
|
|||||||
|
|
||||||
return f"Historical Data:\n{formatted_results}" if ltm_results else ""
|
return f"Historical Data:\n{formatted_results}" if ltm_results else ""
|
||||||
|
|
||||||
def _fetch_entity_context(self, query) -> str:
|
def _fetch_entity_context(self, query: str) -> str:
|
||||||
"""
|
"""
|
||||||
Fetches relevant entity information from Entity Memory related to the task's description and expected_output,
|
Fetches relevant entity information from Entity Memory related to the task's description and expected_output,
|
||||||
formatted as bullet points.
|
formatted as bullet points.
|
||||||
@@ -94,6 +95,8 @@ class ContextualMemory:
|
|||||||
Returns:
|
Returns:
|
||||||
str: Formatted user memories as bullet points, or an empty string if none found.
|
str: Formatted user memories as bullet points, or an empty string if none found.
|
||||||
"""
|
"""
|
||||||
|
if not self.um:
|
||||||
|
return ""
|
||||||
user_memories = self.um.search(query)
|
user_memories = self.um.search(query)
|
||||||
if not user_memories:
|
if not user_memories:
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class EntityMemory(Memory):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, crew=None, embedder_config=None, storage=None, path=None):
|
def __init__(self, crew=None, embedder_config=None, storage=None, path=None):
|
||||||
if hasattr(crew, "memory_config") and crew.memory_config is not None:
|
if crew and hasattr(crew, "memory_config") and crew.memory_config is not None:
|
||||||
self.memory_provider = crew.memory_config.get("provider")
|
self.memory_provider = crew.memory_config.get("provider")
|
||||||
else:
|
else:
|
||||||
self.memory_provider = None
|
self.memory_provider = None
|
||||||
|
|||||||
@@ -15,8 +15,17 @@ class LongTermMemory(Memory):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, storage=None, path=None):
|
def __init__(self, storage=None, path=None):
|
||||||
|
"""Initialize long term memory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
storage: Optional custom storage instance
|
||||||
|
path: Optional custom path for storage location
|
||||||
|
|
||||||
|
Note:
|
||||||
|
If both storage and path are provided, storage takes precedence
|
||||||
|
"""
|
||||||
if not storage:
|
if not storage:
|
||||||
storage = LTMSQLiteStorage(db_path=path) if path else LTMSQLiteStorage()
|
storage = LTMSQLiteStorage(storage_path=path) if path else LTMSQLiteStorage()
|
||||||
super().__init__(storage)
|
super().__init__(storage)
|
||||||
|
|
||||||
def save(self, item: LongTermMemoryItem) -> None: # type: ignore # BUG?: Signature of "save" incompatible with supertype "Memory"
|
def save(self, item: LongTermMemoryItem) -> None: # type: ignore # BUG?: Signature of "save" incompatible with supertype "Memory"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class ShortTermMemory(Memory):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, crew=None, embedder_config=None, storage=None, path=None):
|
def __init__(self, crew=None, embedder_config=None, storage=None, path=None):
|
||||||
if hasattr(crew, "memory_config") and crew.memory_config is not None:
|
if crew and hasattr(crew, "memory_config") and crew.memory_config is not None:
|
||||||
self.memory_provider = crew.memory_config.get("provider")
|
self.memory_provider = crew.memory_config.get("provider")
|
||||||
else:
|
else:
|
||||||
self.memory_provider = None
|
self.memory_provider = None
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import Any, Dict, List, Optional
|
from pathlib import Path
|
||||||
|
import os
|
||||||
|
from typing import Any, Dict, List, Optional, TypeVar
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from crewai.utilities.paths import get_default_storage_path
|
||||||
|
|
||||||
|
|
||||||
class BaseRAGStorage(ABC):
|
class BaseRAGStorage(ABC):
|
||||||
@@ -12,17 +18,46 @@ class BaseRAGStorage(ABC):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
type: str,
|
type: str,
|
||||||
|
storage_path: Optional[Path] = None,
|
||||||
allow_reset: bool = True,
|
allow_reset: bool = True,
|
||||||
embedder_config: Optional[Any] = None,
|
embedder_config: Optional[Any] = None,
|
||||||
crew: Any = None,
|
crew: Any = None,
|
||||||
):
|
) -> None:
|
||||||
|
"""Initialize the BaseRAGStorage.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
type: Type of storage being used
|
||||||
|
storage_path: Optional custom path for storage location
|
||||||
|
allow_reset: Whether storage can be reset
|
||||||
|
embedder_config: Optional configuration for the embedder
|
||||||
|
crew: Optional crew instance this storage belongs to
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PermissionError: If storage path is not writable
|
||||||
|
OSError: If storage path cannot be created
|
||||||
|
"""
|
||||||
self.type = type
|
self.type = type
|
||||||
|
self.storage_path = storage_path if storage_path else get_default_storage_path('rag')
|
||||||
|
|
||||||
|
# Validate storage path
|
||||||
|
try:
|
||||||
|
self.storage_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
if not os.access(self.storage_path.parent, os.W_OK):
|
||||||
|
raise PermissionError(f"No write permission for storage path: {self.storage_path}")
|
||||||
|
except OSError as e:
|
||||||
|
raise OSError(f"Failed to initialize storage path: {str(e)}")
|
||||||
|
|
||||||
self.allow_reset = allow_reset
|
self.allow_reset = allow_reset
|
||||||
self.embedder_config = embedder_config
|
self.embedder_config = embedder_config
|
||||||
self.crew = crew
|
self.crew = crew
|
||||||
self.agents = self._initialize_agents()
|
self.agents = self._initialize_agents()
|
||||||
|
|
||||||
def _initialize_agents(self) -> str:
|
def _initialize_agents(self) -> str:
|
||||||
|
"""Initialize agent identifiers for storage.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Underscore-joined string of sanitized agent role names
|
||||||
|
"""
|
||||||
if self.crew:
|
if self.crew:
|
||||||
return "_".join(
|
return "_".join(
|
||||||
[self._sanitize_role(agent.role) for agent in self.crew.agents]
|
[self._sanitize_role(agent.role) for agent in self.crew.agents]
|
||||||
@@ -31,12 +66,27 @@ class BaseRAGStorage(ABC):
|
|||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _sanitize_role(self, role: str) -> str:
|
def _sanitize_role(self, role: str) -> str:
|
||||||
"""Sanitizes agent roles to ensure valid directory names."""
|
"""Sanitizes agent roles to ensure valid directory names.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
role: The agent role name to sanitize
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Sanitized role name safe for use in paths
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def save(self, value: Any, metadata: Dict[str, Any]) -> None:
|
def save(self, value: Any, metadata: Dict[str, Any]) -> None:
|
||||||
"""Save a value with metadata to the storage."""
|
"""Save a value with metadata to the storage.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The value to store
|
||||||
|
metadata: Additional metadata to store with the value
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
OSError: If there is an error writing to storage
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -46,25 +96,55 @@ class BaseRAGStorage(ABC):
|
|||||||
limit: int = 3,
|
limit: int = 3,
|
||||||
filter: Optional[dict] = None,
|
filter: Optional[dict] = None,
|
||||||
score_threshold: float = 0.35,
|
score_threshold: float = 0.35,
|
||||||
) -> List[Any]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""Search for entries in the storage."""
|
"""Search for entries in the storage.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: The search query string
|
||||||
|
limit: Maximum number of results to return
|
||||||
|
filter: Optional filter criteria
|
||||||
|
score_threshold: Minimum similarity score threshold
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Dict[str, Any]]: List of matching entries with their metadata
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def reset(self) -> None:
|
def reset(self) -> None:
|
||||||
"""Reset the storage."""
|
"""Reset the storage.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
OSError: If there is an error clearing storage
|
||||||
|
PermissionError: If reset is not allowed
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _generate_embedding(
|
def _generate_embedding(
|
||||||
self, text: str, metadata: Optional[Dict[str, Any]] = None
|
self, text: str, metadata: Optional[Dict[str, Any]] = None
|
||||||
) -> Any:
|
) -> List[float]:
|
||||||
"""Generate an embedding for the given text and metadata."""
|
"""Generate an embedding for the given text and metadata.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: Text to generate embedding for
|
||||||
|
metadata: Optional metadata to include in embedding
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[float]: Vector embedding of the text
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If text is empty or invalid
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _initialize_app(self):
|
def _initialize_app(self) -> None:
|
||||||
"""Initialize the vector db."""
|
"""Initialize the vector db.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
OSError: If vector db initialization fails
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def setup_config(self, config: Dict[str, Any]):
|
def setup_config(self, config: Dict[str, Any]):
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from crewai.task import Task
|
from crewai.task import Task
|
||||||
from crewai.utilities import Printer
|
from crewai.utilities import Printer
|
||||||
from crewai.utilities.crew_json_encoder import CrewJSONEncoder
|
from crewai.utilities.crew_json_encoder import CrewJSONEncoder
|
||||||
from crewai.utilities.paths import db_storage_path
|
from crewai.utilities.paths import get_default_storage_path
|
||||||
|
|
||||||
|
|
||||||
class KickoffTaskOutputsSQLiteStorage:
|
class KickoffTaskOutputsSQLiteStorage:
|
||||||
@@ -13,10 +15,26 @@ class KickoffTaskOutputsSQLiteStorage:
|
|||||||
An updated SQLite storage class for kickoff task outputs storage.
|
An updated SQLite storage class for kickoff task outputs storage.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, storage_path: Optional[Path] = None) -> None:
|
||||||
self, db_path: str = f"{db_storage_path()}/latest_kickoff_task_outputs.db"
|
"""Initialize kickoff task outputs storage.
|
||||||
) -> None:
|
|
||||||
self.db_path = db_path
|
Args:
|
||||||
|
storage_path: Optional custom path for storage location
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PermissionError: If storage path is not writable
|
||||||
|
OSError: If storage path cannot be created
|
||||||
|
"""
|
||||||
|
self.storage_path = storage_path if storage_path else get_default_storage_path('kickoff')
|
||||||
|
|
||||||
|
# Validate storage path
|
||||||
|
try:
|
||||||
|
self.storage_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
if not os.access(self.storage_path.parent, os.W_OK):
|
||||||
|
raise PermissionError(f"No write permission for storage path: {self.storage_path}")
|
||||||
|
except OSError as e:
|
||||||
|
raise OSError(f"Failed to initialize storage path: {str(e)}")
|
||||||
|
|
||||||
self._printer: Printer = Printer()
|
self._printer: Printer = Printer()
|
||||||
self._initialize_db()
|
self._initialize_db()
|
||||||
|
|
||||||
@@ -25,7 +43,7 @@ class KickoffTaskOutputsSQLiteStorage:
|
|||||||
Initializes the SQLite database and creates LTM table
|
Initializes the SQLite database and creates LTM table
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
with sqlite3.connect(str(self.storage_path)) as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
@@ -55,9 +73,21 @@ class KickoffTaskOutputsSQLiteStorage:
|
|||||||
task_index: int,
|
task_index: int,
|
||||||
was_replayed: bool = False,
|
was_replayed: bool = False,
|
||||||
inputs: Dict[str, Any] = {},
|
inputs: Dict[str, Any] = {},
|
||||||
):
|
) -> None:
|
||||||
|
"""Add a task output to storage.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
task: The task whose output is being stored
|
||||||
|
output: The output data from the task
|
||||||
|
task_index: Index of this task in the sequence
|
||||||
|
was_replayed: Whether this was from a replay
|
||||||
|
inputs: Optional input data that led to this output
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
sqlite3.Error: If there is an error saving to database
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
with sqlite3.connect(str(self.storage_path)) as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
@@ -90,7 +120,7 @@ class KickoffTaskOutputsSQLiteStorage:
|
|||||||
Updates an existing row in the latest_kickoff_task_outputs table based on task_index.
|
Updates an existing row in the latest_kickoff_task_outputs table based on task_index.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
with sqlite3.connect(str(self.storage_path)) as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
fields = []
|
fields = []
|
||||||
@@ -119,7 +149,7 @@ class KickoffTaskOutputsSQLiteStorage:
|
|||||||
|
|
||||||
def load(self) -> Optional[List[Dict[str, Any]]]:
|
def load(self) -> Optional[List[Dict[str, Any]]]:
|
||||||
try:
|
try:
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
with sqlite3.connect(str(self.storage_path)) as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
SELECT *
|
SELECT *
|
||||||
@@ -155,7 +185,7 @@ class KickoffTaskOutputsSQLiteStorage:
|
|||||||
Deletes all rows from the latest_kickoff_task_outputs table.
|
Deletes all rows from the latest_kickoff_task_outputs table.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
with sqlite3.connect(str(self.storage_path)) as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("DELETE FROM latest_kickoff_task_outputs")
|
cursor.execute("DELETE FROM latest_kickoff_task_outputs")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional, Union
|
from typing import Any, Dict, List, Optional, Union
|
||||||
|
|
||||||
from crewai.utilities import Printer
|
from crewai.utilities import Printer
|
||||||
from crewai.utilities.paths import db_storage_path
|
from crewai.utilities.paths import get_default_storage_path
|
||||||
|
|
||||||
|
|
||||||
class LTMSQLiteStorage:
|
class LTMSQLiteStorage:
|
||||||
@@ -11,10 +13,26 @@ class LTMSQLiteStorage:
|
|||||||
An updated SQLite storage class for LTM data storage.
|
An updated SQLite storage class for LTM data storage.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, storage_path: Optional[Path] = None) -> None:
|
||||||
self, db_path: str = f"{db_storage_path()}/long_term_memory_storage.db"
|
"""Initialize LTM SQLite storage.
|
||||||
) -> None:
|
|
||||||
self.db_path = db_path
|
Args:
|
||||||
|
storage_path: Optional custom path for storage location
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PermissionError: If storage path is not writable
|
||||||
|
OSError: If storage path cannot be created
|
||||||
|
"""
|
||||||
|
self.storage_path = storage_path if storage_path else get_default_storage_path('ltm')
|
||||||
|
|
||||||
|
# Validate storage path
|
||||||
|
try:
|
||||||
|
self.storage_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
if not os.access(self.storage_path.parent, os.W_OK):
|
||||||
|
raise PermissionError(f"No write permission for storage path: {self.storage_path}")
|
||||||
|
except OSError as e:
|
||||||
|
raise OSError(f"Failed to initialize storage path: {str(e)}")
|
||||||
|
|
||||||
self._printer: Printer = Printer()
|
self._printer: Printer = Printer()
|
||||||
self._initialize_db()
|
self._initialize_db()
|
||||||
|
|
||||||
@@ -23,7 +41,7 @@ class LTMSQLiteStorage:
|
|||||||
Initializes the SQLite database and creates LTM table
|
Initializes the SQLite database and creates LTM table
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
with sqlite3.connect(str(self.storage_path)) as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
@@ -51,9 +69,20 @@ class LTMSQLiteStorage:
|
|||||||
datetime: str,
|
datetime: str,
|
||||||
score: Union[int, float],
|
score: Union[int, float],
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""Save a memory entry to long-term memory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
task_description: Description of the task this memory relates to
|
||||||
|
metadata: Additional data to store with the memory
|
||||||
|
datetime: Timestamp for when this memory was created
|
||||||
|
score: Relevance score for this memory (higher is more relevant)
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
sqlite3.Error: If there is an error saving to the database
|
||||||
|
"""
|
||||||
"""Saves data to the LTM table with error handling."""
|
"""Saves data to the LTM table with error handling."""
|
||||||
try:
|
try:
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
with sqlite3.connect(str(self.storage_path)) as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
@@ -74,7 +103,7 @@ class LTMSQLiteStorage:
|
|||||||
) -> Optional[List[Dict[str, Any]]]:
|
) -> Optional[List[Dict[str, Any]]]:
|
||||||
"""Queries the LTM table by task description with error handling."""
|
"""Queries the LTM table by task description with error handling."""
|
||||||
try:
|
try:
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
with sqlite3.connect(str(self.storage_path)) as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
f"""
|
f"""
|
||||||
@@ -109,7 +138,7 @@ class LTMSQLiteStorage:
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Resets the LTM table with error handling."""
|
"""Resets the LTM table with error handling."""
|
||||||
try:
|
try:
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
with sqlite3.connect(str(self.storage_path)) as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("DELETE FROM long_term_memories")
|
cursor.execute("DELETE FROM long_term_memories")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Mem0Storage(Storage):
|
|||||||
|
|
||||||
self.memory_type = type
|
self.memory_type = type
|
||||||
self.crew = crew
|
self.crew = crew
|
||||||
self.memory_config = crew.memory_config
|
self.memory_config = crew.memory_config if crew else None
|
||||||
|
|
||||||
# User ID is required for user memory type "user" since it's used as a unique identifier for the user.
|
# User ID is required for user memory type "user" since it's used as a unique identifier for the user.
|
||||||
user_id = self._get_user_id()
|
user_id = self._get_user_id()
|
||||||
@@ -27,9 +27,10 @@ class Mem0Storage(Storage):
|
|||||||
raise ValueError("User ID is required for user memory type")
|
raise ValueError("User ID is required for user memory type")
|
||||||
|
|
||||||
# API key in memory config overrides the environment variable
|
# API key in memory config overrides the environment variable
|
||||||
mem0_api_key = self.memory_config.get("config", {}).get("api_key") or os.getenv(
|
if self.memory_config and self.memory_config.get("config"):
|
||||||
"MEM0_API_KEY"
|
mem0_api_key = self.memory_config.get("config").get("api_key")
|
||||||
)
|
else:
|
||||||
|
mem0_api_key = os.getenv("MEM0_API_KEY")
|
||||||
self.memory = MemoryClient(api_key=mem0_api_key)
|
self.memory = MemoryClient(api_key=mem0_api_key)
|
||||||
|
|
||||||
def _sanitize_role(self, role: str) -> str:
|
def _sanitize_role(self, role: str) -> str:
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ from chromadb.api import ClientAPI
|
|||||||
from crewai.memory.storage.base_rag_storage import BaseRAGStorage
|
from crewai.memory.storage.base_rag_storage import BaseRAGStorage
|
||||||
from crewai.utilities import EmbeddingConfigurator
|
from crewai.utilities import EmbeddingConfigurator
|
||||||
from crewai.utilities.constants import MAX_FILE_NAME_LENGTH
|
from crewai.utilities.constants import MAX_FILE_NAME_LENGTH
|
||||||
from crewai.utilities.paths import db_storage_path
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
@@ -40,9 +39,15 @@ class RAGStorage(BaseRAGStorage):
|
|||||||
app: ClientAPI | None = None
|
app: ClientAPI | None = None
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, type, allow_reset=True, embedder_config=None, crew=None, path=None
|
self,
|
||||||
|
type,
|
||||||
|
storage_path=None,
|
||||||
|
allow_reset=True,
|
||||||
|
embedder_config=None,
|
||||||
|
crew=None,
|
||||||
|
path=None,
|
||||||
):
|
):
|
||||||
super().__init__(type, allow_reset, embedder_config, crew)
|
super().__init__(type, storage_path, allow_reset, embedder_config, crew)
|
||||||
agents = crew.agents if crew else []
|
agents = crew.agents if crew else []
|
||||||
agents = [self._sanitize_role(agent.role) for agent in agents]
|
agents = [self._sanitize_role(agent.role) for agent in agents]
|
||||||
agents = "_".join(agents)
|
agents = "_".join(agents)
|
||||||
@@ -90,7 +95,7 @@ class RAGStorage(BaseRAGStorage):
|
|||||||
"""
|
"""
|
||||||
Ensures file name does not exceed max allowed by OS
|
Ensures file name does not exceed max allowed by OS
|
||||||
"""
|
"""
|
||||||
base_path = f"{db_storage_path()}/{type}"
|
base_path = f"{self.storage_path}/{type}"
|
||||||
|
|
||||||
if len(file_name) > MAX_FILE_NAME_LENGTH:
|
if len(file_name) > MAX_FILE_NAME_LENGTH:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
@@ -152,7 +157,7 @@ class RAGStorage(BaseRAGStorage):
|
|||||||
try:
|
try:
|
||||||
if self.app:
|
if self.app:
|
||||||
self.app.reset()
|
self.app.reset()
|
||||||
shutil.rmtree(f"{db_storage_path()}/{self.type}")
|
shutil.rmtree(f"{self.storage_path}/{self.type}")
|
||||||
self.app = None
|
self.app = None
|
||||||
self.collection = None
|
self.collection = None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ def cache_handler(func):
|
|||||||
|
|
||||||
|
|
||||||
def crew(func) -> Callable[..., Crew]:
|
def crew(func) -> Callable[..., Crew]:
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper(self, *args, **kwargs) -> Crew:
|
def wrapper(self, *args, **kwargs) -> Crew:
|
||||||
instantiated_tasks = []
|
instantiated_tasks = []
|
||||||
|
|||||||
@@ -216,5 +216,5 @@ def CrewBase(cls: T) -> T:
|
|||||||
# Include base class (qual)name in the wrapper class (qual)name.
|
# Include base class (qual)name in the wrapper class (qual)name.
|
||||||
WrappedClass.__name__ = CrewBase.__name__ + "(" + cls.__name__ + ")"
|
WrappedClass.__name__ = CrewBase.__name__ + "(" + cls.__name__ + ")"
|
||||||
WrappedClass.__qualname__ = CrewBase.__qualname__ + "(" + cls.__name__ + ")"
|
WrappedClass.__qualname__ = CrewBase.__qualname__ + "(" + cls.__name__ + ")"
|
||||||
|
|
||||||
return cast(T, WrappedClass)
|
return cast(T, WrappedClass)
|
||||||
|
|||||||
@@ -373,7 +373,9 @@ class Task(BaseModel):
|
|||||||
content = (
|
content = (
|
||||||
json_output
|
json_output
|
||||||
if json_output
|
if json_output
|
||||||
else pydantic_output.model_dump_json() if pydantic_output else result
|
else pydantic_output.model_dump_json()
|
||||||
|
if pydantic_output
|
||||||
|
else result
|
||||||
)
|
)
|
||||||
self._save_file(content)
|
self._save_file(content)
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class EmbeddingConfigurator:
|
|||||||
if embedder_config is None:
|
if embedder_config is None:
|
||||||
return self._create_default_embedding_function()
|
return self._create_default_embedding_function()
|
||||||
|
|
||||||
provider = embedder_config.get("provider")
|
provider = embedder_config.get("provider", "")
|
||||||
config = embedder_config.get("config", {})
|
config = embedder_config.get("config", {})
|
||||||
model_name = config.get("model")
|
model_name = config.get("model")
|
||||||
|
|
||||||
@@ -38,12 +38,13 @@ class EmbeddingConfigurator:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ValueError(f"Invalid custom embedding function: {str(e)}")
|
raise ValueError(f"Invalid custom embedding function: {str(e)}")
|
||||||
|
|
||||||
if provider not in self.embedding_functions:
|
embedding_function = self.embedding_functions.get(provider, None)
|
||||||
|
if not embedding_function:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f"Unsupported embedding provider: {provider}, supported providers: {list(self.embedding_functions.keys())}"
|
f"Unsupported embedding provider: {provider}, supported providers: {list(self.embedding_functions.keys())}"
|
||||||
)
|
)
|
||||||
|
|
||||||
return self.embedding_functions[provider](config, model_name)
|
return embedding_function(config, model_name)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _create_default_embedding_function():
|
def _create_default_embedding_function():
|
||||||
|
|||||||
@@ -22,3 +22,26 @@ def get_project_directory_name():
|
|||||||
cwd = Path.cwd()
|
cwd = Path.cwd()
|
||||||
project_directory_name = cwd.name
|
project_directory_name = cwd.name
|
||||||
return project_directory_name
|
return project_directory_name
|
||||||
|
|
||||||
|
def get_default_storage_path(storage_type: str) -> Path:
|
||||||
|
"""Returns the default storage path for a given storage type.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
storage_type: Type of storage ('ltm', 'kickoff', 'rag')
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path: Default storage path for the specified type
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If storage_type is not recognized
|
||||||
|
"""
|
||||||
|
base_path = db_storage_path()
|
||||||
|
|
||||||
|
if storage_type == 'ltm':
|
||||||
|
return base_path / 'latest_long_term_memories.db'
|
||||||
|
elif storage_type == 'kickoff':
|
||||||
|
return base_path / 'latest_kickoff_task_outputs.db'
|
||||||
|
elif storage_type == 'rag':
|
||||||
|
return base_path
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unknown storage type: {storage_type}")
|
||||||
|
|||||||
@@ -28,9 +28,10 @@ def test_create_success(mock_subprocess):
|
|||||||
with in_temp_dir():
|
with in_temp_dir():
|
||||||
tool_command = ToolCommand()
|
tool_command = ToolCommand()
|
||||||
|
|
||||||
with patch.object(tool_command, "login") as mock_login, patch(
|
with (
|
||||||
"sys.stdout", new=StringIO()
|
patch.object(tool_command, "login") as mock_login,
|
||||||
) as fake_out:
|
patch("sys.stdout", new=StringIO()) as fake_out,
|
||||||
|
):
|
||||||
tool_command.create("test-tool")
|
tool_command.create("test-tool")
|
||||||
output = fake_out.getvalue()
|
output = fake_out.getvalue()
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ def test_install_success(mock_get, mock_subprocess_run):
|
|||||||
capture_output=False,
|
capture_output=False,
|
||||||
text=True,
|
text=True,
|
||||||
check=True,
|
check=True,
|
||||||
env=unittest.mock.ANY
|
env=unittest.mock.ANY,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert "Successfully installed sample-tool" in output
|
assert "Successfully installed sample-tool" in output
|
||||||
|
|||||||
83
tests/memory/test_storage_paths.py
Normal file
83
tests/memory/test_storage_paths.py
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
|
import pytest
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from crewai.memory.storage.ltm_sqlite_storage import LTMSQLiteStorage
|
||||||
|
from crewai.memory.storage.kickoff_task_outputs_storage import KickoffTaskOutputsSQLiteStorage
|
||||||
|
from crewai.memory.storage.base_rag_storage import BaseRAGStorage
|
||||||
|
from crewai.utilities.paths import get_default_storage_path
|
||||||
|
|
||||||
|
class MockRAGStorage(BaseRAGStorage):
|
||||||
|
"""Mock implementation of BaseRAGStorage for testing."""
|
||||||
|
def _sanitize_role(self, role: str) -> str:
|
||||||
|
return role.lower()
|
||||||
|
|
||||||
|
def save(self, value, metadata):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def search(self, query, limit=3, filter=None, score_threshold=0.35):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _generate_embedding(self, text, metadata=None):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def _initialize_app(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_default_storage_paths():
|
||||||
|
"""Test that default storage paths are created correctly."""
|
||||||
|
ltm_path = get_default_storage_path('ltm')
|
||||||
|
kickoff_path = get_default_storage_path('kickoff')
|
||||||
|
rag_path = get_default_storage_path('rag')
|
||||||
|
|
||||||
|
assert str(ltm_path).endswith('latest_long_term_memories.db')
|
||||||
|
assert str(kickoff_path).endswith('latest_kickoff_task_outputs.db')
|
||||||
|
assert isinstance(rag_path, Path)
|
||||||
|
|
||||||
|
def test_custom_storage_paths():
|
||||||
|
"""Test that custom storage paths are respected."""
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
custom_path = Path(temp_dir) / 'custom.db'
|
||||||
|
|
||||||
|
ltm = LTMSQLiteStorage(storage_path=custom_path)
|
||||||
|
assert ltm.storage_path == custom_path
|
||||||
|
|
||||||
|
kickoff = KickoffTaskOutputsSQLiteStorage(storage_path=custom_path)
|
||||||
|
assert kickoff.storage_path == custom_path
|
||||||
|
|
||||||
|
rag = MockRAGStorage('test', storage_path=custom_path)
|
||||||
|
assert rag.storage_path == custom_path
|
||||||
|
|
||||||
|
def test_directory_creation():
|
||||||
|
"""Test that storage directories are created automatically."""
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
test_dir = Path(temp_dir) / 'test_storage'
|
||||||
|
storage_path = test_dir / 'test.db'
|
||||||
|
|
||||||
|
assert not test_dir.exists()
|
||||||
|
LTMSQLiteStorage(storage_path=storage_path)
|
||||||
|
assert test_dir.exists()
|
||||||
|
|
||||||
|
def test_permission_error():
|
||||||
|
"""Test that permission errors are handled correctly."""
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
test_dir = Path(temp_dir) / 'readonly'
|
||||||
|
test_dir.mkdir()
|
||||||
|
os.chmod(test_dir, 0o444) # Read-only
|
||||||
|
|
||||||
|
storage_path = test_dir / 'test.db'
|
||||||
|
with pytest.raises((PermissionError, OSError)) as exc_info:
|
||||||
|
LTMSQLiteStorage(storage_path=storage_path)
|
||||||
|
# Verify that the error message mentions permission
|
||||||
|
assert "permission" in str(exc_info.value).lower()
|
||||||
|
|
||||||
|
def test_invalid_path():
|
||||||
|
"""Test that invalid paths raise appropriate errors."""
|
||||||
|
with pytest.raises(OSError):
|
||||||
|
# Try to create storage in a non-existent root directory
|
||||||
|
LTMSQLiteStorage(storage_path=Path('/nonexistent/dir/test.db'))
|
||||||
68
uv.lock
generated
68
uv.lock
generated
@@ -1,10 +1,18 @@
|
|||||||
version = 1
|
version = 1
|
||||||
requires-python = ">=3.10, <3.13"
|
requires-python = ">=3.10, <3.13"
|
||||||
resolution-markers = [
|
resolution-markers = [
|
||||||
"python_full_version < '3.11'",
|
"python_full_version < '3.11' and sys_platform == 'darwin'",
|
||||||
"python_full_version == '3.11.*'",
|
"python_full_version < '3.11' and platform_machine == 'aarch64' and sys_platform == 'linux'",
|
||||||
"python_full_version >= '3.12' and python_full_version < '3.12.4'",
|
"(python_full_version < '3.11' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform != 'darwin' and sys_platform != 'linux')",
|
||||||
"python_full_version >= '3.12.4'",
|
"python_full_version == '3.11.*' and sys_platform == 'darwin'",
|
||||||
|
"python_full_version == '3.11.*' and platform_machine == 'aarch64' and sys_platform == 'linux'",
|
||||||
|
"(python_full_version == '3.11.*' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform != 'darwin' and sys_platform != 'linux')",
|
||||||
|
"python_full_version >= '3.12' and python_full_version < '3.12.4' and sys_platform == 'darwin'",
|
||||||
|
"python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and sys_platform == 'linux'",
|
||||||
|
"(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and sys_platform != 'darwin' and sys_platform != 'linux')",
|
||||||
|
"python_full_version >= '3.12.4' and sys_platform == 'darwin'",
|
||||||
|
"python_full_version >= '3.12.4' and platform_machine == 'aarch64' and sys_platform == 'linux'",
|
||||||
|
"(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12.4' and sys_platform != 'darwin' and sys_platform != 'linux')",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -300,7 +308,7 @@ name = "build"
|
|||||||
version = "1.2.2.post1"
|
version = "1.2.2.post1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "colorama", marker = "os_name == 'nt'" },
|
{ name = "colorama", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" },
|
||||||
{ name = "importlib-metadata", marker = "python_full_version < '3.10.2'" },
|
{ name = "importlib-metadata", marker = "python_full_version < '3.10.2'" },
|
||||||
{ name = "packaging" },
|
{ name = "packaging" },
|
||||||
{ name = "pyproject-hooks" },
|
{ name = "pyproject-hooks" },
|
||||||
@@ -535,7 +543,7 @@ name = "click"
|
|||||||
version = "8.1.7"
|
version = "8.1.7"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "colorama", marker = "platform_system == 'Windows'" },
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 }
|
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -642,7 +650,6 @@ tools = [
|
|||||||
[package.dev-dependencies]
|
[package.dev-dependencies]
|
||||||
dev = [
|
dev = [
|
||||||
{ name = "cairosvg" },
|
{ name = "cairosvg" },
|
||||||
{ name = "crewai-tools" },
|
|
||||||
{ name = "mkdocs" },
|
{ name = "mkdocs" },
|
||||||
{ name = "mkdocs-material" },
|
{ name = "mkdocs-material" },
|
||||||
{ name = "mkdocs-material-extensions" },
|
{ name = "mkdocs-material-extensions" },
|
||||||
@@ -696,7 +703,6 @@ requires-dist = [
|
|||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
dev = [
|
dev = [
|
||||||
{ name = "cairosvg", specifier = ">=2.7.1" },
|
{ name = "cairosvg", specifier = ">=2.7.1" },
|
||||||
{ name = "crewai-tools", specifier = ">=0.17.0" },
|
|
||||||
{ name = "mkdocs", specifier = ">=1.4.3" },
|
{ name = "mkdocs", specifier = ">=1.4.3" },
|
||||||
{ name = "mkdocs-material", specifier = ">=9.5.7" },
|
{ name = "mkdocs-material", specifier = ">=9.5.7" },
|
||||||
{ name = "mkdocs-material-extensions", specifier = ">=1.3.1" },
|
{ name = "mkdocs-material-extensions", specifier = ">=1.3.1" },
|
||||||
@@ -2462,7 +2468,7 @@ version = "1.6.1"
|
|||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "click" },
|
{ name = "click" },
|
||||||
{ name = "colorama", marker = "platform_system == 'Windows'" },
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
{ name = "ghp-import" },
|
{ name = "ghp-import" },
|
||||||
{ name = "jinja2" },
|
{ name = "jinja2" },
|
||||||
{ name = "markdown" },
|
{ name = "markdown" },
|
||||||
@@ -2643,7 +2649,7 @@ version = "2.10.2"
|
|||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "pygments" },
|
{ name = "pygments" },
|
||||||
{ name = "pywin32", marker = "platform_system == 'Windows'" },
|
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
||||||
{ name = "tqdm" },
|
{ name = "tqdm" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/3a/93/80ac75c20ce54c785648b4ed363c88f148bf22637e10c9863db4fbe73e74/mpire-2.10.2.tar.gz", hash = "sha256:f66a321e93fadff34585a4bfa05e95bd946cf714b442f51c529038eb45773d97", size = 271270 }
|
sdist = { url = "https://files.pythonhosted.org/packages/3a/93/80ac75c20ce54c785648b4ed363c88f148bf22637e10c9863db4fbe73e74/mpire-2.10.2.tar.gz", hash = "sha256:f66a321e93fadff34585a4bfa05e95bd946cf714b442f51c529038eb45773d97", size = 271270 }
|
||||||
@@ -2890,7 +2896,7 @@ name = "nvidia-cudnn-cu12"
|
|||||||
version = "9.1.0.70"
|
version = "9.1.0.70"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux')" },
|
{ name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
|
||||||
]
|
]
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/9f/fd/713452cd72343f682b1c7b9321e23829f00b842ceaedcda96e742ea0b0b3/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f", size = 664752741 },
|
{ url = "https://files.pythonhosted.org/packages/9f/fd/713452cd72343f682b1c7b9321e23829f00b842ceaedcda96e742ea0b0b3/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f", size = 664752741 },
|
||||||
@@ -2917,9 +2923,9 @@ name = "nvidia-cusolver-cu12"
|
|||||||
version = "11.4.5.107"
|
version = "11.4.5.107"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux')" },
|
{ name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
|
||||||
{ name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux')" },
|
{ name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
|
||||||
{ name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux')" },
|
{ name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
|
||||||
]
|
]
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/bc/1d/8de1e5c67099015c834315e333911273a8c6aaba78923dd1d1e25fc5f217/nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl", hash = "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd", size = 124161928 },
|
{ url = "https://files.pythonhosted.org/packages/bc/1d/8de1e5c67099015c834315e333911273a8c6aaba78923dd1d1e25fc5f217/nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl", hash = "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd", size = 124161928 },
|
||||||
@@ -2930,7 +2936,7 @@ name = "nvidia-cusparse-cu12"
|
|||||||
version = "12.1.0.106"
|
version = "12.1.0.106"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux')" },
|
{ name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
|
||||||
]
|
]
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/65/5b/cfaeebf25cd9fdec14338ccb16f6b2c4c7fa9163aefcf057d86b9cc248bb/nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c", size = 195958278 },
|
{ url = "https://files.pythonhosted.org/packages/65/5b/cfaeebf25cd9fdec14338ccb16f6b2c4c7fa9163aefcf057d86b9cc248bb/nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c", size = 195958278 },
|
||||||
@@ -3480,7 +3486,7 @@ name = "portalocker"
|
|||||||
version = "2.10.1"
|
version = "2.10.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "pywin32", marker = "platform_system == 'Windows'" },
|
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891 }
|
sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891 }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -5022,19 +5028,19 @@ dependencies = [
|
|||||||
{ name = "fsspec" },
|
{ name = "fsspec" },
|
||||||
{ name = "jinja2" },
|
{ name = "jinja2" },
|
||||||
{ name = "networkx" },
|
{ name = "networkx" },
|
||||||
{ name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
|
{ name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
{ name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
|
{ name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
{ name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
|
{ name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
{ name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
|
{ name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
{ name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
|
{ name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
{ name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
|
{ name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
{ name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
|
{ name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
{ name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
|
{ name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
{ name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
|
{ name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
{ name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
|
{ name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
{ name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
|
{ name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
{ name = "sympy" },
|
{ name = "sympy" },
|
||||||
{ name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
|
{ name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -5081,7 +5087,7 @@ name = "tqdm"
|
|||||||
version = "4.66.5"
|
version = "4.66.5"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "colorama", marker = "platform_system == 'Windows'" },
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/58/83/6ba9844a41128c62e810fddddd72473201f3eacde02046066142a2d96cc5/tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad", size = 169504 }
|
sdist = { url = "https://files.pythonhosted.org/packages/58/83/6ba9844a41128c62e810fddddd72473201f3eacde02046066142a2d96cc5/tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad", size = 169504 }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -5124,7 +5130,7 @@ version = "0.27.0"
|
|||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "attrs" },
|
{ name = "attrs" },
|
||||||
{ name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" },
|
{ name = "cffi", marker = "(implementation_name != 'pypy' and os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (implementation_name != 'pypy' and os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" },
|
||||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||||
{ name = "idna" },
|
{ name = "idna" },
|
||||||
{ name = "outcome" },
|
{ name = "outcome" },
|
||||||
@@ -5155,7 +5161,7 @@ name = "triton"
|
|||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "filelock", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux')" },
|
{ name = "filelock", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
|
||||||
]
|
]
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/45/27/14cc3101409b9b4b9241d2ba7deaa93535a217a211c86c4cc7151fb12181/triton-3.0.0-1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e1efef76935b2febc365bfadf74bcb65a6f959a9872e5bddf44cc9e0adce1e1a", size = 209376304 },
|
{ url = "https://files.pythonhosted.org/packages/45/27/14cc3101409b9b4b9241d2ba7deaa93535a217a211c86c4cc7151fb12181/triton-3.0.0-1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e1efef76935b2febc365bfadf74bcb65a6f959a9872e5bddf44cc9e0adce1e1a", size = 209376304 },
|
||||||
|
|||||||
Reference in New Issue
Block a user