diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e3465645..368bee60 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,8 +4,11 @@ repos: hooks: - id: ruff args: [--fix] + exclude: ^(agentstack/templates/|examples/|tests/fixtures/).* - id: ruff-format + exclude: ^(agentstack/templates/|examples/|tests/fixtures/).* - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.8.0 hooks: - - id: mypy \ No newline at end of file + - id: mypy + exclude: ^(agentstack/templates/|examples/|tests/fixtures/).* diff --git a/agentstack/agents.py b/agentstack/agents.py index 1c5ab290..951e85ab 100644 --- a/agentstack/agents.py +++ b/agentstack/agents.py @@ -1,4 +1,3 @@ -from typing import Optional import os from pathlib import Path import pydantic diff --git a/agentstack/cli/cli.py b/agentstack/cli/cli.py index 0c085d5d..daf8b29a 100644 --- a/agentstack/cli/cli.py +++ b/agentstack/cli/cli.py @@ -1,8 +1,8 @@ from typing import Optional -import os, sys +import os +import sys import time from datetime import datetime -from pathlib import Path import json import shutil @@ -413,8 +413,10 @@ def insert_template( pass # subprocess.check_output(["git", "init"]) # subprocess.check_output(["git", "add", "."]) - except: - print("Failed to initialize git repository. Maybe you're already in one? Do this with: git init") + except Exception as e: + print( + f"Failed to initialize git repository ({str(e)}). Maybe you're already in one? Do this with: git init" + ) # TODO: check if poetry is installed and if so, run poetry install in the new directory # os.system("poetry install") diff --git a/agentstack/cli/run.py b/agentstack/cli/run.py index 17c48b49..efb0400f 100644 --- a/agentstack/cli/run.py +++ b/agentstack/cli/run.py @@ -9,7 +9,7 @@ from agentstack.exceptions import ValidationError from agentstack import inputs from agentstack import frameworks -from agentstack.utils import term_color, get_framework +from agentstack.utils import term_color MAIN_FILENAME: Path = Path("src/main.py") MAIN_MODULE_NAME = "main" @@ -35,34 +35,34 @@ def _format_friendy_error_message(exception: Exception): match (name, message, tracebacks): # The user doesn't have an environment variable set for the LLM provider. - case ('AuthenticationError', m, t) if 'litellm.AuthenticationError' in t[-1]: + case ('AuthenticationError', _, t) if 'litellm.AuthenticationError' in t[-1]: variable_name = [k for k in COMMON_LLM_ENV_VARS if k in message] or ["correct"] return ( "We were unable to connect to the LLM provider. " f"Ensure your .env file has the {variable_name[0]} variable set." ) # This happens when the LLM configured for an agent is invalid. - case ('BadRequestError', m, t) if 'LLM Provider NOT provided' in t[-1]: + case ('BadRequestError', _, t) if 'LLM Provider NOT provided' in t[-1]: return ( "An invalid LLM was configured for an agent. " "Ensure the 'llm' attribute of the agent in the agents.yaml file is in the format /." ) # The user has not configured the correct agent name in the tasks.yaml file. - case ('KeyError', m, t) if 'self.tasks_config[task_name]["agent"]' in t[-2]: + case ('KeyError', _, t) if 'self.tasks_config[task_name]["agent"]' in t[-2]: return ( f"The agent {message} is not defined in your agents file. " "Ensure the 'agent' fields in your tasks.yaml correspond to an entry in the agents.yaml file." ) # The user does not have an agent defined in agents.yaml file, but it does # exist in the entrypoint code. - case ('KeyError', m, t) if 'config=self.agents_config[' in t[-2]: + case ('KeyError', _, tracebacks) if 'config=self.agents_config[' in tracebacks[-2]: return ( f"The agent {message} is not defined in your agents file. " "Ensure all agents referenced in your code are defined in the agents.yaml file." ) # The user does not have a task defined in tasks.yaml file, but it does # exist in the entrypoint code. - case ('KeyError', m, t) if 'config=self.tasks_config[' in t[-2]: + case ('KeyError', _, tracebacks) if 'config=self.tasks_config[' in tracebacks[-2]: return ( f"The task {message} is not defined in your tasks. " "Ensure all tasks referenced in your code are defined in the tasks.yaml file." diff --git a/agentstack/conf.py b/agentstack/conf.py index 2b7810e4..219c4794 100644 --- a/agentstack/conf.py +++ b/agentstack/conf.py @@ -1,5 +1,5 @@ from typing import Optional, Union -import os, sys +import os import json from pathlib import Path from pydantic import BaseModel diff --git a/agentstack/frameworks/crewai.py b/agentstack/frameworks/crewai.py index 69d21fb7..c0edb062 100644 --- a/agentstack/frameworks/crewai.py +++ b/agentstack/frameworks/crewai.py @@ -151,11 +151,9 @@ def add_agent_tools(self, agent_name: str, tool: ToolConfig): method = asttools.find_method(self.get_agent_methods(), agent_name) if method is None: raise ValidationError(f"`@agent` method `{agent_name}` does not exist in {ENTRYPOINT}") - existing_node: ast.List = self.get_agent_tools(agent_name) existing_elts: list[ast.expr] = existing_node.elts - - new_tool_nodes: list[ast.expr] = [] + # Add new tool nodes to existing elements for tool_name in tool.tools: # TODO there is definitely a better way to do this. We can't use # a `set` becasue the ast nodes are unique objects. diff --git a/agentstack/generation/agent_generation.py b/agentstack/generation/agent_generation.py index 31bbd63c..74621fe4 100644 --- a/agentstack/generation/agent_generation.py +++ b/agentstack/generation/agent_generation.py @@ -1,6 +1,5 @@ import sys from typing import Optional -from pathlib import Path from agentstack.exceptions import ValidationError from agentstack.conf import ConfigFile from agentstack import frameworks diff --git a/agentstack/generation/files.py b/agentstack/generation/files.py index f2ad90a0..cf5bb16f 100644 --- a/agentstack/generation/files.py +++ b/agentstack/generation/files.py @@ -1,6 +1,5 @@ -from typing import Optional, Union -import os, sys -from pathlib import Path +import os +import sys if sys.version_info >= (3, 11): import tomllib diff --git a/agentstack/generation/task_generation.py b/agentstack/generation/task_generation.py index 91bee560..0ff851a2 100644 --- a/agentstack/generation/task_generation.py +++ b/agentstack/generation/task_generation.py @@ -1,6 +1,5 @@ import sys from typing import Optional -from pathlib import Path from agentstack.exceptions import ValidationError from agentstack import frameworks from agentstack.utils import verify_agentstack_project diff --git a/agentstack/generation/tool_generation.py b/agentstack/generation/tool_generation.py index 314ff481..5cc390bf 100644 --- a/agentstack/generation/tool_generation.py +++ b/agentstack/generation/tool_generation.py @@ -58,9 +58,9 @@ def add_import_for_tool(self, tool: ToolConfig, framework: str): try: last_import = asttools.get_all_imports(self.tree)[-1] - start, end = self.get_node_range(last_import) + _, end = self.get_node_range(last_import) except IndexError: - start, end = 0, 0 # No imports in the file + end = 0 # No imports in the file import_statement = tool.get_import_statement(framework) self.edit_node_range(end, end, f"\n{import_statement}") diff --git a/agentstack/inputs.py b/agentstack/inputs.py index 248e0d79..550eb95a 100644 --- a/agentstack/inputs.py +++ b/agentstack/inputs.py @@ -1,4 +1,3 @@ -from typing import Optional import os from pathlib import Path from ruamel.yaml import YAML, YAMLError diff --git a/agentstack/main.py b/agentstack/main.py index eac6482a..c34f6e37 100644 --- a/agentstack/main.py +++ b/agentstack/main.py @@ -66,7 +66,7 @@ def main(): parents=[global_parser], formatter_class=argparse.RawDescriptionHelpFormatter, epilog=''' - --input-=VALUE Specify inputs to be passed to the run. + --input-=VALUE Specify inputs to be passed to the run. These will override the inputs in the project's inputs.yaml file. Examples: --input-topic=Sports --input-content-type=News ''', @@ -138,7 +138,7 @@ def main(): ) export_parser.add_argument('filename', help='The name of the file to export to') - update = subparsers.add_parser('update', aliases=['u'], help='Check for updates', parents=[global_parser]) + _ = subparsers.add_parser('update', aliases=['u'], help='Check for updates', parents=[global_parser]) # Parse known args and store unknown args in extras; some commands use them later on args, extra_args = parser.parse_known_args() diff --git a/agentstack/proj_templates.py b/agentstack/proj_templates.py index e90aaca3..5cec2add 100644 --- a/agentstack/proj_templates.py +++ b/agentstack/proj_templates.py @@ -1,5 +1,5 @@ -from typing import Optional, Literal -import os, sys +from typing import Literal +import os from pathlib import Path import pydantic import requests @@ -99,7 +99,7 @@ def write_to_file(self, filename: Path): @classmethod def from_template_name(cls, name: str) -> 'TemplateConfig': path = get_package_path() / f'templates/proj_templates/{name}.json' - if not name in get_all_template_names(): + if name not in get_all_template_names(): raise ValidationError(f"Template {name} not bundled with agentstack.") return cls.from_file(path) diff --git a/agentstack/tasks.py b/agentstack/tasks.py index f5e79846..28ee8535 100644 --- a/agentstack/tasks.py +++ b/agentstack/tasks.py @@ -1,4 +1,3 @@ -from typing import Optional import os from pathlib import Path import pydantic diff --git a/agentstack/telemetry.py b/agentstack/telemetry.py index 6fc0165c..2031a4ad 100644 --- a/agentstack/telemetry.py +++ b/agentstack/telemetry.py @@ -29,7 +29,7 @@ import psutil import requests from agentstack import conf -from agentstack.utils import get_telemetry_opt_out, get_framework, get_version +from agentstack.utils import get_telemetry_opt_out, get_version TELEMETRY_URL = 'https://api.agentstack.sh/telemetry' diff --git a/agentstack/templates/crewai/tools/pipedream_tool.py b/agentstack/templates/crewai/tools/pipedream_tool.py new file mode 100644 index 00000000..0b978864 --- /dev/null +++ b/agentstack/templates/crewai/tools/pipedream_tool.py @@ -0,0 +1,51 @@ +from crewai_tools import BaseTool +from typing import Optional, Dict +import os +import requests +import json +from pydantic import Field + +class PipedreamActionTool(BaseTool): + name: str = "pipedream_action" + description: str = "Execute Pipedream component actions" + base_url: str = "https://api.pipedream.com/v1" + api_key: Optional[str] = Field(default_factory=lambda: os.getenv("PIPEDREAM_API_KEY")) + headers: Dict[str, str] = Field(default_factory=lambda: { + "Authorization": f"Bearer {os.getenv('PIPEDREAM_API_KEY')}", + "Content-Type": "application/json" + }) + + def _run(self, component_id: str, input_data: Optional[dict] = None) -> str: + try: + url = f"{self.base_url}/components/{component_id}/event" + response = requests.post( + url, + headers=self.headers, + json=input_data or {} + ) + response.raise_for_status() + return json.dumps(response.json(), indent=2) + except Exception as e: + return f"Error executing Pipedream component: {str(e)}" + +class PipedreamTriggerTool(BaseTool): + name: str = "pipedream_trigger" + description: str = "List Pipedream component events" + base_url: str = "https://api.pipedream.com/v1" + api_key: Optional[str] = Field(default_factory=lambda: os.getenv("PIPEDREAM_API_KEY")) + headers: Dict[str, str] = Field(default_factory=lambda: { + "Authorization": f"Bearer {os.getenv('PIPEDREAM_API_KEY')}", + "Content-Type": "application/json" + }) + + def _run(self, component_id: str) -> str: + try: + url = f"{self.base_url}/components/{component_id}/events" + response = requests.get(url, headers=self.headers) + response.raise_for_status() + return json.dumps(response.json(), indent=2) + except Exception as e: + return f"Error listing Pipedream events: {str(e)}" + +pipedream_action = PipedreamActionTool() +pipedream_trigger = PipedreamTriggerTool() diff --git a/agentstack/tools/pipedream.json b/agentstack/tools/pipedream.json new file mode 100644 index 00000000..9097f193 --- /dev/null +++ b/agentstack/tools/pipedream.json @@ -0,0 +1,11 @@ +{ + "name": "pipedream", + "url": "https://pipedream.com/docs/connect/components", + "category": "api", + "packages": ["requests", "crewai_tools"], + "env": { + "PIPEDREAM_API_KEY": "..." + }, + "tools": ["pipedream_action", "pipedream_trigger"], + "cta": "Create an API key at https://pipedream.com/settings/api-key" +} diff --git a/agentstack/update.py b/agentstack/update.py index 8a01792f..e52c6636 100644 --- a/agentstack/update.py +++ b/agentstack/update.py @@ -1,5 +1,6 @@ import json -import os, sys +import os +import sys import time from pathlib import Path from packaging.version import parse as parse_version, Version @@ -50,7 +51,7 @@ def get_latest_version(package: str) -> Version: f"{ENDPOINT_URL}/{package}/", headers={"Accept": "application/vnd.pypi.simple.v1+json"} ) if response.status_code != 200: - raise Exception(f"Failed to fetch package data from pypi.") + raise Exception("Failed to fetch package data from pypi.") data = response.json() return parse_version(data['versions'][-1]) @@ -116,7 +117,7 @@ def check_for_updates(update_requested: bool = False): try: latest_version: Version = get_latest_version(AGENTSTACK_PACKAGE) - except Exception as e: + except Exception: print(term_color("Failed to retrieve package index.", 'red')) return diff --git a/agentstack/utils.py b/agentstack/utils.py index e1564dc2..c4340b03 100644 --- a/agentstack/utils.py +++ b/agentstack/utils.py @@ -1,5 +1,5 @@ -from typing import Optional, Union -import os, sys +import os +import sys import json from ruamel.yaml import YAML import re @@ -19,7 +19,7 @@ def get_version(package: str = 'agentstack'): def verify_agentstack_project(): try: - agentstack_config = conf.ConfigFile() + _ = conf.ConfigFile() # Just verify it exists except FileNotFoundError: print( "\033[31mAgentStack Error: This does not appear to be an AgentStack project." diff --git a/pyproject.toml b/pyproject.toml index 69f3c301..928f28ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,9 @@ dependencies = [ "requests>=2.32", "appdirs>=1.4.4", "python-dotenv>=1.0.1", + "crewai==0.83.0", + "crewai-tools==0.14.0", + "selenium>=4.18.1", ] [project.optional-dependencies] @@ -39,17 +42,13 @@ dev = [ ] test = [ "tox", + "pytest", + "parameterized", ] -crewai = [ - "crewai==0.83.0", - "crewai-tools==0.14.0", -] - [tool.setuptools.package-data] agentstack = ["templates/**/*"] - [project.scripts] agentstack = "agentstack.main:main" diff --git a/tests/fixtures/frameworks/crewai/entrypoint_max.py b/tests/fixtures/frameworks/crewai/entrypoint_max.py index 6ccb9af2..4ebeb514 100644 --- a/tests/fixtures/frameworks/crewai/entrypoint_max.py +++ b/tests/fixtures/frameworks/crewai/entrypoint_max.py @@ -1,6 +1,5 @@ from crewai import Agent, Crew, Process, Task from crewai.project import CrewBase, agent, crew, task -import tools @CrewBase diff --git a/tests/fixtures/frameworks/crewai/entrypoint_min.py b/tests/fixtures/frameworks/crewai/entrypoint_min.py index f423807f..2f21c25b 100644 --- a/tests/fixtures/frameworks/crewai/entrypoint_min.py +++ b/tests/fixtures/frameworks/crewai/entrypoint_min.py @@ -1,6 +1,5 @@ -from crewai import Agent, Crew, Process, Task -from crewai.project import CrewBase, agent, crew, task -import tools +from crewai import Crew, Process +from crewai.project import CrewBase, crew @CrewBase diff --git a/tests/test_agents_config.py b/tests/test_agents_config.py index 5b110192..be85df34 100644 --- a/tests/test_agents_config.py +++ b/tests/test_agents_config.py @@ -1,8 +1,6 @@ -import json -import os, sys +import os import shutil import unittest -import importlib.resources from pathlib import Path from agentstack import conf from agentstack.agents import AgentConfig, AGENTS_FILENAME @@ -22,10 +20,10 @@ def tearDown(self): def test_empty_file(self): config = AgentConfig("agent_name") assert config.name == "agent_name" - assert config.role is "" - assert config.goal is "" - assert config.backstory is "" - assert config.llm is "" + assert config.role == "" + assert config.goal == "" + assert config.backstory == "" + assert config.llm == "" def test_read_minimal_yaml(self): shutil.copy(BASE_PATH / "fixtures/agents_min.yaml", self.project_dir / AGENTS_FILENAME) diff --git a/tests/test_cli_init.py b/tests/test_cli_init.py index b07d7a3f..5ff74b9f 100644 --- a/tests/test_cli_init.py +++ b/tests/test_cli_init.py @@ -1,7 +1,7 @@ import subprocess -import os, sys +import os +import sys import unittest -from parameterized import parameterized from pathlib import Path import shutil diff --git a/tests/test_cli_loads.py b/tests/test_cli_loads.py index 6ac8fcad..84cf81d2 100644 --- a/tests/test_cli_loads.py +++ b/tests/test_cli_loads.py @@ -1,5 +1,6 @@ import subprocess -import os, sys +import os +import sys import unittest from pathlib import Path import shutil diff --git a/tests/test_cli_templates.py b/tests/test_cli_templates.py index 285b91c1..36bfad90 100644 --- a/tests/test_cli_templates.py +++ b/tests/test_cli_templates.py @@ -1,5 +1,6 @@ import subprocess -import os, sys +import os +import sys import unittest from parameterized import parameterized from pathlib import Path @@ -36,9 +37,9 @@ def test_init_command_for_template(self, template_name): @unittest.skip("We're trying a new base template. TODO: Fix this test.") def test_export_template_v1(self): - result = self._run_cli('init', f"test_project") + result = self._run_cli('init', "test_project") self.assertEqual(result.returncode, 0) - os.chdir(self.project_dir / f"test_project") + os.chdir(self.project_dir / "test_project") result = self._run_cli('generate', 'agent', 'test_agent', '--llm', 'opeenai/gpt-4o') self.assertEqual(result.returncode, 0) result = self._run_cli('generate', 'task', 'test_task', '--agent', 'test_agent') diff --git a/tests/test_cli_tools.py b/tests/test_cli_tools.py index f5048b72..9dab4b3f 100644 --- a/tests/test_cli_tools.py +++ b/tests/test_cli_tools.py @@ -1,5 +1,6 @@ import subprocess -import os, sys +import os +import sys import unittest from parameterized import parameterized from pathlib import Path diff --git a/tests/test_frameworks.py b/tests/test_frameworks.py index 4b8e3cf3..7f25ca24 100644 --- a/tests/test_frameworks.py +++ b/tests/test_frameworks.py @@ -1,4 +1,4 @@ -import os, sys +import os from pathlib import Path import shutil import unittest @@ -55,7 +55,7 @@ def test_get_framework_module(self): assert module.__name__ == f"agentstack.frameworks.{self.framework}" def test_get_framework_module_invalid(self): - with self.assertRaises(Exception) as context: + with self.assertRaises(Exception): frameworks.get_framework_module('invalid') def test_validate_project(self): @@ -64,7 +64,7 @@ def test_validate_project(self): def test_validate_project_invalid(self): self._populate_min_entrypoint() - with self.assertRaises(ValidationError) as context: + with self.assertRaises(ValidationError): frameworks.validate_project() def test_add_tool(self): @@ -84,7 +84,7 @@ def test_add_tool_starred(self): def test_add_tool_invalid(self): self._populate_min_entrypoint() - with self.assertRaises(ValidationError) as context: + with self.assertRaises(ValidationError): frameworks.add_tool(self._get_test_tool(), 'test_agent') def test_remove_tool(self): diff --git a/tests/test_generation_agent.py b/tests/test_generation_agent.py index f2b39f5f..a4e3cf8b 100644 --- a/tests/test_generation_agent.py +++ b/tests/test_generation_agent.py @@ -1,4 +1,4 @@ -import os, sys +import os from pathlib import Path import shutil import unittest @@ -7,7 +7,6 @@ from agentstack.conf import ConfigFile, set_path from agentstack import frameworks -from agentstack.exceptions import ValidationError from agentstack.generation.agent_generation import add_agent BASE_PATH = Path(__file__).parent @@ -54,7 +53,7 @@ def test_add_agent(self): ast.parse(entrypoint_src) def test_add_agent_exists(self): - with self.assertRaises(SystemExit) as context: + with self.assertRaises(SystemExit): add_agent( 'test_agent', role='role', diff --git a/tests/test_generation_files.py b/tests/test_generation_files.py index 900efdfd..0d55b439 100644 --- a/tests/test_generation_files.py +++ b/tests/test_generation_files.py @@ -8,7 +8,6 @@ from agentstack.utils import ( verify_agentstack_project, get_framework, - get_telemetry_opt_out, get_version, ) diff --git a/tests/test_generation_tasks.py b/tests/test_generation_tasks.py index 7c871cd2..5679574d 100644 --- a/tests/test_generation_tasks.py +++ b/tests/test_generation_tasks.py @@ -1,4 +1,4 @@ -import os, sys +import os from pathlib import Path import shutil import unittest @@ -6,11 +6,9 @@ import ast from agentstack.conf import ConfigFile, set_path -from agentstack.exceptions import ValidationError from agentstack import frameworks from agentstack.tasks import TaskConfig from agentstack.generation.task_generation import add_task -from agentstack.generation.agent_generation import add_agent BASE_PATH = Path(__file__).parent @@ -55,7 +53,7 @@ def test_add_task(self): ast.parse(entrypoint_src) def test_add_agent_exists(self): - with self.assertRaises(SystemExit) as context: + with self.assertRaises(SystemExit): add_task( 'test_task', description='description', diff --git a/tests/test_generation_tool.py b/tests/test_generation_tool.py index 779f7f91..7429bd80 100644 --- a/tests/test_generation_tool.py +++ b/tests/test_generation_tool.py @@ -1,4 +1,4 @@ -import os, sys +import os from pathlib import Path import shutil import unittest @@ -7,7 +7,7 @@ from agentstack.conf import ConfigFile, set_path from agentstack import frameworks -from agentstack.tools import get_all_tools, ToolConfig +from agentstack.tools import ToolConfig from agentstack.generation.tool_generation import add_tool, remove_tool, TOOLS_INIT_FILENAME diff --git a/tests/test_pipedream_tool.py b/tests/test_pipedream_tool.py new file mode 100644 index 00000000..87c96d15 --- /dev/null +++ b/tests/test_pipedream_tool.py @@ -0,0 +1,87 @@ +import unittest +from unittest.mock import patch, MagicMock +from agentstack.tools import ToolConfig +from agentstack.templates.crewai.tools.pipedream_tool import PipedreamActionTool, PipedreamTriggerTool + + +class TestPipedreamTool(unittest.TestCase): + def test_pipedream_config(self): + """Test that the Pipedream tool configuration is valid.""" + tool_conf = ToolConfig.from_tool_name('pipedream') + self.assertEqual(tool_conf.name, 'pipedream') + self.assertEqual(tool_conf.category, 'api') + self.assertIn('pipedream_action', tool_conf.tools) + self.assertIn('pipedream_trigger', tool_conf.tools) + + @patch('requests.post') + def test_pipedream_action(self, mock_post): + """Test that the Pipedream action tool executes components correctly.""" + # Setup mock response + mock_response = MagicMock() + mock_response.json.return_value = {"status": "success"} + mock_response.raise_for_status.return_value = None + mock_post.return_value = mock_response + + # Create tool and execute + tool = PipedreamActionTool() + result = tool._run('test_component_id', {'param': 'value'}) + + # Verify + self.assertEqual(result, '{\n "status": "success"\n}') + mock_post.assert_called_once_with( + 'https://api.pipedream.com/v1/components/test_component_id/event', + headers={'Authorization': 'Bearer None', 'Content-Type': 'application/json'}, + json={'param': 'value'}, + ) + + @patch('requests.post') + def test_pipedream_action_error(self, mock_post): + """Test that the Pipedream action tool handles errors correctly.""" + # Setup mock error + mock_post.side_effect = Exception('API Error') + + # Create tool and execute + tool = PipedreamActionTool() + result = tool._run('test_component_id') + + # Verify + self.assertEqual(result, 'Error executing Pipedream component: API Error') + mock_post.assert_called_once() + + @patch('requests.get') + def test_pipedream_trigger(self, mock_get): + """Test that the Pipedream trigger tool lists events correctly.""" + # Setup mock response + mock_response = MagicMock() + mock_response.json.return_value = [{"event": "test"}] + mock_response.raise_for_status.return_value = None + mock_get.return_value = mock_response + + # Create tool and execute + tool = PipedreamTriggerTool() + result = tool._run('test_component_id') + + # Verify + self.assertEqual(result, '[\n {\n "event": "test"\n }\n]') + mock_get.assert_called_once_with( + 'https://api.pipedream.com/v1/components/test_component_id/events', + headers={'Authorization': 'Bearer None', 'Content-Type': 'application/json'}, + ) + + @patch('requests.get') + def test_pipedream_trigger_error(self, mock_get): + """Test that the Pipedream trigger tool handles errors correctly.""" + # Setup mock error + mock_get.side_effect = Exception('API Error') + + # Create tool and execute + tool = PipedreamTriggerTool() + result = tool._run('test_component_id') + + # Verify + self.assertEqual(result, 'Error listing Pipedream events: API Error') + mock_get.assert_called_once() + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_tasks_config.py b/tests/test_tasks_config.py index 498ea9c8..63ea163f 100644 --- a/tests/test_tasks_config.py +++ b/tests/test_tasks_config.py @@ -1,8 +1,6 @@ -import json -import os, sys +import os import shutil import unittest -import importlib.resources from pathlib import Path from agentstack import conf from agentstack.tasks import TaskConfig, TASKS_FILENAME @@ -22,17 +20,17 @@ def tearDown(self): def test_empty_file(self): config = TaskConfig("task_name") assert config.name == "task_name" - assert config.description is "" - assert config.expected_output is "" - assert config.agent is "" + assert config.description == "" + assert config.expected_output == "" + assert config.agent == "" def test_read_minimal_yaml(self): shutil.copy(BASE_PATH / "fixtures/tasks_min.yaml", self.project_dir / TASKS_FILENAME) config = TaskConfig("task_name") assert config.name == "task_name" - assert config.description is "" - assert config.expected_output is "" - assert config.agent is "" + assert config.description == "" + assert config.expected_output == "" + assert config.agent == "" def test_read_maximal_yaml(self): shutil.copy(BASE_PATH / "fixtures/tasks_max.yaml", self.project_dir / TASKS_FILENAME) diff --git a/tests/test_templates_config.py b/tests/test_templates_config.py index 47926c0f..575d1386 100644 --- a/tests/test_templates_config.py +++ b/tests/test_templates_config.py @@ -1,5 +1,4 @@ from pathlib import Path -import json import unittest from parameterized import parameterized from agentstack.exceptions import ValidationError diff --git a/tests/test_tool_generation_init.py b/tests/test_tool_generation_init.py index 8eb0b65a..a8cee279 100644 --- a/tests/test_tool_generation_init.py +++ b/tests/test_tool_generation_init.py @@ -1,4 +1,4 @@ -import os, sys +import os from pathlib import Path import shutil import unittest @@ -42,11 +42,11 @@ def _get_test_tool_alt(self) -> ToolConfig: def test_tools_init_file(self): tools_init = ToolsInitFile(conf.PATH / TOOLS_INIT_FILENAME) # file is empty - assert tools_init.get_import_for_tool(self._get_test_tool()) == None + assert tools_init.get_import_for_tool(self._get_test_tool()) is None def test_tools_init_file_missing(self): - with self.assertRaises(ValidationError) as context: - tools_init = ToolsInitFile(conf.PATH / 'missing') + with self.assertRaises(ValidationError): + _ = ToolsInitFile(conf.PATH / 'missing') def test_tools_init_file_add_import(self): tool = self._get_test_tool() @@ -66,7 +66,7 @@ def test_tools_init_file_add_import_multiple(self): tools_init.add_import_for_tool(tool_alt, self.framework) # Should not be able to re-add a tool import - with self.assertRaises(ValidationError) as context: + with self.assertRaises(ValidationError): with ToolsInitFile(conf.PATH / TOOLS_INIT_FILENAME) as tools_init: tools_init.add_import_for_tool(tool, self.framework) diff --git a/tests/validate_pipedream_config.py b/tests/validate_pipedream_config.py new file mode 100644 index 00000000..7ba8209c --- /dev/null +++ b/tests/validate_pipedream_config.py @@ -0,0 +1,19 @@ +from agentstack.tools import ToolConfig + + +def validate_pipedream_config(): + try: + tool_conf = ToolConfig.from_tool_name("pipedream") + print("Successfully loaded tool config:") + print(f"Name: {tool_conf.name}") + print(f"Category: {tool_conf.category}") + print(f"Tools: {tool_conf.tools}") + return True + except Exception as e: + print(f"Error loading tool config: {str(e)}") + return False + + +if __name__ == "__main__": + success = validate_pipedream_config() + exit(0 if success else 1) diff --git a/tox.ini b/tox.ini index 6c6a966b..30dc9607 100644 --- a/tox.ini +++ b/tox.ini @@ -14,6 +14,6 @@ deps = commands = pytest -v {posargs} mypy: mypy agentops -setenv = +setenv = AGENTSTACK_TELEMETRY_OPT_OUT = 1 - AGENTSTACK_UPDATE_DISABLE = 1 \ No newline at end of file + AGENTSTACK_UPDATE_DISABLE = 1