Skip to content

Commit

Permalink
v0.2.0 - remove context builder fn, add pause/unpause
Browse files Browse the repository at this point in the history
  • Loading branch information
lalalune committed Jul 30, 2023
1 parent 3d82f3b commit 4705b01
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 177 deletions.
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ def step_two(next_output, loop_data):
# Run the loop
loop_data = start(steps=[step_one, step_two])

# Pause the loop
pause(loop_data)

# Unpause the loop
unpause(loop_data)

# Stop the loop
stop(loop_data)
```
Expand Down Expand Up @@ -102,6 +108,48 @@ None

---

Sure, here are the updated sections for the `pause` and `unpause` functions in your README file.

---

## Function `pause`

```python
pause(loop_data)
```

### Description

Pauses the loop. When paused, the loop will not execute the next step until it's either stepped using the `step` function or unpaused using the `unpause` function.

### Parameters

- `loop_data`: a dictionary containing the `pause_event` which is returned by the `start` function.

### Returns

None

---

## Function `unpause`

```python
unpause(loop_data)
```

### Description

Resumes the loop after it has been paused with the `pause` function. If the loop is not paused, calling this function has no effect.

### Parameters

- `loop_data`: a dictionary containing the `pause_event` which is returned by the `start` function.

### Returns

None

## Function `step`

```python
Expand Down
6 changes: 3 additions & 3 deletions agentloop/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from .loop import start, step, stop, loop
from .loop import start, step, stop, loop, pause, unpause
from .input import step_with_input_key
from .context import create_context_builders

__all__ = [
"start",
"stop",
"step",
"pause",
"unpause",
"loop",
"step_with_input_key",
"create_context_builders",
]
37 changes: 0 additions & 37 deletions agentloop/context.py

This file was deleted.

2 changes: 1 addition & 1 deletion agentloop/input.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .loop import stop
from agentloop.loop import stop

def step_with_input_key(loop_data):
"""
Expand Down
64 changes: 41 additions & 23 deletions agentloop/loop.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import threading


def start(steps, stepped=False):
def start(steps, paused=False):
"""
Function to start the main loop
Args:
stepped: boolean - whether the loop should run one-step-at-a-time.
paused: boolean - whether the loop should run automatically. If paused can be stepped one-step-at-a-time.
Defaults to False.
Returns:
Expand All @@ -17,9 +17,13 @@ def start(steps, stepped=False):
"stop_event": threading.Event(),
"step_event": threading.Event(),
"started_event": threading.Event(),
"pause_event": threading.Event(),
}

thread = threading.Thread(target=loop, args=(steps, stepped, loop_data))
if paused:
loop_data["pause_event"].set()

thread = threading.Thread(target=loop, args=(steps, loop_data))
loop_data["thread"] = thread

thread.start()
Expand Down Expand Up @@ -58,49 +62,63 @@ def step(loop_data):
loop_data["step_event"].set()


def loop(steps, stepped=False, loop_data=None):
def pause(loop_data):
"""
Function to pause the loop
Args:
loop_data: loop data object, created by the start function
This function does not return any value.
"""
loop_data["pause_event"].set()


def unpause(loop_data):
"""
Function to unpause the loop
Args:
loop_data: loop data object, created by the start function
This function does not return any value.
"""
loop_data["pause_event"].clear()


def loop(steps, loop_data):
"""
Run the step array in a loop until stopped
Args:
steps: array of functions to be run in the loop
stepped: boolean - whether the loop should run in stepped mode or not
paused: boolean - whether the loop should run start up paused (can be stepped) or running
loop_data: loop data object, created by the start function
This function does not return any value.
"""
if loop_data is None:
loop_data = {
"stop_event": threading.Event(),
"step_event": threading.Event(),
"started_event": threading.Event(),
}

