From 5de92dcabcd69d13a335279a4fd7845116b427d1 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Tue, 14 May 2024 09:56:12 -0400 Subject: [PATCH 1/2] Return endrun instead of raising to avoid false error --- src/controlflow/core/controller/controller.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/controlflow/core/controller/controller.py b/src/controlflow/core/controller/controller.py index a7997308..631c66a3 100644 --- a/src/controlflow/core/controller/controller.py +++ b/src/controlflow/core/controller/controller.py @@ -57,7 +57,6 @@ class Controller(BaseModel, ExposeSyncMethodsMixin): validate_default=True, ) agents: list[Agent] | None = None - run_dependencies: bool = True context: dict = {} graph: Graph = None model_config: dict = dict(extra="forbid") @@ -90,7 +89,7 @@ def end_run(): End your turn if you have no tasks to work on. Only call this tool if necessary; otherwise you can end your turn normally. """ - raise EndRun() + return EndRun() return end_run From 17dd4feabfc398074ac6adac8eafa3a39a34bab2 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Tue, 14 May 2024 09:56:21 -0400 Subject: [PATCH 2/2] add max iterations --- src/controlflow/core/task.py | 27 +++++++++++++++++---------- src/controlflow/settings.py | 2 +- src/controlflow/utilities/types.py | 3 +++ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/controlflow/core/task.py b/src/controlflow/core/task.py index f6b88da2..7150b6ba 100644 --- a/src/controlflow/core/task.py +++ b/src/controlflow/core/task.py @@ -29,7 +29,7 @@ from controlflow.utilities.context import ctx from controlflow.utilities.logging import get_logger from controlflow.utilities.prefect import wrap_prefect_tool -from controlflow.utilities.types import AssistantTool, ControlFlowModel +from controlflow.utilities.types import NOTSET, AssistantTool, ControlFlowModel from controlflow.utilities.user_access import talk_to_human if TYPE_CHECKING: @@ -46,9 +46,6 @@ class TaskStatus(Enum): SKIPPED = "skipped" -NOTSET = "__notset__" - - def visit_task_collection( val: Any, fn: Callable, recursion_limit: int = 3, _counter: int = 0 ) -> list["Task"]: @@ -239,24 +236,34 @@ def add_dependency(self, task: "Task"): if self not in task._downstreams: task._downstreams.append(self) - def run_once(self, agent: "Agent" = None, run_dependencies: bool = True): + def run_once(self, agent: "Agent" = None): """ Runs the task with provided agent. If no agent is provided, one will be selected from the task's agents. """ from controlflow.core.controller import Controller - controller = Controller( - tasks=[self], agents=agent, run_dependencies=run_dependencies - ) + controller = Controller(tasks=[self], agents=agent) controller.run_once() - def run(self, run_dependencies: bool = True) -> T: + def run(self, max_iterations: int = NOTSET) -> T: """ Runs the task with provided agents until it is complete. + + If max_iterations is provided, the task will run at most that many times before raising an error. """ + if max_iterations == NOTSET: + max_iterations = marvin.settings.max_task_iterations + if max_iterations is None: + max_iterations = float("inf") + + counter = 0 while self.is_incomplete(): - self.run_once(run_dependencies=run_dependencies) + if counter >= max_iterations: + raise ValueError( + f"{self.friendly_name()} did not complete after {max_iterations} iterations." + ) + self.run_once() if self.is_successful(): return self.result elif self.is_failed(): diff --git a/src/controlflow/settings.py b/src/controlflow/settings.py index 1a563249..ad4a2802 100644 --- a/src/controlflow/settings.py +++ b/src/controlflow/settings.py @@ -47,7 +47,7 @@ def apply(self): class Settings(ControlFlowSettings): assistant_model: str = "gpt-4o" - max_agent_iterations: int = 10 + max_task_iterations: int = None prefect: PrefectSettings = Field(default_factory=PrefectSettings) enable_global_flow: bool = Field( True, diff --git a/src/controlflow/utilities/types.py b/src/controlflow/utilities/types.py index ab398c82..fe7292eb 100644 --- a/src/controlflow/utilities/types.py +++ b/src/controlflow/utilities/types.py @@ -4,6 +4,9 @@ from marvin.utilities.asyncio import ExposeSyncMethodsMixin from pydantic import BaseModel +# flag for unset defaults +NOTSET = "__NOTSET__" + class ControlFlowModel(BaseModel): model_config = dict(validate_assignment=True, extra="forbid")