community[minor]: Connery Tool and Toolkit (#14506)

## Summary

This PR implements the "Connery Action Tool" and "Connery Toolkit".
Using them, you can integrate Connery actions into your LangChain agents
and chains.

Connery is an open-source plugin infrastructure for AI.

With Connery, you can easily create a custom plugin with a set of
actions and seamlessly integrate them into your LangChain agents and
chains. Connery will handle the rest: runtime, authorization, secret
management, access management, audit logs, and other vital features.
Additionally, Connery and our community offer a wide range of
ready-to-use open-source plugins for your convenience.

Learn more about Connery:

- GitHub: https://github.com/connery-io/connery-platform
- Documentation: https://docs.connery.io
- Twitter: https://twitter.com/connery_io

## TODOs

- [x] API wrapper
   - [x] Integration tests
- [x] Connery Action Tool
   - [x] Docs
   - [x] Example
   - [x] Integration tests
- [x] Connery Toolkit
  - [x] Docs
  - [x] Example
- [x] Formatting (`make format`)
- [x] Linting (`make lint`)
- [x] Testing (`make test`)
pull/13704/head^2
Volodymyr Machula 5 months ago committed by GitHub
parent 8457c31c04
commit 32c5be8b73
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,136 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Connery Toolkit\n",
"\n",
"Using this toolkit, you can integrate Connery Actions into your LangChain agent.\n",
"\n",
"If you want to use only one particular Connery Action in your agent,\n",
"check out the [Connery Action Tool](/docs/integrations/tools/connery) documentation.\n",
"\n",
"## What is Connery?\n",
"\n",
"Connery is an open-source plugin infrastructure for AI.\n",
"\n",
"With Connery, you can easily create a custom plugin with a set of actions and seamlessly integrate them into your LangChain agent.\n",
"Connery will take care of critical aspects such as runtime, authorization, secret management, access management, audit logs, and other vital features.\n",
"\n",
"Furthermore, Connery, supported by our community, provides a diverse collection of ready-to-use open-source plugins for added convenience.\n",
"\n",
"Learn more about Connery:\n",
"\n",
"- GitHub: https://github.com/connery-io/connery\n",
"- Documentation: https://docs.connery.io\n",
"\n",
"## Prerequisites\n",
"\n",
"To use Connery Actions in your LangChain agent, you need to do some preparation:\n",
"\n",
"1. Set up the Connery runner using the [Quickstart](https://docs.connery.io/docs/runner/quick-start/) guide.\n",
"2. Install all the plugins with the actions you want to use in your agent.\n",
"3. Set environment variables `CONNERY_RUNNER_URL` and `CONNERY_RUNNER_API_KEY` so the toolkit can communicate with the Connery Runner.\n",
"\n",
"## Example of using Connery Toolkit\n",
"\n",
"In the example below, we create an agent that uses two Connery Actions to summarize a public webpage and send the summary by email:\n",
"\n",
"1. **Summarize public webpage** action from the [Summarization](https://github.com/connery-io/summarization-plugin) plugin.\n",
"2. **Send email** action from the [Gmail](https://github.com/connery-io/gmail) plugin.\n",
"\n",
"You can see a LangSmith trace of this example [here](https://smith.langchain.com/public/4af5385a-afe9-46f6-8a53-57fe2d63c5bc/r)."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m\n",
"Invoking: `CA72DFB0AB4DF6C830B43E14B0782F70` with `{'publicWebpageUrl': 'http://www.paulgraham.com/vb.html'}`\n",
"\n",
"\n",
"\u001b[0m\u001b[33;1m\u001b[1;3m{'summary': 'The author reflects on the concept of life being short and how having children made them realize the true brevity of life. They discuss how time can be converted into discrete quantities and how limited certain experiences are. The author emphasizes the importance of prioritizing and eliminating unnecessary things in life, as well as actively pursuing meaningful experiences. They also discuss the negative impact of getting caught up in online arguments and the need to be aware of how time is being spent. The author suggests pruning unnecessary activities, not waiting to do things that matter, and savoring the time one has.'}\u001b[0m\u001b[32;1m\u001b[1;3m\n",
"Invoking: `CABC80BB79C15067CA983495324AE709` with `{'recipient': 'test@example.com', 'subject': 'Summary of the webpage', 'body': 'Here is a short summary of the webpage http://www.paulgraham.com/vb.html:\\n\\nThe author reflects on the concept of life being short and how having children made them realize the true brevity of life. They discuss how time can be converted into discrete quantities and how limited certain experiences are. The author emphasizes the importance of prioritizing and eliminating unnecessary things in life, as well as actively pursuing meaningful experiences. They also discuss the negative impact of getting caught up in online arguments and the need to be aware of how time is being spent. The author suggests pruning unnecessary activities, not waiting to do things that matter, and savoring the time one has.\\n\\nYou can find the full webpage [here](http://www.paulgraham.com/vb.html).'}`\n",
"\n",
"\n",
"\u001b[0m\u001b[33;1m\u001b[1;3m{'messageId': '<2f04b00e-122d-c7de-c91e-e78e0c3276d6@gmail.com>'}\u001b[0m\u001b[32;1m\u001b[1;3mI have sent the email with the summary of the webpage to test@example.com. Please check your inbox.\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"I have sent the email with the summary of the webpage to test@example.com. Please check your inbox.\n"
]
}
],
"source": [
"import os\n",
"\n",
"from langchain.agents import AgentType, initialize_agent\n",
"from langchain.chat_models import ChatOpenAI\n",
"from langchain_community.agent_toolkits.connery import ConneryToolkit\n",
"from langchain_community.tools.connery import ConneryService\n",
"\n",
"# Specify your Connery Runner credentials.\n",
"os.environ[\"CONNERY_RUNNER_URL\"] = \"\"\n",
"os.environ[\"CONNERY_RUNNER_API_KEY\"] = \"\"\n",
"\n",
"# Specify OpenAI API key.\n",
"os.environ[\"OPENAI_API_KEY\"] = \"\"\n",
"\n",
"# Specify your email address to receive the email with the summary from example below.\n",
"recepient_email = \"test@example.com\"\n",
"\n",
"# Create a Connery Toolkit with all the available actions from the Connery Runner.\n",
"connery_service = ConneryService()\n",
"connery_toolkit = ConneryToolkit.create_instance(connery_service)\n",
"\n",
"# Use OpenAI Functions agent to execute the prompt using actions from the Connery Toolkit.\n",
"llm = ChatOpenAI(temperature=0)\n",
"agent = initialize_agent(\n",
" connery_toolkit.get_tools(), llm, AgentType.OPENAI_FUNCTIONS, verbose=True\n",
")\n",
"result = agent.run(\n",
" f\"\"\"Make a short summary of the webpage http://www.paulgraham.com/vb.html in three sentences\n",
"and send it to {recepient_email}. Include the link to the webpage into the body of the email.\"\"\"\n",
")\n",
"print(result)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"NOTE: Connery Action is a structured tool, so you can only use it in the agents supporting structured tools."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

@ -0,0 +1,165 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Connery Action Tool\n",
"\n",
"Using this tool, you can integrate individual Connery Action into your LangChain agent.\n",
"\n",
"If you want to use more than one Connery Action in your agent,\n",
"check out the [Connery Toolkit](/docs/integrations/toolkits/connery) documentation.\n",
"\n",
"## What is Connery?\n",
"\n",
"Connery is an open-source plugin infrastructure for AI.\n",
"\n",
"With Connery, you can easily create a custom plugin with a set of actions and seamlessly integrate them into your LangChain agent.\n",
"Connery will take care of critical aspects such as runtime, authorization, secret management, access management, audit logs, and other vital features.\n",
"\n",
"Furthermore, Connery, supported by our community, provides a diverse collection of ready-to-use open-source plugins for added convenience.\n",
"\n",
"Learn more about Connery:\n",
"\n",
"- GitHub: https://github.com/connery-io/connery\n",
"- Documentation: https://docs.connery.io\n",
"\n",
"## Prerequisites\n",
"\n",
"To use Connery Actions in your LangChain agent, you need to do some preparation:\n",
"\n",
"1. Set up the Connery runner using the [Quickstart](https://docs.connery.io/docs/runner/quick-start/) guide.\n",
"2. Install all the plugins with the actions you want to use in your agent.\n",
"3. Set environment variables `CONNERY_RUNNER_URL` and `CONNERY_RUNNER_API_KEY` so the toolkit can communicate with the Connery Runner.\n",
"\n",
"## Example of using Connery Action Tool\n",
"\n",
"In the example below, we fetch action by its ID from the Connery Runner and then call it with the specified parameters.\n",
"\n",
"Here, we use the ID of the **Send email** action from the [Gmail](https://github.com/connery-io/gmail) plugin."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"from langchain.agents import AgentType, initialize_agent\n",
"from langchain.chat_models import ChatOpenAI\n",
"from langchain_community.tools.connery import ConneryService\n",
"\n",
"# Specify your Connery Runner credentials.\n",
"os.environ[\"CONNERY_RUNNER_URL\"] = \"\"\n",
"os.environ[\"CONNERY_RUNNER_API_KEY\"] = \"\"\n",
"\n",
"# Specify OpenAI API key.\n",
"os.environ[\"OPENAI_API_KEY\"] = \"\"\n",
"\n",
"# Specify your email address to receive the emails from examples below.\n",
"recepient_email = \"test@example.com\"\n",
"\n",
"# Get the SendEmail action from the Connery Runner by ID.\n",
"connery_service = ConneryService()\n",
"send_email_action = connery_service.get_action(\"CABC80BB79C15067CA983495324AE709\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Run the action manually."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"manual_run_result = send_email_action.run(\n",
" {\n",
" \"recipient\": recepient_email,\n",
" \"subject\": \"Test email\",\n",
" \"body\": \"This is a test email sent from Connery.\",\n",
" }\n",
")\n",
"print(manual_run_result)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Run the action using the OpenAI Functions agent.\n",
"\n",
"You can see a LangSmith trace of this example [here](https://smith.langchain.com/public/a37d216f-c121-46da-a428-0e09dc19b1dc/r)."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m\n",
"Invoking: `CABC80BB79C15067CA983495324AE709` with `{'recipient': 'test@example.com', 'subject': 'Late for Meeting', 'body': 'Dear Team,\\n\\nI wanted to inform you that I will be late for the meeting today. I apologize for any inconvenience caused. Please proceed with the meeting without me and I will join as soon as I can.\\n\\nBest regards,\\n[Your Name]'}`\n",
"\n",
"\n",
"\u001b[0m\u001b[36;1m\u001b[1;3m{'messageId': '<d34a694d-50e0-3988-25da-e86b4c51d7a7@gmail.com>'}\u001b[0m\u001b[32;1m\u001b[1;3mI have sent an email to test@example.com informing them that you will be late for the meeting.\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"I have sent an email to test@example.com informing them that you will be late for the meeting.\n"
]
}
],
"source": [
"llm = ChatOpenAI(temperature=0)\n",
"agent = initialize_agent(\n",
" [send_email_action], llm, AgentType.OPENAI_FUNCTIONS, verbose=True\n",
")\n",
"agent_run_result = agent.run(\n",
" f\"Send an email to the {recepient_email} and say that I will be late for the meeting.\"\n",
")\n",
"print(agent_run_result)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"NOTE: Connery Action is a structured tool, so you can only use it in the agents supporting structured tools."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

@ -18,6 +18,7 @@ from langchain_community.agent_toolkits.amadeus.toolkit import AmadeusToolkit
from langchain_community.agent_toolkits.azure_cognitive_services import (
AzureCognitiveServicesToolkit,
)
from langchain_community.agent_toolkits.connery import ConneryToolkit
from langchain_community.agent_toolkits.file_management.toolkit import (
FileManagementToolkit,
)
@ -50,6 +51,7 @@ __all__ = [
"AINetworkToolkit",
"AmadeusToolkit",
"AzureCognitiveServicesToolkit",
"ConneryToolkit",
"FileManagementToolkit",
"GmailToolkit",
"JiraToolkit",

@ -0,0 +1,7 @@
"""
This module contains the ConneryToolkit.
"""
from .toolkit import ConneryToolkit
__all__ = ["ConneryToolkit"]

@ -0,0 +1,51 @@
from typing import List
from langchain_core.pydantic_v1 import root_validator
from langchain_core.tools import BaseTool
from langchain_community.agent_toolkits.base import BaseToolkit
from langchain_community.tools.connery import ConneryService
class ConneryToolkit(BaseToolkit):
"""
A LangChain Toolkit with a list of Connery Actions as tools.
"""
tools: List[BaseTool]
def get_tools(self) -> List[BaseTool]:
"""
Returns the list of Connery Actions.
"""
return self.tools
@root_validator()
def validate_attributes(cls, values: dict) -> dict:
"""
Validate the attributes of the ConneryToolkit class.
Parameters:
values (dict): The arguments to validate.
Returns:
dict: The validated arguments.
"""
if not values.get("tools"):
raise ValueError("The attribute 'tools' must be set.")
return values
@classmethod
def create_instance(cls, connery_service: ConneryService) -> "ConneryToolkit":
"""
Creates a Connery Toolkit using a Connery Service.
Parameters:
connery_service (ConneryService): The Connery Service
to to get the list of Connery Actions.
Returns:
ConneryToolkit: The Connery Toolkit.
"""
instance = cls(tools=connery_service.list_actions())
return instance

@ -118,6 +118,12 @@ def _import_brave_search_tool() -> Any:
return BraveSearch
def _import_connery_tool() -> Any:
from langchain_community.tools.connery import ConneryAction
return ConneryAction
def _import_ddg_search_tool_DuckDuckGoSearchResults() -> Any:
from langchain_community.tools.ddg_search.tool import DuckDuckGoSearchResults
@ -797,6 +803,8 @@ def __getattr__(name: str) -> Any:
return _import_bing_search_tool_BingSearchRun()
elif name == "BraveSearch":
return _import_brave_search_tool()
elif name == "ConneryAction":
return _import_connery_tool()
elif name == "DuckDuckGoSearchResults":
return _import_ddg_search_tool_DuckDuckGoSearchResults()
elif name == "DuckDuckGoSearchRun":
@ -1035,6 +1043,7 @@ __all__ = [
"BingSearchRun",
"BraveSearch",
"ClickTool",
"ConneryAction",
"CopyFileTool",
"CurrentWebPageTool",
"DeleteFileTool",

@ -0,0 +1,8 @@
"""
This module contains the ConneryAction Tool and ConneryService.
"""
from .service import ConneryService
from .tool import ConneryAction
__all__ = ["ConneryAction", "ConneryService"]

@ -0,0 +1,32 @@
from typing import List, Optional
from langchain_core.pydantic_v1 import BaseModel
class Validation(BaseModel):
"""Connery Action parameter validation model."""
required: Optional[bool] = None
class Parameter(BaseModel):
"""Connery Action parameter model."""
key: str
title: str
description: Optional[str] = None
type: str
validation: Optional[Validation] = None
class Action(BaseModel):
"""Connery Action model."""
id: str
key: str
title: str
description: Optional[str] = None
type: str
inputParameters: List[Parameter]
outputParameters: List[Parameter]
pluginId: str

@ -0,0 +1,165 @@
import json
from typing import Dict, List, Optional
import requests
from langchain_core.pydantic_v1 import BaseModel, root_validator
from langchain_core.utils.env import get_from_dict_or_env
from langchain_community.tools.connery.models import Action
from langchain_community.tools.connery.tool import ConneryAction
class ConneryService(BaseModel):
"""
A service for interacting with the Connery Runner API.
It gets the list of available actions from the Connery Runner,
wraps them in ConneryAction Tools and returns them to the user.
It also provides a method for running the actions.
"""
runner_url: Optional[str] = None
api_key: Optional[str] = None
@root_validator()
def validate_attributes(cls, values: Dict) -> Dict:
"""
Validate the attributes of the ConneryService class.
Parameters:
values (dict): The arguments to validate.
Returns:
dict: The validated arguments.
"""
runner_url = get_from_dict_or_env(values, "runner_url", "CONNERY_RUNNER_URL")
api_key = get_from_dict_or_env(values, "api_key", "CONNERY_RUNNER_API_KEY")
if not runner_url:
raise ValueError("CONNERY_RUNNER_URL environment variable must be set.")
if not api_key:
raise ValueError("CONNERY_RUNNER_API_KEY environment variable must be set.")
values["runner_url"] = runner_url
values["api_key"] = api_key
return values
def list_actions(self) -> List[ConneryAction]:
"""
Returns the list of actions available in the Connery Runner.
Returns:
List[ConneryAction]: The list of actions available in the Connery Runner.
"""
return [
ConneryAction.create_instance(action, self)
for action in self._list_actions()
]
def get_action(self, action_id: str) -> ConneryAction:
"""
Returns the specified action available in the Connery Runner.
Parameters:
action_id (str): The ID of the action to return.
Returns:
ConneryAction: The action with the specified ID.
"""
return ConneryAction.create_instance(self._get_action(action_id), self)
def run_action(self, action_id: str, input: Dict[str, str] = {}) -> Dict[str, str]:
"""
Runs the specified Connery Action with the provided input.
Parameters:
action_id (str): The ID of the action to run.
input (Dict[str, str]): The input object expected by the action.
Returns:
Dict[str, str]: The output of the action.
"""
return self._run_action(action_id, input)
def _list_actions(self) -> List[Action]:
"""
Returns the list of actions available in the Connery Runner.
Returns:
List[Action]: The list of actions available in the Connery Runner.
"""
response = requests.get(
f"{self.runner_url}/v1/actions", headers=self._get_headers()
)
if not response.ok:
raise ValueError(
(
"Failed to list actions."
f"Status code: {response.status_code}."
f"Error message: {response.json()['error']['message']}"
)
)
return [Action(**action) for action in response.json()["data"]]
def _get_action(self, action_id: str) -> Action:
"""
Returns the specified action available in the Connery Runner.
Parameters:
action_id (str): The ID of the action to return.
Returns:
Action: The action with the specified ID.
"""
actions = self._list_actions()
action = next((action for action in actions if action.id == action_id), None)
if not action:
raise ValueError(
(
f"The action with ID {action_id} was not found in the list"
"of available actions in the Connery Runner."
)
)
return action
def _run_action(self, action_id: str, input: Dict[str, str] = {}) -> Dict[str, str]:
"""
Runs the specified Connery Action with the provided input.
Parameters:
action_id (str): The ID of the action to run.
prompt (str): This is a plain English prompt
with all the information needed to run the action.
input (Dict[str, str]): The input object expected by the action.
If provided together with the prompt,
the input takes precedence over the input specified in the prompt.
Returns:
Dict[str, str]: The output of the action.
"""
response = requests.post(
f"{self.runner_url}/v1/actions/{action_id}/run",
headers=self._get_headers(),
data=json.dumps({"input": input}),
)
if not response.ok:
raise ValueError(
(
"Failed to run action."
f"Status code: {response.status_code}."
f"Error message: {response.json()['error']['message']}"
)
)
if not response.json()["data"]["output"]:
return {}
else:
return response.json()["data"]["output"]
def _get_headers(self) -> Dict[str, str]:
"""
Returns a standard set of HTTP headers
to be used in API calls to the Connery runner.
Returns:
Dict[str, str]: The standard set of HTTP headers.
"""
return {"Content-Type": "application/json", "x-api-key": self.api_key or ""}

@ -0,0 +1,163 @@
import asyncio
from functools import partial
from typing import Any, Dict, List, Optional, Type
from langchain_core.callbacks.manager import (
AsyncCallbackManagerForToolRun,
CallbackManagerForToolRun,
)
from langchain_core.pydantic_v1 import BaseModel, Field, create_model, root_validator
from langchain_core.tools import BaseTool
from langchain_community.tools.connery.models import Action, Parameter
class ConneryAction(BaseTool):
"""
A LangChain Tool wrapping a Connery Action.
"""
name: str
description: str
args_schema: Type[BaseModel]
action: Action
connery_service: Any
def _run(
self,
run_manager: Optional[CallbackManagerForToolRun] = None,
**kwargs: Dict[str, str],
) -> Dict[str, str]:
"""
Runs the Connery Action with the provided input.
Parameters:
kwargs (Dict[str, str]): The input dictionary expected by the action.
Returns:
Dict[str, str]: The output of the action.
"""
return self.connery_service.run_action(self.action.id, kwargs)
async def _arun(
self,
run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
**kwargs: Dict[str, str],
) -> Dict[str, str]:
"""
Runs the Connery Action asynchronously with the provided input.
Parameters:
kwargs (Dict[str, str]): The input dictionary expected by the action.
Returns:
Dict[str, str]: The output of the action.
"""
func = partial(self._run, **kwargs)
return await asyncio.get_event_loop().run_in_executor(None, func)
def get_schema_json(self) -> str:
"""
Returns the JSON representation of the Connery Action Tool schema.
This is useful for debugging.
Returns:
str: The JSON representation of the Connery Action Tool schema.
"""
return self.args_schema.schema_json(indent=2)
@root_validator()
def validate_attributes(cls, values: dict) -> dict:
"""
Validate the attributes of the ConneryAction class.
Parameters:
values (dict): The arguments to validate.
Returns:
dict: The validated arguments.
"""
# Import ConneryService here and check if it is an instance
# of ConneryService to avoid circular imports
from .service import ConneryService
if not isinstance(values.get("connery_service"), ConneryService):
raise ValueError(
"The attribute 'connery_service' must be an instance of ConneryService."
)
if not values.get("name"):
raise ValueError("The attribute 'name' must be set.")
if not values.get("description"):
raise ValueError("The attribute 'description' must be set.")
if not values.get("args_schema"):
raise ValueError("The attribute 'args_schema' must be set.")
if not values.get("action"):
raise ValueError("The attribute 'action' must be set.")
if not values.get("connery_service"):
raise ValueError("The attribute 'connery_service' must be set.")
return values
@classmethod
def create_instance(cls, action: Action, connery_service: Any) -> "ConneryAction":
"""
Creates a Connery Action Tool from a Connery Action.
Parameters:
action (Action): The Connery Action to wrap in a Connery Action Tool.
connery_service (ConneryService): The Connery Service
to run the Connery Action. We use Any here to avoid circular imports.
Returns:
ConneryAction: The Connery Action Tool.
"""
# Import ConneryService here and check if it is an instance
# of ConneryService to avoid circular imports
from .service import ConneryService
if not isinstance(connery_service, ConneryService):
raise ValueError(
"The connery_service must be an instance of ConneryService."
)
input_schema = cls._create_input_schema(action.inputParameters)
description = action.title + (
": " + action.description if action.description else ""
)
instance = cls(
name=action.id,
description=description,
args_schema=input_schema,
action=action,
connery_service=connery_service,
)
return instance
@classmethod
def _create_input_schema(cls, inputParameters: List[Parameter]) -> Type[BaseModel]:
"""
Creates an input schema for a Connery Action Tool
based on the input parameters of the Connery Action.
Parameters:
inputParameters: List of input parameters of the Connery Action.
Returns:
Type[BaseModel]: The input schema for the Connery Action Tool.
"""
dynamic_input_fields: Dict[str, Any] = {}
for param in inputParameters:
default = ... if param.validation and param.validation.required else None
title = param.title
description = param.title + (
": " + param.description if param.description else ""
)
type = param.type
dynamic_input_fields[param.key] = (
str,
Field(default, title=title, description=description, type=type),
)
InputModel = create_model("InputSchema", **dynamic_input_fields)
return InputModel

@ -0,0 +1,41 @@
"""Integration test for Connery API Wrapper."""
from langchain_community.tools.connery import ConneryService
def test_list_actions() -> None:
"""Test for listing Connery Actions."""
connery = ConneryService()
output = connery._list_actions()
assert output is not None
assert len(output) > 0
def test_get_action() -> None:
"""Test for getting Connery Action."""
connery = ConneryService()
# This is the ID of the preinstalled action "Refresh plugin cache"
output = connery._get_action("CAF979E6D2FF4C8B946EEBAFCB3BA475")
assert output is not None
assert output.id == "CAF979E6D2FF4C8B946EEBAFCB3BA475"
def test_run_action_with_no_iput() -> None:
"""Test for running Connery Action without input."""
connery = ConneryService()
# refreshPluginCache action from connery-io/connery-runner-administration plugin
output = connery._run_action("CAF979E6D2FF4C8B946EEBAFCB3BA475")
assert output is not None
assert output == {}
def test_run_action_with_iput() -> None:
"""Test for running Connery Action with input."""
connery = ConneryService()
# summarizePublicWebpage action from connery-io/summarization-plugin plugin
output = connery._run_action(
"CA72DFB0AB4DF6C830B43E14B0782F70",
{"publicWebpageUrl": "http://www.paulgraham.com/vb.html"},
)
assert output is not None
assert output["summary"] is not None
assert len(output["summary"]) > 0

@ -4,6 +4,7 @@ EXPECTED_ALL = [
"AINetworkToolkit",
"AmadeusToolkit",
"AzureCognitiveServicesToolkit",
"ConneryToolkit",
"FileManagementToolkit",
"GmailToolkit",
"JiraToolkit",

@ -24,6 +24,7 @@ EXPECTED_ALL = [
"BingSearchRun",
"BraveSearch",
"ClickTool",
"ConneryAction",
"CopyFileTool",
"CurrentWebPageTool",
"DeleteFileTool",

@ -25,6 +25,7 @@ _EXPECTED = [
"BingSearchRun",
"BraveSearch",
"ClickTool",
"ConneryAction",
"CopyFileTool",
"CurrentWebPageTool",
"DeleteFileTool",

Loading…
Cancel
Save