JSON message format prorotype

frdel committed Jun 21, 2024 at 09:06 UTC 2330288798952bb78cad0b9c6a0d242abb62b088
18 files changed +241 -266
agent.py
+18 -26
@@ -51,7 +51,9 @@ class Agent:
51 def message_loop(self, msg: str):
52 try:
53 printer = PrintStyle(italic=True, font_color="#b3ffd9", padding=False)
54 - user_message = msg
54 + user_message = files.read_file("./prompts/fw.user_message.md", message=msg)
55 + self.append_message(user_message, human=True) # Append the user's input to the history
56 +
57 self.stop_loop = False
58 self.loop_result = []
59
@@ -61,8 +63,7 @@ class Agent:
63 self.intervention_status = False # reset interventon status
64 try:
65
64 - self.append_message(user_message, human=True) # Append the user's input to the history
65 - inputs = {"input": user_message,"messages": self.history}
66 + inputs = {"messages": self.history}
67 chain = self.prompt | Agent.model_chat
68 formatted_inputs = self.prompt.format(**inputs)
69
@@ -149,31 +150,22 @@ class Agent:
150
151 def process_tools(self, msg: str):
152 # search for tool usage requests in agent message
152 - tool_requests = extract_tools.extract_tool_requests2(msg)
153 -
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 -
166 - for tool in tools:
167 - if self.handle_intervention(): break # wait if paused and handle intervention message if needed
153 + tool_request = extract_tools.json_parse_dirty(msg)
154 +
155 + tool = self.get_tool(
156 + tool_request["tool_name"],
157 + tool_request["tool_args"],
158 + msg)
159
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
160 + if self.handle_intervention(): return # wait if paused and handle intervention message if needed
161 +
162 + tool.before_execution()
163 + response = tool.execute()
164 + tool.after_execution(response)
165 + if response.break_loop: return response.message
166
167
176 - def get_tool(self, name: str, content: str, args: dict, index: int, message: str, tools: list, **kwargs):
168 + def get_tool(self, name: str, args: dict, message: str, **kwargs):
169 from tools.unknown import Unknown
170 from tools.helpers.tool import Tool
171
@@ -187,4 +179,4 @@ class Agent:
179 tool_class = cls[1]
180 break
181
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
182 + return tool_class(agent=self, name=name, args=args, message=message, **kwargs)
\ No newline at end of file
main.py
+3 -2
@@ -16,13 +16,14 @@ 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)
20 # chat_llm = models.get_groq_llama70b_json(temperature=0.2)
21 # chat_llm = models.get_groq_llama8b(temperature=0.2)
21 - chat_llm = models.get_openai_gpt35(temperature=0)
22 + # chat_llm = models.get_openai_gpt35(temperature=0)
23 # chat_llm = models.get_openai_gpt4o(temperature=0)
24 # chat_llm = models.get_anthropic_opus(temperature=0)
25 # chat_llm = models.get_anthropic_sonnet(temperature=0)
25 - # chat_llm = models.get_anthropic_haiku(temperature=0)
26 + chat_llm = models.get_anthropic_haiku(temperature=0)
27 # chat_llm = models.get_ollama_dolphin()
28
29 # embedding model used for memory
prompts/agent.system.md
+27 -99
@@ -1,100 +1,28 @@
1 # Your role
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 -- 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 - 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.
19 -- Important!: Do not use multiple message types at the same time except for thoughts. Do not send multiple messages and/or tools at once to avoid conflicts.
20 -- Never send your thoughts as messages, always use <thought$> for that.
21 -
22 -## Communication examples:
23 -These examples are for illustration purposes only. Do not reuse any of these examples literally.
24 -
25 -**Example response 1**:
26 -<thought$>
27 -The user asked for my name. I will respond with my name.
28 -</thought$>
29 -
30 -**Example response 2**:
31 -<message$>
32 -Greetings! How can I assist you today?
33 -</message$>
34 -
35 -**Example response 3**:
36 -<delegation$>
37 -I need you to use your tools and get me the current day of the week.
38 -</delegation$>
39 -
40 -**Example response 4**:
41 -<task_result$>
42 -Current day of week is Monday.
43 -</task_result$>
44 -
45 -
46 -# Step by step instruction manual to problem solving
47 -- IMPORTANT: FOLLOW STEP BY STEP, NEVER SKIP!
48 -- Explain each step using your <thought$>.
49 -- Enhance each step by loading and saving your <memory_tool$>.
50 -
51 -1. Always check your <memory_tool$> first!. Maybe already have information about similiar problem that can help.
52 -2. Then check your <knowledge_tool$>.
53 - - Look for straightforward solutions compatible with your available tools.
54 - - Always look for opensource python/nodejs/terminal tools and packages first.
55 -3. Break task into subtasks by asking yourself the following questions. If they are positive, break task into subtasks and explain them.
56 - - Question A: Can some parts of the task be separated and well explained to subordinate agent to solve?
57 - - Question B: Can the result if these tasks can be reasonably returned to you from your user?
58 -4. Processing subtasks.
59 - - Go through subtasks step by step and delagate them using <delegate$> response type.
60 - - Collect results from subordinate agent and validate completeness and correctness. Communicate followup request to your subordinate if needed.
61 - - Helpful new information should be saved with <memory_tool$>.
62 - - Regurarly report back to your user and check your path is correct.
63 - - If you are contacted by your subordinate, steer him to the right path.
64 -5. Completing the task
65 - - Consolidate all subtasks and explain the status.
66 - - Verify the result using your tools if possible (check created files etc.)
67 - - Do not accept failure, search for error solution and try again with fixed input or different ways.
68 - - If there is helpful information discovered during the solution, save it into your memory using <memory_tool$> for later.
69 - - Report back to your user using <task_done$> message type, describe the result and provide all necessary information. Do not just output your response, you must use the tool for that.
70 -
71 -# General operation manual
72 -- Use your reasoning and process each problem in a step-by-step manner.
73 -- To keep track of your process, use your <thought$> response type. You will be prompted again to continue with more thoughts or tool calls until you are satisfied.
74 -- Always check your previous messages and prevent repetition. Always move towards solution.
75 -- Avoid solutions that require credentials, user interaction, GUI usage etc. All has to be done using code and terminal.
76 -- When asked about your memory, it always refers to <memory_tool$>. Use your <memory_tool$> regularly.
77 -
78 -# Tips and tricks
79 -- Focus on python/nodejs/linux libraries when searching for solutions. You can use them with your tools and make solutions easy.
80 -- Do not search for solutions that require GUI, browser or other user interaction, it is not possible. You can only use code and terminal.
81 -- Try using <knowledge_tool$> multiple times in various ways to increase search potential.
82 -- Sometimes you don't need tools, some things can be determined.
83 -- Make a good use of your <memory_tool$>. So much can be learned from your history. Update your memory with new findings.
84 -
85 -# Penalties
86 -- For every unthoughtful <code_execution_tool$> you will be penalized, so use <memory_tool$> regularly to memorize your previous failures and learn from them.
87 -- For every solution requiring overly complex software usage, you will be penalized, do always use <memory_tool$> and <knowledge_tool$> to find the easiest, most compatible and reliable libraries.
88 -
89 -# Tool usage instructions
90 -- Tool message types can be used to call tools that help you solve problems.
91 -- To use a tool, use message type named as the tool: <tool_name_here$> in your response. Use with potential arguments of the tool. The main input data (message, code, question) go inside tags. No escaping.
92 -- Result will be sent to you in the next message, wait for it.
93 -- Only use tools provided in Available tools section, do not try to use any tool name you have not been instructed to.
94 -- Do not use more tools multiple tools in one message that rely on their outputs, you have to send the message after each tool and wait for output.
95 -- Important:End your response right after tool closing tag and wait for user.
96 -
97 -## Tool usage generic example:
98 -<name_of_tool$ arg1="val1"/>
99 -main input data for tool
100 -</name_of_tool$>
\ No newline at end of file
2 +- You are autonomous JSON AI task solver
3 +
4 +# Communication
5 +- Your response is a JSON containing the following fields:
6 + 1. **thoughts**: Array of thoughts regarding the current task
7 + - Use thoughs to prepare solution and outline next steps
8 + 2. **tool_name**: Name of the tool to be used
9 + - Tools help you gather knowledge and execute actions
10 + 3. **tool_args**: Object of arguments that are passed to the tool
11 + - Each tool has specific arguments listed in Available tools section
12 +
13 +## Response example that must be used every time
14 +~~~json
15 +{
16 + "thoughts": [
17 + "The user has requested...",
18 + "I need to follow these steps...",
19 + "I need to use the tool...",
20 + "Then I will..."
21 + ],
22 + "tool_name": "name_of_tool",
23 + "tool_args": {
24 + "arg1": "val1",
25 + "arg2": "val2"
26 + }
27 +}
28 +~~~
\ No newline at end of file
prompts/agent.tools.md
+64 -24
@@ -1,55 +1,95 @@
1 ## Tools available:
2
3 +### response:
4 +Final answer for user.
5 +Ends task processing - only use when the task is done or no task is being processed.
6 +Place your result in "text" argument.
7 +Memory can provide guidance, online sources can provide up to date information.
8 +Always verify memory by online.
9 +**Example usage**:
10 +~~~json
11 +{
12 + "thoughts": [
13 + "The has greeted me...",
14 + "I will...",
15 + ],
16 + "tool_name": "response",
17 + "tool_args": {
18 + "text": "Hi...",
19 + }
20 +}
21 +~~~
22 +
23 ### knowledge_tool:
4 -Provide question and get both online and memory response.
24 +Provide "question" argument and get both online and memory response.
25 This tool is very powerful and can answer very specific questions directly.
26 First always try to ask for result rather that guidance.
27 Memory can provide guidance, online sources can provide up to date information.
28 Always verify memory by online.
9 -Do not use in combination with other tools except for thoughts. Wait for response before using other tools.
29 **Example usage**:
11 -<knowledge_tool$>
12 -What is the user id of John Doe on twitter?
13 -</knowledge_tool$>
30 +~~~json
31 +{
32 + "thoughts": [
33 + "I need to gather information about...",
34 + "First I will search...",
35 + "Then I will...",
36 + ],
37 + "tool_name": "knowledge_tool",
38 + "tool_args": {
39 + "question": "How to...",
40 + }
41 +}
42 +~~~
43
44 ### memory_tool:
45 Access your persistent memory to load or save memories.
46 Memories can help you to remember important information and later reuse it.
47 With this you are able to learn and improve.
19 -Put the memory you need to load or save after the tag.
48 Use argument "action" with value "load", "save" or "delete", based on what you want to do.
49 +Use argument "memory" for content to load or save.
50 When loading memories using action "load", provide keywords or question relevant to your current task.
51 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.
52 When deleting memories using action "delete", provide a prompt to search memories to delete.
53 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.
54 **Example usages**:
27 -<memory_tool$ action="load">
28 -How to get current working directory in python?
29 -</memory_tool$>
30 -
31 -<memory_tool$ action="save">
32 -# How to get current working directory in python:
33 -Here is a python code to get current working directory:
34 -
35 -import os
36 -return os.getcwd()
37 -</memory_tool$>
55 +~~~json
56 +{
57 + "thoughts": [
58 + "I need to do...",
59 + "Maybe I have done it in the past...",
60 + "Let me check the memory...",
61 + ],
62 + "tool_name": "memory_tool",
63 + "tool_args": {
64 + "action": "load",
65 + "question": "How to...",
66 + }
67 +}
68 +~~~
69
70 ### code_execution_tool:
71 Execute provided terminal commands, python code or nodejs code.
72 This tool can be used to achieve any task that requires computation, or any other software related activity.
42 -Place your command or code between tags. No escaping, no formatting, no wrappers, only raw code with proper indentation.
73 +Place your code escaped and properly indented in the "code" argument.
74 Select the corresponding runtime with "runtime" argument. Possible values are "terminal", "python" and "nodejs".
75 You can use pip, npm and apt-get in terminal runtime to install any required packages.
76 IMPORTANT: Never use implicit print or implicit output, it does not work! If you need output of your code, you MUST use print() or console.log() to output selected variables.
77 When tool outputs error, you need to change your code accordingly before trying again. knowledge_tool can help analyze errors.
47 -If your code execution is successful, save it using <memory_tool$ action="save"> so it can be reused later.
78 Keep in mind that current working directory CWD automatically resets before every tool call.
79 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.
80 Do not use in combination with other tools except for thoughts. Wait for response before using other tools.
81 **Example usage**:
52 -<code_execution_tool$ runtime="python">
53 -import os
54 -return os.getcwd()
55 -</code_execution_tool$>
82 +~~~json
83 +{
84 + "thoughts": [
85 + "I need to do...",
86 + "I can use library...",
87 + "Then I can...",
88 + ],
89 + "tool_name": "memory_tool",
90 + "tool_args": {
91 + "runtime": "python",
92 + "code": "import os\nreturn os.getcwd()",
93 + }
94 +}
95 +~~~
\ No newline at end of file
prompts/fw.tool_response.md
+6 -2
@@ -1,2 +1,6 @@
1 -Response from {{tool_name}} tool:
2 -{{tool_response}}
\ No newline at end of file
1 +~~~json
2 +{
3 + "response_from_tool": "{{tool_name}}",
4 + "data": {{tool_response}}
5 +}
6 +~~~
\ No newline at end of file
prompts/fw.user_message.md new
+5
@@ -0,0 +1,5 @@
1 +~~~json
2 +{
3 + "user": "{{message}}"
4 +}
5 +~~~
\ No newline at end of file
tools/code_execution_tool.py
+5 -5
@@ -6,24 +6,24 @@ 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):
9 +class CodeExecution(Tool):
10
11 def execute(self):
12
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)
16 + response = self.execute_python_code(self.args["code"])
17 elif runtime == "nodejs":
18 - response = self.execute_nodejs_code(self.content)
18 + response = self.execute_nodejs_code(self.args["code"])
19 elif runtime == "terminal":
20 - response = self.execute_terminal_command(self.content)
20 + response = self.execute_terminal_command(self.args["code"])
21 else:
22 response = files.read_file("./prompts/fw.code_runtime_wrong.md", runtime=runtime)
23
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)
26 + return Response(message=response, break_loop=False)
27
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)
tools/delegation.py
+2 -2
@@ -3,7 +3,7 @@ from tools.helpers.tool import Tool, Response
3 from tools.helpers import files
4 from tools.helpers.print_style import PrintStyle
5
6 -class Unknown(Tool):
6 +class Delegation(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
@@ -12,4 +12,4 @@ class Unknown(Tool):
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
15 + return self.agent.get_data("subordinate").message_loop(self.args["task"])
\ No newline at end of file
tools/helpers/extract_tools.py
+94 -61
@@ -1,87 +1,120 @@
1 import re, os
2 +from typing import Any
3 from . import files
4 +import dirtyjson
5 +import regex
6
4 -def extract_tool_requests2(response):
5 - # Regex to match the tags ending with $, allowing for varying whitespace
6 - pattern = r'<(\w+)\$[\s]*(.*?)>([\s\S]*?)(?=<\w+\$|<\/\1\$|$)'
7 - matches = re.findall(pattern, response, re.DOTALL)
7 +
8 +def json_parse_dirty(json:str) -> Any:
9 + ext_json = extract_json_string(json)
10 + ext_json = fix_json_string(ext_json)
11 + data = dirtyjson.loads(ext_json)
12 + return data
13 +
14 +def extract_json_string(content):
15 + # Regular expression pattern to match a JSON object
16 + pattern = r'\{(?:[^{}]|(?R))*\}|\[(?:[^\[\]]|(?R))*\]|"(?:\\.|[^"\\])*"|true|false|null|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?'
17 +
18 + # Search for the pattern in the content
19 + match = regex.search(pattern, content)
20 +
21 + if match:
22 + # Return the matched JSON string
23 + return match.group(0)
24 + else:
25 + print("No JSON content found.")
26 + return ""
27 +
28 +def fix_json_string(json_string):
29 + # Function to replace unescaped line breaks within JSON string values
30 + def replace_unescaped_newlines(match):
31 + return match.group(0).replace('\n', '\\n')
32 +
33 + # Use regex to find string values and apply the replacement function
34 + fixed_string = re.sub(r'(?<=: ")(.*?)(?=")', replace_unescaped_newlines, json_string, flags=re.DOTALL)
35 + return fixed_string
36 +
37 +# def extract_tool_requests2(response):
38 +# # Regex to match the tags ending with $, allowing for varying whitespace
39 +# pattern = r'<(\w+)\$[\s]*(.*?)>([\s\S]*?)(?=<\w+\$|<\/\1\$|$)'
40 +# matches = re.findall(pattern, response, re.DOTALL)
41
9 - tool_usages = []
10 - allowed_tags = list_python_files("tools")
42 +# tool_usages = []
43 +# allowed_tags = list_python_files("tools")
44
12 - for match in matches:
13 - tag_name, attributes, content = match
45 +# for match in matches:
46 +# tag_name, attributes, content = match
47
15 - if tag_name not in allowed_tags: continue
48 +# if tag_name not in allowed_tags: continue
49
17 - tool_dict = {}
18 - tool_dict['name'] = tag_name
19 - tool_dict['args'] = {}
50 +# tool_dict = {}
51 +# tool_dict['name'] = tag_name
52 +# tool_dict['args'] = {}
53
21 - # Parse attributes
22 - for attr in re.findall(r'(\w+)\s*=\s*"([^"]+)"', attributes):
23 - tool_dict['args'][attr[0]] = attr[1]
54 +# # Parse attributes
55 +# for attr in re.findall(r'(\w+)\s*=\s*"([^"]+)"', attributes):
56 +# tool_dict['args'][attr[0]] = attr[1]
57
25 - # Add body content
26 - tool_dict["content"] = content.strip()
27 - tool_dict["index"] = len(tool_usages)
28 - tool_usages.append(tool_dict)
58 +# # Add body content
59 +# tool_dict["content"] = content.strip()
60 +# tool_dict["index"] = len(tool_usages)
61 +# tool_usages.append(tool_dict)
62
30 - return tool_usages
63 +# return tool_usages
64
32 -def extract_tool_requests(response):
33 - # Regex to match the tool blocks, allowing for varying whitespace
34 - pattern = r'<tool\$[\s]*(.*?)>(.*?)<\/tool\$\s*>'
35 - matches = re.findall(pattern, response, re.DOTALL)
65 +# def extract_tool_requests(response):
66 +# # Regex to match the tool blocks, allowing for varying whitespace
67 +# pattern = r'<tool\$[\s]*(.*?)>(.*?)<\/tool\$\s*>'
68 +# matches = re.findall(pattern, response, re.DOTALL)
69
37 - tool_usages = []
70 +# tool_usages = []
71
39 - for match in matches:
40 - attributes, body = match
41 - tool_dict = {}
42 - # Parse attributes
43 - for attr in re.findall(r'(\w+)\s*=\s*"([^"]+)"', attributes):
44 - tool_dict[attr[0]] = attr[1]
45 - # Add body content
46 - tool_dict["body"] = body.strip()
47 - tool_usages.append(tool_dict)
72 +# for match in matches:
73 +# attributes, body = match
74 +# tool_dict = {}
75 +# # Parse attributes
76 +# for attr in re.findall(r'(\w+)\s*=\s*"([^"]+)"', attributes):
77 +# tool_dict[attr[0]] = attr[1]
78 +# # Add body content
79 +# tool_dict["body"] = body.strip()
80 +# tool_usages.append(tool_dict)
81
49 - return tool_usages
82 +# return tool_usages
83
51 -def extract_specified_tags(response):
84 +# def extract_specified_tags(response):
85
53 - allowed_tags = list_python_files("tools")
86 +# allowed_tags = list_python_files("tools")
87
55 - # Create a regex pattern to match specified tags and their attributes
56 - pattern = r'<({})([\s\S]*?)>'.format('|'.join(allowed_tags))
57 - matches = re.findall(pattern, response, re.DOTALL)
88 +# # Create a regex pattern to match specified tags and their attributes
89 +# pattern = r'<({})([\s\S]*?)>'.format('|'.join(allowed_tags))
90 +# matches = re.findall(pattern, response, re.DOTALL)
91
59 - extracted_tags = []
92 +# extracted_tags = []
93
61 - for match in matches:
62 - tag_name, attributes = match
63 - tag_dict = {}
64 - tag_dict['name'] = tag_name
94 +# for match in matches:
95 +# tag_name, attributes = match
96 +# tag_dict = {}
97 +# tag_dict['name'] = tag_name
98
66 - # Parse attributes
67 - for attr in re.findall(r'(\w+)\s*=\s*"([^"]+)"', attributes):
68 - tag_dict[attr[0]] = attr[1]
99 +# # Parse attributes
100 +# for attr in re.findall(r'(\w+)\s*=\s*"([^"]+)"', attributes):
101 +# tag_dict[attr[0]] = attr[1]
102
70 - # Extract the body text (everything after the tag until the next tag or end of string)
71 - body_pattern = r'<{0}[\s\S]*?>([\s\S]*?)(?=<|$)'.format(tag_name)
72 - body_match = re.search(body_pattern, response, re.DOTALL)
73 - tag_dict['body'] = body_match.group(1).strip() if body_match else ''
103 +# # Extract the body text (everything after the tag until the next tag or end of string)
104 +# body_pattern = r'<{0}[\s\S]*?>([\s\S]*?)(?=<|$)'.format(tag_name)
105 +# body_match = re.search(body_pattern, response, re.DOTALL)
106 +# tag_dict['body'] = body_match.group(1).strip() if body_match else ''
107
75 - extracted_tags.append(tag_dict)
108 +# extracted_tags.append(tag_dict)
109
77 - return extracted_tags
78 -
79 -def list_python_files(directory):
80 - # List all files in the given directory
81 - list = os.listdir(files.get_abs_path(directory))
82 - # Filter for Python files and remove the extension
83 - python_files = { os.path.splitext(file)[0] for file in list if file.endswith('.py') }
84 - return python_files
110 +# return extracted_tags
111 +
112 +# def list_python_files(directory):
113 +# # List all files in the given directory
114 +# list = os.listdir(files.get_abs_path(directory))
115 +# # Filter for Python files and remove the extension
116 +# python_files = { os.path.splitext(file)[0] for file in list if file.endswith('.py') }
117 +# return python_files
118
119 # import re
120 # from xml.etree import ElementTree as ET
tools/helpers/files.py
+4 -1
@@ -4,7 +4,7 @@ def read_file(relative_path, **kwargs):
4 absolute_path = get_abs_path(relative_path) # Construct the absolute path to the target file
5
6 with open(absolute_path) as f:
7 - content = f.read()
7 + content = remove_code_fences(f.read())
8
9 # Replace placeholders with values from kwargs
10 for key, value in kwargs.items():
@@ -16,6 +16,9 @@ def read_file(relative_path, **kwargs):
16
17 return content
18
19 +def remove_code_fences(text):
20 + return re.sub(r'~~~\w*\n|~~~', '', text)
21 +
22 def get_abs_path(*relative_paths):
23 return os.path.join(get_base_dir(), *relative_paths)
24
tools/helpers/tool.py
+3 -6
@@ -5,20 +5,17 @@ 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:
8 + def __init__(self, message: str, break_loop: bool) -> None:
9 self.message = message
10 - self.stop_tool_processing = stop_tool_processing
10 self.break_loop = break_loop
11
12 class Tool:
13
15 - def __init__(self, agent: Agent, name: str, content: str, args: dict, message: str, tools: list['Tool'], **kwargs) -> None:
14 + def __init__(self, agent: Agent, name: str, args: dict, message: str, **kwargs) -> None:
15 self.agent = agent
16 self.name = name
18 - self.content = content
17 self.args = args
18 self.message = message
21 - self.tools = tools
19
20 @abstractmethod
21 def execute(self) -> Response:
@@ -26,7 +23,7 @@ class Tool:
23
24 def before_execution(self):
25 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)
26 + PrintStyle(font_color="#85C1E9").print(self.args)
27
28 def after_execution(self, response: Response):
29 msg_response = files.read_file("./prompts/fw.tool_response.md", tool_name=self.name, tool_response=response.message)
tools/knowledge_tool.py
+3 -3
@@ -12,12 +12,12 @@ 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)
15 + future_online = executor.submit(online_knowledge_tool.process_question, self.args["question"])
16 + future_memory = executor.submit(memory_tool.process_query, self.agent, self.args["question"])
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
23 + return Response(message=result, break_loop=False)
\ No newline at end of file
tools/memory_tool.py
+3 -3
@@ -11,8 +11,8 @@ result_count = 3 #TODO parametrize better
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)
14 + result = process_query(self.agent, self.args["memory"],self.args["action"])
15 + return Response(message=result, break_loop=False)
16
17
18 def initialize(embeddings_model,messages_returned=3, subdir=""):
@@ -24,7 +24,7 @@ def initialize(embeddings_model,messages_returned=3, subdir=""):
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)
27 + id = db.insert_document(str(message))
28 return files.read_file("./prompts/fw.memory_saved.md")
29
30 elif action.strip().lower() == "delete":
tools/online_knowledge_tool.py
+2 -3
@@ -2,11 +2,10 @@ from agent import Agent
2 from tools.helpers import perplexity_search
3 from tools.helpers.tool import Tool, Response
4
5 -class Unknown(Tool):
5 +class OnlineKnowledge(Tool):
6 def execute(self):
7 return Response(
8 - message=process_question(self.content),
9 - stop_tool_processing=True,
8 + message=process_question(self.args["question"]),
9 break_loop=False,
10 )
11
tools/response.py renamed
+2 -2
@@ -7,12 +7,12 @@ 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):
10 +class ResponseTool(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)
15 + return Response(message=self.args["text"], break_loop=True)
16 # else:
17
18
tools/task_done.py deleted
-11
@@ -1,11 +0,0 @@
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 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 deleted
-15
@@ -1,15 +0,0 @@
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
-1
@@ -7,6 +7,5 @@ class Unknown(Tool):
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,
10 break_loop=False)
11