langroid 0.39.5__py3-none-any.whl → 0.41.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,68 @@
1
+ """
2
+ A tool to trigger a Exa search for a given query,
3
+ (https://docs.exa.ai/reference/getting-started)
4
+ and return the top results with their titles, links, summaries.
5
+ Since the tool is stateless (i.e. does not need
6
+ access to agent state), it can be enabled for any agent, without having to define a
7
+ special method inside the agent: `agent.enable_message(ExaSearchTool)`
8
+
9
+ NOTE: To use this tool, you need to:
10
+
11
+ * set the EXA_API_KEY environment variables in
12
+ your `.env` file, e.g. `EXA_API_KEY=your_api_key_here`
13
+ (Note as of 28 Jan 2023, Metaphor renamed to Exa, so you can also use
14
+ `EXA_API_KEY=your_api_key_here`)
15
+
16
+ * install langroid with the `exa-py` extra, e.g.
17
+ `pip install langroid[exa]` or `uv pip install langroid[exa]`
18
+ or `poetry add langroid[exa]` or `uv add langroid[exa]`
19
+ (it installs the `exa_py` package from pypi).
20
+
21
+ For more information, please refer to the official docs:
22
+ https://exa.ai/
23
+ """
24
+
25
+ from typing import List, Tuple
26
+
27
+ from langroid.agent.tool_message import ToolMessage
28
+ from langroid.parsing.web_search import exa_search
29
+
30
+
31
+ class ExaSearchTool(ToolMessage):
32
+ request: str = "exa_search"
33
+ purpose: str = """
34
+ To search the web and return up to <num_results>
35
+ links relevant to the given <query>. When using this tool,
36
+ ONLY show the required JSON, DO NOT SAY ANYTHING ELSE.
37
+ Wait for the results of the web search, and then use them to
38
+ compose your response.
39
+ """
40
+ query: str
41
+ num_results: int
42
+
43
+ def handle(self) -> str:
44
+ """
45
+ Conducts a search using the exa API based on the provided query
46
+ and number of results by triggering a exa_search.
47
+
48
+ Returns:
49
+ str: A formatted string containing the titles, links, and
50
+ summaries of each search result, separated by two newlines.
51
+ """
52
+
53
+ search_results = exa_search(self.query, self.num_results)
54
+ # return Title, Link, Summary of each result, separated by two newlines
55
+ results_str = "\n\n".join(str(result) for result in search_results)
56
+ return f"""
57
+ BELOW ARE THE RESULTS FROM THE WEB SEARCH. USE THESE TO COMPOSE YOUR RESPONSE:
58
+ {results_str}
59
+ """
60
+
61
+ @classmethod
62
+ def examples(cls) -> List["ToolMessage" | Tuple[str, "ToolMessage"]]:
63
+ return [
64
+ cls(
65
+ query="When was the Llama2 Large Language Model (LLM) released?",
66
+ num_results=3,
67
+ ),
68
+ ]
@@ -0,0 +1,50 @@
1
+ """
2
+ A tool to trigger a Tavily search for a given query, and return the top results with
3
+ their titles, links, summaries. Since the tool is stateless (i.e. does not need
4
+ access to agent state), it can be enabled for any agent, without having to define a
5
+ special method inside the agent: `agent.enable_message(TavilySearchTool)`
6
+ """
7
+
8
+ from typing import List, Tuple
9
+
10
+ from langroid.agent.tool_message import ToolMessage
11
+ from langroid.parsing.web_search import tavily_search
12
+
13
+
14
+ class TavilySearchTool(ToolMessage):
15
+ request: str = "tavily_search"
16
+ purpose: str = """
17
+ To search the web and return up to <num_results>
18
+ links relevant to the given <query>. When using this tool,
19
+ ONLY show the required JSON, DO NOT SAY ANYTHING ELSE.
20
+ Wait for the results of the web search, and then use them to
21
+ compose your response.
22
+ """
23
+ query: str
24
+ num_results: int
25
+
26
+ def handle(self) -> str:
27
+ """
28
+ Conducts a search using Tavily based on the provided query
29
+ and number of results by triggering a tavily_search.
30
+
31
+ Returns:
32
+ str: A formatted string containing the titles, links, and
33
+ summaries of each search result, separated by two newlines.
34
+ """
35
+ search_results = tavily_search(self.query, self.num_results)
36
+ # return Title, Link, Summary of each result, separated by two newlines
37
+ results_str = "\n\n".join(str(result) for result in search_results)
38
+ return f"""
39
+ BELOW ARE THE RESULTS FROM THE WEB SEARCH. USE THESE TO COMPOSE YOUR RESPONSE:
40
+ {results_str}
41
+ """
42
+
43
+ @classmethod
44
+ def examples(cls) -> List["ToolMessage" | Tuple[str, "ToolMessage"]]:
45
+ return [
46
+ cls(
47
+ query="When was the Llama2 Large Language Model (LLM) released?",
48
+ num_results=3,
49
+ ),
50
+ ]
@@ -118,7 +118,7 @@ def preprocess_text(text: str) -> str:
118
118
  str: The preprocessed text.
