store_if_artifact ran before the after_tool_call hooks, so a hook that
replaced the result with a FileArtifact put raw bytes / a dataclass repr
into the tool message and events. Re-run store_if_artifact on the final
result after the hook loop in all three native tool paths (no-op for the
normal string case).
The tool-result cache stores the raw FileArtifact and hands back the same
instance on every cache hit, where store_if_artifact ran again and minted a
fresh handle plus another byte copy. Repeated identical cached calls therefore
stacked duplicate copies of the same payload until scope/TTL cleanup. The store
now reuses an existing handle when the same FileArtifact instance is stored
again under the same scope, keying off object identity (the cache keeps the
object alive, so the id is stable within a run).
- Wire resolve_artifact_handles/store_if_artifact into
agent_utils.execute_single_native_tool_call, the native tool path used
by StepExecutor (Plan-and-Execute mode); previously a FileArtifact
produced or consumed there bypassed the bypass and leaked raw bytes.
- Fold the crew/agent.crew fallback into artifact_scope_id(crew, task,
agent) so all four execution paths derive the cleanup scope identically
instead of repeating 'self.crew or getattr(self.agent, ...)'.
- Sanitize ']' and newlines (not just quotes) in the placeholder so an
odd filename can't break the bracketed attribute line; extend
_human_size with TB/PB.
- Store each artifact's own expiry (expires_at) instead of a shared
stored_at; prune by per-entry expiry on store and enforce it on
resolve. Previously a short-TTL store could evict long-TTL entries and
expired handles stayed resolvable until the next write.
- Derive the artifact scope from the executor's crew or the agent's crew
so the native and ReAct paths agree with the crew-id Crew passes to
clear_artifact_scope, preventing crew-bound artifacts from lingering
under a task scope until TTL.
The handle regex matches hex case-insensitively, but store keys are
lowercase uuid4 strings. Normalize the captured uuid to lowercase before
lookup so a handle echoed by the model with uppercase hex still resolves
to its bytes instead of leaking the raw token to the downstream tool.
Binary file data (PPTX, PDF, images) returned by one tool and echoed by
the model as a base64 argument to another tool drifts by a few characters,
invalidating the base64 and corrupting the resulting file.
Tools can now return a FileArtifact instead of a base64 string. The agent
executor stores the bytes out-of-band (execution-scoped, TTL-backed) and
shows the model a short, namespaced `crewai+file://` handle, expanding it
back to exact base64 just before the consuming tool runs. Wired into the
native (default AgentExecutor + legacy) and ReAct execution paths with
per-run cleanup.
Centralize FlowTrigger and FlowMethodDecorator so start/listen/router and the boolean trigger helpers share one authoring contract. This preserves decorated method signatures for static checking while allowing route-label strings in nested FlowCondition data.
Export the shared typing helpers for static analyzers, use an explicit Protocol body, align condition validation with Sequence-backed condition data, and drop the stale call-arg ignore exposed by the signature-preserving decorators.
Update the flow guide to use or_(...) for multi-label listeners.
* feat(lock_store): make locking backend overridable
Allow the centralised lock factory to use a pluggable backend instead of
the hardcoded Redis/file selection. Backends are resolved with precedence
override > CREWAI_LOCK_FACTORY env > built-in default:
- set_lock_backend()/reset_lock_backend() and a scoped lock_backend()
context manager for programmatic overrides
- CREWAI_LOCK_FACTORY="module:callable" env import-path, resolved lazily
and cached, with clear errors on malformed or non-callable specs
- LockBackend Protocol documenting the contract (raw name in, context
manager out; backend owns its namespacing)
Default Redis/file behavior is unchanged when nothing is overridden.
* refactor(lock_store): use explicit body for LockBackend protocol method
Replace the no-op `...` body with `raise NotImplementedError` to satisfy
the CodeQL ineffectual-statement check while keeping the Protocol
structural-typing only.
* refactor(lock_store): drop scoped lock_backend context manager
Keep the backend overridable via set_lock_backend/reset_lock_backend and
the CREWAI_LOCK_FACTORY env path, but remove the scoped lock_backend()
context manager. It was speculative surface and the only thread-unsafe
piece (racy save/restore of the module global); nothing depends on it.
* refactor(lock_store): drop reset_lock_backend alias
reset_lock_backend() was just set_lock_backend(None); callers use that
directly. Clearing the override is documented on set_lock_backend.
* style(lock_store): apply ruff format
* refactor(lock_store): simplify overridable backend to a single setter
Reduce the override surface to just set_lock_backend(): lock() uses the
custom backend when one is set, otherwise the unchanged Redis/file default.
Drop the CREWAI_LOCK_FACTORY env import-path, the runtime_checkable
Protocol, the precedence resolver, and the getter — a custom backend is
now any callable(name, *, timeout) -> context manager, registered in
process.
* fix(lock_store): snapshot backend to avoid check-then-call race
Read the module-global backend once into a local before the None check
and the call, so a concurrent set_lock_backend(None) cannot make lock()
invoke None.
* docs(lock_store): clarify name handling for custom backends
The default namespaces the lock name; custom backends receive it
verbatim. Correct the lock() docstring which implied namespacing always
happens.
* docs(lock_store): note set_lock_backend is for one-time startup setup
The Flow DSL lived in one 1033-line `dsl.py` that mixed every decorator
(`@start`/`@listen`/`@router`), the `human_feedback` decorator,
condition combinators, and FlowDefinition extraction helpers in a single
file.
Split it into a `dsl/` package where each decorator gets its own module
(`start.py` 68 lines, `listen.py` 55, `router.py` 164,
`human_feedback.py` 98) and the shared extraction/condition helpers stay
in `utils.py`. The public API is re-exported from `dsl/__init__.py`, so
import paths are unchanged.
This is simpler because each decorator is now read and changed in
isolation instead of scanning a 1000-line file to find one of them, and
router-specific annotation parsing no longer sits next to unrelated
start/listen logic.
* Build FlowDefinition from Flow DSL metadata
Introduce `FlowDefinition`, a serializable model built from the Flow
DSL's runtime metadata. It becomes the structural contract for Flow
methods, triggers, routers, state, and configuration.
The visualization layer is the first consumer: `flow_structure` and
`build_flow_structure` now project from the definition instead of
re-introspecting the class. The runner still executes from live
registries, but the definition gives future runners a single static
contract to read.
This replaces AST source parsing for router return values, crew
references, and state schema with runtime metadata plus explicit
`@router(paths=...)` or `Literal`/`Enum` return hints. AST parsing was
fragile and could silently fail for dynamic or non-inspectable methods.
The refactor removes obsolete introspection and serializer code:
* Delete `flow_serializer.py`, `flow/utils.py`, and
`visualization/schema.py`
* Move flow structure modeling into `flow_definition.py`
* Simplify visualization building around the static definition contract
* Format files
* feat: add conversational flows documentation and chat session support
- Introduced a new guide for building multi-turn chat applications using , detailing session management and message handling.
- Added class to facilitate chat interactions, including streaming support and event handling.
- Implemented for class-level defaults and improved input normalization for conversational turns.
- Enhanced event listeners to manage flow events and tracing more effectively, including support for nested crew executions.
- Added tests for conversational flow helpers and kickoff parameters to ensure functionality and reliability.
* linted
* feat: enhance flow event tracing and session management
- Updated TraceCollectionListener to handle nested flows without re-claiming parent session batches.
- Ensured that method execution events are always emitted for tracing, regardless of flow event suppression.
- Improved finalization logic for flow trace batches to respect session deferral flags.
- Added tests to verify that method execution events are emitted correctly when flow events are suppressed and that deferred session finalization is respected in nested flows.
* updated docs
* feat: introduce experimental conversational flow framework
- Added a new module for conversational flow, including classes for managing conversation state, messages, and events.
- Implemented and for structured intent handling and routing.
- Enhanced the class to support turn-oriented conversational applications with built-in routing and message handling.
- Updated to include new classes in the public API.
- Added tests to validate the functionality of the new conversational flow features.
* handled docs
* feat(flow): enhance conversational flow handling and tracing
- Introduced support for deferred multi-turn tracing to maintain continuous event sequences.
- Updated method to delegate to restored checkpoint flows, improving session management.
- Added tests to validate the new tracing behavior and ensure correct event handling in conversational flows.
* fix multimodal test
* better conversational
* adjusted prompt
* drop unused
* fix test
* refactor: rename to and update related documentation
This commit refactors the class to for clarity and consistency across the codebase. The documentation has been updated to reflect this change, ensuring that references to the new class are accurate. Additionally, the alias for legacy imports is maintained for backward compatibility. The changes enhance the overall structure and readability of the conversational flow implementation.
* fix test
* adding experimetnal indicators
* fix test and reloaded cassettes
* cleanup ConversationalFlow class
* addressing double finalization and fixed tests
* improve on emphemeral tracing and adddressing comments
* Handle Snowflake Claude stringified tool calls
* Fix Snowflake tool id type narrowing
* Extract Snowflake tool result text in summaries
* Bump PyJWT for vulnerability scan
---------
Co-authored-by: João Moura <joaomdmoura@gmail.com>
* docs: add Databricks integration guide to enterprise integrations
Add documentation for connecting CrewAI agents to Databricks via the
Databricks managed MCP servers. Highlights Genie, Databricks SQL, Unity
Catalog Functions, and Vector Search, each configured as a separate MCP
connection, and covers OAuth/PAT setup. Includes ko, pt-BR, and ar
translations and registers the page in all docs.json navigation blocks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: use locale-specific slugs for Databricks nav entries
Add databricks integration entries to pt-BR, ko, and ar nav blocks
using locale-specific prefixes instead of only having en/ entries.
Co-authored-by: Luzk <2128595+Luzk@users.noreply.github.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Iris <iris@crewai.com>
Co-authored-by: Luzk <2128595+Luzk@users.noreply.github.com>
Co-authored-by: Greyson LaLonde <greyson.r.lalonde@gmail.com>
Co-authored-by: Lucas Gomide <lucaslg200@gmail.com>
The previous discard-after-body approach cleared the gate mid-wave, so
a slow parallel @start finishing after the listener body could re-fire
the same multi-source or_ listener. Re-arm only when a router emits a
signal that matches the listener's condition; parallel @start paths
never reach that branch and the race gate keeps protecting them.
Closes#5972
This commit separates the monolithic `flow.py` into three modules, each
with one job:
- `dsl.py` - the Python DSL for flows (@start/@listen/@router, or_/and_)
- `flow_definition.py` - the structural model extracted from the DSL
- `runtime.py` - the execution engine and state for flows
This phase moves code only and should not have any breaking changes.
uv 0.11.7 -> 0.11.17 patches GHSA-4gg8-gxpx-9rph. chromadb has no
patched release for GHSA-f4j7-r4q5-qw2c (server-only pre-auth RCE,
not reachable in our embedded use); ignore until upstream ships a fix.
* docs: add Snowflake integration guide to enterprise integrations
Add documentation for connecting CrewAI agents to Snowflake via the
Snowflake-managed MCP server. Highlights Cortex Analyst, Cortex Search,
and SQL execution, and covers OAuth/PAT setup. Registers the page in
all docs.json navigation blocks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs: add Snowflake integration page for ko, ar, pt-BR
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Iris Clawd <iris@crewai.com>
Moves the registry/cache pieces of PR #5867 under crewai.experimental.skills
and the CLI commands under `crewai experimental skill`. The stable local-file
skills feature (loader, parser, validation, models) stays in crewai.skills.
Both entry points now require CREWAI_EXPERIMENTAL=1:
- resolve_registry_ref() calls require_experimental_skills() before resolving
- The `crewai experimental` CLI group raises UsageError when the flag is unset
SkillDownloadStarted/CompletedEvent move out of crewai.events.types.skill_events
into crewai.experimental.skills.events.
* refactor(skills): move 'version' off SkillFrontmatter into metadata
The skill version is now stored as `metadata.version` rather than a
top-level field on `SkillFrontmatter`. A `before` validator lifts any
top-level YAML `version:` into `metadata['version']` so existing SKILL.md
files keep parsing.
- Adds an <Info> "ACP (Beta) Docs Navigation" block at the top of every
Agent Control Plane page so readers can jump between Overview,
Monitoring, and Rules without scrolling to the bottom-of-page Related
cards.
* feat: enhance StdioTransport to prevent environment variable leakage
- Replaced os.environ.copy() with get_default_environment() to ensure only allowed environment variables are passed to the MCP server.
- Added tests to verify that ambient environment variables do not leak and that user-supplied environment variables can override defaults.
* feat: add environment variable filtering hook to StdioTransport
- Introduced an optional `_env_filter_hook` to allow extensions to modify the environment variables passed to MCP servers, enabling features like credential stripping.
- Updated tests to ensure the filtering hook is applied correctly after merging user-supplied and default environment variables.
* Fix structured output leaks in tool-calling loops
* addressing comments
* drop scripts
* Update Gemini agent tests to include structured output with thoughts and bump model version to 2.5-flash
* merge
* Update Anthropic test cases to use new model and tool structure
- Changed the model from "claude-3-5-haiku-20241022" to "claude-sonnet-4-6" in the test setup.
- Updated the request and response formats in the YAML test cassette to reflect the new tool structure and improved content formatting.
- Adjusted the expected response body to match the new output format from the assistant, including changes in tool usage and response details.
- Increased rate limit values in the response headers for better testing scenarios.
* adjusted bedrock cassettes
* adjusting cassettes for bedrock
* fix test
* Update VCR configuration to use 'host' instead of 'bedrock_host' for request matching
* docs: document one-time admin package install step
The previous revision described a manual "install in Salesforce first,
then connect from AMP" flow that nobody actually follows, and linked to
a private repo customers can't access.
* docs: point Integrations link at crewai_plus/unified_tools