Add script/code block action to FlowDefinition#6197
Conversation
📝 WalkthroughWalkthroughAdds a ChangesScript Action Feature
Sequence Diagram(s)sequenceDiagram
participant FlowRunner
participant build_action
participant ScriptAction
participant outputs_by_name
participant _flow_script
FlowRunner->>build_action: FlowScriptActionDefinition(code=...)
build_action->>ScriptAction: construct ScriptAction
ScriptAction->>ScriptAction: ast.parse(code) + exec wrapper
Note over ScriptAction: Compiled _flow_script function created
build_action-->>FlowRunner: ScriptAction instance
Note over FlowRunner: At invocation time
FlowRunner->>ScriptAction: run(...)
ScriptAction->>outputs_by_name: flow._method_outputs + local_context["outputs"]
outputs_by_name-->>ScriptAction: dict[str, Any]
ScriptAction->>_flow_script: (state, outputs, input, item)
_flow_script-->>ScriptAction: return value
ScriptAction-->>FlowRunner: result
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~28 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
fa2edd7 to
218696f
Compare
69e5eb5 to
b69e5cc
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/crewai/src/crewai/flow/runtime/_actions.py`:
- Around line 167-173: The exec(compile(...)) call that executes the script
source needs to be gated behind an explicit safety check that is disabled by
default. Add a configuration option or flag (disabled by default) that must be
explicitly enabled to allow script execution. Before the exec(compile(source,
namespace["__name__"], "exec"), namespace) call, check if this unsafe opt-in
flag is enabled, and if not, raise an exception or warning that indicates script
execution is disabled and requires explicit opt-in. This way, the code follows a
fail-closed security pattern where script execution is blocked unless explicitly
allowed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a2d486de-8242-424b-812f-d94adcf05e5f
📒 Files selected for processing (6)
lib/crewai/src/crewai/flow/flow_definition.pylib/crewai/src/crewai/flow/runtime/_actions.pylib/crewai/src/crewai/flow/runtime/_expressions.pylib/crewai/src/crewai/flow/runtime/_outputs.pylib/crewai/tests/test_flow_definition.pylib/crewai/tests/test_flow_from_definition.py
b69e5cc to
d96695b
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d96695b. Configure here.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/crewai/src/crewai/flow/runtime/_actions.py`:
- Around line 174-190: The ast.FunctionDef constructor is being called with the
type_params parameter unconditionally, but this parameter was only introduced in
Python 3.12, causing TypeError on Python 3.10 and 3.11. Modify the
ast.FunctionDef call to conditionally include the type_params parameter only
when running on Python 3.12 or later by checking the Python version using
sys.version_info before constructing the FunctionDef object, and only include
type_params=[] when the version check passes.
In `@lib/crewai/tests/test_flow_from_definition.py`:
- Around line 1148-1164: The test_script_action_requires_explicit_opt_in
function assumes the CREWAI_ALLOW_FLOW_SCRIPT_EXECUTION environment variable is
unset, but if it's pre-set by the test runner, the test will fail
nondeterministically. Modify the test to explicitly control the environment
variable state by using pytest's monkeypatch fixture to ensure the variable is
unset before running the Flow.from_definition call, and allow monkeypatch to
automatically restore the original state after the test completes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: fcd735ca-795b-45f9-83a0-02a3254d4a52
📒 Files selected for processing (7)
lib/crewai/src/crewai/flow/flow_definition.pylib/crewai/src/crewai/flow/runtime/_actions.pylib/crewai/src/crewai/flow/runtime/_expressions.pylib/crewai/src/crewai/flow/runtime/_outputs.pylib/crewai/tests/test_checkpoint.pylib/crewai/tests/test_flow_definition.pylib/crewai/tests/test_flow_from_definition.py
✅ Files skipped from review due to trivial changes (1)
- lib/crewai/tests/test_flow_definition.py
🚧 Files skipped from review as they are similar to previous changes (2)
- lib/crewai/src/crewai/flow/runtime/_expressions.py
- lib/crewai/src/crewai/flow/flow_definition.py
d96695b to
386a165
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
lib/crewai/src/crewai/flow/runtime/__init__.py (1)
1093-1094: ⚡ Quick winNarrow the fail-fast exception to script opt-in failures.
Re-raising every
RuntimeErrorchanges unrelated action-build failures from the existing unresolved-action aggregation into immediate failures. Use a script-specificRuntimeErrorsubclass so only the env-gate failure bypassesunresolved.Proposed targeted exception
# lib/crewai/src/crewai/flow/runtime/_actions.py _ALLOW_SCRIPT_EXECUTION_ENV_VAR = "CREWAI_ALLOW_FLOW_SCRIPT_EXECUTION" _TRUSTED_SCRIPT_EXECUTION_VALUES = frozenset({"1", "true", "yes"}) + + +class FlowScriptExecutionDisabledError(RuntimeError): + """Raised when inline flow script execution is not explicitly enabled."""# lib/crewai/src/crewai/flow/runtime/_actions.py - raise RuntimeError( + raise FlowScriptExecutionDisabledError( "Flow script execution is disabled by default. " f"Set {_ALLOW_SCRIPT_EXECUTION_ENV_VAR}=1 to enable it only for " "trusted flow definitions." )# lib/crewai/src/crewai/flow/runtime/__init__.py -from crewai.flow.runtime._actions import build_action +from crewai.flow.runtime._actions import ( + FlowScriptExecutionDisabledError, + build_action, +)# lib/crewai/src/crewai/flow/runtime/__init__.py - except RuntimeError: + except FlowScriptExecutionDisabledError: raise🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/crewai/src/crewai/flow/runtime/__init__.py` around lines 1093 - 1094, The except clause at lines 1093-1094 is catching and re-raising all RuntimeError exceptions, which causes unrelated action-build failures to bypass the unresolved action aggregation logic instead of being collected. Create a script-specific RuntimeError subclass (e.g., ScriptRuntimeError or similar) and modify the except clause to only catch and re-raise that specific subclass. This ensures that only env-gate failures that raise the script-specific exception will trigger immediate failure, while other RuntimeError instances will continue through the existing aggregation logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@lib/crewai/src/crewai/flow/runtime/__init__.py`:
- Around line 1093-1094: The except clause at lines 1093-1094 is catching and
re-raising all RuntimeError exceptions, which causes unrelated action-build
failures to bypass the unresolved action aggregation logic instead of being
collected. Create a script-specific RuntimeError subclass (e.g.,
ScriptRuntimeError or similar) and modify the except clause to only catch and
re-raise that specific subclass. This ensures that only env-gate failures that
raise the script-specific exception will trigger immediate failure, while other
RuntimeError instances will continue through the existing aggregation logic.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 1062677d-4525-4ade-afaa-8d712e8f3cbd
📒 Files selected for processing (8)
lib/crewai/src/crewai/flow/flow_definition.pylib/crewai/src/crewai/flow/runtime/__init__.pylib/crewai/src/crewai/flow/runtime/_actions.pylib/crewai/src/crewai/flow/runtime/_expressions.pylib/crewai/src/crewai/flow/runtime/_outputs.pylib/crewai/tests/test_checkpoint.pylib/crewai/tests/test_flow_definition.pylib/crewai/tests/test_flow_from_definition.py
✅ Files skipped from review due to trivial changes (1)
- lib/crewai/tests/test_flow_definition.py
🚧 Files skipped from review as they are similar to previous changes (5)
- lib/crewai/src/crewai/flow/runtime/_expressions.py
- lib/crewai/tests/test_flow_from_definition.py
- lib/crewai/tests/test_checkpoint.py
- lib/crewai/src/crewai/flow/flow_definition.py
- lib/crewai/src/crewai/flow/runtime/_outputs.py
386a165 to
78fdf4c
Compare
78fdf4c to
adcebc8
Compare
Let a Flow method run trusted inline Python with `call: script`. The code
is compiled once into a generated function and receives the runtime
values as arguments.
```yaml
methods:
normalize:
start: true
do:
call: script
code: |
import math
state["rounded"] = math.ceil(state["raw_score"])
return f"rounded:{state['rounded']}"
```
Even though this shares the same surface of tools (custom code), I
decided to make it opt-in for now, using
`CREWAI_ALLOW_FLOW_SCRIPT_EXECUTION=1`.
adcebc8 to
5efd07c
Compare

