langroid 0.32.2__py3-none-any.whl → 0.33.4__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.
- {langroid-0.32.2.dist-info → langroid-0.33.4.dist-info}/METADATA +149 -123
- langroid-0.33.4.dist-info/RECORD +7 -0
- {langroid-0.32.2.dist-info → langroid-0.33.4.dist-info}/WHEEL +1 -1
- langroid-0.33.4.dist-info/entry_points.txt +4 -0
- pyproject.toml +317 -212
- langroid/__init__.py +0 -106
- langroid/agent/__init__.py +0 -41
- langroid/agent/base.py +0 -1983
- langroid/agent/batch.py +0 -398
- langroid/agent/callbacks/__init__.py +0 -0
- langroid/agent/callbacks/chainlit.py +0 -598
- langroid/agent/chat_agent.py +0 -1899
- langroid/agent/chat_document.py +0 -454
- langroid/agent/openai_assistant.py +0 -882
- langroid/agent/special/__init__.py +0 -59
- langroid/agent/special/arangodb/__init__.py +0 -0
- langroid/agent/special/arangodb/arangodb_agent.py +0 -656
- langroid/agent/special/arangodb/system_messages.py +0 -186
- langroid/agent/special/arangodb/tools.py +0 -107
- langroid/agent/special/arangodb/utils.py +0 -36
- langroid/agent/special/doc_chat_agent.py +0 -1466
- langroid/agent/special/lance_doc_chat_agent.py +0 -262
- langroid/agent/special/lance_rag/__init__.py +0 -9
- langroid/agent/special/lance_rag/critic_agent.py +0 -198
- langroid/agent/special/lance_rag/lance_rag_task.py +0 -82
- langroid/agent/special/lance_rag/query_planner_agent.py +0 -260
- langroid/agent/special/lance_tools.py +0 -61
- langroid/agent/special/neo4j/__init__.py +0 -0
- langroid/agent/special/neo4j/csv_kg_chat.py +0 -174
- langroid/agent/special/neo4j/neo4j_chat_agent.py +0 -433
- langroid/agent/special/neo4j/system_messages.py +0 -120
- langroid/agent/special/neo4j/tools.py +0 -32
- langroid/agent/special/relevance_extractor_agent.py +0 -127
- langroid/agent/special/retriever_agent.py +0 -56
- langroid/agent/special/sql/__init__.py +0 -17
- langroid/agent/special/sql/sql_chat_agent.py +0 -654
- langroid/agent/special/sql/utils/__init__.py +0 -21
- langroid/agent/special/sql/utils/description_extractors.py +0 -190
- langroid/agent/special/sql/utils/populate_metadata.py +0 -85
- langroid/agent/special/sql/utils/system_message.py +0 -35
- langroid/agent/special/sql/utils/tools.py +0 -64
- langroid/agent/special/table_chat_agent.py +0 -263
- langroid/agent/task.py +0 -2095
- langroid/agent/tool_message.py +0 -393
- langroid/agent/tools/__init__.py +0 -38
- langroid/agent/tools/duckduckgo_search_tool.py +0 -50
- langroid/agent/tools/file_tools.py +0 -234
- langroid/agent/tools/google_search_tool.py +0 -39
- langroid/agent/tools/metaphor_search_tool.py +0 -67
- langroid/agent/tools/orchestration.py +0 -303
- langroid/agent/tools/recipient_tool.py +0 -235
- langroid/agent/tools/retrieval_tool.py +0 -32
- langroid/agent/tools/rewind_tool.py +0 -137
- langroid/agent/tools/segment_extract_tool.py +0 -41
- langroid/agent/xml_tool_message.py +0 -382
- langroid/cachedb/__init__.py +0 -17
- langroid/cachedb/base.py +0 -58
- langroid/cachedb/momento_cachedb.py +0 -108
- langroid/cachedb/redis_cachedb.py +0 -153
- langroid/embedding_models/__init__.py +0 -39
- langroid/embedding_models/base.py +0 -74
- langroid/embedding_models/models.py +0 -461
- langroid/embedding_models/protoc/__init__.py +0 -0
- langroid/embedding_models/protoc/embeddings.proto +0 -19
- langroid/embedding_models/protoc/embeddings_pb2.py +0 -33
- langroid/embedding_models/protoc/embeddings_pb2.pyi +0 -50
- langroid/embedding_models/protoc/embeddings_pb2_grpc.py +0 -79
- langroid/embedding_models/remote_embeds.py +0 -153
- langroid/exceptions.py +0 -65
- langroid/language_models/__init__.py +0 -53
- langroid/language_models/azure_openai.py +0 -153
- langroid/language_models/base.py +0 -678
- langroid/language_models/config.py +0 -18
- langroid/language_models/mock_lm.py +0 -124
- langroid/language_models/openai_gpt.py +0 -1964
- langroid/language_models/prompt_formatter/__init__.py +0 -16
- langroid/language_models/prompt_formatter/base.py +0 -40
- langroid/language_models/prompt_formatter/hf_formatter.py +0 -132
- langroid/language_models/prompt_formatter/llama2_formatter.py +0 -75
- langroid/language_models/utils.py +0 -151
- langroid/mytypes.py +0 -84
- langroid/parsing/__init__.py +0 -52
- langroid/parsing/agent_chats.py +0 -38
- langroid/parsing/code_parser.py +0 -121
- langroid/parsing/document_parser.py +0 -718
- langroid/parsing/para_sentence_split.py +0 -62
- langroid/parsing/parse_json.py +0 -155
- langroid/parsing/parser.py +0 -313
- langroid/parsing/repo_loader.py +0 -790
- langroid/parsing/routing.py +0 -36
- langroid/parsing/search.py +0 -275
- langroid/parsing/spider.py +0 -102
- langroid/parsing/table_loader.py +0 -94
- langroid/parsing/url_loader.py +0 -111
- langroid/parsing/urls.py +0 -273
- langroid/parsing/utils.py +0 -373
- langroid/parsing/web_search.py +0 -155
- langroid/prompts/__init__.py +0 -9
- langroid/prompts/dialog.py +0 -17
- langroid/prompts/prompts_config.py +0 -5
- langroid/prompts/templates.py +0 -141
- langroid/pydantic_v1/__init__.py +0 -10
- langroid/pydantic_v1/main.py +0 -4
- langroid/utils/__init__.py +0 -19
- langroid/utils/algorithms/__init__.py +0 -3
- langroid/utils/algorithms/graph.py +0 -103
- langroid/utils/configuration.py +0 -98
- langroid/utils/constants.py +0 -30
- langroid/utils/git_utils.py +0 -252
- langroid/utils/globals.py +0 -49
- langroid/utils/logging.py +0 -135
- langroid/utils/object_registry.py +0 -66
- langroid/utils/output/__init__.py +0 -20
- langroid/utils/output/citations.py +0 -41
- langroid/utils/output/printing.py +0 -99
- langroid/utils/output/status.py +0 -40
- langroid/utils/pandas_utils.py +0 -30
- langroid/utils/pydantic_utils.py +0 -602
- langroid/utils/system.py +0 -286
- langroid/utils/types.py +0 -93
- langroid/vector_store/__init__.py +0 -50
- langroid/vector_store/base.py +0 -357
- langroid/vector_store/chromadb.py +0 -214
- langroid/vector_store/lancedb.py +0 -401
- langroid/vector_store/meilisearch.py +0 -299
- langroid/vector_store/momento.py +0 -278
- langroid/vector_store/qdrantdb.py +0 -468
- langroid-0.32.2.dist-info/RECORD +0 -128
- {langroid-0.32.2.dist-info → langroid-0.33.4.dist-info/licenses}/LICENSE +0 -0
@@ -1,234 +0,0 @@
|
|
1
|
-
from contextlib import chdir
|
2
|
-
from pathlib import Path
|
3
|
-
from textwrap import dedent
|
4
|
-
from typing import Callable, List, Tuple, Type
|
5
|
-
|
6
|
-
import git
|
7
|
-
|
8
|
-
from langroid.agent.tool_message import ToolMessage
|
9
|
-
from langroid.agent.xml_tool_message import XMLToolMessage
|
10
|
-
from langroid.pydantic_v1 import Field
|
11
|
-
from langroid.utils.git_utils import git_commit_file
|
12
|
-
from langroid.utils.system import create_file, list_dir, read_file
|
13
|
-
|
14
|
-
|
15
|
-
class ReadFileTool(ToolMessage):
|
16
|
-
request: str = "read_file_tool"
|
17
|
-
purpose: str = "Read the contents of a <file_path>"
|
18
|
-
file_path: str
|
19
|
-
|
20
|
-
_line_nums: bool = True # whether to add line numbers to the content
|
21
|
-
_curr_dir: Callable[[], str] | None = None
|
22
|
-
|
23
|
-
@classmethod
|
24
|
-
def create(
|
25
|
-
cls,
|
26
|
-
get_curr_dir: Callable[[], str] | None,
|
27
|
-
) -> Type["ReadFileTool"]:
|
28
|
-
"""
|
29
|
-
Create a subclass of ReadFileTool for a specific directory
|
30
|
-
|
31
|
-
Args:
|
32
|
-
get_curr_dir (callable): A function that returns the current directory.
|
33
|
-
|
34
|
-
Returns:
|
35
|
-
Type[ReadFileTool]: A subclass of the ReadFileTool class, specifically
|
36
|
-
for the current directory.
|
37
|
-
"""
|
38
|
-
|
39
|
-
class CustomReadFileTool(cls): # type: ignore
|
40
|
-
_curr_dir: Callable[[], str] | None = (
|
41
|
-
staticmethod(get_curr_dir) if get_curr_dir else None
|
42
|
-
)
|
43
|
-
|
44
|
-
return CustomReadFileTool
|
45
|
-
|
46
|
-
@classmethod
|
47
|
-
def examples(cls) -> List[ToolMessage | tuple[str, ToolMessage]]:
|
48
|
-
return [
|
49
|
-
cls(file_path="src/lib.rs"),
|
50
|
-
(
|
51
|
-
"I want to read the contents of src/main.rs",
|
52
|
-
cls(file_path="src/main.rs"),
|
53
|
-
),
|
54
|
-
]
|
55
|
-
|
56
|
-
def handle(self) -> str:
|
57
|
-
# return contents as str for LLM to read
|
58
|
-
# ASSUME: file_path should be relative to the curr_dir
|
59
|
-
try:
|
60
|
-
dir = (self._curr_dir and self._curr_dir()) or Path.cwd()
|
61
|
-
with chdir(dir):
|
62
|
-
# if file doesn't exist, return an error message
|
63
|
-
content = read_file(self.file_path, self._line_nums)
|
64
|
-
line_num_str = ""
|
65
|
-
if self._line_nums:
|
66
|
-
line_num_str = "(Line numbers added for reference only!)"
|
67
|
-
return f"""
|
68
|
-
CONTENTS of {self.file_path}:
|
69
|
-
{line_num_str}
|
70
|
-
---------------------------
|
71
|
-
{content}
|
72
|
-
"""
|
73
|
-
except FileNotFoundError:
|
74
|
-
return f"File not found: {self.file_path}"
|
75
|
-
|
76
|
-
|
77
|
-
class WriteFileTool(XMLToolMessage):
|
78
|
-
request: str = "write_file_tool"
|
79
|
-
purpose: str = """
|
80
|
-
Tool for writing <content> in a certain <language> to a <file_path>
|
81
|
-
"""
|
82
|
-
|
83
|
-
file_path: str = Field(..., description="The path to the file to write the content")
|
84
|
-
|
85
|
-
language: str = Field(
|
86
|
-
default="",
|
87
|
-
description="""
|
88
|
-
The language of the content; could be human language or programming language
|
89
|
-
""",
|
90
|
-
)
|
91
|
-
content: str = Field(
|
92
|
-
...,
|
93
|
-
description="The content to write to the file",
|
94
|
-
verbatim=True, # preserve the content as is; uses CDATA section in XML
|
95
|
-
)
|
96
|
-
_curr_dir: Callable[[], str] | None = None
|
97
|
-
_git_repo: Callable[[], git.Repo] | None = None
|
98
|
-
_commit_message: str = "Agent write file tool"
|
99
|
-
|
100
|
-
@classmethod
|
101
|
-
def create(
|
102
|
-
cls,
|
103
|
-
get_curr_dir: Callable[[], str] | None,
|
104
|
-
get_git_repo: Callable[[], str] | None,
|
105
|
-
) -> Type["WriteFileTool"]:
|
106
|
-
"""
|
107
|
-
Create a subclass of WriteFileTool with the current directory and git repo.
|
108
|
-
|
109
|
-
Args:
|
110
|
-
get_curr_dir (callable): A function that returns the current directory.
|
111
|
-
get_git_repo (callable): A function that returns the git repo.
|
112
|
-
|
113
|
-
Returns:
|
114
|
-
Type[WriteFileTool]: A subclass of the WriteFileTool class, specifically
|
115
|
-
for the current directory and git repo.
|
116
|
-
"""
|
117
|
-
|
118
|
-
class CustomWriteFileTool(cls): # type: ignore
|
119
|
-
_curr_dir: Callable[[], str] | None = (
|
120
|
-
staticmethod(get_curr_dir) if get_curr_dir else None
|
121
|
-
)
|
122
|
-
_git_repo: Callable[[], str] | None = (
|
123
|
-
staticmethod(get_git_repo) if get_git_repo else None
|
124
|
-
)
|
125
|
-
|
126
|
-
return CustomWriteFileTool
|
127
|
-
|
128
|
-
@classmethod
|
129
|
-
def examples(cls) -> List[ToolMessage | Tuple[str, ToolMessage]]:
|
130
|
-
return [
|
131
|
-
(
|
132
|
-
"""
|
133
|
-
I want to define a simple hello world python function
|
134
|
-
in a file "mycode/hello.py"
|
135
|
-
""",
|
136
|
-
cls(
|
137
|
-
file_path="mycode/hello.py",
|
138
|
-
language="python",
|
139
|
-
content="""
|
140
|
-
def hello():
|
141
|
-
print("Hello, World!")
|
142
|
-
""",
|
143
|
-
),
|
144
|
-
),
|
145
|
-
cls(
|
146
|
-
file_path="src/lib.rs",
|
147
|
-
language="rust",
|
148
|
-
content="""
|
149
|
-
fn main() {
|
150
|
-
println!("Hello, World!");
|
151
|
-
}
|
152
|
-
""",
|
153
|
-
),
|
154
|
-
cls(
|
155
|
-
file_path="docs/intro.txt",
|
156
|
-
content="""
|
157
|
-
# Introduction
|
158
|
-
This is the first sentence of the introduction.
|
159
|
-
""",
|
160
|
-
),
|
161
|
-
]
|
162
|
-
|
163
|
-
def handle(self) -> str:
|
164
|
-
curr_dir = (self._curr_dir and self._curr_dir()) or Path.cwd()
|
165
|
-
with chdir(curr_dir):
|
166
|
-
create_file(self.file_path, self.content)
|
167
|
-
msg = f"Content written to {self.file_path}"
|
168
|
-
# possibly commit the file
|
169
|
-
if self._git_repo:
|
170
|
-
git_commit_file(
|
171
|
-
self._git_repo(),
|
172
|
-
self.file_path,
|
173
|
-
self._commit_message,
|
174
|
-
)
|
175
|
-
msg += " and committed"
|
176
|
-
return msg
|
177
|
-
|
178
|
-
|
179
|
-
class ListDirTool(ToolMessage):
|
180
|
-
request: str = "list_dir_tool"
|
181
|
-
purpose: str = "List the contents of a <dir_path>"
|
182
|
-
dir_path: str
|
183
|
-
|
184
|
-
_curr_dir: Callable[[], str] | None = None
|
185
|
-
|
186
|
-
@classmethod
|
187
|
-
def create(
|
188
|
-
cls,
|
189
|
-
get_curr_dir: Callable[[], str] | None,
|
190
|
-
) -> Type["ReadFileTool"]:
|
191
|
-
"""
|
192
|
-
Create a subclass of ListDirTool for a specific directory
|
193
|
-
|
194
|
-
Args:
|
195
|
-
get_curr_dir (callable): A function that returns the current directory.
|
196
|
-
|
197
|
-
Returns:
|
198
|
-
Type[ReadFileTool]: A subclass of the ReadFileTool class, specifically
|
199
|
-
for the current directory.
|
200
|
-
"""
|
201
|
-
|
202
|
-
class CustomListDirTool(cls): # type: ignore
|
203
|
-
_curr_dir: Callable[[], str] | None = (
|
204
|
-
staticmethod(get_curr_dir) if get_curr_dir else None
|
205
|
-
)
|
206
|
-
|
207
|
-
return CustomListDirTool
|
208
|
-
|
209
|
-
@classmethod
|
210
|
-
def examples(cls) -> List[ToolMessage | tuple[str, ToolMessage]]:
|
211
|
-
return [
|
212
|
-
cls(dir_path="src"),
|
213
|
-
(
|
214
|
-
"I want to list the contents of src",
|
215
|
-
cls(dir_path="src"),
|
216
|
-
),
|
217
|
-
]
|
218
|
-
|
219
|
-
def handle(self) -> str:
|
220
|
-
# ASSUME: dir_path should be relative to the curr_dir_path
|
221
|
-
dir = (self._curr_dir and self._curr_dir()) or Path.cwd()
|
222
|
-
with chdir(dir):
|
223
|
-
contents = list_dir(self.dir_path)
|
224
|
-
|
225
|
-
if not contents:
|
226
|
-
return f"Directory not found or empty: {self.dir_path}"
|
227
|
-
contents_str = "\n".join(contents)
|
228
|
-
return dedent(
|
229
|
-
f"""
|
230
|
-
LISTING of directory {self.dir_path}:
|
231
|
-
---------------------------
|
232
|
-
{contents_str}
|
233
|
-
""".strip()
|
234
|
-
)
|
@@ -1,39 +0,0 @@
|
|
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 typing import List, Tuple
|
13
|
-
|
14
|
-
from langroid.agent.tool_message import ToolMessage
|
15
|
-
from langroid.parsing.web_search import google_search
|
16
|
-
|
17
|
-
|
18
|
-
class GoogleSearchTool(ToolMessage):
|
19
|
-
request: str = "web_search"
|
20
|
-
purpose: str = """
|
21
|
-
To search the web and return up to <num_results> links relevant to
|
22
|
-
the given <query>.
|
23
|
-
"""
|
24
|
-
query: str
|
25
|
-
num_results: int
|
26
|
-
|
27
|
-
def handle(self) -> str:
|
28
|
-
search_results = google_search(self.query, self.num_results)
|
29
|
-
# return Title, Link, Summary of each result, separated by two newlines
|
30
|
-
return "\n\n".join(str(result) for result in search_results)
|
31
|
-
|
32
|
-
@classmethod
|
33
|
-
def examples(cls) -> List["ToolMessage" | Tuple[str, "ToolMessage"]]:
|
34
|
-
return [
|
35
|
-
cls(
|
36
|
-
query="When was the Llama2 Large Language Model (LLM) released?",
|
37
|
-
num_results=3,
|
38
|
-
),
|
39
|
-
]
|
@@ -1,67 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
A tool to trigger a Metaphor 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(MetaphorSearchTool)`
|
8
|
-
|
9
|
-
NOTE: To use this tool, you need to:
|
10
|
-
|
11
|
-
* set the METAPHOR_API_KEY environment variables in
|
12
|
-
your `.env` file, e.g. `METAPHOR_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 `metaphor` extra, e.g.
|
17
|
-
`pip install langroid[metaphor]` or `poetry add langroid[metaphor]`
|
18
|
-
(it installs the `metaphor-python` package from pypi).
|
19
|
-
|
20
|
-
For more information, please refer to the official docs:
|
21
|
-
https://metaphor.systems/
|
22
|
-
"""
|
23
|
-
|
24
|
-
from typing import List, Tuple
|
25
|
-
|
26
|
-
from langroid.agent.tool_message import ToolMessage
|
27
|
-
from langroid.parsing.web_search import metaphor_search
|
28
|
-
|
29
|
-
|
30
|
-
class MetaphorSearchTool(ToolMessage):
|
31
|
-
request: str = "metaphor_search"
|
32
|
-
purpose: str = """
|
33
|
-
To search the web and return up to <num_results>
|
34
|
-
links relevant to the given <query>. When using this tool,
|
35
|
-
ONLY show the required JSON, DO NOT SAY ANYTHING ELSE.
|
36
|
-
Wait for the results of the web search, and then use them to
|
37
|
-
compose your response.
|
38
|
-
"""
|
39
|
-
query: str
|
40
|
-
num_results: int
|
41
|
-
|
42
|
-
def handle(self) -> str:
|
43
|
-
"""
|
44
|
-
Conducts a search using the metaphor API based on the provided query
|
45
|
-
and number of results by triggering a metaphor_search.
|
46
|
-
|
47
|
-
Returns:
|
48
|
-
str: A formatted string containing the titles, links, and
|
49
|
-
summaries of each search result, separated by two newlines.
|
50
|
-
"""
|
51
|
-
|
52
|
-
search_results = metaphor_search(self.query, self.num_results)
|
53
|
-
# return Title, Link, Summary of each result, separated by two newlines
|
54
|
-
results_str = "\n\n".join(str(result) for result in search_results)
|
55
|
-
return f"""
|
56
|
-
BELOW ARE THE RESULTS FROM THE WEB SEARCH. USE THESE TO COMPOSE YOUR RESPONSE:
|
57
|
-
{results_str}
|
58
|
-
"""
|
59
|
-
|
60
|
-
@classmethod
|
61
|
-
def examples(cls) -> List["ToolMessage" | Tuple[str, "ToolMessage"]]:
|
62
|
-
return [
|
63
|
-
cls(
|
64
|
-
query="When was the Llama2 Large Language Model (LLM) released?",
|
65
|
-
num_results=3,
|
66
|
-
),
|
67
|
-
]
|
@@ -1,303 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Various tools to for agents to be able to control flow of Task, e.g.
|
3
|
-
termination, routing to another agent, etc.
|
4
|
-
"""
|
5
|
-
|
6
|
-
from typing import Any, List, Tuple
|
7
|
-
|
8
|
-
from langroid.agent.chat_agent import ChatAgent
|
9
|
-
from langroid.agent.chat_document import ChatDocument
|
10
|
-
from langroid.agent.tool_message import ToolMessage
|
11
|
-
from langroid.mytypes import Entity
|
12
|
-
from langroid.pydantic_v1 import Extra
|
13
|
-
from langroid.utils.types import to_string
|
14
|
-
|
15
|
-
|
16
|
-
class AgentDoneTool(ToolMessage):
|
17
|
-
"""Tool for AGENT entity (i.e. agent_response or downstream tool handling fns) to
|
18
|
-
signal the current task is done."""
|
19
|
-
|
20
|
-
purpose: str = """
|
21
|
-
To signal the current task is done, along with an optional message <content>
|
22
|
-
of arbitrary type (default None) and an
|
23
|
-
optional list of <tools> (default empty list).
|
24
|
-
"""
|
25
|
-
request: str = "agent_done_tool"
|
26
|
-
content: Any = None
|
27
|
-
tools: List[ToolMessage] = []
|
28
|
-
# only meant for agent_response or tool-handlers, not for LLM generation:
|
29
|
-
_allow_llm_use: bool = False
|
30
|
-
|
31
|
-
def response(self, agent: ChatAgent) -> ChatDocument:
|
32
|
-
content_str = "" if self.content is None else to_string(self.content)
|
33
|
-
return agent.create_agent_response(
|
34
|
-
content=content_str,
|
35
|
-
content_any=self.content,
|
36
|
-
tool_messages=[self] + self.tools,
|
37
|
-
)
|
38
|
-
|
39
|
-
|
40
|
-
class DoneTool(ToolMessage):
|
41
|
-
"""Tool for Agent Entity (i.e. agent_response) or LLM entity (i.e. llm_response) to
|
42
|
-
signal the current task is done, with some content as the result."""
|
43
|
-
|
44
|
-
purpose: str = """
|
45
|
-
To signal the current task is done, along with an optional message <content>
|
46
|
-
of arbitrary type (default None).
|
47
|
-
"""
|
48
|
-
request: str = "done_tool"
|
49
|
-
content: str = ""
|
50
|
-
|
51
|
-
def response(self, agent: ChatAgent) -> ChatDocument:
|
52
|
-
return agent.create_agent_response(
|
53
|
-
content=self.content,
|
54
|
-
content_any=self.content,
|
55
|
-
tool_messages=[self],
|
56
|
-
)
|
57
|
-
|
58
|
-
@classmethod
|
59
|
-
def instructions(cls) -> str:
|
60
|
-
tool_name = cls.default_value("request")
|
61
|
-
return f"""
|
62
|
-
When you determine your task is finished,
|
63
|
-
use the tool `{tool_name}` to signal this,
|
64
|
-
along with any message or result, in the `content` field.
|
65
|
-
"""
|
66
|
-
|
67
|
-
|
68
|
-
class ResultTool(ToolMessage):
|
69
|
-
"""Class to use as a wrapper for sending arbitrary results from an Agent's
|
70
|
-
agent_response or tool handlers, to:
|
71
|
-
(a) trigger completion of the current task (similar to (Agent)DoneTool), and
|
72
|
-
(b) be returned as the result of the current task, i.e. this tool would appear
|
73
|
-
in the resulting ChatDocument's `tool_messages` list.
|
74
|
-
See test_tool_handlers_and_results in test_tool_messages.py, and
|
75
|
-
examples/basic/tool-extract-short-example.py.
|
76
|
-
|
77
|
-
Note:
|
78
|
-
- when defining a tool handler or agent_response, you can directly return
|
79
|
-
ResultTool(field1 = val1, ...),
|
80
|
-
where the values can be arbitrary data structures, including nested
|
81
|
-
Pydantic objs, or you can define a subclass of ResultTool with the
|
82
|
-
fields you want to return.
|
83
|
-
- This is a special ToolMessage that is NOT meant to be used or handled
|
84
|
-
by an agent.
|
85
|
-
- AgentDoneTool is more restrictive in that you can only send a `content`
|
86
|
-
or `tools` in the result.
|
87
|
-
"""
|
88
|
-
|
89
|
-
request: str = "result_tool"
|
90
|
-
purpose: str = "Ignored; Wrapper for a structured message"
|
91
|
-
id: str = "" # placeholder for OpenAI-API tool_call_id
|
92
|
-
|
93
|
-
class Config:
|
94
|
-
extra = Extra.allow
|
95
|
-
arbitrary_types_allowed = False
|
96
|
-
validate_all = True
|
97
|
-
validate_assignment = True
|
98
|
-
# do not include these fields in the generated schema
|
99
|
-
# since we don't require the LLM to specify them
|
100
|
-
schema_extra = {"exclude": {"purpose", "id", "strict"}}
|
101
|
-
|
102
|
-
def handle(self) -> AgentDoneTool:
|
103
|
-
return AgentDoneTool(tools=[self])
|
104
|
-
|
105
|
-
|
106
|
-
class FinalResultTool(ToolMessage):
|
107
|
-
"""Class to use as a wrapper for sending arbitrary results from an Agent's
|
108
|
-
agent_response or tool handlers, to:
|
109
|
-
(a) trigger completion of the current task as well as all parent tasks, and
|
110
|
-
(b) be returned as the final result of the root task, i.e. this tool would appear
|
111
|
-
in the final ChatDocument's `tool_messages` list.
|
112
|
-
See test_tool_handlers_and_results in test_tool_messages.py, and
|
113
|
-
examples/basic/chat-tool-function.py.
|
114
|
-
|
115
|
-
Note:
|
116
|
-
- when defining a tool handler or agent_response, you can directly return
|
117
|
-
FinalResultTool(field1 = val1, ...),
|
118
|
-
where the values can be arbitrary data structures, including nested
|
119
|
-
Pydantic objs, or you can define a subclass of FinalResultTool with the
|
120
|
-
fields you want to return.
|
121
|
-
- This is a special ToolMessage that is NOT meant to be used by an agent's
|
122
|
-
llm_response, but only by agent_response or tool handlers.
|
123
|
-
- A subclass of this tool can be defined, with specific fields, and
|
124
|
-
with _allow_llm_use = True, to allow the LLM to generate this tool,
|
125
|
-
and have the effect of terminating the current and all parent tasks,
|
126
|
-
with the tool appearing in the final ChatDocument's `tool_messages` list.
|
127
|
-
See examples/basic/multi-agent-return-result.py.
|
128
|
-
"""
|
129
|
-
|
130
|
-
request: str = ""
|
131
|
-
purpose: str = "Ignored; Wrapper for a structured message"
|
132
|
-
id: str = "" # placeholder for OpenAI-API tool_call_id
|
133
|
-
_allow_llm_use: bool = False
|
134
|
-
|
135
|
-
class Config:
|
136
|
-
extra = Extra.allow
|
137
|
-
arbitrary_types_allowed = False
|
138
|
-
validate_all = True
|
139
|
-
validate_assignment = True
|
140
|
-
# do not include these fields in the generated schema
|
141
|
-
# since we don't require the LLM to specify them
|
142
|
-
schema_extra = {"exclude": {"purpose", "id", "strict"}}
|
143
|
-
|
144
|
-
|
145
|
-
class PassTool(ToolMessage):
|
146
|
-
"""Tool for "passing" on the received msg (ChatDocument),
|
147
|
-
so that an as-yet-unspecified agent can handle it.
|
148
|
-
Similar to ForwardTool, but without specifying the recipient agent.
|
149
|
-
"""
|
150
|
-
|
151
|
-
purpose: str = """
|
152
|
-
To pass the current message so that other agents can handle it.
|
153
|
-
"""
|
154
|
-
request: str = "pass_tool"
|
155
|
-
|
156
|
-
def response(self, agent: ChatAgent, chat_doc: ChatDocument) -> ChatDocument:
|
157
|
-
"""When this tool is enabled for an Agent, this will result in a method
|
158
|
-
added to the Agent with signature:
|
159
|
-
`forward_tool(self, tool: PassTool, chat_doc: ChatDocument) -> ChatDocument:`
|
160
|
-
"""
|
161
|
-
# if PassTool is in chat_doc, pass its parent, else pass chat_doc itself
|
162
|
-
doc = chat_doc
|
163
|
-
while True:
|
164
|
-
tools = agent.get_tool_messages(doc)
|
165
|
-
if not any(isinstance(t, type(self)) for t in tools):
|
166
|
-
break
|
167
|
-
if doc.parent is None:
|
168
|
-
break
|
169
|
-
doc = doc.parent
|
170
|
-
assert doc is not None, "PassTool: parent of chat_doc must not be None"
|
171
|
-
new_doc = ChatDocument.deepcopy(doc)
|
172
|
-
new_doc.metadata.sender = Entity.AGENT
|
173
|
-
return new_doc
|
174
|
-
|
175
|
-
@classmethod
|
176
|
-
def instructions(cls) -> str:
|
177
|
-
return """
|
178
|
-
Use the `pass_tool` to PASS the current message
|
179
|
-
so that another agent can handle it.
|
180
|
-
"""
|
181
|
-
|
182
|
-
|
183
|
-
class DonePassTool(PassTool):
|
184
|
-
"""Tool to signal DONE, AND Pass incoming/current msg as result.
|
185
|
-
Similar to PassTool, except we append a DoneTool to the result tool_messages.
|
186
|
-
"""
|
187
|
-
|
188
|
-
purpose: str = """
|
189
|
-
To signal the current task is done, with results set to the current/incoming msg.
|
190
|
-
"""
|
191
|
-
request: str = "done_pass_tool"
|
192
|
-
|
193
|
-
def response(self, agent: ChatAgent, chat_doc: ChatDocument) -> ChatDocument:
|
194
|
-
# use PassTool to get the right ChatDocument to pass...
|
195
|
-
new_doc = PassTool.response(self, agent, chat_doc)
|
196
|
-
tools = agent.get_tool_messages(new_doc)
|
197
|
-
# ...then return an AgentDoneTool with content, tools from this ChatDocument
|
198
|
-
return AgentDoneTool(content=new_doc.content, tools=tools) # type: ignore
|
199
|
-
|
200
|
-
@classmethod
|
201
|
-
def instructions(cls) -> str:
|
202
|
-
return """
|
203
|
-
When you determine your task is finished,
|
204
|
-
and want to pass the current message as the result of the task,
|
205
|
-
use the `done_pass_tool` to signal this.
|
206
|
-
"""
|
207
|
-
|
208
|
-
|
209
|
-
class ForwardTool(PassTool):
|
210
|
-
"""Tool for forwarding the received msg (ChatDocument) to another agent or entity.
|
211
|
-
Similar to PassTool, but with a specified recipient agent.
|
212
|
-
"""
|
213
|
-
|
214
|
-
purpose: str = """
|
215
|
-
To forward the current message to an <agent>, where <agent>
|
216
|
-
could be the name of an agent, or an entity such as "user", "llm".
|
217
|
-
"""
|
218
|
-
request: str = "forward_tool"
|
219
|
-
agent: str
|
220
|
-
|
221
|
-
def response(self, agent: ChatAgent, chat_doc: ChatDocument) -> ChatDocument:
|
222
|
-
"""When this tool is enabled for an Agent, this will result in a method
|
223
|
-
added to the Agent with signature:
|
224
|
-
`forward_tool(self, tool: ForwardTool, chat_doc: ChatDocument) -> ChatDocument:`
|
225
|
-
"""
|
226
|
-
# if chat_doc contains ForwardTool, then we forward its parent ChatDocument;
|
227
|
-
# else forward chat_doc itself
|
228
|
-
new_doc = PassTool.response(self, agent, chat_doc)
|
229
|
-
new_doc.metadata.recipient = self.agent
|
230
|
-
return new_doc
|
231
|
-
|
232
|
-
@classmethod
|
233
|
-
def instructions(cls) -> str:
|
234
|
-
return """
|
235
|
-
If you need to forward the current message to another agent,
|
236
|
-
use the `forward_tool` to do so,
|
237
|
-
setting the `recipient` field to the name of the recipient agent.
|
238
|
-
"""
|
239
|
-
|
240
|
-
|
241
|
-
class SendTool(ToolMessage):
|
242
|
-
"""Tool for agent or LLM to send content to a specified agent.
|
243
|
-
Similar to RecipientTool.
|
244
|
-
"""
|
245
|
-
|
246
|
-
purpose: str = """
|
247
|
-
To send message <content> to agent specified in <to> field.
|
248
|
-
"""
|
249
|
-
request: str = "send_tool"
|
250
|
-
to: str
|
251
|
-
content: str = ""
|
252
|
-
|
253
|
-
def response(self, agent: ChatAgent) -> ChatDocument:
|
254
|
-
return agent.create_agent_response(
|
255
|
-
self.content,
|
256
|
-
recipient=self.to,
|
257
|
-
)
|
258
|
-
|
259
|
-
@classmethod
|
260
|
-
def instructions(cls) -> str:
|
261
|
-
return """
|
262
|
-
If you need to send a message to another agent,
|
263
|
-
use the `send_tool` to do so, with these field values:
|
264
|
-
- `to` field = name of the recipient agent,
|
265
|
-
- `content` field = the message to send.
|
266
|
-
"""
|
267
|
-
|
268
|
-
@classmethod
|
269
|
-
def examples(cls) -> List["ToolMessage" | Tuple[str, "ToolMessage"]]:
|
270
|
-
return [
|
271
|
-
cls(to="agent1", content="Hello, agent1!"),
|
272
|
-
(
|
273
|
-
"""
|
274
|
-
I need to send the content 'Who built the Gemini model?',
|
275
|
-
to the 'Searcher' agent.
|
276
|
-
""",
|
277
|
-
cls(to="Searcher", content="Who built the Gemini model?"),
|
278
|
-
),
|
279
|
-
]
|
280
|
-
|
281
|
-
|
282
|
-
class AgentSendTool(ToolMessage):
|
283
|
-
"""Tool for Agent (i.e. agent_response) to send content or tool_messages
|
284
|
-
to a specified agent. Similar to SendTool except that AgentSendTool is only
|
285
|
-
usable by agent_response (or handler of another tool), to send content or
|
286
|
-
tools to another agent. SendTool does not allow sending tools.
|
287
|
-
"""
|
288
|
-
|
289
|
-
purpose: str = """
|
290
|
-
To send message <content> and <tools> to agent specified in <to> field.
|
291
|
-
"""
|
292
|
-
request: str = "agent_send_tool"
|
293
|
-
to: str
|
294
|
-
content: str = ""
|
295
|
-
tools: List[ToolMessage] = []
|
296
|
-
_allow_llm_use: bool = False
|
297
|
-
|
298
|
-
def response(self, agent: ChatAgent) -> ChatDocument:
|
299
|
-
return agent.create_agent_response(
|
300
|
-
self.content,
|
301
|
-
tool_messages=self.tools,
|
302
|
-
recipient=self.to,
|
303
|
-
)
|