Flow visualizer (#1375)

* Almost working!

* It fully works but not clean enought

* Working but not clean engouth

* Everything is workign

* WIP. Working on adding and & or to flows. In the middle of setting up template for flow as well

* template working

* Everything is working

* More changes and todos

* Add more support for @start

* Router working now

* minor tweak to

* minor tweak to conditions and event handling

* Update logs

* Too trigger happy with cleanup

* Added in Thiago fix

* Flow passing results again

* Working on docs.

* made more progress updates on docs

* Finished talking about controlling flows

* add flow output

* fixed flow output section

* add crews to flows section is looking good now

* more flow doc changes

* Update docs and add more examples

* drop visualizer

* save visualizer

* pyvis is beginning to work

* pyvis working

* it is working

* regular methods and triggers working. Need to work on router next.

* properly identifying router and router children nodes. Need to fix color

* children router working. Need to support loops

* curving cycles but need to add curve conditionals

* everythin is showing up properly need to fix curves

* all working. needs to be cleaned up

* adjust padding

* drop lib

* clean up prior to PR

* incorporate joao feedback

* final tweaks for joao
This commit is contained in:
Brandon Hancock (bhancock_ai)
2024-09-30 19:52:56 -04:00
committed by GitHub
parent 7f830b4f43
commit 32fdd11c93
12 changed files with 1158 additions and 906 deletions

View File

@@ -1,9 +1,13 @@
# flow.py
import asyncio
import inspect
from typing import Any, Callable, Dict, Generic, List, Set, Type, TypeVar, Union
from pydantic import BaseModel
from crewai.flow.flow_visualizer import visualize_flow
T = TypeVar("T", bound=Union[BaseModel, Dict[str, Any]])
@@ -57,10 +61,12 @@ def listen(condition):
return decorator
def router(method):
def router(method, paths=None):
def decorator(func):
func.__is_router__ = True
func.__router_for__ = method.__name__
if paths:
func.__router_paths__ = paths
return func
return decorator
@@ -101,6 +107,7 @@ class FlowMeta(type):
start_methods = []
listeners = {}
routers = {}
router_paths = {}
for attr_name, attr_value in dct.items():
if hasattr(attr_value, "__is_start_method__"):
@@ -115,10 +122,19 @@ class FlowMeta(type):
listeners[attr_name] = (condition_type, methods)
elif hasattr(attr_value, "__is_router__"):
routers[attr_value.__router_for__] = attr_name
if hasattr(attr_value, "__router_paths__"):
router_paths[attr_name] = attr_value.__router_paths__
# **Register router as a listener to its triggering method**
trigger_method_name = attr_value.__router_for__
methods = [trigger_method_name]
condition_type = "OR"
listeners[attr_name] = (condition_type, methods)
setattr(cls, "_start_methods", start_methods)
setattr(cls, "_listeners", listeners)
setattr(cls, "_routers", routers)
setattr(cls, "_router_paths", router_paths)
return cls
@@ -127,6 +143,7 @@ class Flow(Generic[T], metaclass=FlowMeta):
_start_methods: List[str] = []
_listeners: Dict[str, tuple[str, List[str]]] = {}
_routers: Dict[str, str] = {}
_router_paths: Dict[str, List[str]] = {}
initial_state: Union[Type[T], T, None] = None
def __class_getitem__(cls, item):
@@ -250,3 +267,6 @@ class Flow(Generic[T], metaclass=FlowMeta):
import traceback
traceback.print_exc()
def visualize(self, filename: str = "crewai_flow_graph"):
visualize_flow(self, filename)