Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

community: add Salesforce tools and API wrapper #29750

Closed
wants to merge 10 commits into from
227 changes: 227 additions & 0 deletions docs/docs/integrations/tools/salesforce.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "07b8af61",
"metadata": {},
"source": [
"# Salesforce\n",
"\n",
"This notebook shows how to use the Salesforce tools in LangChain.\n",
"\n",
"The Salesforce integration provides tools for:\n",
"1. Querying Salesforce data using SOQL\n",
"2. Getting information about Salesforce objects\n",
"3. Listing available Salesforce objects\n",
"\n",
"## Installation\n",
"\n",
"First, you need to install the `simple-salesforce` package:\n",
"\n",
"```bash\n",
"pip install simple-salesforce\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "72ec2685",
"metadata": {},
"outputs": [],
"source": [
"from simple_salesforce import Salesforce\n",
"from langchain_community.tools.salesforce import (\n",
" QuerySalesforceTool,\n",
" InfoSalesforceTool,\n",
" ListSalesforceTool\n",
")"
]
},
{
"cell_type": "markdown",
"id": "8c8d1845",
"metadata": {},
"source": [
"## Setup\n",
"\n",
"You can initialize the Salesforce tools in two ways:\n",
"\n",
"1. Using direct credentials\n",
"2. Using an existing Salesforce instance\n",
"\n",
"### Option 1: Using Direct Credentials"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6b979320",
"metadata": {},
"outputs": [],
"source": [
"# Initialize Salesforce with credentials\n",
"sf = Salesforce(\n",
" username='your_username',\n",
" password='your_password',\n",
" security_token='your_token',\n",
" domain='test' # Use 'test' for sandbox, remove for production\n",
")\n",
"\n",
"# Create tools\n",
"tools = [\n",
" QuerySalesforceTool(sfdc_instance=sf),\n",
" InfoSalesforceTool(sfdc_instance=sf),\n",
" ListSalesforceTool(sfdc_instance=sf)\n",
"]"
]
},
{
"cell_type": "markdown",
"id": "33a07a24",
"metadata": {},
"source": [
"## Using the Tools\n",
"\n",
"### 1. List Available Objects"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4390be44",
"metadata": {},
"outputs": [],
"source": [
"# List all queryable objects in your Salesforce instance\n",
"result = list_tool.run(\"\")\n",
"print(result)"
]
},
{
"cell_type": "markdown",
"id": "0e260339",
"metadata": {},
"source": [
"### 2. Get Object Information"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "802f9662",
"metadata": {},
"outputs": [],
"source": [
"# Get information about specific objects\n",
"result = info_tool.run(\"Account,Contact\")\n",
"print(result)"
]
},
{
"cell_type": "markdown",
"id": "80bd9c66",
"metadata": {},
"source": [
"### 3. Query Salesforce Data"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a3f43b83",
"metadata": {},
"outputs": [],
"source": [
"# Execute a SOQL query\n",
"query = \"SELECT Id, Name, Industry FROM Account LIMIT 5\"\n",
"result = query_tool.run(query)\n",
"print(result)"
]
},
{
"cell_type": "markdown",
"id": "1eef235d",
"metadata": {},
"source": [
"## Using with an Agent\n",
"\n",
"The Salesforce tools can be used with LangChain agents to enable natural language interactions with your Salesforce data:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0b35fe3c",
"metadata": {},
"outputs": [],
"source": [
"from langchain_core.prompts import ChatPromptTemplate\n",
"from langchain_openai import ChatOpenAI\n",
"from langchain.agents import create_openai_functions_agent\n",
"from langchain.agents import AgentExecutor\n",
"\n",
"# Initialize the language model\n",
"llm = ChatOpenAI(temperature=0)\n",
"\n",
"# Create a prompt template\n",
"prompt = ChatPromptTemplate.from_messages([\n",
" (\"system\", \"You are a helpful assistant that can query Salesforce data. \"\n",
" \"Use the available tools to help answer questions about Salesforce data.\"),\n",
" (\"user\", \"{input}\")\n",
"])\n",
"\n",
"# Create the agent\n",
"agent = create_openai_functions_agent(llm, tools, prompt)\n",
"agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "46c907e3",
"metadata": {},
"outputs": [],
"source": [
"# Example: Ask the agent to get information about accounts\n",
"result = agent_executor.invoke(\n",
" {\"input\": \"What are the top 5 accounts by revenue?\"}\n",
")\n",
"print(result[\"output\"])"
]
},
{
"cell_type": "markdown",
"id": "b5243741",
"metadata": {},
"source": [
"## Error Handling\n",
"\n",
"The tools are designed to handle errors gracefully:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6c4bcb65",
"metadata": {},
"outputs": [],
"source": [
"# Example: Invalid SOQL query\n",
"result = query_tool.run(\"SELECT Invalid FROM Account\")\n",
"print(result)\n",
"\n",
"# Example: Invalid object name\n",
"result = info_tool.run(\"InvalidObject\")\n",
"print(result)"
]
}
],
"metadata": {
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
15 changes: 15 additions & 0 deletions libs/community/langchain_community/tools/salesforce/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""Salesforce API toolkit."""

from langchain_community.tools.salesforce.tool import (
BaseSalesforceTool,
InfoSalesforceTool,
ListSalesforceTool,
QuerySalesforceTool,
)

__all__ = [
"BaseSalesforceTool",
"InfoSalesforceTool",
"ListSalesforceTool",
"QuerySalesforceTool",
]
97 changes: 97 additions & 0 deletions libs/community/langchain_community/tools/salesforce/tool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
"""Tools for interacting with Salesforce."""

from typing import Optional, Type

from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field
from simple_salesforce import Salesforce

from langchain_community.utilities.salesforce import SalesforceAPIWrapper


class BaseSalesforceTool(BaseTool):
"""Base tool for interacting with Salesforce."""

sfdc_instance: Salesforce = Field(exclude=True)

@property
def api_wrapper(self) -> SalesforceAPIWrapper:
"""Get the API wrapper."""
return SalesforceAPIWrapper(self.sfdc_instance)


class QuerySalesforceInput(BaseModel):
"""Input for Salesforce queries."""

query: str = Field(..., description="The SOQL query to execute against Salesforce")


class QuerySalesforceTool(BaseSalesforceTool):
"""Tool for querying Salesforce using SOQL."""

name: str = "salesforce_query"
description: str = (
"Execute a SOQL query against Salesforce. "
"If the query is not correct, an error message will be returned. "
"If an error is returned, rewrite the query, check the query, and try again."
)
args_schema: Type[BaseModel] = QuerySalesforceInput

def _run(
self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None
) -> str:
"""Execute the Salesforce query."""
result = self.api_wrapper.run_no_throw(query)
if isinstance(result, dict):
return str(result)
return result


class InfoSalesforceInput(BaseModel):
"""Input for getting Salesforce object info."""

object_names: str = Field(
...,
description="Comma-separated list of Salesforce object names to get info about",
)


class InfoSalesforceTool(BaseSalesforceTool):
"""Tool for getting metadata about Salesforce objects."""

name: str = "salesforce_object_info"
description: str = (
"Get information about one or more Salesforce objects. "
"Input should be a comma-separated list of object names. "
"Example: 'Account,Contact,Opportunity'"
)
args_schema: Type[BaseModel] = InfoSalesforceInput

def _run(
self, object_names: str, run_manager: Optional[CallbackManagerForToolRun] = None
) -> str:
"""Get the schema for tables in a comma-separated list."""
object_list = [name.strip() for name in object_names.split(",")]
return self.api_wrapper.get_object_info_no_throw(object_list)


class ListSalesforceTool(BaseSalesforceTool):
"""Tool for listing available Salesforce objects."""

name: str = "salesforce_list_objects"
description: str = (
"Get a list of available objects in your Salesforce instance. "
"Input should be an empty string."
)

def _run(
self,
tool_input: str = "",
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Get a comma-separated list of Salesforce object names."""
try:
return ", ".join(self.api_wrapper.get_usable_object_names())
except Exception as e:
return f"Error: {str(e)}"
9 changes: 9 additions & 0 deletions libs/community/langchain_community/utilities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,171 +8,174 @@
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from langchain_community.utilities.alpha_vantage import (
AlphaVantageAPIWrapper,
)
from langchain_community.utilities.apify import (
ApifyWrapper,
)
from langchain_community.utilities.arcee import (
ArceeWrapper,
)
from langchain_community.utilities.arxiv import (
ArxivAPIWrapper,
)
from langchain_community.utilities.asknews import (
AskNewsAPIWrapper,
)
from langchain_community.utilities.awslambda import (
LambdaWrapper,
)
from langchain_community.utilities.bibtex import (
BibtexparserWrapper,
)
from langchain_community.utilities.bing_search import (
BingSearchAPIWrapper,
)
from langchain_community.utilities.brave_search import (
BraveSearchWrapper,
)
from langchain_community.utilities.dataherald import DataheraldAPIWrapper
from langchain_community.utilities.dria_index import (
DriaAPIWrapper,
)
from langchain_community.utilities.duckduckgo_search import (
DuckDuckGoSearchAPIWrapper,
)
from langchain_community.utilities.golden_query import (
GoldenQueryAPIWrapper,
)
from langchain_community.utilities.google_books import (
GoogleBooksAPIWrapper,
)
from langchain_community.utilities.google_finance import (
GoogleFinanceAPIWrapper,
)
from langchain_community.utilities.google_jobs import (
GoogleJobsAPIWrapper,
)
from langchain_community.utilities.google_lens import (
GoogleLensAPIWrapper,
)
from langchain_community.utilities.google_places_api import (
GooglePlacesAPIWrapper,
)
from langchain_community.utilities.google_scholar import (
GoogleScholarAPIWrapper,
)
from langchain_community.utilities.google_search import (
GoogleSearchAPIWrapper,
)
from langchain_community.utilities.google_serper import (
GoogleSerperAPIWrapper,
)
from langchain_community.utilities.google_trends import (
GoogleTrendsAPIWrapper,
)
from langchain_community.utilities.graphql import (
GraphQLAPIWrapper,
)
from langchain_community.utilities.infobip import (
InfobipAPIWrapper,
)
from langchain_community.utilities.jira import (
JiraAPIWrapper,
)
from langchain_community.utilities.max_compute import (
MaxComputeAPIWrapper,
)
from langchain_community.utilities.merriam_webster import (
MerriamWebsterAPIWrapper,
)
from langchain_community.utilities.metaphor_search import (
MetaphorSearchAPIWrapper,
)
from langchain_community.utilities.mojeek_search import (
MojeekSearchAPIWrapper,
)
from langchain_community.utilities.nasa import (
NasaAPIWrapper,
)
from langchain_community.utilities.nvidia_riva import (
AudioStream,
NVIDIARivaASR,
NVIDIARivaStream,
NVIDIARivaTTS,
RivaASR,
RivaTTS,
)
from langchain_community.utilities.openweathermap import (
OpenWeatherMapAPIWrapper,
)
from langchain_community.utilities.oracleai import (
OracleSummary,
)
from langchain_community.utilities.outline import (
OutlineAPIWrapper,
)
from langchain_community.utilities.passio_nutrition_ai import (
NutritionAIAPI,
)
from langchain_community.utilities.portkey import (
Portkey,
)
from langchain_community.utilities.powerbi import (
PowerBIDataset,
)
from langchain_community.utilities.pubmed import (
PubMedAPIWrapper,
)
from langchain_community.utilities.rememberizer import RememberizerAPIWrapper
from langchain_community.utilities.requests import (
Requests,
RequestsWrapper,
TextRequestsWrapper,
)
from langchain_community.utilities.scenexplain import (
SceneXplainAPIWrapper,
)
from langchain_community.utilities.searchapi import (
SearchApiAPIWrapper,
)
from langchain_community.utilities.searx_search import (
SearxSearchWrapper,
)
from langchain_community.utilities.serpapi import (
SerpAPIWrapper,
)
from langchain_community.utilities.spark_sql import (
SparkSQL,
)
from langchain_community.utilities.sql_database import (
SQLDatabase,
)
from langchain_community.utilities.stackexchange import (
StackExchangeAPIWrapper,
)
from langchain_community.utilities.steam import (
SteamWebAPIWrapper,
)
from langchain_community.utilities.tensorflow_datasets import (
TensorflowDatasets,
)
from langchain_community.utilities.twilio import (
TwilioAPIWrapper,
)
from langchain_community.utilities.wikipedia import (
WikipediaAPIWrapper,
)
from langchain_community.utilities.wolfram_alpha import (
WolframAlphaAPIWrapper,
)
from langchain_community.utilities.you import (
YouSearchAPIWrapper,
)
from langchain_community.utilities.zapier import (
ZapierNLAWrapper,
)
from langchain_community.utilities.salesforce import (
SalesforceAPIWrapper,
)

Check failure on line 178 in libs/community/langchain_community/utilities/__init__.py

View workflow job for this annotation

GitHub Actions / cd libs/community / make lint #3.13

Ruff (I001)

langchain_community/utilities/__init__.py:11:5: I001 Import block is un-sorted or un-formatted

Check failure on line 178 in libs/community/langchain_community/utilities/__init__.py

View workflow job for this annotation

GitHub Actions / cd libs/community / make lint #3.9

Ruff (I001)

langchain_community/utilities/__init__.py:11:5: I001 Import block is un-sorted or un-formatted

__all__ = [
"AlphaVantageAPIWrapper",
Expand Down Expand Up @@ -236,6 +239,7 @@
"WolframAlphaAPIWrapper",
"YouSearchAPIWrapper",
"ZapierNLAWrapper",
"SalesforceAPIWrapper",
]

_module_lookup = {
Expand Down Expand Up @@ -300,6 +304,7 @@
"WolframAlphaAPIWrapper": "langchain_community.utilities.wolfram_alpha",
"YouSearchAPIWrapper": "langchain_community.utilities.you",
"ZapierNLAWrapper": "langchain_community.utilities.zapier",
"SalesforceAPIWrapper": "langchain_community.utilities.salesforce",
}

REMOVED = {
Expand All @@ -320,4 +325,8 @@
if name in _module_lookup:
module = importlib.import_module(_module_lookup[name])
return getattr(module, name)
if name == "SalesforceAPIWrapper":
from langchain_community.utilities.salesforce import SalesforceAPIWrapper

return SalesforceAPIWrapper
raise AttributeError(f"module {__name__} has no attribute {name}")
Loading
Loading