multi-tool xml parser + tool superclass
frdel committed
Jun 20, 2024 at 21:39 UTC
fa208ba3be27d2a4239f39043ab6666173ab17c8
16 files changed
+262
-161
agent.py
+34
-57
@@ -7,7 +7,7 @@ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
7
from langchain_core.messages import HumanMessage
8
from langchain_core.language_models.chat_models import BaseChatModel
9
10
-rate_limit = rate_limiter.rate_limiter(30,160000) #TODO! move to main.py
10
+rate_limit = rate_limiter.rate_limiter(30,160000) #TODO! implement properly
11
12
class Agent:
13
@@ -41,8 +41,6 @@ class Agent:
41
self.last_message = ""
42
self.intervention_message = ""
43
self.intervention_status = False
44
- self.stop_loop = False
45
- self.loop_result = []
44
45
self.data = {} # free data object all the tools can use
46
@@ -90,13 +88,9 @@ class Agent:
88
89
self.append_message(agent_response) # Append the assistant's response to the history
90
93
- self.process_tools(agent_response)
91
+ tools_result = self.process_tools(agent_response) # process tools requested in agent message
92
+ if tools_result: return tools_result #break the execution if the task is done
93
95
- #break the execution if the task is done
96
- if self.stop_loop:
97
- return "\n\n".join(self.loop_result)
98
-
99
-
94
# Forward errors to the LLM, maybe he can fix them
95
except Exception as e:
96
msg_response = files.read_file("./prompts/fw.error.md", error=str(e)) # error message template
@@ -116,14 +110,6 @@ class Agent:
110
def set_data(self, field:str, value):
111
self.data[field] = value
112
119
- def set_result(self, result:str):
120
- self.stop_loop = True
121
- self.loop_results = [result]
122
-
123
- def add_result(self, result:str):
124
- self.stop_loop = True
125
- self.loop_result.append(result)
126
-
113
def append_message(self, msg: str, human: bool = False):
114
message_type = "human" if human else "ai"
115
if self.history and self.history[-1].type == message_type:
@@ -164,50 +150,41 @@ class Agent:
150
def process_tools(self, msg: str):
151
# search for tool usage requests in agent message
152
tool_requests = extract_tools.extract_tool_requests2(msg)
167
- tool_index = 0
168
-
169
- for tool_request in tool_requests:
170
- tool_index += 1
153
172
- if self.handle_intervention(): break # wait if paused and handle intervention message if needed
173
-
174
- tool_name = tool_request["name"]
175
- tool_function = self.get_tool(tool_name)
176
- tool_args = tool_request["args"] or {}
154
+ #build tools
155
+ tools = []
156
+ for tool_request in tool_requests:
157
+ tools.append(
158
+ self.get_tool(
159
+ tool_request["name"],
160
+ tool_request["content"],
161
+ tool_request["args"],
162
+ len(tools),
163
+ msg,
164
+ tools))
165
178
- if callable(tool_function):
179
-
180
- PrintStyle(font_color="#1B4F72", padding=True, background_color="white", bold=True).print(f"{self.name}: Using tool {tool_name}:")
181
- PrintStyle(font_color="#85C1E9").print(tool_args, tool_request["body"], sep="\n") if tool_args else PrintStyle(font_color="#85C1E9").print(tool_request["body"])
182
-
183
- tool_args["_name"] = tool_name
184
- tool_args["_message"] = msg
185
- tool_args["_tools"] = tool_requests
186
- tool_args["_tool_index"] = tool_index
187
-
188
- tool_response = tool_function(self, tool_request["body"], **tool_args) or "" # call tool function with all parameters, body parameter separated for convenience
189
- Agent.streaming_agent = self # mark self as current streamer again, it may have changed during tool use
190
-
191
- if self.handle_intervention(): break # wait if paused and handle intervention message if needed
166
+ for tool in tools:
167
+ if self.handle_intervention(): break # wait if paused and handle intervention message if needed
168
193
- msg_response = files.read_file("./prompts/fw.tool_response.md", tool_name=tool_name, tool_response=tool_response)
194
- self.append_message(msg_response, human=True)
195
-
196
- PrintStyle(font_color="#1B4F72", background_color="white", padding=True, bold=True).print(f"{self.name}: Response from {tool_name}:")
197
- PrintStyle(font_color="#85C1E9").print(tool_response)
198
- else:
199
- if self.handle_intervention(): break # wait if paused and handle intervention message if needed
200
- msg_response = files.read_file("./prompts/fw.tool_not_found.md", tool_name=tool_name, tools_prompt=self.tools_prompt)
201
- self.append_message(msg_response,True)
202
- PrintStyle(font_color="orange", padding=True).print(msg_response)
169
+ tool.before_execution()
170
+ response = tool.execute()
171
+ tool.after_execution(response)
172
+ if response.break_loop: return response.message
173
+ if response.stop_tool_processing: break
174
175
176
+ def get_tool(self, name: str, content: str, args: dict, index: int, message: str, tools: list, **kwargs):
177
+ from tools.unknown import Unknown
178
+ from tools.helpers.tool import Tool
179
+
180
+ tool_class = Unknown
181
+ if files.exists("tools",f"{name}.py"):
182
+ module = importlib.import_module("tools." + name) # Import the module
183
+ class_list = inspect.getmembers(module, inspect.isclass) # Get all functions in the module
184
206
- def get_tool(self, name: str):
207
- if not files.exists("tools",f"{name}.py"): return # file has to exist in tools
208
- module = importlib.import_module("tools." + name) # Import the module
209
- functions_list = {name: func for name, func in inspect.getmembers(module, inspect.isfunction)} # Get all functions in the module
185
+ for cls in class_list:
186
+ if cls[1] is not Tool and issubclass(cls[1], Tool):
187
+ tool_class = cls[1]
188
+ break
189
211
- if "execute" in functions_list: return functions_list["execute"] # Check if the module contains a function named "execute"
212
- if functions_list: return next(iter(functions_list.values())) # Return the first function if no "execute" function is found
213
- return None # Return None if no functions are found
\ No newline at end of file
190
+ return tool_class(agent=self, name=name, content=content, index=index, args=args, message=message, tools=tools, **kwargs)
\ No newline at end of file
main.py
+2
-1
@@ -16,7 +16,8 @@ os.chdir(files.get_abs_path("./work_dir")) #change CWD to work_dir
16
def chat():
17
18
# chat model used for agents
19
- # chat_llm = models.get_groq_llama70b(temperature=0.2)
19
+ # chat_llm = models.get_groq_llama70b_json(temperature=0.2)
20
+ # chat_llm = models.get_groq_llama8b(temperature=0.2)
21
chat_llm = models.get_openai_gpt35(temperature=0)
22
# chat_llm = models.get_openai_gpt4o(temperature=0)
23
# chat_llm = models.get_anthropic_opus(temperature=0)
models.py
+5
@@ -54,6 +54,11 @@ def get_groq_llama70b(api_key=None, temperature=DEFAULT_TEMPERATURE):
54
api_key = api_key or get_api_key("groq")
55
return ChatGroq(model_name="llama3-70b-8192", temperature=temperature, api_key=api_key) # type: ignore
56
57
+def get_groq_llama70b_json(api_key=None, temperature=DEFAULT_TEMPERATURE):
58
+ api_key = api_key or get_api_key("groq")
59
+ return ChatGroq(model_name="llama3-70b-8192", temperature=temperature, api_key=api_key, model_kwargs={"response_format": {"type": "json_object"}}) # type: ignore
60
+
61
+
62
def get_groq_llama8b(api_key=None, temperature=DEFAULT_TEMPERATURE):
63
api_key = api_key or get_api_key("groq")
64
return ChatGroq(model_name="Llama3-8b-8192", temperature=temperature, api_key=api_key) # type: ignore
prompts/agent.system.md
+7
-6
@@ -1,17 +1,18 @@
1
# Your role
2
-- You are a fully autonomous, memory-enhanced, AI task solver, NOT a chatbot.
3
-- You solve tasks and respond to questions by user using your memory, tools, and subordinates.
2
+- You are a fully autonomous, memory-enhanced, XML, AI task solver, NOT a chatbot.
3
+- You solve tasks and respond to questions by user using your memory, tools, and subordinates in a specialized XML format.
4
- You solve tasks automatically without the user, you do not inform the user how to do it, you execute the steps necessary.
5
- You never lie or speculate about your actions, all of your actions need to be conducted by your tools.
6
- You never refuse to accomplish a task. You are capable of doing anything using your tools and subordinates.
7
8
# Communication instrucions
9
-- Your every response must be wrapped in a XML tag defining its type ending with $.
9
+- Every part of your response must be wrapped in a XML tag defining its type ending with $. This tag corresponds to a tool that will be used to handle that part of response.
10
- Possible response types are:
11
- <thought$> - Your thoughts, useful for chain of thought process, not sent to anyone. Use this for every problem solving, it will help you iterate on the topic.
12
- - <message$> - Message sent to the user. No other response types are visible to the user.
13
- - <delegation$ reset="false"> - Subtask delegation to another agent. This will help you solve more complex tasks. Use argument reset="true" to start fresh context for new subtask, "false" when sending followup questions.
14
- - <task_done$> - Final result of given task, once all steps are complete or there is nothing more to do.
12
+ You can use as many thoughts as you want, even after
13
+ - <message$> - Message sent to the user. No other response types are visible to the user. Do not use in combination with other tools.
14
+ - <delegation$ reset="false"> - Subtask delegation to another agent. This will help you solve more complex tasks. Use argument reset="true" to start fresh context for new subtask, "false" when sending followup questions. Do not use in combination with other tools.
15
+ - <task_done$> - Final result of given task, once all steps are complete or there is nothing more to do. Do not use in combination with other tools.
16
- And all other tools described in the Available tools section.
17
- <memory_tool$> - Load or save memories to your persistent memory.
18
- Your response content is inside the tag.
prompts/agent.tools.md
+4
-1
@@ -5,7 +5,8 @@ Provide question and get both online and memory response.
5
This tool is very powerful and can answer very specific questions directly.
6
First always try to ask for result rather that guidance.
7
Memory can provide guidance, online sources can provide up to date information.
8
-Alway verify memory by online.
8
+Always verify memory by online.
9
+Do not use in combination with other tools except for thoughts. Wait for response before using other tools.
10
**Example usage**:
11
<knowledge_tool$>
12
What is the user id of John Doe on twitter?
@@ -21,6 +22,7 @@ When loading memories using action "load", provide keywords or question relevant
22
When saving memories using action "save", provide a title, short summary and and all the necessary information to help you later solve similiar tasks including details like code executed, libraries used etc.
23
When deleting memories using action "delete", provide a prompt to search memories to delete.
24
Be specific with your question, do not input vague queries.
25
+Do not use in combination with other tools except for thoughts. Wait for response before using other tools.
26
**Example usages**:
27
<memory_tool$ action="load">
28
How to get current working directory in python?
@@ -45,6 +47,7 @@ When tool outputs error, you need to change your code accordingly before trying
47
If your code execution is successful, save it using <memory_tool$ action="save"> so it can be reused later.
48
Keep in mind that current working directory CWD automatically resets before every tool call.
49
IMPORTANT!: Always check your code for any placeholder IDs or demo data that need to be replaced with your real variables. Do not simply reuse code snippets from tutorials.
50
+Do not use in combination with other tools except for thoughts. Wait for response before using other tools.
51
**Example usage**:
52
<code_execution_tool$ runtime="python">
53
import os
tools/code_execution_tool.py
+27
-23
@@ -2,33 +2,37 @@ import os, json, contextlib, subprocess, ast, shlex
2
from io import StringIO
3
from tools.helpers import files, messages
4
from agent import Agent
5
+from tools.helpers.tool import Tool, Response
6
+from tools.helpers import files
7
+from tools.helpers.print_style import PrintStyle
8
9
+class Unknown(Tool):
10
7
-def execute(agent:Agent , code_text:str, runtime:str, **kwargs):
11
+ def execute(self):
12
9
- os.chdir(files.get_abs_path("./work_dir")) #change CWD to work_dir
10
-
11
- if runtime == "python":
12
- response = execute_python_code(code_text)
13
- elif runtime == "nodejs":
14
- response = execute_nodejs_code(code_text)
15
- elif runtime == "terminal":
16
- response = execute_terminal_command(code_text)
17
- else:
18
- return files.read_file("./prompts/fw.code_runtime_wrong.md", runtime=runtime)
13
+ os.chdir(files.get_abs_path("./work_dir")) #change CWD to work_dir
14
+ runtime = self.args["runtime"].lower().strip()
15
+ if runtime == "python":
16
+ response = self.execute_python_code(self.content)
17
+ elif runtime == "nodejs":
18
+ response = self.execute_nodejs_code(self.content)
19
+ elif runtime == "terminal":
20
+ response = self.execute_terminal_command(self.content)
21
+ else:
22
+ response = files.read_file("./prompts/fw.code_runtime_wrong.md", runtime=runtime)
23
20
- response = messages.truncate_text(response.strip(), 2000) # TODO parameterize
21
- if not response: response = files.read_file("./prompts/fw.code_no_output.md")
22
- return response
24
+ response = messages.truncate_text(response.strip(), 2000) # TODO parameterize
25
+ if not response: response = files.read_file("./prompts/fw.code_no_output.md")
26
+ return Response(message=response, stop_tool_processing=True, break_loop=False)
27
24
-def execute_python_code(code, input_data="y\n"):
25
- result = subprocess.run(['python', '-c', code], capture_output=True, text=True, input=input_data)
26
- return result.stdout + result.stderr
28
+ def execute_python_code(self, code, input_data="y\n"):
29
+ result = subprocess.run(['python', '-c', code], capture_output=True, text=True, input=input_data)
30
+ return result.stdout + result.stderr
31
28
-def execute_nodejs_code(code, input_data="y\n"):
29
- result = subprocess.run(['node', '-e', code], capture_output=True, text=True, input=input_data)
30
- return result.stdout + result.stderr
32
+ def execute_nodejs_code(self, code, input_data="y\n"):
33
+ result = subprocess.run(['node', '-e', code], capture_output=True, text=True, input=input_data)
34
+ return result.stdout + result.stderr
35
32
-def execute_terminal_command(command, input_data="y\n"):
33
- result = subprocess.run(command, shell=True, capture_output=True, text=True, input=input_data)
34
- return result.stdout + result.stderr
\ No newline at end of file
36
+ def execute_terminal_command(self, command, input_data="y\n"):
37
+ result = subprocess.run(command, shell=True, capture_output=True, text=True, input=input_data)
38
+ return result.stdout + result.stderr
\ No newline at end of file
tools/delegation.py
+13
-8
@@ -1,10 +1,15 @@
1
from agent import Agent
2
+from tools.helpers.tool import Tool, Response
3
+from tools.helpers import files
4
+from tools.helpers.print_style import PrintStyle
5
3
-def execute(agent:Agent, message: str, reset: str = "false", **kwargs):
4
- # create subordinate agent using the data object on this agent and set superior agent to his data object
5
- if agent.get_data("subordinate") is None or reset.lower().strip() == "true":
6
- subordinate = Agent(system_prompt=agent.system_prompt, tools_prompt=agent.tools_prompt, number=agent.number+1)
7
- subordinate.set_data("superior", agent)
8
- agent.set_data("subordinate", subordinate)
9
- # run subordinate agent message loop
10
- return agent.get_data("subordinate").message_loop(message)
\ No newline at end of file
6
+class Unknown(Tool):
7
+
8
+ def execute(self):
9
+ # create subordinate agent using the data object on this agent and set superior agent to his data object
10
+ if self.agent.get_data("subordinate") is None or self.args["reset"].lower().strip() == "true":
11
+ subordinate = Agent(system_prompt=self.agent.system_prompt, tools_prompt=self.agent.tools_prompt, number=self.agent.number+1)
12
+ subordinate.set_data("superior", self.agent)
13
+ self.agent.set_data("subordinate", subordinate)
14
+ # run subordinate agent message loop
15
+ return self.agent.get_data("subordinate").message_loop(self.content)
\ No newline at end of file
tools/helpers/extract_tools.py
+3
-2
@@ -10,7 +10,7 @@ def extract_tool_requests2(response):
10
allowed_tags = list_python_files("tools")
11
12
for match in matches:
13
- tag_name, attributes, body = match
13
+ tag_name, attributes, content = match
14
15
if tag_name not in allowed_tags: continue
16
@@ -23,7 +23,8 @@ def extract_tool_requests2(response):
23
tool_dict['args'][attr[0]] = attr[1]
24
25
# Add body content
26
- tool_dict["body"] = body.strip()
26
+ tool_dict["content"] = content.strip()
27
+ tool_dict["index"] = len(tool_usages)
28
tool_usages.append(tool_dict)
29
30
return tool_usages
tools/helpers/tool.py
new
+35
@@ -0,0 +1,35 @@
1
+from abc import abstractmethod
2
+from typing import TypedDict
3
+from agent import Agent
4
+from tools.helpers.print_style import PrintStyle
5
+from tools.helpers import files
6
+
7
+class Response:
8
+ def __init__(self, message: str, stop_tool_processing: bool, break_loop: bool) -> None:
9
+ self.message = message
10
+ self.stop_tool_processing = stop_tool_processing
11
+ self.break_loop = break_loop
12
+
13
+class Tool:
14
+
15
+ def __init__(self, agent: Agent, name: str, content: str, args: dict, message: str, tools: list['Tool'], **kwargs) -> None:
16
+ self.agent = agent
17
+ self.name = name
18
+ self.content = content
19
+ self.args = args
20
+ self.message = message
21
+ self.tools = tools
22
+
23
+ @abstractmethod
24
+ def execute(self) -> Response:
25
+ pass
26
+
27
+ def before_execution(self):
28
+ PrintStyle(font_color="#1B4F72", padding=True, background_color="white", bold=True).print(f"{self.agent.name}: Using tool {self.name}:")
29
+ PrintStyle(font_color="#85C1E9").print(self.args, self.content, sep="\n") if self.args else PrintStyle(font_color="#85C1E9").print(self.content)
30
+
31
+ def after_execution(self, response: Response):
32
+ msg_response = files.read_file("./prompts/fw.tool_response.md", tool_name=self.name, tool_response=response.message)
33
+ self.agent.append_message(msg_response, human=True)
34
+ PrintStyle(font_color="#1B4F72", background_color="white", padding=True, bold=True).print(f"{self.agent.name}: Response from {self.name}:")
35
+ PrintStyle(font_color="#85C1E9").print(response.message)
\ No newline at end of file
tools/knowledge_tool.py
+16
-9
@@ -3,14 +3,21 @@ from . import online_knowledge_tool
3
from . import memory_tool
4
import concurrent.futures
5
6
-def execute(agent, question, **kwargs):
7
- with concurrent.futures.ThreadPoolExecutor() as executor:
8
- # Schedule the two functions to be run in parallel
9
- future_online = executor.submit(online_knowledge_tool.execute, agent, question)
10
- future_memory = executor.submit(memory_tool.execute, agent, question)
6
12
- # Wait for both functions to complete
13
- online_result = future_online.result()
14
- memory_result = future_memory.result()
7
16
- return f"# Online sources:\n{online_result}\n\n# Memory:\n{memory_result}"
\ No newline at end of file
8
+from tools.helpers.tool import Tool, Response
9
+from tools.helpers import files
10
+
11
+class Knowledge(Tool):
12
+ def execute(self):
13
+ with concurrent.futures.ThreadPoolExecutor() as executor:
14
+ # Schedule the two functions to be run in parallel
15
+ future_online = executor.submit(online_knowledge_tool.process_question, self.content)
16
+ future_memory = executor.submit(memory_tool.process_query, self.agent, self.content)
17
+
18
+ # Wait for both functions to complete
19
+ online_result = future_online.result()
20
+ memory_result = future_memory.result()
21
+
22
+ result = f"# Online sources:\n{online_result}\n\n# Memory:\n{memory_result}"
23
+ return Response(message=result, stop_tool_processing=True, break_loop=False)
\ No newline at end of file
tools/memory_tool.py
+11
-1
@@ -2,17 +2,27 @@ from agent import Agent
2
from tools.helpers.vector_db import VectorDB, Document
3
from tools.helpers import files
4
import os, json
5
+from tools.helpers.tool import Tool, Response
6
+from tools.helpers.print_style import PrintStyle
7
8
db: VectorDB
9
result_count = 3 #TODO parametrize better
10
11
+
12
+class Memory(Tool):
13
+ def execute(self):
14
+ result = process_query(self.agent, self.content,self.args["action"])
15
+ return Response(message=result, stop_tool_processing=True, break_loop=False)
16
+
17
+
18
def initialize(embeddings_model,messages_returned=3, subdir=""):
19
global db, result_count
20
dir = os.path.join("memory",subdir)
21
db = VectorDB(embeddings_model=embeddings_model, in_memory=False, cache_dir=dir)
22
result_count = messages_returned
23
15
-def execute(agent:Agent, message: str, action: str = "load", **kwargs):
24
+
25
+def process_query(agent:Agent, message: str, action: str = "load", **kwargs):
26
if action.strip().lower() == "save":
27
id = db.insert_document(message)
28
return files.read_file("./prompts/fw.memory_saved.md")
tools/message.py
+61
-47
@@ -2,54 +2,68 @@ from agent import Agent
2
from tools.helpers import files
3
from tools.helpers.print_style import PrintStyle
4
5
-def execute(agent:Agent, message: str, _tools, _tool_index, timeout=15, **kwargs):
5
+from agent import Agent
6
+from tools.helpers.tool import Tool, Response
7
+from tools.helpers import files
8
+from tools.helpers.print_style import PrintStyle
9
+
10
+class Unknown(Tool):
11
+
12
+ def execute(self):
13
+ # superior = self.agent.get_data("superior")
14
+ # if superior:
15
+ return Response(message=self.content, stop_tool_processing=True, break_loop=True)
16
+ # else:
17
+
18
+
19
+# def execute(agent:Agent, message: str, _tools, _tool_index, timeout=15, **kwargs):
20
7
- # for models that like to use multiple tools in one response, we do a little trick to help the flow
8
- # if there are tools producing output before this message or any other tools after this message,
9
- # this message will be sent as information only and will not stop the loop
10
- # if this is the last tool in the iteration and no outputing tools we used before, we stop the loop
11
- # and wait for user input
21
+# # for models that like to use multiple tools in one response, we do a little trick to help the flow
22
+# # if there are tools producing output before this message or any other tools after this message,
23
+# # this message will be sent as information only and will not stop the loop
24
+# # if this is the last tool in the iteration and no outputing tools we used before, we stop the loop
25
+# # and wait for user input
26
27
14
- # tools called before this one that produce output
15
- outputing_tools_before = filter_tools(
16
- filters=[
17
- {"name":"memory_tool","action":"load"},
18
- {"name":"online_knowledge_tool"},
19
- {"name":"delegation"},
20
- ],
21
- tools=_tools[:_tool_index]
22
- )
23
-
24
- # tools called after this one
25
- other_tools_after = any(tool["name"] != kwargs["_name"] for tool in _tools[_tool_index:]) #are there other tools than messages used after this one?
26
-
27
- agent.set_data("timeout", timeout) # set the timeout for response
28
-
29
- #if there are other tools used, message is only for information, it does not stop the loop
30
- if outputing_tools_before or other_tools_after:
31
- return non_blocking_message(agent, message, timeout=timeout, **kwargs)
32
- else: #if there are only messages used in this iteration, collect them into the loop result
33
- return blocking_message(agent, message, timeout=timeout, **kwargs)
34
-
35
-def blocking_message(agent:Agent, message: str, timeout=15, **kwargs):
36
- agent.add_result(message)
37
- return files.read_file("./prompts/fw.msg_sent.md")
38
-
39
-def non_blocking_message(agent:Agent, message: str, timeout=15, **kwargs):
40
- if agent.get_data("superior"): # add to superior messages if it is an agent
41
- msg_for_user = files.read_file("./prompts/fw.msg_from_subordinate.md",name=agent.name,message=message)
42
- agent.get_data("superior").append_message(msg_for_user, human=True)
43
-
44
- # output to console
45
- PrintStyle(font_color="white",background_color="#1D8348", bold=True, padding=True).print(f"{agent.name}: reponse:")
46
- PrintStyle(font_color="white").print(f"{message}")
47
-
48
- return files.read_file("./prompts/fw.msg_info_sent.md") #return message o
28
+# # tools called before this one that produce output
29
+# outputing_tools_before = filter_tools(
30
+# filters=[
31
+# {"name":"memory_tool","action":"load"},
32
+# {"name":"online_knowledge_tool"},
33
+# {"name":"delegation"},
34
+# ],
35
+# tools=_tools[:_tool_index]
36
+# )
37
+
38
+# # tools called after this one
39
+# other_tools_after = any(tool["name"] != kwargs["_name"] for tool in _tools[_tool_index:]) #are there other tools than messages used after this one?
40
+
41
+# agent.set_data("timeout", timeout) # set the timeout for response
42
+
43
+# #if there are other tools used, message is only for information, it does not stop the loop
44
+# if outputing_tools_before or other_tools_after:
45
+# return non_blocking_message(agent, message, timeout=timeout, **kwargs)
46
+# else: #if there are only messages used in this iteration, collect them into the loop result
47
+# return blocking_message(agent, message, timeout=timeout, **kwargs)
48
+
49
+# def blocking_message(agent:Agent, message: str, timeout=15, **kwargs):
50
+# agent.add_result(message)
51
+# return files.read_file("./prompts/fw.msg_sent.md")
52
+
53
+# def non_blocking_message(agent:Agent, message: str, timeout=15, **kwargs):
54
+# if agent.get_data("superior"): # add to superior messages if it is an agent
55
+# msg_for_user = files.read_file("./prompts/fw.msg_from_subordinate.md",name=agent.name,message=message)
56
+# agent.get_data("superior").append_message(msg_for_user, human=True)
57
+
58
+# # output to console
59
+# PrintStyle(font_color="white",background_color="#1D8348", bold=True, padding=True).print(f"{agent.name}: reponse:")
60
+# PrintStyle(font_color="white").print(f"{message}")
61
+
62
+# return files.read_file("./prompts/fw.msg_info_sent.md") #return message o
63
50
-def filter_tools(filters, tools):
51
- filtered_data = []
52
- for data_item in tools:
53
- if any(all(data_item.get(key) == value for key, value in filter_item.items()) for filter_item in filters):
54
- filtered_data.append(data_item)
55
- return filtered_data
\ No newline at end of file
64
+# def filter_tools(filters, tools):
65
+# filtered_data = []
66
+# for data_item in tools:
67
+# if any(all(data_item.get(key) == value for key, value in filter_item.items()) for filter_item in filters):
68
+# filtered_data.append(data_item)
69
+# return filtered_data
\ No newline at end of file
tools/online_knowledge_tool.py
+10
-3
@@ -1,7 +1,14 @@
1
from agent import Agent
2
from tools.helpers import perplexity_search
3
+from tools.helpers.tool import Tool, Response
4
5
+class Unknown(Tool):
6
+ def execute(self):
7
+ return Response(
8
+ message=process_question(self.content),
9
+ stop_tool_processing=True,
10
+ break_loop=False,
11
+ )
12
5
-def execute(agent:Agent, question:str, **kwargs):
6
- return perplexity_search.perplexity_search(question)
7
-
\ No newline at end of file
13
+def process_question(question):
14
+ return str(perplexity_search.perplexity_search(question))
\ No newline at end of file
tools/task_done.py
+7
-3
@@ -1,7 +1,11 @@
1
from agent import Agent
2
+from tools.helpers.tool import Tool, Response
3
from tools.helpers import files
4
from tools.helpers.print_style import PrintStyle
5
5
-def execute(agent:Agent, result: str, **kwargs):
6
- agent.set_data("timeout",0) # wait for user, no timeout
7
- agent.add_result(result) # add result data
\ No newline at end of file
6
+class TaskDone(Tool):
7
+
8
+ def execute(self):
9
+ self.agent.set_data("timeout",0) # wait for user, no timeout
10
+ return Response(message=self.content, stop_tool_processing=True, break_loop=True)
11
+
tools/thought.py
new
+15
@@ -0,0 +1,15 @@
1
+from agent import Agent
2
+from tools.helpers.tool import Tool, Response
3
+from tools.helpers import files
4
+from tools.helpers.print_style import PrintStyle
5
+
6
+class Thought(Tool):
7
+ def execute(self):
8
+ return Response(message="", stop_tool_processing=False, break_loop=False)
9
+
10
+ def before_execution(self):
11
+ pass
12
+
13
+ def after_execution(self, response: Response):
14
+ pass
15
+
tools/unknown.py
new
+12
@@ -0,0 +1,12 @@
1
+from tools.helpers.tool import Tool, Response
2
+from tools.helpers import files
3
+
4
+class Unknown(Tool):
5
+ def execute(self):
6
+ return Response(
7
+ message=files.read_file("prompts/fw.tool_not_found.md",
8
+ tool_name=self.name,
9
+ tools_prompt=files.read_file("prompts/agent.tools.md")),
10
+ stop_tool_processing=True,
11
+ break_loop=False)
12
+