From e72b08ec4981f79c368f72c82d69843cf86ebeb8 Mon Sep 17 00:00:00 2001 From: Greyson LaLonde Date: Sat, 4 Apr 2026 03:57:39 +0800 Subject: [PATCH] fix: resolve mypy errors from optional executor fields - Disable union-attr/arg-type at file level in the two executor files where agent/task/crew are always set at runtime but typed as optional - Fix Liskov override in OpenAICompletion: use BaseAgent instead of Agent - Remove stale type: ignore comments now covered by file-level disables --- .../src/crewai/agents/crew_agent_executor.py | 21 +++++++++-------- .../src/crewai/experimental/agent_executor.py | 23 ++++++++++--------- lib/crewai/src/crewai/lite_agent.py | 2 +- .../llms/providers/openai/completion.py | 14 +++++------ 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/lib/crewai/src/crewai/agents/crew_agent_executor.py b/lib/crewai/src/crewai/agents/crew_agent_executor.py index 02d2e0e40..c8bc1a0dc 100644 --- a/lib/crewai/src/crewai/agents/crew_agent_executor.py +++ b/lib/crewai/src/crewai/agents/crew_agent_executor.py @@ -1,3 +1,4 @@ +# mypy: disable-error-code="union-attr,arg-type" """Agent executor for crew AI agents. Handles agent execution flow including LLM interactions, tool execution, @@ -296,7 +297,7 @@ class CrewAgentExecutor(BaseAgentExecutor): use_native_tools = ( hasattr(self.llm, "supports_function_calling") and callable(getattr(self.llm, "supports_function_calling", None)) - and self.llm.supports_function_calling() # type: ignore[union-attr] + and self.llm.supports_function_calling() and self.original_tools ) @@ -409,8 +410,8 @@ class CrewAgentExecutor(BaseAgentExecutor): formatted_answer, tool_result ) - self._invoke_step_callback(formatted_answer) # type: ignore[arg-type] - self._append_message(formatted_answer.text) # type: ignore[union-attr] + self._invoke_step_callback(formatted_answer) + self._append_message(formatted_answer.text) except OutputParserError as e: formatted_answer = handle_output_parser_exception( # type: ignore[assignment] @@ -947,7 +948,7 @@ class CrewAgentExecutor(BaseAgentExecutor): before_hook_context = ToolCallHookContext( tool_name=func_name, tool_input=args_dict or {}, - tool=structured_tool, # type: ignore[arg-type] + tool=structured_tool, agent=self.agent, task=self.task, crew=self.crew, @@ -1012,7 +1013,7 @@ class CrewAgentExecutor(BaseAgentExecutor): after_hook_context = ToolCallHookContext( tool_name=func_name, tool_input=args_dict or {}, - tool=structured_tool, # type: ignore[arg-type] + tool=structured_tool, agent=self.agent, task=self.task, crew=self.crew, @@ -1142,7 +1143,7 @@ class CrewAgentExecutor(BaseAgentExecutor): use_native_tools = ( hasattr(self.llm, "supports_function_calling") and callable(getattr(self.llm, "supports_function_calling", None)) - and self.llm.supports_function_calling() # type: ignore[union-attr] + and self.llm.supports_function_calling() and self.original_tools ) @@ -1250,8 +1251,8 @@ class CrewAgentExecutor(BaseAgentExecutor): formatted_answer, tool_result ) - await self._ainvoke_step_callback(formatted_answer) # type: ignore[arg-type] - self._append_message(formatted_answer.text) # type: ignore[union-attr] + await self._ainvoke_step_callback(formatted_answer) + self._append_message(formatted_answer.text) except OutputParserError as e: formatted_answer = handle_output_parser_exception( # type: ignore[assignment] @@ -1634,7 +1635,7 @@ class CrewAgentExecutor(BaseAgentExecutor): Final answer after feedback. """ provider = get_provider() - return provider.handle_feedback(formatted_answer, self) # type: ignore[arg-type] + return provider.handle_feedback(formatted_answer, self) async def _ahandle_human_feedback( self, formatted_answer: AgentFinish @@ -1648,7 +1649,7 @@ class CrewAgentExecutor(BaseAgentExecutor): Final answer after feedback. """ provider = get_provider() - return await provider.handle_feedback_async(formatted_answer, self) # type: ignore[arg-type] + return await provider.handle_feedback_async(formatted_answer, self) def _is_training_mode(self) -> bool: """Check if training mode is active. diff --git a/lib/crewai/src/crewai/experimental/agent_executor.py b/lib/crewai/src/crewai/experimental/agent_executor.py index c54f18f2e..ff31251f3 100644 --- a/lib/crewai/src/crewai/experimental/agent_executor.py +++ b/lib/crewai/src/crewai/experimental/agent_executor.py @@ -1,3 +1,4 @@ +# mypy: disable-error-code="union-attr,arg-type" from __future__ import annotations import asyncio @@ -297,12 +298,12 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor from crewai.utilities.reasoning_handler import AgentReasoning if self.task: - planning_handler = AgentReasoning(agent=self.agent, task=self.task) # type: ignore[arg-type] + planning_handler = AgentReasoning(agent=self.agent, task=self.task) else: # For kickoff() path - use input text directly, no Task needed input_text = getattr(self, "_kickoff_input", "") planning_handler = AgentReasoning( - agent=self.agent, # type: ignore[arg-type] + agent=self.agent, description=input_text or "Complete the requested task", expected_output="Complete the task successfully", ) @@ -387,28 +388,28 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor step failures reliably trigger replanning rather than being silently ignored. """ - config = self.agent.planning_config # type: ignore[attr-defined] + config = self.agent.planning_config if config is not None: return str(config.reasoning_effort) return "medium" def _get_max_replans(self) -> int: """Get max replans from planning config or default to 3.""" - config = self.agent.planning_config # type: ignore[attr-defined] + config = self.agent.planning_config if config is not None: return int(config.max_replans) return 3 def _get_max_step_iterations(self) -> int: """Get max step iterations from planning config or default to 15.""" - config = self.agent.planning_config # type: ignore[attr-defined] + config = self.agent.planning_config if config is not None: return int(config.max_step_iterations) return 15 def _get_step_timeout(self) -> int | None: """Get per-step timeout from planning config or default to None.""" - config = self.agent.planning_config # type: ignore[attr-defined] + config = self.agent.planning_config if config is not None: return int(config.step_timeout) if config.step_timeout is not None else None return None @@ -1784,7 +1785,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor before_hook_context = ToolCallHookContext( tool_name=func_name, tool_input=args_dict, - tool=structured_tool, # type: ignore[arg-type] + tool=structured_tool, agent=self.agent, task=self.task, crew=self.crew, @@ -1858,7 +1859,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor after_hook_context = ToolCallHookContext( tool_name=func_name, tool_input=args_dict, - tool=structured_tool, # type: ignore[arg-type] + tool=structured_tool, agent=self.agent, task=self.task, crew=self.crew, @@ -2358,11 +2359,11 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor from crewai.utilities.reasoning_handler import AgentReasoning if self.task: - planning_handler = AgentReasoning(agent=self.agent, task=self.task) # type: ignore[arg-type] + planning_handler = AgentReasoning(agent=self.agent, task=self.task) else: input_text = getattr(self, "_kickoff_input", "") planning_handler = AgentReasoning( - agent=self.agent, # type: ignore[arg-type] + agent=self.agent, description=input_text or "Complete the requested task", expected_output="Complete the task successfully", ) @@ -2379,7 +2380,7 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor): # type: ignor # description is a read-only property — recreate with enhanced text input_text = getattr(self, "_kickoff_input", "") planning_handler = AgentReasoning( - agent=self.agent, # type: ignore[arg-type] + agent=self.agent, description=enhanced_description or input_text or "Complete the requested task", diff --git a/lib/crewai/src/crewai/lite_agent.py b/lib/crewai/src/crewai/lite_agent.py index bbb464010..2bed7e92f 100644 --- a/lib/crewai/src/crewai/lite_agent.py +++ b/lib/crewai/src/crewai/lite_agent.py @@ -891,7 +891,7 @@ class LiteAgent(FlowTrackable, BaseModel): messages=self._messages, callbacks=self._callbacks, printer=self._printer, - from_agent=self, + from_agent=self, # type: ignore[arg-type] executor_context=self, response_model=response_model, verbose=self.verbose, diff --git a/lib/crewai/src/crewai/llms/providers/openai/completion.py b/lib/crewai/src/crewai/llms/providers/openai/completion.py index d58e6b0d9..804ce2927 100644 --- a/lib/crewai/src/crewai/llms/providers/openai/completion.py +++ b/lib/crewai/src/crewai/llms/providers/openai/completion.py @@ -29,7 +29,7 @@ from crewai.utilities.types import LLMMessage if TYPE_CHECKING: - from crewai.agent.core import Agent + from crewai.agents.agent_builder.base_agent import BaseAgent from crewai.task import Task from crewai.tools.base_tool import BaseTool @@ -359,7 +359,7 @@ class OpenAICompletion(BaseLLM): callbacks: list[Any] | None = None, available_functions: dict[str, Any] | None = None, from_task: Task | None = None, - from_agent: Agent | None = None, + from_agent: BaseAgent | None = None, response_model: type[BaseModel] | None = None, ) -> str | Any: """Call OpenAI API (Chat Completions or Responses based on api setting). @@ -427,7 +427,7 @@ class OpenAICompletion(BaseLLM): tools: list[dict[str, BaseTool]] | None = None, available_functions: dict[str, Any] | None = None, from_task: Task | None = None, - from_agent: Agent | None = None, + from_agent: BaseAgent | None = None, response_model: type[BaseModel] | None = None, ) -> str | Any: """Call OpenAI Chat Completions API.""" @@ -459,7 +459,7 @@ class OpenAICompletion(BaseLLM): callbacks: list[Any] | None = None, available_functions: dict[str, Any] | None = None, from_task: Task | None = None, - from_agent: Agent | None = None, + from_agent: BaseAgent | None = None, response_model: type[BaseModel] | None = None, ) -> str | Any: """Async call to OpenAI API (Chat Completions or Responses). @@ -522,7 +522,7 @@ class OpenAICompletion(BaseLLM): tools: list[dict[str, BaseTool]] | None = None, available_functions: dict[str, Any] | None = None, from_task: Task | None = None, - from_agent: Agent | None = None, + from_agent: BaseAgent | None = None, response_model: type[BaseModel] | None = None, ) -> str | Any: """Async call to OpenAI Chat Completions API.""" @@ -553,7 +553,7 @@ class OpenAICompletion(BaseLLM): tools: list[dict[str, BaseTool]] | None = None, available_functions: dict[str, Any] | None = None, from_task: Task | None = None, - from_agent: Agent | None = None, + from_agent: BaseAgent | None = None, response_model: type[BaseModel] | None = None, ) -> str | Any: """Call OpenAI Responses API.""" @@ -584,7 +584,7 @@ class OpenAICompletion(BaseLLM): tools: list[dict[str, BaseTool]] | None = None, available_functions: dict[str, Any] | None = None, from_task: Task | None = None, - from_agent: Agent | None = None, + from_agent: BaseAgent | None = None, response_model: type[BaseModel] | None = None, ) -> str | Any: """Async call to OpenAI Responses API."""