abstractflow 0.1.0__py3-none-any.whl → 0.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. abstractflow/__init__.py +74 -94
  2. abstractflow/__main__.py +2 -0
  3. abstractflow/adapters/__init__.py +11 -0
  4. abstractflow/adapters/agent_adapter.py +5 -0
  5. abstractflow/adapters/control_adapter.py +5 -0
  6. abstractflow/adapters/effect_adapter.py +5 -0
  7. abstractflow/adapters/event_adapter.py +5 -0
  8. abstractflow/adapters/function_adapter.py +5 -0
  9. abstractflow/adapters/subflow_adapter.py +5 -0
  10. abstractflow/adapters/variable_adapter.py +5 -0
  11. abstractflow/cli.py +75 -28
  12. abstractflow/compiler.py +23 -0
  13. abstractflow/core/__init__.py +5 -0
  14. abstractflow/core/flow.py +11 -0
  15. abstractflow/py.typed +2 -0
  16. abstractflow/runner.py +402 -0
  17. abstractflow/visual/__init__.py +43 -0
  18. abstractflow/visual/agent_ids.py +5 -0
  19. abstractflow/visual/builtins.py +5 -0
  20. abstractflow/visual/code_executor.py +5 -0
  21. abstractflow/visual/event_ids.py +33 -0
  22. abstractflow/visual/executor.py +968 -0
  23. abstractflow/visual/interfaces.py +440 -0
  24. abstractflow/visual/models.py +277 -0
  25. abstractflow/visual/session_runner.py +182 -0
  26. abstractflow/visual/workspace_scoped_tools.py +29 -0
  27. abstractflow/workflow_bundle.py +290 -0
  28. abstractflow-0.3.1.dist-info/METADATA +186 -0
  29. abstractflow-0.3.1.dist-info/RECORD +33 -0
  30. {abstractflow-0.1.0.dist-info → abstractflow-0.3.1.dist-info}/WHEEL +1 -1
  31. {abstractflow-0.1.0.dist-info → abstractflow-0.3.1.dist-info}/licenses/LICENSE +2 -0
  32. abstractflow-0.1.0.dist-info/METADATA +0 -238
  33. abstractflow-0.1.0.dist-info/RECORD +0 -10
  34. {abstractflow-0.1.0.dist-info → abstractflow-0.3.1.dist-info}/entry_points.txt +0 -0
  35. {abstractflow-0.1.0.dist-info → abstractflow-0.3.1.dist-info}/top_level.txt +0 -0
abstractflow/__init__.py CHANGED
@@ -1,104 +1,84 @@
1
+ """AbstractFlow - Multi-agent orchestration layer for the Abstract Framework.
2
+
3
+ AbstractFlow enables composition of agents into pipelines and coordinates
4
+ their execution via AbstractRuntime. It provides:
5
+
6
+ - Flow: Declarative flow definition with nodes and edges
7
+ - FlowRunner: High-level interface for running flows
8
+ - compile_flow: Convert Flow to WorkflowSpec for direct runtime usage
9
+
10
+ Example:
11
+ >>> from abstractflow import Flow, FlowRunner
12
+ >>>
13
+ >>> # Define a simple flow
14
+ >>> flow = Flow("my_pipeline")
15
+ >>> flow.add_node("step1", lambda x: x * 2, input_key="value", output_key="doubled")
16
+ >>> flow.add_node("step2", lambda x: x + 10, input_key="doubled", output_key="result")
17
+ >>> flow.add_edge("step1", "step2")
18
+ >>> flow.set_entry("step1")
19
+ >>>
20
+ >>> # Run the flow
21
+ >>> runner = FlowRunner(flow)
22
+ >>> result = runner.run({"value": 5})
23
+ >>> print(result) # {'result': 20, 'success': True}
24
+
25
+ For agent-based flows:
26
+ >>> from abstractflow import Flow, FlowRunner
27
+ >>> from abstractagent import create_react_agent
28
+ >>>
29
+ >>> planner = create_react_agent(provider="ollama", model="qwen3:4b")
30
+ >>> executor = create_react_agent(provider="ollama", model="qwen3:4b")
31
+ >>>
32
+ >>> flow = Flow("plan_and_execute")
33
+ >>> flow.add_node("plan", planner, output_key="plan")
34
+ >>> flow.add_node("execute", executor, input_key="plan")
35
+ >>> flow.add_edge("plan", "execute")
36
+ >>> flow.set_entry("plan")
37
+ >>>
38
+ >>> runner = FlowRunner(flow)
39
+ >>> result = runner.run({"context": {"task": "Build a REST API"}})
1
40
  """
2
- AbstractFlow - Diagram-based AI workflow generation.
3
41
 
