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
This commit is contained in:
Greyson LaLonde
2026-04-04 03:57:39 +08:00
parent c1f9d9270b
commit e72b08ec49
4 changed files with 31 additions and 29 deletions

View File

@@ -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.

View File

@@ -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",

View File

@@ -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,

View File

@@ -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."""