Skip to content

Commit

Permalink
Tweak how tasks run
Browse files Browse the repository at this point in the history
  • Loading branch information
jlowin committed May 8, 2024
1 parent 48f0c48 commit 793d9a7
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 54 deletions.
18 changes: 5 additions & 13 deletions examples/choose_a_number.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
from control_flow import Agent, Task, ai_flow, ai_task
from control_flow import Agent, Task, ai_flow

a1 = Agent(
name="A1",
a1 = Agent(name="A1", instructions="You struggle to make decisions.")
a2 = Agent(
name="A2",
instructions="You like to make decisions.",
)
a2 = Agent(name="A2", instructions="You struggle to make decisions.")


@ai_task(user_access=True)
def get_user_name() -> str:
"""get the user's name"""
pass


@ai_flow
def demo():
task = Task[int]("Choose a number between 1 and 100", agents=[a1, a2])
task = Task("Choose a number between 1 and 100", agents=[a1, a2], result_type=int)

while task.is_incomplete():
a1.run(task)
a2.run(task)

get_user_name()

return task


Expand Down
12 changes: 6 additions & 6 deletions examples/pineapple_pizza.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ def demo():
with instructions("one sentence max"):
task = Task(
"All agents must give an argument based on the user message",
result_type=None,
agents=[a1, a2],
context={"user_message": user_message},
)
while task.is_incomplete():
a1.run(task)
a2.run(task)
task2 = Task("Which argument is more compelling?")
task.run_until_complete()

task2 = Task(
"Post a message saying which argument about the user message is more compelling?"
)
while task2.is_incomplete():
Agent(instructions="you always pick a side").run(task2)
task2.run(agents=[Agent(instructions="you always pick a side")])


demo()
55 changes: 21 additions & 34 deletions src/control_flow/core/controller/instruction_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,27 @@ def render(self) -> str:

class AgentTemplate(Template):
template: str = """
You are an AI agent. Your name is "{{ agent.name }}". {% if
agent.description %}
You are an AI agent. Your name is "{{ agent.name }}".
{% if agent.description %}
Your description: "{{ agent.description }}"
{% endif -%}
{% if agent.instructions %}
Your instructions: "{{ agent.instructions }}"
{% endif -%}
The following description has been provided for you: {{ agent.description }}
{% endif -%}
You have been created by a program to complete certain tasks. Each task has
an objective and criteria for success. Your job is to perform any required
actions and then mark each task as successful. If a task also requires a
result, you must provide it; this is how the program receives data from you
as it can not read your messages.
Your job is to complete any incomplete tasks by performing any required
actions and then marking them as successful. Note that some tasks may
require collaboration before they are complete. If the task requires a
result, you must provide it. You are fully capable of completing any task
and have all the information and context you need. Never mark task as failed
unless you encounter a technical or human issue that prevents progress. Do
not work on or even respond to tasks that are already complete.
Some tasks may require collaboration before they are complete; others may
take multiple iterations. You are fully capable of completing any task and
have all the information and context you need. Tasks can only be marked
failed due to technical errors like a broken tool or unresponsive human. You
must make a subjective decision if a task requires it. Do not work on or
even respond to tasks that are already complete.
"""
agent: Agent
Expand Down Expand Up @@ -94,36 +101,17 @@ class CommunicationTemplate(Template):
class InstructionsTemplate(Template):
template: str = """
## Instructions
{% if agent_instructions -%}
### Agent instructions
These instructions apply only to you:
{{ agent_instructions }}
{% endif %}
{% if additional_instructions -%}
### Additional instructions
These instructions were additionally provided for this part of the workflow:
You must follow these instructions for this part of the workflow:
{% for instruction in additional_instructions %}
- {{ instruction }}
{% endfor %}
{% endif %}
"""
agent_instructions: str | None = None
additional_instructions: list[str] = []

def should_render(self):
return any(
[
self.agent_instructions,
self.additional_instructions,
]
)
return bool(self.additional_instructions)


class TasksTemplate(Template):
Expand Down Expand Up @@ -238,7 +226,6 @@ def render(self):
controller_context=self.controller.context,
),
InstructionsTemplate(
agent_instructions=self.agent.instructions,
additional_instructions=self.instructions,
),
CommunicationTemplate(agent=self.agent, other_agents=other_agents),
Expand Down
26 changes: 25 additions & 1 deletion src/control_flow/core/task.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import datetime
import itertools
from enum import Enum
from typing import TYPE_CHECKING, Callable, TypeVar

Expand Down Expand Up @@ -32,7 +33,7 @@ class Task(ControlFlowModel):
context: dict = {}
status: TaskStatus = TaskStatus.INCOMPLETE
result: T = None
result_type: type[T] | None = str
result_type: type[T] | None = None
error: str | None = None
tools: list[AssistantTool | Callable] = []
created_at: datetime.datetime = Field(default_factory=datetime.datetime.now)
Expand All @@ -43,6 +44,29 @@ def __init__(self, objective, **kwargs):
# allow objective as a positional arg
super().__init__(objective=objective, **kwargs)

def run(self, agents: list["Agent"] = None):
"""
Runs the task with provided agents for up to one cycle through the agents.
"""
if not agents and not self.agents:
raise ValueError("No agents provided to run task.")

for agent in agents or self.agents:
if self.is_complete():
break
agent.run(tasks=[self])

def run_until_complete(self, agents: list["Agent"] = None):
"""
Runs the task with provided agents until it is complete.
"""
if not agents and not self.agents:
raise ValueError("No agents provided to run task.")
agents = itertools.cycle(agents or self.agents)
while self.is_incomplete():
agent = next(agents)
agent.run(tasks=[self])

def is_incomplete(self) -> bool:
return self.status == TaskStatus.INCOMPLETE

Expand Down

0 comments on commit 793d9a7

Please sign in to comment.