fix: auto-restore persisted state for class-level @persist decorator#5379
fix: auto-restore persisted state for class-level @persist decorator#5379devin-ai-integration[bot] wants to merge 4 commits intomainfrom
Conversation
When @persist is applied at the class level, new flow instances now automatically load the most recent persisted state for that flow class. This matches the documented behavior where creating a new instance of a @persist-decorated flow seamlessly continues from the previous run's state. Changes: - Add load_latest_by_class() to FlowPersistence base class - Implement load_latest_by_class() in SQLiteFlowPersistence with flow_class column and index for efficient lookups - Store flow class name when persisting state via PersistenceDecorator - Auto-restore latest state in class-level @persist decorator's __init__ - Add migration for existing databases (ALTER TABLE ADD COLUMN) Fixes #5378 Co-Authored-By: João <joao@crewai.com>
|
Prompt hidden (unlisted session) |
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Co-Authored-By: João <joao@crewai.com>
Co-Authored-By: João <joao@crewai.com>
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 378b59a. Configure here.
| flow_uuid=flow_uuid, | ||
| method_name=method_name, | ||
| state_data=state_data, | ||
| flow_class=flow_class_name, |
There was a problem hiding this comment.
Missing TypeError fallback breaks custom persistence backends
High Severity
The persist_state decorator now passes flow_class to persistence_instance.save_state without a fallback for custom FlowPersistence implementations. This causes a TypeError that's re-raised as an uncaught RuntimeError, crashing flows using custom backends. A TypeError fallback was claimed but not implemented.
Reviewed by Cursor Bugbot for commit 378b59a. Configure here.
Co-Authored-By: João <joao@crewai.com>


Summary
Fixes #5378. When
@persistis applied at the class level, new flow instances now automatically load the most recent persisted state for that flow class. Previously, the documentedPersistentCounterFlowexample didn't work — users had to manually passinputs={"id": old_uuid}tokickoff()to restore state, contradicting the docs.How it works:
flow_classcolumn is added to theflow_statesSQLite table, populated withtype(flow_instance).__name__on each save.load_latest_by_class(flow_class)method is added toFlowPersistence(default returnsNone) and implemented inSQLiteFlowPersistence.@persistdecorator's__init__wrapper now callsload_latest_by_classafter initialization and restores state if found.@persistis not affected — it continues to only save, not auto-restore.save_statepassesflow_classas a kwarg with aTypeErrorfallback for backends that don't accept it.Includes DB migration (
ALTER TABLE ADD COLUMN) for existing databases and a new index onflow_class.Review & Testing Checklist for Human
@persistwill now auto-load state on new instances. If anyone relied on fresh state each run with class-level@persist, this is a breaking change. Verify this is the intended behavior.__name__only (not fully qualified). Two flow classes with the same name in different modules sharing the same DB would collide. Decide if__qualname__ormodule + qualnameis needed instead.persist_state: The try/except that catchesTypeErrorwhen passingflow_classto custom backends could mask unrelatedTypeErrorbugs. Review whether this is acceptable or if a more targeted check (e.g.inspect.signature) would be safer.save_pending_feedbackdoes not populateflow_class: States saved via the HITL pending feedback path won't be found byload_latest_by_class. Verify this is acceptable.uv run pytest lib/crewai/tests/test_flow_persistence.py -vvto verify all 12 tests pass. Consider also testing with an existing SQLite DB (without theflow_classcolumn) to validate the migration path.Notes
FlowPersistence.load_latest_by_class()returnsNoneby default, so custom persistence implementations are unaffected unless they opt in.Link to Devin session: https://app.devin.ai/sessions/47c270d8584548d4a2683b7d021eb8d5
Note
Medium Risk
Behavior changes for any existing class-level
@persistusers (new instances may start with restored state instead of a fresh state). Includes a SQLite schema migration and new lookup path keyed by class name, which could cause unexpected restores if names collide or data is incompatible.Overview
Enables automatic state restoration when
@persistis applied at the class level by loading the most recent persisted state for that flow class during__init__and calling_restore_state(failures are swallowed with debug logging).Extends the persistence API to pass an optional
flow_classintosave_state, addsFlowPersistence.load_latest_by_class()(no-op by default), and implements it inSQLiteFlowPersistenceby migrating/adding aflow_classcolumn + index onflow_statesand querying the latest row by class. Adds comprehensive tests covering class-level auto-restore for typed and dict state, isolation between different flow classes, and confirming method-level@persistdoes not auto-restore.Reviewed by Cursor Bugbot for commit 327a5c4. Bugbot is set up for automated code reviews on this repo. Configure here.