frdel commited on
Commit
db9d435
·
1 Parent(s): 9504283

user input timeouts, tools consolidation

Browse files
agent.py CHANGED
@@ -7,7 +7,6 @@ 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
-
11
  rate_limit = rate_limiter.rate_limiter(30,160000) #TODO! move to main.py
12
 
13
  class Agent:
@@ -28,7 +27,7 @@ class Agent:
28
  messages_returned=memory_results,
29
  subdir=memory_subdir )
30
 
31
- def __init__(self, system_prompt:Optional[str]=None, tools_prompt:Optional[str]=None, superior:Optional['Agent']=None, number=0):
32
 
33
  self.number = number
34
  self.name = f"Agent {self.number}"
@@ -38,15 +37,14 @@ class Agent:
38
  self.system_prompt = system_prompt.replace("{", "{{").replace("}", "}}")
39
  self.tools_prompt = tools_prompt.replace("{", "{{").replace("}", "}}")
40
 
41
- self.superior: Optional['Agent'] = superior
42
-
43
- self.subordinate: Optional['Agent'] = None
44
  self.history = []
45
  self.last_message = ""
46
  self.intervention_message = ""
47
  self.intervention_status = False
48
  self.stop_loop = False
49
  self.loop_result = ""
 
 
50
 
51
  self.prompt = ChatPromptTemplate.from_messages([
52
  ("system", self.system_prompt + "\n\n" + self.tools_prompt),
@@ -111,6 +109,12 @@ class Agent:
111
 
112
  finally:
113
  Agent.streaming_agent = None # unset current streamer
 
 
 
 
 
 
114
 
115
  def append_message(self, msg: str, human: bool = False):
116
  message_type = "human" if human else "ai"
 
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
11
 
12
  class Agent:
 
27
  messages_returned=memory_results,
28
  subdir=memory_subdir )
29
 
30
+ def __init__(self, system_prompt:Optional[str]=None, tools_prompt:Optional[str]=None, number=0):
31
 
32
  self.number = number
33
  self.name = f"Agent {self.number}"
 
37
  self.system_prompt = system_prompt.replace("{", "{{").replace("}", "}}")
38
  self.tools_prompt = tools_prompt.replace("{", "{{").replace("}", "}}")
39
 
 
 
 
40
  self.history = []
41
  self.last_message = ""
42
  self.intervention_message = ""
43
  self.intervention_status = False
44
  self.stop_loop = False
45
  self.loop_result = ""
46
+
47
+ self.data = {} # free data object all the tools can use
48
 
49
  self.prompt = ChatPromptTemplate.from_messages([
50
  ("system", self.system_prompt + "\n\n" + self.tools_prompt),
 
109
 
110
  finally:
111
  Agent.streaming_agent = None # unset current streamer
112
+
113
+ def get_data(self, field:str):
114
+ return self.data.get(field, None)
115
+
116
+ def set_data(self, field:str, value):
117
+ self.data[field] = value
118
 
119
  def append_message(self, msg: str, human: bool = False):
120
  message_type = "human" if human else "ai"
docs/splash_wide.png CHANGED

Git LFS Details

  • SHA256: c569709e917de98936594b84e74a5ea4f71c9994e049ab4d5ab6f8cb3f306731
  • Pointer size: 130 Bytes
  • Size of remote file: 87.1 kB

Git LFS Details

  • SHA256: 027244f3ac813803ec834bb6484a379444d16786e7d182fce1edb99aff1ddd8f
  • Pointer size: 130 Bytes
  • Size of remote file: 86.2 kB
main.py CHANGED
@@ -3,6 +3,9 @@ from ansio import application_keypad, mouse_input, raw_input
3
  from ansio.input import InputEvent, get_input_event
4
  from agent import Agent
5
  from tools.helpers.print_style import PrintStyle
 
 
 
6
 
7
  input_lock = threading.Lock()
8
 
@@ -12,7 +15,7 @@ def chat():
12
  # chat model used for agents
13
  # chat_llm = models.get_groq_llama70b(temperature=0.2)
14
  # chat_llm = models.get_openai_gpt35(temperature=0)
15
- chat_llm = models.get_openai_gpt4o()
16
  # chat_llm = models.get_anthropic_sonnet(temperature=0)
17
  # chat_llm = models.get_anthropic_haiku()
18
  # chat_llm = models.get_ollama_dolphin()
@@ -32,15 +35,30 @@ def chat():
32
  # create the first agent
33
  agent0 = Agent()
34
 
35
- # start the conversation loop
36
  while True:
37
  # ask user for message
38
- PrintStyle(background_color="#6C3483", font_color="white", bold=True, padding=True).print(f"User message ('exit' to leave):")
39
  with input_lock:
40
- user_input = input("> ").strip()
41
- PrintStyle(font_color="white", padding=False, log_only=True).print(f"> {user_input}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
-
44
  # exit the conversation when the user types 'exit'
45
  if user_input.lower() == 'exit': break
46
 
 
3
  from ansio.input import InputEvent, get_input_event
4
  from agent import Agent
5
  from tools.helpers.print_style import PrintStyle
6
+ from tools.helpers.files import read_file
7
+ from pytimedinput import timedInput as timed_input
8
+
9
 
10
  input_lock = threading.Lock()
11
 
 
15
  # chat model used for agents
16
  # chat_llm = models.get_groq_llama70b(temperature=0.2)
17
  # chat_llm = models.get_openai_gpt35(temperature=0)
18
+ chat_llm = models.get_openai_gpt4o(temperature=0)
19
  # chat_llm = models.get_anthropic_sonnet(temperature=0)
20
  # chat_llm = models.get_anthropic_haiku()
21
  # chat_llm = models.get_ollama_dolphin()
 
35
  # create the first agent
36
  agent0 = Agent()
37
 
38
+ # start the conversation loop
39
  while True:
40
  # ask user for message
 
41
  with input_lock:
42
+ timeout = agent0.get_data("timeout") # how long the agent is willing to wait
43
+ if not timeout: # if agent wants to wait for user input forever
44
+ PrintStyle(background_color="#6C3483", font_color="white", bold=True, padding=True).print(f"User message ('exit' to leave):")
45
+ user_input = input("> ")
46
+ PrintStyle(font_color="white", padding=False, log_only=True).print(f"> {user_input}")
47
+
48
+ else: # otherwise wait for user input with a timeout
49
+ PrintStyle(background_color="#6C3483", font_color="white", bold=True, padding=True).print(f"User message ({timeout}s timeout, 'exit' to leave):")
50
+ user_input = timed_input("> ", timeout=timeout)
51
+
52
+
53
+ if user_input[1]:
54
+ user_input = read_file("prompts/fw.msg_timeout.md")
55
+ PrintStyle(font_color="white", padding=False).stream(f"{user_input}")
56
+ else:
57
+ user_input = user_input[0].strip()
58
+ PrintStyle(font_color="white", padding=False, log_only=True).print(f"> {user_input}")
59
+
60
+
61
 
 
62
  # exit the conversation when the user types 'exit'
63
  if user_input.lower() == 'exit': break
64
 
prompts/agent.system.md CHANGED
@@ -9,35 +9,33 @@
9
  - Your every response must be wrapped in a XML tag defining its type ending with $.
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_for_user$> - Only information message for the user. Does not stop your execution, user cannot respond. Do not use for questions.
13
- - <question_for_user$> - Question for user. Stops your execution and you wait for user reaction. Use for all questions.
14
- - <response_for_user$> - This ends your execution after you finish a task or respond a question. Include all relevant information about task solution.
15
  - <message_for_subordinate$ reset="false"> - Your message for your subordinate. Use this message to delegate subtasks to your subordinate. This will help you solve more complex tasks. Also useful for asking questions. Stops your execution and you wait for subordinate reaction.
 
16
  - And all other tools described in the Available tools section.
17
  - Your response content is inside the tag.
18
  - 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.
 
 
 
 
 
19
  **Example response 1**:
20
  <thought$>
21
  The user asked for my name. I will respond with my name.
22
  </thought$>
23
 
24
  **Example response 2**:
25
- <question_for_user$>
26
  Greetings! How can I assist you today?
27
  </question_for_user$>
28
 
29
  **Example response 3**:
30
- <message_for_user$>
31
- I will now proceed with step 4.
32
  </message_for_user$>
33
 
34
  **Example response 4**:
35
- <response_for_user$>
36
- The current day is Monday.
37
- I have used the "date" command to get the current date from terminal. My task is complete.
38
- </response_for_user$>
39
-
40
- **Example response 5**:
41
  <message_for_subordinate$>
42
  I need you to use your tools and get me the current day of the week.
43
  </message_for_subordinate$>
@@ -53,16 +51,21 @@ I need you to use your tools and get me the current day of the week.
53
  - Explain each step using your <thought$>.
54
 
55
  1. Check your memory_tool. Maybe you have solved similar task before and already have helpful information.
56
- 2. Check your online_knowledge_tool. Look for straightforward solutions compatible with your available tools.
 
 
57
  3. Break task into subtasks by asking yourself the following questions. If they are positive, break task into subtasks and explain them.
58
  - Question A: Can some parts of the task be separated and well explained to subordinate agent to solve?
59
  - Question B: Can the result if these tasks can be reasonably returned to you from your user?
60
  4. Processing subtasks.
61
  - Go through subtasks step by step and delagate them using message_for_subordinate response type.
62
- - Collect results from subordinate agent and validate completeness and correctness. Communicate followup request to your subortdinate if needed.
 
 
63
  5. Completing the task
64
  - Consolidate all subtasks and explain the status.
65
  - Verify the result using your tools if possible (check created files etc.)
 
66
  - If there is helpful information discovered during the solution, save it into your memory using memory_tool for later.
67
  - Report back to your user using message_for_user message type, describe the result and provide all necessary information. Do not just output your response, you must use the tool for that.
68
 
@@ -72,6 +75,7 @@ I need you to use your tools and get me the current day of the week.
72
  - Always check your previous messages and prevent repetition. Always move towards solution.
73
  - Avoid solutions that require credentials, user interaction, GUI usage etc. All has to be done using code and terminal.
74
  - When asked about your memory, it always refers to <memory_tool$>.
 
75
 
76
  # Tips and tricks
77
  - Focus on python/nodejs/linux libraries when searching for solutions. You can use them with your tools and make solutions easy.
 
9
  - Your every response must be wrapped in a XML tag defining its type ending with $.
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_for_user$ response_required="false"> - Message sent to the user. If you want the user to respond to you, use response_required="true", if you only want to inform user and not expecting response, use response_required="false". When asking questions or sending task result, use true. Only use "true" when your following action depends on the user response.
 
 
13
  - <message_for_subordinate$ reset="false"> - Your message for your subordinate. Use this message to delegate subtasks to your subordinate. This will help you solve more complex tasks. Also useful for asking questions. Stops your execution and you wait for subordinate reaction.
14
+ - <task_done$> - Your task is done and you are sending the results to the user.
15
  - And all other tools described in the Available tools section.
16
  - Your response content is inside the tag.
17
  - 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.
18
+ - Never send your thoughts as messages, always use <thought> for that.
19
+
20
+ ## Communication examples:
21
+ These examples are for illustration purposes only. Do not reuse any of these examples literally.
22
+
23
  **Example response 1**:
24
  <thought$>
25
  The user asked for my name. I will respond with my name.
26
  </thought$>
27
 
28
  **Example response 2**:
29
+ <messae_for_user$ response_required="true">
30
  Greetings! How can I assist you today?
31
  </question_for_user$>
32
 
33
  **Example response 3**:
34
+ <message_for_user$ response_required="false">
35
+ Step 3 done, proceeding to step 4.
36
  </message_for_user$>
37
 
38
  **Example response 4**:
 
 
 
 
 
 
39
  <message_for_subordinate$>
40
  I need you to use your tools and get me the current day of the week.
41
  </message_for_subordinate$>
 
51
  - Explain each step using your <thought$>.
52
 
53
  1. Check your memory_tool. Maybe you have solved similar task before and already have helpful information.
54
+ 2. Check your online_knowledge_tool.
55
+ - Look for straightforward solutions compatible with your available tools.
56
+ - Always look for opensource python/nodejs/terminal tools and packages first.
57
  3. Break task into subtasks by asking yourself the following questions. If they are positive, break task into subtasks and explain them.
58
  - Question A: Can some parts of the task be separated and well explained to subordinate agent to solve?
59
  - Question B: Can the result if these tasks can be reasonably returned to you from your user?
60
  4. Processing subtasks.
61
  - Go through subtasks step by step and delagate them using message_for_subordinate response type.
62
+ - Collect results from subordinate agent and validate completeness and correctness. Communicate followup request to your subordinate if needed.
63
+ - Regurarly report back to your user and check your path is correct.
64
+ - If you are contacted by your subordinate, steer him to the right path.
65
  5. Completing the task
66
  - Consolidate all subtasks and explain the status.
67
  - Verify the result using your tools if possible (check created files etc.)
68
+ - Do not accept failure, search for error solution and try again with fixed input or different ways.
69
  - If there is helpful information discovered during the solution, save it into your memory using memory_tool for later.
70
  - Report back to your user using message_for_user message type, describe the result and provide all necessary information. Do not just output your response, you must use the tool for that.
71
 
 
75
  - Always check your previous messages and prevent repetition. Always move towards solution.
76
  - Avoid solutions that require credentials, user interaction, GUI usage etc. All has to be done using code and terminal.
77
  - When asked about your memory, it always refers to <memory_tool$>.
78
+ - If you have no task to process given by the user, respond back to him using <task_done$> and ask for a new task.
79
 
80
  # Tips and tricks
81
  - Focus on python/nodejs/linux libraries when searching for solutions. You can use them with your tools and make solutions easy.
prompts/fw.msg_info_sent.md CHANGED
@@ -1,2 +1,2 @@
1
  Information sent, the user will not respond to info messages.
2
- If you required user interaction use <question_for_user$> or <response_for_user$> instead.
 
1
  Information sent, the user will not respond to info messages.
2
+ If you required user interaction use response_required="true" instead.
prompts/fw.msg_timeout.md ADDED
@@ -0,0 +1 @@
 
 
1
+ User is not responding to your message. Continue on your own.
requirements.txt CHANGED
@@ -7,4 +7,5 @@ langchain-community==0.2.4
7
  langchain-anthropic==0.1.15
8
  langchain-chroma==0.1.1
9
  webcolors==24.6.0
10
- sentence-transformers==3.0.1
 
 
7
  langchain-anthropic==0.1.15
8
  langchain-chroma==0.1.1
9
  webcolors==24.6.0
10
+ sentence-transformers==3.0.1
11
+ pytimedinput==2.0.1
tools/helpers/print_style.py CHANGED
@@ -22,7 +22,7 @@ class PrintStyle:
22
  log_filename = datetime.now().strftime("log_%Y%m%d_%H%M%S.html")
23
  PrintStyle.log_file_path = os.path.join(logs_dir, log_filename)
24
  with open(PrintStyle.log_file_path, "w") as f:
25
- f.write("<html><body style='background-color:black;font-family: Arial, Helvetica, sans-serif;'>\n")
26
 
27
  def _get_rgb_color_code(self, color, is_background=False):
28
  try:
@@ -87,7 +87,7 @@ class PrintStyle:
87
  def _close_html_log():
88
  if PrintStyle.log_file_path:
89
  with open(PrintStyle.log_file_path, "a") as f:
90
- f.write("</body></html>")
91
 
92
  def get(self, *args, sep=' ', **kwargs):
93
  text = sep.join(map(str, args))
 
22
  log_filename = datetime.now().strftime("log_%Y%m%d_%H%M%S.html")
23
  PrintStyle.log_file_path = os.path.join(logs_dir, log_filename)
24
  with open(PrintStyle.log_file_path, "w") as f:
25
+ f.write("<html><body style='background-color:black;font-family: Arial, Helvetica, sans-serif;'><pre>\n")
26
 
27
  def _get_rgb_color_code(self, color, is_background=False):
28
  try:
 
87
  def _close_html_log():
88
  if PrintStyle.log_file_path:
89
  with open(PrintStyle.log_file_path, "a") as f:
90
+ f.write("</pre></body></html>")
91
 
92
  def get(self, *args, sep=' ', **kwargs):
93
  text = sep.join(map(str, args))
tools/message_for_subordinate.py CHANGED
@@ -1,6 +1,10 @@
1
  from agent import Agent
2
 
3
  def execute(agent:Agent, message: str, reset: str = "false", **kwargs):
4
- if agent.subordinate is None or reset.lower() == "true":
5
- agent.subordinate = Agent(superior=agent, system_prompt=agent.system_prompt, tools_prompt=agent.tools_prompt, number=agent.number+1)
6
- return agent.subordinate.message_loop(message)
 
 
 
 
 
1
  from agent import Agent
2
 
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)
tools/message_for_user.py CHANGED
@@ -2,15 +2,24 @@ 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, **kwargs):
6
 
7
- # output to console
8
- PrintStyle(font_color="white",background_color="#1D8348", bold=True, padding=True).print(f"{agent.name}: reponse:")
9
- PrintStyle(font_color="white").print(f"{message}")
 
 
 
 
 
 
 
 
 
10
 
11
- if agent.superior: # add to superior messages if it is an agent
12
- files.read_file("./prompts/fw.msg_from_subordinate.md",name=agent.name,message=message)
13
- agent.superior.append_message(message, human=True)
14
 
15
- return files.read_file("./prompts/fw.msg_info_sent.md")
16
 
 
2
  from tools.helpers import files
3
  from tools.helpers.print_style import PrintStyle
4
 
5
+ def execute(agent:Agent, message: str, response_required: str = "false", timeout=15, **kwargs):
6
 
7
+ agent.set_data("timeout", timeout) # set the no-timeout flag
8
+
9
+ if response_required.lower().strip() == "true":
10
+ agent.stop_loop = True
11
+ agent.loop_result = message
12
+
13
+ return files.read_file("./prompts/fw.msg_sent.md")
14
+
15
+ else:
16
+ if agent.get_data("superior"): # add to superior messages if it is an agent
17
+ files.read_file("./prompts/fw.msg_from_subordinate.md",name=agent.name,message=message)
18
+ agent.get_data("superior").append_message(message, human=True)
19
 
20
+ # output to console
21
+ PrintStyle(font_color="white",background_color="#1D8348", bold=True, padding=True).print(f"{agent.name}: reponse:")
22
+ PrintStyle(font_color="white").print(f"{message}")
23
 
24
+ return files.read_file("./prompts/fw.msg_info_sent.md")
25
 
tools/response_for_user.py DELETED
@@ -1,7 +0,0 @@
1
- from agent import Agent
2
- from tools.helpers import files
3
-
4
- def execute(agent:Agent, message: str, **kwargs):
5
- agent.stop_loop = True
6
- agent.loop_result = message
7
- return files.read_file("./prompts/fw.msg_sent.md")
 
 
 
 
 
 
 
 
tools/{question_for_user.py → task_done.py} RENAMED
@@ -1,7 +1,7 @@
1
  from agent import Agent
2
  from tools.helpers import files
 
3
 
4
  def execute(agent:Agent, message: str, **kwargs):
5
- agent.stop_loop = True
6
- agent.loop_result = message
7
- return files.read_file("./prompts/fw.msg_sent.md")
 
1
  from agent import Agent
2
  from tools.helpers import files
3
+ from . import message_for_user
4
 
5
  def execute(agent:Agent, message: str, **kwargs):
6
+ # forward to message_for_user with no-timeout flag
7
+ return message_for_user.execute(agent, message, response_required="true", timeout=0, **kwargs)