Skip to content

Commit

Permalink
Merge pull request #26 from jlowin/cf
Browse files Browse the repository at this point in the history
control_flow → controlflow
  • Loading branch information
jlowin authored May 12, 2024
2 parents e0b1924 + 6d3b14a commit 75afc34
Show file tree
Hide file tree
Showing 46 changed files with 208 additions and 122 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![image](https://github.com/jlowin/control_flow/assets/153965/c2a8a2f0-8777-49a6-a79b-a0e101bd4a04)
![image](https://github.com/jlowin/controlflow/assets/153965/c2a8a2f0-8777-49a6-a79b-a0e101bd4a04)

# ControlFlow

Expand Down Expand Up @@ -39,15 +39,15 @@ This targeted approach results in AI systems that are easier to build, maintain,
ControlFlow is under active development.

```bash
git clone https://github.com/jlowin/control_flow.git
cd control_flow
git clone https://github.com/jlowin/controlflow.git
cd controlflow
pip install .
```

## Example

```python
from control_flow import Agent, Task, flow, task, instructions
from controlflow import Agent, Task, flow, task, instructions
from pydantic import BaseModel


Expand Down Expand Up @@ -94,4 +94,4 @@ if __name__ == "__main__":



<img width="1491" alt="image" src="https://github.com/jlowin/control_flow/assets/153965/43b7278b-7bcf-4d65-b219-c3a20f62a179">
<img width="1491" alt="image" src="https://github.com/jlowin/controlflow/assets/153965/43b7278b-7bcf-4d65-b219-c3a20f62a179">
86 changes: 86 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# ControlFlow

**ControlFlow is a framework for building agentic LLM workflows.**

ControlFlow provides a structured and intuitive way to create complex AI-powered applications while adhering to traditional software engineering best practices. The resulting workflows are observable, controllable, and easy to trust.


!!! question "What's an agentic workflow?"
An agentic workflow is a process that treats AI agents as autonomous entities capable of performing tasks, making decisions, and communicating with each other. ControlFlow provides a structured and intuitive way to define, organize, and execute such AI-powered workflows, enabling developers to create complex applications that leverage the power of AI agents while maintaining a clear, maintainable, and debuggable structure.

## Let's see it
```python
from controlflow import flow, Task, Agent

agent = Agent(name='Marvin', description='An expert screewriter.')


@flow
def my_flow():

genre = Task('Choose a movie genre', result_type=['sci-fi', 'western', 'comedy', 'action', 'romance'], agents=[agent])
plot = Task('Generate a plot outline', result_type=str, context=dict(genre=genre), agents=[agent])
title = Task('Come up with a title', result_type=str, context=dict(genre=genre, plot=plot), agents=[agent])

# run the last task in the chain
title.run()

return dict(genre=genre.result, plot=plot.result, title=title.result)

my_flow()
```
## Why ControlFlow?

Building AI applications with large language models (LLMs) is a complex endeavor. Many frameworks rely on monolithic "super-agents" that attempt to handle a wide range of tasks autonomously, but this approach often leads to opaque, hard-to-control workflows that are difficult to integrate with traditional software development practices. ControlFlow offers a better way, guided by three core design principles:

1. **Specialized agents**: ControlFlow advocates for the use of specialized, single-purpose LLMs rather than monolithic models that try to do everything. By assigning specific tasks to purpose-built models, ControlFlow ensures that the right tool is used for each job, leading to more efficient, cost-effective, and higher-quality results.

2. **Declarative tasks**: ControlFlow embraces a declarative approach to defining AI workflows, allowing developers to focus on the desired outcomes rather than the intricacies of steering LLM behavior. By specifying tasks and their requirements using intuitive constructs like the `@task` decorator, developers can express what needs to be done without worrying about the details of how it will be accomplished.

3. **Integrated control**: ControlFlow recognizes the importance of balancing AI capabilities with traditional software development practices. Instead of relying on end-to-end AI systems that make all workflow decisions autonomously, ControlFlow allows developers to have as much or as little AI input as needed, ensuring that they maintain visibility and control over their applications.

These design principles manifest in several key features of ControlFlow:

### Modular architecture
ControlFlow breaks down AI workflows into discrete, self-contained tasks, each with a specific objective and set of requirements. This modular approach promotes transparency, reusability, and maintainability, making it easier to develop, test, and optimize individual components of the AI workflow.

### Agent orchestration
ControlFlow's runtime engine handles the orchestration of specialized AI agents, assigning tasks to the most appropriate models and managing the flow of data between them. This orchestration layer abstracts away the complexities of coordinating multiple AI components, allowing developers to focus on the high-level logic of their applications.

### Native debugging and observability
ControlFlow prioritizes transparency and ease of debugging by providing native tools for monitoring and inspecting the execution of AI tasks. Developers can easily track the progress of their workflows, identify bottlenecks or issues, and gain insights into the behavior of individual agents, ensuring that their AI applications are functioning as intended.

### Seamless integration
ControlFlow is designed to integrate seamlessly with existing Python codebases, treating AI tasks as first-class citizens in the application logic. The `Task` class provides a clean interface for defining the inputs, outputs, and requirements of each task, making it easy to incorporate AI capabilities into traditional software workflows. This seamless integration allows for a gradual and controlled adoption of AI, reducing the risk and complexity of introducing AI into existing systems.

By adhering to these principles and leveraging these features, ControlFlow empowers developers to build AI applications that are more transparent, maintainable, and aligned with software engineering best practices. Whether you're looking to introduce AI capabilities into an existing system or build a new AI-powered application from scratch, ControlFlow provides a flexible, pragmatic, and developer-friendly framework for harnessing the power of LLMs while maintaining control and visibility over your workflow. With ControlFlow, you can focus on delivering high-quality AI solutions without sacrificing the robustness and reliability of traditional software development approaches.

## Key Concepts

- **Flow**: Flows are containers for agentic workflows, and maintain consistent context and history across all of their tasks.

- **Task**: Tasks represent discrete objectives for agents to solve. By specifing the expected inputs and outputs, as well as any additional tools, instructions, or collaborators, tasks provide a clear structure for agents to follow. Completing its tasks is the primary objective of a ControlFlow agent.

- **Agent**: AI agents are assigned to tasks and responsible for completing them. Each agent is designed to be "single-serving," optimized only for completing its task in cooperation with other agents and the broader workflow.

## Getting Started

To get started with ControlFlow, install it using pip:

```bash
pip install controlflow
```

Check out the [Quickstart](quickstart.md) guide for a step-by-step walkthrough of creating your first ControlFlow application.

## Dive Deeper

- Explore the [Concepts](concepts/index.md) section to learn more about the core components of ControlFlow.
- Refer to the [API Reference](api/index.md) for detailed information on the classes and functions provided by the framework.
- Browse the [Examples](examples/index.md) to see ControlFlow in action across various use cases.

## Get Involved

ControlFlow is an open-source project, and we welcome contributions from the community. If you encounter a bug, have a feature request, or want to contribute code, please visit our [GitHub repository](https://github.com/jlowin/controlflow).

Join our [community forum](https://github.com/jlowin/controlflow/discussions) to ask questions, share your projects, and engage with other ControlFlow users and developers.
2 changes: 1 addition & 1 deletion examples/choose_a_number.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from control_flow import Agent, Task, flow
from controlflow import Agent, Task, flow

a1 = Agent(name="A1", instructions="You struggle to make decisions.")
a2 = Agent(
Expand Down
6 changes: 3 additions & 3 deletions examples/documentation.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import glob as glob_module
from pathlib import Path

import control_flow
from control_flow import flow, task
import controlflow
from controlflow import flow, task
from marvin.beta.assistants import Assistant, Thread
from marvin.tools.filesystem import read, write

ROOT = Path(control_flow.__file__).parents[2]
ROOT = Path(controlflow.__file__).parents[2]


def glob(pattern: str) -> list[str]:
Expand Down
4 changes: 2 additions & 2 deletions examples/multi_agent_conversation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from control_flow import Agent, Task, flow
from control_flow.core.controller.moderators import Moderator
from controlflow import Agent, Task, flow
from controlflow.core.controller.moderators import Moderator

jerry = Agent(
name="Jerry",
Expand Down
4 changes: 2 additions & 2 deletions examples/pineapple_pizza.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from control_flow import Agent, Task, flow
from control_flow.instructions import instructions
from controlflow import Agent, Task, flow
from controlflow.instructions import instructions

a1 = Agent(
name="Half-full",
Expand Down
2 changes: 1 addition & 1 deletion examples/readme_example.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from control_flow import Agent, Task, flow, instructions, task
from controlflow import Agent, Task, flow, instructions, task
from pydantic import BaseModel


Expand Down
4 changes: 2 additions & 2 deletions examples/teacher_student.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from control_flow import Agent, Task, flow
from control_flow.instructions import instructions
from controlflow import Agent, Task, flow
from controlflow.instructions import instructions

teacher = Agent(name="teacher")
student = Agent(name="student")
Expand Down
2 changes: 1 addition & 1 deletion examples/write_and_critique_paper.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from control_flow import Agent, Task
from controlflow import Agent, Task

writer = Agent(name="writer")
editor = Agent(name="editor", instructions="you always find at least one problem")
Expand Down
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[project]
name = "control_flow"
name = "controlflow"
version = "0.1.0"
description = "AI Workflows"
authors = [
Expand Down Expand Up @@ -43,7 +43,7 @@ tests = [
"pytest-xdist",
"pre-commit>=3.7.0",
]
dev = ["control_flow[tests]", "ipython>=8.22.2", "pdbpp>=0.10.3", "ruff>=0.3.4"]
dev = ["controlflow[tests]", "ipython>=8.22.2", "pdbpp>=0.10.3", "ruff>=0.3.4"]

[build-system]
requires = ["hatchling"]
Expand All @@ -56,7 +56,7 @@ managed = true
allow-direct-references = true

[tool.hatch.build.targets.wheel]
packages = ["src/control_flow"]
packages = ["src/controlflow"]

# ruff configuration
[tool.ruff]
Expand All @@ -72,4 +72,4 @@ skip-magic-trailing-comma = false
"__init__.py" = ['I', 'F401', 'E402']
"conftest.py" = ["F401", "F403"]
'tests/fixtures/*.py' = ['F401', 'F403']
"src/control_flow/utilities/types.py" = ['F401']
"src/controlflow/utilities/types.py" = ['F401']
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import marvin

from control_flow.core.agent import Agent
from control_flow.instructions import get_instructions
from control_flow.utilities.context import ctx
from control_flow.utilities.threads import get_history
from controlflow.core.agent import Agent
from controlflow.instructions import get_instructions
from controlflow.utilities.context import ctx
from controlflow.utilities.threads import get_history


def choose_agent(
Expand Down
File renamed without changes.
12 changes: 6 additions & 6 deletions src/control_flow/core/agent.py → src/controlflow/core/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
from marvin.utilities.tools import tool_from_function
from pydantic import Field

from control_flow.core.flow import get_flow
from control_flow.core.task import Task
from control_flow.utilities.prefect import (
from controlflow.core.flow import get_flow
from controlflow.core.task import Task
from controlflow.utilities.prefect import (
wrap_prefect_tool,
)
from control_flow.utilities.types import Assistant, AssistantTool, ControlFlowModel
from control_flow.utilities.user_access import talk_to_human
from controlflow.utilities.types import Assistant, AssistantTool, ControlFlowModel
from controlflow.utilities.user_access import talk_to_human

logger = logging.getLogger(__name__)

Expand All @@ -32,7 +32,7 @@ def get_tools(self) -> list[AssistantTool | Callable]:

@expose_sync_method("run")
async def run_async(self, tasks: list[Task] | Task | None = None):
from control_flow.core.controller import Controller
from controlflow.core.controller import Controller

if isinstance(tasks, Task):
tasks = [tasks]
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@
from prefect.context import FlowRunContext
from pydantic import BaseModel, Field, field_validator, model_validator

from control_flow.core.agent import Agent
from control_flow.core.controller.moderators import marvin_moderator
from control_flow.core.flow import Flow, get_flow, get_flow_messages
from control_flow.core.graph import Graph
from control_flow.core.task import Task
from control_flow.instructions import get_instructions
from control_flow.utilities.prefect import (
from controlflow.core.agent import Agent
from controlflow.core.controller.moderators import marvin_moderator
from controlflow.core.flow import Flow, get_flow, get_flow_messages
from controlflow.core.graph import Graph
from controlflow.core.task import Task
from controlflow.instructions import get_instructions
from controlflow.utilities.prefect import (
create_json_artifact,
create_python_artifact,
wrap_prefect_tool,
)
from control_flow.utilities.types import FunctionTool, Thread
from controlflow.utilities.types import FunctionTool, Thread

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -93,7 +93,7 @@ async def _run_agent(

@prefect_task(task_run_name=f'Run Agent: "{agent.name}"')
async def _run_agent(agent: Agent, tasks: list[Task], thread: Thread = None):
from control_flow.core.controller.instruction_template import MainTemplate
from controlflow.core.controller.instruction_template import MainTemplate

tasks = tasks or self.tasks

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

from pydantic import BaseModel

from control_flow.core.agent import Agent
from control_flow.core.task import Task
from control_flow.utilities.jinja import jinja_env
from control_flow.utilities.types import ControlFlowModel
from controlflow.core.agent import Agent
from controlflow.core.task import Task
from controlflow.utilities.jinja import jinja_env
from controlflow.utilities.types import ControlFlowModel

from .controller import Controller

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import marvin
from pydantic import BaseModel, Field

from control_flow.core.agent import Agent
from control_flow.core.flow import Flow, get_flow_messages
from control_flow.core.task import Task
from controlflow.core.agent import Agent
from controlflow.core.flow import Flow, get_flow_messages
from controlflow.core.task import Task

if TYPE_CHECKING:
from control_flow.core.agent import Agent
from controlflow.core.agent import Agent


def round_robin(agents: list[Agent], tasks: list[Task]) -> Generator[Any, Any, Agent]:
Expand Down
16 changes: 8 additions & 8 deletions src/control_flow/core/flow.py → src/controlflow/core/flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
from prefect import task as prefect_task
from pydantic import Field, field_validator

import control_flow
from control_flow.utilities.context import ctx
from control_flow.utilities.logging import get_logger
from control_flow.utilities.marvin import patch_marvin
from control_flow.utilities.types import AssistantTool, ControlFlowModel
import controlflow
from controlflow.utilities.context import ctx
from controlflow.utilities.logging import get_logger
from controlflow.utilities.marvin import patch_marvin
from controlflow.utilities.types import AssistantTool, ControlFlowModel

if TYPE_CHECKING:
from control_flow.core.agent import Agent
from controlflow.core.agent import Agent
logger = get_logger(__name__)


def default_agent():
from control_flow.core.agent import Agent
from controlflow.core.agent import Agent

return [
Agent(
Expand Down Expand Up @@ -81,7 +81,7 @@ def get_flow() -> Flow:
"""
flow: Flow | None = ctx.get("flow")
if not flow:
if control_flow.settings.enable_global_flow:
if controlflow.settings.enable_global_flow:
return GLOBAL_FLOW
else:
raise ValueError("No flow found in context.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from pydantic import BaseModel

from control_flow.core.task import Task
from controlflow.core.task import Task


class EdgeType(Enum):
Expand Down
Loading

0 comments on commit 75afc34

Please sign in to comment.