From 44b92ef12f5f47f328267eedcc3d4c53a869de6c Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 19 Jan 2025 07:42:38 +0000 Subject: [PATCH 1/4] fix: ensure persisted state overrides class defaults - Remove early return in Flow.__init__ to allow proper state initialization - Add test_flow_default_override.py to verify state override behavior - Fix issue where default values weren't being overridden by persisted state Fixes the issue where persisted state values weren't properly overriding class defaults when restarting a flow with a previously saved state ID. Co-Authored-By: Joe Moura --- src/crewai/flow/flow.py | 8 ++--- tests/test_flow_default_override.py | 53 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 tests/test_flow_default_override.py diff --git a/src/crewai/flow/flow.py b/src/crewai/flow/flow.py index ad91d1236..dc8e862f4 100644 --- a/src/crewai/flow/flow.py +++ b/src/crewai/flow/flow.py @@ -492,12 +492,8 @@ class Flow(Generic[T], metaclass=FlowMeta): ) elif kwargs and "id" in kwargs: stored_state = self._persistence.load_state(kwargs["id"]) - if not stored_state: - # For kwargs["id"], we allow creating new state if not found - self._state = self._create_initial_state() - if kwargs: - self._initialize_state(kwargs) - return + # Don't return early if state not found - let the normal initialization flow handle it + # This ensures proper state initialization and override behavior # Initialize state based on persistence and kwargs if stored_state: diff --git a/tests/test_flow_default_override.py b/tests/test_flow_default_override.py new file mode 100644 index 000000000..495a3edf9 --- /dev/null +++ b/tests/test_flow_default_override.py @@ -0,0 +1,53 @@ +"""Test that persisted state properly overrides default values.""" + +import os +from typing import Optional + +import pytest +from pydantic import BaseModel + +from crewai.flow.flow import Flow, FlowState, start +from crewai.flow.persistence import persist +from crewai.flow.persistence.sqlite import SQLiteFlowPersistence + + +class PoemState(FlowState): + """Test state model with default values that should be overridden.""" + sentence_count: int = 1000 # Default that should be overridden + poem: str = "" + + +def test_default_value_override(tmp_path): + """Test that persisted state values override class defaults.""" + db_path = os.path.join(tmp_path, "test_flows.db") + persistence = SQLiteFlowPersistence(db_path) + + @persist(persistence) + class PoemFlow(Flow[PoemState]): + initial_state = PoemState + + @start() + def set_sentence_count(self): + # First run will set a custom value + if not self.state.sentence_count or self.state.sentence_count == 1000: + self.state.sentence_count = 2 + + # First run - should set sentence_count to 2 + # First run - should set sentence_count to 2 + flow1 = PoemFlow(persistence=persistence) + flow1.kickoff() + original_uuid = flow1.state.id + assert flow1.state.sentence_count == 2 + + # Second run - should load sentence_count=2 instead of default 1000 + flow2 = PoemFlow(persistence=persistence) + flow2.kickoff(inputs={"id": original_uuid}) + assert flow2.state.sentence_count == 2 # Should load 2, not default 1000 + + # Third run - explicit override should work + flow3 = PoemFlow( + persistence=persistence, + id=original_uuid, + sentence_count=3, # Override persisted value + ) + assert flow3.state.sentence_count == 3 # Should use override value From 4f4f229a0b0516dab425d501053f7ef55273bf39 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 19 Jan 2025 08:28:58 +0000 Subject: [PATCH 2/4] test: improve state restoration verification with has_set_count flag Co-Authored-By: Joe Moura --- tests/test_flow_default_override.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_flow_default_override.py b/tests/test_flow_default_override.py index 495a3edf9..099fc5bee 100644 --- a/tests/test_flow_default_override.py +++ b/tests/test_flow_default_override.py @@ -28,9 +28,10 @@ def test_default_value_override(tmp_path): @start() def set_sentence_count(self): - # First run will set a custom value - if not self.state.sentence_count or self.state.sentence_count == 1000: + # Only set sentence_count on first run, not when loading from persistence + if not self.state.has_set_count: self.state.sentence_count = 2 + self.state.has_set_count = True # First run - should set sentence_count to 2 # First run - should set sentence_count to 2 From db626ec99d514aeccb0b7e032db15b5071664a82 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 19 Jan 2025 08:30:38 +0000 Subject: [PATCH 3/4] test: add has_set_count field to PoemState Co-Authored-By: Joe Moura --- tests/test_flow_default_override.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_flow_default_override.py b/tests/test_flow_default_override.py index 099fc5bee..28053c249 100644 --- a/tests/test_flow_default_override.py +++ b/tests/test_flow_default_override.py @@ -15,6 +15,7 @@ class PoemState(FlowState): """Test state model with default values that should be overridden.""" sentence_count: int = 1000 # Default that should be overridden poem: str = "" + has_set_count: bool = False # Track whether we've set the count def test_default_value_override(tmp_path): From b75ef482bf660499c5057a910a45693f3d6f77af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moura?= Date: Sun, 19 Jan 2025 00:46:26 -0800 Subject: [PATCH 4/4] refactoring test --- tests/test_flow_default_override.py | 44 +++++++++++++++++------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/tests/test_flow_default_override.py b/tests/test_flow_default_override.py index 28053c249..b2bcfa9c5 100644 --- a/tests/test_flow_default_override.py +++ b/tests/test_flow_default_override.py @@ -14,42 +14,50 @@ from crewai.flow.persistence.sqlite import SQLiteFlowPersistence class PoemState(FlowState): """Test state model with default values that should be overridden.""" sentence_count: int = 1000 # Default that should be overridden - poem: str = "" has_set_count: bool = False # Track whether we've set the count -def test_default_value_override(tmp_path): +def test_default_value_override(): """Test that persisted state values override class defaults.""" - db_path = os.path.join(tmp_path, "test_flows.db") - persistence = SQLiteFlowPersistence(db_path) - - @persist(persistence) + + @persist() class PoemFlow(Flow[PoemState]): initial_state = PoemState - + @start() def set_sentence_count(self): + print("Setting sentence count") + print(self.state) # Only set sentence_count on first run, not when loading from persistence - if not self.state.has_set_count: + if self.state.has_set_count and self.state.sentence_count == 2: + self.state.sentence_count = 3 + elif self.state.has_set_count and self.state.sentence_count == 1000: + self.state.sentence_count = 1000 + elif self.state.has_set_count and self.state.sentence_count == 5: + self.state.sentence_count = 5 + else: self.state.sentence_count = 2 self.state.has_set_count = True - + # First run - should set sentence_count to 2 - # First run - should set sentence_count to 2 - flow1 = PoemFlow(persistence=persistence) + flow1 = PoemFlow() flow1.kickoff() original_uuid = flow1.state.id assert flow1.state.sentence_count == 2 - + # Second run - should load sentence_count=2 instead of default 1000 - flow2 = PoemFlow(persistence=persistence) + flow2 = PoemFlow() flow2.kickoff(inputs={"id": original_uuid}) - assert flow2.state.sentence_count == 2 # Should load 2, not default 1000 - + assert flow2.state.sentence_count == 3 # Should load 2, not default 1000 + + # Third run - should not load sentence_count=2 instead of default 1000 + flow2 = PoemFlow() + flow2.kickoff(inputs={"has_set_count": True}) + assert flow2.state.sentence_count == 1000 # Should load 1000, not 2 + # Third run - explicit override should work flow3 = PoemFlow( - persistence=persistence, id=original_uuid, - sentence_count=3, # Override persisted value + sentence_count=5, # Override persisted value ) - assert flow3.state.sentence_count == 3 # Should use override value + assert flow3.state.sentence_count == 5 # Should use override value