mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-08-10 08:21:54 +00:00
fix(tools): let raise through the parallel native path, guard all handlers
Chasing down CodeRabbit's note about callers of execute_single_native_tool_call turned up a fifth place this exception was being downgraded: the experimental executor's parallel branch wrapped future.result() in a broad except and folded the abort into a fake tool result, so the remaining parallel calls carried on. The sequential path and crew_agent_executor's parallel branch were already fine. Five separate handlers have swallowed this during review, so added a guard test asserting the passthrough at every site rather than trusting the next one gets spotted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
This commit is contained in:
@@ -1767,6 +1767,10 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor):
|
||||
idx = future_to_idx[future]
|
||||
try:
|
||||
ordered_results[idx] = future.result()
|
||||
except ToolExecutionFailedError:
|
||||
# A deliberate stop: folding it into a tool result would
|
||||
# let the remaining parallel calls carry on.
|
||||
raise
|
||||
except Exception as e:
|
||||
tool_call = runnable_tool_calls[idx]
|
||||
info = extract_tool_call_info(tool_call)
|
||||
|
||||
@@ -700,6 +700,32 @@ class TestRaisePolicySurvivesEveryWrapper:
|
||||
).kickoff()
|
||||
assert not result.has_tool_failures
|
||||
|
||||
def test_every_broad_handler_around_tool_execution_lets_it_through(self) -> None:
|
||||
"""Guard against a new `except Exception` quietly downgrading an abort.
|
||||
|
||||
Five separate handlers have swallowed this exception during review of
|
||||
this PR, so assert the passthrough at each site rather than trusting
|
||||
that the next one will be spotted.
|
||||
"""
|
||||
import inspect
|
||||
|
||||
from crewai.agent.core import Agent as AgentCls
|
||||
from crewai.agents.crew_agent_executor import CrewAgentExecutor
|
||||
from crewai.agents.step_executor import StepExecutor
|
||||
from crewai.experimental.agent_executor import AgentExecutor
|
||||
|
||||
sites = [
|
||||
(AgentCls._execute_with_timeout, "_passthrough_exceptions"),
|
||||
(StepExecutor.execute, "ToolExecutionFailedError"),
|
||||
(AgentExecutor.execute_tool_action, "ToolExecutionFailedError"),
|
||||
(AgentExecutor.execute_native_tool, "ToolExecutionFailedError"),
|
||||
(CrewAgentExecutor._invoke_loop_react, "ToolExecutionFailedError"),
|
||||
(CrewAgentExecutor._ainvoke_loop_react, "ToolExecutionFailedError"),
|
||||
]
|
||||
for func, expected in sites:
|
||||
source = inspect.getsource(func)
|
||||
assert expected in source, f"{func.__qualname__} lost its passthrough"
|
||||
|
||||
def test_passthrough_tuple_includes_the_error(self) -> None:
|
||||
from crewai.agent.core import _passthrough_exceptions
|
||||
|
||||
|
||||
Reference in New Issue
Block a user