mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-08-10 16:32:28 +00:00
fix(tools): make crew-scoped policy real and close the last raise leak
Two findings, and the first was a documented feature that never worked. `resolve_tool_failure_policy` consulted a crew, and the docs advertised crew as a scope, but `Crew` had no `tool_failure_policy` field at all -- and even with one it was unreachable, because `BaseAgent` defaulted the policy to `WARN` rather than `None`, so resolution always stopped at the agent. Crew-level configuration was silently ignored. Fixed by making "inherit" the default everywhere instead of baking `warn` into one layer: `Crew` gains the field, and `BaseAgent`/`LiteAgent` default to `None` like `Task` and `BaseTool` already did. The resolver owns the single fallback, so the chain is genuinely tool > task > agent > crew > warn and the effective default with nothing configured is still `warn`. Reading `agent.tool_failure_policy` now returns `None` (meaning "inherit") rather than `WARN`. The other: `StepExecutor` re-raised `ToolExecutionFailedError` from its outer handler, but the nested handler around the native-to-text tooling fallback still caught it and returned `StepResult(success=False)`. An agent whose LLM lacked native tool calling would therefore not abort under `raise`. That is the third distinct place this exception was being downgraded; it now re-raises there too. Testing: 8 further tests, 60 total, including the full precedence chain walked one level at a time and crew-scoped `raise`/`ignore` driven end-to-end through `kickoff()` rather than only through the resolver -- the gap that let the original crew bug pass review. Full suite matches baseline exactly at 377 pre-existing failures; mypy clean on every changed file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ETacm2dMASfpMAYUiDu5YG
This commit is contained in:
@@ -388,7 +388,7 @@ tool's `max_usage_count` is spent, or when the agent calls a tool that does not
|
||||
| `raise` | Records and emits, then aborts with `ToolExecutionFailedError`. |
|
||||
|
||||
```python Code
|
||||
from crewai import Agent, Task
|
||||
from crewai import Agent, Crew, Task
|
||||
from crewai.tools.tool_failure import ToolFailurePolicy
|
||||
|
||||
agent = Agent(
|
||||
@@ -406,10 +406,18 @@ task = Task(
|
||||
agent=agent,
|
||||
tool_failure_policy=ToolFailurePolicy.RAISE,
|
||||
)
|
||||
|
||||
# Or set a baseline once for every agent in the crew.
|
||||
crew = Crew(
|
||||
agents=[agent],
|
||||
tasks=[task],
|
||||
tool_failure_policy=ToolFailurePolicy.WARN,
|
||||
)
|
||||
```
|
||||
|
||||
The most specific setting wins: tool, then task, then agent, then crew, then the
|
||||
`warn` default.
|
||||
The most specific setting wins: **tool → task → agent → crew → `warn`**. Every
|
||||
level defaults to `None`, meaning "inherit from the next one out", so the
|
||||
effective default with nothing configured anywhere is `warn`.
|
||||
|
||||
### Inspecting Failures
|
||||
|
||||
|
||||
Reference in New Issue
Block a user