refactor: update CacheHandler imports to use direct path

- Update imports from crewai.agents.cache to crewai.agents.cache.cache_handler
- Remove CacheHandler from agents module __all__ export
This commit is contained in:
Greyson LaLonde
2025-09-03 18:18:05 -04:00
parent 94029017c3
commit bdfc38ba32
8 changed files with 124 additions and 119 deletions

View File

@@ -16,7 +16,7 @@ from typing import (
from pydantic import Field, InstanceOf, PrivateAttr, model_validator from pydantic import Field, InstanceOf, PrivateAttr, model_validator
from crewai.agents import CacheHandler from crewai.agents.cache.cache_handler import CacheHandler
from crewai.agents.agent_builder.base_agent import BaseAgent from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.crew_agent_executor import CrewAgentExecutor from crewai.agents.crew_agent_executor import CrewAgentExecutor
from crewai.knowledge.knowledge import Knowledge from crewai.knowledge.knowledge import Knowledge

View File

@@ -1,5 +1,10 @@
from crewai.agents.cache.cache_handler import CacheHandler
from crewai.agents.parser import parse, AgentAction, AgentFinish, OutputParserException from crewai.agents.parser import parse, AgentAction, AgentFinish, OutputParserException
from crewai.agents.tools_handler import ToolsHandler from crewai.agents.tools_handler import ToolsHandler
__all__ = ["CacheHandler", "parse", "AgentAction", "AgentFinish", "OutputParserException", "ToolsHandler"] __all__ = [
"parse",
"AgentAction",
"AgentFinish",
"OutputParserException",
"ToolsHandler",
]

View File

@@ -37,7 +37,7 @@ from pydantic_core import PydanticCustomError
from crewai.agent import Agent from crewai.agent import Agent
from crewai.agents.agent_builder.base_agent import BaseAgent from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.cache import CacheHandler from crewai.agents.cache.cache_handler import CacheHandler
from crewai.crews.crew_output import CrewOutput from crewai.crews.crew_output import CrewOutput
from crewai.flow.flow_trackable import FlowTrackable from crewai.flow.flow_trackable import FlowTrackable
from crewai.knowledge.knowledge import Knowledge from crewai.knowledge.knowledge import Knowledge

View File

@@ -33,7 +33,7 @@ from pydantic import (
from crewai.agents.agent_builder.base_agent import BaseAgent from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.agent_builder.utilities.base_token_process import TokenProcess from crewai.agents.agent_builder.utilities.base_token_process import TokenProcess
from crewai.agents.cache import CacheHandler from crewai.agents.cache.cache_handler import CacheHandler
from crewai.agents.parser import ( from crewai.agents.parser import (
AgentAction, AgentAction,
AgentFinish, AgentFinish,

View File

@@ -1,6 +1,6 @@
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from crewai.agents.cache import CacheHandler from crewai.agents.cache.cache_handler import CacheHandler
from crewai.tools.structured_tool import CrewStructuredTool from crewai.tools.structured_tool import CrewStructuredTool

View File

@@ -11,6 +11,14 @@ import json5
from json_repair import repair_json from json_repair import repair_json
from crewai.agents.tools_handler import ToolsHandler from crewai.agents.tools_handler import ToolsHandler
from crewai.events.event_bus import crewai_event_bus
from crewai.events.types.tool_usage_events import (
ToolSelectionErrorEvent,
ToolUsageErrorEvent,
ToolUsageFinishedEvent,
ToolUsageStartedEvent,
ToolValidateInputErrorEvent,
)
from crewai.task import Task from crewai.task import Task
from crewai.telemetry import Telemetry from crewai.telemetry import Telemetry
from crewai.tools.structured_tool import CrewStructuredTool from crewai.tools.structured_tool import CrewStructuredTool
@@ -20,14 +28,6 @@ from crewai.utilities.agent_utils import (
get_tool_names, get_tool_names,
render_text_description_and_args, render_text_description_and_args,
) )
from crewai.events.event_bus import crewai_event_bus
from crewai.events.types.tool_usage_events import (
ToolSelectionErrorEvent,
ToolUsageErrorEvent,
ToolUsageFinishedEvent,
ToolUsageStartedEvent,
ToolValidateInputErrorEvent,
)
if TYPE_CHECKING: if TYPE_CHECKING:
from crewai.agents.agent_builder.base_agent import BaseAgent from crewai.agents.agent_builder.base_agent import BaseAgent
@@ -69,12 +69,12 @@ class ToolUsage:
def __init__( def __init__(
self, self,
tools_handler: Optional[ToolsHandler], tools_handler: Optional[ToolsHandler],
tools: List[CrewStructuredTool], tools: list[CrewStructuredTool],
task: Optional[Task], task: Optional[Task],
function_calling_llm: Any, function_calling_llm: Any,
agent: Optional[Union["BaseAgent", "LiteAgent"]] = None, agent: Optional[Union["BaseAgent", "LiteAgent"]] = None,
action: Any = None, action: Any = None,
fingerprint_context: Optional[Dict[str, str]] = None, fingerprint_context: Optional[dict[str, str]] = None,
) -> None: ) -> None:
self._i18n: I18N = agent.i18n if agent else I18N() self._i18n: I18N = agent.i18n if agent else I18N()
self._printer: Printer = Printer() self._printer: Printer = Printer()
@@ -105,7 +105,7 @@ class ToolUsage:
return self._tool_calling(tool_string) return self._tool_calling(tool_string)
def use( def use(
self, calling: Union[ToolCalling, InstructorToolCalling], tool_string: str self, calling: ToolCalling | InstructorToolCalling, tool_string: str
) -> str: ) -> str:
if isinstance(calling, ToolUsageErrorException): if isinstance(calling, ToolUsageErrorException):
error = calling.message error = calling.message
@@ -147,7 +147,7 @@ class ToolUsage:
self, self,
tool_string: str, tool_string: str,
tool: CrewStructuredTool, tool: CrewStructuredTool,
calling: Union[ToolCalling, InstructorToolCalling], calling: ToolCalling | InstructorToolCalling,
) -> str: ) -> str:
if self._check_tool_repeated_usage(calling=calling): # type: ignore # _check_tool_repeated_usage of "ToolUsage" does not return a value (it only ever returns None) if self._check_tool_repeated_usage(calling=calling): # type: ignore # _check_tool_repeated_usage of "ToolUsage" does not return a value (it only ever returns None)
try: try:
@@ -346,7 +346,7 @@ class ToolUsage:
return result return result
def _check_tool_repeated_usage( def _check_tool_repeated_usage(
self, calling: Union[ToolCalling, InstructorToolCalling] self, calling: ToolCalling | InstructorToolCalling
) -> bool: ) -> bool:
if not self.tools_handler: if not self.tools_handler:
return False return False
@@ -393,7 +393,7 @@ class ToolUsage:
return tool return tool
if self.task: if self.task:
self.task.increment_tools_errors() self.task.increment_tools_errors()
tool_selection_data: Dict[str, Any] = { tool_selection_data: dict[str, Any] = {
"agent_key": getattr(self.agent, "key", None) if self.agent else None, "agent_key": getattr(self.agent, "key", None) if self.agent else None,
"agent_role": getattr(self.agent, "role", None) if self.agent else None, "agent_role": getattr(self.agent, "role", None) if self.agent else None,
"tool_name": tool_name, "tool_name": tool_name,
@@ -430,7 +430,7 @@ class ToolUsage:
def _function_calling( def _function_calling(
self, tool_string: str self, tool_string: str
) -> Union[ToolCalling, InstructorToolCalling]: ) -> ToolCalling | InstructorToolCalling:
model = ( model = (
InstructorToolCalling InstructorToolCalling
if self.function_calling_llm.supports_function_calling() if self.function_calling_llm.supports_function_calling()
@@ -459,7 +459,7 @@ class ToolUsage:
def _original_tool_calling( def _original_tool_calling(
self, tool_string: str, raise_error: bool = False self, tool_string: str, raise_error: bool = False
) -> Union[ToolCalling, InstructorToolCalling, ToolUsageErrorException]: ) -> ToolCalling | InstructorToolCalling | ToolUsageErrorException:
tool_name = self.action.tool tool_name = self.action.tool
tool = self._select_tool(tool_name) tool = self._select_tool(tool_name)
try: try:
@@ -488,7 +488,7 @@ class ToolUsage:
def _tool_calling( def _tool_calling(
self, tool_string: str self, tool_string: str
) -> Union[ToolCalling, InstructorToolCalling, ToolUsageErrorException]: ) -> ToolCalling | InstructorToolCalling | ToolUsageErrorException:
try: try:
try: try:
return self._original_tool_calling(tool_string, raise_error=True) return self._original_tool_calling(tool_string, raise_error=True)
@@ -510,7 +510,7 @@ class ToolUsage:
) )
return self._tool_calling(tool_string) return self._tool_calling(tool_string)
def _validate_tool_input(self, tool_input: Optional[str]) -> Dict[str, Any]: def _validate_tool_input(self, tool_input: Optional[str]) -> dict[str, Any]:
if tool_input is None: if tool_input is None:
return {} return {}
@@ -586,7 +586,7 @@ class ToolUsage:
def on_tool_error( def on_tool_error(
self, self,
tool: Any, tool: Any,
tool_calling: Union[ToolCalling, InstructorToolCalling], tool_calling: ToolCalling | InstructorToolCalling,
e: Exception, e: Exception,
) -> None: ) -> None:
event_data = self._prepare_event_data(tool, tool_calling) event_data = self._prepare_event_data(tool, tool_calling)
@@ -595,7 +595,7 @@ class ToolUsage:
def on_tool_use_finished( def on_tool_use_finished(
self, self,
tool: Any, tool: Any,
tool_calling: Union[ToolCalling, InstructorToolCalling], tool_calling: ToolCalling | InstructorToolCalling,
from_cache: bool, from_cache: bool,
started_at: float, started_at: float,
result: Any, result: Any,
@@ -616,7 +616,7 @@ class ToolUsage:
crewai_event_bus.emit(self, ToolUsageFinishedEvent(**event_data)) crewai_event_bus.emit(self, ToolUsageFinishedEvent(**event_data))
def _prepare_event_data( def _prepare_event_data(
self, tool: Any, tool_calling: Union[ToolCalling, InstructorToolCalling] self, tool: Any, tool_calling: ToolCalling | InstructorToolCalling
) -> dict: ) -> dict:
event_data = { event_data = {
"run_attempts": self._run_attempts, "run_attempts": self._run_attempts,

View File

@@ -7,7 +7,7 @@ from unittest.mock import MagicMock, patch
import pytest import pytest
from crewai import Agent, Crew, Task from crewai import Agent, Crew, Task
from crewai.agents.cache import CacheHandler from crewai.agents.cache.cache_handler import CacheHandler
from crewai.agents.crew_agent_executor import AgentFinish, CrewAgentExecutor from crewai.agents.crew_agent_executor import AgentFinish, CrewAgentExecutor
from crewai.knowledge.knowledge import Knowledge from crewai.knowledge.knowledge import Knowledge
from crewai.knowledge.knowledge_config import KnowledgeConfig from crewai.knowledge.knowledge_config import KnowledgeConfig
@@ -559,9 +559,9 @@ def test_agent_repeated_tool_usage(capsys):
expected_message = ( expected_message = (
"I tried reusing the same input, I must stop using this action input." "I tried reusing the same input, I must stop using this action input."
) )
assert ( assert expected_message in output, (
expected_message in output f"Expected message not found in output. Output was: {output}"
), f"Expected message not found in output. Output was: {output}" )
@pytest.mark.vcr(filter_headers=["authorization"]) @pytest.mark.vcr(filter_headers=["authorization"])
@@ -602,9 +602,9 @@ def test_agent_repeated_tool_usage_check_even_with_disabled_cache(capsys):
has_max_iterations = "maximum iterations reached" in output_lower has_max_iterations = "maximum iterations reached" in output_lower
has_final_answer = "final answer" in output_lower or "42" in captured.out has_final_answer = "final answer" in output_lower or "42" in captured.out
assert ( assert has_repeated_usage_message or (has_max_iterations and has_final_answer), (
has_repeated_usage_message or (has_max_iterations and has_final_answer) f"Expected repeated tool usage handling or proper max iteration handling. Output was: {captured.out[:500]}..."
), f"Expected repeated tool usage handling or proper max iteration handling. Output was: {captured.out[:500]}..." )
@pytest.mark.vcr(filter_headers=["authorization"]) @pytest.mark.vcr(filter_headers=["authorization"])

View File

@@ -11,7 +11,7 @@ import pydantic_core
import pytest import pytest
from crewai.agent import Agent from crewai.agent import Agent
from crewai.agents import CacheHandler from crewai.agents.cache.cache_handler import CacheHandler
from crewai.crew import Crew from crewai.crew import Crew
from crewai.crews.crew_output import CrewOutput from crewai.crews.crew_output import CrewOutput
from crewai.flow import Flow, start from crewai.flow import Flow, start
@@ -622,12 +622,12 @@ def test_crew_with_delegating_agents_should_not_override_task_tools(ceo, writer)
_, kwargs = mock_execute_sync.call_args _, kwargs = mock_execute_sync.call_args
tools = kwargs["tools"] tools = kwargs["tools"]
assert any( assert any(isinstance(tool, TestTool) for tool in tools), (
isinstance(tool, TestTool) for tool in tools "TestTool should be present"
), "TestTool should be present" )
assert any( assert any("delegate" in tool.name.lower() for tool in tools), (
"delegate" in tool.name.lower() for tool in tools "Delegation tool should be present"
), "Delegation tool should be present" )
@pytest.mark.vcr(filter_headers=["authorization"]) @pytest.mark.vcr(filter_headers=["authorization"])
@@ -686,12 +686,12 @@ def test_crew_with_delegating_agents_should_not_override_agent_tools(ceo, writer
_, kwargs = mock_execute_sync.call_args _, kwargs = mock_execute_sync.call_args
tools = kwargs["tools"] tools = kwargs["tools"]
assert any( assert any(isinstance(tool, TestTool) for tool in new_ceo.tools), (
isinstance(tool, TestTool) for tool in new_ceo.tools "TestTool should be present"
), "TestTool should be present" )
assert any( assert any("delegate" in tool.name.lower() for tool in tools), (
"delegate" in tool.name.lower() for tool in tools "Delegation tool should be present"
), "Delegation tool should be present" )
@pytest.mark.vcr(filter_headers=["authorization"]) @pytest.mark.vcr(filter_headers=["authorization"])
@@ -815,17 +815,17 @@ def test_task_tools_override_agent_tools_with_allow_delegation(researcher, write
used_tools = kwargs["tools"] used_tools = kwargs["tools"]
# Confirm AnotherTestTool is present but TestTool is not # Confirm AnotherTestTool is present but TestTool is not
assert any( assert any(isinstance(tool, AnotherTestTool) for tool in used_tools), (
isinstance(tool, AnotherTestTool) for tool in used_tools "AnotherTestTool should be present"
), "AnotherTestTool should be present" )
assert not any( assert not any(isinstance(tool, TestTool) for tool in used_tools), (
isinstance(tool, TestTool) for tool in used_tools "TestTool should not be present among used tools"
), "TestTool should not be present among used tools" )
# Confirm delegation tool(s) are present # Confirm delegation tool(s) are present
assert any( assert any("delegate" in tool.name.lower() for tool in used_tools), (
"delegate" in tool.name.lower() for tool in used_tools "Delegation tool should be present"
), "Delegation tool should be present" )
# Finally, make sure the agent's original tools remain unchanged # Finally, make sure the agent's original tools remain unchanged
assert len(researcher_with_delegation.tools) == 1 assert len(researcher_with_delegation.tools) == 1
@@ -929,9 +929,9 @@ def test_cache_hitting_between_agents(researcher, writer, ceo):
tool="multiplier", input={"first_number": 2, "second_number": 6} tool="multiplier", input={"first_number": 2, "second_number": 6}
) )
assert cache_calls[0] == expected_call, f"First call mismatch: {cache_calls[0]}" assert cache_calls[0] == expected_call, f"First call mismatch: {cache_calls[0]}"
assert ( assert cache_calls[1] == expected_call, (
cache_calls[1] == expected_call f"Second call mismatch: {cache_calls[1]}"
), f"Second call mismatch: {cache_calls[1]}" )
@pytest.mark.vcr(filter_headers=["authorization"]) @pytest.mark.vcr(filter_headers=["authorization"])
@@ -1674,9 +1674,9 @@ def test_code_execution_flag_adds_code_tool_upon_kickoff():
# Verify that exactly one tool was used and it was a CodeInterpreterTool # Verify that exactly one tool was used and it was a CodeInterpreterTool
assert len(used_tools) == 1, "Should have exactly one tool" assert len(used_tools) == 1, "Should have exactly one tool"
assert isinstance( assert isinstance(used_tools[0], CodeInterpreterTool), (
used_tools[0], CodeInterpreterTool "Tool should be CodeInterpreterTool"
), "Tool should be CodeInterpreterTool" )
@pytest.mark.vcr(filter_headers=["authorization"]) @pytest.mark.vcr(filter_headers=["authorization"])
@@ -3815,9 +3815,9 @@ def test_fetch_inputs():
expected_placeholders = {"role_detail", "topic", "field"} expected_placeholders = {"role_detail", "topic", "field"}
actual_placeholders = crew.fetch_inputs() actual_placeholders = crew.fetch_inputs()
assert ( assert actual_placeholders == expected_placeholders, (
actual_placeholders == expected_placeholders f"Expected {expected_placeholders}, but got {actual_placeholders}"
), f"Expected {expected_placeholders}, but got {actual_placeholders}" )
def test_task_tools_preserve_code_execution_tools(): def test_task_tools_preserve_code_execution_tools():
@@ -3892,20 +3892,20 @@ def test_task_tools_preserve_code_execution_tools():
used_tools = kwargs["tools"] used_tools = kwargs["tools"]
# Verify all expected tools are present # Verify all expected tools are present
assert any( assert any(isinstance(tool, TestTool) for tool in used_tools), (
isinstance(tool, TestTool) for tool in used_tools "Task's TestTool should be present"
), "Task's TestTool should be present" )
assert any( assert any(isinstance(tool, CodeInterpreterTool) for tool in used_tools), (
isinstance(tool, CodeInterpreterTool) for tool in used_tools "CodeInterpreterTool should be present"
), "CodeInterpreterTool should be present" )
assert any( assert any("delegate" in tool.name.lower() for tool in used_tools), (
"delegate" in tool.name.lower() for tool in used_tools "Delegation tool should be present"
), "Delegation tool should be present" )
# Verify the total number of tools (TestTool + CodeInterpreter + 2 delegation tools) # Verify the total number of tools (TestTool + CodeInterpreter + 2 delegation tools)
assert ( assert len(used_tools) == 4, (
len(used_tools) == 4 "Should have TestTool, CodeInterpreter, and 2 delegation tools"
), "Should have TestTool, CodeInterpreter, and 2 delegation tools" )
@pytest.mark.vcr(filter_headers=["authorization"]) @pytest.mark.vcr(filter_headers=["authorization"])
@@ -3949,9 +3949,9 @@ def test_multimodal_flag_adds_multimodal_tools():
used_tools = kwargs["tools"] used_tools = kwargs["tools"]
# Check that the multimodal tool was added # Check that the multimodal tool was added
assert any( assert any(isinstance(tool, AddImageTool) for tool in used_tools), (
isinstance(tool, AddImageTool) for tool in used_tools "AddImageTool should be present when agent is multimodal"
), "AddImageTool should be present when agent is multimodal" )
# Verify we have exactly one tool (just the AddImageTool) # Verify we have exactly one tool (just the AddImageTool)
assert len(used_tools) == 1, "Should only have the AddImageTool" assert len(used_tools) == 1, "Should only have the AddImageTool"
@@ -4215,9 +4215,9 @@ def test_crew_guardrail_feedback_in_context():
assert len(execution_contexts) > 1, "Task should have been executed multiple times" assert len(execution_contexts) > 1, "Task should have been executed multiple times"
# Verify that the second execution included the guardrail feedback # Verify that the second execution included the guardrail feedback
assert ( assert "Output must contain the keyword 'IMPORTANT'" in execution_contexts[1], (
"Output must contain the keyword 'IMPORTANT'" in execution_contexts[1] "Guardrail feedback should be included in retry context"
), "Guardrail feedback should be included in retry context" )
# Verify final output meets guardrail requirements # Verify final output meets guardrail requirements
assert "IMPORTANT" in result.raw, "Final output should contain required keyword" assert "IMPORTANT" in result.raw, "Final output should contain required keyword"
@@ -4433,46 +4433,46 @@ def test_crew_copy_with_memory():
try: try:
crew_copy = crew.copy() crew_copy = crew.copy()
assert hasattr( assert hasattr(crew_copy, "_short_term_memory"), (
crew_copy, "_short_term_memory" "Copied crew should have _short_term_memory"
), "Copied crew should have _short_term_memory" )
assert ( assert crew_copy._short_term_memory is not None, (
crew_copy._short_term_memory is not None "Copied _short_term_memory should not be None"
), "Copied _short_term_memory should not be None" )
assert ( assert id(crew_copy._short_term_memory) != original_short_term_id, (
id(crew_copy._short_term_memory) != original_short_term_id "Copied _short_term_memory should be a new object"
), "Copied _short_term_memory should be a new object" )
assert hasattr( assert hasattr(crew_copy, "_long_term_memory"), (
crew_copy, "_long_term_memory" "Copied crew should have _long_term_memory"
), "Copied crew should have _long_term_memory" )
assert ( assert crew_copy._long_term_memory is not None, (
crew_copy._long_term_memory is not None "Copied _long_term_memory should not be None"
), "Copied _long_term_memory should not be None" )
assert ( assert id(crew_copy._long_term_memory) != original_long_term_id, (
id(crew_copy._long_term_memory) != original_long_term_id "Copied _long_term_memory should be a new object"
), "Copied _long_term_memory should be a new object" )
assert hasattr( assert hasattr(crew_copy, "_entity_memory"), (
crew_copy, "_entity_memory" "Copied crew should have _entity_memory"
), "Copied crew should have _entity_memory" )
assert ( assert crew_copy._entity_memory is not None, (
crew_copy._entity_memory is not None "Copied _entity_memory should not be None"
), "Copied _entity_memory should not be None" )
assert ( assert id(crew_copy._entity_memory) != original_entity_id, (
id(crew_copy._entity_memory) != original_entity_id "Copied _entity_memory should be a new object"
), "Copied _entity_memory should be a new object" )
if original_external_id: if original_external_id:
assert hasattr( assert hasattr(crew_copy, "_external_memory"), (
crew_copy, "_external_memory" "Copied crew should have _external_memory"
), "Copied crew should have _external_memory" )
assert ( assert crew_copy._external_memory is not None, (
crew_copy._external_memory is not None "Copied _external_memory should not be None"
), "Copied _external_memory should not be None" )
assert ( assert id(crew_copy._external_memory) != original_external_id, (
id(crew_copy._external_memory) != original_external_id "Copied _external_memory should be a new object"
), "Copied _external_memory should be a new object" )
else: else:
assert ( assert (
not hasattr(crew_copy, "_external_memory") not hasattr(crew_copy, "_external_memory")