119
119
  """
120
120
  # Ensure the NLTK resources are available
121
- for resource in ["punkt", "wordnet", "stopwords"]:
121
+ for resource in ["tokenizers/punkt", "corpora/wordnet", "corpora/stopwords"]:
122
122
  download_nltk_resource(resource)
123
123
 
124
124
  # Lowercase the text
langroid/parsing/utils.py CHANGED
@@ -28,12 +28,13 @@ def download_nltk_resource(resource: str) -> None:
28
28
  try:
29
29
  nltk.data.find(resource)
30
30
  except LookupError:
31
- nltk.download(resource, quiet=True)
31
+ model = resource.split("/")[-1]
32
+ nltk.download(model, quiet=True)
32
33
 
33
34
 
34
35
  # Download punkt_tab resource at module import
35
- download_nltk_resource("punkt_tab")
36
- download_nltk_resource("gutenberg")
36
+ download_nltk_resource("tokenizers/punkt_tab")
37
+ download_nltk_resource("corpora/gutenberg")
37
38
 
38
39
  T = TypeVar("T")
39
40
 
@@ -16,6 +16,8 @@ from duckduckgo_search import DDGS
16
16
  from googleapiclient.discovery import Resource, build
17
17
  from requests.models import Response
18
18
 
19
+ from langroid.exceptions import LangroidImportError
20
+
19
21
 
20
22
  class WebSearchResult:
21
23
  """
@@ -109,13 +111,7 @@ def metaphor_search(query: str, num_results: int = 5) -> List[WebSearchResult]:
109
111
  try:
110
112
  from metaphor_python import Metaphor
111
113
  except ImportError:
112
- raise ImportError(
113
- "You are attempting to use the `metaphor_python` library;"
114
- "To use it, please install langroid with the `metaphor` extra, e.g. "
115
- "`pip install langroid[metaphor]` or `poetry add langroid[metaphor]` "
116
- "or `uv add langroid[metaphor]`"
117
- "(it installs the `metaphor_python` package from pypi)."
118
- )
114
+ raise LangroidImportError("metaphor-python", "metaphor")
119
115
 
120
116
  client = Metaphor(api_key=api_key)
121
117
 
@@ -130,6 +126,53 @@ def metaphor_search(query: str, num_results: int = 5) -> List[WebSearchResult]:
130
126
  ]
131
127
 
132
128
 
129
+ def exa_search(query: str, num_results: int = 5) -> List[WebSearchResult]:
130
+ """
131
+ Method that makes an API call by Exa client that queries
132
+ the top num_results links that matches the query. Returns a list
133
+ of WebSearchResult objects.
134
+
135
+ Args:
136
+ query (str): The query body that users wants to make.
137
+ num_results (int): Number of top matching results that we want
138
+ to grab
139
+ """
140
+
141
+ load_dotenv()
142
+
143
+ api_key = os.getenv("EXA_API_KEY")
144
+ if not api_key:
145
+ raise ValueError(
146
+ """
147
+ EXA_API_KEY environment variables are not set.
148
+ Please set one of them to your API key, and try again.
149
+ """
150
+ )
151
+
152
+ try:
153
+ from exa_py import Exa
154
+ except ImportError:
155
+ raise LangroidImportError("exa-py", "exa")
156
+
157
+ client = Exa(api_key=api_key)
158
+
159
+ response = client.search(
160
+ query=query,
161
+ num_results=num_results,
162
+ )
163
+ raw_results = response.results
164
+
165
+ return [
166
+ WebSearchResult(
167
+ title=result.title or "",
168
+ link=result.url,
169
+ max_content_length=3500,
170
+ max_summary_length=300,
171
+ )
172
+ for result in raw_results
173
+ ]
174
+
175
+
133
176
  def duckduckgo_search(query: str, num_results: int = 5) -> List[WebSearchResult]:
134
177
  """
135
178
  Method that makes an API call by DuckDuckGo client that queries
@@ -154,3 +197,44 @@ def duckduckgo_search(query: str, num_results: int = 5) -> List[WebSearchResult]
154
197
  )
155
198
  for result in search_results
156
199
  ]
200
+
201
+
202
+ def tavily_search(query: str, num_results: int = 5) -> List[WebSearchResult]:
203
+ """
204
+ Method that makes an API call to Tavily API that queries
205
+ the top `num_results` links that match the query. Returns a list
206
+ of WebSearchResult objects.
207
+
208
+ Args:
209
+ query (str): The query body that users wants to make.
210
+ num_results (int): Number of top matching results that we want
211
+ to grab
212
+ """
213
+
214
+ load_dotenv()
215
+
216
+ api_key = os.getenv("TAVILY_API_KEY")
217
+ if not api_key:
218
+ raise ValueError(
219
+ "TAVILY_API_KEY environment variable is not set. "
220
+ "Please set it to your API key and try again."
221
+ )
222
+
223
+ try:
224
+ from tavily import TavilyClient
225
+ except ImportError:
226
+ raise LangroidImportError("tavily-python", "tavily")
227
+
228
+ client = TavilyClient(api_key=api_key)
229
+ response = client.search(query=query, max_results=num_results)
230
+ search_results = response["results"]
231
+
232
+ return [
233
+ WebSearchResult(
234
+ title=result["title"],
235
+ link=result["url"],
236
+ max_content_length=3500,
237
+ max_summary_length=300,
238
+ )
239
+ for result in search_results
240
+ ]
@@ -23,11 +23,7 @@ try:
23
23
  MeiliSearch
24
24
  MeiliSearchConfig
25
25
  __all__.extend(["meilisearch", "MeiliSearch", "MeiliSearchConfig"])
26
- except ImportError:
27
- pass
28
26
 
29
-
30
- try:
31
27
  from . import lancedb
32
28
  from .lancedb import LanceDB, LanceDBConfig
33
29
 
@@ -35,10 +31,6 @@ try:
35
31
  LanceDB
36
32
  LanceDBConfig
37
33
  __all__.extend(["lancedb", "LanceDB", "LanceDBConfig"])
38
- except ImportError:
39
- pass
40
-
41
- try:
42
34
  from . import chromadb
43
35
  from .chromadb import ChromaDBConfig, ChromaDB
44
36
 
@@ -46,10 +38,15 @@ try:
46
38
  ChromaDB
47
39
  ChromaDBConfig
48
40
  __all__.extend(["chromadb", "ChromaDBConfig", "ChromaDB"])
49
- except ImportError:
50
- pass
51
41
 
52
- try:
42
+ from . import postgres
43
+ from .postgres import PostgresDB, PostgresDBConfig
44
+
45
+ postgres # silence linters
46
+ PostgresDB
47
+ PostgresDBConfig
48
+ __all__.extend(["postgres", "PostgresDB", "PostgresDBConfig"])
49
+
53
50
  from . import weaviatedb
54
51
  from .weaviatedb import WeaviateDBConfig, WeaviateDB
55
52
 
@@ -57,5 +54,13 @@ try:
57
54
  WeaviateDB
58
55
  WeaviateDBConfig
59
56
  __all__.extend(["weaviatedb", "WeaviateDB", "WeaviateDBConfig"])
57
+
58
+ from . import pineconedb
59
+ from .pineconedb import PineconeDB, PineconeDBConfig
60
+
61
+ pineconedb
62
+ PineconeDB
63
+ PineconeDBConfig
64
+ __all__.extend(["pineconedb", "PineconeDB", "PineconeDBConfig"])
60
65
  except ImportError:
61
66
  pass
@@ -59,6 +59,8 @@ class VectorStore(ABC):
59
59
  from langroid.vector_store.lancedb import LanceDB, LanceDBConfig
60
60
  from langroid.vector_store.meilisearch import MeiliSearch, MeiliSearchConfig
61
61
  from langroid.vector_store.momento import MomentoVI, MomentoVIConfig
62
+ from langroid.vector_store.pineconedb import PineconeDB, PineconeDBConfig
63
+ from langroid.vector_store.postgres import PostgresDB, PostgresDBConfig
62
64
  from langroid.vector_store.qdrantdb import QdrantDB, QdrantDBConfig
63
65
  from langroid.vector_store.weaviatedb import WeaviateDB, WeaviateDBConfig
64
66
 
@@ -72,8 +74,12 @@ class VectorStore(ABC):
72
74
  return LanceDB(config)
73
75
  elif isinstance(config, MeiliSearchConfig):
74
76
  return MeiliSearch(config)
77
+ elif isinstance(config, PostgresDBConfig):
78
+ return PostgresDB(config)
75
79
  elif isinstance(config, WeaviateDBConfig):
76
80
  return WeaviateDB(config)
81
+ elif isinstance(config, PineconeDBConfig):
82
+ return PineconeDB(config)
77
83
 
78
84
  else:
79
85
  logger.warning(