Let a Flow method run trusted inline Python with
call: script. The code is compiled once into a generated function and receives the runtime values as arguments.Even though this shares the same surface of tools (custom code), I decided to make it opt-in for now, using
CREWAI_ALLOW_FLOW_SCRIPT_EXECUTION=1.Note
High Risk
Introduces arbitrary trusted Python execution via flow YAML when an env var is set; misconfiguration or untrusted definitions could run hostile code with full process privileges (not sandboxed).
Overview
Adds a new
call: scriptflow method action so YAML/JSON definitions can run trusted inline Python without a separate importablecoderef. The schema introducesFlowScriptActionDefinition(code, optionallanguage: python), wired throughScriptActionin the runtime action builder alongside existing expression/crew/tool actions.At build time, script source is parsed with
ast, wrapped in a generated_flow_script(state, outputs, input, item)function, andexec’d once. Runtime values are passed as arguments (not string-interpolated into the source). Scripts can mutate flow state, read prior step outputs, listener trigger input, andeachiterationitem.Security: execution is off by default. Enabling requires
CREWAI_ALLOW_FLOW_SCRIPT_EXECUTION=1(alsotrue/yes). Without it,Flow.from_definitionraisesFlowScriptExecutionDisabledErrorexplicitly instead of treating the method as an unresolvable action.Refactor: method output naming/merging for CEL and scripts is centralized in new
outputs_by_name(_outputs.py), replacing duplicated logic in_expressions.py.Reviewed by Cursor Bugbot for commit 5efd07c. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
New Features
call: "script"action type. Scripts can access and modify flow state, read outputs from previous steps, and process inputs/items, with security controls requiring explicit opt-in via environment variable.Improvements