next_output = None
loop_data["started_event"].set() # Indicate that the loop has started
while not loop_data["stop_event"].is_set():
for step in steps:
# check how many arguments step takes, 1 or 2?
number_of_args = step.__code__.co_argcount
if number_of_args == 1:
next_output = step(next_output)
elif number_of_args == 2:
next_output = step(next_output, loop_data)
else:
raise ValueError(
"Step function must take 1 or 2 arguments"
"Valid arguments are next_output, loop_data (optional)"
"Step function must take 1 or 2 arguments. "
"Valid arguments are next_output, loop_data (optional). "
"Found {} arguments".format(number_of_args)
)
if stepped:
# Wait here until step_event is set
while not loop_data["step_event"].wait(timeout=1):
if loop_data["stop_event"].is_set():
break
if loop_data["stop_event"].is_set():
break

while loop_data["pause_event"].is_set():
print("Loop paused")
if loop_data["stop_event"].wait(timeout=1):
return
if loop_data["step_event"].wait(timeout=1):
loop_data["step_event"].clear()
if loop_data["stop_event"].is_set():
break


1 change: 1 addition & 0 deletions agentloop/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .loop import *
109 changes: 109 additions & 0 deletions agentloop/tests/loop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import threading
import time

from agentloop import start, step, stop, pause, unpause


def step_one(options_dict, loop_data):
if options_dict is None:
options_dict = {"step_one": 0, "step_two": 0}
# increment step_one
options_dict["step_one"] += 1
print("step_one: ", options_dict["step_one"])
return options_dict


def step_two(options_dict):
# increment step_two
options_dict["step_two"] += 1
print("step_two: ", options_dict["step_two"])
return options_dict


def inner_loop(context):
loop_data = start(steps=[step_one, step_two], paused=False)
for _ in range(3):
step(loop_data)
# sleep 1 s
time.sleep(0.1)
stop(loop_data) # Stop the loop
return context


def test_inner_loop():
print("Starting test_start")
loop_data = start(steps=[step_one, inner_loop, step_two], paused=False)
for _ in range(3):
step(loop_data)
# sleep 1 s
time.sleep(0.1)
assert isinstance(loop_data["thread"], threading.Thread)
assert isinstance(loop_data["step_event"], threading.Event)
assert loop_data["thread"].is_alive() is True
stop(loop_data) # Stop the loop
assert loop_data["thread"].is_alive() is False


def test_start():
print("Starting test_start")
loop_data = start(steps=[step_one, step_two], paused=False)

assert isinstance(loop_data["thread"], threading.Thread)
assert isinstance(loop_data["step_event"], threading.Event)
assert loop_data["thread"].is_alive() is True
stop(loop_data) # Stop the loop
assert loop_data["thread"].is_alive() is False


def test_start_paused():
print("Starting test_start_paused")
loop_data = start(steps=[step_one, step_two], paused=True)

assert isinstance(loop_data["thread"], threading.Thread)
assert isinstance(loop_data["step_event"], threading.Event)
assert loop_data["thread"].is_alive() is True
for _ in range(5):
step(loop_data)
# sleep 1 s
time.sleep(0.1)
stop(loop_data) # Stop the loop
assert loop_data["thread"].is_alive() is False


def test_pause_unpause():
print("Starting test_pause_unpause")

shared_dict = {"paused": False}

def check_pause_status(options_dict, loop_data):
# Modify the shared_dict to reflect pause status
shared_dict["paused"] = loop_data["pause_event"].is_set()
return options_dict
print("loop")
loop_data = start(steps=[step_one, check_pause_status, step_two, check_pause_status], paused=False)
print("loop2")
assert isinstance(loop_data["thread"], threading.Thread)
assert isinstance(loop_data["step_event"], threading.Event)
assert loop_data["thread"].is_alive() is True
print("assert")
# Initially, we're not paused
step(loop_data)
time.sleep(0.1)
assert shared_dict["paused"] == False

# After pausing, we should be paused
pause(loop_data)
step(loop_data)
shared_dict["paused"] = loop_data["pause_event"].is_set()
time.sleep(1)
assert shared_dict["paused"] == True

# After unpausing, we should no longer be paused
unpause(loop_data)
step(loop_data)
time.sleep(1)
shared_dict["paused"] = loop_data["pause_event"].is_set()
assert shared_dict["paused"] == False

stop(loop_data)
assert loop_data["thread"].is_alive() is False
44 changes: 0 additions & 44 deletions publish.sh

This file was deleted.

Loading

0 comments on commit 4705b01

Please sign in to comment.