diff --git a/maestro/cli/__init__.py b/maestro/cli/__init__.py index 63f2e4e..38d7ccf 100644 --- a/maestro/cli/__init__.py +++ b/maestro/cli/__init__.py @@ -12,12 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -import dotenv +import os, sys, dotenv dotenv.load_dotenv() -from .cli import CLI - -__all__ = { - "CLI" -} +sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/../src") +sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/../cli") \ No newline at end of file diff --git a/maestro/cli/cli.py b/maestro/cli/cli.py deleted file mode 100644 index 8b6e3bd..0000000 --- a/maestro/cli/cli.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright © 2025 IBM -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from .commands import Validate, Create, Run, Deploy - -class CLI: - def __init__(self, args): - self.args = args - VERBOSE, DRY_RUN = False, False - if self.args['--verbose']: - VERBOSE = True - if self.args['--dry-run']: - DRY_RUN = True - - def command(self): - if self.args.get('validate') and self.args['validate']: - return Validate(self.args) - elif self.args.get('create') and self.args['create']: - return Create(self.args) - elif self.args.get('run') and self.args['run']: - return Run(self.args) - elif self.args.get('deploy') and self.args['deploy']: - return Deploy(self.args) - else: - raise Exception("Invalid command") diff --git a/maestro/cli/commands.py b/maestro/cli/commands.py index 07e650b..44c1bec 100644 --- a/maestro/cli/commands.py +++ b/maestro/cli/commands.py @@ -15,11 +15,32 @@ import os, yaml, json, jsonschema from openai import OpenAI -from src.workflow import Workflow - from jsonschema.exceptions import ValidationError -from .common import Console, parse_yaml +from common import Console, parse_yaml +from src.workflow import Workflow + +# Root CLI class +class CLI: + def __init__(self, args): + self.args = args + VERBOSE, DRY_RUN = False, False + if self.args['--verbose']: + VERBOSE = True + if self.args['--dry-run']: + DRY_RUN = True + + def command(self): + if self.args.get('validate') and self.args['validate']: + return Validate(self.args) + elif self.args.get('create') and self.args['create']: + return Create(self.args) + elif self.args.get('run') and self.args['run']: + return Run(self.args) + elif self.args.get('deploy') and self.args['deploy']: + return Deploy(self.args) + else: + raise Exception("Invalid command") # Base class for all commands class Command: diff --git a/maestro/cli/maestro.py b/maestro/cli/maestro.py index e9c29ec..ca2746a 100755 --- a/maestro/cli/maestro.py +++ b/maestro/cli/maestro.py @@ -38,8 +38,8 @@ from docopt import docopt -from .cli import CLI -from .common import Console +from commands import CLI +from common import Console def __execute(command): try: diff --git a/maestro/demos/workflows/activity-planner-crewai.ai/run.py b/maestro/demos/workflows/activity-planner-crewai.ai/run.py index ceebb88..27d8fc2 100755 --- a/maestro/demos/workflows/activity-planner-crewai.ai/run.py +++ b/maestro/demos/workflows/activity-planner-crewai.ai/run.py @@ -10,7 +10,6 @@ sys.path.append("maestro/demos/agents/crewai/activity_planner") sys.path.append("demos/agents/crewai/activity_planner") - def test_agent_runs() -> None: """ Verify the test agent runs correctly diff --git a/maestro/deployment/Dockerfile b/maestro/deployments/Dockerfile similarity index 100% rename from maestro/deployment/Dockerfile rename to maestro/deployments/Dockerfile diff --git a/maestro/deployment/api.py b/maestro/deployments/api.py similarity index 100% rename from maestro/deployment/api.py rename to maestro/deployments/api.py diff --git a/maestro/deployment/entrypoint.sh b/maestro/deployments/entrypoint.sh similarity index 100% rename from maestro/deployment/entrypoint.sh rename to maestro/deployments/entrypoint.sh diff --git a/maestro/deployment/entrypoint_api.sh b/maestro/deployments/entrypoint_api.sh similarity index 100% rename from maestro/deployment/entrypoint_api.sh rename to maestro/deployments/entrypoint_api.sh diff --git a/maestro/deployment/maestro.html b/maestro/deployments/maestro.html similarity index 100% rename from maestro/deployment/maestro.html rename to maestro/deployments/maestro.html diff --git a/maestro/deployment/maestro.sh b/maestro/deployments/maestro.sh similarity index 100% rename from maestro/deployment/maestro.sh rename to maestro/deployments/maestro.sh diff --git a/maestro/deployment/maestro.yaml b/maestro/deployments/maestro.yaml similarity index 100% rename from maestro/deployment/maestro.yaml rename to maestro/deployments/maestro.yaml diff --git a/maestro/src/maestro-cli b/maestro/maestro similarity index 100% rename from maestro/src/maestro-cli rename to maestro/maestro diff --git a/maestro/pyproject.toml b/maestro/pyproject.toml index f37a0a6..baf1af5 100644 --- a/maestro/pyproject.toml +++ b/maestro/pyproject.toml @@ -8,8 +8,6 @@ readme = "README.md" packages = [ {include = "src", from="."}, {include = "cli", from="."}, - #{ include = "activity_planner", from = "demos/agents/crewai" } - # TODO - Packaging demos allows them to be run after a pip install ] [tool.poetry.dependencies] diff --git a/maestro/src/__init__.py b/maestro/src/__init__.py index 3a07e59..bd64b8d 100644 --- a/maestro/src/__init__.py +++ b/maestro/src/__init__.py @@ -1,4 +1,25 @@ -# SPDX-License-Identifier: Apache-2.0 +# Copyright © 2025 IBM +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dotenv + +dotenv.load_dotenv() + from .workflow import Workflow from .bee_agent import BeeAgent from .agent import save_agent, restore_agent, remove_agent + +__all__ = { + "Workflow" +} diff --git a/maestro/src/agent_factory.py b/maestro/src/agent_factory.py index 16ff6ac..85b560e 100644 --- a/maestro/src/agent_factory.py +++ b/maestro/src/agent_factory.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 from enum import Enum from typing import Callable, Type, Union + from .bee_agent import BeeAgent from .crewai_agent import CrewAIAgent diff --git a/maestro/src/bee_agent.py b/maestro/src/bee_agent.py index a69e394..ee23504 100755 --- a/maestro/src/bee_agent.py +++ b/maestro/src/bee_agent.py @@ -1,14 +1,13 @@ #! /usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 -import os +import os, dotenv -import dotenv from openai import AssistantEventHandler, OpenAI from openai.types.beta import AssistantStreamEvent from openai.types.beta.threads.runs import RunStep, RunStepDelta, ToolCall -from .agent import Agent +from src.agent import Agent dotenv.load_dotenv() diff --git a/maestro/src/mock_agent.py b/maestro/src/mock_agent.py old mode 100644 new mode 100755 diff --git a/maestro/src/workflow.py b/maestro/src/workflow.py index d1eb1bf..e00f407 100755 --- a/maestro/src/workflow.py +++ b/maestro/src/workflow.py @@ -1,26 +1,23 @@ #! /usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 -import os -import dotenv -from .step import Step -from .agent_factory import AgentFramework +import os, dotenv -# TODO: Refactor later to factory or similar -from .crewai_agent import CrewAIAgent -from .bee_agent import BeeAgent -from .mock_agent import MockAgent -from .agent import restore_agent +from src.step import Step +from src.agent_factory import AgentFramework -dotenv.load_dotenv() +from src.crewai_agent import CrewAIAgent +from src.bee_agent import BeeAgent +from src.mock_agent import MockAgent +from src.agent import restore_agent +dotenv.load_dotenv() def find_index(steps, name): for step in steps: if step.get("name") == name: return steps.index(step) - @staticmethod def get_agent_class(framework: str) -> type: if os.getenv("DRY_RUN"): @@ -30,7 +27,6 @@ def get_agent_class(framework: str) -> type: else: return BeeAgent - class Workflow: agents = {} steps = {} diff --git a/maestro/tests/__init__.py b/maestro/tests/__init__.py index 9881313..ccc9e27 100644 --- a/maestro/tests/__init__.py +++ b/maestro/tests/__init__.py @@ -1 +1,18 @@ -# SPDX-License-Identifier: Apache-2.0 +# Copyright © 2025 IBM +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os, sys + +sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/../src") +sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/../cli") \ No newline at end of file diff --git a/maestro/tests/bee/test_bee.py b/maestro/tests/bee/test_bee.py index cbf4432..625ffa3 100755 --- a/maestro/tests/bee/test_bee.py +++ b/maestro/tests/bee/test_bee.py @@ -1,15 +1,24 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 +# Copyright © 2025 IBM +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os, dotenv, yaml from unittest import TestCase -import dotenv -import yaml -import os from pytest_mock import mocker -# TODO consider moving to same directory as BeeAgent source -from src import Workflow -from src import BeeAgent +from src.workflow import Workflow +from src.bee_agent import BeeAgent dotenv.load_dotenv() @@ -43,5 +52,4 @@ def parse_yaml(file_path): print(result) assert result is not None - # This gets returned by the mock function which uses the prompt from the workflow - assert (result["final_prompt"]=="Mock agent: answer for Welcome") + assert result["final_prompt"].startswith("OK:Welcome") diff --git a/maestro/cli/test_commands.py b/maestro/tests/cli/test_commands.py similarity index 99% rename from maestro/cli/test_commands.py rename to maestro/tests/cli/test_commands.py index 8f2faf8..b4ce212 100755 --- a/maestro/cli/test_commands.py +++ b/maestro/tests/cli/test_commands.py @@ -18,11 +18,11 @@ from unittest import TestCase -from .cli import CLI +from cli.commands import CLI class TestCommand(TestCase): - TEST_FIXTURES_ROOT_PATH = os.path.join(os.path.dirname(__file__), "../tests") - SCHEMAS_ROOT_PATH = os.path.join(os.path.dirname(__file__), "../schemas") + TEST_FIXTURES_ROOT_PATH = os.path.join(os.path.dirname(__file__), "..") + SCHEMAS_ROOT_PATH = os.path.join(os.path.dirname(__file__), "../../schemas") def get_fixture(self, file_name): return os.path.join(self.TEST_FIXTURES_ROOT_PATH, file_name) diff --git a/maestro/tests/crewai/test_crewai.py b/maestro/tests/crewai/test_crewai.py index 32c4024..a88918a 100755 --- a/maestro/tests/crewai/test_crewai.py +++ b/maestro/tests/crewai/test_crewai.py @@ -1,19 +1,30 @@ #!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 + +# Copyright © 2025 IBM +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dotenv, os, yaml from unittest import TestCase -import dotenv -import os -import yaml -from src import Workflow +from src.workflow import Workflow dotenv.load_dotenv() # TODO: consider moving setup here # @pytest.fixture(scope="module") - class CrewAITest(TestCase): def test_agent_runs(self) -> None: diff --git a/maestro/tests/examples/test_condition.py b/maestro/tests/examples/test_condition.py old mode 100644 new mode 100755 index 13570c9..cd72b51 --- a/maestro/tests/examples/test_condition.py +++ b/maestro/tests/examples/test_condition.py @@ -1,25 +1,32 @@ -#! /usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 +#!/usr/bin/env python3 + +# Copyright © 2025 IBM +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os, sys, json, dotenv, yaml -import json -import os -import sys - -import dotenv from openai import OpenAI -import yaml -from src import Workflow -dotenv.load_dotenv() +from src.workflow import Workflow +dotenv.load_dotenv() def parse_yaml(file_path): with open(file_path, "r") as file: yaml_data = list(yaml.safe_load_all(file)) return yaml_data - - if __name__ == "__main__": agents_yaml = parse_yaml(os.path.join(os.path.dirname(__file__),"condition_agents.yaml")) workflow_yaml = parse_yaml(os.path.join(os.path.dirname(__file__),"condition_workflow.yaml")) diff --git a/maestro/tests/workflow/test_sequence.py b/maestro/tests/workflow/test_sequence.py old mode 100644 new mode 100755 index 2fbc09c..0add74f --- a/maestro/tests/workflow/test_sequence.py +++ b/maestro/tests/workflow/test_sequence.py @@ -1,14 +1,26 @@ #!/usr/bin/env python3 -# SPDX-License-Identifier: Apache-2.0 -import yaml -import dotenv +# Copyright © 2025 IBM +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os, yaml, dotenv + from unittest import TestCase from pytest_mock import mocker -import os -from src import Workflow -from src import BeeAgent +from src.workflow import Workflow +from src.bee_agent import BeeAgent dotenv.load_dotenv()