langroid 0.1.39__tar.gz → 0.1.41__tar.gz

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.
Files changed (76) hide show
  1. {langroid-0.1.39 → langroid-0.1.41}/PKG-INFO +25 -11
  2. {langroid-0.1.39 → langroid-0.1.41}/README.md +23 -10
  3. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/base.py +2 -1
  4. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/special/doc_chat_agent.py +40 -10
  5. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/special/retriever_agent.py +2 -2
  6. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/special/sql_chat_agent.py +3 -3
  7. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/special/table_chat_agent.py +63 -7
  8. langroid-0.1.41/langroid/agent/stateless_tools/google_search_tool.py +28 -0
  9. {langroid-0.1.39 → langroid-0.1.41}/langroid/language_models/openai_gpt.py +3 -3
  10. langroid-0.1.39/langroid/agent/stateless_tools/google_search_tool.py → langroid-0.1.41/langroid/parsing/web_search.py +22 -29
  11. {langroid-0.1.39 → langroid-0.1.41}/pyproject.toml +2 -1
  12. langroid-0.1.41/setup.py +94 -0
  13. langroid-0.1.39/setup.py +0 -93
  14. {langroid-0.1.39 → langroid-0.1.41}/LICENSE +0 -0
  15. {langroid-0.1.39 → langroid-0.1.41}/langroid/__init__.py +0 -0
  16. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/__init__.py +0 -0
  17. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/chat_agent.py +0 -0
  18. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/chat_document.py +0 -0
  19. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/helpers.py +0 -0
  20. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/junk +0 -0
  21. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/special/__init__.py +0 -0
  22. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/special/recipient_validator_agent.py +0 -0
  23. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/stateless_tools/__init__.py +0 -0
  24. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/task.py +0 -0
  25. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent/tool_message.py +0 -0
  26. {langroid-0.1.39 → langroid-0.1.41}/langroid/agent_config.py +0 -0
  27. {langroid-0.1.39 → langroid-0.1.41}/langroid/cachedb/__init__.py +0 -0
  28. {langroid-0.1.39 → langroid-0.1.41}/langroid/cachedb/base.py +0 -0
  29. {langroid-0.1.39 → langroid-0.1.41}/langroid/cachedb/momento_cachedb.py +0 -0
  30. {langroid-0.1.39 → langroid-0.1.41}/langroid/cachedb/redis_cachedb.py +0 -0
  31. {langroid-0.1.39 → langroid-0.1.41}/langroid/embedding_models/__init__.py +0 -0
  32. {langroid-0.1.39 → langroid-0.1.41}/langroid/embedding_models/base.py +0 -0
  33. {langroid-0.1.39 → langroid-0.1.41}/langroid/embedding_models/clustering.py +0 -0
  34. {langroid-0.1.39 → langroid-0.1.41}/langroid/embedding_models/models.py +0 -0
  35. {langroid-0.1.39 → langroid-0.1.41}/langroid/language_models/__init__.py +0 -0
  36. {langroid-0.1.39 → langroid-0.1.41}/langroid/language_models/base.py +0 -0
  37. {langroid-0.1.39 → langroid-0.1.41}/langroid/language_models/utils.py +0 -0
  38. {langroid-0.1.39 → langroid-0.1.41}/langroid/mytypes.py +0 -0
  39. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/__init__.py +0 -0
  40. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/agent_chats.py +0 -0
  41. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/code-parsing.md +0 -0
  42. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/code_parser.py +0 -0
  43. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/json.py +0 -0
  44. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/para_sentence_split.py +0 -0
  45. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/parser.py +0 -0
  46. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/pdf_parser.py +0 -0
  47. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/repo_loader.py +0 -0
  48. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/table_loader.py +0 -0
  49. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/url_loader.py +0 -0
  50. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/url_loader_cookies.py +0 -0
  51. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/urls.py +0 -0
  52. {langroid-0.1.39 → langroid-0.1.41}/langroid/parsing/utils.py +0 -0
  53. {langroid-0.1.39 → langroid-0.1.41}/langroid/prompts/__init__.py +0 -0
  54. {langroid-0.1.39 → langroid-0.1.41}/langroid/prompts/dialog.py +0 -0
  55. {langroid-0.1.39 → langroid-0.1.41}/langroid/prompts/prompts_config.py +0 -0
  56. {langroid-0.1.39 → langroid-0.1.41}/langroid/prompts/templates.py +0 -0
  57. {langroid-0.1.39 → langroid-0.1.41}/langroid/prompts/transforms.py +0 -0
  58. {langroid-0.1.39 → langroid-0.1.41}/langroid/scripts/__init__.py +0 -0
  59. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/__init__.py +0 -0
  60. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/configuration.py +0 -0
  61. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/constants.py +0 -0
  62. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/docker.py +0 -0
  63. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/llms/__init__.py +0 -0
  64. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/llms/strings.py +0 -0
  65. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/logging.py +0 -0
  66. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/output/__init__.py +0 -0
  67. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/output/printing.py +0 -0
  68. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/system.py +0 -0
  69. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/web/__init__.py +0 -0
  70. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/web/login.py +0 -0
  71. {langroid-0.1.39 → langroid-0.1.41}/langroid/utils/web/selenium_login.py +0 -0
  72. {langroid-0.1.39 → langroid-0.1.41}/langroid/vector_store/__init__.py +0 -0
  73. {langroid-0.1.39 → langroid-0.1.41}/langroid/vector_store/base.py +0 -0
  74. {langroid-0.1.39 → langroid-0.1.41}/langroid/vector_store/chromadb.py +0 -0
  75. {langroid-0.1.39 → langroid-0.1.41}/langroid/vector_store/qdrant_cloud.py +0 -0
  76. {langroid-0.1.39 → langroid-0.1.41}/langroid/vector_store/qdrantdb.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langroid
3
- Version: 0.1.39
3
+ Version: 0.1.41
4
4
  Summary: Harness LLMs with Multi-Agent Programming
5
5
  License: MIT
6
6
  Author: Prasad Chalasani
@@ -39,6 +39,7 @@ Requires-Dist: openai (>=0.27.5,<0.28.0)
39
39
  Requires-Dist: pandas (>=2.0.3,<3.0.0)
40
40
  Requires-Dist: pre-commit (>=3.3.2,<4.0.0)
41
41
  Requires-Dist: prettytable (>=3.8.0,<4.0.0)
42
+ Requires-Dist: psycopg2 (>=2.9.7,<3.0.0)
42
43
  Requires-Dist: pydantic (==1.10.11)
43
44
  Requires-Dist: pygithub (>=1.58.1,<2.0.0)
44
45
  Requires-Dist: pygments (>=2.15.1,<3.0.0)
