mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-22 21:48:12 -05:00
Compare commits
4 Commits
testing-cl
...
swiftyos/o
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f7822d5b7 | ||
|
|
2c1275040f | ||
|
|
e627ad5a64 | ||
|
|
fc70862f76 |
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Generic, List, TypeVar
|
||||
|
||||
@@ -123,8 +124,10 @@ class ObjectLookupBase(Block, ABC, Generic[T]):
|
||||
)
|
||||
|
||||
def run(self, input_data: ObjectLookupBaseInput[T]) -> BlockOutput:
|
||||
obj = input_data.input
|
||||
key = input_data.key
|
||||
obj = input_data.input
|
||||
if isinstance(obj, str):
|
||||
obj = json.loads(obj)
|
||||
|
||||
if isinstance(obj, dict) and key in obj:
|
||||
yield "output", obj[key]
|
||||
@@ -169,7 +172,7 @@ class OutputBlock(ObjectLookupBase[Any]):
|
||||
|
||||
class DictionaryAddEntryBlock(Block):
|
||||
class Input(BlockSchema):
|
||||
dictionary: dict | None = SchemaField(
|
||||
dictionary: dict | None | str = SchemaField(
|
||||
default=None,
|
||||
description="The dictionary to add the entry to. If not provided, a new dictionary will be created.",
|
||||
placeholder='{"key1": "value1", "key2": "value2"}',
|
||||
@@ -216,6 +219,8 @@ class DictionaryAddEntryBlock(Block):
|
||||
# If no dictionary is provided, create a new one
|
||||
if input_data.dictionary is None:
|
||||
updated_dict = {}
|
||||
elif isinstance(input_data.dictionary, str):
|
||||
updated_dict = json.loads(input_data.dictionary)
|
||||
else:
|
||||
# Create a copy of the input dictionary to avoid modifying the original
|
||||
updated_dict = input_data.dictionary.copy()
|
||||
@@ -300,3 +305,41 @@ class ListAddEntryBlock(Block):
|
||||
yield "updated_list", updated_list
|
||||
except Exception as e:
|
||||
yield "error", f"Failed to add entry to list: {str(e)}"
|
||||
|
||||
|
||||
class CreateListBlock(Block):
|
||||
class Input(BlockSchema):
|
||||
items: List[Any] = Field(
|
||||
description="Items to be added to the list", default=[]
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
list: List[Any] = SchemaField(description="The list with the new entry added.")
|
||||
error: str = SchemaField(description="Error message if the operation failed.")
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
id="aeb08fc1-2fc1-4141-bc8e-f758f183a812",
|
||||
description="Adds a new entry to a list. The entry can be of any type. If no list is provided, a new one is created.",
|
||||
categories={BlockCategory.BASIC},
|
||||
input_schema=CreateListBlock.Input,
|
||||
output_schema=CreateListBlock.Output,
|
||||
test_input=[
|
||||
{
|
||||
"items": [1, "string", {"existing_key": "existing_value"}],
|
||||
},
|
||||
],
|
||||
test_output=[
|
||||
(
|
||||
"list",
|
||||
[
|
||||
1,
|
||||
"string",
|
||||
{"existing_key": "existing_value"},
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
def run(self, input_data: Input) -> BlockOutput:
|
||||
yield "list", input_data.items
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from typing import Any, List, Tuple
|
||||
|
||||
from autogpt_server.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from autogpt_server.data.model import SchemaField
|
||||
from autogpt_server.data.model import Field, SchemaField
|
||||
|
||||
|
||||
class ForEachBlock(Block):
|
||||
@@ -10,9 +10,13 @@ class ForEachBlock(Block):
|
||||
description="The list of items to iterate over",
|
||||
placeholder="[1, 2, 3, 4, 5]",
|
||||
)
|
||||
return_index: bool = Field(
|
||||
description="If it should just yield the item or the item and index",
|
||||
default=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
item: Tuple[int, Any] = SchemaField(
|
||||
item: Tuple[int, Any] | Any = SchemaField(
|
||||
description="A tuple with the index and current item in the iteration"
|
||||
)
|
||||
|
||||
@@ -33,4 +37,7 @@ class ForEachBlock(Block):
|
||||
|
||||
def run(self, input_data: Input) -> BlockOutput:
|
||||
for index, item in enumerate(input_data.items):
|
||||
yield "item", (index, item)
|
||||
if input_data.return_index:
|
||||
yield "item", (index, item)
|
||||
else:
|
||||
yield "item", item
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Union
|
||||
from typing import Any, Union
|
||||
|
||||
from autogpt_server.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
|
||||
@@ -137,3 +137,41 @@ class TimerBlock(Block):
|
||||
|
||||
time.sleep(total_seconds)
|
||||
yield "message", "timer finished"
|
||||
|
||||
|
||||
class WaitBlock(Block):
|
||||
class Input(BlockSchema):
|
||||
data: Any
|
||||
seconds: Union[int, str] = 0
|
||||
minutes: Union[int, str] = 0
|
||||
hours: Union[int, str] = 0
|
||||
days: Union[int, str] = 0
|
||||
|
||||
class Output(BlockSchema):
|
||||
data: Any
|
||||
message: str
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
id="d67a9c52-5e4e-11e2-bcfd-0770200c9c61",
|
||||
description="This block waits a given time period, then returns the input data",
|
||||
categories={BlockCategory.TEXT},
|
||||
input_schema=WaitBlock.Input,
|
||||
output_schema=WaitBlock.Output,
|
||||
test_input=[{"seconds": 1, "data": "something"}],
|
||||
test_output=[
|
||||
("data", "something"),
|
||||
],
|
||||
)
|
||||
|
||||
def run(self, input_data: Input) -> BlockOutput:
|
||||
|
||||
seconds = int(input_data.seconds)
|
||||
minutes = int(input_data.minutes)
|
||||
hours = int(input_data.hours)
|
||||
days = int(input_data.days)
|
||||
|
||||
total_seconds = seconds + minutes * 60 + hours * 3600 + days * 86400
|
||||
|
||||
time.sleep(total_seconds)
|
||||
yield "data", input_data.data
|
||||
|
||||
319
rnd/autogpt_server/graph_templates/Async Bug Graph_v27.json
Normal file
319
rnd/autogpt_server/graph_templates/Async Bug Graph_v27.json
Normal file
@@ -0,0 +1,319 @@
|
||||
{
|
||||
"id": "dd6eee5f-1ec9-46a9-840a-98d652bfeaef",
|
||||
"version": 27,
|
||||
"is_active": true,
|
||||
"is_template": false,
|
||||
"name": "Async Bug Graph",
|
||||
"description": "Agent Description",
|
||||
"nodes": [
|
||||
{
|
||||
"id": "ee1aa2d8-8ae9-49c5-b949-c8bc1f64c1b1",
|
||||
"block_id": "b2g2c3d4-5e6f-7g8h-9i0j-k1l2m3n4o5p6",
|
||||
"input_default": {
|
||||
"key": "item"
|
||||
},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": 115.43720926499259,
|
||||
"y": 111.1650147372838
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "672dc715-1c4a-4845-9ca4-cdea58392389",
|
||||
"block_id": "db7d8f02-2f44-4c55-ab7a-eae0941f0c30",
|
||||
"input_default": {
|
||||
"texts": [],
|
||||
"format": "{path_string} same as {should_be_same}"
|
||||
},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": 2761.2885335656524,
|
||||
"y": 381.88199866097335
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "b875a2ee-cc1c-43e5-bfa2-6181c1c267aa",
|
||||
"block_id": "aeb08fc1-2fc1-4141-bc8e-f758f183a812",
|
||||
"input_default": {
|
||||
"items": [
|
||||
"{\"item\": \"one\"}",
|
||||
"{\"item\": \"two\"}",
|
||||
"{\"item\": \"three\"}",
|
||||
"{\"item\": \"four\"}"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": -907.0675129350209,
|
||||
"y": -158.6404843200935
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "8629f421-1792-4cc9-9ff9-2619d330208d",
|
||||
"block_id": "f3b1c1b2-4c4f-4f0d-8d2f-4c4f0d8d2f4c",
|
||||
"input_default": {},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": 3356.6302763437966,
|
||||
"y": 365.69194750094584
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "a796407e-e2aa-4a78-8349-74e8fcf29acd",
|
||||
"block_id": "31d1064e-7446-4693-a7d4-65e5ca1180d1",
|
||||
"input_default": {
|
||||
"key": "path_string"
|
||||
},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": 2022.5433773817927,
|
||||
"y": 341.365624355902
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "b88a15a0-b206-4fb7-87d9-6c0855f30706",
|
||||
"block_id": "31d1064e-7446-4693-a7d4-65e5ca1180d1",
|
||||
"input_default": {
|
||||
"key": "should_be_same"
|
||||
},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": 2378.4218596312107,
|
||||
"y": -662.6702903841343
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "8c784897-9989-42b0-b46c-f0ff2c552ccf",
|
||||
"block_id": "f8e7d6c5-b4a3-2c1d-0e9f-8g7h6i5j4k3l",
|
||||
"input_default": {
|
||||
"return_index": false
|
||||
},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": -307.80980510121657,
|
||||
"y": -183.40632582304875
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "7920e629-a792-4931-bbda-f7e8f48a7f10",
|
||||
"block_id": "db7d8f02-2f44-4c55-ab7a-eae0941f0c30",
|
||||
"input_default": {
|
||||
"texts": [],
|
||||
"format": "{path_string} same as {should_be_same}"
|
||||
},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": 3237.363889239568,
|
||||
"y": -338.7056564591866
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "1bf74f10-9c11-4302-9b25-1454c4aa8c1f",
|
||||
"block_id": "d67a9c52-5e4e-11e2-bcfd-0770200c9c61",
|
||||
"input_default": {
|
||||
"seconds": "3"
|
||||
},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": 1423.4009426673902,
|
||||
"y": 412.93463171958416
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "d1b1e337-c214-4586-9f35-f297fee7373b",
|
||||
"block_id": "31d1064e-7446-4693-a7d4-65e5ca1180d1",
|
||||
"input_default": {
|
||||
"key": "should_be_same"
|
||||
},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": 2109.5446580301345,
|
||||
"y": 860.7214483654554
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "b7eb124c-9e3f-42de-9c51-957f1fdba448",
|
||||
"block_id": "31d1064e-7446-4693-a7d4-65e5ca1180d1",
|
||||
"input_default": {
|
||||
"key": "path_string"
|
||||
},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": 1568.9031528685712,
|
||||
"y": -160.68552495576077
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "e6f6208e-528f-4465-a0be-2665d5fa9a77",
|
||||
"block_id": "db7d8f02-2f44-4c55-ab7a-eae0941f0c30",
|
||||
"input_default": {
|
||||
"format": "Fast Path Item is {item}"
|
||||
},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": 792.1126241529676,
|
||||
"y": -556.8424043502238
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "a8ee5748-55d7-41d1-9e3a-922da1011e20",
|
||||
"block_id": "db7d8f02-2f44-4c55-ab7a-eae0941f0c30",
|
||||
"input_default": {
|
||||
"texts": [],
|
||||
"format": "Slow Path Item is {item}"
|
||||
},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": 740.520265186629,
|
||||
"y": 84.492978274699
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "352967f4-8490-4203-b413-a332904521b1",
|
||||
"block_id": "f3b1c1b2-4c4f-4f0d-8d2f-4c4f0d8d2f4c",
|
||||
"input_default": {},
|
||||
"metadata": {
|
||||
"position": {
|
||||
"x": 3952.194366925888,
|
||||
"y": -245.2362702707926
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"id": "67516fd1-4c28-4e67-8ade-07d8e78a91f8",
|
||||
"source_id": "a8ee5748-55d7-41d1-9e3a-922da1011e20",
|
||||
"sink_id": "1bf74f10-9c11-4302-9b25-1454c4aa8c1f",
|
||||
"source_name": "output",
|
||||
"sink_name": "data",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "72d5ee64-d4ba-4cf8-a414-345babb1810f",
|
||||
"source_id": "d1b1e337-c214-4586-9f35-f297fee7373b",
|
||||
"sink_id": "672dc715-1c4a-4845-9ca4-cdea58392389",
|
||||
"source_name": "updated_dictionary",
|
||||
"sink_name": "named_texts",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "a73cfe8a-f60b-4fb9-9bd8-cb11b8be5316",
|
||||
"source_id": "1bf74f10-9c11-4302-9b25-1454c4aa8c1f",
|
||||
"sink_id": "a796407e-e2aa-4a78-8349-74e8fcf29acd",
|
||||
"source_name": "data",
|
||||
"sink_name": "value",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "cc213a85-e649-44da-999a-fe8d2bb022a7",
|
||||
"source_id": "e6f6208e-528f-4465-a0be-2665d5fa9a77",
|
||||
"sink_id": "b7eb124c-9e3f-42de-9c51-957f1fdba448",
|
||||
"source_name": "output",
|
||||
"sink_name": "value",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "7f9959af-145a-4fe7-b897-317e51b8f70e",
|
||||
"source_id": "b88a15a0-b206-4fb7-87d9-6c0855f30706",
|
||||
"sink_id": "7920e629-a792-4931-bbda-f7e8f48a7f10",
|
||||
"source_name": "updated_dictionary",
|
||||
"sink_name": "named_texts",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "6eb53905-d954-4236-aec6-fd38c3a18872",
|
||||
"source_id": "ee1aa2d8-8ae9-49c5-b949-c8bc1f64c1b1",
|
||||
"sink_id": "b88a15a0-b206-4fb7-87d9-6c0855f30706",
|
||||
"source_name": "output",
|
||||
"sink_name": "value",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "5a4c2d4a-5914-4855-a72e-1a559ae33e4b",
|
||||
"source_id": "8c784897-9989-42b0-b46c-f0ff2c552ccf",
|
||||
"sink_id": "a8ee5748-55d7-41d1-9e3a-922da1011e20",
|
||||
"source_name": "item",
|
||||
"sink_name": "named_texts",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "05a0fd2c-fe23-4395-a550-b7bc8446ab9f",
|
||||
"source_id": "7920e629-a792-4931-bbda-f7e8f48a7f10",
|
||||
"sink_id": "352967f4-8490-4203-b413-a332904521b1",
|
||||
"source_name": "output",
|
||||
"sink_name": "text",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "1451c239-fcb3-4c7a-8d1c-d668995f7cfd",
|
||||
"source_id": "ee1aa2d8-8ae9-49c5-b949-c8bc1f64c1b1",
|
||||
"sink_id": "d1b1e337-c214-4586-9f35-f297fee7373b",
|
||||
"source_name": "output",
|
||||
"sink_name": "value",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "4be8734c-009c-43ed-a5f8-1e0943df8419",
|
||||
"source_id": "8c784897-9989-42b0-b46c-f0ff2c552ccf",
|
||||
"sink_id": "e6f6208e-528f-4465-a0be-2665d5fa9a77",
|
||||
"source_name": "item",
|
||||
"sink_name": "named_texts",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "1d02f828-acd6-46ca-a84c-0dc17e4890e1",
|
||||
"source_id": "672dc715-1c4a-4845-9ca4-cdea58392389",
|
||||
"sink_id": "8629f421-1792-4cc9-9ff9-2619d330208d",
|
||||
"source_name": "output",
|
||||
"sink_name": "text",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "101f20e5-ec8a-46fc-883d-f01c135e457d",
|
||||
"source_id": "a796407e-e2aa-4a78-8349-74e8fcf29acd",
|
||||
"sink_id": "d1b1e337-c214-4586-9f35-f297fee7373b",
|
||||
"source_name": "updated_dictionary",
|
||||
"sink_name": "dictionary",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "1e41f028-4682-46f7-940e-e0dc6e593d1e",
|
||||
"source_id": "b7eb124c-9e3f-42de-9c51-957f1fdba448",
|
||||
"sink_id": "b88a15a0-b206-4fb7-87d9-6c0855f30706",
|
||||
"source_name": "updated_dictionary",
|
||||
"sink_name": "dictionary",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "c80961ee-166d-4523-95d8-5cceb3975793",
|
||||
"source_id": "b875a2ee-cc1c-43e5-bfa2-6181c1c267aa",
|
||||
"sink_id": "8c784897-9989-42b0-b46c-f0ff2c552ccf",
|
||||
"source_name": "list",
|
||||
"sink_name": "items",
|
||||
"is_static": false
|
||||
},
|
||||
{
|
||||
"id": "1685867f-d1b6-46e3-9676-404e9be4fe6d",
|
||||
"source_id": "8c784897-9989-42b0-b46c-f0ff2c552ccf",
|
||||
"sink_id": "ee1aa2d8-8ae9-49c5-b949-c8bc1f64c1b1",
|
||||
"source_name": "item",
|
||||
"sink_name": "input",
|
||||
"is_static": false
|
||||
}
|
||||
],
|
||||
"subgraphs": {}
|
||||
}
|
||||
@@ -1,7 +1,17 @@
|
||||
import pytest
|
||||
from prisma.models import User
|
||||
|
||||
from autogpt_server.blocks.basic import ObjectLookupBlock, ValueBlock
|
||||
from autogpt_server.blocks.basic import (
|
||||
ObjectLookupBlock,
|
||||
ValueBlock,
|
||||
CreateListBlock,
|
||||
ObjectLookupBase,
|
||||
DictionaryAddEntryBlock,
|
||||
PrintingBlock,
|
||||
)
|
||||
from autogpt_server.blocks.iteration import ForEachBlock
|
||||
from autogpt_server.blocks.text import TextFormatterBlock
|
||||
from autogpt_server.blocks.time_blocks import WaitBlock
|
||||
from autogpt_server.blocks.maths import MathsBlock, Operation
|
||||
from autogpt_server.data import execution, graph
|
||||
from autogpt_server.executor import ExecutionManager
|
||||
@@ -17,6 +27,7 @@ async def execute_graph(
|
||||
test_user: User,
|
||||
input_data: dict,
|
||||
num_execs: int = 4,
|
||||
timeout: int = 20,
|
||||
) -> str:
|
||||
# --- Test adding new executions --- #
|
||||
response = await agent_server.execute_graph(test_graph.id, input_data, test_user.id)
|
||||
@@ -24,7 +35,7 @@ async def execute_graph(
|
||||
|
||||
# Execution queue should be empty
|
||||
assert await wait_execution(
|
||||
test_manager, test_user.id, test_graph.id, graph_exec_id, num_execs
|
||||
test_manager, test_user.id, test_graph.id, graph_exec_id, num_execs, timeout=timeout
|
||||
)
|
||||
return graph_exec_id
|
||||
|
||||
@@ -239,3 +250,237 @@ async def test_static_input_link_on_graph(server):
|
||||
for exec_data in executions[-3:]:
|
||||
assert exec_data.status == execution.ExecutionStatus.COMPLETED
|
||||
assert exec_data.output_data == {"result": [9]}
|
||||
|
||||
|
||||
@pytest.mark.asyncio(scope="session")
|
||||
async def test_async_bug_graph_behavior(server):
|
||||
"""
|
||||
This test is asserting the behaviour of the Async Bug Graph.
|
||||
|
||||
Test scenario:
|
||||
The graph has multiple nodes performing object lookups, formatting texts, and processing lists.
|
||||
The graph links them in a specific sequence to test asynchronous operations and dependencies.
|
||||
"""
|
||||
nodes = [
|
||||
graph.Node( # Node 0 - executed once
|
||||
block_id=CreateListBlock().id,
|
||||
input_default={
|
||||
"items": [
|
||||
'{"item": "one"}',
|
||||
'{"item": "two"}',
|
||||
'{"item": "three"}',
|
||||
'{"item": "four"}',
|
||||
]
|
||||
},
|
||||
),
|
||||
graph.Node( # Node 1 - executed once
|
||||
block_id=ForEachBlock().id,
|
||||
input_default={"return_index": False},
|
||||
),
|
||||
graph.Node( # Node 2 - executed once per loop
|
||||
block_id=ObjectLookupBlock().id,
|
||||
input_default={"key": "item", "input": {}},
|
||||
),
|
||||
graph.Node( # Node 3 (TOP) - executed once per loop
|
||||
block_id=TextFormatterBlock().id,
|
||||
input_default={"format": "Fast Path Item is {item}"},
|
||||
),
|
||||
graph.Node( # Node 4 (BOTTOM) - executed once per loop
|
||||
block_id=TextFormatterBlock().id,
|
||||
input_default={"format": "Slow Path Item is {item}"},
|
||||
),
|
||||
graph.Node( # Node 5 (TOP) - executed once per loop
|
||||
block_id=DictionaryAddEntryBlock().id,
|
||||
input_default={"key": "path_string"},
|
||||
),
|
||||
graph.Node( # Node 6 (BOTTOM) - executed once per loop
|
||||
block_id=WaitBlock().id,
|
||||
input_default={"seconds": 1},
|
||||
),
|
||||
graph.Node( # Node 7 (TOP) - executed once per loop
|
||||
block_id=DictionaryAddEntryBlock().id,
|
||||
input_default={"key": "should_be_same"},
|
||||
),
|
||||
graph.Node( # Node 8 (BOTTOM) - executed once per loop
|
||||
block_id=DictionaryAddEntryBlock().id,
|
||||
input_default={"key": "path_string"},
|
||||
),
|
||||
graph.Node( # Node 9 (BOTTOM) - executed once per loop
|
||||
block_id=DictionaryAddEntryBlock().id,
|
||||
input_default={"key": "should_be_same"},
|
||||
),
|
||||
graph.Node( # Node 10 (TOP) - executed once per loop
|
||||
block_id=TextFormatterBlock().id,
|
||||
input_default={"format": "{path_string} same as {should_be_same}"},
|
||||
),
|
||||
graph.Node( # Node 11 (BOTTOM) - executed once per loop
|
||||
block_id=TextFormatterBlock().id,
|
||||
input_default={"format": "{path_string} same as {should_be_same}"},
|
||||
),
|
||||
graph.Node( # Node 12 (TOP) - executed once per loop
|
||||
block_id=PrintingBlock().id,
|
||||
),
|
||||
graph.Node( # Node 13 (BOTTOM) - executed once per loop
|
||||
block_id=PrintingBlock().id,
|
||||
),
|
||||
]
|
||||
# num execs = 2 initial + 9 per loop = 2 + 9*3 = 29
|
||||
|
||||
links = [
|
||||
graph.Link(
|
||||
source_id=nodes[0].id,
|
||||
sink_id=nodes[1].id,
|
||||
source_name="list",
|
||||
sink_name="items",
|
||||
is_static=False,
|
||||
),
|
||||
# ForEachBlock needs to be connected to 2x text formmater blocks and object lookup block
|
||||
graph.Link(
|
||||
source_id=nodes[1].id, # ForEachBlock
|
||||
sink_id=nodes[2].id, # ObjectLookupBlock
|
||||
source_name="item",
|
||||
sink_name="input",
|
||||
is_static=False,
|
||||
),
|
||||
graph.Link(
|
||||
source_id=nodes[1].id, # ForEachBlock
|
||||
sink_id=nodes[3].id, # TextFormatterBlock
|
||||
source_name="item",
|
||||
sink_name="named_texts",
|
||||
is_static=False,
|
||||
),
|
||||
graph.Link(
|
||||
source_id=nodes[1].id, # ForEachBlock
|
||||
sink_id=nodes[4].id, # TextFormatterBlock
|
||||
source_name="item",
|
||||
sink_name="named_texts",
|
||||
is_static=False,
|
||||
),
|
||||
# Top Execution Path
|
||||
graph.Link(
|
||||
source_id=nodes[3].id, # TextFormatterBlock
|
||||
sink_id=nodes[5].id, # DictionaryAddEntryBlock
|
||||
source_name="output",
|
||||
sink_name="value",
|
||||
is_static=False,
|
||||
),
|
||||
graph.Link(
|
||||
source_id=nodes[5].id, # DictionaryAddEntryBlock
|
||||
sink_id=nodes[7].id, # DictionaryAddEntryBlock
|
||||
source_name="updated_dictionary",
|
||||
sink_name="dictionary",
|
||||
is_static=False,
|
||||
),
|
||||
graph.Link(
|
||||
source_id=nodes[7].id, # DictionaryAddEntryBlock
|
||||
sink_id=nodes[10].id, # TextFormatterBlock
|
||||
source_name="updated_dictionary",
|
||||
sink_name="named_texts",
|
||||
is_static=False,
|
||||
),
|
||||
graph.Link(
|
||||
source_id=nodes[10].id, # TextFormatterBlock
|
||||
sink_id=nodes[12].id, # PrintingBlock
|
||||
source_name="output",
|
||||
sink_name="text",
|
||||
is_static=False,
|
||||
),
|
||||
# Object Lookup Block needs to be connected to the DictionaryAddEntryBlock
|
||||
graph.Link(
|
||||
source_id=nodes[2].id, # ObjectLookupBlock
|
||||
sink_id=nodes[7].id, # DictionaryAddEntryBlock
|
||||
source_name="output",
|
||||
sink_name="value",
|
||||
),
|
||||
graph.Link(
|
||||
source_id=nodes[10].id, # TextFormatterBlock
|
||||
sink_id=nodes[12].id, # PrintingBlock
|
||||
source_name="output",
|
||||
sink_name="text",
|
||||
is_static=False,
|
||||
),
|
||||
# Bottom Execution Path
|
||||
graph.Link(
|
||||
source_id=nodes[4].id, # TextFormatterBlock
|
||||
sink_id=nodes[6].id, # WaitBlock
|
||||
source_name="output",
|
||||
sink_name="data",
|
||||
is_static=False,
|
||||
),
|
||||
graph.Link(
|
||||
source_id=nodes[6].id, # WaitBlock
|
||||
sink_id=nodes[8].id, # DictionaryAddEntryBlock
|
||||
source_name="data",
|
||||
sink_name="value",
|
||||
is_static=False,
|
||||
),
|
||||
graph.Link(
|
||||
source_id=nodes[8].id, # DictionaryAddEntryBlock
|
||||
sink_id=nodes[9].id, # DictionaryAddEntryBlock
|
||||
source_name="updated_dictionary",
|
||||
sink_name="dictionary",
|
||||
is_static=False,
|
||||
),
|
||||
# Object Lookup Block needs to be connected to the DictionaryAddEntryBlock
|
||||
graph.Link(
|
||||
source_id=nodes[2].id, # ObjectLookupBlock
|
||||
sink_id=nodes[9].id, # DictionaryAddEntryBlock
|
||||
source_name="output",
|
||||
sink_name="value",
|
||||
),
|
||||
graph.Link(
|
||||
source_id=nodes[9].id, # DictionaryAddEntryBlock
|
||||
sink_id=nodes[11].id, # TextFormatterBlock
|
||||
source_name="updated_dictionary",
|
||||
sink_name="named_texts",
|
||||
is_static=False,
|
||||
),
|
||||
graph.Link(
|
||||
source_id=nodes[11].id, # TextFormatterBlock
|
||||
sink_id=nodes[13].id, # PrintingBlock
|
||||
source_name="output",
|
||||
sink_name="text",
|
||||
is_static=False,
|
||||
),
|
||||
|
||||
]
|
||||
|
||||
test_graph = graph.Graph(
|
||||
name="Async Bug Graph",
|
||||
description="Agent Description",
|
||||
nodes=nodes,
|
||||
links=links,
|
||||
)
|
||||
|
||||
test_user = await create_test_user()
|
||||
test_graph = await graph.create_graph(test_graph, user_id=test_user.id)
|
||||
graph_exec_id = await execute_graph(
|
||||
server.agent_server, server.exec_manager, test_graph, test_user, {}, 54
|
||||
)
|
||||
executions = await server.agent_server.get_run_execution_results(
|
||||
test_graph.id, graph_exec_id, test_user.id
|
||||
)
|
||||
assert len(executions) == 54
|
||||
|
||||
expected_ouputs = set(
|
||||
[
|
||||
"Fast Path Item is one should be the same as one",
|
||||
"Fast Path Item is two should be the same as two",
|
||||
"Fast Path Item is three should be the same as three",
|
||||
"Fast Path Item is four should be the same as four",
|
||||
"Slow Path Item is one should be the same as one",
|
||||
"Slow Path Item is two should be the same as two",
|
||||
"Slow Path Item is three should be the same as three",
|
||||
"Slow Path Item is four should be the same as four",
|
||||
]
|
||||
)
|
||||
|
||||
actaul_outputs = set()
|
||||
|
||||
for exec_data in executions:
|
||||
if "text" in exec_data.input_data:
|
||||
output = exec_data.input_data["text"]
|
||||
actaul_outputs.add(output)
|
||||
|
||||
assert expected_ouputs.isdisjoint(actaul_outputs), f"Actual: {actaul_outputs}"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user