4
- Built on top of AbstractCore for unified LLM provider access.
5
- """
6
-
7
- __version__ = "0.1.0"
8
- __author__ = "AbstractFlow Team"
42
+ __version__ = "0.3.1"
43
+ __author__ = "Laurent-Philippe Albou"
9
44
  __email__ = "contact@abstractflow.ai"
10
45
  __license__ = "MIT"
11
46
 
12
- # Core imports that will be available when the package is fully implemented
13
- __all__ = [
14
- "__version__",
15
- "WorkflowBuilder",
16
- "Node",
17
- "LLMNode",
18
- "TextNode",
19
- "ConditionalNode",
20
- "TransformNode",
21
- ]
22
-
23
- # Placeholder implementations - these will be replaced with actual implementations
24
- class WorkflowBuilder:
25
- """
26
- Visual workflow builder for creating AI-powered diagrams.
27
-
28
- This is a placeholder implementation. The full version will provide:
29
- - Drag-and-drop workflow creation
30
- - Real-time execution monitoring
31
- - Multi-provider LLM support via AbstractCore
32
- - Export to various formats
33
- """
34
-
35
- def __init__(self):
36
- """Initialize a new workflow builder."""
37
- raise NotImplementedError(
38
- "AbstractFlow is currently in development. "
39
- "This placeholder package reserves the PyPI name. "
40
- "Follow https://github.com/lpalbou/AbstractFlow for updates."
41
- )
42
-
43
-
44
- class Node:
45
- """Base class for all workflow nodes."""
46
-
47
- def __init__(self, node_id: str):
48
- """Initialize a workflow node."""
49
- raise NotImplementedError(
50
- "AbstractFlow is currently in development. "
51
- "This placeholder package reserves the PyPI name. "
52
- "Follow https://github.com/lpalbou/AbstractFlow for updates."
53
- )
47
+ # Core classes
48
+ from .core.flow import Flow, FlowNode, FlowEdge
54
49
 
50
+ # Compiler
51
+ from .compiler import compile_flow
55
52
 
56
- class LLMNode(Node):
57
- """Node for LLM-based text generation and processing."""
58
-
59
- def __init__(self, provider: str, model: str, **kwargs):
60
- """Initialize an LLM node with AbstractCore provider."""
61
- raise NotImplementedError(
62
- "AbstractFlow is currently in development. "
63
- "This placeholder package reserves the PyPI name. "
64
- "Follow https://github.com/lpalbou/AbstractFlow for updates."
65
- )
53
+ # Runner
54
+ from .runner import FlowRunner
66
55
 
56
+ # Adapters (for advanced usage)
57
+ from .adapters import (
58
+ create_function_node_handler,
59
+ create_agent_node_handler,
60
+ create_subflow_node_handler,
61
+ )
67
62
 
68
- class TextNode(Node):
69
- """Node for text input/output operations."""
70
-
71
- def __init__(self, text_id: str):
72
- """Initialize a text node."""
73
- raise NotImplementedError(
74
- "AbstractFlow is currently in development. "
75
- "This placeholder package reserves the PyPI name. "
76
- "Follow https://github.com/lpalbou/AbstractFlow for updates."
77
- )
78
-
79
-
80
- class ConditionalNode(Node):
81
- """Node for conditional branching in workflows."""
82
-
83
- def __init__(self, condition: str):
84
- """Initialize a conditional node."""
85
- raise NotImplementedError(
86
- "AbstractFlow is currently in development. "
87
- "This placeholder package reserves the PyPI name. "
88
- "Follow https://github.com/lpalbou/AbstractFlow for updates."
89
- )
90
-
91
-
92
- class TransformNode(Node):
93
- """Node for data transformation operations."""
94
-
95
- def __init__(self, transform_func: str):
96
- """Initialize a transform node."""
97
- raise NotImplementedError(
98
- "AbstractFlow is currently in development. "
99
- "This placeholder package reserves the PyPI name. "
100
- "Follow https://github.com/lpalbou/AbstractFlow for updates."
101
- )
63
+ __all__ = [
64
+ # Version info
65
+ "__version__",
66
+ "__author__",
67
+ "__email__",
68
+ "__license__",
69
+ # Core classes
70
+ "Flow",
71
+ "FlowNode",
72
+ "FlowEdge",
73
+ # Compiler
74
+ "compile_flow",
75
+ # Runner
76
+ "FlowRunner",
77
+ # Adapters
78
+ "create_function_node_handler",
79
+ "create_agent_node_handler",
80
+ "create_subflow_node_handler",
81
+ ]
102
82
 
103
83
 
104
84
  def get_version() -> str:
@@ -107,5 +87,5 @@ def get_version() -> str:
107
87
 
108
88
 
109
89
  def is_development_version() -> bool:
110
- """Check if this is a development/placeholder version."""
111
- return True # This will be False in the actual implementation
90
+ """Check if this is a development version."""
91
+ return False # Now implemented!
abstractflow/__main__.py CHANGED
@@ -8,3 +8,5 @@ from .cli import main
8
8
 
9
9
  if __name__ == "__main__":
10
10
  exit(main())
11
+
12
+
@@ -0,0 +1,11 @@
1
+ """AbstractFlow adapters for converting handlers to workflow nodes."""
2
+
3
+ from .function_adapter import create_function_node_handler
4
+ from .agent_adapter import create_agent_node_handler
5
+ from .subflow_adapter import create_subflow_node_handler
6
+
7
+ __all__ = [
8
+ "create_function_node_handler",
9
+ "create_agent_node_handler",
10
+ "create_subflow_node_handler",
11
+ ]
@@ -0,0 +1,5 @@
1
+ """Re-export: AbstractRuntime VisualFlow compiler adapter."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abstractruntime.visualflow_compiler.adapters.agent_adapter import * # noqa: F401,F403
@@ -0,0 +1,5 @@
1
+ """Re-export: AbstractRuntime VisualFlow compiler adapter."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abstractruntime.visualflow_compiler.adapters.control_adapter import * # noqa: F401,F403
@@ -0,0 +1,5 @@
1
+ """Re-export: AbstractRuntime VisualFlow compiler adapter."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abstractruntime.visualflow_compiler.adapters.effect_adapter import * # noqa: F401,F403
@@ -0,0 +1,5 @@
1
+ """Re-export: AbstractRuntime VisualFlow compiler adapter."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abstractruntime.visualflow_compiler.adapters.event_adapter import * # noqa: F401,F403
@@ -0,0 +1,5 @@
1
+ """Re-export: AbstractRuntime VisualFlow compiler adapter."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abstractruntime.visualflow_compiler.adapters.function_adapter import * # noqa: F401,F403
@@ -0,0 +1,5 @@
1
+ """Re-export: AbstractRuntime VisualFlow compiler adapter."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abstractruntime.visualflow_compiler.adapters.subflow_adapter import * # noqa: F401,F403
@@ -0,0 +1,5 @@
1
+ """Re-export: AbstractRuntime VisualFlow compiler adapter."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abstractruntime.visualflow_compiler.adapters.variable_adapter import * # noqa: F401,F403
abstractflow/cli.py CHANGED
@@ -1,42 +1,89 @@
1
- """
2
- Command-line interface for AbstractFlow.
1
+ """Command-line interface for AbstractFlow.
2
+
3
+ Current implemented features:
4
+ - WorkflowBundle (.flow) pack/inspect/unpack (backlog 314)
3
5
 
