Skip to content

Split flow.py into DSL, definition, and runtime#5997

Merged
vinibrsl merged 1 commit into
mainfrom
refactor/flow-separate-concerns
Jun 1, 2026
Merged

Split flow.py into DSL, definition, and runtime#5997
vinibrsl merged 1 commit into
mainfrom
refactor/flow-separate-concerns

Conversation

@vinibrsl
Copy link
Copy Markdown
Member

@vinibrsl vinibrsl commented Jun 1, 2026

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.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a complete flow authoring DSL and analysis infrastructure. The changes add public decorators for defining flow methods (start, listen, router), condition combinators (or_, and_), AST-based inference for router return paths, and graph traversal utilities for flow structure analysis, with a refactored utils module and updated test patches.

Changes

Flow DSL and Analysis Infrastructure

Layer / File(s) Summary
Flow DSL Decorators and Condition Combinators
lib/crewai/src/crewai/flow/dsl.py
Introduces start, listen, and router decorators that wrap methods in typed wrapper classes and parse condition arguments (method-name strings, condition dicts with nested "conditions" or direct "methods", or callable references). Condition combinators or_ and and_ normalize variadic inputs into FlowCondition dicts with appropriate semantics, converting callables to names and validating entries.
AST-based Router Path Inference
lib/crewai/src/crewai/flow/flow_definition.py (lines 1–406)
Implements AST helpers: _extract_string_literals_from_type_annotation extracts string constants from Literal[...], unions, and Enum types; _unwrap_function peels decorator wrappers; get_possible_return_constants parses router function source with AST to infer possible string return values from direct returns, dict lookups, variable/attribute constants, conditional branches, and limited class-context comparisons.
Flow Graph Analysis and Relationships
lib/crewai/src/crewai/flow/flow_definition.py (lines 408–740)
Adds graph utilities: calculate_node_levels computes BFS-like hierarchical levels from start methods across listener OR/AND triggers and router paths; count_outgoing_edges tallies outgoing listener-trigger edges; build_ancestor_dict/dfs_ancestors produce ancestor sets; build_parent_children_dict, get_child_index, and process_router_paths support parent→children mapping and router path processing.
Flow Definition Extraction and Validation
lib/crewai/src/crewai/flow/flow_definition.py (lines 741–1041)
Defines runtime type guards for method names, callables, condition structures, and flow method wrappers; includes condition-tree normalization and _extract_all_methods_recursive; implements extract_flow_definition to gather start_methods, listeners, routers, and router_paths (using explicit __router_paths__ or AST-inferred constants).
Backwards Compatible Utils Refactoring
lib/crewai/src/crewai/flow/utils.py
Replaces the previous implementations with a shim that imports and re-exports flow analysis utilities from crewai.flow.flow_definition via __all__.
Test Event Bus Patch Updates
lib/crewai/tests/test_async_human_feedback.py
Updates eleven test locations to patch crewai.flow.runtime.crewai_event_bus.emit instead of crewai.flow.flow.crewai_event_bus.emit.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 A new DSL blooms with decorators bright,
AST whispers secrets deep at night,
Graphs dance with nodes and edges true,
Flow definition made fresh and new!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main refactoring: splitting a monolithic flow module into three separate modules (DSL, definition, and runtime).
Docstring Coverage ✅ Passed Docstring coverage is 93.88% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/flow-separate-concerns

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread lib/crewai/src/crewai/flow/flow_definition.py Dismissed
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.
@vinibrsl vinibrsl force-pushed the refactor/flow-separate-concerns branch from cee9f7b to 1c7b61a Compare June 1, 2026 18:39
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 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/dsl.py`:
- Around line 1-320: This file fails Ruff formatting; run the formatter and
commit the changes so CI passes—invoke the ruff formatter (e.g., `ruff format
lib/crewai/src/crewai/flow/dsl.py` or `uv run ruff format --package lib`) and
stage the modified file; ensure formatting changes cover the decorator functions
and combinators (start, listen, router, or_, and and_) and their
docstrings/signatures, then re-run `uv run ruff format --check lib/` to confirm
CI will succeed.

In `@lib/crewai/src/crewai/flow/flow_definition.py`:
- Around line 587-603: The router-path branch (checking node in flow._routers
and iterating flow._router_paths) propagates ancestors[node] to listeners but
fails to include the router node itself; modify the dfs_ancestors logic so that
before merging ancestors[node] into ancestors[listener_name] you also add the
router node (node) as a direct ancestor (e.g., ensure ancestors[listener_name]
includes node along with ancestors[node]); update the block that handles
flow._router_paths within dfs_ancestors (references: flow._routers,
flow._router_paths, ancestors, dfs_ancestors, listener_name, node) and handle
the case where ancestors[node] may not yet exist.
- Around line 858-894: The helper _extract_all_methods_recursive currently
filters out any string not present in flow._methods when a flow is provided,
which strips router output labels needed by callers like process_router_paths,
build_parent_children_dict, and dfs_ancestors; change
_extract_all_methods_recursive to accept an optional flag (e.g.,
include_non_method_labels: bool = False) that, when true, returns string labels
even if they are not in flow._methods, and update the router-aware callers
(process_router_paths, build_parent_children_dict, dfs_ancestors) to call
_extract_all_methods_recursive(..., include_non_method_labels=True) so router
branches are preserved while keeping the default behavior unchanged for callers
that only want method names.
- Around line 178-181: get_possible_return_constants() currently calls
inspect.getsource(function) and uses function.__self__/__qualname__/__globals__
for class-context lookup which inspects the wrapper instead of the original
callable; update all introspection to use the already-computed unwrapped
variable: replace inspect.getsource(function) with inspect.getsource(unwrapped)
and change uses of function.__self__, function.__qualname__, and
function.__globals__ in the class-context lookup to unwrapped.__self__,
unwrapped.__qualname__, and unwrapped.__globals__ so AST/class resolution
operates on the real underlying function (note: leave any globals already taken
from unwrapped unchanged).
🪄 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: 50e554b4-1a29-4f90-906b-4a11415fea91

📥 Commits

Reviewing files that changed from the base of the PR and between 4dafb05 and cee9f7b.

📒 Files selected for processing (6)
  • lib/crewai/src/crewai/flow/dsl.py
  • lib/crewai/src/crewai/flow/flow.py
  • lib/crewai/src/crewai/flow/flow_definition.py
  • lib/crewai/src/crewai/flow/runtime.py
  • lib/crewai/src/crewai/flow/utils.py
  • lib/crewai/tests/test_async_human_feedback.py

Comment thread lib/crewai/src/crewai/flow/dsl.py
Comment thread lib/crewai/src/crewai/flow/flow_definition.py
Comment thread lib/crewai/src/crewai/flow/flow_definition.py
Comment thread lib/crewai/src/crewai/flow/flow_definition.py
@vinibrsl vinibrsl merged commit 1aba9fe into main Jun 1, 2026
59 checks passed
@vinibrsl vinibrsl deleted the refactor/flow-separate-concerns branch June 1, 2026 21:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants