Summary
The core SDK ships two independent copies of the workflow engine. praisonaiagents/memory/workflows.py (1,983 LOC) defines its own WorkflowContext, StepResult, the pattern helpers (Route, Parallel, Loop, Repeat, route, parallel, loop, repeat), a full Workflow class and a full WorkflowManager class. The canonical engine now lives in praisonaiagents/workflows/workflows.py (4,531 LOC) and is newer/feature-richer. This is duplicate logic with drift, not a feature.
This is a structural consolidation only — every public import path and behaviour is preserved.
Current behaviour
- Canonical engine:
praisonaiagents/workflows/workflows.py (4,531 LOC) — the version exported everywhere.
- Stale duplicate:
praisonaiagents/memory/workflows.py (1,983 LOC) — separate WorkflowContext/StepResult dataclasses, Workflow (lines ~182–719) and WorkflowManager (lines ~720–1968).
praisonaiagents/memory/__init__.py already re-exports all workflow symbols from ..workflows, not from memory.workflows:
praisonaiagents/memory/__init__.py:96 → from ..workflows import WorkflowManager
- lines 99–135 →
Workflow, Task, WorkflowContext, StepResult, Pipeline, Route, Parallel, Loop, Repeat, route, parallel, loop, repeat all sourced from ..workflows
- line 155 →
create_workflow_manager from ..workflows.workflows
- So
from praisonaiagents.memory import Workflow / WorkflowManager already resolves to the canonical engine. The 1,983 LOC file is reachable only via the explicit module path praisonaiagents.memory.workflows.
No production module imports memory.workflows. The only references are tests asserting the backward-compatible path still works:
tests/test_workflow_patterns.py:462 — from praisonaiagents.memory.workflows import (Workflow, Task, WorkflowContext, StepResult, route, parallel, loop, repeat)
tests/unit/test_paths_wiring.py:289+ — inspects workflows.WorkflowManager source for DEFAULT_DIR_NAME / _get_checkpoints_dir paths wiring.
Why it matters
- Maintenance: every workflow fix/feature must be applied in two places or silently diverge. The duplicate is already stale relative to
workflows/workflows.py (e.g. newer route/parallel/output_file parsing paths exist only in the canonical file).
- Correctness risk: a user importing via
praisonaiagents.memory.workflows gets the older implementation, while praisonaiagents.memory gives the newer one — same names, different behaviour.
Category
Duplicate logic
Capability preserved
from praisonaiagents.memory.workflows import Workflow, Task, WorkflowContext, StepResult, route, parallel, loop, repeat keeps working (backward-compatible path).
from praisonaiagents.memory import Workflow, Pipeline, WorkflowManager, ... keeps working (already routed to canonical).
- All workflow patterns (Route/Parallel/Loop/Repeat),
WorkflowManager, checkpoints, and paths-wiring behaviour unchanged.
Proposed approach
Turn memory/workflows.py into a thin re-export shim that imports the canonical symbols from praisonaiagents.workflows.workflows, deleting the duplicated bodies. This collapses ~2,000 LOC to a few lines while keeping the legacy import path alive.
Resolution sketch
# Before: praisonaiagents/memory/workflows.py (1,983 LOC)
@dataclass
class WorkflowContext: ...
class Workflow: ... # full duplicate body
class WorkflowManager: ... # full duplicate body
# After: praisonaiagents/memory/workflows.py (thin shim, same public names)
"""Backward-compatible re-export. Canonical engine lives in
praisonaiagents.workflows.workflows."""
from ..workflows.workflows import ( # noqa: F401
WorkflowContext, StepResult, Workflow, WorkflowManager,
Route, Parallel, Loop, Repeat,
route, parallel, loop, repeat,
create_workflow_manager,
)
from ..task.task import Task # noqa: F401
Severity
Medium
Validation
- Traced:
memory/__init__.py re-exports workflow symbols from ..workflows, never from memory.workflows; no production code imports memory.workflows.
- Confirmed the only consumers of the explicit module path are backward-compat tests (
tests/test_workflow_patterns.py, tests/unit/test_paths_wiring.py).
- Confirmed this is duplication/drift, not two intentional engines — both define the same public surface; the canonical one is the superset.
- Before merging, verify the canonical
workflows.WorkflowManager still satisfies tests/unit/test_paths_wiring.py (uses DEFAULT_DIR_NAME, no hard-coded ".praisonai/workflows", _get_checkpoints_dir routed through paths.py); if any wiring assertion is specific to the old copy, port it onto the canonical class as part of the shim change.
Keep unchanged
- The canonical
praisonaiagents/workflows/workflows.py engine and its full feature set.
- All public import paths (
praisonaiagents.memory, praisonaiagents.memory.workflows, praisonaiagents.workflows).
- Lazy-loading behaviour in
memory/__init__.py.
Summary
The core SDK ships two independent copies of the workflow engine.
praisonaiagents/memory/workflows.py(1,983 LOC) defines its ownWorkflowContext,StepResult, the pattern helpers (Route,Parallel,Loop,Repeat,route,parallel,loop,repeat), a fullWorkflowclass and a fullWorkflowManagerclass. The canonical engine now lives inpraisonaiagents/workflows/workflows.py(4,531 LOC) and is newer/feature-richer. This is duplicate logic with drift, not a feature.This is a structural consolidation only — every public import path and behaviour is preserved.
Current behaviour
praisonaiagents/workflows/workflows.py(4,531 LOC) — the version exported everywhere.praisonaiagents/memory/workflows.py(1,983 LOC) — separateWorkflowContext/StepResultdataclasses,Workflow(lines ~182–719) andWorkflowManager(lines ~720–1968).praisonaiagents/memory/__init__.pyalready re-exports all workflow symbols from..workflows, not frommemory.workflows:praisonaiagents/memory/__init__.py:96→from ..workflows import WorkflowManagerWorkflow,Task,WorkflowContext,StepResult,Pipeline,Route,Parallel,Loop,Repeat,route,parallel,loop,repeatall sourced from..workflowscreate_workflow_managerfrom..workflows.workflowsfrom praisonaiagents.memory import Workflow/WorkflowManageralready resolves to the canonical engine. The 1,983 LOC file is reachable only via the explicit module pathpraisonaiagents.memory.workflows.No production module imports
memory.workflows. The only references are tests asserting the backward-compatible path still works:tests/test_workflow_patterns.py:462—from praisonaiagents.memory.workflows import (Workflow, Task, WorkflowContext, StepResult, route, parallel, loop, repeat)tests/unit/test_paths_wiring.py:289+— inspectsworkflows.WorkflowManagersource forDEFAULT_DIR_NAME/_get_checkpoints_dirpaths wiring.Why it matters
workflows/workflows.py(e.g. newer route/parallel/output_file parsing paths exist only in the canonical file).praisonaiagents.memory.workflowsgets the older implementation, whilepraisonaiagents.memorygives the newer one — same names, different behaviour.Category
Duplicate logic
Capability preserved
from praisonaiagents.memory.workflows import Workflow, Task, WorkflowContext, StepResult, route, parallel, loop, repeatkeeps working (backward-compatible path).from praisonaiagents.memory import Workflow, Pipeline, WorkflowManager, ...keeps working (already routed to canonical).WorkflowManager, checkpoints, and paths-wiring behaviour unchanged.Proposed approach
Turn
memory/workflows.pyinto a thin re-export shim that imports the canonical symbols frompraisonaiagents.workflows.workflows, deleting the duplicated bodies. This collapses ~2,000 LOC to a few lines while keeping the legacy import path alive.Resolution sketch
Severity
Medium
Validation
memory/__init__.pyre-exports workflow symbols from..workflows, never frommemory.workflows; no production code importsmemory.workflows.tests/test_workflow_patterns.py,tests/unit/test_paths_wiring.py).workflows.WorkflowManagerstill satisfiestests/unit/test_paths_wiring.py(usesDEFAULT_DIR_NAME, no hard-coded".praisonai/workflows",_get_checkpoints_dirrouted throughpaths.py); if any wiring assertion is specific to the old copy, port it onto the canonical class as part of the shim change.Keep unchanged
praisonaiagents/workflows/workflows.pyengine and its full feature set.praisonaiagents.memory,praisonaiagents.memory.workflows,praisonaiagents.workflows).memory/__init__.py.