* fix(bedrock): group parallel tool results in single user message
When an AWS Bedrock model makes multiple tool calls in a single
response, the Converse API requires all corresponding tool results
to be sent back in a single user message. Previously, each tool
result was emitted as a separate user message, causing:
ValidationException: Expected toolResult blocks at messages.2.content
Fix: When processing consecutive tool messages, append the toolResult
block to the preceding user message (if it already contains
toolResult blocks) instead of creating a new message. This groups
all parallel tool results together while keeping tool results from
different assistant turns separate.
Fixes#4749
Signed-off-by: Giulio Leone <6887247+giulio-leone@users.noreply.github.com>
* Update lib/crewai/tests/llms/bedrock/test_bedrock.py
* fix: group bedrock tool results
Co-authored-by: João Moura <joaomdmoura@gmail.com>
---------
Signed-off-by: Giulio Leone <6887247+giulio-leone@users.noreply.github.com>
Co-authored-by: Giulio Leone <6887247+giulio-leone@users.noreply.github.com>
Co-authored-by: João Moura <joaomdmoura@gmail.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* fix: allow hyphenated tool names in MCP references like notion#get-page
The _SLUG_RE regex on BaseAgent rejected MCP tool references containing
hyphens (e.g. "notion#get-page") because the fragment pattern only
matched \w (word chars)
* fix: create fresh MCP client per tool invocation to prevent parallel call races
When the LLM dispatches parallel calls to MCP tools on the same server, the executor runs them concurrently via ThreadPoolExecutor. Previously, all tools from a server shared a single MCPClient instance, and even the same tool called twice would reuse one client. Since each thread creates its own asyncio event loop via asyncio.run(), concurrent connect/disconnect calls on the shared client caused anyio cancel-scope errors ("Attempted to exit cancel scope in a different task than it was entered in").
The fix introduces a client_factory pattern: MCPNativeTool now receives a zero-arg callable that produces a fresh MCPClient + transport on every
_run_async() invocation. This eliminates all shared mutable connection state between concurrent calls, whether to the same tool or different tools from the same server.
* test: ensure we can filter hyphenated MCP tool
* feat: add dedicated Brave Search tools for web, news, image, video, local POIs, and Brave's newest LLM Context endpoint
* fix: normalize transformed response shape
* revert legacy tool name
* fix: schema change prevented property resolution
* Update tool.specs.json
* fix: add fallback for search_langugage
* simplify exports
* makes rate-limiting logic per-instance
* fix(brave-tools): correct _refine_response return type annotations
The abstract method and subclasses annotated _refine_response as returning
dict[str, Any] but most implementations actually return list[dict[str, Any]].
Updated base to return Any, and each subclass to match its actual return type.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Joao Moura <joaomdmoura@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(memory): convert Memory, MemoryScope, and MemorySlice to BaseModel
* fix(test): update mock memory attribute from _read_only to read_only
* fix: handle re-validation in wrap validators and patch BaseModel class in tests
ThreadPoolExecutor threads do not inherit the calling thread's contextvars
context, causing _event_id_stack and _current_celery_task_id to be empty
in worker threads. This broke OTel span parenting for parallel tool calls
(missing parent_event_id) and lost the Celery task ID in the enterprise
tracking layer ([Task ID: no-task]).
Fix by capturing an independent context copy per submission via
contextvars.copy_context().run in CrewAgentExecutor._handle_native_tool_calls,
so each worker thread starts with the correct inherited context without
sharing mutable state across threads.
* feat: enhance memory recall limits and update documentation
- Increased the memory recall limit in the Agent class from 5 to 15.
- Updated the RecallMemoryTool to allow a recall limit of 20.
- Expanded the documentation for the recall_memory feature to emphasize the importance of multiple queries for comprehensive results.
* feat: increase memory recall limit and enhance memory context documentation
- Increased the memory recall limit in the Agent class from 15 to 20.
- Updated the memory context message to clarify the nature of the memories presented and the importance of using the Search memory tool for comprehensive results.
* refactor: remove inferred_categories from RecallState and update category merging logic
- Removed the inferred_categories field from RecallState to simplify state management.
- Updated the _merged_categories method to only merge caller-supplied categories, enhancing clarity in category handling.
* refactor: simplify category handling in RecallFlow
- Updated the _merged_categories method to return only caller-supplied categories, removing the previous merging logic for inferred categories. This change enhances clarity and maintains consistency in category management.
* fix(gemini): group parallel function_response parts in a single Content object
When Gemini makes N parallel tool calls, the API requires all N function_response parts in one Content object. Previously each tool result created a separate Content, causing 400 INVALID_ARGUMENT errors. Merge consecutive function_response parts into the existing Content instead of appending new ones.
* Address change requested
- function_response is a declared field on the types.Part Pydantic model so hasattr can be replaced with p.function_response is not None
* fix(telemetry): skip signal handler registration in non-main threads
When CrewAI is initialized from a non-main thread (e.g. Streamlit, Flask,
Django, Jupyter), the telemetry module attempted to register signal handlers
which only work in the main thread. This caused multiple noisy ValueError
tracebacks to be printed to stderr, confusing users even though the errors
were caught and non-fatal.
Check `threading.current_thread() is not threading.main_thread()` before
attempting signal registration, and skip silently with a debug-level log
message instead of printing full tracebacks.
Fixes crewAIInc/crewAI#4289
* fix(test): move Telemetry() inside signal.signal mock context
Refs: #4649
* fix(telemetry): move signal.signal mock inside thread to wrap Telemetry() construction
The patch context now activates inside init_in_thread so the mock
is guaranteed to be active before and during Telemetry.__init__,
addressing the Copilot review feedback.
Refs: #4289
* fix(test): mock logger.debug instead of capsys for deterministic assertion
Replace signal.signal-only mock with combined logger + signal mock.
Assert logger.debug was called with the skip message and signal.signal
was never invoked from the non-main thread.
Refs: #4289
pypdf <6.7.4 has multiple DoS vulnerabilities via crafted PDF streams
(FlateDecode, LZWDecode, RunLengthDecode, XFA, TreeObject, outlines).
Only basic PdfReader/PdfWriter APIs are used in crewai-files, none of
which changed in the 5.0 or 6.0 breaking releases.