4
- This is a placeholder CLI that will be expanded in future versions.
6
+ Other commands are intentionally kept minimal for now.
5
7
  """
6
8
 
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import json
7
13
  import sys
8
14
  from typing import List, Optional
9
15
 
16
+ from .workflow_bundle import inspect_workflow_bundle, pack_workflow_bundle, unpack_workflow_bundle
17
+ from abstractruntime.workflow_bundle import workflow_bundle_manifest_to_dict
18
+
19
+
20
+ def _build_parser() -> argparse.ArgumentParser:
21
+ p = argparse.ArgumentParser(prog="abstractflow", add_help=True)
22
+ sub = p.add_subparsers(dest="command")
23
+
24
+ bundle = sub.add_parser("bundle", help="WorkflowBundle (.flow) tools")
25
+ bundle_sub = bundle.add_subparsers(dest="bundle_cmd")
26
+
27
+ pack = bundle_sub.add_parser("pack", help="Pack a .flow bundle from a root VisualFlow JSON file")
28
+ pack.add_argument("root", help="Path to root VisualFlow JSON (e.g., ./flows/<id>.json)")
29
+ pack.add_argument("--out", required=True, help="Output .flow path")
30
+ pack.add_argument("--bundle-id", default=None, help="Bundle id (default: root flow id)")
31
+ pack.add_argument("--bundle-version", default="0.0.0", help="Bundle version (default: 0.0.0)")
32
+ pack.add_argument("--flows-dir", default=None, help="Directory containing flow JSON files (default: root's directory)")
33
+ pack.add_argument(
34
+ "--entrypoint",
35
+ action="append",
36
+ default=None,
37
+ help="Entrypoint flow id (repeatable). Default: root flow id",
38
+ )
39
+
40
+ insp = bundle_sub.add_parser("inspect", help="Print bundle manifest (JSON)")
41
+ insp.add_argument("bundle", help="Path to .flow (zip) or extracted directory")
42
+
43
+ unpack = bundle_sub.add_parser("unpack", help="Extract a .flow bundle to a directory")
44
+ unpack.add_argument("bundle", help="Path to .flow (zip) or extracted directory")
45
+ unpack.add_argument("--dir", required=True, help="Output directory")
46
+
47
+ return p
48
+
10
49
 
11
50
  def main(args: Optional[List[str]] = None) -> int:
12
- """
13
- Main entry point for the AbstractFlow CLI.
14
-
15
- Args:
16
- args: Command-line arguments (defaults to sys.argv[1:])
17
-
18
- Returns:
19
- Exit code (0 for success, non-zero for error)
20
- """
21
51
  if args is None:
22
52
  args = sys.argv[1:]
23
-
24
- print("🚧 AbstractFlow CLI - Coming Soon!")
25
- print()
26
- print("AbstractFlow is currently in development.")
27
- print("This placeholder package reserves the PyPI name.")
28
- print()
29
- print("Planned CLI features:")
30
- print(" • abstractflow create <workflow> - Create new workflow")
31
- print(" • abstractflow run <workflow> - Execute workflow")
32
- print(" • abstractflow validate <workflow> - Validate workflow")
33
- print(" • abstractflow export <workflow> - Export workflow")
34
- print(" • abstractflow serve - Start workflow server")
35
- print()
36
- print("Follow https://github.com/lpalbou/AbstractFlow for updates!")
37
-
53
+
54
+ parser = _build_parser()
55
+ ns = parser.parse_args(args)
56
+
57
+ if ns.command == "bundle":
58
+ if ns.bundle_cmd == "pack":
59
+ packed = pack_workflow_bundle(
60
+ root_flow_json=ns.root,
61
+ out_path=ns.out,
62
+ bundle_id=ns.bundle_id,
63
+ bundle_version=ns.bundle_version,
64
+ flows_dir=ns.flows_dir,
65
+ entrypoints=list(ns.entrypoint) if isinstance(ns.entrypoint, list) and ns.entrypoint else None,
66
+ )
67
+ sys.stdout.write(str(packed.path) + "\n")
68
+ return 0
69
+
70
+ if ns.bundle_cmd == "inspect":
71
+ man = inspect_workflow_bundle(bundle_path=ns.bundle)
72
+ sys.stdout.write(json.dumps(workflow_bundle_manifest_to_dict(man), indent=2, ensure_ascii=False) + "\n")
73
+ return 0
74
+
75
+ if ns.bundle_cmd == "unpack":
76
+ out = unpack_workflow_bundle(bundle_path=ns.bundle, out_dir=ns.dir)
77
+ sys.stdout.write(str(out) + "\n")
78
+ return 0
79
+
80
+ parser.error("Missing bundle subcommand (pack|inspect|unpack)")
81
+
82
+ parser.print_help()
38
83
  return 0
39
84
 
40
85
 
41
86
  if __name__ == "__main__":
42
- sys.exit(main())
87
+ raise SystemExit(main())
88
+
89
+
@@ -0,0 +1,23 @@
1
+ """AbstractFlow compiler shim.
2
+
3
+ AbstractFlow no longer owns workflow compilation semantics. The single source of
4
+ truth for VisualFlow/Flow compilation lives in `abstractruntime.visualflow_compiler`.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from abstractruntime.visualflow_compiler.compiler import (
10
+ _create_visual_agent_effect_handler,
11
+ _sync_effect_results_to_node_outputs,
12
+ compile_flow,
13
+ compile_visualflow,
14
+ compile_visualflow_tree,
15
+ )
16
+
17
+ __all__ = [
18
+ "compile_flow",
19
+ "compile_visualflow",
20
+ "compile_visualflow_tree",
21
+ "_create_visual_agent_effect_handler",
22
+ "_sync_effect_results_to_node_outputs",
23
+ ]
@@ -0,0 +1,5 @@
1
+ """AbstractFlow core module."""
2
+
3
+ from .flow import Flow, FlowNode, FlowEdge
4
+
5
+ __all__ = ["Flow", "FlowNode", "FlowEdge"]
@@ -0,0 +1,11 @@
1
+ """Flow definition classes for AbstractFlow.
2
+
3
+ This module is a thin re-export of AbstractRuntime's Flow IR so there is a
4
+ single semantics + IR surface shared across hosts.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from abstractruntime.visualflow_compiler.flow import Flow, FlowEdge, FlowNode
10
+
11
+ __all__ = ["Flow", "FlowNode", "FlowEdge"]
abstractflow/py.typed CHANGED
@@ -1 +1,3 @@
1
1
  # Marker file for PEP 561 - indicates this package supports type checking
2
+
3
+