From c016350bc60dd9f59cc376e1e8c081fab25ea595 Mon Sep 17 00:00:00 2001 From: Collin Dutter Date: Thu, 21 Nov 2024 18:30:45 +0000 Subject: [PATCH] Refactor/tools (#1361) --- CHANGELOG.md | 12 + MIGRATION.md | 134 ++++++ .../knowledge-bases/accessing-data.md | 2 +- .../official-tools/aws-iam-tool.md | 65 --- .../official-tools/aws-s3-tool.md | 42 -- .../official-tools/google-calendar-tool.md | 7 - .../official-tools/google-docs-tool.md | 34 -- .../official-tools/google-drive-tool.md | 31 -- .../official-tools/google-gmail-tool.md | 32 -- .../griptape-cloud-knowledge-base-tool.md | 9 - .../official-tools/openweather-tool.md | 7 - .../official-tools/src/aws_iam_tool_1.py | 13 - .../official-tools/src/aws_s3_tool_1.py | 13 - .../src/google_calendar_tool_1.py | 29 -- .../official-tools/src/google_docs_tool_1.py | 29 -- .../official-tools/src/google_drive_tool_1.py | 29 -- .../official-tools/src/google_gmail_tool_1.py | 30 -- .../griptape_cloud_knowledge_base_tool_1.py | 18 - .../official-tools/src/openweather_tool_1.py | 14 - griptape/tools/__init__.py | 20 - griptape/tools/aws_iam/__init__.py | 0 griptape/tools/aws_iam/tool.py | 84 ---- griptape/tools/aws_s3/__init__.py | 0 griptape/tools/aws_s3/tool.py | 216 ---------- griptape/tools/base_aws_tool.py | 27 -- griptape/tools/base_google_tool.py | 57 --- griptape/tools/google_calendar/__init__.py | 0 .../tools/google_calendar/requirements.txt | 1 - griptape/tools/google_calendar/tool.py | 122 ------ griptape/tools/google_docs/__init__.py | 0 griptape/tools/google_docs/requirements.txt | 1 - griptape/tools/google_docs/tool.py | 246 ----------- griptape/tools/google_drive/__init__.py | 0 griptape/tools/google_drive/requirements.txt | 1 - griptape/tools/google_drive/tool.py | 399 ------------------ griptape/tools/google_gmail/__init__.py | 0 griptape/tools/google_gmail/requirements.txt | 1 - griptape/tools/google_gmail/tool.py | 57 --- .../griptape_cloud_knowledge_base/__init__.py | 0 .../griptape_cloud_knowledge_base/tool.py | 70 --- griptape/tools/openweather/__init__.py | 0 griptape/tools/openweather/tool.py | 208 --------- mkdocs.yml | 8 - tests/unit/tools/test_aws_iam_tool.py | 31 -- tests/unit/tools/test_aws_s3_tool.py | 52 --- tests/unit/tools/test_google_docs_tool.py | 24 -- tests/unit/tools/test_google_drive_tool.py | 52 --- tests/unit/tools/test_google_gmail_tool.py | 12 - ...test_griptape_cloud_knowledge_base_tool.py | 85 ---- tests/unit/tools/test_openweather_tool.py | 72 ---- 50 files changed, 147 insertions(+), 2249 deletions(-) delete mode 100644 docs/griptape-tools/official-tools/aws-iam-tool.md delete mode 100644 docs/griptape-tools/official-tools/aws-s3-tool.md delete mode 100644 docs/griptape-tools/official-tools/google-calendar-tool.md delete mode 100644 docs/griptape-tools/official-tools/google-docs-tool.md delete mode 100644 docs/griptape-tools/official-tools/google-drive-tool.md delete mode 100644 docs/griptape-tools/official-tools/google-gmail-tool.md delete mode 100644 docs/griptape-tools/official-tools/griptape-cloud-knowledge-base-tool.md delete mode 100644 docs/griptape-tools/official-tools/openweather-tool.md delete mode 100644 docs/griptape-tools/official-tools/src/aws_iam_tool_1.py delete mode 100644 docs/griptape-tools/official-tools/src/aws_s3_tool_1.py delete mode 100644 docs/griptape-tools/official-tools/src/google_calendar_tool_1.py delete mode 100644 docs/griptape-tools/official-tools/src/google_docs_tool_1.py delete mode 100644 docs/griptape-tools/official-tools/src/google_drive_tool_1.py delete mode 100644 docs/griptape-tools/official-tools/src/google_gmail_tool_1.py delete mode 100644 docs/griptape-tools/official-tools/src/griptape_cloud_knowledge_base_tool_1.py delete mode 100644 docs/griptape-tools/official-tools/src/openweather_tool_1.py delete mode 100644 griptape/tools/aws_iam/__init__.py delete mode 100644 griptape/tools/aws_iam/tool.py delete mode 100644 griptape/tools/aws_s3/__init__.py delete mode 100644 griptape/tools/aws_s3/tool.py delete mode 100644 griptape/tools/base_aws_tool.py delete mode 100644 griptape/tools/base_google_tool.py delete mode 100644 griptape/tools/google_calendar/__init__.py delete mode 100644 griptape/tools/google_calendar/requirements.txt delete mode 100644 griptape/tools/google_calendar/tool.py delete mode 100644 griptape/tools/google_docs/__init__.py delete mode 100644 griptape/tools/google_docs/requirements.txt delete mode 100644 griptape/tools/google_docs/tool.py delete mode 100644 griptape/tools/google_drive/__init__.py delete mode 100644 griptape/tools/google_drive/requirements.txt delete mode 100644 griptape/tools/google_drive/tool.py delete mode 100644 griptape/tools/google_gmail/__init__.py delete mode 100644 griptape/tools/google_gmail/requirements.txt delete mode 100644 griptape/tools/google_gmail/tool.py delete mode 100644 griptape/tools/griptape_cloud_knowledge_base/__init__.py delete mode 100644 griptape/tools/griptape_cloud_knowledge_base/tool.py delete mode 100644 griptape/tools/openweather/__init__.py delete mode 100644 griptape/tools/openweather/tool.py delete mode 100644 tests/unit/tools/test_aws_iam_tool.py delete mode 100644 tests/unit/tools/test_aws_s3_tool.py delete mode 100644 tests/unit/tools/test_google_docs_tool.py delete mode 100644 tests/unit/tools/test_google_drive_tool.py delete mode 100644 tests/unit/tools/test_google_gmail_tool.py delete mode 100644 tests/unit/tools/test_griptape_cloud_knowledge_base_tool.py delete mode 100644 tests/unit/tools/test_openweather_tool.py diff --git a/CHANGELOG.md b/CHANGELOG.md index d36a958b4..128242ea7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **BREAKING**: Updated `numpy` to `~2.0.2` and `pandas` to `^2.2`. - **BREAKING**: Renamed `StructureRunTask.driver` to `StructureRunTask.structure_run_driver`. - **BREAKING**: Renamed `StructureRunTool.driver` to `StructureRunTool.structure_run_driver`. +- **BREAKING**: Moved the following Google Tools to the [Griptape Google Extension](https://github.com/griptape-ai/griptape-google): + - `GoogleCalendarTool` + - `GoogleDocsTool` + - `GoogleDriveTool` + - `GoogleGmailTool` +- **BREAKING**: Moved the following AWS Tools to the [Griptape AWS Extension](https://github.com/griptape-ai/griptape-google): + - `AwsCliTool` + - `AwsIamTool` + - `AwsPricingTool` + - `AwsS3Tool` +- **BREAKING**: Moved the `OpenWeatherTool` to the [Griptape Open Weather Extension](https://github.com/griptape-ai/griptape-open-weather) +- **BREAKING**: Removed `GriptapeCloudKnowledgeBaseTool`. Use a RAG Engine with `GriptapeCloudVectorStoreDriver` instead. - File Manager Driver path logic has been improved. - `LocalFileManagerDriver.workdir` can now be a relative path or absolute path. Relative paths will be prefixed with the current working directory. - `AmazonS3FileManagerDriver.workdir` can now be a relative path or absolute path. Relative paths will be prefixed with `/`. diff --git a/MIGRATION.md b/MIGRATION.md index c01c26b28..fbeaec0a8 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -279,6 +279,140 @@ StructureRunTool( ) ``` +### Moved Google Tools To Griptape Google Extension + +Google tools have been moved to the `griptape-google` extension. Install the extension to use Google tools. + +```bash +poetry add git+https://github.com/griptape-ai/griptape-google.git +``` + +#### Before + +```python +from griptape.tools import GoogleGmailTool +``` + +#### After + +```python +from griptape.google.tools import GoogleGmailTool +``` + +### Moved AWS Tools To Griptape AWS Extension + +AWS tools have been moved to the `griptape-aws` extension. Install the extension to use AWS tools. + +```bash +poetry add git+https://github.com/griptape-ai/griptape-aws.git +``` + +#### Before + +```python +from griptape.tools import AwsS3Tool +``` + +#### After + +```python +from griptape.aws.tools import AwsS3Tool +``` + +### Moved `OpenWeatherTool` To Griptape OpenWeather Extension + +`OpenWeatherTool` has been moved to the `griptape-openweather` extension. Install the extension to use the tool. + +```bash +poetry add git+https://github.com/griptape-ai/griptape-open-weather.git +``` + +#### Before + +```python +from griptape.tools import OpenWeatherTool +``` + +#### After + +```python +from griptape.openweather.tools import OpenWeatherTool +``` + +### Removed `GriptapeCloudKnowledgeBaseTool` + +`GriptapeCloudKnowledgeBaseTool` has been removed. Build a RAG Engine with a `GriptapeCloudVectorStoreDriver` instead. + +#### Before + +```python +import os + +from griptape.structures import Agent +from griptape.tools import GriptapeCloudKnowledgeBaseTool + +knowledge_base_client = GriptapeCloudKnowledgeBaseTool( + description="Contains information about the company and its operations", + api_key=os.environ["GT_CLOUD_API_KEY"], + knowledge_base_id=os.environ["GT_CLOUD_KB_ID"], +) + +agent = Agent( + tools=[ + knowledge_base_client, + ] +) + +agent.run("What is the company's corporate travel policy?") +``` + +#### After + +```python +from __future__ import annotations + +import os + +from griptape.drivers import GriptapeCloudVectorStoreDriver +from griptape.engines.rag import RagEngine +from griptape.engines.rag.modules import ( + PromptResponseRagModule, + VectorStoreRetrievalRagModule, +) +from griptape.engines.rag.stages import ( + ResponseRagStage, + RetrievalRagStage, +) +from griptape.structures import Agent +from griptape.tools import RagTool + +engine = RagEngine( + retrieval_stage=RetrievalRagStage( + retrieval_modules=[ + VectorStoreRetrievalRagModule( + vector_store_driver=GriptapeCloudVectorStoreDriver( + api_key=os.environ["GT_CLOUD_API_KEY"], + knowledge_base_id=os.environ["GT_CLOUD_KB_ID"], + ) + ) + ] + ), + response_stage=ResponseRagStage( + response_modules=[PromptResponseRagModule()], + ), +) + +agent = Agent( + tools=[ + RagTool( + description="Contains information about the company and its operations", + rag_engine=engine, + ), + ], +) +agent.run("What is the company's corporate travel policy?") +``` + ## 0.33.X to 0.34.X ### `AnthropicDriversConfig` Embedding Driver diff --git a/docs/griptape-cloud/knowledge-bases/accessing-data.md b/docs/griptape-cloud/knowledge-bases/accessing-data.md index 1890127e6..a5dcf00ed 100644 --- a/docs/griptape-cloud/knowledge-bases/accessing-data.md +++ b/docs/griptape-cloud/knowledge-bases/accessing-data.md @@ -30,4 +30,4 @@ curl -H "Authorization: Bearer ${GT_CLOUD_API_KEY}" --json '{"query": "test ques ## Using the Griptape Framework -You can use the [GriptapeCloudVectorStoreDriver](../../griptape-framework/drivers/vector-store-drivers.md/#griptape-cloud-knowledge-base) to query your Knowledge Base with Griptape and the [GriptapeCloudKnowledgeBaseTool](../../griptape-tools/official-tools/griptape-cloud-knowledge-base-tool.md) to search. +You can use the [GriptapeCloudVectorStoreDriver](../../griptape-framework/drivers/vector-store-drivers.md/#griptape-cloud-knowledge-base) to query your Knowledge Base with Griptape. diff --git a/docs/griptape-tools/official-tools/aws-iam-tool.md b/docs/griptape-tools/official-tools/aws-iam-tool.md deleted file mode 100644 index 3524c36b7..000000000 --- a/docs/griptape-tools/official-tools/aws-iam-tool.md +++ /dev/null @@ -1,65 +0,0 @@ -# Aws Iam Tool - -This tool enables LLMs to make AWS IAM API requests. - -```python ---8<-- "docs/griptape-tools/official-tools/src/aws_iam_tool_1.py" -``` - -``` -[08/12/24 14:56:59] INFO ToolkitTask 12345abcd67890efghijk1112131415 - Input: List all my IAM users -[08/12/24 14:57:00] INFO Subtask 54321dcba09876fedcba1234567890ab - Actions: [ - { - "tag": "call_OxhQ9ITNIFq0WjkSnOCYAx8h", - "name": "AwsIamClient", - "path": "list_users", - "input": { - "values": {} - } - } - ] - INFO Subtask 54321dcba09876fedcba1234567890ab - Response: {'Path': '/', 'UserName': 'dummy-user-1', 'UserId': 'AIDAAAAAA1111AAAAAA1111', 'Arn': - 'arn:aws:iam::123456789012:user/dummy-user-1', 'CreateDate': datetime.datetime(2024, 8, 7, 15, 8, 7, tzinfo=tzutc())} - - {'Path': '/', 'UserName': 'dummy-user-2', 'UserId': 'AIDBBBBBB2222BBBBBB2222', 'Arn': - 'arn:aws:iam::123456789012:user/dummy-user-2', 'CreateDate': datetime.datetime(2023, 7, 18, 20, 29, 27, tzinfo=tzutc())} - - {'Path': '/', 'UserName': 'dummy-user-3', 'UserId': 'AIDCCCCCC3333CCCCCC3333', 'Arn': - 'arn:aws:iam::123456789012:user/dummy-user-3', 'CreateDate': datetime.datetime(2024, 7, 15, 19, 39, 41, tzinfo=tzutc())} - - {'Path': '/', 'UserName': 'dummy-user-4', 'UserId': 'AIDDDDDDD4444DDDDDD4444', 'Arn': - 'arn:aws:iam::123456789012:user/dummy-user-4', 'CreateDate': datetime.datetime(2024, 8, 2, 19, 28, 31, tzinfo=tzutc())} - - {'Path': '/', 'UserName': 'dummy-user-5', 'UserId': 'AIDEEEEE5555EEEEE5555', 'Arn': - 'arn:aws:iam::123456789012:user/dummy-user-5', 'CreateDate': datetime.datetime(2023, 8, 29, 20, 56, 37, tzinfo=tzutc())} -[08/12/24 14:57:08] INFO ToolkitTask 12345abcd67890efghijk1112131415 - Output: Here are all your IAM users: - - 1. **Username:** dummy-user-1 - - **UserId:** AIDAAAAAA1111AAAAAA1111 - - **Arn:** arn:aws:iam::123456789012:user/dummy-user-1 - - **CreateDate:** 2024-08-07 - - 2. **Username:** dummy-user-2 - - **UserId:** AIDBBBBBB2222BBBBBB2222 - - **Arn:** arn:aws:iam::123456789012:user/dummy-user-2 - - **CreateDate:** 2023-07-18 - - 3. **Username:** dummy-user-3 - - **UserId:** AIDCCCCCC3333CCCCCC3333 - - **Arn:** arn:aws:iam::123456789012:user/dummy-user-3 - - **CreateDate:** 2024-07-15 - - 4. **Username:** dummy-user-4 - - **UserId:** AIDDDDDDD4444DDDDDD4444 - - **Arn:** arn:aws:iam::123456789012:user/dummy-user-4 - - **CreateDate:** 2024-08-02 - - 5. **Username:** dummy-user-5 - - **UserId:** AIDEEEEE5555EEEEE5555 - - **Arn:** arn:aws:iam::123456789012:user/dummy-user-5 - - **CreateDate:** 2023-08-29 -``` diff --git a/docs/griptape-tools/official-tools/aws-s3-tool.md b/docs/griptape-tools/official-tools/aws-s3-tool.md deleted file mode 100644 index 9e44dda10..000000000 --- a/docs/griptape-tools/official-tools/aws-s3-tool.md +++ /dev/null @@ -1,42 +0,0 @@ -# Aws S3 Tool - -This tool enables LLMs to make AWS S3 API requests. - -```python ---8<-- "docs/griptape-tools/official-tools/src/aws_s3_tool_1.py" -``` - -``` -[08/12/24 14:51:36] INFO ToolkitTask bfc329ebc7d34497b429ab0d18ff7e7b - Input: List all my S3 buckets. -[08/12/24 14:51:37] INFO Subtask dfd07f9e204c4a3d8f55ca3eb9d37ec5 - Actions: [ - { - "tag": "call_pZQ05Zmm6lSbEcvPWt4XEDj6", - "name": "AwsS3Client", - "path": "list_s3_buckets", - "input": { - "values": {} - } - } - ] - INFO Subtask dfd07f9e204c4a3d8f55ca3eb9d37ec5 - Response: {'Name': 'dummy-bucket-1', 'CreationDate': datetime.datetime(2023, 9, 14, 15, 41, 46, - tzinfo=tzutc())} - - {'Name': 'dummy-bucket-2', 'CreationDate': datetime.datetime(2023, 9, 14, 15, 40, 33, tzinfo=tzutc())} - - {'Name': 'dummy-bucket-3', 'CreationDate': datetime.datetime(2023, 6, 23, 20, 19, 53, tzinfo=tzutc())} - - {'Name': 'dummy-bucket-4', 'CreationDate': datetime.datetime(2023, 8, 19, 17, 17, 13, tzinfo=tzutc())} - - {'Name': 'dummy-bucket-5', 'CreationDate': datetime.datetime(2024, 2, 15, 23, 17, 21, tzinfo=tzutc())} -[08/12/24 14:51:43] INFO ToolkitTask bfc329ebc7d34497b429ab0d18ff7e7b - Output: Here are all your S3 buckets: - - 1. dummy-bucket-1 (Created on 2023-09-14) - 2. dummy-bucket-2 (Created on 2023-09-14) - 3. dummy-bucket-3 (Created on 2023-06-23) - 4. dummy-bucket-4 (Created on 2023-08-19) - 5. dummy-bucket-5 (Created on 2024-02-15) -``` diff --git a/docs/griptape-tools/official-tools/google-calendar-tool.md b/docs/griptape-tools/official-tools/google-calendar-tool.md deleted file mode 100644 index 313a97777..000000000 --- a/docs/griptape-tools/official-tools/google-calendar-tool.md +++ /dev/null @@ -1,7 +0,0 @@ -# Google Calendar Tool - -The [GoogleCalendarTool](../../reference/griptape/tools/google_calendar/tool.md) tool allows you to interact with Google Calendar. - -```python ---8<-- "docs/griptape-tools/official-tools/src/google_calendar_tool_1.py" -``` diff --git a/docs/griptape-tools/official-tools/google-docs-tool.md b/docs/griptape-tools/official-tools/google-docs-tool.md deleted file mode 100644 index bc3e4e814..000000000 --- a/docs/griptape-tools/official-tools/google-docs-tool.md +++ /dev/null @@ -1,34 +0,0 @@ -# Google Docs Tool - -The [GoogleDocsTool](../../reference/griptape/tools/google_docs/tool.md) tool provides a way to interact with the Google Docs API. It can be used to create new documents, save content to existing documents, and more. - -```python ---8<-- "docs/griptape-tools/official-tools/src/google_docs_tool_1.py" -``` - -``` -[10/05/23 12:56:19] INFO ToolkitTask 90721b7478a74618a63d852d35be3b18 - Input: Create doc with name 'test_creation' in - test folder with content 'Hey, Tony.' -[10/05/23 12:56:28] INFO Subtask 042b7050755f43578bba2c315d124fcb - Thought: The user wants to create a Google Doc - named 'test_creation' in a folder named 'test' - with the content 'Hey, Tony.'. I can use the - 'save_content_to_google_doc' activity of the - GoogleDocsTool tool to achieve this. - - Action: {"name": - "GoogleDocsTool", "path": - "save_content_to_google_doc", "input": {"values": - {"file_path": "test_creation", "content": "Hey, - Tony.", "folder_path": "test"}}} -[10/05/23 12:56:31] INFO Subtask 042b7050755f43578bba2c315d124fcb - Response: Content has been successfully saved to - Google Doc with ID: - 1OgKbsPqxOnzkf65kodb1i1_qC1zjX_Bend5XL5bVxpA. -[10/05/23 12:56:38] INFO ToolkitTask 90721b7478a74618a63d852d35be3b18 - Output: The document 'test_creation' has been - successfully created in the 'test' folder with the - content 'Hey, Tony.'. The Google Doc ID is - 1OgKbsPqxOnzkf65kodb1i1_qC1zjX_Bend5XL5bVxpA. -``` diff --git a/docs/griptape-tools/official-tools/google-drive-tool.md b/docs/griptape-tools/official-tools/google-drive-tool.md deleted file mode 100644 index 5d11ddd92..000000000 --- a/docs/griptape-tools/official-tools/google-drive-tool.md +++ /dev/null @@ -1,31 +0,0 @@ -# Google Drive Tool - -The [GoogleDriveTool](../../reference/griptape/tools/google_drive/tool.md) tool provides a way to interact with the Google Drive API. It can be used to save content on Drive, list files, and more. - -```python ---8<-- "docs/griptape-tools/official-tools/src/google_drive_tool_1.py" -``` - -``` -[10/05/23 10:49:14] INFO ToolkitTask 2ae3bb7e828744f3a2631c29c6fce001 - Input: Save the content 'Hi this is Tony' in a file - named 'hello.txt' to my Drive. -[10/05/23 10:49:24] INFO Subtask 381430d881354184ace65af39e0b292b - Thought: The user wants to save the content 'Hi - this is Tony' in a file named 'hello.txt' to Google - Drive. I can use the 'save_content_to_drive' - activity of the GoogleDriveTool tool to - accomplish this. - - Action: {"name": - "GoogleDriveTool", "path": - "save_content_to_drive", "input": {"values": - {"path": "hello.txt", "content": "Hi this is - Tony"}}} -[10/05/23 10:49:26] INFO Subtask 381430d881354184ace65af39e0b292b - Response: saved successfully -[10/05/23 10:49:29] INFO ToolkitTask 2ae3bb7e828744f3a2631c29c6fce001 - Output: The content 'Hi this is Tony' has been - successfully saved in a file named 'hello.txt' on - your Google Drive. -``` diff --git a/docs/griptape-tools/official-tools/google-gmail-tool.md b/docs/griptape-tools/official-tools/google-gmail-tool.md deleted file mode 100644 index dd66856b6..000000000 --- a/docs/griptape-tools/official-tools/google-gmail-tool.md +++ /dev/null @@ -1,32 +0,0 @@ -# Google Gmail Tool - -The [GoogleGmailTool](../../reference/griptape/tools/google_gmail/tool.md) tool provides a way to interact with the Gmail API. It can be used to create draft emails, send emails, and more. - -```python ---8<-- "docs/griptape-tools/official-tools/src/google_gmail_tool_1.py" -``` - -``` -[10/05/23 13:24:05] INFO ToolkitTask 1f190f823d584053bfe9942f41b6cb2d - Input: Create a draft email in Gmail to - example@email.com with the subject 'Test Draft', - the body 'This is a test draft email.' -[10/05/23 13:24:15] INFO Subtask 7f2cce7e5b0e425ba696531561697b96 - Thought: The user wants to create a draft email in - Gmail. I can use the GoogleGmailTool tool with - the create_draft_email activity to accomplish this. - I will need to provide the 'to', 'subject', and - 'body' values as input. - - Action: {"name": - "GoogleGmailTool", "path": - "create_draft_email", "input": {"values": {"to": - "example@email.com", "subject": "Test Draft", - "body": "This is a test draft email."}}} -[10/05/23 13:24:16] INFO Subtask 7f2cce7e5b0e425ba696531561697b96 - Response: An email draft was successfully - created (ID: r6322867913697829111) -[10/05/23 13:24:19] INFO ToolkitTask 1f190f823d584053bfe9942f41b6cb2d - Output: The draft email has been successfully - created in Gmail with the ID: r6322867913697829111. -``` diff --git a/docs/griptape-tools/official-tools/griptape-cloud-knowledge-base-tool.md b/docs/griptape-tools/official-tools/griptape-cloud-knowledge-base-tool.md deleted file mode 100644 index c0ce7c1d1..000000000 --- a/docs/griptape-tools/official-tools/griptape-cloud-knowledge-base-tool.md +++ /dev/null @@ -1,9 +0,0 @@ -# Griptape Cloud Knowledge Base Tool - -The [GriptapeCloudKnowledgeBaseTool](../../reference/griptape/tools/griptape_cloud_knowledge_base/tool.md) is a lightweight Tool to retrieve data from a RAG pipeline and vector store hosted in [Griptape Cloud](https://cloud.griptape.ai). It enables searching across a centralized [Knowledge Base](https://cloud.griptape.ai/knowledge-bases) that can consist of various data sources such as Confluence, Google Docs, and web pages. - -**Note:** This tool requires a [Knowledge Base](https://cloud.griptape.ai/knowledge-bases) hosted in Griptape Cloud and an [API Key](https://cloud.griptape.ai/configuration/api-keys) for access. - -```python ---8<-- "docs/griptape-tools/official-tools/src/griptape_cloud_knowledge_base_tool_1.py" -``` diff --git a/docs/griptape-tools/official-tools/openweather-tool.md b/docs/griptape-tools/official-tools/openweather-tool.md deleted file mode 100644 index be1ed3972..000000000 --- a/docs/griptape-tools/official-tools/openweather-tool.md +++ /dev/null @@ -1,7 +0,0 @@ -# Open Weather Tool - -The [OpenWeatherTool](../../reference/griptape/tools/openweather/tool.md) enables LLMs to use [OpenWeatherMap](https://openweathermap.org/). - -```python ---8<-- "docs/griptape-tools/official-tools/src/openweather_tool_1.py" -``` diff --git a/docs/griptape-tools/official-tools/src/aws_iam_tool_1.py b/docs/griptape-tools/official-tools/src/aws_iam_tool_1.py deleted file mode 100644 index 89718010f..000000000 --- a/docs/griptape-tools/official-tools/src/aws_iam_tool_1.py +++ /dev/null @@ -1,13 +0,0 @@ -import boto3 - -from griptape.structures import Agent -from griptape.tools import AwsIamTool - -# Initialize the AWS IAM client -aws_iam_client = AwsIamTool(session=boto3.Session()) - -# Create an agent with the AWS IAM client tool -agent = Agent(tools=[aws_iam_client]) - -# Run the agent with a high-level task -agent.run("List all my IAM users") diff --git a/docs/griptape-tools/official-tools/src/aws_s3_tool_1.py b/docs/griptape-tools/official-tools/src/aws_s3_tool_1.py deleted file mode 100644 index 3d9425534..000000000 --- a/docs/griptape-tools/official-tools/src/aws_s3_tool_1.py +++ /dev/null @@ -1,13 +0,0 @@ -import boto3 - -from griptape.structures import Agent -from griptape.tools import AwsS3Tool - -# Initialize the AWS S3 client -aws_s3_client = AwsS3Tool(session=boto3.Session(), off_prompt=True) - -# Create an agent with the AWS S3 client tool -agent = Agent(tools=[aws_s3_client]) - -# Task to list all the AWS S3 buckets -agent.run("List all my S3 buckets.") diff --git a/docs/griptape-tools/official-tools/src/google_calendar_tool_1.py b/docs/griptape-tools/official-tools/src/google_calendar_tool_1.py deleted file mode 100644 index afbb20c9f..000000000 --- a/docs/griptape-tools/official-tools/src/google_calendar_tool_1.py +++ /dev/null @@ -1,29 +0,0 @@ -import os - -from griptape.structures import Agent -from griptape.tools import GoogleCalendarTool - -# Create the GoogleCalendarTool tool -google_calendarendar_tool = GoogleCalendarTool( - service_account_credentials={ - "type": os.environ["GOOGLE_ACCOUNT_TYPE"], - "project_id": os.environ["GOOGLE_PROJECT_ID"], - "private_key_id": os.environ["GOOGLE_PRIVATE_KEY_ID"], - "private_key": os.environ["GOOGLE_PRIVATE_KEY"], - "client_email": os.environ["GOOGLE_CLIENT_EMAIL"], - "client_id": os.environ["GOOGLE_CLIENT_ID"], - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": os.environ["GOOGLE_CERT_URL"], - }, - owner_email=os.environ["GOOGLE_OWNER_EMAIL"], -) - -# Set up an agent using the GoogleCalendarTool tool -agent = Agent(tools=[google_calendarendar_tool]) - -# Task: Get upcoming events from a Google calendar -agent.run( - "Get me the details of the next upcoming event from my primary calendar.", -) diff --git a/docs/griptape-tools/official-tools/src/google_docs_tool_1.py b/docs/griptape-tools/official-tools/src/google_docs_tool_1.py deleted file mode 100644 index 0d8e8a3cb..000000000 --- a/docs/griptape-tools/official-tools/src/google_docs_tool_1.py +++ /dev/null @@ -1,29 +0,0 @@ -import os - -from griptape.structures import Agent -from griptape.tools import GoogleDocsTool - -# Create the GoogleDocsTool tool -google_docs_tool = GoogleDocsTool( - service_account_credentials={ - "type": os.environ["GOOGLE_ACCOUNT_TYPE"], - "project_id": os.environ["GOOGLE_PROJECT_ID"], - "private_key_id": os.environ["GOOGLE_PRIVATE_KEY_ID"], - "private_key": os.environ["GOOGLE_PRIVATE_KEY"], - "client_email": os.environ["GOOGLE_CLIENT_EMAIL"], - "client_id": os.environ["GOOGLE_CLIENT_ID"], - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": os.environ["GOOGLE_CERT_URL"], - }, - owner_email=os.environ["GOOGLE_OWNER_EMAIL"], -) - -# Set up an agent using the GoogleDocsTool tool -agent = Agent(tools=[google_docs_tool]) - -# Task: Create a new Google Doc and save content to it -agent.run( - "Create doc with name 'test_creation' in test folder with content 'Hey, Tony.", -) diff --git a/docs/griptape-tools/official-tools/src/google_drive_tool_1.py b/docs/griptape-tools/official-tools/src/google_drive_tool_1.py deleted file mode 100644 index d8e43a6db..000000000 --- a/docs/griptape-tools/official-tools/src/google_drive_tool_1.py +++ /dev/null @@ -1,29 +0,0 @@ -import os - -from griptape.structures import Agent -from griptape.tools import GoogleDriveTool - -# Create the GoogleDriveTool tool -google_drive_tool = GoogleDriveTool( - service_account_credentials={ - "type": os.environ["GOOGLE_ACCOUNT_TYPE"], - "project_id": os.environ["GOOGLE_PROJECT_ID"], - "private_key_id": os.environ["GOOGLE_PRIVATE_KEY_ID"], - "private_key": os.environ["GOOGLE_PRIVATE_KEY"], - "client_email": os.environ["GOOGLE_CLIENT_EMAIL"], - "client_id": os.environ["GOOGLE_CLIENT_ID"], - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": os.environ["GOOGLE_CERT_URL"], - }, - owner_email=os.environ["GOOGLE_OWNER_EMAIL"], -) - -# Set up an agent using the GoogleDriveTool tool -agent = Agent(tools=[google_drive_tool]) - -# Task: Save content to my Google Drive (default directory is root) -agent.run( - "Save the content 'Hi this is Tony' in a filed named 'hello.txt' to my Drive.", -) diff --git a/docs/griptape-tools/official-tools/src/google_gmail_tool_1.py b/docs/griptape-tools/official-tools/src/google_gmail_tool_1.py deleted file mode 100644 index 44e0ceb39..000000000 --- a/docs/griptape-tools/official-tools/src/google_gmail_tool_1.py +++ /dev/null @@ -1,30 +0,0 @@ -import os - -from griptape.structures import Agent -from griptape.tools import GoogleGmailTool - -# Create the GoogleGmailTool tool -gmail_tool = GoogleGmailTool( - service_account_credentials={ - "type": os.environ["GOOGLE_ACCOUNT_TYPE"], - "project_id": os.environ["GOOGLE_PROJECT_ID"], - "private_key_id": os.environ["GOOGLE_PRIVATE_KEY_ID"], - "private_key": os.environ["GOOGLE_PRIVATE_KEY"], - "client_email": os.environ["GOOGLE_CLIENT_EMAIL"], - "client_id": os.environ["GOOGLE_CLIENT_ID"], - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": os.environ["GOOGLE_CERT_URL"], - }, - owner_email=os.environ["GOOGLE_OWNER_EMAIL"], -) - -# Set up an agent using the GoogleGmailTool tool -agent = Agent(tools=[gmail_tool]) - -# Task: Create a draft email in GMail -agent.run( - "Create a draft email in Gmail to example@email.com with the subject 'Test Draft', the body " - "'This is a test draft email.'", -) diff --git a/docs/griptape-tools/official-tools/src/griptape_cloud_knowledge_base_tool_1.py b/docs/griptape-tools/official-tools/src/griptape_cloud_knowledge_base_tool_1.py deleted file mode 100644 index 8488a6ae8..000000000 --- a/docs/griptape-tools/official-tools/src/griptape_cloud_knowledge_base_tool_1.py +++ /dev/null @@ -1,18 +0,0 @@ -import os - -from griptape.structures import Agent -from griptape.tools import GriptapeCloudKnowledgeBaseTool - -knowledge_base_client = GriptapeCloudKnowledgeBaseTool( - description="Contains information about the company and its operations", - api_key=os.environ["GT_CLOUD_API_KEY"], - knowledge_base_id=os.environ["GT_CLOUD_KB_ID"], -) - -agent = Agent( - tools=[ - knowledge_base_client, - ] -) - -agent.run("What is the company's corporate travel policy?") diff --git a/docs/griptape-tools/official-tools/src/openweather_tool_1.py b/docs/griptape-tools/official-tools/src/openweather_tool_1.py deleted file mode 100644 index b592620fa..000000000 --- a/docs/griptape-tools/official-tools/src/openweather_tool_1.py +++ /dev/null @@ -1,14 +0,0 @@ -import os - -from griptape.structures import Agent -from griptape.tools import OpenWeatherTool - -agent = Agent( - tools=[ - OpenWeatherTool( - api_key=os.environ["OPENWEATHER_API_KEY"], - ), - ] -) - -agent.run("What's the weather currently like in San Francisco?") diff --git a/griptape/tools/__init__.py b/griptape/tools/__init__.py index ce59088f3..6eb21e921 100644 --- a/griptape/tools/__init__.py +++ b/griptape/tools/__init__.py @@ -9,21 +9,11 @@ from .file_manager.tool import FileManagerTool from .vector_store.tool import VectorStoreTool from .date_time.tool import DateTimeTool -from .base_aws_tool import BaseAwsTool -from .aws_iam.tool import AwsIamTool -from .aws_s3.tool import AwsS3Tool from .computer.tool import ComputerTool -from .base_google_tool import BaseGoogleTool -from .google_gmail.tool import GoogleGmailTool -from .google_calendar.tool import GoogleCalendarTool -from .google_docs.tool import GoogleDocsTool -from .google_drive.tool import GoogleDriveTool -from .openweather.tool import OpenWeatherTool from .prompt_image_generation.tool import PromptImageGenerationTool from .variation_image_generation.tool import VariationImageGenerationTool from .inpainting_image_generation.tool import InpaintingImageGenerationTool from .outpainting_image_generation.tool import OutpaintingImageGenerationTool -from .griptape_cloud_knowledge_base.tool import GriptapeCloudKnowledgeBaseTool from .structure_run.tool import StructureRunTool from .image_query.tool import ImageQueryTool from .rag.tool import RagTool @@ -36,14 +26,6 @@ __all__ = [ "BaseTool", "BaseImageGenerationTool", - "BaseAwsTool", - "AwsIamTool", - "AwsS3Tool", - "BaseGoogleTool", - "GoogleGmailTool", - "GoogleDocsTool", - "GoogleCalendarTool", - "GoogleDriveTool", "CalculatorTool", "WebSearchTool", "WebScraperTool", @@ -54,12 +36,10 @@ "VectorStoreTool", "DateTimeTool", "ComputerTool", - "OpenWeatherTool", "PromptImageGenerationTool", "VariationImageGenerationTool", "InpaintingImageGenerationTool", "OutpaintingImageGenerationTool", - "GriptapeCloudKnowledgeBaseTool", "StructureRunTool", "ImageQueryTool", "RagTool", diff --git a/griptape/tools/aws_iam/__init__.py b/griptape/tools/aws_iam/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/griptape/tools/aws_iam/tool.py b/griptape/tools/aws_iam/tool.py deleted file mode 100644 index d5b20d56a..000000000 --- a/griptape/tools/aws_iam/tool.py +++ /dev/null @@ -1,84 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -from attrs import define, field -from schema import Literal, Schema - -from griptape.artifacts import ErrorArtifact, ListArtifact, TextArtifact -from griptape.tools import BaseAwsTool -from griptape.utils.decorators import activity, lazy_property - -if TYPE_CHECKING: - from mypy_boto3_iam import IAMClient - - -@define -class AwsIamTool(BaseAwsTool): - _client: IAMClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) - - @lazy_property() - def client(self) -> IAMClient: - return self.session.client("iam") - - @activity( - config={ - "description": "Can be use to get a policy for an AWS IAM user.", - "schema": Schema( - { - Literal("user_name", description="Username of the AWS IAM user."): str, - Literal( - "policy_name", - description="PolicyName of the AWS IAM Policy embedded in the specified IAM user.", - ): str, - }, - ), - }, - ) - def get_user_policy(self, params: dict) -> TextArtifact | ErrorArtifact: - try: - policy = self.client.get_user_policy( - UserName=params["values"]["user_name"], - PolicyName=params["values"]["policy_name"], - ) - return TextArtifact(policy["PolicyDocument"]) - except Exception as e: - return ErrorArtifact(f"error returning policy document: {e}") - - @activity(config={"description": "Can be used to list AWS MFA Devices"}) - def list_mfa_devices(self) -> ListArtifact | ErrorArtifact: - try: - devices = self.client.list_mfa_devices() - return ListArtifact([TextArtifact(str(d)) for d in devices["MFADevices"]]) - except Exception as e: - return ErrorArtifact(f"error listing mfa devices: {e}") - - @activity( - config={ - "description": "Can be used to list policies for a given IAM user.", - "schema": Schema( - {Literal("user_name", description="Username of the AWS IAM user for which to list policies."): str}, - ), - }, - ) - def list_user_policies(self, params: dict) -> ListArtifact | ErrorArtifact: - try: - policies = self.client.list_user_policies(UserName=params["values"]["user_name"]) - policy_names = policies["PolicyNames"] - - attached_policies = self.client.list_attached_user_policies(UserName=params["values"]["user_name"]) - attached_policy_names = [ - p["PolicyName"] for p in attached_policies["AttachedPolicies"] if "PolicyName" in p - ] - - return ListArtifact([TextArtifact(str(p)) for p in policy_names + attached_policy_names]) - except Exception as e: - return ErrorArtifact(f"error listing iam user policies: {e}") - - @activity(config={"description": "Can be used to list AWS IAM users."}) - def list_users(self) -> ListArtifact | ErrorArtifact: - try: - users = self.client.list_users() - return ListArtifact([TextArtifact(str(u)) for u in users["Users"]]) - except Exception as e: - return ErrorArtifact(f"error listing s3 users: {e}") diff --git a/griptape/tools/aws_s3/__init__.py b/griptape/tools/aws_s3/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/griptape/tools/aws_s3/tool.py b/griptape/tools/aws_s3/tool.py deleted file mode 100644 index fb0c2fdf2..000000000 --- a/griptape/tools/aws_s3/tool.py +++ /dev/null @@ -1,216 +0,0 @@ -from __future__ import annotations - -import io -from typing import TYPE_CHECKING, Any - -from attrs import define, field -from schema import Literal, Schema - -from griptape.artifacts import BlobArtifact, ErrorArtifact, InfoArtifact, ListArtifact, TextArtifact -from griptape.tools import BaseAwsTool -from griptape.utils.decorators import activity, lazy_property - -if TYPE_CHECKING: - from mypy_boto3_s3 import S3Client - - -@define -class AwsS3Tool(BaseAwsTool): - _client: S3Client = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) - - @lazy_property() - def client(self) -> S3Client: - return self.session.client("s3") - - @activity( - config={ - "description": "Can be used to get an access control list (ACL) of an AWS S3 bucket.", - "schema": Schema( - { - Literal( - "bucket_name", - description="The bucket name that contains the object for which to get the ACL information.", - ): str, - }, - ), - }, - ) - def get_bucket_acl(self, params: dict) -> TextArtifact | ErrorArtifact: - try: - acl = self.client.get_bucket_acl(Bucket=params["values"]["bucket_name"]) - return TextArtifact(acl) - except Exception as e: - return ErrorArtifact(f"error getting bucket acl: {e}") - - @activity( - config={ - "description": "Can be used to get an AWS S3 bucket policy.", - "schema": Schema( - {Literal("bucket_name", description="The bucket name for which to get the bucket policy."): str}, - ), - }, - ) - def get_bucket_policy(self, params: dict) -> TextArtifact | ErrorArtifact: - try: - policy = self.client.get_bucket_policy(Bucket=params["values"]["bucket_name"]) - return TextArtifact(policy) - except Exception as e: - return ErrorArtifact(f"error getting bucket policy: {e}") - - @activity( - config={ - "description": "Can be used to get an access control list (ACL) of an object in the AWS S3 bucket.", - "schema": Schema( - { - Literal("bucket_name", description="Name of the AWS S3 bucket for which to get an ACL."): str, - Literal("object_key", description="Key of the object for which to get the ACL information."): str, - }, - ), - }, - ) - def get_object_acl(self, params: dict) -> TextArtifact | ErrorArtifact: - try: - acl = self.client.get_object_acl( - Bucket=params["values"]["bucket_name"], - Key=params["values"]["object_key"], - ) - return TextArtifact(acl) - except Exception as e: - return ErrorArtifact(f"error getting object acl: {e}") - - @activity(config={"description": "Can be used to list all AWS S3 buckets."}) - def list_s3_buckets(self) -> ListArtifact | ErrorArtifact: - try: - buckets = self.client.list_buckets() - - return ListArtifact([TextArtifact(str(b)) for b in buckets["Buckets"]]) - except Exception as e: - return ErrorArtifact(f"error listing s3 buckets: {e}") - - @activity( - config={ - "description": "Can be used to list all objects in an AWS S3 bucket.", - "schema": Schema({Literal("bucket_name", description="The name of the S3 bucket to list."): str}), - }, - ) - def list_objects(self, params: dict) -> ListArtifact | ErrorArtifact: - try: - objects = self.client.list_objects_v2(Bucket=params["values"]["bucket_name"]) - - if "Contents" not in objects: - return ErrorArtifact("no objects found in the bucket") - - return ListArtifact([TextArtifact(str(o)) for o in objects["Contents"]]) - except Exception as e: - return ErrorArtifact(f"error listing objects in bucket: {e}") - - @activity( - config={ - "description": "Can be used to upload memory artifacts to an AWS S3 bucket", - "schema": Schema( - { - "memory_name": str, - "artifact_namespace": str, - "bucket_name": str, - Literal("object_key", description="Destination object key name. For example, 'baz.txt'"): str, - }, - ), - }, - ) - def upload_memory_artifacts_to_s3(self, params: dict) -> InfoArtifact | ErrorArtifact: - memory = self.find_input_memory(params["values"]["memory_name"]) - artifact_namespace = params["values"]["artifact_namespace"] - bucket_name = params["values"]["bucket_name"] - object_key = params["values"]["object_key"] - - if memory: - artifacts = memory.load_artifacts(artifact_namespace) - - if len(artifacts) == 0: - return ErrorArtifact("no artifacts found") - elif len(artifacts) == 1: - try: - self._upload_object(bucket_name, object_key, artifacts.value[0].value) - - return InfoArtifact("uploaded successfully") - except Exception as e: - return ErrorArtifact(f"error uploading objects to the bucket: {e}") - else: - try: - for a in artifacts.value: - self._upload_object(bucket_name, object_key, a.value) - - return InfoArtifact("uploaded successfully") - except Exception as e: - return ErrorArtifact(f"error uploading objects to the bucket: {e}") - else: - return ErrorArtifact("memory not found") - - @activity( - config={ - "description": "Can be used to upload content to an AWS S3 bucket", - "schema": Schema( - { - "bucket_name": str, - Literal("object_key", description="Destination object key name. For example, 'baz.txt'"): str, - "content": str, - }, - ), - }, - ) - def upload_content_to_s3(self, params: dict) -> ErrorArtifact | InfoArtifact: - content = params["values"]["content"] - bucket_name = params["values"]["bucket_name"] - object_key = params["values"]["object_key"] - - try: - self._upload_object(bucket_name, object_key, content) - - return InfoArtifact("uploaded successfully") - except Exception as e: - return ErrorArtifact(f"error uploading objects to the bucket: {e}") - - @activity( - config={ - "description": "Can be used to download objects from AWS S3", - "schema": Schema( - { - Literal("objects", description="A list of bucket name and object key pairs to download"): [ - { - Literal( - "bucket_name", - description="The name of the bucket to download the object from", - ): str, - Literal( - "object_key", - description="The name of the object key to download from the bucket", - ): str, - }, - ], - }, - ), - }, - ) - def download_objects(self, params: dict) -> ListArtifact | ErrorArtifact: - objects = params["values"]["objects"] - artifacts = [] - for object_info in objects: - try: - obj = self.client.get_object(Bucket=object_info["bucket_name"], Key=object_info["object_key"]) - - content = obj["Body"].read() - artifacts.append(BlobArtifact(content, name=object_info["object_key"])) - - except Exception as e: - return ErrorArtifact(f"error downloading objects from bucket: {e}") - - return ListArtifact(artifacts) - - def _upload_object(self, bucket_name: str, object_name: str, value: Any) -> None: - self.client.create_bucket(Bucket=bucket_name) - - self.client.upload_fileobj( - Fileobj=io.BytesIO(value.encode() if isinstance(value, str) else value), - Bucket=bucket_name, - Key=object_name, - ) diff --git a/griptape/tools/base_aws_tool.py b/griptape/tools/base_aws_tool.py deleted file mode 100644 index 72fc54583..000000000 --- a/griptape/tools/base_aws_tool.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import annotations - -from abc import ABC -from typing import TYPE_CHECKING - -from attrs import define, field - -from griptape.artifacts import BaseArtifact, ErrorArtifact, TextArtifact -from griptape.tools import BaseTool -from griptape.utils.decorators import activity - -if TYPE_CHECKING: - import boto3 - - -@define -class BaseAwsTool(BaseTool, ABC): - session: boto3.Session = field(kw_only=True) - - @activity(config={"description": "Can be used to get current AWS account and IAM principal."}) - def get_current_aws_identity(self, params: dict) -> BaseArtifact: - try: - session = self.session - sts = session.client("sts") - return TextArtifact(str(sts.get_caller_identity())) - except Exception as e: - return ErrorArtifact(f"error getting current aws caller identity: {e}") diff --git a/griptape/tools/base_google_tool.py b/griptape/tools/base_google_tool.py deleted file mode 100644 index c40a583cf..000000000 --- a/griptape/tools/base_google_tool.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import annotations - -from abc import ABC -from typing import Any, Optional - -from attrs import define, field - -from griptape.tools import BaseTool - - -@define -class BaseGoogleTool(BaseTool, ABC): - DRIVE_FILE_SCOPES = ["https://www.googleapis.com/auth/drive.file"] - - DRIVE_AUTH_SCOPES = ["https://www.googleapis.com/auth/drive"] - - service_account_credentials: dict = field(kw_only=True) - - def _build_client(self, scopes: list[str], service_name: str, version: str, owner_email: str) -> Any: - from google.oauth2 import service_account - from googleapiclient.discovery import build - - credentials = service_account.Credentials.from_service_account_info( - self.service_account_credentials, - scopes=scopes, - ) - - return build(serviceName=service_name, version=version, credentials=credentials.with_subject(owner_email)) - - def _convert_path_to_file_id(self, service: Any, path: str) -> Optional[str]: - parts = path.split("/") - current_id = "root" - - for idx, part in enumerate(parts): - if idx == len(parts) - 1: - query = f"name='{part}' and '{current_id}' in parents" - else: - query = f"name='{part}' and '{current_id}' in parents and mimeType='application/vnd.google-apps.folder'" - - response = service.files().list(q=query).execute() - files = response.get("files", []) - - if not files: - if idx != len(parts) - 1: - folder_metadata = { - "name": part, - "mimeType": "application/vnd.google-apps.folder", - "parents": [current_id], - } - folder = service.files().create(body=folder_metadata, fields="id").execute() - current_id = folder.get("id") - else: - current_id = None - else: - current_id = files[0]["id"] - - return current_id diff --git a/griptape/tools/google_calendar/__init__.py b/griptape/tools/google_calendar/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/griptape/tools/google_calendar/requirements.txt b/griptape/tools/google_calendar/requirements.txt deleted file mode 100644 index 704bcd50c..000000000 --- a/griptape/tools/google_calendar/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -google-api-python-client \ No newline at end of file diff --git a/griptape/tools/google_calendar/tool.py b/griptape/tools/google_calendar/tool.py deleted file mode 100644 index de9c4e8e1..000000000 --- a/griptape/tools/google_calendar/tool.py +++ /dev/null @@ -1,122 +0,0 @@ -from __future__ import annotations - -import datetime -import logging - -from attrs import define, field -from schema import Literal, Optional, Schema - -from griptape.artifacts import ErrorArtifact, InfoArtifact, ListArtifact, TextArtifact -from griptape.tools import BaseGoogleTool -from griptape.utils.decorators import activity - - -@define -class GoogleCalendarTool(BaseGoogleTool): - CREATE_EVENT_SCOPES = ["https://www.googleapis.com/auth/calendar"] - - GET_UPCOMING_EVENTS_SCOPES = ["https://www.googleapis.com/auth/calendar"] - - owner_email: str = field(kw_only=True) - - @activity( - config={ - "description": "Can be used to get upcoming events from a google calendar", - "schema": Schema( - { - Literal("calendar_id", description="id of the google calendar such as 'primary'"): str, - Literal("max_events", description="maximum number of events to return"): int, - }, - ), - }, - ) - def get_upcoming_events(self, params: dict) -> ListArtifact | ErrorArtifact: - values = params["values"] - - try: - service = self._build_client( - scopes=self.GET_UPCOMING_EVENTS_SCOPES, - service_name="calendar", - version="v3", - owner_email=self.owner_email, - ) - now = datetime.datetime.utcnow().isoformat() + "Z" - - events_result = ( - service.events() - .list( - calendarId=values["calendar_id"], - timeMin=now, - maxResults=values["max_events"], - singleEvents=True, - orderBy="startTime", - ) - .execute() - ) - events = events_result.get("items", []) - - return ListArtifact([TextArtifact(str(e)) for e in events]) - except Exception as e: - logging.error(e) - return ErrorArtifact(f"error retrieving calendar events {e}") - - @activity( - config={ - "description": "Can be used to create an event on a google calendar", - "schema": Schema( - { - Literal( - "start_datetime", - description="combined date-time value in string format according to RFC3399 " - "excluding the timezone for when the meeting starts", - ): str, - Literal( - "start_time_zone", - description="time zone in which the start time is specified in string format " - "according to IANA time zone data base name, such as 'Europe/Zurich'", - ): str, - Literal( - "end_datetime", - description="combined date-time value in string format according to RFC3399 " - "excluding the timezone for when the meeting ends", - ): str, - Literal( - "end_time_zone", - description="time zone in which the end time is specified in string format " - "according to IANA time zone data base name, such as 'Europe/Zurich'", - ): str, - Literal("title", description="title of the event"): str, - Literal("description", description="description of the event"): str, - Literal( - "attendees", - description="list of the email addresses of attendees using 'email' as key", - ): list[str], - Optional(Literal("location", description="location of the event")): str, - }, - ), - }, - ) - def create_event(self, params: dict) -> InfoArtifact | ErrorArtifact: - values = params["values"] - - try: - service = self._build_client( - scopes=self.CREATE_EVENT_SCOPES, - service_name="calendar", - version="v3", - owner_email=self.owner_email, - ) - - event = { - "summary": values["title"], - "location": values.get("location"), - "description": values["description"], - "start": {"dateTime": values["start_datetime"], "timeZone": values["start_time_zone"]}, - "end": {"dateTime": values["end_datetime"], "timeZone": values["end_time_zone"]}, - "attendees": values["attendees"], - } - event = service.events().insert(calendarId="primary", body=event).execute() - return InfoArtifact(f'A calendar event was successfully created. (Link:{event.get("htmlLink")})') - except Exception as e: - logging.error(e) - return ErrorArtifact(f"error creating calendar event: {e}") diff --git a/griptape/tools/google_docs/__init__.py b/griptape/tools/google_docs/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/griptape/tools/google_docs/requirements.txt b/griptape/tools/google_docs/requirements.txt deleted file mode 100644 index 704bcd50c..000000000 --- a/griptape/tools/google_docs/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -google-api-python-client \ No newline at end of file diff --git a/griptape/tools/google_docs/tool.py b/griptape/tools/google_docs/tool.py deleted file mode 100644 index be40b09da..000000000 --- a/griptape/tools/google_docs/tool.py +++ /dev/null @@ -1,246 +0,0 @@ -from __future__ import annotations - -import logging - -from attrs import define, field -from schema import Literal, Optional, Schema - -from griptape.artifacts import ErrorArtifact, InfoArtifact -from griptape.tools import BaseGoogleTool -from griptape.utils.decorators import activity - - -@define -class GoogleDocsTool(BaseGoogleTool): - DOCS_SCOPES = ["https://www.googleapis.com/auth/documents"] - - DEFAULT_FOLDER_PATH = "root" - - owner_email: str = field(kw_only=True) - - @activity( - config={ - "description": "Can be used to append text to a Google Doc.", - "schema": Schema( - { - Literal( - "file_path", - description="Destination file path of Google Doc in the POSIX format. " - "For example, 'foo/bar/baz.txt'", - ): str, - Literal("text", description="Text to be appended to the Google Doc."): str, - }, - ), - }, - ) - def append_text_to_google_doc(self, params: dict) -> InfoArtifact | ErrorArtifact: - values = params["values"] - file_path = values.get("file_path") - text = values.get("text") - - try: - docs_service = self._build_client( - scopes=self.DOCS_SCOPES, - service_name="docs", - version="v1", - owner_email=self.owner_email, - ) - drive_service = self._build_client( - scopes=self.DRIVE_FILE_SCOPES, - service_name="drive", - version="v3", - owner_email=self.owner_email, - ) - - document_id = self._convert_path_to_file_id(drive_service, file_path) - if document_id: - doc = docs_service.documents().get(documentId=document_id).execute() - content = doc["body"]["content"] - last_text = content[-1]["paragraph"]["elements"][-1]["textRun"]["content"] - append_index = content[-1]["endIndex"] - if last_text.endswith("\n"): - append_index -= 1 - - requests = [{"insertText": {"location": {"index": append_index}, "text": text}}] - - docs_service.documents().batchUpdate(documentId=document_id, body={"requests": requests}).execute() - return InfoArtifact("text appended successfully") - else: - return ErrorArtifact(f"error appending to Google Doc, file not found for path {file_path}") - - except Exception as e: - logging.error(e) - return ErrorArtifact(f"error appending text to Google Doc with path {file_path}: {e}") - - @activity( - config={ - "description": "Can be used to prepend text to a Google Doc", - "schema": Schema( - { - Literal( - "file_path", - description="Destination file path of Google Doc in the POSIX format. " - "For example, 'foo/bar/baz.txt'", - ): str, - Literal("text", description="Text to be prepended to the Google Doc."): str, - }, - ), - }, - ) - def prepend_text_to_google_doc(self, params: dict) -> InfoArtifact | ErrorArtifact: - values = params["values"] - file_path = values.get("file_path") - text = values.get("text") - - try: - docs_service = self._build_client( - scopes=self.DOCS_SCOPES, - service_name="docs", - version="v1", - owner_email=self.owner_email, - ) - drive_service = self._build_client( - scopes=self.DRIVE_FILE_SCOPES, - service_name="drive", - version="v3", - owner_email=self.owner_email, - ) - - document_id = self._convert_path_to_file_id(drive_service, file_path) - if document_id: - doc = docs_service.documents().get(documentId=document_id).execute() - - if len(doc["body"]["content"]) == 1: - requests = [{"insertText": {"location": {"index": 1}, "text": text}}] - else: - start_index = doc["body"]["content"][1]["startIndex"] - requests = [{"insertText": {"location": {"index": start_index}, "text": text}}] - - docs_service.documents().batchUpdate(documentId=document_id, body={"requests": requests}).execute() - return InfoArtifact("text prepended successfully") - else: - return ErrorArtifact(f"error prepending to google doc, file not found for path {file_path}") - - except Exception as e: - logging.error(e) - return ErrorArtifact(f"error prepending text to Google Doc with path {file_path}: {e}") - - @activity( - config={ - "description": "Can be used to create a new Google Doc and optionally save content to it.", - "schema": Schema( - { - Literal( - "file_path", - description="Name of the file to be created, which will be used to save content in.", - ): str, - Optional("content", default=None, description="Optional content to be saved in Google Doc."): str, - Optional( - "folder_path", - default=DEFAULT_FOLDER_PATH, - description="Path of the folder where the Google doc will be created.", - ): str, - }, - ), - }, - ) - def save_content_to_google_doc(self, params: dict) -> ErrorArtifact | InfoArtifact: - values = params["values"] - file_path = values.get("file_path") - content = values.get("content") - folder_path = values.get("folder_path", self.DEFAULT_FOLDER_PATH) - - try: - docs_service = self._build_client( - scopes=self.DOCS_SCOPES, - service_name="docs", - version="v1", - owner_email=self.owner_email, - ) - drive_service = self._build_client( - scopes=self.DRIVE_FILE_SCOPES, - service_name="drive", - version="v3", - owner_email=self.owner_email, - ) - - body = {"title": file_path} - - doc = docs_service.documents().create(body=body).execute() - doc_id = doc["documentId"] - - if folder_path.lower() != self.DEFAULT_FOLDER_PATH: - folder_id = self._convert_path_to_file_id(drive_service, folder_path) - if folder_id: - drive_service.files().update(fileId=doc_id, addParents=folder_id, fields="id, parents").execute() - else: - return ErrorArtifact(f"Error: Folder not found for path {folder_path}") - - if content: - save_content_params = {"document_id": doc_id, "content": content} - saved_document_id = self._save_to_doc(save_content_params) - return InfoArtifact(f"Content has been successfully saved to Google Doc with ID: {saved_document_id}.") - else: - return InfoArtifact(f"Google Doc '{file_path}' created with ID: {doc_id}") - - except Exception as e: - logging.error(e) - return ErrorArtifact(f"Error creating/saving Google Doc: {e}") - - @activity( - config={ - "description": "Can be used to load content from memory and save it to a new Google Doc " - "in the specified folder.", - "schema": Schema( - { - "memory_name": str, - "artifact_namespace": str, - "file_name": str, - Optional( - "folder_path", - description="Path of the folder where the Google Doc should be saved.", - default=DEFAULT_FOLDER_PATH, - ): str, - }, - ), - }, - ) - def save_memory_artifacts_to_google_docs(self, params: dict) -> ErrorArtifact | InfoArtifact: - values = params["values"] - memory = self.find_input_memory(values["memory_name"]) - - if memory: - artifacts = memory.load_artifacts(values["artifact_namespace"]) - - if artifacts: - try: - file_path = values["file_name"] - content = "\n".join([a.value for a in artifacts]) - - save_params = { - "file_path": file_path, - "content": content, - "folder_path": values.get("folder_path", self.DEFAULT_FOLDER_PATH), - } - - return self.save_content_to_google_doc(save_params) - - except Exception as e: - return ErrorArtifact(f"Error: {e}") - - else: - return ErrorArtifact("no artifacts found") - else: - return ErrorArtifact("memory not found") - - def _save_to_doc(self, params: dict) -> str: - service = self._build_client( - scopes=self.DOCS_SCOPES, - service_name="docs", - version="v1", - owner_email=self.owner_email, - ) - - requests = [{"insertText": {"location": {"index": 1}, "text": params["content"]}}] - service.documents().batchUpdate(documentId=params["document_id"], body={"requests": requests}).execute() - return params["document_id"] diff --git a/griptape/tools/google_drive/__init__.py b/griptape/tools/google_drive/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/griptape/tools/google_drive/requirements.txt b/griptape/tools/google_drive/requirements.txt deleted file mode 100644 index 704bcd50c..000000000 --- a/griptape/tools/google_drive/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -google-api-python-client \ No newline at end of file diff --git a/griptape/tools/google_drive/tool.py b/griptape/tools/google_drive/tool.py deleted file mode 100644 index 1642ebaf7..000000000 --- a/griptape/tools/google_drive/tool.py +++ /dev/null @@ -1,399 +0,0 @@ -from __future__ import annotations - -import logging -from io import BytesIO -from typing import Any, Optional - -import schema -from attrs import define, field -from schema import Literal, Or, Schema - -from griptape.artifacts import BlobArtifact, ErrorArtifact, InfoArtifact, ListArtifact, TextArtifact -from griptape.tools import BaseGoogleTool -from griptape.utils.decorators import activity - - -@define -class GoogleDriveTool(BaseGoogleTool): - LIST_FILES_SCOPES = ["https://www.googleapis.com/auth/drive.readonly"] - - GOOGLE_EXPORT_MIME_MAPPING = { - "application/vnd.google-apps.document": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - "application/vnd.google-apps.spreadsheet": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - "application/vnd.google-apps.presentation": "application/vnd.openxmlformats-officedocument.presentationml.presentation", - } - - DEFAULT_FOLDER_PATH = "root" - - SERVICE_NAME = "drive" - - SERVICE_VERSION = "v3" - - owner_email: str = field(kw_only=True) - - @activity( - config={ - "description": "Can be used to list files in a specific Google Drive folder.", - "schema": Schema( - { - schema.Optional( - "folder_path", - default=DEFAULT_FOLDER_PATH, - description="Path of the Google Drive folder (like 'MainFolder/Subfolder1/Subfolder2') " - "from which files should be listed.", - ): str, - }, - ), - }, - ) - def list_files(self, params: dict) -> ListArtifact | ErrorArtifact: - values = params["values"] - from google.auth.exceptions import MalformedError # pyright: ignore[reportMissingImports] - - folder_path = values.get("folder_path", self.DEFAULT_FOLDER_PATH) - - try: - service = self._build_client( - self.LIST_FILES_SCOPES, - self.SERVICE_NAME, - self.SERVICE_VERSION, - self.owner_email, - ) - - if folder_path == self.DEFAULT_FOLDER_PATH: - query = "mimeType != 'application/vnd.google-apps.folder' and 'root' in parents and trashed=false" - else: - folder_id = self._convert_path_to_file_id(service, folder_path) - if folder_id: - query = f"'{folder_id}' in parents and trashed=false" - else: - return ErrorArtifact(f"Could not find folder: {folder_path}") - - items = self._list_files(service, query) - return ListArtifact([TextArtifact(i) for i in items]) - - except MalformedError: - return ErrorArtifact("error listing files due to malformed credentials") - except Exception as e: - return ErrorArtifact(f"error listing files from Google Drive: {e}") - - @activity( - config={ - "description": "Can be used to save memory artifacts to Google Drive using folder paths", - "schema": Schema( - { - "memory_name": str, - "artifact_namespace": str, - "file_name": str, - schema.Optional( - "folder_path", - description="Path of the Google Drive folder (like 'MainFolder/Subfolder1/Subfolder2') " - "where the file should be saved.", - default=DEFAULT_FOLDER_PATH, - ): str, - }, - ), - }, - ) - def save_memory_artifacts_to_drive(self, params: dict) -> ErrorArtifact | InfoArtifact: - values = params["values"] - memory = self.find_input_memory(values["memory_name"]) - file_name = values["file_name"] - folder_path = values.get("folder_path", self.DEFAULT_FOLDER_PATH) - - if memory: - artifacts = memory.load_artifacts(values["artifact_namespace"]) - - if artifacts: - service = self._build_client( - self.DRIVE_FILE_SCOPES, - self.SERVICE_NAME, - self.SERVICE_VERSION, - self.owner_email, - ) - - if folder_path == self.DEFAULT_FOLDER_PATH: - folder_id = self.DEFAULT_FOLDER_PATH - else: - folder_id = self._convert_path_to_file_id(service, folder_path) - - if folder_id: - try: - if len(artifacts) == 1: - self._save_to_drive(file_name, artifacts[0].value, folder_id) - else: - for a in artifacts: - self._save_to_drive(f"{a.name}-{file_name}", a.value, folder_id) - - return InfoArtifact("saved successfully") - - except Exception as e: - return ErrorArtifact(f"error saving file to Google Drive: {e}") - else: - return ErrorArtifact(f"Could not find folder: {folder_path}") - else: - return ErrorArtifact("no artifacts found") - else: - return ErrorArtifact("memory not found") - - @activity( - config={ - "description": "Can be used to save content to a file on Google Drive", - "schema": Schema( - { - Literal( - "path", - description="Destination file path on Google Drive in the POSIX format. " - "For example, 'foo/bar/baz.txt'", - ): str, - "content": str, - }, - ), - }, - ) - def save_content_to_drive(self, params: dict) -> ErrorArtifact | InfoArtifact: - content = params["values"]["content"] - filename = params["values"]["path"] - - try: - self._save_to_drive(filename, content) - - return InfoArtifact("saved successfully") - except Exception as e: - return ErrorArtifact(f"error saving file to Google Drive: {e}") - - @activity( - config={ - "description": "Can be used to download multiple files from Google Drive based on a provided list of paths", - "schema": Schema( - { - Literal( - "paths", - description="List of paths to files to be loaded in the POSIX format. " - "For example, ['foo/bar/file1.txt', 'foo/bar/file2.txt']", - ): [str], - }, - ), - }, - ) - def download_files(self, params: dict) -> ListArtifact | ErrorArtifact: - from google.auth.exceptions import MalformedError - from googleapiclient.errors import HttpError # pyright: ignore[reportMissingImports] - - values = params["values"] - downloaded_files = [] - - try: - service = self._build_client( - self.LIST_FILES_SCOPES, - self.SERVICE_NAME, - self.SERVICE_VERSION, - self.owner_email, - ) - - for path in values["paths"]: - file_id = self._convert_path_to_file_id(service, path) - if file_id: - file_info = service.files().get(fileId=file_id).execute() - mime_type = file_info["mimeType"] - - if mime_type in self.GOOGLE_EXPORT_MIME_MAPPING: - export_mime = self.GOOGLE_EXPORT_MIME_MAPPING[mime_type] - request = service.files().export_media(fileId=file_id, mimeType=export_mime) - else: - request = service.files().get_media(fileId=file_id) - - downloaded_files.append(BlobArtifact(request.execute())) - else: - logging.error("Could not find file: %s", path) - - return ListArtifact(downloaded_files) - except HttpError as e: - return ErrorArtifact(f"error downloading file in Google Drive: {e}") - except MalformedError: - return ErrorArtifact("error downloading file due to malformed credentials") - except Exception as e: - return ErrorArtifact(f"error downloading file to Google Drive: {e}") - - @activity( - config={ - "description": "Can search for files on Google Drive based on name or content", - "schema": Schema( - { - Literal( - "search_mode", - description="File search mode. Use 'name' to search in file name or " - "'content' to search in file content", - ): Or( - "name", # pyright: ignore [reportArgumentType] - "content", # pyright: ignore [reportArgumentType] - ), - Literal( - "search_query", - description="Query to search for. If search_mode is 'name', it's the file name. If 'content', " - "it's the text within files.", - ): str, - schema.Optional( - "folder_path", - description="Path of the Google Drive folder (like 'MainFolder/Subfolder1/Subfolder2') " - "where the search should be performed.", - default=DEFAULT_FOLDER_PATH, - ): str, - }, - ), - }, - ) - def search_files(self, params: dict) -> ListArtifact | ErrorArtifact: - from google.auth.exceptions import MalformedError - from googleapiclient.errors import HttpError # pyright: ignore[reportMissingImports] - - values = params["values"] - - search_mode = values["search_mode"] - folder_path = values.get("folder_path", self.DEFAULT_FOLDER_PATH) - - try: - service = self._build_client( - self.LIST_FILES_SCOPES, - self.SERVICE_NAME, - self.SERVICE_VERSION, - self.owner_email, - ) - - folder_id = None - if folder_path == self.DEFAULT_FOLDER_PATH: - folder_id = self.DEFAULT_FOLDER_PATH - else: - folder_id = self._convert_path_to_file_id(service, folder_path) - - if folder_id: - query = None - if search_mode == "name": - query = f"name='{values['search_query']}'" - elif search_mode == "content": - query = f"fullText contains '{values['search_query']}'" - else: - return ErrorArtifact(f"Invalid search mode: {search_mode}") - - query += " and trashed=false" - if folder_id != self.DEFAULT_FOLDER_PATH: - query += f" and '{folder_id}' in parents" - - results = service.files().list(q=query).execute() - items = results.get("files", []) - return ListArtifact([TextArtifact(i) for i in items]) - else: - return ErrorArtifact(f"Folder path {folder_path} not found") - - except HttpError as e: - return ErrorArtifact(f"error searching for file in Google Drive: {e}") - except MalformedError: - return ErrorArtifact("error searching for file due to malformed credentials") - except Exception as e: - return ErrorArtifact(f"error searching file to Google Drive: {e}") - - @activity( - config={ - "description": "Can be used to share a file with a specified user.", - "schema": Schema( - { - Literal("file_path", description="The path of the file to share"): str, - Literal("email_address", description="The email address of the user to share with"): str, - schema.Optional( - "role", - default="reader", - description="The role to give to the user, e.g., 'reader', 'writer', or 'commenter'", - ): Or( - "reader", # pyright: ignore [reportArgumentType] - "writer", # pyright: ignore [reportArgumentType] - "commenter", # pyright: ignore [reportArgumentType] - ), - }, - ), - }, - ) - def share_file(self, params: dict) -> InfoArtifact | ErrorArtifact: - from google.auth.exceptions import MalformedError - from googleapiclient.errors import HttpError # pyright: ignore [reportMissingImports] - - values = params["values"] - file_path = values.get("file_path") - email_address = values.get("email_address") - role = values.get("role", "reader") - - try: - service = self._build_client( - scopes=self.DRIVE_AUTH_SCOPES, - service_name="drive", - version="v3", - owner_email=self.owner_email, - ) - - if file_path.lower() == self.DEFAULT_FOLDER_PATH: - file_id = self.DEFAULT_FOLDER_PATH - else: - file_id = self._convert_path_to_file_id(service, file_path) - - if file_id: - batch_update_permission_request_body = {"role": role, "type": "user", "emailAddress": email_address} - request = service.permissions().create( - fileId=file_id, - body=batch_update_permission_request_body, - fields="id", - ) - request.execute() - return InfoArtifact(f"File at {file_path} shared with {email_address} as a {role}") - else: - return ErrorArtifact(f"error finding file at path: {file_path}") - except HttpError as e: - return ErrorArtifact(f"error sharing file due to http error: {e}") - except MalformedError as e: - return ErrorArtifact(f"error sharing file due to malformed credentials: {e}") - except Exception as e: - return ErrorArtifact(f"error sharing file: {e}") - - def _save_to_drive( - self, - filename: str, - value: Any, - parent_folder_id: Optional[str] = None, - ) -> InfoArtifact | ErrorArtifact: - from googleapiclient.http import MediaIoBaseUpload # pyright: ignore[reportMissingImports] - - service = self._build_client(self.DRIVE_FILE_SCOPES, self.SERVICE_NAME, self.SERVICE_VERSION, self.owner_email) - - if isinstance(value, str): - value = value.encode() - - parts = filename.split("/") - if len(parts) > 1: - directory = "/".join(parts[:-1]) - parent_folder_id = self._convert_path_to_file_id(service, directory) - if not parent_folder_id: - return ErrorArtifact(f"Could not find folder: {directory}") - filename = parts[-1] - - file_metadata = {"name": filename, "parents": []} - if parent_folder_id: - file_metadata["parents"] = [parent_folder_id] - - media = MediaIoBaseUpload(BytesIO(value), mimetype="application/octet-stream", resumable=True) - - file = service.files().create(body=file_metadata, media_body=media, fields="id").execute() - return InfoArtifact(file) - - def _list_files(self, service: Any, query: str) -> list[dict]: - items = [] - next_page_token = None - - while True: - results = service.files().list(q=query, pageToken=next_page_token).execute() - - files = results.get("files", []) - items.extend(files) - - next_page_token = results.get("nextPageToken") - if not next_page_token: - break - - return items diff --git a/griptape/tools/google_gmail/__init__.py b/griptape/tools/google_gmail/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/griptape/tools/google_gmail/requirements.txt b/griptape/tools/google_gmail/requirements.txt deleted file mode 100644 index 704bcd50c..000000000 --- a/griptape/tools/google_gmail/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -google-api-python-client \ No newline at end of file diff --git a/griptape/tools/google_gmail/tool.py b/griptape/tools/google_gmail/tool.py deleted file mode 100644 index 2cc959168..000000000 --- a/griptape/tools/google_gmail/tool.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import annotations - -import base64 -import logging -from email.message import EmailMessage - -from attrs import define, field -from schema import Literal, Schema - -from griptape.artifacts import ErrorArtifact, InfoArtifact -from griptape.tools import BaseGoogleTool -from griptape.utils.decorators import activity - - -@define -class GoogleGmailTool(BaseGoogleTool): - CREATE_DRAFT_EMAIL_SCOPES = ["https://www.googleapis.com/auth/gmail.compose"] - - owner_email: str = field(kw_only=True) - - @activity( - config={ - "description": "Can be used to create a draft email in GMail", - "schema": Schema( - { - Literal("to", description="email address which to send to"): str, - Literal("subject", description="subject of the email"): str, - Literal("body", description="body of the email"): str, - }, - ), - }, - ) - def create_draft_email(self, params: dict) -> InfoArtifact | ErrorArtifact: - values = params["values"] - - try: - service = self._build_client( - scopes=self.CREATE_DRAFT_EMAIL_SCOPES, - service_name="gmail", - version="v1", - owner_email=self.owner_email, - ) - - message = EmailMessage() - message.set_content(values["body"]) - message["To"] = values["to"] - message["From"] = self.owner_email - message["Subject"] = values["subject"] - - encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode() - create_message = {"message": {"raw": encoded_message}} - draft = service.users().drafts().create(userId="me", body=create_message).execute() - return InfoArtifact(f'An email draft was successfully created (ID: {draft["id"]})') - - except Exception as error: - logging.error(error) - return ErrorArtifact(f"error creating draft email: {error}") diff --git a/griptape/tools/griptape_cloud_knowledge_base/__init__.py b/griptape/tools/griptape_cloud_knowledge_base/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/griptape/tools/griptape_cloud_knowledge_base/tool.py b/griptape/tools/griptape_cloud_knowledge_base/tool.py deleted file mode 100644 index 13ff76baa..000000000 --- a/griptape/tools/griptape_cloud_knowledge_base/tool.py +++ /dev/null @@ -1,70 +0,0 @@ -from __future__ import annotations - -from typing import Optional -from urllib.parse import urljoin - -from attrs import define, field -from schema import Literal, Schema - -from griptape.artifacts import ErrorArtifact, TextArtifact -from griptape.tools.base_griptape_cloud_tool import BaseGriptapeCloudTool -from griptape.utils.decorators import activity - - -@define -class GriptapeCloudKnowledgeBaseTool(BaseGriptapeCloudTool): - """Tool for querying a Griptape Cloud Knowledge Base. - - Attributes: - description: LLM-friendly knowledge base description. - knowledge_base_id: ID of the Griptape Cloud Knowledge Base. - """ - - description: Optional[str] = field(default=None, kw_only=True) - knowledge_base_id: str = field(kw_only=True) - - @activity( - config={ - "description": "Can be used to search a knowledge base with the following description: {{ _self._get_knowledge_base_description() }}", - "schema": Schema( - { - Literal( - "query", - description="A natural language search query to run against the knowledge base", - ): str, - }, - ), - }, - ) - def query(self, params: dict) -> TextArtifact | ErrorArtifact: - from requests import exceptions, post - - query = params["values"]["query"] - url = urljoin(self.base_url.strip("/"), f"/api/knowledge-bases/{self.knowledge_base_id}/search") - - try: - response = post(url, json={"query": query}, headers=self.headers) - - return TextArtifact(response.text) - except exceptions.RequestException as err: - return ErrorArtifact(str(err)) - - def _get_knowledge_base_description(self) -> str: - from requests import get - - if self.description: - return self.description - else: - url = urljoin(self.base_url.strip("/"), f"/api/knowledge-bases/{self.knowledge_base_id}/") - - response = get(url, headers=self.headers) - response_body = response.json() - if response.status_code == 200: - if "description" in response_body: - return response_body["description"] - else: - raise ValueError( - f"No description found for Knowledge Base {self.knowledge_base_id}. Please set a description, or manually set the `GriptapeCloudKnowledgeBaseTool.description` attribute.", - ) - else: - raise ValueError(f"Error accessing Knowledge Base {self.knowledge_base_id}.") diff --git a/griptape/tools/openweather/__init__.py b/griptape/tools/openweather/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/griptape/tools/openweather/tool.py b/griptape/tools/openweather/tool.py deleted file mode 100644 index 311db733b..000000000 --- a/griptape/tools/openweather/tool.py +++ /dev/null @@ -1,208 +0,0 @@ -from __future__ import annotations - -import logging -from typing import Optional - -import requests -from attrs import define, field -from schema import Literal, Schema - -from griptape.artifacts import ErrorArtifact, InfoArtifact, ListArtifact, TextArtifact -from griptape.tools import BaseTool -from griptape.utils.decorators import activity - - -@define -class OpenWeatherTool(BaseTool): - BASE_URL = "https://api.openweathermap.org/data/3.0/onecall" - GEOCODING_URL = "https://api.openweathermap.org/geo/1.0/direct" - US_STATE_CODES = [ - "AL", - "AK", - "AZ", - "AR", - "CA", - "CO", - "CT", - "DE", - "FL", - "GA", - "HI", - "ID", - "IL", - "IN", - "IA", - "KS", - "KY", - "LA", - "ME", - "MD", - "MA", - "MI", - "MN", - "MS", - "MO", - "MT", - "NE", - "NV", - "NH", - "NJ", - "NM", - "NY", - "NC", - "ND", - "OH", - "OK", - "OR", - "PA", - "RI", - "SC", - "SD", - "TN", - "TX", - "UT", - "VT", - "VA", - "WA", - "WV", - "WI", - "WY", - ] - api_key: str = field(kw_only=True) - units: str = field(default="imperial", kw_only=True) - - @activity( - config={ - "description": "Can be used to fetch the latitude and longitude for a given location.", - "schema": Schema( - { - Literal( - "location", - description="Location to fetch coordinates for. " - "For US cities, use the format 'city_name, state_code'. " - "For non-US cities, use 'city_name, country_code'. " - "For cities without specifying state or country, simply use 'city_name'.", - ): str, - }, - ), - }, - ) - def get_coordinates_by_location(self, params: dict) -> InfoArtifact | ErrorArtifact: - location = params["values"].get("location") - coordinates = self._fetch_coordinates(location) - if coordinates: - lat, lon = coordinates - return InfoArtifact(f"Coordinates for {location}: Latitude: {lat}, Longitude: {lon}") - else: - return ErrorArtifact(f"Error fetching coordinates for location: {location}") - - def _fetch_coordinates(self, location: str) -> Optional[tuple[float, Optional[float]]]: - parts = location.split(",") - if len(parts) == 2 and parts[1].strip() in self.US_STATE_CODES: - location += ", US" - request_params = {"q": location, "limit": 1, "appid": self.api_key} - try: - response = requests.get(self.GEOCODING_URL, params=request_params) - if response.status_code == 200: - data = response.json() - if data and isinstance(data, list): - return data[0]["lat"], data[0]["lon"] - else: - logging.error( - "Error fetching coordinates. HTTP Status Code: %s. Response: %s", - response.status_code, - response.text, - ) - except Exception as e: - logging.error("Error fetching coordinates: %s", e) - return None - - @activity( - config={ - "description": "Can be used to fetch current weather data for a given location. " - "Temperatures are returned in {{ _self.units }} by default.", - "schema": Schema({Literal("location", description="Location to fetch weather data for."): str}), - }, - ) - def get_current_weather_by_location(self, params: dict) -> ListArtifact | TextArtifact | ErrorArtifact: - location = params["values"].get("location") - coordinates = self._fetch_coordinates(location) - if coordinates: - lat, lon = coordinates - request_params = { - "lat": lat, - "lon": lon, - "exclude": "minutely,hourly,daily,alerts", - "appid": self.api_key, - "units": self.units, - } - return self._fetch_weather_data(request_params) - else: - return ErrorArtifact(f"Error fetching coordinates for location: {location}") - - @activity( - config={ - "description": "Can be used to fetch hourly forecast for a given location up to 48 hours ahead. " - "Temperatures are returned in {{ _self.units }} by default.", - "schema": Schema({Literal("location", description="Location to fetch hourly forecast for."): str}), - }, - ) - def get_hourly_forecast_by_location(self, params: dict) -> ListArtifact | TextArtifact | ErrorArtifact: - location = params["values"].get("location") - coordinates = self._fetch_coordinates(location) - if coordinates: - lat, lon = coordinates - request_params = { - "lat": lat, - "lon": lon, - "exclude": "minutely,current,daily,alerts", - "appid": self.api_key, - "units": self.units, - } - return self._fetch_weather_data(request_params) - else: - return ErrorArtifact(f"Error fetching coordinates for location: {location}") - - @activity( - config={ - "description": "Can be used to fetch daily forecast for a given location up to 8 days ahead. " - "Temperatures are returned in {{ _self.units }} by default.", - "schema": Schema({Literal("location", description="Location to fetch daily forecast for."): str}), - }, - ) - def get_daily_forecast_by_location(self, params: dict) -> ListArtifact | TextArtifact | ErrorArtifact: - location = params["values"].get("location") - coordinates = self._fetch_coordinates(location) - if coordinates: - lat, lon = coordinates - request_params = { - "lat": lat, - "lon": lon, - "exclude": "minutely,hourly,current,alerts", - "appid": self.api_key, - "units": self.units, - } - return self._fetch_weather_data(request_params) - else: - return ErrorArtifact(f"Error fetching coordinates for location: {location}") - - def _fetch_weather_data(self, request_params: dict) -> ListArtifact | TextArtifact | ErrorArtifact: - try: - response = requests.get(self.BASE_URL, params=request_params) - if response.status_code == 200: - data = response.json() - if isinstance(data, list): - wrapped_data = [InfoArtifact(item) for item in data] - return ListArtifact(wrapped_data) - else: - return TextArtifact(str(data)) - else: - logging.error( - "Error fetching weather data. HTTP Status Code: %s. Response: %s", - response.status_code, - response.text, - ) - return ErrorArtifact("Error fetching weather data from OpenWeather API") - except Exception as e: - logging.error("Error fetching weather data: %s", e) - return ErrorArtifact(f"Error fetching weather data: {e}") diff --git a/mkdocs.yml b/mkdocs.yml index b8cbe6822..892069431 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -143,19 +143,12 @@ nav: - Tools: - Overview: "griptape-tools/index.md" - Official Tools: - - Aws Iam: "griptape-tools/official-tools/aws-iam-tool.md" - - Aws S3: "griptape-tools/official-tools/aws-s3-tool.md" - Calculator: "griptape-tools/official-tools/calculator-tool.md" - Computer: "griptape-tools/official-tools/computer-tool.md" - Date Time: "griptape-tools/official-tools/date-time-tool.md" - Email: "griptape-tools/official-tools/email-tool.md" - File Manager: "griptape-tools/official-tools/file-manager-tool.md" - - Google Calendar: "griptape-tools/official-tools/google-calendar-tool.md" - - Google Gmail: "griptape-tools/official-tools/google-gmail-tool.md" - - Google Drive: "griptape-tools/official-tools/google-drive-tool.md" - - Google Docs: "griptape-tools/official-tools/google-docs-tool.md" - Structure Run Client: "griptape-tools/official-tools/structure-run-tool.md" - - Open Weather: "griptape-tools/official-tools/openweather-tool.md" - Rest Api Client: "griptape-tools/official-tools/rest-api-tool.md" - Sql: "griptape-tools/official-tools/sql-tool.md" - Vector Store Tool: "griptape-tools/official-tools/vector-store-tool.md" @@ -168,7 +161,6 @@ nav: - Image Query: "griptape-tools/official-tools/image-query-tool.md" - Text To Speech: "griptape-tools/official-tools/text-to-speech-tool.md" - Audio Transcription: "griptape-tools/official-tools/audio-transcription-tool.md" - - Griptape Cloud Knowledge Base: "griptape-tools/official-tools/griptape-cloud-knowledge-base-tool.md" - Rag: "griptape-tools/official-tools/rag-tool.md" - Extraction: "griptape-tools/official-tools/extraction-tool.md" - Query: "griptape-tools/official-tools/query-tool.md" diff --git a/tests/unit/tools/test_aws_iam_tool.py b/tests/unit/tools/test_aws_iam_tool.py deleted file mode 100644 index fb2b1e381..000000000 --- a/tests/unit/tools/test_aws_iam_tool.py +++ /dev/null @@ -1,31 +0,0 @@ -import boto3 -import pytest - -from griptape.tools import AwsIamTool -from tests.utils.aws import mock_aws_credentials - - -class TestAwsIamTool: - @pytest.fixture(autouse=True) - def _run_before_and_after_tests(self): - mock_aws_credentials() - - def test_get_user_policy(self): - value = {"user_name": "test_user", "policy_name": "test_policy"} - assert ( - "error returning policy document" - in AwsIamTool(session=boto3.Session()).get_user_policy({"values": value}).value - ) - - def test_list_mfa_devices(self): - assert "error listing mfa devices" in AwsIamTool(session=boto3.Session()).list_mfa_devices({}).value - - def test_list_user_policies(self): - value = {"user_name": "test_user"} - assert ( - "error listing iam user policies" - in AwsIamTool(session=boto3.Session()).list_user_policies({"values": value}).value - ) - - def test_list_users(self): - assert "error listing s3 users" in AwsIamTool(session=boto3.Session()).list_users({}).value diff --git a/tests/unit/tools/test_aws_s3_tool.py b/tests/unit/tools/test_aws_s3_tool.py deleted file mode 100644 index 8be8ebc5c..000000000 --- a/tests/unit/tools/test_aws_s3_tool.py +++ /dev/null @@ -1,52 +0,0 @@ -import boto3 -import pytest -from moto import mock_aws - -from griptape.tools import AwsS3Tool - - -class TestAwsS3Tool: - @pytest.fixture() - def session(self): - mock = mock_aws() - mock.start() - yield boto3.Session(region_name="us-east-1") - mock.stop() - - def test_get_bucket_acl(self, session): - value = {"bucket_name": "bucket_test"} - assert "error getting bucket acl" in AwsS3Tool(session=session).get_bucket_acl({"values": value}).value - - def test_get_bucket_policy(self, session): - value = {"bucket_name": "bucket_test"} - assert "error getting bucket policy" in AwsS3Tool(session=session).get_bucket_policy({"values": value}).value - - def test_get_object_acl(self, session): - value = {"bucket_name": "bucket_test", "object_key": "key_test"} - assert "error getting object acl" in AwsS3Tool(session=session).get_object_acl({"values": value}).value - - def test_list_s3_buckets(self, session): - assert AwsS3Tool(session=session).list_s3_buckets({}).value == [] - - def test_list_objects(self, session): - value = {"bucket_name": "bucket_test"} - assert "error listing objects in bucket" in AwsS3Tool(session=session).list_objects({"values": value}).value - - def test_upload_memory_artifacts_to_s3(self, session): - value = { - "memory_name": "foobar", - "bucket_name": "bucket_test", - "artifact_namespace": "foo", - "object_key": "test.txt", - } - assert "memory not found" in AwsS3Tool(session=session).upload_memory_artifacts_to_s3({"values": value}).value - - def test_upload_content_to_s3(self, session): - value = {"content": "foobar", "bucket_name": "bucket_test", "object_key": "test.txt"} - - assert "uploaded successfully" in AwsS3Tool(session=session).upload_content_to_s3({"values": value}).value - - def test_download_objects(self, session): - value = {"objects": {"bucket_name": "bucket_test", "object_key": "test.txt"}} - - assert "error downloading objects" in AwsS3Tool(session=session).download_objects({"values": value}).value diff --git a/tests/unit/tools/test_google_docs_tool.py b/tests/unit/tools/test_google_docs_tool.py deleted file mode 100644 index 516961c61..000000000 --- a/tests/unit/tools/test_google_docs_tool.py +++ /dev/null @@ -1,24 +0,0 @@ -import pytest - - -class TestGoogleDocsTool: - @pytest.fixture() - def mock_docs_client(self): - from griptape.tools import GoogleDocsTool - - return GoogleDocsTool(owner_email="tony@griptape.ai", service_account_credentials={}) - - def test_append_text(self, mock_docs_client): - params = {"file_path": "test_folder/test_document", "text": "Appending this text"} - result = mock_docs_client.append_text_to_google_doc({"values": params}).value - assert "error appending text to Google Doc with path" in result - - def test_prepend_text(self, mock_docs_client): - params = {"file_path": "test_folder/test_document", "text": "Prepending this text"} - result = mock_docs_client.prepend_text_to_google_doc({"values": params}).value - assert "error prepending text to Google Doc with path" in result - - def test_save_content_to_google_doc(self, mock_docs_client): - params = {"file_path": "test_document", "content": "Sample content"} - result = mock_docs_client.save_content_to_google_doc({"values": params}).value - assert "Error creating/saving Google Doc:" in result diff --git a/tests/unit/tools/test_google_drive_tool.py b/tests/unit/tools/test_google_drive_tool.py deleted file mode 100644 index 55eae2267..000000000 --- a/tests/unit/tools/test_google_drive_tool.py +++ /dev/null @@ -1,52 +0,0 @@ -from griptape.artifacts import ErrorArtifact -from griptape.tools import GoogleDriveTool - - -class TestGoogleDriveTool: - def test_list_files(self): - value = {"folder_path": "root"} # This can be any folder path you want to test - result = GoogleDriveTool(owner_email="tony@griptape.ai", service_account_credentials={}).list_files( - {"values": value} - ) - - assert isinstance(result, ErrorArtifact) - assert "error listing files due to malformed credentials" in result.value - - def test_save_content_to_drive(self): - value = {"path": "/path/to/your/file.txt", "content": "Sample content for the file."} - result = GoogleDriveTool(owner_email="tony@griptape.ai", service_account_credentials={}).save_content_to_drive( - {"values": value} - ) - - assert isinstance(result, ErrorArtifact) - assert "error saving file to Google Drive" in result.value - - def test_download_files(self): - value = {"file_paths": ["example_folder/example_file.txt"]} - result = GoogleDriveTool(owner_email="tony@griptape.ai", service_account_credentials={}).download_files( - {"values": value} - ) - - assert isinstance(result, ErrorArtifact) - - assert "error downloading file due to malformed credentials" in result.value - - def test_search_files(self): - value = {"search_mode": "name", "file_name": "search_file_name.txt"} - result = GoogleDriveTool(owner_email="tony@griptape.ai", service_account_credentials={}).search_files( - {"values": value} - ) - - assert isinstance(result, ErrorArtifact) - - assert "error searching for file due to malformed credentials" in result.value - - def test_share_file(self): - value = {"file_path": "/path/to/your/file.txt", "email_address": "sample_email@example.com", "role": "reader"} - result = GoogleDriveTool(owner_email="tony@griptape.ai", service_account_credentials={}).share_file( - {"values": value} - ) - - assert isinstance(result, ErrorArtifact) - - assert "error sharing file due to malformed credentials" in result.value diff --git a/tests/unit/tools/test_google_gmail_tool.py b/tests/unit/tools/test_google_gmail_tool.py deleted file mode 100644 index ace7ef0ba..000000000 --- a/tests/unit/tools/test_google_gmail_tool.py +++ /dev/null @@ -1,12 +0,0 @@ -from griptape.tools import GoogleGmailTool - - -class TestGoogleGmailTool: - def test_create_draft_email(self): - value = {"subject": "stacey's mom", "from": "test@test.com", "body": "got it going on"} - assert ( - "error creating draft email" - in GoogleGmailTool(service_account_credentials={}, owner_email="tony@griptape.ai") - .create_draft_email({"values": value}) - .value - ) diff --git a/tests/unit/tools/test_griptape_cloud_knowledge_base_tool.py b/tests/unit/tools/test_griptape_cloud_knowledge_base_tool.py deleted file mode 100644 index b98713273..000000000 --- a/tests/unit/tools/test_griptape_cloud_knowledge_base_tool.py +++ /dev/null @@ -1,85 +0,0 @@ -import pytest -from requests import exceptions - -from griptape.artifacts import ErrorArtifact, TextArtifact - - -class TestGriptapeCloudKnowledgeBaseTool: - @pytest.fixture() - def client(self, mocker): - from griptape.tools import GriptapeCloudKnowledgeBaseTool - - mock_response = mocker.Mock() - mock_response.status_code = 201 - mock_response.text.return_value = "foo bar" - mocker.patch("requests.post", return_value=mock_response) - - mock_response = mocker.Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"description": "fizz buzz"} - mocker.patch("requests.get", return_value=mock_response) - - return GriptapeCloudKnowledgeBaseTool( - base_url="https://api.griptape.ai", api_key="foo bar", knowledge_base_id="1" - ) - - @pytest.fixture() - def client_no_description(self, mocker): - from griptape.tools import GriptapeCloudKnowledgeBaseTool - - mock_response = mocker.Mock() - mock_response.json.return_value = {} - mock_response.status_code = 200 - mocker.patch("requests.get", return_value=mock_response) - - return GriptapeCloudKnowledgeBaseTool( - base_url="https://api.griptape.ai", api_key="foo bar", knowledge_base_id="1" - ) - - @pytest.fixture() - def client_kb_not_found(self, mocker): - from griptape.tools import GriptapeCloudKnowledgeBaseTool - - mock_response = mocker.Mock() - mock_response.json.return_value = {} - mock_response.status_code = 404 - mocker.patch("requests.get", return_value=mock_response) - - return GriptapeCloudKnowledgeBaseTool( - base_url="https://api.griptape.ai", api_key="foo bar", knowledge_base_id="1" - ) - - @pytest.fixture() - def client_kb_error(self, mocker): - from griptape.tools import GriptapeCloudKnowledgeBaseTool - - mock_response = mocker.Mock() - mock_response.status_code = 500 - mocker.patch("requests.post", return_value=mock_response, side_effect=exceptions.RequestException("error")) - - return GriptapeCloudKnowledgeBaseTool( - base_url="https://api.griptape.ai", api_key="foo bar", knowledge_base_id="1" - ) - - def test_query(self, client): - assert isinstance(client.query({"values": {"query": "foo bar"}}), TextArtifact) - - def test_query_error(self, client_kb_error): - assert isinstance(client_kb_error.query({"values": {"query": "foo bar"}}), ErrorArtifact) - assert client_kb_error.query({"values": {"query": "foo bar"}}).value == "error" - - def test_get_knowledge_base_description(self, client): - assert client._get_knowledge_base_description() == "fizz buzz" - - client.description = "foo bar" - assert client._get_knowledge_base_description() == "foo bar" - - def test_get_knowledge_base_description_error(self, client_no_description): - exception_match_text = f"No description found for Knowledge Base {client_no_description.knowledge_base_id}. Please set a description, or manually set the `GriptapeCloudKnowledgeBaseTool.description` attribute." - with pytest.raises(ValueError, match=exception_match_text): - client_no_description._get_knowledge_base_description() - - def test_get_knowledge_base_kb_error(self, client_kb_not_found): - exception_match_text = f"Error accessing Knowledge Base {client_kb_not_found.knowledge_base_id}." - with pytest.raises(ValueError, match=exception_match_text): - client_kb_not_found._get_knowledge_base_description() diff --git a/tests/unit/tools/test_openweather_tool.py b/tests/unit/tools/test_openweather_tool.py deleted file mode 100644 index 44acaf571..000000000 --- a/tests/unit/tools/test_openweather_tool.py +++ /dev/null @@ -1,72 +0,0 @@ -from unittest.mock import patch - -import pytest - -from griptape.artifacts import ErrorArtifact -from griptape.tools import OpenWeatherTool - - -@pytest.fixture() -def client(): - return OpenWeatherTool(api_key="YOUR_API_KEY") - - -class MockResponse: - def __init__(self, json_data, status_code) -> None: - self.json_data = json_data - self.status_code = status_code - - def json(self): - return self.json_data - - -def mock_requests_get(*args, **kwargs): - if args[0] == OpenWeatherTool.GEOCODING_URL: - return MockResponse([{"lat": 40.7128, "lon": -74.0061}], 200) - elif args[0] == OpenWeatherTool.BASE_URL: - return MockResponse({"weather": "sunny"}, 200) - return MockResponse(None, 404) - - -@patch("requests.get", side_effect=mock_requests_get) -def test_get_coordinates_by_location(mock_get, client): - params = {"values": {"location": "New York, NY"}} - result = client.get_coordinates_by_location(params) - assert result.to_text() == "Coordinates for New York, NY: Latitude: 40.7128, Longitude: -74.0061" - - -@patch("requests.get", side_effect=mock_requests_get) -def test_get_current_weather_by_location(mock_get, client): - params = {"values": {"location": "New York, NY"}} - result = client.get_current_weather_by_location(params) - assert result.to_text() == "{'weather': 'sunny'}" - - -@patch("requests.get", side_effect=mock_requests_get) -def test_get_hourly_forecast_by_location(mock_get, client): - params = {"values": {"location": "New York, NY"}} - result = client.get_hourly_forecast_by_location(params) - assert result.to_text() == "{'weather': 'sunny'}" - - -@patch("requests.get", side_effect=mock_requests_get) -def test_get_daily_forecast_by_location(mock_get, client): - params = {"values": {"location": "New York, NY"}} - result = client.get_daily_forecast_by_location(params) - assert result.to_text() == "{'weather': 'sunny'}" - - -@patch("requests.get", return_value=MockResponse(None, 401)) -def test_invalid_api_key(mock_get, client): - params = {"values": {"location": "New York, NY"}} - result = client.get_coordinates_by_location(params) - assert isinstance(result, ErrorArtifact) - assert "Error fetching coordinates for location: New York, NY" in result.to_text() - - -@patch("requests.get", return_value=MockResponse(None, 404)) -def test_invalid_location(mock_get, client): - params = {"values": {"location": "InvalidCity, XX"}} - result = client.get_coordinates_by_location(params) - assert isinstance(result, ErrorArtifact) - assert "Error fetching coordinates for location: InvalidCity, XX" in result.to_text()