From 5200c26ff9eeccbf02963409cc8ff412c23a204f Mon Sep 17 00:00:00 2001 From: Mic Neale Date: Wed, 11 Sep 2024 16:26:42 +1000 Subject: [PATCH 1/7] add a jira toolkit --- .goosehints | 2 ++ pyproject.toml | 1 + src/goose/toolkit/jira.py | 27 +++++++++++++++++++++++++++ src/goose/toolkit/prompts/jira.jinja | 23 +++++++++++++++++++++++ tests/test_jira.py | 26 ++++++++++++++++++++++++++ 5 files changed, 79 insertions(+) create mode 100644 .goosehints create mode 100644 src/goose/toolkit/jira.py create mode 100644 src/goose/toolkit/prompts/jira.jinja create mode 100644 tests/test_jira.py diff --git a/.goosehints b/.goosehints new file mode 100644 index 000000000000..7be3856b15d6 --- /dev/null +++ b/.goosehints @@ -0,0 +1,2 @@ +This is a python CLI app that uses UV. Read CONTRIBUTING.md for information on how to build and test it as needed. +Some key concepts are that it is run as a command line interface, dependes on the "ai-exchange" package, and has the concept of toolkits which are ways that its behavior can be extended. Look in src/goose and tests. \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index dcdc37893c13..de5b28eccab2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ goose-ai = "goose.module_name" [project.entry-points."goose.toolkit"] developer = "goose.toolkit.developer:Developer" github = "goose.toolkit.github:Github" +jira = "goose.toolkit.jira:Jira" screen = "goose.toolkit.screen:Screen" repo_context = "goose.toolkit.repo_context.repo_context:RepoContext" diff --git a/src/goose/toolkit/jira.py b/src/goose/toolkit/jira.py new file mode 100644 index 000000000000..69c00f2d38f3 --- /dev/null +++ b/src/goose/toolkit/jira.py @@ -0,0 +1,27 @@ +from exchange import Message # type: ignore +from goose.toolkit.base import tool # type: ignore +import re + +from goose.toolkit.base import Toolkit + + +class Jira(Toolkit): + """Provides an additional prompt on how to interact with Jira""" + + def system(self) -> str: + """Retrieve detailed configuration and procedural guidelines for Jira operations""" + return Message.load("prompts/jira.jinja").text + + @tool + def is_jira_issue(self, issue_key: str) -> str: + """ + Checks if a given string is a valid JIRA issue key. + Use this if it looks like the user is asking about a JIRA issue. + + Args: + issue_key (str): The potential Jira issue key to be validated. + + """ + pattern = r"[A-Z]+-\d+" + return bool(re.match(pattern, issue_key)) + diff --git a/src/goose/toolkit/prompts/jira.jinja b/src/goose/toolkit/prompts/jira.jinja new file mode 100644 index 000000000000..3e7d11493a4a --- /dev/null +++ b/src/goose/toolkit/prompts/jira.jinja @@ -0,0 +1,23 @@ +You can interact with jira issues via the `jira` command line generally. +If it fails to auth, prompt the user to run `jira init` in a separate terminal and then try again. + +Typically when someone requests you to look at a ticket, they mean to view +not just the top level comments and history, but also the comments nested within that ticket and status. + +Some usages are for looking up a JIRA backlog, or looking up a JIRA issue. +Use the tool is_jira_issue if not sure that a string that looks like a jira issue is. + +Use `jira --help` if not sure of command line options. + +If the jira command line is not installed, you can install it as follows: + +{% if os == 'Darwin' %} +On macOS, install with: +```sh +brew tap ankitpokhrel/jira-cli +brew install jira-cli +``` +{% else %} +On other operating systems, refer to the instructions here: https://github.com/ankitpokhrel/jira-cli +{% endif %} + diff --git a/tests/test_jira.py b/tests/test_jira.py new file mode 100644 index 000000000000..f19555ee43a3 --- /dev/null +++ b/tests/test_jira.py @@ -0,0 +1,26 @@ +import unittest +from unittest.mock import patch +from goose.toolkit.jira import Jira + +class TestJiraToolkit(unittest.TestCase): + + @patch('goose.toolkit.jira.Message.load') + def test_jira_system_prompt(self, mock_load): + mock_load.return_value.text = "This is a prompt for jira" + jira_toolkit = Jira(None) + prompt = jira_toolkit.system() + # Ensure Jinja template syntax isn't present in the loaded prompt + self.assertNotIn("{%", prompt) + self.assertNotIn("%}", prompt) + self.assertEqual(prompt, "This is a prompt for jira") + + def test_is_jira_issue(self): + jira_toolkit = Jira(None) + valid_jira_issue = "PROJ-123" + invalid_jira_issue = "INVALID_ISSUE" + # Ensure the regex correctly identifies valid JIRA issues + self.assertTrue(jira_toolkit.is_jira_issue(valid_jira_issue)) + self.assertFalse(jira_toolkit.is_jira_issue(invalid_jira_issue)) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file From cb0b8d2a9b74c5b1ff2b2f3592c019cedfcddea6 Mon Sep 17 00:00:00 2001 From: Mic Neale Date: Wed, 11 Sep 2024 16:32:38 +1000 Subject: [PATCH 2/7] ruff checks --- .goosehints | 3 ++- src/goose/toolkit/jira.py | 2 +- tests/test_jira.py | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.goosehints b/.goosehints index 7be3856b15d6..f445dda0e014 100644 --- a/.goosehints +++ b/.goosehints @@ -1,2 +1,3 @@ This is a python CLI app that uses UV. Read CONTRIBUTING.md for information on how to build and test it as needed. -Some key concepts are that it is run as a command line interface, dependes on the "ai-exchange" package, and has the concept of toolkits which are ways that its behavior can be extended. Look in src/goose and tests. \ No newline at end of file +Some key concepts are that it is run as a command line interface, dependes on the "ai-exchange" package, and has the concept of toolkits which are ways that its behavior can be extended. Look in src/goose and tests. +Once the user has UV installed it should be able to be used effectively along with uvx to run tasks as needed \ No newline at end of file diff --git a/src/goose/toolkit/jira.py b/src/goose/toolkit/jira.py index 69c00f2d38f3..34fe906367be 100644 --- a/src/goose/toolkit/jira.py +++ b/src/goose/toolkit/jira.py @@ -21,7 +21,7 @@ def is_jira_issue(self, issue_key: str) -> str: Args: issue_key (str): The potential Jira issue key to be validated. - """ + """ pattern = r"[A-Z]+-\d+" return bool(re.match(pattern, issue_key)) diff --git a/tests/test_jira.py b/tests/test_jira.py index f19555ee43a3..37ea32a37e21 100644 --- a/tests/test_jira.py +++ b/tests/test_jira.py @@ -3,7 +3,7 @@ from goose.toolkit.jira import Jira class TestJiraToolkit(unittest.TestCase): - + @patch('goose.toolkit.jira.Message.load') def test_jira_system_prompt(self, mock_load): mock_load.return_value.text = "This is a prompt for jira" @@ -21,6 +21,6 @@ def test_is_jira_issue(self): # Ensure the regex correctly identifies valid JIRA issues self.assertTrue(jira_toolkit.is_jira_issue(valid_jira_issue)) self.assertFalse(jira_toolkit.is_jira_issue(invalid_jira_issue)) - + if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() From 8e594192e611f98325ee7a57befe7fac21ba4ae7 Mon Sep 17 00:00:00 2001 From: Mic Neale Date: Wed, 11 Sep 2024 16:35:49 +1000 Subject: [PATCH 3/7] more fixes --- src/goose/toolkit/jira.py | 1 - tests/test_jira.py | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/goose/toolkit/jira.py b/src/goose/toolkit/jira.py index 34fe906367be..398d89ed7da9 100644 --- a/src/goose/toolkit/jira.py +++ b/src/goose/toolkit/jira.py @@ -24,4 +24,3 @@ def is_jira_issue(self, issue_key: str) -> str: """ pattern = r"[A-Z]+-\d+" return bool(re.match(pattern, issue_key)) - diff --git a/tests/test_jira.py b/tests/test_jira.py index 37ea32a37e21..c62b60989116 100644 --- a/tests/test_jira.py +++ b/tests/test_jira.py @@ -2,9 +2,9 @@ from unittest.mock import patch from goose.toolkit.jira import Jira -class TestJiraToolkit(unittest.TestCase): - @patch('goose.toolkit.jira.Message.load') +class TestJiraToolkit(unittest.TestCase): + @patch("goose.toolkit.jira.Message.load") def test_jira_system_prompt(self, mock_load): mock_load.return_value.text = "This is a prompt for jira" jira_toolkit = Jira(None) @@ -22,5 +22,6 @@ def test_is_jira_issue(self): self.assertTrue(jira_toolkit.is_jira_issue(valid_jira_issue)) self.assertFalse(jira_toolkit.is_jira_issue(invalid_jira_issue)) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() From 244caa38160a5aa969d81a8e7f6192c3b0bfd952 Mon Sep 17 00:00:00 2001 From: Mic Neale Date: Wed, 11 Sep 2024 17:51:56 +1000 Subject: [PATCH 4/7] mention the new toolkit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 873e31ee7d75..37572342427e 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,8 @@ Rules designed to control or manage the output of the model. Moderators that cur * `screen`: for letting goose take a look at your screen to help debug or work on designs (gives goose eyes) * `github`: for awareness and suggestions on how to use github * `repo_context`: for summarizing and understanding a repository you are working in. +* `jira`: for working with JIRA (issues, backlogs, tasks, bugs etc) + #### Configuring goose per repo From 2cc548e42d4b8ac45f83ffa3d3105203129b02d4 Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Fri, 13 Sep 2024 10:54:02 +1000 Subject: [PATCH 5/7] Update src/goose/toolkit/prompts/jira.jinja Co-authored-by: Bradley Axen --- src/goose/toolkit/prompts/jira.jinja | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/goose/toolkit/prompts/jira.jinja b/src/goose/toolkit/prompts/jira.jinja index 3e7d11493a4a..0f327f9e2790 100644 --- a/src/goose/toolkit/prompts/jira.jinja +++ b/src/goose/toolkit/prompts/jira.jinja @@ -12,12 +12,13 @@ Use `jira --help` if not sure of command line options. If the jira command line is not installed, you can install it as follows: {% if os == 'Darwin' %} -On macOS, install with: +If jira is not an available command, suggest to install it with brew: ```sh brew tap ankitpokhrel/jira-cli brew install jira-cli ``` {% else %} -On other operating systems, refer to the instructions here: https://github.com/ankitpokhrel/jira-cli +If jira is not available as a command, suggest to install it following the instructions at +https://github.com/ankitpokhrel/jira-cli {% endif %} From 9dba71464b1aceede7c54ef4719987c79d23b62e Mon Sep 17 00:00:00 2001 From: Mic Neale Date: Mon, 16 Sep 2024 18:28:20 +1000 Subject: [PATCH 6/7] feedback on PR --- src/goose/toolkit/jira.py | 5 ++-- src/goose/toolkit/prompts/jira.jinja | 7 ++--- tests/test_jira.py | 40 +++++++++++++--------------- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/goose/toolkit/jira.py b/src/goose/toolkit/jira.py index 398d89ed7da9..9fb24cad32a2 100644 --- a/src/goose/toolkit/jira.py +++ b/src/goose/toolkit/jira.py @@ -1,7 +1,6 @@ from exchange import Message # type: ignore from goose.toolkit.base import tool # type: ignore import re - from goose.toolkit.base import Toolkit @@ -10,7 +9,8 @@ class Jira(Toolkit): def system(self) -> str: """Retrieve detailed configuration and procedural guidelines for Jira operations""" - return Message.load("prompts/jira.jinja").text + template_content = Message.load("prompts/jira.jinja").text + return template_content @tool def is_jira_issue(self, issue_key: str) -> str: @@ -24,3 +24,4 @@ def is_jira_issue(self, issue_key: str) -> str: """ pattern = r"[A-Z]+-\d+" return bool(re.match(pattern, issue_key)) + diff --git a/src/goose/toolkit/prompts/jira.jinja b/src/goose/toolkit/prompts/jira.jinja index 3e7d11493a4a..6c2f5ad17e0d 100644 --- a/src/goose/toolkit/prompts/jira.jinja +++ b/src/goose/toolkit/prompts/jira.jinja @@ -11,13 +11,10 @@ Use `jira --help` if not sure of command line options. If the jira command line is not installed, you can install it as follows: -{% if os == 'Darwin' %} On macOS, install with: ```sh brew tap ankitpokhrel/jira-cli brew install jira-cli ``` -{% else %} -On other operating systems, refer to the instructions here: https://github.com/ankitpokhrel/jira-cli -{% endif %} - +On other operating systems or for alternative installation methods, refer to the instructions here: +https://github.com/ankitpokhrel/jira-cli diff --git a/tests/test_jira.py b/tests/test_jira.py index c62b60989116..966a6ba8975a 100644 --- a/tests/test_jira.py +++ b/tests/test_jira.py @@ -1,27 +1,25 @@ -import unittest -from unittest.mock import patch +import pytest from goose.toolkit.jira import Jira +@pytest.fixture +def jira_toolkit(): + return Jira(None) -class TestJiraToolkit(unittest.TestCase): - @patch("goose.toolkit.jira.Message.load") - def test_jira_system_prompt(self, mock_load): - mock_load.return_value.text = "This is a prompt for jira" - jira_toolkit = Jira(None) - prompt = jira_toolkit.system() - # Ensure Jinja template syntax isn't present in the loaded prompt - self.assertNotIn("{%", prompt) - self.assertNotIn("%}", prompt) - self.assertEqual(prompt, "This is a prompt for jira") - def test_is_jira_issue(self): - jira_toolkit = Jira(None) - valid_jira_issue = "PROJ-123" - invalid_jira_issue = "INVALID_ISSUE" - # Ensure the regex correctly identifies valid JIRA issues - self.assertTrue(jira_toolkit.is_jira_issue(valid_jira_issue)) - self.assertFalse(jira_toolkit.is_jira_issue(invalid_jira_issue)) +def test_jira_system_prompt(jira_toolkit): + prompt = jira_toolkit.system() + print("System Prompt:\n", prompt) + # Ensure Jinja template syntax isn't present in the loaded prompt + assert "{%" not in prompt + assert "%}" not in prompt + # Ensure both installation instructions are present in the prompt + assert "On macOS, install with:" in prompt + assert "On other operating systems or for alternative installation methods" in prompt -if __name__ == "__main__": - unittest.main() +def test_is_jira_issue(jira_toolkit): + valid_jira_issue = "PROJ-123" + invalid_jira_issue = "INVALID_ISSUE" + # Ensure the regex correctly identifies valid JIRA issues + assert jira_toolkit.is_jira_issue(valid_jira_issue) + assert not jira_toolkit.is_jira_issue(invalid_jira_issue) From 959bab8c533974d2ceea12e60290fc4fdd398e7e Mon Sep 17 00:00:00 2001 From: Mic Neale Date: Mon, 16 Sep 2024 18:34:32 +1000 Subject: [PATCH 7/7] format --- src/goose/toolkit/jira.py | 1 - tests/test_jira.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/goose/toolkit/jira.py b/src/goose/toolkit/jira.py index 9fb24cad32a2..a6cda8b6ddf0 100644 --- a/src/goose/toolkit/jira.py +++ b/src/goose/toolkit/jira.py @@ -24,4 +24,3 @@ def is_jira_issue(self, issue_key: str) -> str: """ pattern = r"[A-Z]+-\d+" return bool(re.match(pattern, issue_key)) - diff --git a/tests/test_jira.py b/tests/test_jira.py index 70141f7b9392..16e23ae49343 100644 --- a/tests/test_jira.py +++ b/tests/test_jira.py @@ -1,6 +1,7 @@ import pytest from goose.toolkit.jira import Jira + @pytest.fixture def jira_toolkit(): return Jira(None)