@@ -77,6 +78,8 @@ Description-Content-Type: text/markdown
77
78
  [![Static Badge](https://img.shields.io/badge/Discord-orange?logoColor=orange&link=https%3A%2F%2Fdiscord.gg%2FZU36McDgDs)](https://discord.gg/ZU36McDgDs)
78
79
  [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langroid/langroid/blob/main/examples/langroid_quick_examples.ipynb)
79
80
 
81
+ [![Share on Twitter](https://img.shields.io/twitter/url?style=social&url=https://github.com/langroid/langroid)](https://twitter.com/intent/tweet?text=Langroid%20is%20a%20powerful,%20elegant%20new%20framework%20to%20easily%20build%20%23LLM%20applications.%20You%20set%20up%20LLM-powered%20Agents%20with%20vector-stores,%20assign%20tasks,%20and%20have%20them%20collaboratively%20solve%20problems%20via%20message-transformations.%20https://github.com/langroid/langroid)
82
+ [![Share on LinkedIn](https://img.shields.io/badge/Share%20on-LinkedIn-blue)](https://www.linkedin.com/shareArticle?mini=true&url=https://github.com/langroid/langroid&title=Langroid:%20A%20Powerful,%20Elegant%20Framework&summary=Langroid%20is%20a%20powerful,%20elegant%20new%20framework%20to%20easily%20build%20%23LLM%20applications.%20You%20set%20up%20LLM-powered%20Agents%20with%20vector-stores,%20assign%20tasks,%20and%20have%20them%20collaboratively%20solve%20problems%20via%20message-transformations.)
80
83
 
81
84
  </div>
82
85
 
@@ -114,7 +117,8 @@ for ideas on what to contribute.
114
117
  <summary> <b>:fire: Updates/Releases</b></summary>
115
118
 
116
119
  - **Aug 2023:**
117
- - **0.1.38:** [`GoogleSearchTool`](langroid/agent/stateless_tools/google_search_tool.py) to enable Agents (their LLM) to do Google searches via function-calling/tools.
120
+ - **Example:** [Answer questions](examples/docqa/chat-search.py) using Google Search + vecdb-retrieval from URL contents.
121
+ - **0.1.39:** [`GoogleSearchTool`](langroid/agent/stateless_tools/google_search_tool.py) to enable Agents (their LLM) to do Google searches via function-calling/tools.
118
122
  See [this chat example](examples/basic/chat-search.py) for how easy it is to add this tool to an agent.
119
123
  - **Colab notebook** to try the quick-start examples: [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langroid/langroid/blob/main/examples/langroid_quick_examples.ipynb)
120
124
  - **0.1.37:** Added [`SQLChatAgent`](langroid/agent/special/sql_chat_agent.py) -- thanks to our latest contributor [Rithwik Babu](https://github.com/rithwikbabu)!
@@ -232,7 +236,8 @@ export OPENAI_API_KEY=your-key-here-without-quotes
232
236
  <details>
233
237
  <summary><b>Optional Setup Instructions (click to expand) </b></summary>
234
238
 
235
- All of the below are optional and not strictly needed to run any of the examples.
239
+ All of the following environment variable settings are optional, and some are only needed
240
+ to use specific features (as noted below).
236
241
 
237
242
  - **Qdrant** Vector Store API Key, URL. This is only required if you want to use Qdrant cloud.
238
243
  You can sign up for a free 1GB account at [Qdrant cloud](https://cloud.qdrant.io).
@@ -357,8 +362,6 @@ task.run() # ... a loop seeking response from LLM or User at each turn
357
362
  <details>
358
363
  <summary><b> Three communicating agents </b></summary>
359
364
 
360
- ```python
361
-
362
365
  A toy numbers game, where when given a number `n`:
363
366
  - `repeater_agent`'s LLM simply returns `n`,
364
367
  - `even_agent`'s LLM returns `n/2` if `n` is even, else says "DO-NOT-KNOW"
@@ -663,13 +666,24 @@ script in the `langroid-examples` repo.
663
666
 
664
667
  # :heart: Thank you to our [supporters](https://github.com/langroid/langroid/stargazers)
665
668
 
666
- If you like this repo, don't forget to leave a star :star: !
669
+ If you like this project, please give it a star ⭐ and 📢 spread the word in your network:
670
+
671
+ [![Share on Twitter](https://img.shields.io/twitter/url?style=social&url=https://github.com/langroid/langroid)](https://twitter.com/intent/tweet?text=Langroid%20is%20a%20powerful,%20elegant%20new%20framework%20to%20easily%20build%20%23LLM%20applications.%20You%20set%20up%20LLM-powered%20Agents%20with%20vector-stores,%20assign%20tasks,%20and%20have%20them%20collaboratively%20solve%20problems%20via%20message-transformations.%20https://github.com/langroid/langroid)
672
+ [![Share on LinkedIn](https://img.shields.io/badge/Share%20on-LinkedIn-blue)](https://www.linkedin.com/shareArticle?mini=true&url=https://github.com/langroid/langroid&title=Langroid:%20A%20Powerful,%20Elegant%20Framework&summary=Langroid%20is%20a%20powerful,%20elegant%20new%20framework%20to%20easily%20build%20%23LLM%20applications.%20You%20set%20up%20LLM-powered%20Agents%20with%20vector-stores,%20assign%20tasks,%20and%20have%20them%20collaboratively%20solve%20problems%20via%20message-transformations.)
673
+
674
+
675
+
676
+
677
+ Your support will help build Langroid's momentum and community.
678
+
679
+
680
+
681
+
682
+ # Langroid Co-Founders
683
+
684
+ - [Prasad Chalasani](https://www.linkedin.com/in/pchalasani/) (IIT BTech/CS, CMU PhD/ML; Independent ML Consultant)
685
+ - [Somesh Jha](https://www.linkedin.com/in/somesh-jha-80208015/) (IIT BTech/CS, CMU PhD/CS; Professor of CS, U Wisc at Madison)
667
686
 
668
- # Contributors
669
687
 
670
- - Prasad Chalasani (IIT BTech/CS, CMU PhD/ML; Independent ML Consultant)
671
- - Somesh Jha (IIT BTech/CS, CMU PhD/CS; Professor of CS, U Wisc at Madison)
672
- - Mohannad Alhanahnah (Research Associate, U Wisc at Madison)
673
- - Ashish Hooda (IIT BTech/CS; PhD Candidate, U Wisc at Madison)
674
688
 
675
689
 
@@ -13,6 +13,8 @@
13
13
  [![Static Badge](https://img.shields.io/badge/Discord-orange?logoColor=orange&link=https%3A%2F%2Fdiscord.gg%2FZU36McDgDs)](https://discord.gg/ZU36McDgDs)
14
14
  [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langroid/langroid/blob/main/examples/langroid_quick_examples.ipynb)
15
15
 
16
+ [![Share on Twitter](https://img.shields.io/twitter/url?style=social&url=https://github.com/langroid/langroid)](https://twitter.com/intent/tweet?text=Langroid%20is%20a%20powerful,%20elegant%20new%20framework%20to%20easily%20build%20%23LLM%20applications.%20You%20set%20up%20LLM-powered%20Agents%20with%20vector-stores,%20assign%20tasks,%20and%20have%20them%20collaboratively%20solve%20problems%20via%20message-transformations.%20https://github.com/langroid/langroid)
17
+ [![Share on LinkedIn](https://img.shields.io/badge/Share%20on-LinkedIn-blue)](https://www.linkedin.com/shareArticle?mini=true&url=https://github.com/langroid/langroid&title=Langroid:%20A%20Powerful,%20Elegant%20Framework&summary=Langroid%20is%20a%20powerful,%20elegant%20new%20framework%20to%20easily%20build%20%23LLM%20applications.%20You%20set%20up%20LLM-powered%20Agents%20with%20vector-stores,%20assign%20tasks,%20and%20have%20them%20collaboratively%20solve%20problems%20via%20message-transformations.)
16
18
 
17
19
  </div>
18
20
 
@@ -50,7 +52,8 @@ for ideas on what to contribute.
50
52
  <summary> <b>:fire: Updates/Releases</b></summary>
51
53
 
52
54
  - **Aug 2023:**
53
- - **0.1.38:** [`GoogleSearchTool`](langroid/agent/stateless_tools/google_search_tool.py) to enable Agents (their LLM) to do Google searches via function-calling/tools.
55
+ - **Example:** [Answer questions](examples/docqa/chat-search.py) using Google Search + vecdb-retrieval from URL contents.
56
+ - **0.1.39:** [`GoogleSearchTool`](langroid/agent/stateless_tools/google_search_tool.py) to enable Agents (their LLM) to do Google searches via function-calling/tools.
54
57
  See [this chat example](examples/basic/chat-search.py) for how easy it is to add this tool to an agent.
55
58
  - **Colab notebook** to try the quick-start examples: [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langroid/langroid/blob/main/examples/langroid_quick_examples.ipynb)
56
59
  - **0.1.37:** Added [`SQLChatAgent`](langroid/agent/special/sql_chat_agent.py) -- thanks to our latest contributor [Rithwik Babu](https://github.com/rithwikbabu)!
@@ -168,7 +171,8 @@ export OPENAI_API_KEY=your-key-here-without-quotes
168
171
  <details>
169
172
  <summary><b>Optional Setup Instructions (click to expand) </b></summary>
170
173
 
171
- All of the below are optional and not strictly needed to run any of the examples.
174
+ All of the following environment variable settings are optional, and some are only needed
175
+ to use specific features (as noted below).
172
176
 
173
177
  - **Qdrant** Vector Store API Key, URL. This is only required if you want to use Qdrant cloud.
174
178
  You can sign up for a free 1GB account at [Qdrant cloud](https://cloud.qdrant.io).
@@ -293,8 +297,6 @@ task.run() # ... a loop seeking response from LLM or User at each turn
293
297
  <details>
294
298
  <summary><b> Three communicating agents </b></summary>
295
299
 
296
- ```python
297
-
298
300
  A toy numbers game, where when given a number `n`:
299
301
  - `repeater_agent`'s LLM simply returns `n`,
300
302
  - `even_agent`'s LLM returns `n/2` if `n` is even, else says "DO-NOT-KNOW"
@@ -599,12 +601,23 @@ script in the `langroid-examples` repo.
599
601
 
600
602
  # :heart: Thank you to our [supporters](https://github.com/langroid/langroid/stargazers)
601
603
 
602
- If you like this repo, don't forget to leave a star :star: !
604
+ If you like this project, please give it a star ⭐ and 📢 spread the word in your network:
605
+
606
+ [![Share on Twitter](https://img.shields.io/twitter/url?style=social&url=https://github.com/langroid/langroid)](https://twitter.com/intent/tweet?text=Langroid%20is%20a%20powerful,%20elegant%20new%20framework%20to%20easily%20build%20%23LLM%20applications.%20You%20set%20up%20LLM-powered%20Agents%20with%20vector-stores,%20assign%20tasks,%20and%20have%20them%20collaboratively%20solve%20problems%20via%20message-transformations.%20https://github.com/langroid/langroid)
607
+ [![Share on LinkedIn](https://img.shields.io/badge/Share%20on-LinkedIn-blue)](https://www.linkedin.com/shareArticle?mini=true&url=https://github.com/langroid/langroid&title=Langroid:%20A%20Powerful,%20Elegant%20Framework&summary=Langroid%20is%20a%20powerful,%20elegant%20new%20framework%20to%20easily%20build%20%23LLM%20applications.%20You%20set%20up%20LLM-powered%20Agents%20with%20vector-stores,%20assign%20tasks,%20and%20have%20them%20collaboratively%20solve%20problems%20via%20message-transformations.)
608
+
609
+
610
+
611
+
612
+ Your support will help build Langroid's momentum and community.
613
+
614
+
615
+
616
+
617
+ # Langroid Co-Founders
618
+
619
+ - [Prasad Chalasani](https://www.linkedin.com/in/pchalasani/) (IIT BTech/CS, CMU PhD/ML; Independent ML Consultant)
620
+ - [Somesh Jha](https://www.linkedin.com/in/somesh-jha-80208015/) (IIT BTech/CS, CMU PhD/CS; Professor of CS, U Wisc at Madison)
603
621
 
604
- # Contributors
605
622
 
606
- - Prasad Chalasani (IIT BTech/CS, CMU PhD/ML; Independent ML Consultant)
607
- - Somesh Jha (IIT BTech/CS, CMU PhD/CS; Professor of CS, U Wisc at Madison)
608
- - Mohannad Alhanahnah (Research Associate, U Wisc at Madison)
609
- - Ashish Hooda (IIT BTech/CS; PhD Candidate, U Wisc at Madison)
610
623
 
@@ -128,9 +128,10 @@ class Agent(ABC):
128
128
  raise ValueError("message_class must be a subclass of ToolMessage")
129
129
  tool = message_class.default_value("request")
130
130
  self.llm_tools_map[tool] = message_class
131
- if hasattr(message_class, "handle"):
131
+ if hasattr(message_class, "handle") and not hasattr(self, tool):
132
132
  """
133
133
  If the message class has a `handle` method,
134
+ and does NOT have a method with the same name as the tool,
134
135
  then we create a method for the agent whose name
135
136
  is the value of `tool`, and whose body is the `handle` method.
136
137
  This removes a separate step of having to define this method
@@ -304,14 +304,21 @@ class DocChatAgent(ChatAgent):
304
304
  )
305
305
 
306
306
  @no_type_check
307
- def answer_from_docs(self, query: str) -> Document:
308
- """Answer query based on docs in vecdb, and conv history"""
309
- response = Document(
310
- content=NO_ANSWER,
311
- metadata=DocMetaData(
312
- source="None",
313
- ),
314
- )
307
+ def get_relevant_extracts(self, query: str) -> List[Document]:
308
+ """
309
+ Get list of docs or extracts relevant to a query. These could be:
310
+ - the original docs, if they exist and are not too long, or
311
+ - a list of doc-chunks retrieved from the VecDB
312
+ that are "relevant" to the query, if these are not too long, or
313
+ - a list of relevant extracts from these doc-chunks
314
+
315
+ Args:
316
+ query (str): query to search for
317
+
318
+ Returns:
319
+ List[Document]: list of relevant docs
320
+
321
+ """
315
322
  if len(self.dialog) > 0 and not self.config.conversation_mode:
316
323
  # In conversation mode, we let self.message_history accumulate
317
324
  # and do not need to convert to standalone query
@@ -324,7 +331,7 @@ class DocChatAgent(ChatAgent):
324
331
 
325
332
  passages = self.original_docs
326
333
 
327
- # if original docs too long, no need to look for relevant parts.
334
+ # if original docs not too long, no need to look for relevant parts.
328
335
  if (
329
336
  passages is None
330
337
  or self.original_docs_length > self.config.max_context_tokens
@@ -335,7 +342,7 @@ class DocChatAgent(ChatAgent):
335
342
  k=self.config.parsing.n_similar_docs,
336
343
  )
337
344
  if len(docs_and_scores) == 0:
338
- return response
345
+ return []
339
346
  passages = [
340
347
  Document(content=d.content, metadata=d.metadata)
341
348
  for (d, _) in docs_and_scores
@@ -347,6 +354,29 @@ class DocChatAgent(ChatAgent):
347
354
  with console.status("[cyan]LLM Extracting verbatim passages..."):
348
355
  with StreamingIfAllowed(self.llm, False):
349
356
  extracts = self.llm.get_verbatim_extracts(query, passages)
357
+
358
+ return extracts
359
+
360
+ @no_type_check
361
+ def answer_from_docs(self, query: str) -> Document:
362
+ """
363
+ Answer query based on relevant docs from the VecDB
364
+
365
+ Args:
366
+ query (str): query to answer
367
+
368
+ Returns:
369
+ Document: answer
370
+ """
371
+ response = Document(
372
+ content=NO_ANSWER,
373
+ metadata=DocMetaData(
374
+ source="None",
375
+ ),
376
+ )
377
+ extracts = self.get_relevant_extracts(query)
378
+ if len(extracts) == 0:
379
+ return response
350
380
  with ExitStack() as stack:
351
381
  # conditionally use Streaming or rich console context
352
382
  cm = (
@@ -97,7 +97,7 @@ class RetrieverAgent(DocChatAgent, ABC):
97
97
  query_str = query.content
98
98
  else:
99
99
  query_str = query
100
- docs = self.get_relevant_docs(query_str)
100
+ docs = self.get_relevant_extracts(query_str)
101
101
  if len(docs) == 0:
102
102
  return None
103
103
  content = "\n\n".join([d.content for d in docs])
@@ -135,7 +135,7 @@ class RetrieverAgent(DocChatAgent, ABC):
135
135
  ]
136
136
  return docs
137
137
 
138
- def get_relevant_docs(self, query: str) -> List[Document]:
138
+ def get_relevant_extracts(self, query: str) -> List[Document]:
139
139
  """
140
140
  Given a query, get the records/docs whose contents are most relevant to the
141
141
  query. First get nearest docs from vector store, then select the best
@@ -28,9 +28,9 @@ console = Console()
28
28
 
29
29
  DEFAULT_SQL_CHAT_SYSTEM_MESSAGE = """
30
30
  You are a savvy data scientist/database administrator, with expertise in
31
- answering questions by querying a SQL database.
31
+ answering questions by querying a {dialect} database.
32
32
  You do not have access to the database 'db' directly, so you will need to use the
33
- `run_query` tool/function-call to answer the question.
33
+ `run_query` tool/function-call to answer questions.
34
34
 
35
35
  The below JSON schema maps the SQL database structure. It outlines tables, each
36
36
  with a description and columns. Each table is identified by a key,
@@ -146,7 +146,7 @@ class SQLChatAgent(ChatAgent):
146
146
 
147
147
  # Update the system message with the table information
148
148
  self.config.system_message = self.config.system_message.format(
149
- schema_dict=schema_dict
149
+ schema_dict=schema_dict, dialect=self.engine.dialect.name
150
150
  )
151
151
 
152
152
  super().__init__(config)
@@ -10,7 +10,9 @@ the code and returns the result as a string.
10
10
  import io
11
11
  import logging
12
12
  import sys
13
+ from typing import no_type_check
13
14
 
15
+ import numpy as np
14
16
  import pandas as pd
15
17
  from rich.console import Console
16
18
 
@@ -26,16 +28,72 @@ logger = logging.getLogger(__name__)
26
28
  console = Console()
27
29
 
28
30
  DEFAULT_TABLE_CHAT_SYSTEM_MESSAGE = """
29
- You are a savvy data scientist, with expertise in analyzing tabular dataset,
31
+ You are a savvy data scientist, with expertise in analyzing tabular datasets,
30
32
  using Python and the Pandas library for dataframe manipulation.
31
33
  Since you do not have access to the dataframe 'df', you
32
34
  will need to use the `run_code` tool/function-call to answer the question.
33
- The columns in the dataframe are:
34
- {columns}
35
+ Here is a summary of the dataframe:
36
+ {summary}
35
37
  Do not assume any columns other than those shown.
38
+ In the code you submit to the `run_code` tool/function,
39
+ do not forget to include any necessary imports, such as `import pandas as pd`.
40
+ Sometimes you may not be able to answer the question in a single call to `run_code`,
41
+ so you can use a series of calls to `run_code` to build up the answer.
42
+ For example you may first want to know something about the possible values in a column.
43
+
44
+ If you receive a null or other unexpected result, see if you have made an assumption
45
+ in your code, and try another way, or use `run_code` to explore the dataframe
46
+ before submitting your final code.
47
+
48
+ Start by asking me what I want to know about the data.
36
49
  """
37
50
 
38
51
 
52
+ @no_type_check
53
+ def dataframe_summary(df: pd.DataFrame) -> str:
54
+ """
55
+ Generate a structured summary for a pandas DataFrame containing numerical
56
+ and categorical values.
57
+
58
+ Args:
59
+ df (pd.DataFrame): The input DataFrame to summarize.
60
+
61
+ Returns:
62
+ str: A nicely structured and formatted summary string.
63
+ """
64
+
65
+ # Column names display
66
+ col_names_str = (
67
+ "COLUMN NAMES:\n" + " ".join([f"'{col}'" for col in df.columns]) + "\n\n"
68
+ )
69
+
70
+ # Numerical data summary
71
+ num_summary = df.describe().applymap(lambda x: "{:.2f}".format(x))
72
+ num_str = "Numerical Column Summary:\n" + num_summary.to_string() + "\n\n"
73
+
74
+ # Categorical data summary
75
+ cat_columns = df.select_dtypes(include=[np.object_]).columns
76
+ cat_summary_list = []
77
+
78
+ for col in cat_columns:
79
+ unique_values = df[col].unique()
80
+ if len(unique_values) < 10:
81
+ cat_summary_list.append(f"'{col}': {', '.join(map(str, unique_values))}")
82
+ else:
83
+ cat_summary_list.append(f"'{col}': {df[col].nunique()} unique values")
84
+
85
+ cat_str = "Categorical Column Summary:\n" + "\n".join(cat_summary_list) + "\n\n"
86
+
87
+ # Missing values summary
88
+ nan_summary = df.isnull().sum().rename("missing_values").to_frame()
89
+ nan_str = "Missing Values Column Summary:\n" + nan_summary.to_string() + "\n"
90
+
91
+ # Combine the summaries into one structured string
92
+ summary_str = col_names_str + num_str + cat_str + nan_str
93
+
94
+ return summary_str
95
+
96
+
39
97
  class TableChatAgentConfig(ChatAgentConfig):
40
98
  system_message: str = DEFAULT_TABLE_CHAT_SYSTEM_MESSAGE
41
99
  user_message: None | str = None
@@ -77,10 +135,8 @@ class TableChatAgent(ChatAgent):
77
135
  df = read_tabular_data(config.data, config.separator)
78
136
 
79
137
  self.df = df
80
- columns_with_quotes = [f"'{c}'" for c in df.columns]
81
- config.system_message = config.system_message.format(
82
- columns=", ".join(columns_with_quotes)
83
- )
138
+ summary = dataframe_summary(df)
139
+ config.system_message = config.system_message.format(summary=summary)
84
140
 
85
141
  super().__init__(config)
86
142
  self.config: TableChatAgentConfig = config
@@ -0,0 +1,28 @@
1
+ """
2
+ A tool to trigger a Google 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(GoogleSearchTool)`
6
+
7
+ NOTE: Using this tool requires setting the GOOGLE_API_KEY and GOOGLE_CSE_ID
8
+ environment variables in your `.env` file, as explained in the
9
+ [README](https://github.com/langroid/langroid#gear-installation-and-setup).
10
+ """
11
+
12
+ from langroid.agent.tool_message import ToolMessage
13
+ from langroid.parsing.web_search import google_search
14
+
15
+
16
+ class GoogleSearchTool(ToolMessage):
17
+ request: str = "web_search"
18
+ purpose: str = """
19
+ To search the web and return up to <num_results> links relevant to
20
+ the given <query>.
21
+ """
22
+ query: str
23
+ num_results: int
24
+
25
+ def handle(self) -> str:
26
+ search_results = google_search(self.query, self.num_results)
27
+ # return Title, Link, Summary of each result, separated by two newlines
28
+ return "\n\n".join(str(result) for result in search_results)
@@ -4,7 +4,7 @@ import logging
4
4
  import os
5
5
  import sys
6
6
  from enum import Enum
7
- from typing import Any, Dict, List, Optional, Tuple, Union, cast
7
+ from typing import Any, Dict, List, Optional, Tuple, Union
8
8
 
9
9
  import openai
10
10
  from dotenv import load_dotenv
@@ -361,13 +361,13 @@ class OpenAIGPT(LanguageModel):
361
361
  LLMResponse object
362
362
  """
363
363
  openai.api_key = self.api_key
364
- if type(messages) == str:
364
+ if isinstance(messages, str):
365
365
  llm_messages = [
366
366
  LLMMessage(role=Role.SYSTEM, content="You are a helpful assistant."),
367
367
  LLMMessage(role=Role.USER, content=messages),
368
368
  ]
369
369
  else:
370
- llm_messages = cast(List[LLMMessage], messages)
370
+ llm_messages = messages
371
371
 
372
372
  @retry_with_exponential_backoff
373
373
  def completions_with_backoff(**kwargs): # type: ignore
@@ -1,3 +1,11 @@
1
+ """
2
+ Utilities for web search.
3
+
4
+ NOTE: Using Google Search requires setting the GOOGLE_API_KEY and GOOGLE_CSE_ID
5
+ environment variables in your `.env` file, as explained in the
6
+ [README](https://github.com/langroid/langroid#gear-installation-and-setup).
7
+ """
8
+
1
9
  import os
2
10
  from typing import Dict, List
3
11
 
@@ -7,12 +15,10 @@ from dotenv import load_dotenv
7
15
  from googleapiclient.discovery import Resource, build
8
16
  from requests.models import Response
9
17
 
10
- from langroid.agent.tool_message import ToolMessage
11
18
 
12
-
13
- class GoogleSearchResult:
19
+ class WebSearchResult:
14
20
  """
15
- Class representing a Google Search result, containing the title, link,
21
+ Class representing a Web Search result, containing the title, link,
16
22
  summary and full content of the result.
17
23
  """
18
24
 
@@ -58,29 +64,16 @@ class GoogleSearchResult:
58
64
  }
59
65
 
60
66
 
61
- class GoogleSearchTool(ToolMessage):
62
- request: str = "web_search"
63
- purpose: str = """
64
- To search the web and return up to <num_results> links relevant to
65
- the given <query>.
66
- """
67
- query: str
68
- num_results: int
69
-
70
- def handle(self) -> str:
71
- load_dotenv()
72
- api_key = os.getenv("GOOGLE_API_KEY")
73
- cse_id = os.getenv("GOOGLE_CSE_ID")
74
- service: Resource = build("customsearch", "v1", developerKey=api_key)
75
- raw_results = (
76
- service.cse()
77
- .list(q=self.query, cx=cse_id, num=self.num_results)
78
- .execute()["items"]
79
- )
67
+ def google_search(query: str, num_results: int = 5) -> List[WebSearchResult]:
68
+ load_dotenv()
69
+ api_key = os.getenv("GOOGLE_API_KEY")
70
+ cse_id = os.getenv("GOOGLE_CSE_ID")
71
+ service: Resource = build("customsearch", "v1", developerKey=api_key)
72
+ raw_results = (
73
+ service.cse().list(q=query, cx=cse_id, num=num_results).execute()["items"]
74
+ )
80
75
 
81
- search_results: List[GoogleSearchResult] = [
82
- GoogleSearchResult(result["title"], result["link"], 3500, 300)
83
- for result in raw_results
84
- ]
85
- # return Title and Link of each result, separated by two newlines
86
- return "\n\n".join(str(result) for result in search_results)
76
+ return [
77
+ WebSearchResult(result["title"], result["link"], 3500, 300)
78
+ for result in raw_results
79
+ ]
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "langroid"
3
- version = "0.1.39"
3
+ version = "0.1.41"
4
4
  description = "Harness LLMs with Multi-Agent Programming"
5
5
  authors = ["Prasad Chalasani <pchalasani@gmail.com>"]
6
6
  readme = "README.md"
@@ -59,6 +59,7 @@ sqlalchemy = "^2.0.19"
59
59
  prettytable = "^3.8.0"
60
60
  google-api-python-client = "^2.95.0"
61
61
  lxml = "^4.9.3"
62
+ psycopg2 = "^2.9.7"
62
63
 
63
64
  [tool.poetry.group.dev.dependencies]
64
65
  pytest = "^7.3.1"
@@ -0,0 +1,94 @@
1
+ # -*- coding: utf-8 -*-
2
+ from setuptools import setup
3
+
4
+ packages = \
5
+ ['langroid',
6
+ 'langroid.agent',
7
+ 'langroid.agent.special',
8
+ 'langroid.agent.stateless_tools',
9
+ 'langroid.cachedb',
10
+ 'langroid.embedding_models',
11
+ 'langroid.language_models',
12
+ 'langroid.parsing',
13
+ 'langroid.prompts',
14
+ 'langroid.scripts',
15
+ 'langroid.utils',
16
+ 'langroid.utils.llms',
17
+ 'langroid.utils.output',
18
+ 'langroid.utils.web',
19
+ 'langroid.vector_store']
20
+
21
+ package_data = \
22
+ {'': ['*']}
23
+
24
+ install_requires = \
25
+ ['autopep8>=2.0.2,<3.0.0',
26
+ 'black[jupyter]>=23.3.0,<24.0.0',
27
+ 'bs4>=0.0.1,<0.0.2',
28
+ 'chromadb>=0.3.21,<0.4.0',
29
+ 'colorlog>=6.7.0,<7.0.0',
30
+ 'faker>=18.9.0,<19.0.0',
31
+ 'fakeredis>=2.12.1,<3.0.0',
32
+ 'fire>=0.5.0,<0.6.0',
33
+ 'flake8>=6.0.0,<7.0.0',
34
+ 'google-api-python-client>=2.95.0,<3.0.0',
35
+ 'halo>=0.0.31,<0.0.32',
36
+ 'lxml>=4.9.3,<5.0.0',
37
+ 'mkdocs-awesome-pages-plugin>=2.8.0,<3.0.0',
38
+ 'mkdocs-gen-files>=0.4.0,<0.5.0',
39
+ 'mkdocs-jupyter>=0.24.1,<0.25.0',
40
+ 'mkdocs-literate-nav>=0.6.0,<0.7.0',
41
+ 'mkdocs-material>=9.1.5,<10.0.0',
42
+ 'mkdocs-section-index>=0.3.5,<0.4.0',
43
+ 'mkdocs>=1.4.2,<2.0.0',
44
+ 'mkdocstrings[python]>=0.21.2,<0.22.0',
45
+ 'momento>=1.7.0,<2.0.0',
46
+ 'mypy>=1.2.0,<2.0.0',
47
+ 'nltk>=3.8.1,<4.0.0',
48
+ 'openai>=0.27.5,<0.28.0',
49
+ 'pandas>=2.0.3,<3.0.0',
50
+ 'pre-commit>=3.3.2,<4.0.0',
51
+ 'prettytable>=3.8.0,<4.0.0',
52
+ 'psycopg2>=2.9.7,<3.0.0',
53
+ 'pydantic==1.10.11',
54
+ 'pygithub>=1.58.1,<2.0.0',
55
+ 'pygments>=2.15.1,<3.0.0',
56
+ 'pyparsing>=3.0.9,<4.0.0',
57
+ 'pypdf>=3.12.2,<4.0.0',
58
+ 'python-dotenv>=1.0.0,<2.0.0',
59
+ 'qdrant-client>=1.3.1,<2.0.0',
60
+ 'redis>=4.5.5,<5.0.0',
61
+ 'requests-oauthlib>=1.3.1,<2.0.0',
62
+ 'requests>=2.31.0,<3.0.0',
63
+ 'rich>=13.3.4,<14.0.0',
64
+ 'ruff>=0.0.270,<0.0.271',
65
+ 'sqlalchemy>=2.0.19,<3.0.0',
66
+ 'tiktoken>=0.3.3,<0.4.0',
67
+ 'trafilatura>=1.5.0,<2.0.0',
68
+ 'typer>=0.7.0,<0.8.0',
69
+ 'types-redis>=4.5.5.2,<5.0.0.0',
70
+ 'types-requests>=2.31.0.1,<3.0.0.0',
71
+ 'wget>=3.2,<4.0']
72
+
73
+ extras_require = \
74
+ {'hf-embeddings': ['sentence-transformers==2.2.2', 'torch==2.0.0']}
75
+
76
+ setup_kwargs = {
77
+ 'name': 'langroid',
78
+ 'version': '0.1.41',
79
+ 'description': 'Harness LLMs with Multi-Agent Programming',
80
+ 'long_description': '<div align="center">\n <img src="docs/assets/langroid-card-lambda-ossem-rust-1200-630.png" alt="Logo" \n width="400" align="center">\n</div>\n\n<div align="center">\n\n[![Pytest](https://github.com/langroid/langroid/actions/workflows/pytest.yml/badge.svg)](https://github.com/langroid/langroid/actions/workflows/pytest.yml)\n[![codecov](https://codecov.io/gh/langroid/langroid/branch/main/graph/badge.svg?token=H94BX5F0TE)](https://codecov.io/gh/langroid/langroid)\n[![Lint](https://github.com/langroid/langroid/actions/workflows/validate.yml/badge.svg)](https://github.com/langroid/langroid/actions/workflows/validate.yml)\n[![Docs](https://github.com/langroid/langroid/actions/workflows/mkdocs-deploy.yml/badge.svg)](https://github.com/langroid/langroid/actions/workflows/mkdocs-deploy.yml)\n[![Static Badge](https://img.shields.io/badge/Documentation-blue?link=https%3A%2F%2Flangroid.github.io%2Flangroid%2F&link=https%3A%2F%2Flangroid.github.io%2Flangroid%2F)](https://langroid.github.io/langroid)\n[![Static Badge](https://img.shields.io/badge/Discord-orange?logoColor=orange&link=https%3A%2F%2Fdiscord.gg%2FZU36McDgDs)](https://discord.gg/ZU36McDgDs)\n[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langroid/langroid/blob/main/examples/langroid_quick_examples.ipynb)\n\n[![Share on Twitter](https://img.shields.io/twitter/url?style=social&url=https://github.com/langroid/langroid)](https://twitter.com/intent/tweet?text=Langroid%20is%20a%20powerful,%20elegant%20new%20framework%20to%20easily%20build%20%23LLM%20applications.%20You%20set%20up%20LLM-powered%20Agents%20with%20vector-stores,%20assign%20tasks,%20and%20have%20them%20collaboratively%20solve%20problems%20via%20message-transformations.%20https://github.com/langroid/langroid)\n[![Share on LinkedIn](https://img.shields.io/badge/Share%20on-LinkedIn-blue)](https://www.linkedin.com/shareArticle?mini=true&url=https://github.com/langroid/langroid&title=Langroid:%20A%20Powerful,%20Elegant%20Framework&summary=Langroid%20is%20a%20powerful,%20elegant%20new%20framework%20to%20easily%20build%20%23LLM%20applications.%20You%20set%20up%20LLM-powered%20Agents%20with%20vector-stores,%20assign%20tasks,%20and%20have%20them%20collaboratively%20solve%20problems%20via%20message-transformations.)\n\n</div>\n\n<h3 align="center">\n <a target="_blank" \n href="https://langroid.github.io/langroid/" rel="dofollow">\n <strong>Documentation</strong></a>\n &middot;\n <a target="_blank" href="https://github.com/langroid/langroid-examples" rel="dofollow">\n <strong>Examples Repo</strong></a>\n &middot;\n <a target="_blank" href="https://discord.gg/ZU36McDgDs" rel="dofollow">\n <strong>Discord</strong></a>\n &middot;\n <a target="_blank" href="./CONTRIBUTING.md" rel="dofollow">\n <strong>Contributing</strong></a>\n\n <br />\n</h3>\n\n`Langroid` is an intuitive, lightweight, extensible and principled\nPython framework to easily build LLM-powered applications. \nYou set up Agents, equip them with optional components (LLM, \nvector-store and methods), assign them tasks, and have them \ncollaboratively solve a problem by exchanging messages. \nThis Multi-Agent paradigm is inspired by the\n[Actor Framework](https://en.wikipedia.org/wiki/Actor_model)\n(but you do not need to know anything about this!).\nWe welcome contributions -- See the [contributions](./CONTRIBUTING.md) document\nfor ideas on what to contribute.\n\n**Questions, Feedback, Ideas? Join us on [Discord](https://discord.gg/ZU36McDgDs)!**\n\n<details>\n<summary> <b>:fire: Updates/Releases</b></summary>\n\n- **Aug 2023:**\n - **Example:** [Answer questions](examples/docqa/chat-search.py) using Google Search + vecdb-retrieval from URL contents. \n - **0.1.39:** [`GoogleSearchTool`](langroid/agent/stateless_tools/google_search_tool.py) to enable Agents (their LLM) to do Google searches via function-calling/tools.\n See [this chat example](examples/basic/chat-search.py) for how easy it is to add this tool to an agent.\n - **Colab notebook** to try the quick-start examples: [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langroid/langroid/blob/main/examples/langroid_quick_examples.ipynb) \n - **0.1.37:** Added [`SQLChatAgent`](langroid/agent/special/sql_chat_agent.py) -- thanks to our latest contributor [Rithwik Babu](https://github.com/rithwikbabu)!\n - Multi-agent Example: [Autocorrect chat](examples/basic/autocorrect.py)\n- **July 2023:** \n - **0.1.30:** Added [`TableChatAgent`](langroid/agent/special/table_chat_agent.py) to \n [chat](examples/data-qa/table_chat.py) with tabular datasets (dataframes, files, URLs): LLM generates Pandas code,\n and code is executed using Langroid\'s tool/function-call mechanism. \n - **Demo:** 3-agent system for Audience [Targeting](https://langroid.github.io/langroid/demos/targeting/audience-targeting/).\n - **0.1.27**: Added [support](langroid/cachedb/momento_cachedb.py) \n for [Momento Serverless Cache](https://www.gomomento.com/) as an alternative to Redis.\n - **0.1.24**: [`DocChatAgent`](langroid/agent/special/doc_chat_agent.py) \n now [accepts](langroid/parsing/pdf_parser.py) PDF files or URLs.\n\n</details>\n\n# :rocket: Demo\nSuppose you want to extract structured information about the key terms \nof a commercial lease document. You can easily do this with Langroid using a two-agent system,\nas we show in the [langroid-examples](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py) repo.\nThe demo showcases just a few of the many features of Langroid, such as:\n- Multi-agent collaboration: `LeaseExtractor` is in charge of the task, and its LLM (GPT4) generates questions \nto be answered by the `DocAgent`.\n- Retrieval augmented question-answering, with **source-citation**: `DocAgent` LLM (GPT4) uses retrieval from a vector-store to \nanswer the `LeaseExtractor`\'s questions, cites the specific excerpt supporting the answer. \n- Function-calling (also known as tool/plugin): When it has all the information it \nneeds, the `LeaseExtractor` LLM presents the information in a structured \nformat using a Function-call. \n\nHere is what it looks like in action:\n\n![Demo](docs/assets/demos/lease-extractor-demo.gif)\n\n\n# :zap: Highlights\n\n- **Agents as first-class citizens:** The [Agent](https://langroid.github.io/langroid/reference/agent/base/#langroid.agent.base.Agent) class encapsulates LLM conversation state,\n and optionally a vector-store and tools. Agents are a core abstraction in Langroid;\n Agents act as _message transformers_, and by default provide 3 _responder_ methods, one corresponding to each entity: LLM, Agent, User.\n- **Tasks:** A [Task](https://langroid.github.io/langroid/reference/agent/task/) class wraps an Agent, and gives the agent instructions (or roles, or goals), \n manages iteration over an Agent\'s responder methods, \n and orchestrates multi-agent interactions via hierarchical, recursive\n task-delegation. The `Task.run()` method has the same \n type-signature as an Agent\'s responder\'s methods, and this is key to how \n a task of an agent can delegate to other sub-tasks: from the point of view of a Task,\n sub-tasks are simply additional responders, to be used in a round-robin fashion \n after the agent\'s own responders.\n- **Modularity, Reusabilily, Loose coupling:** The `Agent` and `Task` abstractions allow users to design\n Agents with specific skills, wrap them in Tasks, and combine tasks in a flexible way.\n- **LLM Support**: Langroid supports OpenAI LLMs including GPT-3.5-Turbo,\n GPT-4-0613\n- **Caching of LLM responses:** Langroid supports [Redis](https://redis.com/try-free/) and \n [Momento](https://www.gomomento.com/) to cache LLM responses.\n- **Vector-stores**: [Qdrant](https://qdrant.tech/) and [Chroma](https://www.trychroma.com/) are currently supported.\n Vector stores allow for Retrieval-Augmented-Generation (RAG).\n- **Grounding and source-citation:** Access to external documents via vector-stores \n allows for grounding and source-citation.\n- **Observability, Logging, Lineage:** Langroid generates detailed logs of multi-agent interactions and\n maintains provenance/lineage of messages, so that you can trace back\n the origin of a message.\n- **Tools/Plugins/Function-calling**: Langroid supports OpenAI\'s recently\n released [function calling](https://platform.openai.com/docs/guides/gpt/function-calling)\n feature. In addition, Langroid has its own native equivalent, which we\n call **tools** (also known as "plugins" in other contexts). Function\n calling and tools have the same developer-facing interface, implemented\n using [Pydantic](https://docs.pydantic.dev/latest/),\n which makes it very easy to define tools/functions and enable agents\n to use them. Benefits of using Pydantic are that you never have to write\n complex JSON specs for function calling, and when the LLM\n hallucinates malformed JSON, the Pydantic error message is sent back to\n the LLM so it can fix it!\n\n--- \n\n# :gear: Installation and Setup\n\n### Install `langroid`\nLangroid requires Python 3.11+. We recommend using a virtual environment.\nUse `pip` to install `langroid` (from PyPi) to your virtual environment:\n```bash\npip install langroid\n```\nThe core Langroid package lets you use OpenAI Embeddings models via their API. \nIf you instead want to use the `all-MiniLM-L6-v2` embeddings model\nfrom from HuggingFace, install Langroid like this:\n```bash\npip install langroid[hf-embeddings]\n```\nNote that this will install `torch` and `sentence-transformers` libraries.\n\n### Set up environment variables (API keys, etc)\n\nTo get started, all you need is an OpenAI API Key.\nIf you don\'t have one, see [this OpenAI Page](https://help.openai.com/en/collections/3675940-getting-started-with-openai-api).\nCurrently only OpenAI models are supported. Others will be added later\n(Pull Requests welcome!).\n\nIn the root of the repo, copy the `.env-template` file to a new file `.env`: \n```bash\ncp .env-template .env\n```\nThen insert your OpenAI API Key. \nYour `.env` file should look like this:\n```bash\nOPENAI_API_KEY=your-key-here-without-quotes\n````\n\nAlternatively, you can set this as an environment variable in your shell\n(you will need to do this every time you open a new shell):\n```bash\nexport OPENAI_API_KEY=your-key-here-without-quotes\n```\n\n\n<details>\n<summary><b>Optional Setup Instructions (click to expand) </b></summary>\n\nAll of the following environment variable settings are optional, and some are only needed \nto use specific features (as noted below).\n\n- **Qdrant** Vector Store API Key, URL. This is only required if you want to use Qdrant cloud.\n You can sign up for a free 1GB account at [Qdrant cloud](https://cloud.qdrant.io).\n If you skip setting up these, Langroid will use Qdrant in local-storage mode.\n Alternatively [Chroma](https://docs.trychroma.com/) is also currently supported. \n We use the local-storage version of Chroma, so there is no need for an API key.\n Langroid uses Qdrant by default.\n- **Redis** Password, host, port: This is optional, and only needed to cache LLM API responses\n using Redis Cloud. Redis [offers](https://redis.com/try-free/) a free 30MB Redis account\n which is more than sufficient to try out Langroid and even beyond.\n If you don\'t set up these, Langroid will use a pure-python \n Redis in-memory cache via the [Fakeredis](https://fakeredis.readthedocs.io/en/latest/) library.\n- **Momento** Serverless Caching of LLM API responses (as an alternative to Redis). \n To use Momento instead of Redis:\n - enter your Momento Token in the `.env` file, as the value of `MOMENTO_AUTH_TOKEN` (see example file below),\n - in the `.env` file set `CACHE_TYPE=momento` (instead of `CACHE_TYPE=redis` which is the default).\n- **GitHub** Personal Access Token (required for apps that need to analyze git\n repos; token-based API calls are less rate-limited). See this\n [GitHub page](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens).\n- **Google Custom Search API Credentials:** Only needed to enable an Agent to use the `GoogleSearchTool`.\n To use Google Search as an LLM Tool/Plugin/function-call, \n you\'ll need to set up \n [a Google API key](https://developers.google.com/custom-search/v1/introduction#identify_your_application_to_google_with_api_key),\n then [setup a Google Custom Search Engine (CSE) and get the CSE ID](https://developers.google.com/custom-search/docs/tutorial/creatingcse).\n (Documentation for these can be challenging, we suggest asking GPT4 for a step-by-step guide.)\n After obtaining these credentials, store them as values of \n `GOOGLE_API_KEY` and `GOOGLE_CSE_ID` in your `.env` file. \n Full documentation on using this (and other such "stateless" tools) is coming soon, but \n in the meantime take a peek at this [chat example](examples/basic/chat-search.py), which \n shows how you can easily equip an Agent with a `GoogleSearchtool`.\n \n\n\nIf you add all of these optional variables, your `.env` file should look like this:\n```bash\nOPENAI_API_KEY=your-key-here-without-quotes\nGITHUB_ACCESS_TOKEN=your-personal-access-token-no-quotes\nCACHE_TYPE=redis # or momento\nREDIS_PASSWORD=your-redis-password-no-quotes\nREDIS_HOST=your-redis-hostname-no-quotes\nREDIS_PORT=your-redis-port-no-quotes\nMOMENTO_AUTH_TOKEN=your-momento-token-no-quotes # instead of REDIS* variables\nQDRANT_API_KEY=your-key\nQDRANT_API_URL=https://your.url.here:6333 # note port number must be included\nGOOGLE_API_KEY=your-key\nGOOGLE_CSE_ID=your-cse-id\n```\n</details>\n\n---\n\n# :tada: Usage Examples\n\nThese are quick teasers to give a glimpse of what you can do with Langroid\nand how your code would look. \n\n:warning: The code snippets below are intended to give a flavor of the code\nand they are **not** complete runnable examples! For that we encourage you to \nconsult the [`langroid-examples`](https://github.com/langroid/langroid-examples) \nrepository.\n\n:information_source: The various LLM prompts and instructions in Langroid\nhave been tested to work well with GPT4.\nSwitching to GPT3.5-Turbo is easy via a config flag\n(e.g., `cfg = OpenAIGPTConfig(chat_model=OpenAIChatModel.GPT3_5_TURBO)`),\nand may suffice for some applications, but in general you may see inferior results.\n\n\n:book: Also see the\n[`Getting Started Guide`](https://langroid.github.io/langroid/quick-start/)\nfor a detailed tutorial.\n\nClick to expand any of the code examples below.\nAll of these can be run in a Colab notebook:\n[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langroid/langroid/blob/main/examples/langroid_quick_examples.ipynb)\n\n<details>\n<summary> <b> Direct interaction with OpenAI LLM </b> </summary>\n\n```python\nfrom langroid.language_models.openai_gpt import ( \n OpenAIGPTConfig, OpenAIChatModel, OpenAIGPT,\n)\nfrom langroid.language_models.base import LLMMessage, Role\n\ncfg = OpenAIGPTConfig(chat_model=OpenAIChatModel.GPT4)\n\nmdl = OpenAIGPT(cfg)\n\nmessages = [\n LLMMessage(content="You are a helpful assistant", role=Role.SYSTEM), \n LLMMessage(content="What is the capital of Ontario?", role=Role.USER),\n]\nresponse = mdl.chat(messages, max_tokens=200)\nprint(response.message)\n```\n</details>\n\n<details>\n<summary> <b> Define an agent, set up a task, and run it </b> </summary>\n\n```python\nfrom langroid.agent.chat_agent import ChatAgent, ChatAgentConfig\nfrom langroid.agent.task import Task\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\n\nconfig = ChatAgentConfig(\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb=None, # no vector store\n)\nagent = ChatAgent(config)\n# get response from agent\'s LLM, and put this in an interactive loop...\n# answer = agent.llm_response("What is the capital of Ontario?")\n # ... OR instead, set up a task (which has a built-in loop) and run it\ntask = Task(agent, name="Bot") \ntask.run() # ... a loop seeking response from LLM or User at each turn\n```\n</details>\n\n<details>\n<summary><b> Three communicating agents </b></summary>\n\nA toy numbers game, where when given a number `n`:\n- `repeater_agent`\'s LLM simply returns `n`,\n- `even_agent`\'s LLM returns `n/2` if `n` is even, else says "DO-NOT-KNOW"\n- `odd_agent`\'s LLM returns `3*n+1` if `n` is odd, else says "DO-NOT-KNOW"\n\nFirst define the 3 agents, and set up their tasks with instructions:\n\n```python\nfrom langroid.utils.constants import NO_ANSWER\nfrom langroid.agent.chat_agent import ChatAgent, ChatAgentConfig\nfrom langroid.agent.task import Task\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\nconfig = ChatAgentConfig(\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb = None,\n)\nrepeater_agent = ChatAgent(config)\nrepeater_task = Task(\n repeater_agent,\n name = "Repeater",\n system_message="""\n Your job is to repeat whatever number you receive.\n """,\n llm_delegate=True, # LLM takes charge of task\n single_round=False, \n)\neven_agent = ChatAgent(config)\neven_task = Task(\n even_agent,\n name = "EvenHandler",\n system_message=f"""\n You will be given a number. \n If it is even, divide by 2 and say the result, nothing else.\n If it is odd, say {NO_ANSWER}\n """,\n single_round=True, # task done after 1 step() with valid response\n)\n\nodd_agent = ChatAgent(config)\nodd_task = Task(\n odd_agent,\n name = "OddHandler",\n system_message=f"""\n You will be given a number n. \n If it is odd, return (n*3+1), say nothing else. \n If it is even, say {NO_ANSWER}\n """,\n single_round=True, # task done after 1 step() with valid response\n)\n```\nThen add the `even_task` and `odd_task` as sub-tasks of `repeater_task`, \nand run the `repeater_task`, kicking it off with a number as input:\n```python\nrepeater_task.add_sub_task([even_task, odd_task])\nrepeater_task.run("3")\n```\n\n</details>\n\n<details>\n<summary><b> Simple Tool/Function-calling example </b></summary>\n\nLangroid leverages Pydantic to support OpenAI\'s\n[Function-calling API](https://platform.openai.com/docs/guides/gpt/function-calling)\nas well as its own native tools. The benefits are that you don\'t have to write\nany JSON to specify the schema, and also if the LLM hallucinates a malformed\ntool syntax, Langroid sends the Pydantic validation error (suitiably sanitized) \nto the LLM so it can fix it!\n\nSimple example: Say the agent has a secret list of numbers, \nand we want the LLM to find the smallest number in the list. \nWe want to give the LLM a `probe` tool/function which takes a\nsingle number `n` as argument. The tool handler method in the agent\nreturns how many numbers in its list are at most `n`.\n\nFirst define the tool using Langroid\'s `ToolMessage` class:\n\n\n```python\nfrom langroid.agent.tool_message import ToolMessage\nclass ProbeTool(ToolMessage):\n request: str = "probe" # specifies which agent method handles this tool\n purpose: str = """\n To find how many numbers in my list are less than or equal to \n the <number> you specify.\n """ # description used to instruct the LLM on when/how to use the tool\n number: int # required argument to the tool\n```\n\nThen define a `SpyGameAgent` as a subclass of `ChatAgent`, \nwith a method `probe` that handles this tool:\n\n```python\nfrom langroid.agent.chat_agent import ChatAgent, ChatAgentConfig\nclass SpyGameAgent(ChatAgent):\n def __init__(self, config: ChatAgentConfig):\n super().__init__(config)\n self.numbers = [3, 4, 8, 11, 15, 25, 40, 80, 90]\n\n def probe(self, msg: ProbeTool) -> str:\n # return how many numbers in self.numbers are less or equal to msg.number\n return str(len([n for n in self.numbers if n <= msg.number]))\n```\n\nWe then instantiate the agent and enable it to use and respond to the tool:\n\n```python\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\nspy_game_agent = SpyGameAgent(\n ChatAgentConfig(\n name="Spy",\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb=None,\n use_tools=False, # don\'t use Langroid native tool\n use_functions_api=True, # use OpenAI function-call API\n )\n)\nspy_game_agent.enable_message(ProbeTool)\n```\n\nFor a full working example see the\n[chat-agent-tool.py](https://github.com/langroid/langroid-examples/blob/main/examples/quick-start/chat-agent-tool.py)\nscript in the `langroid-examples` repo.\n</details>\n\n<details>\n<summary> <b>Tool/Function-calling to extract structured information from text </b> </summary>\n\nSuppose you want an agent to extract \nthe key terms of a lease, from a lease document, as a nested JSON structure.\nFirst define the desired structure via Pydantic models:\n\n```python\nfrom pydantic import BaseModel\nclass LeasePeriod(BaseModel):\n start_date: str\n end_date: str\n\n\nclass LeaseFinancials(BaseModel):\n monthly_rent: str\n deposit: str\n\nclass Lease(BaseModel):\n period: LeasePeriod\n financials: LeaseFinancials\n address: str\n```\n\nThen define the `LeaseMessage` tool as a subclass of Langroid\'s `ToolMessage`.\nNote the tool has a required argument `terms` of type `Lease`:\n\n```python\nclass LeaseMessage(ToolMessage):\n request: str = "lease_info"\n purpose: str = """\n Collect information about a Commercial Lease.\n """\n terms: Lease\n```\n\nThen define a `LeaseExtractorAgent` with a method `lease_info` that handles this tool,\ninstantiate the agent, and enable it to use and respond to this tool:\n\n```python\nclass LeaseExtractorAgent(ChatAgent):\n def lease_info(self, message: LeaseMessage) -> str:\n print(\n f"""\n DONE! Successfully extracted Lease Info:\n {message.terms}\n """\n )\n return json.dumps(message.terms.dict())\n \nlease_extractor_agent = LeaseExtractorAgent(\n ChatAgentConfig(\n llm=OpenAIGPTConfig(),\n use_functions_api=False,\n use_tools=True,\n )\n)\nlease_extractor_agent.enable_message(LeaseMessage)\n```\n\nSee the [`chat_multi_extract.py`](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py)\nscript in the `langroid-examples` repo for a full working example.\n</details>\n\n<details>\n<summary><b> Chat with documents (file paths, URLs, etc) </b></summary>\n\nLangroid provides a specialized agent class `DocChatAgent` for this purpose.\nIt incorporates document sharding, embedding, storage in a vector-DB, \nand retrieval-augmented query-answer generation.\nUsing this class to chat with a collection of documents is easy.\nFirst create a `DocChatAgentConfig` instance, with a \n`doc_paths` field that specifies the documents to chat with.\n\n```python\nfrom langroid.agent.doc_chat_agent import DocChatAgentConfig\nconfig = DocChatAgentConfig(\n doc_paths = [\n "https://en.wikipedia.org/wiki/Language_model",\n "https://en.wikipedia.org/wiki/N-gram_language_model",\n "/path/to/my/notes-on-language-models.txt",\n ]\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb=VectorStoreConfig(\n type="qdrant",\n ),\n)\n```\n\nThen instantiate the `DocChatAgent` (this ingests the docs into the vector-store):\n\n```python\nagent = DocChatAgent(config)\n```\nThen we can either ask the agent one-off questions,\n```python\nagent.chat("What is a language model?")\n```\nor wrap it in a `Task` and run an interactive loop with the user:\n```python\nfrom langroid.task import Task\ntask = Task(agent)\ntask.run()\n```\n\nSee full working scripts in the \n[`docqa`](https://github.com/langroid/langroid-examples/tree/main/examples/docqa)\nfolder of the `langroid-examples` repo.\n</details>\n\n<details>\n<summary><b> :fire: Chat with tabular data (file paths, URLs, dataframes) </b></summary>\n\nUsing Langroid you can set up a `TableChatAgent` with a dataset (file path, URL or dataframe),\nand query it. The Agent\'s LLM generates Pandas code to answer the query, \nvia function-calling (or tool/plugin), and the Agent\'s function-handling method\nexecutes the code and returns the answer.\n\nHere is how you can do this:\n\n```python\nfrom langroid.agent.special.table_chat_agent import TableChatAgent, TableChatAgentConfig\nfrom langroid.agent.task import Task\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\n```\n\nSet up a `TableChatAgent` for a data file, URL or dataframe\n(Ensure the data table has a header row; the delimiter/separator is auto-detected):\n```python\ndataset = "https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv"\n# or dataset = "/path/to/my/data.csv"\n# or dataset = pd.read_csv("/path/to/my/data.csv")\nagent = TableChatAgent(\n config=TableChatAgentConfig(\n data=dataset, \n llm=OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n )\n)\n```\nSet up a task, and ask one-off questions like this: \n\n```python\ntask = Task(\n agent, \n name = "DataAssistant",\n default_human_response="", # to avoid waiting for user input\n)\nresult = task.run(\n "What is the average alcohol content of wines with a quality rating above 7?",\n turns=2 # return after user question, LLM fun-call/tool response, Agent code-exec result\n) \nprint(result.content)\n```\nOr alternatively, set up a task and run it in an interactive loop with the user:\n\n```python\ntask = Task(agent, name="DataAssistant")\ntask.run()\n``` \n\nFor a full working example see the \n[`table_chat.py`](https://github.com/langroid/langroid-examples/tree/main/examples/data-qa/table_chat.py)\nscript in the `langroid-examples` repo.\n\n\n</details>\n\n---\n\n# :heart: Thank you to our [supporters](https://github.com/langroid/langroid/stargazers)\n\nIf you like this project, please give it a star ⭐ and 📢 spread the word in your network:\n\n[![Share on Twitter](https://img.shields.io/twitter/url?style=social&url=https://github.com/langroid/langroid)](https://twitter.com/intent/tweet?text=Langroid%20is%20a%20powerful,%20elegant%20new%20framework%20to%20easily%20build%20%23LLM%20applications.%20You%20set%20up%20LLM-powered%20Agents%20with%20vector-stores,%20assign%20tasks,%20and%20have%20them%20collaboratively%20solve%20problems%20via%20message-transformations.%20https://github.com/langroid/langroid)\n[![Share on LinkedIn](https://img.shields.io/badge/Share%20on-LinkedIn-blue)](https://www.linkedin.com/shareArticle?mini=true&url=https://github.com/langroid/langroid&title=Langroid:%20A%20Powerful,%20Elegant%20Framework&summary=Langroid%20is%20a%20powerful,%20elegant%20new%20framework%20to%20easily%20build%20%23LLM%20applications.%20You%20set%20up%20LLM-powered%20Agents%20with%20vector-stores,%20assign%20tasks,%20and%20have%20them%20collaboratively%20solve%20problems%20via%20message-transformations.)\n\n\n\n\nYour support will help build Langroid\'s momentum and community.\n\n\n\n\n# Langroid Co-Founders\n\n- [Prasad Chalasani](https://www.linkedin.com/in/pchalasani/) (IIT BTech/CS, CMU PhD/ML; Independent ML Consultant)\n- [Somesh Jha](https://www.linkedin.com/in/somesh-jha-80208015/) (IIT BTech/CS, CMU PhD/CS; Professor of CS, U Wisc at Madison)\n\n\n\n',
81
+ 'author': 'Prasad Chalasani',
82
+ 'author_email': 'pchalasani@gmail.com',
83
+ 'maintainer': 'None',
84
+ 'maintainer_email': 'None',
85
+ 'url': 'None',
86
+ 'packages': packages,
87
+ 'package_data': package_data,
88
+ 'install_requires': install_requires,
89
+ 'extras_require': extras_require,
90
+ 'python_requires': '>=3.8.1,<3.12',
91
+ }
92
+
93
+
94
+ setup(**setup_kwargs)
langroid-0.1.39/setup.py DELETED
@@ -1,93 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- from setuptools import setup
3
-
4
- packages = \
5
- ['langroid',
6
- 'langroid.agent',
7
- 'langroid.agent.special',
8
- 'langroid.agent.stateless_tools',
9
- 'langroid.cachedb',
10
- 'langroid.embedding_models',
11
- 'langroid.language_models',
12
- 'langroid.parsing',
13
- 'langroid.prompts',
14
- 'langroid.scripts',
15
- 'langroid.utils',
16
- 'langroid.utils.llms',
17
- 'langroid.utils.output',
18
- 'langroid.utils.web',
19
- 'langroid.vector_store']
20
-
21
- package_data = \
22
- {'': ['*']}
23
-
24
- install_requires = \
25
- ['autopep8>=2.0.2,<3.0.0',
26
- 'black[jupyter]>=23.3.0,<24.0.0',
27
- 'bs4>=0.0.1,<0.0.2',
28
- 'chromadb>=0.3.21,<0.4.0',
29
- 'colorlog>=6.7.0,<7.0.0',
30
- 'faker>=18.9.0,<19.0.0',
31
- 'fakeredis>=2.12.1,<3.0.0',
32
- 'fire>=0.5.0,<0.6.0',
33
- 'flake8>=6.0.0,<7.0.0',
34
- 'google-api-python-client>=2.95.0,<3.0.0',
35
- 'halo>=0.0.31,<0.0.32',
36
- 'lxml>=4.9.3,<5.0.0',
37
- 'mkdocs-awesome-pages-plugin>=2.8.0,<3.0.0',
38
- 'mkdocs-gen-files>=0.4.0,<0.5.0',
39
- 'mkdocs-jupyter>=0.24.1,<0.25.0',
40
- 'mkdocs-literate-nav>=0.6.0,<0.7.0',
41
- 'mkdocs-material>=9.1.5,<10.0.0',
42
- 'mkdocs-section-index>=0.3.5,<0.4.0',
43
- 'mkdocs>=1.4.2,<2.0.0',
44
- 'mkdocstrings[python]>=0.21.2,<0.22.0',
45
- 'momento>=1.7.0,<2.0.0',
46
- 'mypy>=1.2.0,<2.0.0',
47
- 'nltk>=3.8.1,<4.0.0',
48
- 'openai>=0.27.5,<0.28.0',
49
- 'pandas>=2.0.3,<3.0.0',
50
- 'pre-commit>=3.3.2,<4.0.0',
51
- 'prettytable>=3.8.0,<4.0.0',
52
- 'pydantic==1.10.11',
53
- 'pygithub>=1.58.1,<2.0.0',
54
- 'pygments>=2.15.1,<3.0.0',
55
- 'pyparsing>=3.0.9,<4.0.0',
56
- 'pypdf>=3.12.2,<4.0.0',
57
- 'python-dotenv>=1.0.0,<2.0.0',
58
- 'qdrant-client>=1.3.1,<2.0.0',
59
- 'redis>=4.5.5,<5.0.0',
60
- 'requests-oauthlib>=1.3.1,<2.0.0',
61
- 'requests>=2.31.0,<3.0.0',
62
- 'rich>=13.3.4,<14.0.0',
63
- 'ruff>=0.0.270,<0.0.271',
64
- 'sqlalchemy>=2.0.19,<3.0.0',
65
- 'tiktoken>=0.3.3,<0.4.0',
66
- 'trafilatura>=1.5.0,<2.0.0',
67
- 'typer>=0.7.0,<0.8.0',
68
- 'types-redis>=4.5.5.2,<5.0.0.0',
69
- 'types-requests>=2.31.0.1,<3.0.0.0',
70
- 'wget>=3.2,<4.0']
71
-
72
- extras_require = \
73
- {'hf-embeddings': ['sentence-transformers==2.2.2', 'torch==2.0.0']}
74
-
75
- setup_kwargs = {
76
- 'name': 'langroid',
77
- 'version': '0.1.39',
78
- 'description': 'Harness LLMs with Multi-Agent Programming',
79
- 'long_description': '<div align="center">\n <img src="docs/assets/langroid-card-lambda-ossem-rust-1200-630.png" alt="Logo" \n width="400" align="center">\n</div>\n\n<div align="center">\n\n[![Pytest](https://github.com/langroid/langroid/actions/workflows/pytest.yml/badge.svg)](https://github.com/langroid/langroid/actions/workflows/pytest.yml)\n[![codecov](https://codecov.io/gh/langroid/langroid/branch/main/graph/badge.svg?token=H94BX5F0TE)](https://codecov.io/gh/langroid/langroid)\n[![Lint](https://github.com/langroid/langroid/actions/workflows/validate.yml/badge.svg)](https://github.com/langroid/langroid/actions/workflows/validate.yml)\n[![Docs](https://github.com/langroid/langroid/actions/workflows/mkdocs-deploy.yml/badge.svg)](https://github.com/langroid/langroid/actions/workflows/mkdocs-deploy.yml)\n[![Static Badge](https://img.shields.io/badge/Documentation-blue?link=https%3A%2F%2Flangroid.github.io%2Flangroid%2F&link=https%3A%2F%2Flangroid.github.io%2Flangroid%2F)](https://langroid.github.io/langroid)\n[![Static Badge](https://img.shields.io/badge/Discord-orange?logoColor=orange&link=https%3A%2F%2Fdiscord.gg%2FZU36McDgDs)](https://discord.gg/ZU36McDgDs)\n[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langroid/langroid/blob/main/examples/langroid_quick_examples.ipynb)\n\n\n</div>\n\n<h3 align="center">\n <a target="_blank" \n href="https://langroid.github.io/langroid/" rel="dofollow">\n <strong>Documentation</strong></a>\n &middot;\n <a target="_blank" href="https://github.com/langroid/langroid-examples" rel="dofollow">\n <strong>Examples Repo</strong></a>\n &middot;\n <a target="_blank" href="https://discord.gg/ZU36McDgDs" rel="dofollow">\n <strong>Discord</strong></a>\n &middot;\n <a target="_blank" href="./CONTRIBUTING.md" rel="dofollow">\n <strong>Contributing</strong></a>\n\n <br />\n</h3>\n\n`Langroid` is an intuitive, lightweight, extensible and principled\nPython framework to easily build LLM-powered applications. \nYou set up Agents, equip them with optional components (LLM, \nvector-store and methods), assign them tasks, and have them \ncollaboratively solve a problem by exchanging messages. \nThis Multi-Agent paradigm is inspired by the\n[Actor Framework](https://en.wikipedia.org/wiki/Actor_model)\n(but you do not need to know anything about this!).\nWe welcome contributions -- See the [contributions](./CONTRIBUTING.md) document\nfor ideas on what to contribute.\n\n**Questions, Feedback, Ideas? Join us on [Discord](https://discord.gg/ZU36McDgDs)!**\n\n<details>\n<summary> <b>:fire: Updates/Releases</b></summary>\n\n- **Aug 2023:**\n - **0.1.38:** [`GoogleSearchTool`](langroid/agent/stateless_tools/google_search_tool.py) to enable Agents (their LLM) to do Google searches via function-calling/tools.\n See [this chat example](examples/basic/chat-search.py) for how easy it is to add this tool to an agent.\n - **Colab notebook** to try the quick-start examples: [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langroid/langroid/blob/main/examples/langroid_quick_examples.ipynb) \n - **0.1.37:** Added [`SQLChatAgent`](langroid/agent/special/sql_chat_agent.py) -- thanks to our latest contributor [Rithwik Babu](https://github.com/rithwikbabu)!\n - Multi-agent Example: [Autocorrect chat](examples/basic/autocorrect.py)\n- **July 2023:** \n - **0.1.30:** Added [`TableChatAgent`](langroid/agent/special/table_chat_agent.py) to \n [chat](examples/data-qa/table_chat.py) with tabular datasets (dataframes, files, URLs): LLM generates Pandas code,\n and code is executed using Langroid\'s tool/function-call mechanism. \n - **Demo:** 3-agent system for Audience [Targeting](https://langroid.github.io/langroid/demos/targeting/audience-targeting/).\n - **0.1.27**: Added [support](langroid/cachedb/momento_cachedb.py) \n for [Momento Serverless Cache](https://www.gomomento.com/) as an alternative to Redis.\n - **0.1.24**: [`DocChatAgent`](langroid/agent/special/doc_chat_agent.py) \n now [accepts](langroid/parsing/pdf_parser.py) PDF files or URLs.\n\n</details>\n\n# :rocket: Demo\nSuppose you want to extract structured information about the key terms \nof a commercial lease document. You can easily do this with Langroid using a two-agent system,\nas we show in the [langroid-examples](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py) repo.\nThe demo showcases just a few of the many features of Langroid, such as:\n- Multi-agent collaboration: `LeaseExtractor` is in charge of the task, and its LLM (GPT4) generates questions \nto be answered by the `DocAgent`.\n- Retrieval augmented question-answering, with **source-citation**: `DocAgent` LLM (GPT4) uses retrieval from a vector-store to \nanswer the `LeaseExtractor`\'s questions, cites the specific excerpt supporting the answer. \n- Function-calling (also known as tool/plugin): When it has all the information it \nneeds, the `LeaseExtractor` LLM presents the information in a structured \nformat using a Function-call. \n\nHere is what it looks like in action:\n\n![Demo](docs/assets/demos/lease-extractor-demo.gif)\n\n\n# :zap: Highlights\n\n- **Agents as first-class citizens:** The [Agent](https://langroid.github.io/langroid/reference/agent/base/#langroid.agent.base.Agent) class encapsulates LLM conversation state,\n and optionally a vector-store and tools. Agents are a core abstraction in Langroid;\n Agents act as _message transformers_, and by default provide 3 _responder_ methods, one corresponding to each entity: LLM, Agent, User.\n- **Tasks:** A [Task](https://langroid.github.io/langroid/reference/agent/task/) class wraps an Agent, and gives the agent instructions (or roles, or goals), \n manages iteration over an Agent\'s responder methods, \n and orchestrates multi-agent interactions via hierarchical, recursive\n task-delegation. The `Task.run()` method has the same \n type-signature as an Agent\'s responder\'s methods, and this is key to how \n a task of an agent can delegate to other sub-tasks: from the point of view of a Task,\n sub-tasks are simply additional responders, to be used in a round-robin fashion \n after the agent\'s own responders.\n- **Modularity, Reusabilily, Loose coupling:** The `Agent` and `Task` abstractions allow users to design\n Agents with specific skills, wrap them in Tasks, and combine tasks in a flexible way.\n- **LLM Support**: Langroid supports OpenAI LLMs including GPT-3.5-Turbo,\n GPT-4-0613\n- **Caching of LLM responses:** Langroid supports [Redis](https://redis.com/try-free/) and \n [Momento](https://www.gomomento.com/) to cache LLM responses.\n- **Vector-stores**: [Qdrant](https://qdrant.tech/) and [Chroma](https://www.trychroma.com/) are currently supported.\n Vector stores allow for Retrieval-Augmented-Generation (RAG).\n- **Grounding and source-citation:** Access to external documents via vector-stores \n allows for grounding and source-citation.\n- **Observability, Logging, Lineage:** Langroid generates detailed logs of multi-agent interactions and\n maintains provenance/lineage of messages, so that you can trace back\n the origin of a message.\n- **Tools/Plugins/Function-calling**: Langroid supports OpenAI\'s recently\n released [function calling](https://platform.openai.com/docs/guides/gpt/function-calling)\n feature. In addition, Langroid has its own native equivalent, which we\n call **tools** (also known as "plugins" in other contexts). Function\n calling and tools have the same developer-facing interface, implemented\n using [Pydantic](https://docs.pydantic.dev/latest/),\n which makes it very easy to define tools/functions and enable agents\n to use them. Benefits of using Pydantic are that you never have to write\n complex JSON specs for function calling, and when the LLM\n hallucinates malformed JSON, the Pydantic error message is sent back to\n the LLM so it can fix it!\n\n--- \n\n# :gear: Installation and Setup\n\n### Install `langroid`\nLangroid requires Python 3.11+. We recommend using a virtual environment.\nUse `pip` to install `langroid` (from PyPi) to your virtual environment:\n```bash\npip install langroid\n```\nThe core Langroid package lets you use OpenAI Embeddings models via their API. \nIf you instead want to use the `all-MiniLM-L6-v2` embeddings model\nfrom from HuggingFace, install Langroid like this:\n```bash\npip install langroid[hf-embeddings]\n```\nNote that this will install `torch` and `sentence-transformers` libraries.\n\n### Set up environment variables (API keys, etc)\n\nTo get started, all you need is an OpenAI API Key.\nIf you don\'t have one, see [this OpenAI Page](https://help.openai.com/en/collections/3675940-getting-started-with-openai-api).\nCurrently only OpenAI models are supported. Others will be added later\n(Pull Requests welcome!).\n\nIn the root of the repo, copy the `.env-template` file to a new file `.env`: \n```bash\ncp .env-template .env\n```\nThen insert your OpenAI API Key. \nYour `.env` file should look like this:\n```bash\nOPENAI_API_KEY=your-key-here-without-quotes\n````\n\nAlternatively, you can set this as an environment variable in your shell\n(you will need to do this every time you open a new shell):\n```bash\nexport OPENAI_API_KEY=your-key-here-without-quotes\n```\n\n\n<details>\n<summary><b>Optional Setup Instructions (click to expand) </b></summary>\n\nAll of the below are optional and not strictly needed to run any of the examples.\n\n- **Qdrant** Vector Store API Key, URL. This is only required if you want to use Qdrant cloud.\n You can sign up for a free 1GB account at [Qdrant cloud](https://cloud.qdrant.io).\n If you skip setting up these, Langroid will use Qdrant in local-storage mode.\n Alternatively [Chroma](https://docs.trychroma.com/) is also currently supported. \n We use the local-storage version of Chroma, so there is no need for an API key.\n Langroid uses Qdrant by default.\n- **Redis** Password, host, port: This is optional, and only needed to cache LLM API responses\n using Redis Cloud. Redis [offers](https://redis.com/try-free/) a free 30MB Redis account\n which is more than sufficient to try out Langroid and even beyond.\n If you don\'t set up these, Langroid will use a pure-python \n Redis in-memory cache via the [Fakeredis](https://fakeredis.readthedocs.io/en/latest/) library.\n- **Momento** Serverless Caching of LLM API responses (as an alternative to Redis). \n To use Momento instead of Redis:\n - enter your Momento Token in the `.env` file, as the value of `MOMENTO_AUTH_TOKEN` (see example file below),\n - in the `.env` file set `CACHE_TYPE=momento` (instead of `CACHE_TYPE=redis` which is the default).\n- **GitHub** Personal Access Token (required for apps that need to analyze git\n repos; token-based API calls are less rate-limited). See this\n [GitHub page](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens).\n- **Google Custom Search API Credentials:** Only needed to enable an Agent to use the `GoogleSearchTool`.\n To use Google Search as an LLM Tool/Plugin/function-call, \n you\'ll need to set up \n [a Google API key](https://developers.google.com/custom-search/v1/introduction#identify_your_application_to_google_with_api_key),\n then [setup a Google Custom Search Engine (CSE) and get the CSE ID](https://developers.google.com/custom-search/docs/tutorial/creatingcse).\n (Documentation for these can be challenging, we suggest asking GPT4 for a step-by-step guide.)\n After obtaining these credentials, store them as values of \n `GOOGLE_API_KEY` and `GOOGLE_CSE_ID` in your `.env` file. \n Full documentation on using this (and other such "stateless" tools) is coming soon, but \n in the meantime take a peek at this [chat example](examples/basic/chat-search.py), which \n shows how you can easily equip an Agent with a `GoogleSearchtool`.\n \n\n\nIf you add all of these optional variables, your `.env` file should look like this:\n```bash\nOPENAI_API_KEY=your-key-here-without-quotes\nGITHUB_ACCESS_TOKEN=your-personal-access-token-no-quotes\nCACHE_TYPE=redis # or momento\nREDIS_PASSWORD=your-redis-password-no-quotes\nREDIS_HOST=your-redis-hostname-no-quotes\nREDIS_PORT=your-redis-port-no-quotes\nMOMENTO_AUTH_TOKEN=your-momento-token-no-quotes # instead of REDIS* variables\nQDRANT_API_KEY=your-key\nQDRANT_API_URL=https://your.url.here:6333 # note port number must be included\nGOOGLE_API_KEY=your-key\nGOOGLE_CSE_ID=your-cse-id\n```\n</details>\n\n---\n\n# :tada: Usage Examples\n\nThese are quick teasers to give a glimpse of what you can do with Langroid\nand how your code would look. \n\n:warning: The code snippets below are intended to give a flavor of the code\nand they are **not** complete runnable examples! For that we encourage you to \nconsult the [`langroid-examples`](https://github.com/langroid/langroid-examples) \nrepository.\n\n:information_source: The various LLM prompts and instructions in Langroid\nhave been tested to work well with GPT4.\nSwitching to GPT3.5-Turbo is easy via a config flag\n(e.g., `cfg = OpenAIGPTConfig(chat_model=OpenAIChatModel.GPT3_5_TURBO)`),\nand may suffice for some applications, but in general you may see inferior results.\n\n\n:book: Also see the\n[`Getting Started Guide`](https://langroid.github.io/langroid/quick-start/)\nfor a detailed tutorial.\n\nClick to expand any of the code examples below.\nAll of these can be run in a Colab notebook:\n[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langroid/langroid/blob/main/examples/langroid_quick_examples.ipynb)\n\n<details>\n<summary> <b> Direct interaction with OpenAI LLM </b> </summary>\n\n```python\nfrom langroid.language_models.openai_gpt import ( \n OpenAIGPTConfig, OpenAIChatModel, OpenAIGPT,\n)\nfrom langroid.language_models.base import LLMMessage, Role\n\ncfg = OpenAIGPTConfig(chat_model=OpenAIChatModel.GPT4)\n\nmdl = OpenAIGPT(cfg)\n\nmessages = [\n LLMMessage(content="You are a helpful assistant", role=Role.SYSTEM), \n LLMMessage(content="What is the capital of Ontario?", role=Role.USER),\n]\nresponse = mdl.chat(messages, max_tokens=200)\nprint(response.message)\n```\n</details>\n\n<details>\n<summary> <b> Define an agent, set up a task, and run it </b> </summary>\n\n```python\nfrom langroid.agent.chat_agent import ChatAgent, ChatAgentConfig\nfrom langroid.agent.task import Task\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\n\nconfig = ChatAgentConfig(\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb=None, # no vector store\n)\nagent = ChatAgent(config)\n# get response from agent\'s LLM, and put this in an interactive loop...\n# answer = agent.llm_response("What is the capital of Ontario?")\n # ... OR instead, set up a task (which has a built-in loop) and run it\ntask = Task(agent, name="Bot") \ntask.run() # ... a loop seeking response from LLM or User at each turn\n```\n</details>\n\n<details>\n<summary><b> Three communicating agents </b></summary>\n\n```python\n\nA toy numbers game, where when given a number `n`:\n- `repeater_agent`\'s LLM simply returns `n`,\n- `even_agent`\'s LLM returns `n/2` if `n` is even, else says "DO-NOT-KNOW"\n- `odd_agent`\'s LLM returns `3*n+1` if `n` is odd, else says "DO-NOT-KNOW"\n\nFirst define the 3 agents, and set up their tasks with instructions:\n\n```python\nfrom langroid.utils.constants import NO_ANSWER\nfrom langroid.agent.chat_agent import ChatAgent, ChatAgentConfig\nfrom langroid.agent.task import Task\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\nconfig = ChatAgentConfig(\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb = None,\n)\nrepeater_agent = ChatAgent(config)\nrepeater_task = Task(\n repeater_agent,\n name = "Repeater",\n system_message="""\n Your job is to repeat whatever number you receive.\n """,\n llm_delegate=True, # LLM takes charge of task\n single_round=False, \n)\neven_agent = ChatAgent(config)\neven_task = Task(\n even_agent,\n name = "EvenHandler",\n system_message=f"""\n You will be given a number. \n If it is even, divide by 2 and say the result, nothing else.\n If it is odd, say {NO_ANSWER}\n """,\n single_round=True, # task done after 1 step() with valid response\n)\n\nodd_agent = ChatAgent(config)\nodd_task = Task(\n odd_agent,\n name = "OddHandler",\n system_message=f"""\n You will be given a number n. \n If it is odd, return (n*3+1), say nothing else. \n If it is even, say {NO_ANSWER}\n """,\n single_round=True, # task done after 1 step() with valid response\n)\n```\nThen add the `even_task` and `odd_task` as sub-tasks of `repeater_task`, \nand run the `repeater_task`, kicking it off with a number as input:\n```python\nrepeater_task.add_sub_task([even_task, odd_task])\nrepeater_task.run("3")\n```\n\n</details>\n\n<details>\n<summary><b> Simple Tool/Function-calling example </b></summary>\n\nLangroid leverages Pydantic to support OpenAI\'s\n[Function-calling API](https://platform.openai.com/docs/guides/gpt/function-calling)\nas well as its own native tools. The benefits are that you don\'t have to write\nany JSON to specify the schema, and also if the LLM hallucinates a malformed\ntool syntax, Langroid sends the Pydantic validation error (suitiably sanitized) \nto the LLM so it can fix it!\n\nSimple example: Say the agent has a secret list of numbers, \nand we want the LLM to find the smallest number in the list. \nWe want to give the LLM a `probe` tool/function which takes a\nsingle number `n` as argument. The tool handler method in the agent\nreturns how many numbers in its list are at most `n`.\n\nFirst define the tool using Langroid\'s `ToolMessage` class:\n\n\n```python\nfrom langroid.agent.tool_message import ToolMessage\nclass ProbeTool(ToolMessage):\n request: str = "probe" # specifies which agent method handles this tool\n purpose: str = """\n To find how many numbers in my list are less than or equal to \n the <number> you specify.\n """ # description used to instruct the LLM on when/how to use the tool\n number: int # required argument to the tool\n```\n\nThen define a `SpyGameAgent` as a subclass of `ChatAgent`, \nwith a method `probe` that handles this tool:\n\n```python\nfrom langroid.agent.chat_agent import ChatAgent, ChatAgentConfig\nclass SpyGameAgent(ChatAgent):\n def __init__(self, config: ChatAgentConfig):\n super().__init__(config)\n self.numbers = [3, 4, 8, 11, 15, 25, 40, 80, 90]\n\n def probe(self, msg: ProbeTool) -> str:\n # return how many numbers in self.numbers are less or equal to msg.number\n return str(len([n for n in self.numbers if n <= msg.number]))\n```\n\nWe then instantiate the agent and enable it to use and respond to the tool:\n\n```python\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\nspy_game_agent = SpyGameAgent(\n ChatAgentConfig(\n name="Spy",\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb=None,\n use_tools=False, # don\'t use Langroid native tool\n use_functions_api=True, # use OpenAI function-call API\n )\n)\nspy_game_agent.enable_message(ProbeTool)\n```\n\nFor a full working example see the\n[chat-agent-tool.py](https://github.com/langroid/langroid-examples/blob/main/examples/quick-start/chat-agent-tool.py)\nscript in the `langroid-examples` repo.\n</details>\n\n<details>\n<summary> <b>Tool/Function-calling to extract structured information from text </b> </summary>\n\nSuppose you want an agent to extract \nthe key terms of a lease, from a lease document, as a nested JSON structure.\nFirst define the desired structure via Pydantic models:\n\n```python\nfrom pydantic import BaseModel\nclass LeasePeriod(BaseModel):\n start_date: str\n end_date: str\n\n\nclass LeaseFinancials(BaseModel):\n monthly_rent: str\n deposit: str\n\nclass Lease(BaseModel):\n period: LeasePeriod\n financials: LeaseFinancials\n address: str\n```\n\nThen define the `LeaseMessage` tool as a subclass of Langroid\'s `ToolMessage`.\nNote the tool has a required argument `terms` of type `Lease`:\n\n```python\nclass LeaseMessage(ToolMessage):\n request: str = "lease_info"\n purpose: str = """\n Collect information about a Commercial Lease.\n """\n terms: Lease\n```\n\nThen define a `LeaseExtractorAgent` with a method `lease_info` that handles this tool,\ninstantiate the agent, and enable it to use and respond to this tool:\n\n```python\nclass LeaseExtractorAgent(ChatAgent):\n def lease_info(self, message: LeaseMessage) -> str:\n print(\n f"""\n DONE! Successfully extracted Lease Info:\n {message.terms}\n """\n )\n return json.dumps(message.terms.dict())\n \nlease_extractor_agent = LeaseExtractorAgent(\n ChatAgentConfig(\n llm=OpenAIGPTConfig(),\n use_functions_api=False,\n use_tools=True,\n )\n)\nlease_extractor_agent.enable_message(LeaseMessage)\n```\n\nSee the [`chat_multi_extract.py`](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py)\nscript in the `langroid-examples` repo for a full working example.\n</details>\n\n<details>\n<summary><b> Chat with documents (file paths, URLs, etc) </b></summary>\n\nLangroid provides a specialized agent class `DocChatAgent` for this purpose.\nIt incorporates document sharding, embedding, storage in a vector-DB, \nand retrieval-augmented query-answer generation.\nUsing this class to chat with a collection of documents is easy.\nFirst create a `DocChatAgentConfig` instance, with a \n`doc_paths` field that specifies the documents to chat with.\n\n```python\nfrom langroid.agent.doc_chat_agent import DocChatAgentConfig\nconfig = DocChatAgentConfig(\n doc_paths = [\n "https://en.wikipedia.org/wiki/Language_model",\n "https://en.wikipedia.org/wiki/N-gram_language_model",\n "/path/to/my/notes-on-language-models.txt",\n ]\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb=VectorStoreConfig(\n type="qdrant",\n ),\n)\n```\n\nThen instantiate the `DocChatAgent` (this ingests the docs into the vector-store):\n\n```python\nagent = DocChatAgent(config)\n```\nThen we can either ask the agent one-off questions,\n```python\nagent.chat("What is a language model?")\n```\nor wrap it in a `Task` and run an interactive loop with the user:\n```python\nfrom langroid.task import Task\ntask = Task(agent)\ntask.run()\n```\n\nSee full working scripts in the \n[`docqa`](https://github.com/langroid/langroid-examples/tree/main/examples/docqa)\nfolder of the `langroid-examples` repo.\n</details>\n\n<details>\n<summary><b> :fire: Chat with tabular data (file paths, URLs, dataframes) </b></summary>\n\nUsing Langroid you can set up a `TableChatAgent` with a dataset (file path, URL or dataframe),\nand query it. The Agent\'s LLM generates Pandas code to answer the query, \nvia function-calling (or tool/plugin), and the Agent\'s function-handling method\nexecutes the code and returns the answer.\n\nHere is how you can do this:\n\n```python\nfrom langroid.agent.special.table_chat_agent import TableChatAgent, TableChatAgentConfig\nfrom langroid.agent.task import Task\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\n```\n\nSet up a `TableChatAgent` for a data file, URL or dataframe\n(Ensure the data table has a header row; the delimiter/separator is auto-detected):\n```python\ndataset = "https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv"\n# or dataset = "/path/to/my/data.csv"\n# or dataset = pd.read_csv("/path/to/my/data.csv")\nagent = TableChatAgent(\n config=TableChatAgentConfig(\n data=dataset, \n llm=OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n )\n)\n```\nSet up a task, and ask one-off questions like this: \n\n```python\ntask = Task(\n agent, \n name = "DataAssistant",\n default_human_response="", # to avoid waiting for user input\n)\nresult = task.run(\n "What is the average alcohol content of wines with a quality rating above 7?",\n turns=2 # return after user question, LLM fun-call/tool response, Agent code-exec result\n) \nprint(result.content)\n```\nOr alternatively, set up a task and run it in an interactive loop with the user:\n\n```python\ntask = Task(agent, name="DataAssistant")\ntask.run()\n``` \n\nFor a full working example see the \n[`table_chat.py`](https://github.com/langroid/langroid-examples/tree/main/examples/data-qa/table_chat.py)\nscript in the `langroid-examples` repo.\n\n\n</details>\n\n---\n\n# :heart: Thank you to our [supporters](https://github.com/langroid/langroid/stargazers)\n\nIf you like this repo, don\'t forget to leave a star :star: !\n\n# Contributors\n\n- Prasad Chalasani (IIT BTech/CS, CMU PhD/ML; Independent ML Consultant)\n- Somesh Jha (IIT BTech/CS, CMU PhD/CS; Professor of CS, U Wisc at Madison)\n- Mohannad Alhanahnah (Research Associate, U Wisc at Madison)\n- Ashish Hooda (IIT BTech/CS; PhD Candidate, U Wisc at Madison)\n\n',
80
- 'author': 'Prasad Chalasani',
81
- 'author_email': 'pchalasani@gmail.com',
82
- 'maintainer': 'None',
83
- 'maintainer_email': 'None',
84
- 'url': 'None',
85
- 'packages': packages,
86
- 'package_data': package_data,
87
- 'install_requires': install_requires,
88
- 'extras_require': extras_require,
89
- 'python_requires': '>=3.8.1,<3.12',
90
- }
91
-
92
-
93
- setup(**setup_kwargs)
File without changes
File without changes
File without changes